diff --git a/packages/lib/src/text-input/Suggestions.tsx b/packages/lib/src/text-input/Suggestions.tsx
index 9fbad145f..4d8ad9c9f 100644
--- a/packages/lib/src/text-input/Suggestions.tsx
+++ b/packages/lib/src/text-input/Suggestions.tsx
@@ -5,15 +5,10 @@ import Suggestion from "./Suggestion";
import { SuggestionsProps } from "./types";
import DxcIcon from "../icon/Icon";
import scrollbarStyles from "../styles/scroll";
+import DxcBleed from "../bleed/Bleed";
const SuggestionsContainer = styled.div`
- box-sizing: border-box;
max-height: 304px;
- padding: var(--spacing-padding-xxs) var(--spacing-padding-none);
- background-color: var(--color-bg-neutral-lightest);
- border: var(--border-width-s) var(--border-style-default) var(--border-color-neutral-medium);
- border-radius: var(--border-radius-s);
- box-shadow: var(--shadow-200);
color: var(--color-fg-neutral-dark);
font-family: var(--typography-font-family);
font-size: var(--typography-label-m);
@@ -66,38 +61,40 @@ const Suggestions = ({
}, [visualFocusIndex]);
return (
- {
- event.preventDefault();
- }}
- style={styles}
- >
- {isSearching ? (
-
- {translatedLabels.textInput.searchingMessage}
-
- ) : searchHasErrors ? (
-
-
- {translatedLabels.textInput.fetchingDataErrorMessage}
-
- ) : (
-
- {suggestions.map((suggestion, index) => (
-
- ))}
-
- )}
-
+
+ {
+ event.preventDefault();
+ }}
+ style={styles}
+ >
+ {isSearching ? (
+
+ {translatedLabels.textInput.searchingMessage}
+
+ ) : searchHasErrors ? (
+
+
+ {translatedLabels.textInput.fetchingDataErrorMessage}
+
+ ) : (
+
+ {suggestions.map((suggestion, index) => (
+
+ ))}
+
+ )}
+
+
);
};
diff --git a/packages/lib/src/text-input/TextInput.tsx b/packages/lib/src/text-input/TextInput.tsx
index 71b56b0ba..6bf7a71b5 100644
--- a/packages/lib/src/text-input/TextInput.tsx
+++ b/packages/lib/src/text-input/TextInput.tsx
@@ -1,4 +1,3 @@
-import * as Popover from "@radix-ui/react-popover";
import {
ChangeEvent,
FocusEvent,
@@ -24,17 +23,22 @@ import Suggestions from "./Suggestions";
import TextInputPropsType, { AutosuggestWrapperProps, RefType } from "./types";
import {
calculateWidth,
+ decrementNumber,
+ getNumberErrorMessage,
hasSuggestions,
+ incrementNumber,
isNumberIncorrect,
isRequired,
makeCancelable,
patternMismatch,
+ setNumberProps,
} from "./utils";
import HelperText from "../styles/forms/HelperText";
import Label from "../styles/forms/Label";
import ErrorMessage from "../styles/forms/ErrorMessage";
import inputStylesByState from "../styles/forms/inputStylesByState";
import { getLengthErrorMessage } from "../common/utils";
+import DxcPopover from "../popover/Popover";
const TextInputContainer = styled.div<{
margin: TextInputPropsType["margin"];
@@ -154,65 +158,41 @@ const DxcTextInput = forwardRef(
const [isAutosuggestError, changeIsAutosuggestError] = useState(false);
const [filteredSuggestions, changeFilteredSuggestions] = useState([]);
const [visualFocusIndex, changeVisualFocusIndex] = useState(-1);
- const [portalContainer, setPortalContainer] = useState(null);
const width = useWidth(inputContainerRef);
- useEffect(() => {
- setPortalContainer(document?.getElementById(`${inputId}-portal`));
- }, []);
const autosuggestWrapperFunction = (children: ReactNode) => (
- 0 || isSearching || isAutosuggestError)}>
-
- {children}
-
- {portalContainer && (
-
- {
- // Avoid select to lose focus when the list is closed
- event.preventDefault();
- }}
- onOpenAutoFocus={(event) => {
- // Avoid select to lose focus when the list is opened
- event.preventDefault();
- }}
- sideOffset={4}
- style={{ zIndex: "var(--z-textinput)" }}
- >
- {
- changeValue(suggestion);
- closeSuggestions();
- }}
- suggestions={filteredSuggestions}
- styles={{ width }}
- value={value ?? innerValue}
- visualFocusIndex={visualFocusIndex}
- />
-
-
- )}
-
+ 0 || isSearching || isAutosuggestError)}
+ onOpenAutoFocus={(event) => {
+ // Avoid select to lose focus when the list is opened
+ event.preventDefault();
+ }}
+ onCloseAutoFocus={(event) => {
+ // Avoid select to lose focus when the list is closed
+ event.preventDefault();
+ }}
+ popoverContent={
+ {
+ changeValue(suggestion);
+ closeSuggestions();
+ }}
+ suggestions={filteredSuggestions}
+ styles={{ width }}
+ value={value ?? innerValue}
+ visualFocusIndex={visualFocusIndex}
+ />
+ }
+ >
+ {children}
+
);
- const getNumberErrorMessage = (checkedValue: number) =>
- numberInputContext?.minNumber != null && checkedValue < numberInputContext?.minNumber
- ? translatedLabels.numberInput.valueGreaterThanOrEqualToErrorMessage?.(numberInputContext.minNumber)
- : numberInputContext?.maxNumber != null && checkedValue > numberInputContext?.maxNumber
- ? translatedLabels.numberInput.valueLessThanOrEqualToErrorMessage?.(numberInputContext.maxNumber)
- : undefined;
-
const openSuggestions = () => {
if (hasSuggestions(suggestions)) {
changeIsOpen(true);
@@ -256,70 +236,21 @@ const DxcTextInput = forwardRef(
numberInputContext?.typeNumber === "number" &&
isNumberIncorrect(Number(newValue), numberInputContext?.minNumber, numberInputContext?.maxNumber)
) {
- onChange?.({ value: formattedValue, error: getNumberErrorMessage(Number(newValue)) });
+ onChange?.({
+ value: formattedValue,
+ error: getNumberErrorMessage(
+ Number(newValue),
+ translatedLabels.numberInput.valueGreaterThanOrEqualToErrorMessage,
+ translatedLabels.numberInput.valueLessThanOrEqualToErrorMessage,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ ),
+ });
} else {
onChange?.({ value: formattedValue });
}
};
- const decrementNumber = (currentValue = value ?? innerValue) => {
- if (!disabled && !readOnly) {
- const numberValue = Number(currentValue);
- const steppedValue =
- Math.round((numberValue - (numberInputContext?.stepNumber ?? 0) + Number.EPSILON) * 100) / 100;
-
- if (currentValue !== "") {
- if (
- numberInputContext?.minNumber != null &&
- (numberValue < numberInputContext?.minNumber || steppedValue < numberInputContext?.minNumber)
- ) {
- changeValue(numberValue);
- } else if (numberInputContext?.maxNumber != null && numberValue > numberInputContext?.maxNumber) {
- changeValue(numberInputContext?.maxNumber);
- } else if (numberValue === numberInputContext?.minNumber) {
- changeValue(numberInputContext?.minNumber);
- } else {
- changeValue(steppedValue);
- }
- } else if (numberInputContext?.minNumber != null && numberInputContext?.minNumber >= 0) {
- changeValue(numberInputContext?.minNumber);
- } else if (numberInputContext?.maxNumber != null && numberInputContext?.maxNumber < 0) {
- changeValue(numberInputContext?.maxNumber);
- } else if (numberInputContext?.stepNumber != null) {
- changeValue(-numberInputContext.stepNumber);
- }
- }
- };
-
- const incrementNumber = (currentValue = value ?? innerValue) => {
- if (!disabled && !readOnly) {
- const numberValue = Number(currentValue);
- const steppedValue =
- Math.round((numberValue + (numberInputContext?.stepNumber ?? 0) + Number.EPSILON) * 100) / 100;
-
- if (currentValue !== "") {
- if (
- numberInputContext?.maxNumber != null &&
- (numberValue > numberInputContext?.maxNumber || steppedValue > numberInputContext?.maxNumber)
- ) {
- changeValue(numberValue);
- } else if (numberInputContext?.minNumber != null && numberValue < numberInputContext?.minNumber) {
- changeValue(numberInputContext?.minNumber);
- } else if (numberValue === numberInputContext?.maxNumber) {
- changeValue(numberInputContext?.maxNumber);
- } else {
- changeValue(steppedValue);
- }
- } else if (numberInputContext?.minNumber != null && numberInputContext?.minNumber > 0) {
- changeValue(numberInputContext?.minNumber);
- } else if (numberInputContext?.maxNumber != null && numberInputContext?.maxNumber <= 0) {
- changeValue(numberInputContext?.maxNumber);
- } else if (numberInputContext?.stepNumber != null) {
- changeValue(numberInputContext.stepNumber);
- }
- }
- };
-
const handleInputContainerOnClick = () => {
if (document.activeElement !== actionRef.current) {
inputRef.current?.focus();
@@ -360,7 +291,16 @@ const DxcTextInput = forwardRef(
numberInputContext?.typeNumber === "number" &&
isNumberIncorrect(Number(event.target.value), numberInputContext?.minNumber, numberInputContext?.maxNumber)
) {
- onBlur?.({ value: event.target.value, error: getNumberErrorMessage(Number(event.target.value)) });
+ onBlur?.({
+ value: event.target.value,
+ error: getNumberErrorMessage(
+ Number(event.target.value),
+ translatedLabels.numberInput.valueGreaterThanOrEqualToErrorMessage,
+ translatedLabels.numberInput.valueLessThanOrEqualToErrorMessage,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ ),
+ });
} else {
onBlur?.({ value: event.target.value });
}
@@ -371,7 +311,15 @@ const DxcTextInput = forwardRef(
case "ArrowDown":
event.preventDefault();
if (numberInputContext?.typeNumber === "number") {
- decrementNumber();
+ decrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
} else {
openSuggestions();
if (!isAutosuggestError && !isSearching && filteredSuggestions.length > 0) {
@@ -389,7 +337,15 @@ const DxcTextInput = forwardRef(
case "ArrowUp":
event.preventDefault();
if (numberInputContext?.typeNumber === "number") {
- incrementNumber();
+ incrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
} else {
openSuggestions();
if (!isAutosuggestError && !isSearching && filteredSuggestions.length > 0) {
@@ -435,9 +391,25 @@ const DxcTextInput = forwardRef(
const handleNumberInputWheel = (event: WheelEvent) => {
if (document.activeElement === inputRef.current) {
if (event.deltaY < 0) {
- incrementNumber(inputRef.current?.value);
+ incrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
} else {
- decrementNumber(inputRef.current?.value);
+ decrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
}
}
};
@@ -451,21 +423,30 @@ const DxcTextInput = forwardRef(
};
const handleDecrementActionOnClick = () => {
- decrementNumber();
+ decrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
inputRef.current?.focus();
};
const handleIncrementActionOnClick = () => {
- incrementNumber();
+ incrementNumber(
+ inputRef.current?.value,
+ disabled,
+ readOnly,
+ changeValue,
+ numberInputContext?.stepNumber,
+ numberInputContext?.minNumber,
+ numberInputContext?.maxNumber
+ );
inputRef.current?.focus();
};
- const setNumberProps = (type?: string, min?: number, max?: number, step?: number) => {
- if (min != null) inputRef.current?.setAttribute("min", min.toString());
- if (max != null) inputRef.current?.setAttribute("max", max.toString());
- if (step != null) inputRef.current?.setAttribute("step", step.toString());
- if (type != null) inputRef.current?.setAttribute("type", type);
- };
-
useEffect(() => {
if (typeof suggestions === "function") {
changeIsSearching(true);
@@ -501,7 +482,8 @@ const DxcTextInput = forwardRef(
numberInputContext.typeNumber,
numberInputContext.minNumber,
numberInputContext.maxNumber,
- numberInputContext.stepNumber
+ numberInputContext.stepNumber,
+ inputRef.current ?? undefined
);
}
}, [value, innerValue, suggestions, numberInputContext]);
@@ -624,7 +606,6 @@ const DxcTextInput = forwardRef(
{!disabled && typeof error === "string" && }
- {hasSuggestions(suggestions) && }
>
);
}
diff --git a/packages/lib/src/text-input/utils.ts b/packages/lib/src/text-input/utils.ts
index 3f0c73b69..c8e99966c 100644
--- a/packages/lib/src/text-input/utils.ts
+++ b/packages/lib/src/text-input/utils.ts
@@ -71,3 +71,89 @@ export const transformSpecialChars = (str: string) => {
}
return value;
};
+
+export const getNumberErrorMessage = (
+ checkedValue: number,
+ valueGreaterThanOrEqualToErrorMessage: (value: number) => string,
+ valueLessThanOrEqualToErrorMessage: (value: number) => string,
+ minNumber?: number,
+ maxNumber?: number
+) =>
+ minNumber != null && checkedValue < minNumber
+ ? valueGreaterThanOrEqualToErrorMessage?.(minNumber)
+ : maxNumber != null && checkedValue > maxNumber
+ ? valueLessThanOrEqualToErrorMessage?.(maxNumber)
+ : undefined;
+
+export const decrementNumber = (
+ currentValue: string | undefined,
+ disabled: boolean,
+ readOnly: boolean,
+ changeValue: (value: number | string) => void,
+ stepNumber?: number,
+ minNumber?: number,
+ maxNumber?: number
+) => {
+ if (!disabled && !readOnly) {
+ const numberValue = Number(currentValue);
+ const steppedValue = Math.round((numberValue - (stepNumber ?? 0) + Number.EPSILON) * 100) / 100;
+
+ if (currentValue !== "") {
+ if (minNumber != null && (numberValue < minNumber || steppedValue < minNumber)) {
+ changeValue(numberValue);
+ } else if (maxNumber != null && numberValue > maxNumber) {
+ changeValue(maxNumber);
+ } else if (numberValue === minNumber) {
+ changeValue(minNumber);
+ } else {
+ changeValue(steppedValue);
+ }
+ } else if (minNumber != null && minNumber >= 0) {
+ changeValue(minNumber);
+ } else if (maxNumber != null && maxNumber < 0) {
+ changeValue(maxNumber);
+ } else if (stepNumber != null) {
+ changeValue(-stepNumber);
+ }
+ }
+};
+
+export const incrementNumber = (
+ currentValue: string | undefined,
+ disabled: boolean,
+ readOnly: boolean,
+ changeValue: (value: number | string) => void,
+ stepNumber?: number,
+ minNumber?: number,
+ maxNumber?: number
+) => {
+ if (!disabled && !readOnly) {
+ const numberValue = Number(currentValue);
+ const steppedValue = Math.round((numberValue + (stepNumber ?? 0) + Number.EPSILON) * 100) / 100;
+
+ if (currentValue !== "") {
+ if (maxNumber != null && (numberValue > maxNumber || steppedValue > maxNumber)) {
+ changeValue(numberValue);
+ } else if (minNumber != null && numberValue < minNumber) {
+ changeValue(minNumber);
+ } else if (numberValue === maxNumber) {
+ changeValue(maxNumber);
+ } else {
+ changeValue(steppedValue);
+ }
+ } else if (minNumber != null && minNumber > 0) {
+ changeValue(minNumber);
+ } else if (maxNumber != null && maxNumber <= 0) {
+ changeValue(maxNumber);
+ } else if (stepNumber != null) {
+ changeValue(stepNumber);
+ }
+ }
+};
+
+export const setNumberProps = (type?: string, min?: number, max?: number, step?: number, ref?: HTMLInputElement) => {
+ if (min != null) ref?.setAttribute("min", min.toString());
+ if (max != null) ref?.setAttribute("max", max.toString());
+ if (step != null) ref?.setAttribute("step", step.toString());
+ if (type != null) ref?.setAttribute("type", type);
+};