@cwellt_software/cwellt-reactjs-lib 1.3.2 → 1.3.5
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/index.cjs.js +336 -169
- package/dist/index.css +2 -2
- package/dist/index.d.ts +61 -7
- package/dist/index.es.js +336 -169
- package/dist/src/common/functions/colorManipulation.d.ts.map +1 -1
- package/dist/src/common/functions/useSingleAndDoubleClicks.d.ts.map +1 -1
- package/dist/src/components/control/choice/multi-filter/CwMultiFilter.d.ts +6 -0
- package/dist/src/components/control/choice/multi-filter/CwMultiFilter.d.ts.map +1 -1
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +16 -0
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -1
- package/dist/src/components/control/input/new-dates/CwDatePicker.d.ts +10 -1
- package/dist/src/components/control/input/new-dates/CwDatePicker.d.ts.map +1 -1
- package/dist/src/components/control/input/new-dates/CwDateTimePicker.d.ts +6 -1
- package/dist/src/components/control/input/new-dates/CwDateTimePicker.d.ts.map +1 -1
- package/dist/src/components/control/input/new-dates/CwDateTimePickerCompact.d.ts +8 -1
- package/dist/src/components/control/input/new-dates/CwDateTimePickerCompact.d.ts.map +1 -1
- package/dist/src/components/custom/scheduler-new/presentation/NewScheduler.d.ts +2 -0
- package/dist/src/components/custom/scheduler-new/presentation/NewScheduler.d.ts.map +1 -1
- package/dist/src/components/custom/scheduler-new/presentation/components/row/IndicatorRow.d.ts +18 -0
- package/dist/src/components/custom/scheduler-new/presentation/components/row/IndicatorRow.d.ts.map +1 -0
- package/dist/src/components/custom/scheduler-new/presentation/components/row/SchedulerRow.d.ts +2 -0
- package/dist/src/components/custom/scheduler-new/presentation/components/row/SchedulerRow.d.ts.map +1 -1
- package/dist/src/components/custom/super-scheduler/SuperScheduler.d.ts +2 -0
- package/dist/src/components/custom/super-scheduler/SuperScheduler.d.ts.map +1 -1
- package/dist/src/components/display/data/table/CwTable.d.ts +2 -1
- package/dist/src/components/display/data/table/CwTable.d.ts.map +1 -1
- package/dist/src/components/display/text/message/CwMessage.d.ts +3 -2
- package/dist/src/components/display/text/message/CwMessage.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/main.d.ts +0 -1
- package/dist/src/main.d.ts.map +1 -1
- package/dist/src/playground/PlaygroundApp.d.ts +4 -0
- package/dist/src/playground/PlaygroundApp.d.ts.map +1 -0
- package/dist/src/playground/pages/ColorContrastPage.d.ts +3 -0
- package/dist/src/playground/pages/ColorContrastPage.d.ts.map +1 -0
- package/dist/src/playground/pages/DatePickerLocalePage.d.ts +3 -0
- package/dist/src/playground/pages/DatePickerLocalePage.d.ts.map +1 -0
- package/dist/src/playground/pages/TablePaginationPage.d.ts +3 -0
- package/dist/src/playground/pages/TablePaginationPage.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.cjs.js
CHANGED
|
@@ -125,36 +125,60 @@ function getHSLColor(color, alpha = 1) {
|
|
|
125
125
|
const hsl = colorToHSL(color);
|
|
126
126
|
return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha})`;
|
|
127
127
|
}
|
|
128
|
+
function hslToLinearRgb(h, s, l) {
|
|
129
|
+
const sNorm = s / 100;
|
|
130
|
+
const lNorm = l / 100;
|
|
131
|
+
const a = sNorm * Math.min(lNorm, 1 - lNorm);
|
|
132
|
+
const f = (n) => {
|
|
133
|
+
const k = (n + h / 30) % 12;
|
|
134
|
+
return lNorm - a * Math.max(-1, Math.min(k - 3, Math.min(9 - k, 1)));
|
|
135
|
+
};
|
|
136
|
+
return [f(0), f(8), f(4)];
|
|
137
|
+
}
|
|
138
|
+
function srgbLuminance(r, g, b) {
|
|
139
|
+
const lin = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
140
|
+
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
141
|
+
}
|
|
142
|
+
function wcagContrastRatio(lum1, lum2) {
|
|
143
|
+
const lighter = Math.max(lum1, lum2);
|
|
144
|
+
const darker = Math.min(lum1, lum2);
|
|
145
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
146
|
+
}
|
|
128
147
|
function getContrastColor(color) {
|
|
129
|
-
if (color === null)
|
|
148
|
+
if (color === null)
|
|
130
149
|
return '#000000';
|
|
131
|
-
}
|
|
132
150
|
const hsl = colorToHSL(color);
|
|
133
|
-
// Saturated greenyellow and cyan tones need lower luminance threshold (40-35)
|
|
134
|
-
// Saturated mediumblue and blueviolet tones need higher luminance threshold (55-60)
|
|
135
|
-
// Saturated orangered tones need lower luminance threshold (45)
|
|
136
|
-
const isYellowGreen = (hsl.h >= 45 && hsl.h <= 180);
|
|
137
|
-
const isBlueViolet = (hsl.h >= 210 && hsl.h <= 300);
|
|
138
|
-
const isRedOrange = (hsl.h >= 0 && hsl.h <= 30) || (hsl.h >= 330 && hsl.h <= 360);
|
|
139
|
-
let threshold = 50;
|
|
140
|
-
if (isYellowGreen) {
|
|
141
|
-
threshold = 40;
|
|
142
|
-
if (hsl.s >= 70) {
|
|
143
|
-
threshold = 35;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
else if (isBlueViolet) {
|
|
147
|
-
threshold = 55;
|
|
148
|
-
if (hsl.s >= 70) {
|
|
149
|
-
threshold = 60;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else if (isRedOrange && hsl.s >= 80) {
|
|
153
|
-
threshold = 45;
|
|
154
|
-
}
|
|
155
|
-
const contrastL = hsl.l >= threshold ? 20 : 90;
|
|
156
151
|
const contrastS = Math.min(hsl.s, 90);
|
|
157
|
-
|
|
152
|
+
const bgRgb = hslToLinearRgb(hsl.h, hsl.s, hsl.l);
|
|
153
|
+
const bgLum = srgbLuminance(...bgRgb);
|
|
154
|
+
const darkL = 15;
|
|
155
|
+
const lightL = 90;
|
|
156
|
+
const darkLum = srgbLuminance(...hslToLinearRgb(hsl.h, contrastS, darkL));
|
|
157
|
+
const lightLum = srgbLuminance(...hslToLinearRgb(hsl.h, contrastS, lightL));
|
|
158
|
+
const darkRatio = wcagContrastRatio(bgLum, darkLum);
|
|
159
|
+
const lightRatio = wcagContrastRatio(bgLum, lightLum);
|
|
160
|
+
// On saturated backgrounds, dark-tinted text blends visually with the
|
|
161
|
+
// vibrant color even when math says it has better contrast.
|
|
162
|
+
// Prefer light text unless dark has an overwhelmingly higher ratio.
|
|
163
|
+
const saturatedBias = hsl.s >= 30 && bgLum < 0.4;
|
|
164
|
+
// Mid-grays (#777–#999): dark text "sinks" into the background while
|
|
165
|
+
// white text pops, even though dark wins on WCAG ratio.
|
|
166
|
+
const midGrayBias = hsl.s < 15 && bgLum >= 0.18 && bgLum <= 0.35;
|
|
167
|
+
const goLight = saturatedBias
|
|
168
|
+
? darkRatio < lightRatio * 3
|
|
169
|
+
: midGrayBias || lightRatio >= darkRatio;
|
|
170
|
+
let targetL = goLight ? lightL : darkL;
|
|
171
|
+
let bestRatio = goLight ? lightRatio : darkRatio;
|
|
172
|
+
if (bestRatio < 4.5) {
|
|
173
|
+
const step = goLight ? 5 : -5;
|
|
174
|
+
const limit = goLight ? 95 : 0;
|
|
175
|
+
while (bestRatio < 4.5 && targetL !== limit) {
|
|
176
|
+
targetL = goLight ? Math.min(targetL + step, limit) : Math.max(targetL + step, limit);
|
|
177
|
+
const candidateLum = srgbLuminance(...hslToLinearRgb(hsl.h, contrastS, targetL));
|
|
178
|
+
bestRatio = wcagContrastRatio(bgLum, candidateLum);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
|
|
158
182
|
}
|
|
159
183
|
|
|
160
184
|
const SVG_ICONS = {
|
|
@@ -249,7 +273,7 @@ const CwMessage = props => {
|
|
|
249
273
|
}, props.duration ?? CW_DEFAULT_MESSAGE_DURATION);
|
|
250
274
|
return () => clearTimeout(timer);
|
|
251
275
|
}, [props]);
|
|
252
|
-
return (jsxRuntime.jsxs("div", { className: "cw-message", "data-message-type": Object.keys(exports.CwMessageType).find(key => exports.CwMessageType[key] === props.messageType), children: [props.messageType && jsxRuntime.jsx(CwIcon, { iconId: props.messageType.toString(), size: "large" }), props.message] }));
|
|
276
|
+
return (jsxRuntime.jsxs("div", { className: "cw-message", "data-message-type": Object.keys(exports.CwMessageType).find(key => exports.CwMessageType[key] === props.messageType), onClick: props.onClick, style: props.onClick ? { cursor: "pointer" } : undefined, children: [props.messageType && jsxRuntime.jsx(CwIcon, { iconId: props.messageType.toString(), size: "large" }), props.message] }));
|
|
253
277
|
};
|
|
254
278
|
/**
|
|
255
279
|
* Hook for displaying inline messages within specific components.
|
|
@@ -312,11 +336,11 @@ class CwMessageManager {
|
|
|
312
336
|
document.body.prepend(this.messageWrapper);
|
|
313
337
|
this.root = client.createRoot(this.messageWrapper); // Create a root at the messageWrapper
|
|
314
338
|
}
|
|
315
|
-
showMessage(message, type, duration) {
|
|
339
|
+
showMessage(message, type, duration, onClick) {
|
|
316
340
|
const msg = document.createElement("div");
|
|
317
341
|
this.messageWrapper?.prepend(msg);
|
|
318
342
|
const msgRoot = client.createRoot(msg); // Create a root for the new message
|
|
319
|
-
msgRoot.render(jsxRuntime.jsx(CwMessage, { message: message, messageType: type, duration: duration, onClose: () => this.closeMessage(msgRoot) }));
|
|
343
|
+
msgRoot.render(jsxRuntime.jsx(CwMessage, { message: message, messageType: type, duration: duration, onClick: onClick, onClose: () => this.closeMessage(msgRoot) }));
|
|
320
344
|
}
|
|
321
345
|
closeMessage(msgRoot) {
|
|
322
346
|
msgRoot.unmount(); // Unmount the message root
|
|
@@ -338,8 +362,8 @@ class CwMessageManager {
|
|
|
338
362
|
*
|
|
339
363
|
* @note For inline messages within components, use `CwNote` or `useCwMessage` hook instead
|
|
340
364
|
*/
|
|
341
|
-
function CwDisplayMessage(message, type, duration) {
|
|
342
|
-
CwMessageManager.getInstance().showMessage(message, type, duration);
|
|
365
|
+
function CwDisplayMessage(message, type, duration, onClick) {
|
|
366
|
+
CwMessageManager.getInstance().showMessage(message, type, duration, onClick);
|
|
343
367
|
}
|
|
344
368
|
|
|
345
369
|
/**
|
|
@@ -1864,7 +1888,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
|
|
|
1864
1888
|
*
|
|
1865
1889
|
* @returns React component
|
|
1866
1890
|
*/
|
|
1867
|
-
function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10, 20, 50], expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, rowSelection }) {
|
|
1891
|
+
function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10, 20, 50], expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, pageLabel = "page", rowSelection }) {
|
|
1868
1892
|
const [currentPage, setCurrentPage] = React.useState(1);
|
|
1869
1893
|
const [expandedRowKey, setExpandedRowKey] = React.useState(null);
|
|
1870
1894
|
const [sortConfig, setSortConfig] = React.useState({
|
|
@@ -2049,16 +2073,16 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
|
|
|
2049
2073
|
? "sortable"
|
|
2050
2074
|
: sortConfig.direction === "asc"
|
|
2051
2075
|
? "sortable-asc"
|
|
2052
|
-
: "sortable-desc" }))] }), jsxRuntime.jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderTableBody() })] }) }), pagination && data.length > pageSizeOptions[0] && (jsxRuntime.jsxs("footer", { className: "cw-table-pagination", children: [jsxRuntime.jsx("
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2076
|
+
: "sortable-desc" }))] }), jsxRuntime.jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderTableBody() })] }) }), pagination && data.length > pageSizeOptions[0] && (jsxRuntime.jsxs("footer", { className: "cw-table-pagination", children: [jsxRuntime.jsxs("div", { className: "cw-table-pagination-size", children: [jsxRuntime.jsx(CwIcon, { iconId: "list" }), jsxRuntime.jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsxRuntime.jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxRuntime.jsxs("div", { className: "cw-table-pagination-nav", children: [jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left-double" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left" }), jsxRuntime.jsx("input", { type: "text", inputMode: "numeric", value: currentPage, onChange: (e) => {
|
|
2077
|
+
const value = parseInt(e.target.value, 10);
|
|
2078
|
+
if (!isNaN(value))
|
|
2079
|
+
handlePageChange(value);
|
|
2080
|
+
}, onBlur: (e) => {
|
|
2081
|
+
const value = parseInt(e.target.value, 10);
|
|
2082
|
+
if (isNaN(value) || value < 1 || value > totalPages) {
|
|
2083
|
+
handlePageChange(1);
|
|
2084
|
+
}
|
|
2085
|
+
}, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
|
|
2062
2086
|
}
|
|
2063
2087
|
|
|
2064
2088
|
var styles$i = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
|
|
@@ -2815,10 +2839,26 @@ function CwFileUpload(fileUploadProps) {
|
|
|
2815
2839
|
|
|
2816
2840
|
var styles$e = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
|
|
2817
2841
|
|
|
2842
|
+
const DEFAULT_LABELS = {
|
|
2843
|
+
uploadDisabled: 'Upload disabled',
|
|
2844
|
+
clickToUpload: 'Click to upload or drag and drop',
|
|
2845
|
+
acceptedFiles: (accept) => `Accepted files: ${accept}`,
|
|
2846
|
+
singleFileOnly: '(Single file only)',
|
|
2847
|
+
allTypesAccepted: 'All file types accepted',
|
|
2848
|
+
changeFile: 'Change File',
|
|
2849
|
+
clearAll: 'Clear all',
|
|
2850
|
+
addMoreFiles: 'Add More Files',
|
|
2851
|
+
filesSelected: (count) => `${count} file${count !== 1 ? 's' : ''} selected`,
|
|
2852
|
+
fileTooLarge: (name, maxSize) => `File "${name}" is too large. Maximum size allowed is ${maxSize}MB.`,
|
|
2853
|
+
invalidFormat: (name, accepted) => `File "${name}" has an invalid format. Allowed formats: ${accepted}`,
|
|
2854
|
+
invalidMimeType: (name, types) => `File "${name}" has an invalid MIME type. Allowed types: ${types}`,
|
|
2855
|
+
alreadySelected: (name) => `File "${name}" is already selected.`,
|
|
2856
|
+
};
|
|
2818
2857
|
function CwFileUploadMultiple(fileUploadProps) {
|
|
2819
2858
|
const fileInputRef = React.useRef(null);
|
|
2820
2859
|
const [selectedFiles, setSelectedFiles] = React.useState([]);
|
|
2821
2860
|
const [existingFile, setExistingFile] = React.useState(fileUploadProps.initialFileName);
|
|
2861
|
+
const labels = { ...DEFAULT_LABELS, ...fileUploadProps.labels };
|
|
2822
2862
|
React.useEffect(() => {
|
|
2823
2863
|
setExistingFile(fileUploadProps.initialFileName);
|
|
2824
2864
|
}, [fileUploadProps.initialFileName]);
|
|
@@ -2832,7 +2872,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2832
2872
|
if (fileSizeInMB > fileUploadProps.maxFileSize) {
|
|
2833
2873
|
return {
|
|
2834
2874
|
isValid: false,
|
|
2835
|
-
error:
|
|
2875
|
+
error: labels.fileTooLarge(file.name, fileUploadProps.maxFileSize)
|
|
2836
2876
|
};
|
|
2837
2877
|
}
|
|
2838
2878
|
}
|
|
@@ -2849,7 +2889,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2849
2889
|
if (!isExtensionValid) {
|
|
2850
2890
|
return {
|
|
2851
2891
|
isValid: false,
|
|
2852
|
-
error:
|
|
2892
|
+
error: labels.invalidFormat(file.name, fileUploadProps.accept)
|
|
2853
2893
|
};
|
|
2854
2894
|
}
|
|
2855
2895
|
}
|
|
@@ -2859,7 +2899,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2859
2899
|
if (!isMimeTypeValid) {
|
|
2860
2900
|
return {
|
|
2861
2901
|
isValid: false,
|
|
2862
|
-
error:
|
|
2902
|
+
error: labels.invalidMimeType(file.name, fileUploadProps.allowedTypes.join(', '))
|
|
2863
2903
|
};
|
|
2864
2904
|
}
|
|
2865
2905
|
}
|
|
@@ -2873,7 +2913,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2873
2913
|
// Check if the file already exists (by name and size)
|
|
2874
2914
|
const isDuplicate = existingFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
|
|
2875
2915
|
if (isDuplicate) {
|
|
2876
|
-
errors.push(
|
|
2916
|
+
errors.push(labels.alreadySelected(file.name));
|
|
2877
2917
|
continue;
|
|
2878
2918
|
}
|
|
2879
2919
|
const validation = validateFile(file);
|
|
@@ -2964,12 +3004,12 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2964
3004
|
}
|
|
2965
3005
|
}
|
|
2966
3006
|
};
|
|
2967
|
-
return (jsxRuntime.jsxs("div", { className: `${styles$e.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$e.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$e.uploadArea} ${fileUploadProps.disabled ? styles$e.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$e.uploadTitle}`, children: fileUploadProps.disabled ?
|
|
3007
|
+
return (jsxRuntime.jsxs("div", { className: `${styles$e.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$e.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$e.uploadArea} ${fileUploadProps.disabled ? styles$e.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$e.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$e.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$e.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$e.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$e.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$e.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$e.fileInfo, children: jsxRuntime.jsx("p", { className: styles$e.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
|
|
2968
3008
|
setExistingFile(undefined);
|
|
2969
3009
|
if (fileUploadProps.onSelect) {
|
|
2970
3010
|
fileUploadProps.onSelect(null);
|
|
2971
3011
|
}
|
|
2972
|
-
}, disabled: fileUploadProps.disabled, className: styles$e.smallButton })] }), jsxRuntime.jsx(CwButton, { text:
|
|
3012
|
+
}, disabled: fileUploadProps.disabled, className: styles$e.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$e.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("small", { className: styles$e.filesCount, children: labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$e.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$e.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$e.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$e.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$e.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$e.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$e.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
|
|
2973
3013
|
}
|
|
2974
3014
|
|
|
2975
3015
|
function CwInput(CwInputProps) {
|
|
@@ -4329,7 +4369,7 @@ const CwMultiFilterTag = props => {
|
|
|
4329
4369
|
} : undefined }) }));
|
|
4330
4370
|
};
|
|
4331
4371
|
|
|
4332
|
-
var styles$7 = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0"};
|
|
4372
|
+
var styles$7 = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0"};
|
|
4333
4373
|
|
|
4334
4374
|
/**
|
|
4335
4375
|
* A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
|
|
@@ -4470,7 +4510,7 @@ var styles$7 = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-
|
|
|
4470
4510
|
* @param {CwMultiFilterProps} props
|
|
4471
4511
|
* @returns Set the `onChange` callback to a function to check for changes in the selected filters
|
|
4472
4512
|
*/
|
|
4473
|
-
const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, style }) => {
|
|
4513
|
+
const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeholder = "Write to filter", allCategoriesLabel = "ALL CATEGORIES", className, style }) => {
|
|
4474
4514
|
const [filteredTags, setFilteredTags] = React.useState(new Set());
|
|
4475
4515
|
const [inputTextValue, setInputTextValue] = React.useState("");
|
|
4476
4516
|
const [isPanelOpen, setIsPanelOpen] = React.useState(false);
|
|
@@ -4572,9 +4612,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, style
|
|
|
4572
4612
|
inputRef.current?.focus();
|
|
4573
4613
|
}
|
|
4574
4614
|
};
|
|
4575
|
-
return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: styles$7["cw-multi-filter"]
|
|
4615
|
+
return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$7["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
|
|
4576
4616
|
e.preventDefault();
|
|
4577
|
-
}, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, className: styles$7["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-primary)", outlineOffset: "-2px" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.target.value), autoComplete: "off", placeholder:
|
|
4617
|
+
}, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, className: styles$7["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-primary)", outlineOffset: "-2px" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.target.value), autoComplete: "off", placeholder: placeholder, onKeyDown: e => {
|
|
4578
4618
|
switch (e.key) {
|
|
4579
4619
|
case "Enter":
|
|
4580
4620
|
case "Tab": {
|
|
@@ -4604,15 +4644,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, style
|
|
|
4604
4644
|
} })] }), selectedTags.size > 0 ? (jsxRuntime.jsx("input", { type: "reset", value: "\u00D7", onClick: e => {
|
|
4605
4645
|
e.preventDefault();
|
|
4606
4646
|
onChangeSelectedTags(new Set());
|
|
4607
|
-
} })) : null] }), jsxRuntime.jsxs("section", { className: styles$7["cw-multi-filter-catalog-container"], "data-display-none": !isPanelOpen, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", {
|
|
4608
|
-
? {
|
|
4609
|
-
backgroundColor: "var(--cw-color-primary-container)",
|
|
4610
|
-
color: "var(--cw-color-primary)",
|
|
4611
|
-
outline: "2px solid var(--cw-color-primary)",
|
|
4612
|
-
outlineOffset: "-2px",
|
|
4613
|
-
fontWeight: 400
|
|
4614
|
-
}
|
|
4615
|
-
: {}, onClick: () => handleClickCategory("All"), children: "SEARCH IN ALL CATEGORIES" }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { style: selectedCategory === category
|
|
4647
|
+
} })) : null] }), jsxRuntime.jsxs("section", { className: styles$7["cw-multi-filter-catalog-container"], "data-display-none": !isPanelOpen, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$7["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { style: selectedCategory === category
|
|
4616
4648
|
? {
|
|
4617
4649
|
backgroundColor: getColor(category).primary,
|
|
4618
4650
|
color: getColor(category).onPrimary,
|
|
@@ -5162,10 +5194,13 @@ function usePickerPopup({ anchorRef, isOpen, onClose, position = "left-bottom" }
|
|
|
5162
5194
|
return { popupRef, popupStyle: style, renderPopup };
|
|
5163
5195
|
}
|
|
5164
5196
|
|
|
5165
|
-
function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, }) {
|
|
5197
|
+
function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, locale: locale$1 = locale.enGB, todayLabel = "Today", feedback, }) {
|
|
5166
5198
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
5167
5199
|
const [inputValue, setInputValue] = React.useState("");
|
|
5168
5200
|
const containerRef = React.useRef(null);
|
|
5201
|
+
const feedbackMessages = feedback
|
|
5202
|
+
? Array.isArray(feedback) ? feedback : [feedback]
|
|
5203
|
+
: [];
|
|
5169
5204
|
const wrapperRef = React.useRef(null);
|
|
5170
5205
|
const inputRef = React.useRef(null);
|
|
5171
5206
|
const prevValueRef = React.useRef(undefined);
|
|
@@ -5333,11 +5368,11 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
|
|
|
5333
5368
|
...(maxDate ? [{ after: maxDate }] : []),
|
|
5334
5369
|
...(disabledMatcher ? [disabledMatcher] : []),
|
|
5335
5370
|
], [disabledDates, minDate, maxDate, disabledMatcher]);
|
|
5336
|
-
return (jsxRuntime.
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5371
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, modifiers: {
|
|
5372
|
+
today: new Date(),
|
|
5373
|
+
}, modifiersClassNames: {
|
|
5374
|
+
today: "rdp-day-today",
|
|
5375
|
+
} }), showTodayButton && (jsxRuntime.jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
|
|
5341
5376
|
}
|
|
5342
5377
|
|
|
5343
5378
|
var rangeStyles = {"rangeWrapper":"cw-range-picker-module__rangeWrapper__1nIVs","rangePopup":"cw-range-picker-module__rangePopup__E5jd1","presetList":"cw-range-picker-module__presetList__INiLo"};
|
|
@@ -6185,7 +6220,7 @@ function combineDateTimeInOffset(date, hours, minutes, timezoneOffset) {
|
|
|
6185
6220
|
return new Date(zdt.epochMilliseconds);
|
|
6186
6221
|
}
|
|
6187
6222
|
|
|
6188
|
-
function CwDateTimePicker({ value, onChange, minDateTime, maxDateTime, disabledDates, disabledMatcher, timeInterval = 15, minTime, maxTime, labelProps, alignProps, datePlaceholder = "dd.MM.yyyy", timePlaceholder = "HH:mm", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showNowButton = false, timezoneOffset, }) {
|
|
6223
|
+
function CwDateTimePicker({ value, onChange, minDateTime, maxDateTime, disabledDates, disabledMatcher, timeInterval = 15, minTime, maxTime, labelProps, alignProps, datePlaceholder = "dd.MM.yyyy", timePlaceholder = "HH:mm", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showNowButton = false, nowLabel = "Now", locale: locale$1 = locale.enGB, timezoneOffset, }) {
|
|
6189
6224
|
// ========================================
|
|
6190
6225
|
// PROPS NORMALIZATION
|
|
6191
6226
|
// ========================================
|
|
@@ -6425,12 +6460,12 @@ function CwDateTimePicker({ value, onChange, minDateTime, maxDateTime, disabledD
|
|
|
6425
6460
|
const displayMaxDate = React.useMemo(() => normalizedMaxDateTime && timezoneOffset !== undefined
|
|
6426
6461
|
? getDateInOffset(normalizedMaxDateTime, timezoneOffset)
|
|
6427
6462
|
: normalizedMaxDateTime, [normalizedMaxDateTime, timezoneOffset]);
|
|
6428
|
-
return jsxRuntime.jsx("div", { className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsxRuntime.jsx(CwDatePicker, { value: selectedDate, onChange: handleDateChange, minDate: displayMinDate, maxDate: displayMaxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition }), jsxRuntime.jsx(CwTimePicker, { value: selectedTime, onChange: handleTimeChange, interval: timeInterval, minTime: timeRestrictions.minTime, maxTime: timeRestrictions.maxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: handleNowClick, disabled: disabled,
|
|
6463
|
+
return jsxRuntime.jsx("div", { className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsxRuntime.jsx(CwDatePicker, { value: selectedDate, onChange: handleDateChange, minDate: displayMinDate, maxDate: displayMaxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale$1 }), jsxRuntime.jsx(CwTimePicker, { value: selectedTime, onChange: handleTimeChange, interval: timeInterval, minTime: timeRestrictions.minTime, maxTime: timeRestrictions.maxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: handleNowClick, disabled: disabled, text: nowLabel }))] })] }) });
|
|
6429
6464
|
}
|
|
6430
6465
|
|
|
6431
6466
|
var compactStyles = {"compactPopup":"cw-datetime-compact-module__compactPopup__GiuNY","calendarWrapper":"cw-datetime-compact-module__calendarWrapper__P4Nlq","timeWrapper":"cw-datetime-compact-module__timeWrapper__uMe-A","compactTimeList":"cw-datetime-compact-module__compactTimeList__MzSQT"};
|
|
6432
6467
|
|
|
6433
|
-
function CwDateTimePickerCompact({ value, onChange, minDateTime, maxDateTime, disabledDates, disabledMatcher, timeInterval = 15, minTime, maxTime, labelProps, alignProps, placeholder = "dd.mm.yyyy HH:mm", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, }) {
|
|
6468
|
+
function CwDateTimePickerCompact({ value, onChange, minDateTime, maxDateTime, disabledDates, disabledMatcher, timeInterval = 15, minTime, maxTime, labelProps, alignProps, placeholder = "dd.mm.yyyy HH:mm", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, nowLabel = "Now", timeLabel = "Time", locale: locale$1 = locale.enGB, }) {
|
|
6434
6469
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
6435
6470
|
const [inputValue, setInputValue] = React.useState("");
|
|
6436
6471
|
const [selectedDate, setSelectedDate] = React.useState(value);
|
|
@@ -6661,11 +6696,11 @@ function CwDateTimePickerCompact({ value, onChange, minDateTime, maxDateTime, di
|
|
|
6661
6696
|
...(maxDateTime ? [{ after: maxDateTime }] : []),
|
|
6662
6697
|
...(disabledMatcher ? [disabledMatcher] : []),
|
|
6663
6698
|
], [disabledDates, minDateTime, maxDateTime, disabledMatcher]);
|
|
6664
|
-
return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-datetimepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required, maxLength: 16
|
|
6699
|
+
return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-datetimepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required, maxLength: 16 }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear datetime" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar-time" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${compactStyles.compactPopup}`, style: popupStyle, children: [jsxRuntime.jsxs("div", { className: compactStyles.calendarWrapper, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: selectedDate, onSelect: handleDaySelect, defaultMonth: selectedDate, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, modifiers: {
|
|
6665
6700
|
today: new Date(),
|
|
6666
6701
|
}, modifiersClassNames: {
|
|
6667
6702
|
today: "rdp-day-today",
|
|
6668
|
-
} }), showTodayButton && (jsxRuntime.jsx("footer", { className: "cw-flex-row cw-align-center-center", children: jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", icon: "check-big", onClick: handleNowClick, text:
|
|
6703
|
+
} }), showTodayButton && (jsxRuntime.jsx("footer", { className: "cw-flex-row cw-align-center-center", children: jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", icon: "check-big", onClick: handleNowClick, text: nowLabel }) }))] }), jsxRuntime.jsxs("div", { className: compactStyles.timeWrapper, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx(CwIcon, { iconId: "clock", size: "medium" }), jsxRuntime.jsx("span", { children: timeLabel })] }), jsxRuntime.jsx("div", { ref: timeListRef, className: `${timeStyles.timePickerList} ${compactStyles.compactTimeList}`, children: timeOptions.map((time) => {
|
|
6669
6704
|
const isSelected = time === selectedTime;
|
|
6670
6705
|
return (jsxRuntime.jsx("button", { type: "button", className: isSelected ? timeStyles.selected : "", onClick: () => handleTimeSelect(time), children: time }, time));
|
|
6671
6706
|
}) })] })] }))] })] }) }));
|
|
@@ -8005,30 +8040,95 @@ const BackgroundEvent = ({ value, heightRem }) => {
|
|
|
8005
8040
|
}, children: value.icons }) : null, jsxRuntime.jsx("span", { className: styles$2["scheduler-event-text"], children: value.name })] }) }) }) }) })) : null;
|
|
8006
8041
|
};
|
|
8007
8042
|
|
|
8043
|
+
const eventIsVisible = (startDate, endDate, selectedDate, visibleDays) => {
|
|
8044
|
+
const schedulerEnd = Temporal.PlainDate.from({
|
|
8045
|
+
year: selectedDate.getFullYear(),
|
|
8046
|
+
month: selectedDate.getMonth() + 1,
|
|
8047
|
+
day: selectedDate.getDate(),
|
|
8048
|
+
}).add({ days: visibleDays });
|
|
8049
|
+
const schedulerEndDate = new Date(schedulerEnd.year, schedulerEnd.month - 1, schedulerEnd.day);
|
|
8050
|
+
const isBefore = selectedDate > startDate && selectedDate > endDate;
|
|
8051
|
+
const isAfter = schedulerEndDate < startDate && schedulerEndDate < endDate;
|
|
8052
|
+
return !isBefore && !isAfter;
|
|
8053
|
+
};
|
|
8054
|
+
|
|
8055
|
+
const hoursBetween = (date1, date2) => {
|
|
8056
|
+
const oneHourInMillis = 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
|
|
8057
|
+
const timeDiff = date2.getTime() - date1.getTime();
|
|
8058
|
+
return timeDiff / oneHourInMillis;
|
|
8059
|
+
};
|
|
8060
|
+
const getEventSizes = (schedulerDate, totalDays, startDate, endDate) => {
|
|
8061
|
+
if (!eventIsVisible(startDate, endDate, schedulerDate, totalDays)) {
|
|
8062
|
+
return {
|
|
8063
|
+
left: 0,
|
|
8064
|
+
width: 0,
|
|
8065
|
+
};
|
|
8066
|
+
}
|
|
8067
|
+
const totalHours = totalDays * 24;
|
|
8068
|
+
// const dateString = schedulerDate.toISOString().split('T')[0];
|
|
8069
|
+
//const schedulerDateAtZero = new Date(dateString)
|
|
8070
|
+
let startHours = hoursBetween(schedulerDate, startDate);
|
|
8071
|
+
let durationHours = hoursBetween(startDate, endDate);
|
|
8072
|
+
const startOutOfScheduler = startHours < 0;
|
|
8073
|
+
if (startOutOfScheduler) {
|
|
8074
|
+
durationHours += startHours;
|
|
8075
|
+
startHours = 0;
|
|
8076
|
+
}
|
|
8077
|
+
const left = (startHours / totalHours) * 100;
|
|
8078
|
+
// Minimum width equivalent to 15 minutes so zero/near-zero duration events stay visible
|
|
8079
|
+
const MIN_WIDTH_HOURS = 0.25;
|
|
8080
|
+
const minWidth = (MIN_WIDTH_HOURS * 100) / totalHours;
|
|
8081
|
+
const width = Math.max((durationHours * 100) / totalHours, minWidth);
|
|
8082
|
+
return {
|
|
8083
|
+
left,
|
|
8084
|
+
width,
|
|
8085
|
+
};
|
|
8086
|
+
};
|
|
8087
|
+
|
|
8088
|
+
const INDICATOR_HEIGHT_REM = 0.25;
|
|
8089
|
+
const IndicatorRow = ({ indicators, selectedDate, visibleDays }) => {
|
|
8090
|
+
return (jsxRuntime.jsx("div", { style: {
|
|
8091
|
+
position: "relative",
|
|
8092
|
+
height: `${INDICATOR_HEIGHT_REM}rem`,
|
|
8093
|
+
pointerEvents: "none",
|
|
8094
|
+
}, "data-name": "indicator-row", children: indicators.map((indicator) => {
|
|
8095
|
+
const { left, width } = getEventSizes(selectedDate, visibleDays, indicator.start, indicator.end);
|
|
8096
|
+
if (width <= 0)
|
|
8097
|
+
return null;
|
|
8098
|
+
const bar = (jsxRuntime.jsx("div", { style: {
|
|
8099
|
+
position: "absolute",
|
|
8100
|
+
left: `${left}%`,
|
|
8101
|
+
width: `${width}%`,
|
|
8102
|
+
height: `${INDICATOR_HEIGHT_REM}rem`,
|
|
8103
|
+
backgroundColor: indicator.color,
|
|
8104
|
+
borderRadius: "1px",
|
|
8105
|
+
pointerEvents: "auto",
|
|
8106
|
+
} }, indicator.id));
|
|
8107
|
+
if (indicator.tooltip) {
|
|
8108
|
+
return (jsxRuntime.jsx(CwTooltipNew, { content: indicator.tooltip, position: "bottom", dissapearsWhenHover: true, showDelay: 200, children: bar }, indicator.id));
|
|
8109
|
+
}
|
|
8110
|
+
return bar;
|
|
8111
|
+
}) }));
|
|
8112
|
+
};
|
|
8113
|
+
|
|
8114
|
+
// Fires onClick on the first click of a sequence (detail === 1) and
|
|
8115
|
+
// onDoubleClick on the native dblclick event. Subsequent clicks of a
|
|
8116
|
+
// double-click sequence (detail > 1) are suppressed so the same logical
|
|
8117
|
+
// interaction does not fire onClick twice. Selection therefore appears
|
|
8118
|
+
// within one paint frame instead of being delayed by an artificial timer.
|
|
8008
8119
|
function useSingleAndDoubleClicks(onClick, onDoubleClick) {
|
|
8009
|
-
const timer = React.useRef(null);
|
|
8010
|
-
const cancelPendingClick = React.useCallback(() => {
|
|
8011
|
-
if (timer.current) {
|
|
8012
|
-
clearTimeout(timer.current);
|
|
8013
|
-
timer.current = null;
|
|
8014
|
-
}
|
|
8015
|
-
}, [timer]);
|
|
8016
8120
|
const handleClick = React.useCallback((e) => {
|
|
8017
|
-
// We only cache the most recent click event, so cancel any pending clicks
|
|
8018
8121
|
e.stopPropagation();
|
|
8019
8122
|
e.preventDefault();
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
}, 500);
|
|
8025
|
-
}, [timer, cancelPendingClick, onClick]);
|
|
8123
|
+
if (e.detail > 1)
|
|
8124
|
+
return;
|
|
8125
|
+
onClick(e);
|
|
8126
|
+
}, [onClick]);
|
|
8026
8127
|
const handleDoubleClick = React.useCallback((e) => {
|
|
8027
8128
|
e.stopPropagation();
|
|
8028
8129
|
e.preventDefault();
|
|
8029
|
-
cancelPendingClick();
|
|
8030
8130
|
onDoubleClick(e);
|
|
8031
|
-
}, [
|
|
8131
|
+
}, [onDoubleClick]);
|
|
8032
8132
|
return { handleClick, handleDoubleClick };
|
|
8033
8133
|
}
|
|
8034
8134
|
|
|
@@ -8202,7 +8302,7 @@ const SchedulerEvent = ({ value, heightRem, onEvent }) => {
|
|
|
8202
8302
|
|
|
8203
8303
|
const SchedulerRow = React.memo((props) => {
|
|
8204
8304
|
const [isContextMenuOpen, setIsContextMenuOpen] = React.useState(false);
|
|
8205
|
-
const { events, backgroundEvents, rowHeader, contextMenuItems, RowTitleComp, EventComp, BackgroundEventComp, weekendLines, divisionLines, timeLinePercentage, selectedDate, visibleDays, onEvent, } = props;
|
|
8305
|
+
const { events, backgroundEvents, indicatorRows, rowHeader, contextMenuItems, RowTitleComp, EventComp, BackgroundEventComp, weekendLines, divisionLines, timeLinePercentage, selectedDate, visibleDays, onEvent, } = props;
|
|
8206
8306
|
const internalRows = separateEventsToInnerRows(events);
|
|
8207
8307
|
const schedulerDivRef = React.useRef(null);
|
|
8208
8308
|
const { handleClick, handleDoubleClick } = useSingleAndDoubleClicks((e) => {
|
|
@@ -8259,7 +8359,7 @@ const SchedulerRow = React.memo((props) => {
|
|
|
8259
8359
|
height: props.rowHeightInRem + "rem",
|
|
8260
8360
|
pointerEvents: "none"
|
|
8261
8361
|
}, children: internalRow.map((event) => (jsxRuntime.jsx(EventComp, { value: event, heightRem: props.rowHeightInRem, onEvent: onEvent }, event.id))) }, index));
|
|
8262
|
-
}), !(timeLinePercentage < 0 || timeLinePercentage > 100) && (jsxRuntime.jsx(TimeLine, { color: "red", left: `${timeLinePercentage}%`, top: "0px", height: `100%` }))] }) })] }));
|
|
8362
|
+
}), indicatorRows.length > 0 && (jsxRuntime.jsx(IndicatorRow, { indicators: indicatorRows, selectedDate: selectedDate, visibleDays: visibleDays })), !(timeLinePercentage < 0 || timeLinePercentage > 100) && (jsxRuntime.jsx(TimeLine, { color: "red", left: `${timeLinePercentage}%`, top: "0px", height: `100%` }))] }) })] }));
|
|
8263
8363
|
}, (prevProps, nextProps) => {
|
|
8264
8364
|
// This memo is necessary to prevent re-render all the rows when a user makes drag and drop
|
|
8265
8365
|
const getEventKey = (event) => {
|
|
@@ -8285,6 +8385,9 @@ const SchedulerRow = React.memo((props) => {
|
|
|
8285
8385
|
return false;
|
|
8286
8386
|
}
|
|
8287
8387
|
}
|
|
8388
|
+
if (prevProps.indicatorRows.length !== nextProps.indicatorRows.length) {
|
|
8389
|
+
return false;
|
|
8390
|
+
}
|
|
8288
8391
|
// If we got here, the events are the same
|
|
8289
8392
|
return true;
|
|
8290
8393
|
});
|
|
@@ -8475,51 +8578,6 @@ const getWeeksByDays = (visibleDays, selectedDate) => {
|
|
|
8475
8578
|
return weeks;
|
|
8476
8579
|
};
|
|
8477
8580
|
|
|
8478
|
-
const eventIsVisible = (startDate, endDate, selectedDate, visibleDays) => {
|
|
8479
|
-
const schedulerEnd = Temporal.PlainDate.from({
|
|
8480
|
-
year: selectedDate.getFullYear(),
|
|
8481
|
-
month: selectedDate.getMonth() + 1,
|
|
8482
|
-
day: selectedDate.getDate(),
|
|
8483
|
-
}).add({ days: visibleDays });
|
|
8484
|
-
const schedulerEndDate = new Date(schedulerEnd.year, schedulerEnd.month - 1, schedulerEnd.day);
|
|
8485
|
-
const isBefore = selectedDate > startDate && selectedDate > endDate;
|
|
8486
|
-
const isAfter = schedulerEndDate < startDate && schedulerEndDate < endDate;
|
|
8487
|
-
return !isBefore && !isAfter;
|
|
8488
|
-
};
|
|
8489
|
-
|
|
8490
|
-
const hoursBetween = (date1, date2) => {
|
|
8491
|
-
const oneHourInMillis = 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
|
|
8492
|
-
const timeDiff = date2.getTime() - date1.getTime();
|
|
8493
|
-
return timeDiff / oneHourInMillis;
|
|
8494
|
-
};
|
|
8495
|
-
const getEventSizes = (schedulerDate, totalDays, startDate, endDate) => {
|
|
8496
|
-
if (!eventIsVisible(startDate, endDate, schedulerDate, totalDays)) {
|
|
8497
|
-
return {
|
|
8498
|
-
left: 0,
|
|
8499
|
-
width: 0,
|
|
8500
|
-
};
|
|
8501
|
-
}
|
|
8502
|
-
const totalHours = totalDays * 24;
|
|
8503
|
-
// const dateString = schedulerDate.toISOString().split('T')[0];
|
|
8504
|
-
//const schedulerDateAtZero = new Date(dateString)
|
|
8505
|
-
let startHours = hoursBetween(schedulerDate, startDate);
|
|
8506
|
-
let durationHours = hoursBetween(startDate, endDate);
|
|
8507
|
-
const startOutOfScheduler = startHours < 0;
|
|
8508
|
-
if (startOutOfScheduler) {
|
|
8509
|
-
durationHours += startHours;
|
|
8510
|
-
startHours = 0;
|
|
8511
|
-
}
|
|
8512
|
-
const left = (startHours / totalHours) * 100;
|
|
8513
|
-
// Minimum width equivalent to 15 minutes so zero/near-zero duration events stay visible
|
|
8514
|
-
const MIN_WIDTH_HOURS = 0.25;
|
|
8515
|
-
const minWidth = (MIN_WIDTH_HOURS * 100) / totalHours;
|
|
8516
|
-
const width = Math.max((durationHours * 100) / totalHours, minWidth);
|
|
8517
|
-
return {
|
|
8518
|
-
left,
|
|
8519
|
-
width,
|
|
8520
|
-
};
|
|
8521
|
-
};
|
|
8522
|
-
|
|
8523
8581
|
function getLinesByDivisions(headerDivision, _) {
|
|
8524
8582
|
const lines = headerDivision.flatMap((division) => division.bottom.map((_, i) => ({ isDayBoundary: i === 0 })));
|
|
8525
8583
|
const left = 100 / lines.length;
|
|
@@ -8575,8 +8633,65 @@ const getNow = (isUtc) => {
|
|
|
8575
8633
|
};
|
|
8576
8634
|
const milliSecondsInSecond = 1000;
|
|
8577
8635
|
const refreshMilliSeconds = 45 * milliSecondsInSecond;
|
|
8636
|
+
const EMPTY_EVENTS = [];
|
|
8637
|
+
const EMPTY_BG_EVENTS = [];
|
|
8638
|
+
const EMPTY_INDICATORS = [];
|
|
8639
|
+
// Memoised row body. Receives flat props (the per-row buckets are looked up
|
|
8640
|
+
// by the outer Row wrapper). As long as those bucket arrays keep their
|
|
8641
|
+
// reference (see `groupByRowIdStable`) and the rest of the render-context
|
|
8642
|
+
// values are stable, this row will skip re-rendering on selection clicks
|
|
8643
|
+
// that don't affect it.
|
|
8644
|
+
const RowContent = React.memo(function RowContent(props) {
|
|
8645
|
+
const header = {
|
|
8646
|
+
value: props.row,
|
|
8647
|
+
width: props.rowHeaderWidth,
|
|
8648
|
+
onEvent: props.onEvent,
|
|
8649
|
+
};
|
|
8650
|
+
return (jsxRuntime.jsx("div", { style: {
|
|
8651
|
+
...props.style,
|
|
8652
|
+
backgroundColor: props.rowColor
|
|
8653
|
+
}, children: jsxRuntime.jsx(SchedulerRow, { events: props.events, backgroundEvents: props.backgroundEvents, indicatorRows: props.indicatorRows, rowHeader: header, EventComp: props.EventComp, BackgroundEventComp: props.BackgroundEventComp, RowTitleComp: props.RowTitleComp, weekendLines: props.weekendLines, divisionLines: props.divisionLines, timeLinePercentage: props.timeLinePercentage, rowHeightInRem: props.rowHeightRem, onEvent: props.onEvent, contextMenuItems: props.contextMenuItems, visibleDays: props.visibleDays, selectedDate: props.selectedDate }) }, props.row.rowId));
|
|
8654
|
+
});
|
|
8655
|
+
// Outer (unmemoised) row: looks up per-row buckets from the shared `data`
|
|
8656
|
+
// object and forwards them as flat props to `RowContent`. Because the
|
|
8657
|
+
// referenced arrays are reused when their contents are unchanged
|
|
8658
|
+
// (see `groupByRowIdStable`), `RowContent.memo` will skip the work.
|
|
8659
|
+
const Row = ({ index, style, data }) => {
|
|
8660
|
+
const row = data.rows[index];
|
|
8661
|
+
const rowColor = data.groupRowColors
|
|
8662
|
+
? Math.floor(index / 2) % 2 === 0 ? data.evenColor : data.oddColor
|
|
8663
|
+
: index % 2 === 0 ? data.evenColor : data.oddColor;
|
|
8664
|
+
return (jsxRuntime.jsx(RowContent, { style: style, row: row, rowColor: rowColor, events: data.eventsByRow.get(row.rowId) ?? EMPTY_EVENTS, backgroundEvents: data.backgroundEventsByRow.get(row.rowId) ?? EMPTY_BG_EVENTS, indicatorRows: data.indicatorRowsByRow.get(row.rowId) ?? EMPTY_INDICATORS, EventComp: data.EventComp, BackgroundEventComp: data.BackgroundEventComp, RowTitleComp: data.RowTitleComp, rowHeaderWidth: data.rowHeaderWidth, rowHeightRem: data.rowHeightRem, weekendLines: data.weekendLines, divisionLines: data.divisionLines, timeLinePercentage: data.timeLinePercentage, selectedDate: data.selectedDate, visibleDays: data.visibleDays, contextMenuItems: data.contextMenuItems, onEvent: data.onEvent }));
|
|
8665
|
+
};
|
|
8666
|
+
// Bucket items by rowId, but reuse previous bucket arrays whenever a row's
|
|
8667
|
+
// contents have not changed. Keeping bucket references stable is essential
|
|
8668
|
+
// for `RowContent.memo` to skip work when only one row's events change
|
|
8669
|
+
// (e.g. on selection clicks).
|
|
8670
|
+
const groupByRowIdStable = (items, prev) => {
|
|
8671
|
+
const next = new Map();
|
|
8672
|
+
for (const item of items) {
|
|
8673
|
+
const bucket = next.get(item.rowId);
|
|
8674
|
+
if (bucket) {
|
|
8675
|
+
bucket.push(item);
|
|
8676
|
+
}
|
|
8677
|
+
else {
|
|
8678
|
+
next.set(item.rowId, [item]);
|
|
8679
|
+
}
|
|
8680
|
+
}
|
|
8681
|
+
if (!prev)
|
|
8682
|
+
return next;
|
|
8683
|
+
for (const [rowId, bucket] of next) {
|
|
8684
|
+
const prevBucket = prev.get(rowId);
|
|
8685
|
+
if (prevBucket
|
|
8686
|
+
&& prevBucket.length === bucket.length
|
|
8687
|
+
&& prevBucket.every((v, i) => v === bucket[i])) {
|
|
8688
|
+
next.set(rowId, prevBucket);
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
return next;
|
|
8692
|
+
};
|
|
8578
8693
|
const Scheduler = (props) => {
|
|
8579
|
-
const { header: headerContent, id, events: eventsState, backgroundEvents, contextMenuItems, EventComp, RowTitleComp, orderCategories = ["title"], useOrderCategory, onEvent, groupRowColors, rowHeaderWidth = 180, rowHeightRem = 1.75, } = props;
|
|
8694
|
+
const { header: headerContent, id, events: eventsState, backgroundEvents, indicatorRows: allIndicatorRows = [], contextMenuItems, EventComp, RowTitleComp, orderCategories = ["title"], useOrderCategory, onEvent, groupRowColors, rowHeaderWidth = 180, rowHeightRem = 1.75, } = props;
|
|
8580
8695
|
const BackgroundEventComp = props.BackgroundEventComp ?? BackgroundEvent;
|
|
8581
8696
|
const rows = useOrderCategory === false
|
|
8582
8697
|
? props.rows
|
|
@@ -8584,21 +8699,49 @@ const Scheduler = (props) => {
|
|
|
8584
8699
|
const instanceRef = React.useRef(null);
|
|
8585
8700
|
// const rowHeaderWidth = "180px";
|
|
8586
8701
|
const { selectedDate, visibleDays, isUtc, isHeaderVisible, visibleRows: stateVisibleRows } = props.state;
|
|
8587
|
-
const events = filterVisibleEvents(eventsState, selectedDate, visibleDays);
|
|
8702
|
+
const events = React.useMemo(() => filterVisibleEvents(eventsState, selectedDate, visibleDays), [eventsState, selectedDate, visibleDays]);
|
|
8588
8703
|
React.useEffect(() => {
|
|
8589
8704
|
instanceRef.current?.resetAfterIndex(0);
|
|
8590
|
-
}, [orderCategories, props.rows.length, events]);
|
|
8591
|
-
|
|
8592
|
-
|
|
8705
|
+
}, [orderCategories, props.rows.length, events, allIndicatorRows]);
|
|
8706
|
+
// Bucket events / backgroundEvents / indicatorRows by rowId once per render
|
|
8707
|
+
// instead of running events.filter() per row inside the row renderer.
|
|
8708
|
+
// Reuse previous bucket arrays when their contents are unchanged so the
|
|
8709
|
+
// memoised RowContent below can skip work (essential for selection clicks
|
|
8710
|
+
// to be cheap).
|
|
8711
|
+
const eventsByRowRef = React.useRef();
|
|
8712
|
+
const backgroundEventsByRowRef = React.useRef();
|
|
8713
|
+
const indicatorRowsByRowRef = React.useRef();
|
|
8714
|
+
const eventsByRow = React.useMemo(() => {
|
|
8715
|
+
const next = groupByRowIdStable(events, eventsByRowRef.current);
|
|
8716
|
+
eventsByRowRef.current = next;
|
|
8717
|
+
return next;
|
|
8718
|
+
}, [events]);
|
|
8719
|
+
const backgroundEventsByRow = React.useMemo(() => {
|
|
8720
|
+
const next = groupByRowIdStable(backgroundEvents, backgroundEventsByRowRef.current);
|
|
8721
|
+
backgroundEventsByRowRef.current = next;
|
|
8722
|
+
return next;
|
|
8723
|
+
}, [backgroundEvents]);
|
|
8724
|
+
const indicatorRowsByRow = React.useMemo(() => {
|
|
8725
|
+
const next = groupByRowIdStable(allIndicatorRows, indicatorRowsByRowRef.current);
|
|
8726
|
+
indicatorRowsByRowRef.current = next;
|
|
8727
|
+
return next;
|
|
8728
|
+
}, [allIndicatorRows]);
|
|
8729
|
+
const totalHeightRem = rows.reduce((acc, row) => {
|
|
8730
|
+
const filteredEvents = eventsByRow.get(row.rowId) ?? [];
|
|
8593
8731
|
const innerRows = separateEventsToInnerRows(filteredEvents);
|
|
8594
|
-
|
|
8732
|
+
const eventHeight = Math.max(innerRows.length, 1) * rowHeightRem;
|
|
8733
|
+
const hasIndicators = indicatorRowsByRow.has(row.rowId);
|
|
8734
|
+
return acc + eventHeight + (hasIndicators ? INDICATOR_HEIGHT_REM : 0);
|
|
8595
8735
|
}, 0);
|
|
8596
|
-
const
|
|
8736
|
+
const schedulerContentHeight = stateVisibleRows != null
|
|
8737
|
+
? Math.min(totalHeightRem, stateVisibleRows * rowHeightRem)
|
|
8738
|
+
: Math.max(totalHeightRem, rowHeightRem);
|
|
8597
8739
|
const totalHours = visibleDays * 24;
|
|
8598
8740
|
const [timeLinePercentage, setTimeLinePercentage] = React.useState(0);
|
|
8741
|
+
const divisions = React.useMemo(() => getDefaultDivisions(visibleDays, selectedDate), [visibleDays, selectedDate]);
|
|
8599
8742
|
const header = {
|
|
8600
8743
|
content: headerContent,
|
|
8601
|
-
divisions
|
|
8744
|
+
divisions,
|
|
8602
8745
|
visibleDays: visibleDays,
|
|
8603
8746
|
width: rowHeaderWidth,
|
|
8604
8747
|
selectedDate,
|
|
@@ -8608,9 +8751,8 @@ const Scheduler = (props) => {
|
|
|
8608
8751
|
};
|
|
8609
8752
|
const evenColor = "var(--cw-color-surface-container-low)";
|
|
8610
8753
|
const oddColor = "var(--cw-color-surface-container)";
|
|
8611
|
-
const
|
|
8612
|
-
const
|
|
8613
|
-
const divisionLines = getLinesByDivisions(header.divisions);
|
|
8754
|
+
const weekendsLines = React.useMemo(() => getWeekendLinesByDatesVisible(selectedDate, visibleDays), [selectedDate, visibleDays]);
|
|
8755
|
+
const divisionLines = React.useMemo(() => getLinesByDivisions(divisions), [divisions, visibleDays]);
|
|
8614
8756
|
// Timeline percentage calculation
|
|
8615
8757
|
React.useEffect(() => {
|
|
8616
8758
|
const updateTimeLinePercentage = () => {
|
|
@@ -8621,30 +8763,55 @@ const Scheduler = (props) => {
|
|
|
8621
8763
|
const interval = setInterval(updateTimeLinePercentage, refreshMilliSeconds);
|
|
8622
8764
|
return () => clearInterval(interval);
|
|
8623
8765
|
}, [selectedDate, isUtc, totalHours]);
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8766
|
+
const itemData = React.useMemo(() => ({
|
|
8767
|
+
rows,
|
|
8768
|
+
eventsByRow,
|
|
8769
|
+
backgroundEventsByRow,
|
|
8770
|
+
indicatorRowsByRow,
|
|
8771
|
+
EventComp: EventComp,
|
|
8772
|
+
BackgroundEventComp,
|
|
8773
|
+
RowTitleComp: RowTitleComp,
|
|
8774
|
+
rowHeaderWidth,
|
|
8775
|
+
rowHeightRem,
|
|
8776
|
+
weekendLines: weekendsLines,
|
|
8777
|
+
divisionLines,
|
|
8778
|
+
timeLinePercentage,
|
|
8779
|
+
selectedDate,
|
|
8780
|
+
visibleDays,
|
|
8781
|
+
contextMenuItems,
|
|
8782
|
+
onEvent,
|
|
8783
|
+
groupRowColors,
|
|
8784
|
+
evenColor,
|
|
8785
|
+
oddColor,
|
|
8786
|
+
}), [
|
|
8787
|
+
rows,
|
|
8788
|
+
eventsByRow,
|
|
8789
|
+
backgroundEventsByRow,
|
|
8790
|
+
indicatorRowsByRow,
|
|
8791
|
+
EventComp,
|
|
8792
|
+
BackgroundEventComp,
|
|
8793
|
+
RowTitleComp,
|
|
8794
|
+
rowHeaderWidth,
|
|
8795
|
+
rowHeightRem,
|
|
8796
|
+
weekendsLines,
|
|
8797
|
+
divisionLines,
|
|
8798
|
+
timeLinePercentage,
|
|
8799
|
+
selectedDate,
|
|
8800
|
+
visibleDays,
|
|
8801
|
+
contextMenuItems,
|
|
8802
|
+
onEvent,
|
|
8803
|
+
groupRowColors,
|
|
8804
|
+
]);
|
|
8640
8805
|
const getItemSize = React.useCallback((index) => {
|
|
8641
8806
|
const row = rows[index];
|
|
8642
|
-
const filteredEvents =
|
|
8807
|
+
const filteredEvents = eventsByRow.get(row.rowId) ?? [];
|
|
8643
8808
|
const innerRows = separateEventsToInnerRows(filteredEvents);
|
|
8644
8809
|
const rowsNumber = innerRows.length > 0 ? innerRows.length : 1;
|
|
8645
8810
|
const pixelsInRem = 16;
|
|
8646
|
-
|
|
8647
|
-
|
|
8811
|
+
const hasIndicators = indicatorRowsByRow.has(row.rowId);
|
|
8812
|
+
const indicatorPixels = hasIndicators ? INDICATOR_HEIGHT_REM * pixelsInRem : 0;
|
|
8813
|
+
return rowsNumber * rowHeightRem * pixelsInRem + indicatorPixels;
|
|
8814
|
+
}, [rows, eventsByRow, indicatorRowsByRow, rowHeightRem]);
|
|
8648
8815
|
// Render
|
|
8649
8816
|
return (jsxRuntime.jsxs("div", { id: id, style: {
|
|
8650
8817
|
position: "relative",
|
|
@@ -8655,7 +8822,7 @@ const Scheduler = (props) => {
|
|
|
8655
8822
|
position: "sticky",
|
|
8656
8823
|
top: 0,
|
|
8657
8824
|
zIndex: 1,
|
|
8658
|
-
}, children: jsxRuntime.jsx(SchedulerHeader, { ...header }) })), jsxRuntime.jsx(reactWindow.VariableSizeList, { height: schedulerContentHeight * 16, itemCount: rows.length, itemSize: getItemSize, width: "100%", style: { overflowX: "hidden" }, ref: instanceRef, className: styles$2["hide-scrollbar"], children: Row })] }));
|
|
8825
|
+
}, children: jsxRuntime.jsx(SchedulerHeader, { ...header }) })), jsxRuntime.jsx(reactWindow.VariableSizeList, { height: schedulerContentHeight * 16, itemCount: rows.length, itemSize: getItemSize, itemData: itemData, width: "100%", style: { overflowX: "hidden" }, ref: instanceRef, className: styles$2["hide-scrollbar"], children: Row })] }));
|
|
8659
8826
|
};
|
|
8660
8827
|
|
|
8661
8828
|
class UiEvent {
|
|
@@ -9018,13 +9185,13 @@ const PinRowHeader = ({ value, width, onEvent }) => {
|
|
|
9018
9185
|
jsxRuntime.jsxs("span", { className: styles["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxRuntime.jsxs("span", { children: ["-", value.subtitle2] })] })] }), isLoading ? jsxRuntime.jsx("span", { className: "cwi-icons cwi-spinner" }) : undefined] }) }, value.rowId) }, value.rowId);
|
|
9019
9186
|
};
|
|
9020
9187
|
|
|
9021
|
-
const SuperScheduler = ({ id, state, header, rows, events, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, contextMenuItems, onEvent, rowHeightRem = 1.75 }) => {
|
|
9188
|
+
const SuperScheduler = ({ id, state, header, rows, events, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75 }) => {
|
|
9022
9189
|
const pinnedRows = rows.filter((it) => it.isPinned);
|
|
9023
9190
|
const notPinnedRows = rows.filter((it) => !it.isPinned);
|
|
9024
9191
|
const isFirstVisible = pinnedRows.length > 0;
|
|
9025
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFirstVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Scheduler, { id: `${id}-pinned`, state: state, header: header, rows: pinnedRows, events: events, backgroundEvents: backgroundEvents, contextMenuItems: contextMenuItems, orderCategories: pinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
|
|
9192
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFirstVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Scheduler, { id: `${id}-pinned`, state: state, header: header, rows: pinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: pinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
|
|
9026
9193
|
onEvent(new OnClearPinned());
|
|
9027
|
-
}, children: "Clear pinned" }) })] })), jsxRuntime.jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem })] }));
|
|
9194
|
+
}, children: "Clear pinned" }) })] })), jsxRuntime.jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem })] }));
|
|
9028
9195
|
};
|
|
9029
9196
|
|
|
9030
9197
|
const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder = "Search airport…", required = false, cblConfig, className = "", value, disabled = false, displayMode, initialDisplayText, labelProps, alignProps, width }) => {
|