diff --git a/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js b/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js
index b46ab8939e..fff7f091ae 100644
--- a/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js
+++ b/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js
@@ -1,5 +1,6 @@
import { useState, useRef, useEffect } from 'react';
import { useGridStore } from '@/_stores/gridStore';
+//eslint-disable-next-line import/no-unresolved
import { getCountryCallingCode } from 'react-phone-number-input';
export const useInput = ({
@@ -29,7 +30,7 @@ export const useInput = ({
const [isFocused, setIsFocused] = useState(false);
const [labelWidth, setLabelWidth] = useState(0);
const [iconVisibility, setIconVisibility] = useState(false);
- const [country, setCountry] = useState(properties.defaultCountry);
+ const [country, setCountry] = useState(properties.defaultCountry || 'US');
const { isValid, validationError } = validationStatus;
const isMandatory = validation?.mandatory ?? false;
@@ -96,7 +97,6 @@ export const useInput = ({
}, [validate]);
useEffect(() => {
- if (isInitialRender.current) return;
if (inputType === 'phone') {
let code = getCountryCallingCodeSafe(country);
setInputValue(`+${code}${properties.value}`);
@@ -105,15 +105,6 @@ export const useInput = ({
}
}, [properties.value]);
- // useEffect(() => {
- // if (isInitialRender.current && inputType!=="phone") return;
-
- // setExposedVariable('setValue',
- // async function (value,country){
-
- // }
- // )
-
useEffect(() => {
if (inputType !== 'phone') return;
setExposedVariable('setValue', async function (value, countryCode = country) {
diff --git a/frontend/src/AppBuilder/Widgets/Form/FormUtils.js b/frontend/src/AppBuilder/Widgets/Form/FormUtils.js
index f8366e0b29..9769257b58 100644
--- a/frontend/src/AppBuilder/Widgets/Form/FormUtils.js
+++ b/frontend/src/AppBuilder/Widgets/Form/FormUtils.js
@@ -97,6 +97,8 @@ export function generateUIComponents(JSONSchema, advanced, componentName = '') {
if (uiComponentsDraft?.length > 0 && uiComponentsDraft[index * 2 + 1]) {
switch (typeResolver(value?.type)) {
case 'TextInput':
+ case 'EmailInput':
+ case 'PhoneInput':
if (value?.styles?.backgroundColor)
uiComponentsDraft[index * 2 + 1]['definition']['styles']['backgroundColor'] =
value?.styles?.backgroundColor;
@@ -127,6 +129,11 @@ export function generateUIComponents(JSONSchema, advanced, componentName = '') {
if (value?.value) uiComponentsDraft[index * 2 + 1]['definition']['properties']['value'] = value?.value;
if (value?.placeholder)
uiComponentsDraft[index * 2 + 1]['definition']['properties']['placeholder'] = value?.placeholder;
+
+ if (value?.defaultCountry && typeResolver(value?.type) === 'PhoneInput') {
+ uiComponentsDraft[index * 2 + 1]['definition']['properties']['defaultCountry'] = value?.defaultCountry;
+ }
+
// prevent label from showing up in text input, because it is already shown in the text component. (Defaults to "Label" if not updated explicitly with an empty string)
uiComponentsDraft[index * 2 + 1]['definition']['properties']['label'] = '';
break;
@@ -482,6 +489,10 @@ const typeResolver = (type) => {
return 'DropDown';
case 'button':
return 'Button';
+ case 'emailinput':
+ return 'EmailInput';
+ case 'phoneinput':
+ return 'PhoneInput';
case 'text':
return 'Text';
case 'number':
diff --git a/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx b/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx
index b5bfa9e4c3..89d34b65c7 100644
--- a/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx
+++ b/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx
@@ -26,6 +26,7 @@ const RenderSchema = ({ component, parent, id, onOptionChange, onOptionsChange,
return validateWidget({
...{ widgetValue: value },
...{ validationObject: component.definition.validation },
+ componentType: component?.component,
});
},
[component.definition.validation]
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput.jsx
deleted file mode 100644
index e55ec4b659..0000000000
--- a/frontend/src/AppBuilder/Widgets/PhoneInput.jsx
+++ /dev/null
@@ -1,476 +0,0 @@
-import React, { useEffect, useMemo, useRef, useState } from 'react';
-import Input, { getCountries, getCountryCallingCode } from 'react-phone-number-input/input';
-import en from 'react-phone-number-input/locale/en';
-import flags from 'react-phone-number-input/flags';
-import 'react-phone-number-input/style.css';
-import Select, { components } from 'react-select';
-import cx from 'classnames';
-import SolidIcon from '@/_ui/Icon/SolidIcons';
-import { useInput } from './BaseComponents/hooks/useInput';
-import Loader from '@/ToolJetUI/Loader/Loader';
-import Label from '@/_ui/Label';
-import TickV3 from '@/_ui/Icon/solidIcons/TickV3';
-import Planet from '@/_ui/Icon/bulkIcons/Planet';
-const tinycolor = require('tinycolor2');
-
-export const PhoneInput = (props) => {
- const { properties, styles, componentName, darkMode, height, setExposedVariable, setExposedVariables, fireEvent } =
- props;
- const transformedProps = {
- ...props,
- inputType: 'phone',
- };
- const inputLogic = useInput(transformedProps);
- const {
- inputRef,
- labelRef,
- visibility,
- loading,
- disable,
- validationStatus,
- showValidationError,
- isFocused,
- labelWidth,
- isValid,
- validationError,
- isMandatory,
- handleBlur,
- handleFocus,
- value,
- handlePhoneInputChange,
- country,
- setCountry,
- } = inputLogic;
- const { label, placeholder, isCountryChangeEnabled, defaultCountry = 'US' } = properties;
-
- const {
- padding,
- textColor,
- backgroundColor,
- alignment,
- width,
- direction,
- auto,
- color,
- borderColor,
- accentColor,
- errTextColor,
- boxShadow,
- borderRadius,
- } = styles;
- const _width = (width / 100) * 70;
- const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
- const isInitialRender = useRef(true);
-
- const getCountryCallingCodeSafe = (country) => {
- try {
- return getCountryCallingCode(country);
- } catch (error) {
- return '';
- }
- };
-
- const options = useMemo(
- () =>
- getCountries().map((country) => ({
- label: `${en[country]} +${getCountryCallingCodeSafe(country)}`,
- value: country,
- })),
- []
- );
-
- const onInputValueChange = (value) => {
- setExposedVariables({
- country: country,
- countryCode: getCountryCallingCodeSafe(country),
- formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`,
- });
- handlePhoneInputChange(value);
- };
-
- const handleKeyUp = (e) => {
- if (e.key === 'Enter') {
- onInputValueChange(value);
- fireEvent('onEnterPressed');
- }
- };
-
- useEffect(() => {
- if (isInitialRender.current) {
- setExposedVariables({
- country: country,
- countryCode: getCountryCallingCodeSafe(country),
- formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`,
- value: value,
- setCountryCode: (code) => {
- let value = getCountryCallingCodeSafe(code);
- if (value) {
- setCountry(code);
- } else {
- value = getCountries().find((country) => `+${getCountryCallingCode(country)}` === code);
- setCountry(value ? value : '');
- }
- },
- });
- isInitialRender.current = false;
- }
- }, []);
-
- useEffect(() => {
- if (!isInitialRender.current) {
- setCountry(defaultCountry);
- }
- }, [defaultCountry]);
-
- const disabledState = disable || loading;
-
- const loaderStyle = {
- right:
- direction === 'right' &&
- defaultAlignment === 'side' &&
- ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0))
- ? `${labelWidth + 11}px`
- : '11px',
- top:
- defaultAlignment === 'top'
- ? ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) &&
- 'calc(50% + 10px)'
- : '',
- transform:
- defaultAlignment === 'top' &&
- ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) &&
- ' translateY(-50%)',
- zIndex: 3,
- };
-
- const computedStyles = {
- height: height == 36 ? (padding == 'default' ? '36px' : '40px') : padding == 'default' ? height : height + 4,
- borderRadius: `${borderRadius}px`,
- color: !['#1B1F24', '#000', '#000000ff'].includes(textColor)
- ? textColor
- : disabledState
- ? 'var(--text-disabled)'
- : 'var(--text-primary)',
- borderColor: isFocused
- ? accentColor != '4368E3'
- ? accentColor
- : 'var(--primary-accent-strong)'
- : borderColor != '#CCD1D5'
- ? borderColor
- : disabledState
- ? '1px solid var(--borders-disabled-on-white)'
- : 'var(--borders-default)',
- '--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(),
- backgroundColor:
- backgroundColor != '#fff'
- ? backgroundColor
- : disabledState
- ? darkMode
- ? 'var(--surfaces-app-bg-default)'
- : 'var(--surfaces-surface-03)'
- : 'var(--surfaces-surface-01)',
- padding: '8px 10px',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- borderBottomLeftRadius: '0px',
- borderTopLeftRadius: '0px',
- borderLeft: 'none',
- };
-
- const CustomValueContainer = ({ getValue, ...props }) => {
- const selectedValue = getValue()[0];
- const FlagIcon = selectedValue ? flags[selectedValue.value] : null;
- const countryCode = getCountryCallingCodeSafe(selectedValue.value);
-
- return (
-
- {FlagIcon ? (
-
- <>
- {` +${countryCode}`}
- >
-
- ) : (
-
- )}
-
- );
- };
-
- const CustomOption = (props) => {
- const { label, value: optionValue, isSelected } = props;
- const optionStyle = {
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'start',
- minHeight: '32px',
- gap: '6px',
- cursor: 'pointer',
- fontFamily: 'IBM Plex Sans',
- fontSize: '12px',
- lineHeight: '18px',
- fontWeight: '400',
- color: darkMode ? '#fff' : '#1B1F24',
- width: '100%',
- };
- console.log('darkMode', darkMode);
- const FlagIcon = flags[optionValue];
-
- return (
-
-
-
{FlagIcon ? : null}
- {label}
-
-
-
-
-
- );
- };
-
- const CustomMenuList = (props) => {
- const { children, selectProps } = props;
- const { onInputChange, inputValue } = selectProps;
-
- return (
-
e.stopPropagation()}
- >
-
-
-
-
- {
- onInputChange(e.currentTarget.value, {
- action: 'input-change',
- });
- }}
- onMouseDown={(e) => {
- e.stopPropagation();
- e.target.focus();
- }}
- onTouchEnd={(e) => {
- e.stopPropagation();
- e.target.focus();
- }}
- />
-
-
-
- {children?.length > 0 ? children : No options
}
-
-
- );
- };
-
- const CountrySelect = ({ value, onChange, options, ...rest }) => {
- const [menuIsOpen, setMenuIsOpen] = useState(false);
- const dropdownRef = useRef(null);
-
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
- setMenuIsOpen(false);
- }
- };
-
- // Add event listener when dropdown is open
- if (menuIsOpen) {
- document.addEventListener('mousedown', handleClickOutside);
- }
-
- // Clean up the event listener
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
- }, [menuIsOpen]);
-
- const customStyles = {
- container: (provided) => ({
- ...provided,
- minWidth: !isCountryChangeEnabled || disabledState ? '77px' : '87px',
- width: !isCountryChangeEnabled || disabledState ? '77px' : '87px',
- height: '100%',
- }),
- control: (provided, state) => ({
- ...provided,
- minHeight: '0px',
- height: '100%',
- borderTopLeftRadius: `${borderRadius}px`,
- borderBottomLeftRadius: `${borderRadius}px`,
- borderTopRightRadius: '0px',
- borderBottomRightRadius: '0px',
- borderColor: `${
- !isValid && showValidationError ? 'var(--status-error-strong)' : computedStyles?.borderColor
- } !important`,
- backgroundColor: `${
- isCountryChangeEnabled
- ? computedStyles?.backgroundColor
- : darkMode
- ? 'var(--surfaces-app-bg-default)'
- : 'var(--surfaces-surface-03)'
- } !important`,
- }),
- menu: (provided) => ({
- ...provided,
- width: '208px',
- height: '236px',
- borderRadius: '8px',
- marginTop: '2px',
- }),
- menuList: (provided) => ({
- ...provided,
- maxHeight: '196px',
- overflowY: 'auto',
- scrollbarWidth: 'none',
- gap: '1px',
- padding: '8px',
- borderRadius: '0px 0px 8px 8px',
- display: 'flex',
- flexDirection: 'column',
- backgroundColor: 'var(--surfaces-surface-01)',
- }),
- option: (provided, state) => ({
- ...provided,
- backgroundColor: state.isSelected ? '#4368E31A' : 'var(--surfaces-surface-01)',
- ...(state.isSelected && { borderRadius: '8px' }),
- '&:hover': {
- backgroundColor: 'var(--interactive-overlays-fill-hover)',
- borderRadius: '8px',
- },
- display: 'flex',
- cursor: 'pointer',
- padding: '1px 14px',
- }),
- };
-
- return (
- setMenuIsOpen((prev) => !prev)} ref={dropdownRef}>
-
- );
- };
-
- return (
- <>
-
-
-
- {
- if (selectedOption) {
- setCountry(selectedOption.value);
- }
- }}
- />
-
-
- {loading &&
}
-
- {showValidationError && visibility && (
-
- {validationError}
-
- )}
- >
- );
-};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx
new file mode 100644
index 0000000000..240c44d0f6
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx
@@ -0,0 +1,137 @@
+import React, { useEffect, useRef, useState } from 'react';
+import Select from 'react-select';
+import SolidIcon from '@/_ui/Icon/SolidIcons';
+import { CustomMenuList } from './CustomMenuList';
+import { CustomOption } from './CustomOption';
+import { CustomValueContainer } from './CustomValueContainer';
+
+export const CountrySelect = ({ value, onChange, options, ...rest }) => {
+ const {
+ isCountryChangeEnabled,
+ disabledState,
+ borderRadius,
+ isValid,
+ showValidationError,
+ computedStyles,
+ darkMode,
+ } = rest;
+ const [menuIsOpen, setMenuIsOpen] = useState(false);
+ const dropdownRef = useRef(null);
+
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
+ setMenuIsOpen(false);
+ }
+ };
+
+ if (menuIsOpen) {
+ document.addEventListener('mousedown', handleClickOutside);
+ }
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, [menuIsOpen]);
+
+ const customStyles = {
+ container: (provided) => ({
+ ...provided,
+ minWidth: !isCountryChangeEnabled || disabledState ? '77px' : '87px',
+ width: !isCountryChangeEnabled || disabledState ? '77px' : '87px',
+ height: '100%',
+ }),
+ control: (provided) => ({
+ ...provided,
+ minHeight: '0px',
+ height: '100%',
+ borderTopLeftRadius: `${borderRadius}px`,
+ borderBottomLeftRadius: `${borderRadius}px`,
+ borderTopRightRadius: '0px',
+ borderBottomRightRadius: '0px',
+ borderColor: `${
+ !isValid && showValidationError ? 'var(--status-error-strong)' : computedStyles?.borderColor
+ } !important`,
+ backgroundColor: `${
+ isCountryChangeEnabled
+ ? computedStyles?.backgroundColor
+ : darkMode
+ ? 'var(--surfaces-app-bg-default)'
+ : 'var(--surfaces-surface-03)'
+ } !important`,
+ }),
+ menu: (provided) => ({
+ ...provided,
+ width: '208px',
+ height: '236px',
+ borderRadius: '8px',
+ marginTop: '2px',
+ }),
+ menuList: (provided) => ({
+ ...provided,
+ maxHeight: '196px',
+ overflowY: 'auto',
+ scrollbarWidth: 'none',
+ gap: '1px',
+ padding: '8px',
+ borderRadius: '0px 0px 8px 8px',
+ display: 'flex',
+ flexDirection: 'column',
+ backgroundColor: 'var(--surfaces-surface-01)',
+ }),
+ option: (provided, state) => ({
+ ...provided,
+ backgroundColor: state.isSelected ? '#4368E31A' : 'var(--surfaces-surface-01)',
+ ...(state.isSelected && { borderRadius: '8px' }),
+ '&:hover': {
+ backgroundColor: 'var(--interactive-overlays-fill-hover)',
+ borderRadius: '8px',
+ },
+ display: 'flex',
+ cursor: 'pointer',
+ padding: '1px 14px',
+ }),
+ };
+ return (
+ {
+ if (disabledState || !isCountryChangeEnabled) return;
+ setMenuIsOpen((prev) => !prev);
+ }}
+ ref={dropdownRef}
+ >
+
+ );
+};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CustomMenuList.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomMenuList.jsx
new file mode 100644
index 0000000000..cff9f4fd9f
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomMenuList.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { components } from 'react-select';
+import SolidIcon from '@/_ui/Icon/SolidIcons';
+import cx from 'classnames';
+
+export const CustomMenuList = (props) => {
+ const { children, selectProps } = props;
+ const { onInputChange, inputValue } = selectProps;
+
+ return (
+ e.stopPropagation()}
+ >
+
+
+
+
+ {
+ onInputChange(e.currentTarget.value, {
+ action: 'input-change',
+ });
+ }}
+ onMouseDown={(e) => {
+ e.stopPropagation();
+ e.target.focus();
+ }}
+ onTouchEnd={(e) => {
+ e.stopPropagation();
+ e.target.focus();
+ }}
+ />
+
+
+
+ {children?.length > 0 ? children : No options
}
+
+
+ );
+};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx
new file mode 100644
index 0000000000..8f3b9d7dac
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { components } from 'react-select';
+// eslint-disable-next-line import/no-unresolved
+import flags from 'react-phone-number-input/flags';
+import TickV3 from '@/_ui/Icon/solidIcons/TickV3';
+
+export const CustomOption = (props) => {
+ const { label, value: optionValue, isSelected, darkMode } = props;
+
+ const optionStyle = {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'start',
+ minHeight: '32px',
+ gap: '6px',
+ cursor: 'pointer',
+ fontFamily: 'IBM Plex Sans',
+ fontSize: '12px',
+ lineHeight: '18px',
+ fontWeight: '400',
+ color: darkMode ? '#fff' : '#1B1F24',
+ width: '100%',
+ };
+ const FlagIcon = flags[optionValue];
+
+ return (
+
+
+
{FlagIcon ? : null}
+ {label}
+
+
+
+
+
+ );
+};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx
new file mode 100644
index 0000000000..bf2ad0b5b7
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { components } from 'react-select';
+// eslint-disable-next-line import/no-unresolved
+import flags from 'react-phone-number-input/flags';
+import Planet from '@/_ui/Icon/bulkIcons/Planet';
+import { getCountryCallingCodeSafe } from './utils';
+
+export const CustomValueContainer = ({ getValue, ...props }) => {
+ const selectedValue = getValue()[0];
+ const FlagIcon = selectedValue ? flags[selectedValue.value] : null;
+ const countryCode = getCountryCallingCodeSafe(selectedValue.value);
+
+ return (
+
+ {FlagIcon ? (
+
+ <>
+ {` +${countryCode}`}
+ >
+
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx
new file mode 100644
index 0000000000..ce7bc39fe8
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx
@@ -0,0 +1,254 @@
+import React, { useEffect, useMemo, useRef } from 'react';
+// eslint-disable-next-line import/no-unresolved
+import Input, { getCountries, getCountryCallingCode } from 'react-phone-number-input/input';
+import { getCountryCallingCodeSafe } from './utils';
+// eslint-disable-next-line import/no-unresolved
+import en from 'react-phone-number-input/locale/en';
+import 'react-phone-number-input/style.css';
+import { useInput } from '../BaseComponents/hooks/useInput';
+import Loader from '@/ToolJetUI/Loader/Loader';
+import Label from '@/_ui/Label';
+import { CountrySelect } from './CountrySelect';
+
+const tinycolor = require('tinycolor2');
+
+export const PhoneInput = (props) => {
+ const { properties, styles, componentName, darkMode, setExposedVariables, fireEvent } = props;
+ const transformedProps = {
+ ...props,
+ inputType: 'phone',
+ };
+ const inputLogic = useInput(transformedProps);
+ const {
+ inputRef,
+ labelRef,
+ visibility,
+ loading,
+ disable,
+ showValidationError,
+ isFocused,
+ labelWidth,
+ isValid,
+ validationError,
+ isMandatory,
+ handleBlur,
+ handleFocus,
+ value,
+ handlePhoneInputChange,
+ country,
+ setCountry,
+ } = inputLogic;
+ const { label, placeholder, isCountryChangeEnabled, defaultCountry = 'US' } = properties;
+
+ const {
+ textColor,
+ backgroundColor,
+ alignment,
+ width,
+ direction,
+ auto,
+ color,
+ borderColor,
+ accentColor,
+ errTextColor,
+ boxShadow,
+ borderRadius,
+ } = styles;
+ const _width = (width / 100) * 70;
+ const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
+ const isInitialRender = useRef(true);
+
+ const options = useMemo(
+ () =>
+ getCountries()
+ .map((country) => ({
+ label: `${en[country]} +${getCountryCallingCodeSafe(country)}`,
+ value: country,
+ }))
+ .sort((a, b) => a.label.localeCompare(b.label)),
+ []
+ );
+
+ const onInputValueChange = (value) => {
+ setExposedVariables({
+ country: country,
+ countryCode: `+${getCountryCallingCodeSafe(country)}`,
+ formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`,
+ });
+ handlePhoneInputChange(value);
+ };
+
+ const handleKeyUp = (e) => {
+ if (e.key === 'Enter') {
+ fireEvent('onEnterPressed');
+ }
+ };
+
+ useEffect(() => {
+ if (isInitialRender.current) {
+ setExposedVariables({
+ country: country,
+ countryCode: `+${getCountryCallingCodeSafe(country)}`,
+ formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`,
+ value: value,
+ setCountryCode: (code) => {
+ let value = getCountryCallingCodeSafe(code);
+ if (value) {
+ setCountry(code);
+ } else {
+ value = getCountries().find((country) => `+${getCountryCallingCode(country)}` === code);
+ setCountry(value ? value : '');
+ }
+ },
+ });
+ isInitialRender.current = false;
+ }
+ }, []);
+
+ useEffect(() => {
+ if (!isInitialRender.current) {
+ setCountry(defaultCountry);
+ }
+ }, [defaultCountry]);
+
+ const disabledState = disable || loading;
+
+ const loaderStyle = {
+ right:
+ direction === 'right' &&
+ defaultAlignment === 'side' &&
+ ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0))
+ ? `${labelWidth + 11}px`
+ : '11px',
+ top:
+ defaultAlignment === 'top'
+ ? ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) &&
+ 'calc(50% + 10px)'
+ : '',
+ transform:
+ defaultAlignment === 'top' &&
+ ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) &&
+ ' translateY(-50%)',
+ zIndex: 3,
+ };
+
+ const computedStyles = {
+ height: '100%',
+ borderRadius: `${borderRadius}px`,
+ color: !['#1B1F24', '#000', '#000000ff'].includes(textColor)
+ ? textColor
+ : disabledState
+ ? 'var(--text-disabled)'
+ : 'var(--text-primary)',
+ borderColor: isFocused
+ ? accentColor != '4368E3'
+ ? accentColor
+ : 'var(--primary-accent-strong)'
+ : borderColor != '#CCD1D5'
+ ? borderColor
+ : disabledState
+ ? '1px solid var(--borders-disabled-on-white)'
+ : 'var(--borders-default)',
+ '--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(),
+ backgroundColor:
+ backgroundColor != '#fff'
+ ? backgroundColor
+ : disabledState
+ ? darkMode
+ ? 'var(--surfaces-app-bg-default)'
+ : 'var(--surfaces-surface-03)'
+ : 'var(--surfaces-surface-01)',
+ padding: '8px 10px',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ borderBottomLeftRadius: '0px',
+ borderTopLeftRadius: '0px',
+ borderLeft: 'none',
+ };
+
+ return (
+ <>
+
+
+
+ {
+ if (selectedOption) {
+ setCountry(selectedOption.value);
+ }
+ }}
+ />
+
+
+ {loading &&
}
+
+ {showValidationError && visibility && (
+
+ {validationError}
+
+ )}
+ >
+ );
+};
diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js b/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js
new file mode 100644
index 0000000000..9a23b45ca5
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js
@@ -0,0 +1,10 @@
+// eslint-disable-next-line import/no-unresolved
+import { getCountryCallingCode } from 'react-phone-number-input/input';
+
+export const getCountryCallingCodeSafe = (country) => {
+ try {
+ return getCountryCallingCode(country);
+ } catch (error) {
+ return '';
+ }
+};
diff --git a/frontend/src/AppBuilder/_helpers/editorHelpers.js b/frontend/src/AppBuilder/_helpers/editorHelpers.js
index 53906f7d4a..504a09b92c 100644
--- a/frontend/src/AppBuilder/_helpers/editorHelpers.js
+++ b/frontend/src/AppBuilder/_helpers/editorHelpers.js
@@ -31,7 +31,7 @@ import { Divider } from '@/Editor/Components/Divider';
import { FilePicker } from '@/Editor/Components/FilePicker';
import { PasswordInput } from '@/AppBuilder/Widgets/PasswordInput';
import { EmailInput } from '@/AppBuilder/Widgets/EmailInput';
-import { PhoneInput } from '@/AppBuilder/Widgets/PhoneInput';
+import { PhoneInput } from '@/AppBuilder/Widgets/PhoneInput/PhoneInput';
// import { Calendar } from '@/Editor/Components/Calendar';
// import { Listview } from '@/Editor/Components/Listview';
import { IFrame } from '@/Editor/Components/IFrame';