@cwellt_software/cwellt-reactjs-lib 1.2.16 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -251,7 +251,7 @@ const CwMessage = props => {
251
251
  }, props.duration ?? CW_DEFAULT_MESSAGE_DURATION);
252
252
  return () => clearTimeout(timer);
253
253
  }, [props]);
254
- 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] }));
254
+ 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] }));
255
255
  };
256
256
  /**
257
257
  * Hook for displaying inline messages within specific components.
@@ -314,11 +314,11 @@ class CwMessageManager {
314
314
  document.body.prepend(this.messageWrapper);
315
315
  this.root = client.createRoot(this.messageWrapper); // Create a root at the messageWrapper
316
316
  }
317
- showMessage(message, type, duration) {
317
+ showMessage(message, type, duration, onClick) {
318
318
  const msg = document.createElement("div");
319
319
  this.messageWrapper?.prepend(msg);
320
320
  const msgRoot = client.createRoot(msg); // Create a root for the new message
321
- msgRoot.render(jsxRuntime.jsx(CwMessage, { message: message, messageType: type, duration: duration, onClose: () => this.closeMessage(msgRoot) }));
321
+ msgRoot.render(jsxRuntime.jsx(CwMessage, { message: message, messageType: type, duration: duration, onClick: onClick, onClose: () => this.closeMessage(msgRoot) }));
322
322
  }
323
323
  closeMessage(msgRoot) {
324
324
  msgRoot.unmount(); // Unmount the message root
@@ -340,8 +340,8 @@ class CwMessageManager {
340
340
  *
341
341
  * @note For inline messages within components, use `CwNote` or `useCwMessage` hook instead
342
342
  */
343
- function CwDisplayMessage(message, type, duration) {
344
- CwMessageManager.getInstance().showMessage(message, type, duration);
343
+ function CwDisplayMessage(message, type, duration, onClick) {
344
+ CwMessageManager.getInstance().showMessage(message, type, duration, onClick);
345
345
  }
346
346
 
347
347
  /**
@@ -9049,6 +9049,170 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9049
9049
  }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected airport", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "control-tower" })) })] })] }), showDropdown && options.length > 0 && (jsxRuntime.jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { className: index === highlightedIndex ? "highlighted" : "", onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9050
9050
  };
9051
9051
 
9052
+ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", required = false, cblConfig, className = "", value, disabled = false, initialDisplayText, labelProps, alignProps, width }) => {
9053
+ const [inputValue, setInputValue] = React.useState("");
9054
+ const [options, setOptions] = React.useState([]);
9055
+ const [crewmembers, setCrewmembers] = React.useState([]);
9056
+ const [isLoading, setIsLoading] = React.useState(false);
9057
+ const [isInitialLoading, setIsInitialLoading] = React.useState(false);
9058
+ const [showDropdown, setShowDropdown] = React.useState(false);
9059
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
9060
+ const [tooltipText, setTooltipText] = React.useState("");
9061
+ const inputRef = React.useRef(null);
9062
+ const dropdownRef = React.useRef(null);
9063
+ const searchTimeoutRef = React.useRef();
9064
+ const getDisplayText = React.useCallback((crew) => {
9065
+ return `${crew.threeLetterCode} - ${crew.lastName} ${crew.firstName}`;
9066
+ }, []);
9067
+ const fetchCrewmemberData = React.useCallback(async (crewmemberId) => {
9068
+ setIsInitialLoading(true);
9069
+ try {
9070
+ const response = await fetch(`${cblConfig}controls/cblFindCrew/cblFindCrew/GetCrewmember?crewmemberId=${crewmemberId}`);
9071
+ const result = await response.json();
9072
+ const display = getDisplayText(result);
9073
+ setCrewmembers([result]);
9074
+ setOptions([{ value: result.id, text: display }]);
9075
+ setInputValue(display);
9076
+ setTooltipText(display);
9077
+ }
9078
+ catch (error) {
9079
+ console.error("Error fetching crewmember data:", error);
9080
+ }
9081
+ finally {
9082
+ setIsInitialLoading(false);
9083
+ }
9084
+ }, [cblConfig, getDisplayText]);
9085
+ const searchCrewmembers = React.useCallback(async (searchText) => {
9086
+ if (searchText.length < 2) {
9087
+ setOptions([]);
9088
+ setCrewmembers([]);
9089
+ setShowDropdown(false);
9090
+ return;
9091
+ }
9092
+ setIsLoading(true);
9093
+ try {
9094
+ const response = await fetch(`${cblConfig}controls/cblFindCrew/cblFindCrew/SearchCrewCodeName?text=${encodeURIComponent(searchText)}`);
9095
+ const results = await response.json();
9096
+ const newOptions = results.map(crew => ({
9097
+ value: crew.id,
9098
+ text: getDisplayText(crew)
9099
+ }));
9100
+ setOptions(newOptions);
9101
+ setCrewmembers(results);
9102
+ setShowDropdown(newOptions.length > 0);
9103
+ setHighlightedIndex(-1);
9104
+ }
9105
+ catch (error) {
9106
+ console.error("Error searching crewmembers:", error);
9107
+ setOptions([]);
9108
+ setCrewmembers([]);
9109
+ setShowDropdown(false);
9110
+ }
9111
+ finally {
9112
+ setIsLoading(false);
9113
+ }
9114
+ }, [cblConfig, getDisplayText]);
9115
+ const debouncedSearch = React.useCallback((searchText) => {
9116
+ if (searchTimeoutRef.current) {
9117
+ window.clearTimeout(searchTimeoutRef.current);
9118
+ }
9119
+ searchTimeoutRef.current = window.setTimeout(() => {
9120
+ searchCrewmembers(searchText);
9121
+ }, 300);
9122
+ }, [searchCrewmembers]);
9123
+ const handleInputChange = (e) => {
9124
+ const newValue = e.target.value;
9125
+ setInputValue(newValue);
9126
+ if (newValue !== inputValue) {
9127
+ debouncedSearch(newValue);
9128
+ }
9129
+ };
9130
+ const handleOptionSelect = (optionValue) => {
9131
+ const selectedCrew = crewmembers.find(c => c.id === optionValue);
9132
+ if (!selectedCrew)
9133
+ return;
9134
+ setShowDropdown(false);
9135
+ const display = getDisplayText(selectedCrew);
9136
+ setInputValue(display);
9137
+ setTooltipText(display);
9138
+ handleChange(optionValue);
9139
+ };
9140
+ const handleKeyDown = (e) => {
9141
+ if (!showDropdown || options.length === 0)
9142
+ return;
9143
+ switch (e.key) {
9144
+ case "ArrowDown":
9145
+ e.preventDefault();
9146
+ setHighlightedIndex(prev => prev < options.length - 1 ? prev + 1 : 0);
9147
+ break;
9148
+ case "ArrowUp":
9149
+ e.preventDefault();
9150
+ setHighlightedIndex(prev => prev > 0 ? prev - 1 : options.length - 1);
9151
+ break;
9152
+ case "Enter":
9153
+ e.preventDefault();
9154
+ if (highlightedIndex >= 0 && highlightedIndex < options.length) {
9155
+ handleOptionSelect(options[highlightedIndex].value);
9156
+ }
9157
+ break;
9158
+ case "Escape":
9159
+ setShowDropdown(false);
9160
+ setHighlightedIndex(-1);
9161
+ break;
9162
+ }
9163
+ };
9164
+ React.useEffect(() => {
9165
+ const handleClickOutside = (event) => {
9166
+ if (dropdownRef.current &&
9167
+ !dropdownRef.current.contains(event.target) &&
9168
+ !inputRef.current?.contains(event.target)) {
9169
+ setShowDropdown(false);
9170
+ setHighlightedIndex(-1);
9171
+ }
9172
+ };
9173
+ document.addEventListener("mousedown", handleClickOutside);
9174
+ return () => document.removeEventListener("mousedown", handleClickOutside);
9175
+ }, []);
9176
+ React.useEffect(() => {
9177
+ if (value && value !== 0 && value !== -1) {
9178
+ if (initialDisplayText) {
9179
+ setInputValue(initialDisplayText);
9180
+ setTooltipText(initialDisplayText);
9181
+ }
9182
+ else {
9183
+ fetchCrewmemberData(value);
9184
+ }
9185
+ }
9186
+ }, [value, fetchCrewmemberData, initialDisplayText]);
9187
+ React.useEffect(() => {
9188
+ if (!value || value === 0 || value === -1) {
9189
+ setInputValue("");
9190
+ setTooltipText("");
9191
+ setOptions([]);
9192
+ setCrewmembers([]);
9193
+ }
9194
+ }, [value]);
9195
+ const handleInputFocus = () => {
9196
+ if (options.length > 0) {
9197
+ setShowDropdown(true);
9198
+ }
9199
+ };
9200
+ const handleClear = () => {
9201
+ setInputValue("");
9202
+ setTooltipText("");
9203
+ setOptions([]);
9204
+ setCrewmembers([]);
9205
+ setShowDropdown(false);
9206
+ handleChange(0);
9207
+ inputRef.current?.focus();
9208
+ };
9209
+ const direction = alignProps?.flexDirection || "row";
9210
+ return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className}`, style: {
9211
+ ...(width ? { width } : {}),
9212
+ ...(labelProps?.labelWidth ? { '--label-width': labelProps.labelWidth } : {})
9213
+ }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "person" })) })] })] }), showDropdown && options.length > 0 && (jsxRuntime.jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { className: index === highlightedIndex ? "highlighted" : "", onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9214
+ };
9215
+
9052
9216
  exports.CblDragAndDrop = CblDragAndDrop;
9053
9217
  exports.CwAccordionContainer = CwAccordionContainer;
9054
9218
  exports.CwAlign = CwAlign;
@@ -9079,6 +9243,7 @@ exports.CwExpandable = CwExpandable;
9079
9243
  exports.CwFileUpload = CwFileUpload;
9080
9244
  exports.CwFileUploadMultiple = CwFileUploadMultiple;
9081
9245
  exports.CwFindAirport = CwFindAirport;
9246
+ exports.CwFindCrewmember = CwFindCrewmember;
9082
9247
  exports.CwGenericTooltip = CwGenericTooltip;
9083
9248
  exports.CwHeadingMain = CwHeadingMain;
9084
9249
  exports.CwHeadingSecond = CwHeadingSecond;