mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 08:58:26 +00:00
Merge pull request #12414 from ToolJet/feat/currency-input
Feat/currency input
This commit is contained in:
commit
3254a51c71
56 changed files with 5511 additions and 175 deletions
39
frontend/assets/images/icons/widgets/emailinput.jsx
Normal file
39
frontend/assets/images/icons/widgets/emailinput.jsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react';
|
||||
|
||||
const EmailInput = ({ fill = '#D7DBDF', width = 24, className = '', viewBox = '0 0 49 48' }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox={viewBox}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2.39498 1.9349C3.35945 0.97044 4.66757 0.428589 6.03153 0.428589H43.7458C45.1097 0.428589 46.418 0.97044 47.3825 1.9349C48.347 2.89935 48.8887 4.20746 48.8887 5.57145V17.3819C47.4096 16.4176 45.6432 15.8572 43.7458 15.8572H28.3172C23.11 15.8572 18.8887 20.0785 18.8887 25.2857V31.2857H6.03153C4.66754 31.2857 3.35945 30.7439 2.39498 29.7794C1.43051 28.815 0.888672 27.5068 0.888672 26.1429V5.57145C0.888672 4.20749 1.43051 2.89935 2.39498 1.9349Z"
|
||||
fill="#CCD1D5"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12.8886 10.2858C14.0721 10.2858 15.0315 11.2451 15.0315 12.4286V19.2858C15.0315 20.4692 14.0721 21.4286 12.8886 21.4286C11.7052 21.4286 10.7458 20.4692 10.7458 19.2858V12.4286C10.7458 11.2451 11.7052 10.2858 12.8886 10.2858Z"
|
||||
fill="#4368E3"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M28.3172 20.1428C25.4769 20.1428 23.1744 22.4453 23.1744 25.2857V36.4285C23.1744 39.2688 25.4769 41.5714 28.3172 41.5714H43.7458C46.586 41.5714 48.8887 39.2688 48.8887 36.4285V25.2857C48.8887 22.4453 46.586 20.1428 43.7458 20.1428H28.3172Z"
|
||||
fill="#4368E3"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M48.7087 23.9319L36.0315 29.7828L23.3545 23.9318C23.2371 24.3631 23.1744 24.8171 23.1744 25.2857V28.5688L35.1337 34.0886C35.7034 34.3515 36.36 34.3515 36.9298 34.0886L48.8887 28.5689V25.2857C48.8887 24.8172 48.8259 24.3632 48.7087 23.9319Z"
|
||||
fill="#CCD1D5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default EmailInput;
|
||||
|
|
@ -59,6 +59,8 @@ import Upstatistics from './upstatistics.jsx';
|
|||
import Verticaldivider from './verticaldivider.jsx';
|
||||
import TimePicker from './timepicker.jsx';
|
||||
import DatepickerV2 from './datepickerv2.jsx';
|
||||
import PhoneInput from './phoneinput.jsx';
|
||||
import EmailInput from './emailinput.jsx';
|
||||
|
||||
const WidgetIcon = (props) => {
|
||||
switch (props.name) {
|
||||
|
|
@ -99,6 +101,10 @@ const WidgetIcon = (props) => {
|
|||
return <Datepicker {...props} />;
|
||||
case 'datetimepickerv2':
|
||||
return <DateTimePickerV2 {...props} />;
|
||||
case 'emailinput':
|
||||
return <EmailInput {...props} />;
|
||||
case 'phoneinput':
|
||||
return <PhoneInput {...props} />;
|
||||
case 'daterangepicker':
|
||||
return <Daterangepicker {...props} />;
|
||||
case 'horizontaldivider':
|
||||
|
|
@ -180,6 +186,7 @@ const WidgetIcon = (props) => {
|
|||
case 'text':
|
||||
return <Text {...props} />;
|
||||
case 'textarea':
|
||||
case 'textarealegacy':
|
||||
return <TextArea {...props} />;
|
||||
case 'textinput':
|
||||
return <Textinput {...props} />;
|
||||
|
|
|
|||
36
frontend/assets/images/icons/widgets/phoneinput.jsx
Normal file
36
frontend/assets/images/icons/widgets/phoneinput.jsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import React from 'react';
|
||||
|
||||
const PhoneInput = ({ fill = '#D7DBDF', width = 24, className = '', viewBox = '0 0 49 48' }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox={viewBox}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M7.60296 9.85718C4.99933 9.85718 2.88867 11.9678 2.88867 14.5715V33.4286C2.88867 36.0322 4.99933 38.1429 7.60296 38.1429H42.1744C44.7779 38.1429 46.8887 36.0322 46.8887 33.4286V14.5715C46.8887 11.9678 44.7779 9.85718 42.1744 9.85718H7.60296Z"
|
||||
fill="#CCD1D5"
|
||||
/>
|
||||
<path
|
||||
d="M26.853 27.0714C25.7681 27.0714 24.8887 27.9508 24.8887 29.0357C24.8887 30.1205 25.7681 31 26.853 31H32.8884C33.9733 31 34.8527 30.1205 34.8527 29.0357C34.8527 27.9508 33.9733 27.0714 32.8884 27.0714H26.853Z"
|
||||
fill="#4368E3"
|
||||
/>
|
||||
<g clip-path="url(#clip0_39_14)">
|
||||
<path
|
||||
d="M14.113 30.4517C13.4512 30.8793 12.6626 31.0657 11.8797 30.9794C11.0969 30.8932 10.3675 30.5396 9.81433 29.9781L9.33073 29.5045C9.11871 29.2873 9 28.9956 9 28.6919C9 28.3881 9.11871 28.0965 9.33073 27.8793L11.3834 25.845C11.5984 25.6333 11.8879 25.5147 12.1894 25.5147C12.4909 25.5147 12.7803 25.6333 12.9954 25.845C13.2122 26.0573 13.5035 26.1762 13.8068 26.1762C14.11 26.1762 14.4013 26.0573 14.6181 25.845L17.8422 22.616C17.9497 22.5099 18.0351 22.3834 18.0934 22.2439C18.1517 22.1043 18.1817 21.9546 18.1817 21.8034C18.1817 21.6522 18.1517 21.5024 18.0934 21.3629C18.0351 21.2234 17.9497 21.0969 17.8422 20.9908C17.6308 20.7754 17.5124 20.4855 17.5124 20.1835C17.5124 19.8815 17.6308 19.5916 17.8422 19.3763L19.8841 17.3312C20.1009 17.1189 20.3922 17 20.6954 17C20.9987 17 21.29 17.1189 21.5068 17.3312L21.9797 17.8156C22.5403 18.3696 22.8933 19.1001 22.9794 19.8842C23.0656 20.6682 22.8795 21.4581 22.4525 22.1209C20.2279 25.4045 17.3973 28.2321 14.113 30.4517Z"
|
||||
fill="#4368E3"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_39_14">
|
||||
<rect width="14" height="14" fill="white" transform="translate(9 17)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default PhoneInput;
|
||||
56
frontend/package-lock.json
generated
56
frontend/package-lock.json
generated
|
|
@ -96,6 +96,7 @@
|
|||
"react-circular-progressbar": "^2.1.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-currency-input-field": "^3.10.0",
|
||||
"react-datepicker": "^7.6.0",
|
||||
"react-dates": "^21.8.0",
|
||||
"react-datetime": "^3.2.0",
|
||||
|
|
@ -118,6 +119,7 @@
|
|||
"react-multi-select-component": "^4.3.4",
|
||||
"react-pdf": "^6.2.2",
|
||||
"react-phone-input-2": "^2.15.1",
|
||||
"react-phone-number-input": "^3.4.12",
|
||||
"react-plotly.js": "^2.6.0",
|
||||
"react-qr-reader": "^2.2.1",
|
||||
"react-rnd": "^10.4.1",
|
||||
|
|
@ -29820,6 +29822,11 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/country-flag-icons": {
|
||||
"version": "1.5.18",
|
||||
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.18.tgz",
|
||||
"integrity": "sha512-z+Uzesi8u8IdkViqqbzzbkf3+a7WJpcET5B7sPwTg7GXqPYpVEgNlZ/FC3l8KO4mEf+mNkmzKLppKTN4PlCJEQ=="
|
||||
},
|
||||
"node_modules/country-regex": {
|
||||
"version": "1.1.0",
|
||||
"license": "MIT",
|
||||
|
|
@ -34649,6 +34656,26 @@
|
|||
"version": "0.2.4",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/input-format": {
|
||||
"version": "0.3.14",
|
||||
"resolved": "https://registry.npmjs.org/input-format/-/input-format-0.3.14.tgz",
|
||||
"integrity": "sha512-gHMrgrbCgmT4uK5Um5eVDUohuV9lcs95ZUUN9Px2Y0VIfjTzT2wF8Q3Z4fwLFm7c5Z2OXCm53FHoovj6SlOKdg==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.1.0",
|
||||
"react-dom": ">=18.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.7",
|
||||
"license": "MIT",
|
||||
|
|
@ -36786,6 +36813,11 @@
|
|||
"url": "https://github.com/sponsors/dmonad"
|
||||
}
|
||||
},
|
||||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.12.6",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.6.tgz",
|
||||
"integrity": "sha512-PJiS4ETaUfCOFLpmtKzAbqZQjCCKVu2OhTV4SVNNE7c2nu/dACvtCqj4L0i/KWNnIgRv7yrILvBj5Lonv5Ncxw=="
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.1.1",
|
||||
"license": "MIT",
|
||||
|
|
@ -41248,6 +41280,14 @@
|
|||
"framework-utils": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-currency-input-field": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-currency-input-field/-/react-currency-input-field-3.10.0.tgz",
|
||||
"integrity": "sha512-GRmZogHh1e1LrmgXg/fKHSuRLYUnj/c/AumfvfuDMA0UX1mDR6u2NR0fzDemRdq4tNHNLucJeJ2OKCr3ehqyDA==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-date-picker": {
|
||||
"version": "10.6.0",
|
||||
"license": "MIT",
|
||||
|
|
@ -42035,6 +42075,22 @@
|
|||
"react-dom": "^16.12.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-phone-number-input": {
|
||||
"version": "3.4.12",
|
||||
"resolved": "https://registry.npmjs.org/react-phone-number-input/-/react-phone-number-input-3.4.12.tgz",
|
||||
"integrity": "sha512-Raob77KdtLGm49iC6nuOX9qy6Mg16idkgC7Y1mHmvG2WBYoauHpzxYNlfmFskQKeiztrJIwPhPzBhjFwjenNCA==",
|
||||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"country-flag-icons": "^1.5.17",
|
||||
"input-format": "^0.3.10",
|
||||
"libphonenumber-js": "^1.11.20",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-plotly.js": {
|
||||
"version": "2.6.0",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@
|
|||
"react-circular-progressbar": "^2.1.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-currency-input-field": "^3.10.0",
|
||||
"react-datepicker": "^7.6.0",
|
||||
"react-dates": "^21.8.0",
|
||||
"react-datetime": "^3.2.0",
|
||||
|
|
@ -113,6 +114,7 @@
|
|||
"react-multi-select-component": "^4.3.4",
|
||||
"react-pdf": "^6.2.2",
|
||||
"react-phone-input-2": "^2.15.1",
|
||||
"react-phone-number-input": "^3.4.12",
|
||||
"react-plotly.js": "^2.6.0",
|
||||
"react-qr-reader": "^2.2.1",
|
||||
"react-rnd": "^10.4.1",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@ import { BOX_PADDING } from './appCanvasConstants';
|
|||
const shouldAddBoxShadowAndVisibility = [
|
||||
'Table',
|
||||
'TextInput',
|
||||
'TextArea',
|
||||
'PasswordInput',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'NumberInput',
|
||||
'Text',
|
||||
'Checkbox',
|
||||
|
|
@ -87,6 +91,7 @@ const RenderWidget = ({
|
|||
...{ widgetValue: value },
|
||||
...{ validationObject: unResolvedValidation },
|
||||
customResolveObjects: customResolvables,
|
||||
componentType,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[validateWidget, customResolvables, unResolvedValidation, resolvedValidation]
|
||||
|
|
|
|||
|
|
@ -118,7 +118,10 @@ export const ComponentsManagerTab = ({ darkMode }) => {
|
|||
'TextInput',
|
||||
'NumberInput',
|
||||
'PasswordInput',
|
||||
'Textarea',
|
||||
'TextArea',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'ToggleSwitchV2',
|
||||
'DropdownV2',
|
||||
'MultiselectV2',
|
||||
|
|
|
|||
|
|
@ -1 +1,9 @@
|
|||
export const LEGACY_ITEMS = ['ToggleSwitch', 'DropDown', 'Multiselect', 'RadioButton', 'Datepicker', 'Modal'];
|
||||
export const LEGACY_ITEMS = [
|
||||
'ToggleSwitch',
|
||||
'DropDown',
|
||||
'Multiselect',
|
||||
'RadioButton',
|
||||
'Datepicker',
|
||||
'Modal',
|
||||
'TextArea',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import Accordion from '@/_ui/Accordion';
|
||||
import { baseComponentProperties } from '../DefaultComponent';
|
||||
import Select from '@/_ui/Select';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import flags from 'react-phone-number-input/flags';
|
||||
import FxButton from '@/AppBuilder/CodeBuilder/Elements/FxButton';
|
||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||
import cx from 'classnames';
|
||||
import { CurrencyMap } from '@/AppBuilder/Widgets/PhoneCurrency/constants';
|
||||
|
||||
export const CurrencyInput = ({ componentMeta, darkMode, ...restProps }) => {
|
||||
const {
|
||||
layoutPropertyChanged,
|
||||
component,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
currentState,
|
||||
eventsChanged,
|
||||
apps,
|
||||
allComponents,
|
||||
} = restProps;
|
||||
|
||||
const properties = Object.keys(componentMeta.properties);
|
||||
const events = Object.keys(componentMeta.events);
|
||||
const validations = Object.keys(componentMeta.validation || {});
|
||||
const resolvedProperties = useStore((state) => state.getResolvedComponent(component.id)?.properties);
|
||||
const defaultCountry = resolvedProperties?.defaultCountry || 'US';
|
||||
const isDefaultCountryFxOn = componentMeta?.definition?.properties?.dateFormat?.fxActive || false;
|
||||
|
||||
const options = useMemo(() => {
|
||||
return Object.keys(CurrencyMap).map((country) => ({
|
||||
label: `${CurrencyMap[country].prefix} (${CurrencyMap[country].currency})`,
|
||||
value: country,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const renderCustomOption = ({ label, value: optionValue }) => {
|
||||
const optionStyle = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
height: '18px',
|
||||
gap: '6px',
|
||||
cursor: 'pointer',
|
||||
fontFamily: 'IBM Plex Sans',
|
||||
fontSize: '12px',
|
||||
lineHeight: '18px',
|
||||
fontWeight: '400',
|
||||
color: darkMode ? '#fff' : '#1B1F24',
|
||||
};
|
||||
const FlagIcon = flags[optionValue];
|
||||
|
||||
return (
|
||||
<div style={optionStyle} className={`selectedOption ${optionValue !== 'none' && 'custom-phone-input-options'}`}>
|
||||
<div>{FlagIcon ? <FlagIcon style={{ width: '22px', height: '16px' }} /> : null}</div>
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getCountryDropdown = () => {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="d-flex justify-content-between mb-1">
|
||||
<label className="form-label"> Default Currency</label>
|
||||
<div
|
||||
className={cx({
|
||||
'hide-fx': !isDefaultCountryFxOn,
|
||||
})}
|
||||
>
|
||||
<FxButton
|
||||
active={isDefaultCountryFxOn}
|
||||
onPress={() => {
|
||||
paramUpdated({ name: 'dateFormat' }, 'fxActive', !isDefaultCountryFxOn, 'properties');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isDefaultCountryFxOn ? (
|
||||
<CodeHinter
|
||||
initialValue={defaultCountry}
|
||||
theme={darkMode ? 'monokai' : 'default'}
|
||||
mode="javascript"
|
||||
lineNumbers={false}
|
||||
onChange={(value) => paramUpdated({ name: 'defaultCountry' }, 'value', value, 'properties')}
|
||||
/>
|
||||
) : (
|
||||
<Select
|
||||
width="100%"
|
||||
options={options}
|
||||
value={defaultCountry}
|
||||
customOption={renderCustomOption}
|
||||
onChange={(value) => {
|
||||
paramUpdated({ name: 'defaultCountry' }, 'value', value, 'properties');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const filteredProperties = properties.filter(
|
||||
(property) => componentMeta.properties[property].section !== 'additionalActions'
|
||||
);
|
||||
|
||||
const additionalActions = properties.filter(
|
||||
(property) => componentMeta.properties[property].section === 'additionalActions'
|
||||
);
|
||||
|
||||
const accordionItems = baseComponentProperties(
|
||||
filteredProperties,
|
||||
events,
|
||||
component,
|
||||
componentMeta,
|
||||
layoutPropertyChanged,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
currentState,
|
||||
eventsChanged,
|
||||
apps,
|
||||
allComponents,
|
||||
validations,
|
||||
darkMode,
|
||||
null,
|
||||
additionalActions
|
||||
);
|
||||
|
||||
accordionItems[0].children.splice(4, 0, getCountryDropdown());
|
||||
|
||||
return <Accordion items={accordionItems} />;
|
||||
};
|
||||
|
|
@ -14,8 +14,12 @@ const SHOW_ADDITIONAL_ACTIONS = [
|
|||
'Text',
|
||||
'Container',
|
||||
'TextInput',
|
||||
'TextArea',
|
||||
'NumberInput',
|
||||
'PasswordInput',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'ToggleSwitchV2',
|
||||
'Checkbox',
|
||||
'DropdownV2',
|
||||
|
|
@ -33,6 +37,7 @@ const PROPERTIES_VS_ACCORDION_TITLE = {
|
|||
NumberInput: 'Data',
|
||||
ToggleSwitchV2: 'Data',
|
||||
Checkbox: 'Data',
|
||||
TextArea: 'Data',
|
||||
Button: 'Data',
|
||||
Image: 'Data',
|
||||
Container: 'Data',
|
||||
|
|
@ -122,6 +127,10 @@ export const baseComponentProperties = (
|
|||
'Modal',
|
||||
'TextInput',
|
||||
'PasswordInput',
|
||||
'TextArea',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'NumberInput',
|
||||
'Text',
|
||||
'Table',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import Accordion from '@/_ui/Accordion';
|
||||
import { baseComponentProperties } from '../DefaultComponent';
|
||||
import Select from '@/_ui/Select';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { getCountries } from 'react-phone-number-input/input';
|
||||
import en from 'react-phone-number-input/locale/en';
|
||||
import flags from 'react-phone-number-input/flags';
|
||||
import FxButton from '@/AppBuilder/CodeBuilder/Elements/FxButton';
|
||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||
import cx from 'classnames';
|
||||
|
||||
export const PhoneInput = ({ componentMeta, darkMode, ...restProps }) => {
|
||||
const {
|
||||
layoutPropertyChanged,
|
||||
component,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
currentState,
|
||||
eventsChanged,
|
||||
apps,
|
||||
allComponents,
|
||||
} = restProps;
|
||||
|
||||
const properties = Object.keys(componentMeta.properties);
|
||||
const events = Object.keys(componentMeta.events);
|
||||
const validations = Object.keys(componentMeta.validation || {});
|
||||
const resolvedProperties = useStore((state) => state.getResolvedComponent(component.id)?.properties);
|
||||
const defaultCountry = resolvedProperties?.defaultCountry || 'US';
|
||||
const isDefaultCountryFxOn = componentMeta?.definition?.properties?.dateFormat?.fxActive || false;
|
||||
|
||||
const options = useMemo(
|
||||
() =>
|
||||
getCountries().map((country) => ({
|
||||
label: `${en[country]}`,
|
||||
value: country,
|
||||
})),
|
||||
[]
|
||||
);
|
||||
|
||||
const renderCustomOption = ({ label, value: optionValue }) => {
|
||||
const optionStyle = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
height: '18px',
|
||||
gap: '6px',
|
||||
cursor: 'pointer',
|
||||
fontFamily: 'IBM Plex Sans',
|
||||
fontSize: '12px',
|
||||
lineHeight: '18px',
|
||||
fontWeight: '400',
|
||||
color: darkMode ? '#fff' : '#1B1F24',
|
||||
};
|
||||
const FlagIcon = flags[optionValue];
|
||||
|
||||
return (
|
||||
<div style={optionStyle} className={`selectedOption ${optionValue !== 'none' && 'custom-phone-input-options'}`}>
|
||||
<div>{FlagIcon ? <FlagIcon style={{ width: '22px', height: '16px' }} /> : null}</div>
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getCountryDropdown = () => {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<div className="d-flex justify-content-between mb-1">
|
||||
<label className="form-label"> Default Country</label>
|
||||
<div
|
||||
className={cx({
|
||||
'hide-fx': !isDefaultCountryFxOn,
|
||||
})}
|
||||
>
|
||||
<FxButton
|
||||
active={isDefaultCountryFxOn}
|
||||
onPress={() => {
|
||||
paramUpdated({ name: 'dateFormat' }, 'fxActive', !isDefaultCountryFxOn, 'properties');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isDefaultCountryFxOn ? (
|
||||
<CodeHinter
|
||||
initialValue={defaultCountry}
|
||||
theme={darkMode ? 'monokai' : 'default'}
|
||||
mode="javascript"
|
||||
lineNumbers={false}
|
||||
onChange={(value) => paramUpdated({ name: 'defaultCountry' }, 'value', value, 'properties')}
|
||||
/>
|
||||
) : (
|
||||
<Select
|
||||
width="100%"
|
||||
options={options}
|
||||
value={defaultCountry}
|
||||
customOption={renderCustomOption}
|
||||
onChange={(value) => {
|
||||
paramUpdated({ name: 'defaultCountry' }, 'value', value, 'properties');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const filteredProperties = properties.filter(
|
||||
(property) => componentMeta.properties[property].section !== 'additionalActions'
|
||||
);
|
||||
|
||||
const additionalActions = properties.filter(
|
||||
(property) => componentMeta.properties[property].section === 'additionalActions'
|
||||
);
|
||||
|
||||
const accordionItems = baseComponentProperties(
|
||||
filteredProperties,
|
||||
events,
|
||||
component,
|
||||
componentMeta,
|
||||
layoutPropertyChanged,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
currentState,
|
||||
eventsChanged,
|
||||
apps,
|
||||
allComponents,
|
||||
validations,
|
||||
darkMode,
|
||||
null,
|
||||
additionalActions
|
||||
);
|
||||
|
||||
accordionItems[0].children.splice(3, 0, getCountryDropdown());
|
||||
|
||||
return <Accordion items={accordionItems} />;
|
||||
};
|
||||
|
|
@ -8,6 +8,8 @@ import { validateQueryName, convertToKebabCase, resolveReferences } from '@/_hel
|
|||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { DefaultComponent } from './Components/DefaultComponent';
|
||||
import { FilePicker } from './Components/FilePicker';
|
||||
import { PhoneInput } from './Components/PhoneInput/PhoneInput.jsx';
|
||||
import { CurrencyInput } from './Components/CurrencyInput/CurrencyInput.jsx';
|
||||
import { Modal } from './Components/Modal';
|
||||
import { ModalV2 } from './Components/ModalV2';
|
||||
import { CustomComponent } from './Components/CustomComponent';
|
||||
|
|
@ -36,6 +38,7 @@ import { EMPTY_ARRAY } from '@/_stores/editorStore';
|
|||
import { Select } from './Components/Select';
|
||||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
// import { componentTypes } from '@/Editor/WidgetManager/components';
|
||||
import { componentTypes } from '@/AppBuilder/WidgetManager/componentTypes';
|
||||
import { copyComponents } from '@/AppBuilder/AppCanvas/appCanvasUtils.js';
|
||||
import DatetimePickerV2 from './Components/DatetimePickerV2.jsx';
|
||||
|
|
@ -66,7 +69,11 @@ const INSPECTOR_HEADER_OPTIONS = [
|
|||
const NEW_REVAMPED_COMPONENTS = [
|
||||
'Text',
|
||||
'TextInput',
|
||||
'TextArea',
|
||||
'PasswordInput',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'NumberInput',
|
||||
'Table',
|
||||
'ToggleSwitchV2',
|
||||
|
|
@ -731,6 +738,10 @@ const GetAccordion = React.memo(
|
|||
case 'DatePickerV2':
|
||||
case 'TimePicker':
|
||||
return <DatetimePickerV2 {...restProps} componentName={componentName} />;
|
||||
case 'PhoneInput':
|
||||
return <PhoneInput {...restProps} />;
|
||||
case 'CurrencyInput':
|
||||
return <CurrencyInput {...restProps} componentName={componentName} />;
|
||||
|
||||
default: {
|
||||
return <DefaultComponent {...restProps} />;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ export function renderCustomStyles(
|
|||
componentConfig.component == 'TextInput' ||
|
||||
componentConfig.component == 'NumberInput' ||
|
||||
componentConfig.component == 'PasswordInput' ||
|
||||
componentConfig.component == 'EmailInput' ||
|
||||
componentConfig.component == 'PhoneInput' ||
|
||||
componentConfig.component == 'CurrencyInput' ||
|
||||
componentConfig.component == 'ToggleSwitchV2' ||
|
||||
componentConfig.component == 'Checkbox' ||
|
||||
componentConfig.component == 'Table' ||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const NEW_WIDGETS = [
|
|||
'DatePickerV2',
|
||||
'TimePicker',
|
||||
'ModalV2',
|
||||
'TextArea',
|
||||
];
|
||||
|
||||
export const WidgetBox = ({ component, darkMode }) => {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ import {
|
|||
linkConfig,
|
||||
iconConfig,
|
||||
boundedBoxConfig,
|
||||
emailinputConfig,
|
||||
phoneinputConfig,
|
||||
currencyinputConfig,
|
||||
} from '../widgets';
|
||||
|
||||
export const widgets = [
|
||||
|
|
@ -70,6 +73,9 @@ export const widgets = [
|
|||
textinputConfig,
|
||||
numberinputConfig,
|
||||
passinputConfig,
|
||||
emailinputConfig,
|
||||
phoneinputConfig,
|
||||
currencyinputConfig,
|
||||
datepickerConfig,
|
||||
datetimePickerV2Config,
|
||||
datePickerV2Config,
|
||||
|
|
|
|||
305
frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js
Normal file
305
frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
export const currencyinputConfig = {
|
||||
name: 'CurrencyInput',
|
||||
displayName: 'Currency Input',
|
||||
description: 'Currency input field',
|
||||
component: 'CurrencyInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter your number',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 0,
|
||||
},
|
||||
},
|
||||
decimalPlaces: {
|
||||
type: 'code',
|
||||
displayName: 'Decimal places',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: '2' },
|
||||
},
|
||||
isCountryChangeEnabled: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable currency change',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minValue: { type: 'code', displayName: 'Min value', placeholder: 'Enter min value' },
|
||||
maxValue: { type: 'code', displayName: 'Max value', placeholder: 'Enter max value' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconHome2' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set Value',
|
||||
params: [
|
||||
{ handle: 'value', displayName: 'value', defaultValue: '' },
|
||||
{ handle: 'country', displayName: 'country', defaultValue: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minValue: { value: '' },
|
||||
maxValue: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '0' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter amount' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
isCountryChangeEnabled: { value: '{{true}}' },
|
||||
decimalPlaces: { value: '2' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CFD3D859' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconHome2' },
|
||||
iconVisibility: { value: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
292
frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js
Normal file
292
frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
export const emailinputConfig = {
|
||||
name: 'EmailInput',
|
||||
displayName: 'Email Input',
|
||||
description: 'Email input field',
|
||||
component: 'EmailInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter email',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconMailFilled' },
|
||||
accordian: 'field',
|
||||
visibility: true,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setText',
|
||||
displayName: 'Set text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter email' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CCD1D5' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconMailFilled' },
|
||||
iconVisibility: { value: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -58,6 +58,9 @@ import { kanbanBoardConfig } from './kanbanBoard';
|
|||
import { datetimePickerV2Config } from './datetimepickerV2';
|
||||
import { datePickerV2Config } from './datepickerV2';
|
||||
import { timePickerConfig } from './timepicker';
|
||||
import { emailinputConfig } from './emailinput';
|
||||
import { phoneinputConfig } from './phoneinput';
|
||||
import { currencyinputConfig } from './currencyinput';
|
||||
|
||||
export {
|
||||
buttonConfig,
|
||||
|
|
@ -73,6 +76,9 @@ export {
|
|||
datetimePickerV2Config,
|
||||
datePickerV2Config,
|
||||
timePickerConfig,
|
||||
emailinputConfig,
|
||||
phoneinputConfig,
|
||||
currencyinputConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig, //!Depreciated
|
||||
radiobuttonV2Config,
|
||||
|
|
|
|||
288
frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js
Normal file
288
frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
export const phoneinputConfig = {
|
||||
name: 'PhoneInput',
|
||||
displayName: 'Phone Input',
|
||||
description: 'Phone input field',
|
||||
component: 'PhoneInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter your input',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
isCountryChangeEnabled: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable country change',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set Value',
|
||||
params: [
|
||||
{ handle: 'value', displayName: 'value', defaultValue: '' },
|
||||
{ handle: 'country', displayName: 'country', defaultValue: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
handle: 'setCountryCode',
|
||||
displayName: 'Set country code',
|
||||
params: [{ handle: 'countryCode', displayName: 'Country code', defaultValue: '' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter your phone' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
isCountryChangeEnabled: { value: '{{true}}' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ export const textareaConfig = {
|
|||
description: 'Multi-line text input',
|
||||
component: 'TextArea',
|
||||
defaultSize: {
|
||||
width: 6,
|
||||
width: 10,
|
||||
height: 100,
|
||||
},
|
||||
others: {
|
||||
|
|
@ -12,82 +12,291 @@ export const textareaConfig = {
|
|||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'default text',
|
||||
},
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Placeholder text',
|
||||
defaultValue: 'Enter your input',
|
||||
},
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconHome2' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 4,
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setText',
|
||||
displayName: 'Set Text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New Text' }],
|
||||
displayName: 'Set text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'disable',
|
||||
displayName: 'Disable(deprecated)',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'visibility',
|
||||
displayName: 'Visibility(deprecated)',
|
||||
params: [{ handle: 'visibility', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
},
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter your input' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
borderRadius: { value: '{{4}}' },
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CFD3D859' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconHome2' },
|
||||
iconVisibility: { value: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
240
frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx
Normal file
240
frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
import React, { forwardRef } from 'react';
|
||||
import Label from '@/_ui/Label';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import * as Icons from '@tabler/icons-react';
|
||||
const tinycolor = require('tinycolor2');
|
||||
|
||||
const RenderInput = forwardRef((props, ref) => {
|
||||
return props.inputType !== 'textarea' ? <input {...props} ref={ref} /> : <textarea {...props} ref={ref} />;
|
||||
});
|
||||
|
||||
export const BaseInput = ({
|
||||
height,
|
||||
styles,
|
||||
properties,
|
||||
darkMode,
|
||||
componentName,
|
||||
dataCy,
|
||||
// From useInput hook
|
||||
inputRef,
|
||||
labelRef,
|
||||
visibility,
|
||||
loading,
|
||||
labelWidth,
|
||||
validationError,
|
||||
showValidationError,
|
||||
isFocused,
|
||||
isMandatory,
|
||||
disable,
|
||||
value,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
handleFocus,
|
||||
handleKeyUp,
|
||||
isValid,
|
||||
// Input specific props
|
||||
inputType = 'text',
|
||||
additionalInputProps = {},
|
||||
rightIcon,
|
||||
getCustomStyles,
|
||||
}) => {
|
||||
const {
|
||||
padding,
|
||||
borderRadius,
|
||||
borderColor,
|
||||
backgroundColor,
|
||||
textColor,
|
||||
boxShadow,
|
||||
width,
|
||||
alignment,
|
||||
direction,
|
||||
color,
|
||||
auto,
|
||||
errTextColor,
|
||||
iconColor,
|
||||
accentColor,
|
||||
iconVisibility: showLeftIcon,
|
||||
icon,
|
||||
} = styles;
|
||||
|
||||
const { label, placeholder } = properties;
|
||||
const _width = (width / 100) * 70;
|
||||
const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
|
||||
|
||||
const computedStyles = {
|
||||
height: height == 36 ? (padding == 'default' ? '36px' : '40px') : padding == 'default' ? height : height + 4,
|
||||
borderRadius: `${borderRadius}px`,
|
||||
color: !['#1B1F24', '#000', '#000000ff'].includes(textColor)
|
||||
? textColor
|
||||
: disable || loading
|
||||
? 'var(--text-disabled)'
|
||||
: 'var(--text-primary)',
|
||||
borderColor: isFocused
|
||||
? accentColor != '4368E3'
|
||||
? accentColor
|
||||
: 'var(--primary-accent-strong)'
|
||||
: borderColor != '#CCD1D5'
|
||||
? borderColor
|
||||
: disable || loading
|
||||
? '1px solid var(--borders-disabled-on-white)'
|
||||
: 'var(--borders-default)',
|
||||
'--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(),
|
||||
backgroundColor:
|
||||
backgroundColor != '#fff'
|
||||
? backgroundColor
|
||||
: disable || loading
|
||||
? darkMode
|
||||
? 'var(--surfaces-app-bg-default)'
|
||||
: 'var(--surfaces-surface-03)'
|
||||
: 'var(--surfaces-surface-01)',
|
||||
boxShadow,
|
||||
padding: showLeftIcon ? '8px 10px 8px 29px' : '8px 10px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
};
|
||||
|
||||
let loaderStyle;
|
||||
// for textarea loader position is fixed on top right of input box.
|
||||
if (inputType !== 'textarea') {
|
||||
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,
|
||||
};
|
||||
} else {
|
||||
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' ? '30px' : '10px',
|
||||
transform: 'none',
|
||||
zIndex: 3,
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons[icon] ?? Icons['IconHome2'];
|
||||
|
||||
const finalStyles = getCustomStyles ? getCustomStyles(computedStyles) : computedStyles;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
data-cy={`label-${String(componentName).toLowerCase()}`}
|
||||
className={`text-input d-flex ${
|
||||
defaultAlignment === 'top' &&
|
||||
((width != 0 && label?.length != 0) || (auto && width == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: inputType != 'textarea' && 'align-items-center'
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
${direction === 'right' && defaultAlignment === 'top' ? 'text-right' : ''}
|
||||
${visibility || 'invisible'}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
label={label}
|
||||
width={width}
|
||||
labelRef={labelRef}
|
||||
darkMode={darkMode}
|
||||
color={color}
|
||||
defaultAlignment={defaultAlignment}
|
||||
direction={direction}
|
||||
auto={auto}
|
||||
isMandatory={isMandatory}
|
||||
_width={_width}
|
||||
labelWidth={labelWidth}
|
||||
top={inputType === 'textarea' && defaultAlignment === 'side' && '9px'}
|
||||
/>
|
||||
|
||||
{showLeftIcon && (
|
||||
<IconElement
|
||||
data-cy={'text-input-icon'}
|
||||
style={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
left:
|
||||
direction === 'right'
|
||||
? '11px'
|
||||
: defaultAlignment === 'top'
|
||||
? '11px'
|
||||
: (label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)
|
||||
? `${labelWidth + 11}px`
|
||||
: '11px',
|
||||
position: 'absolute',
|
||||
top:
|
||||
inputType === 'textarea'
|
||||
? defaultAlignment === 'top'
|
||||
? '38px'
|
||||
: '18px'
|
||||
: defaultAlignment === 'side'
|
||||
? '50%'
|
||||
: (label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)
|
||||
? 'calc(50% + 10px)'
|
||||
: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
color: iconColor !== '#CFD3D859' ? iconColor : 'var(--icons-weak-disabled)',
|
||||
zIndex: 3,
|
||||
}}
|
||||
stroke={1.5}
|
||||
/>
|
||||
)}
|
||||
<RenderInput
|
||||
inputType={inputType}
|
||||
data-cy={dataCy}
|
||||
ref={inputRef}
|
||||
type={inputType}
|
||||
className={`tj-text-input-widget ${
|
||||
!isValid && showValidationError ? 'is-invalid' : ''
|
||||
} validation-without-icon`}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
onKeyUp={handleKeyUp}
|
||||
disabled={disable || loading}
|
||||
placeholder={placeholder}
|
||||
style={finalStyles}
|
||||
{...additionalInputProps}
|
||||
/>
|
||||
|
||||
{rightIcon}
|
||||
{loading && <Loader style={loaderStyle} width="16" />}
|
||||
</div>
|
||||
|
||||
{showValidationError && visibility && (
|
||||
<div
|
||||
data-cy={`${String(componentName).toLowerCase()}-invalid-feedback`}
|
||||
style={{
|
||||
color: errTextColor !== '#D72D39' ? errTextColor : 'var(--status-error-strong)',
|
||||
textAlign: direction == 'left' && 'end',
|
||||
fontSize: '11px',
|
||||
fontWeight: '400',
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
235
frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js
Normal file
235
frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
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 = ({
|
||||
id,
|
||||
properties,
|
||||
styles,
|
||||
validation,
|
||||
validate,
|
||||
setExposedVariable,
|
||||
setExposedVariables,
|
||||
fireEvent,
|
||||
inputType,
|
||||
}) => {
|
||||
const isInitialRender = useRef(true);
|
||||
const inputRef = useRef();
|
||||
const labelRef = useRef();
|
||||
|
||||
const { loadingState, disabledState, label, visibility: initialVisibility } = properties;
|
||||
const isResizing = useGridStore((state) => state.resizingComponentId === id);
|
||||
|
||||
const [value, setValue] = useState(properties.value ?? '');
|
||||
const [visibility, setVisibility] = useState(initialVisibility);
|
||||
const [loading, setLoading] = useState(loadingState);
|
||||
const [disable, setDisable] = useState(disabledState || loadingState);
|
||||
const [validationStatus, setValidationStatus] = useState(validate(value));
|
||||
const [showValidationError, setShowValidationError] = useState(false);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [labelWidth, setLabelWidth] = useState(0);
|
||||
const [iconVisibility, setIconVisibility] = useState(false);
|
||||
const [country, setCountry] = useState(properties.defaultCountry || 'US');
|
||||
|
||||
const { isValid, validationError } = validationStatus;
|
||||
const isMandatory = validation?.mandatory ?? false;
|
||||
|
||||
const getCountryCallingCodeSafe = (country) => {
|
||||
try {
|
||||
return getCountryCallingCode(country);
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (labelRef?.current) {
|
||||
const absolutewidth = labelRef?.current?.getBoundingClientRect()?.width;
|
||||
setLabelWidth(absolutewidth);
|
||||
} else setLabelWidth(0);
|
||||
}, [
|
||||
isResizing,
|
||||
styles.width,
|
||||
styles.auto,
|
||||
styles.alignment,
|
||||
styles.iconVisibility,
|
||||
label?.length,
|
||||
isMandatory,
|
||||
styles.padding,
|
||||
styles.direction,
|
||||
labelRef?.current?.getBoundingClientRect()?.width,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('label', label);
|
||||
}, [label]);
|
||||
|
||||
useEffect(() => {
|
||||
disable !== disabledState && setDisable(disabledState);
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isDisabled', disabledState);
|
||||
}, [disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
visibility !== properties.visibility && setVisibility(properties.visibility);
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isVisible', properties.visibility);
|
||||
}, [properties.visibility]);
|
||||
|
||||
useEffect(() => {
|
||||
loading !== loadingState && setLoading(loadingState);
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isLoading', loadingState);
|
||||
}, [loadingState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isMandatory', isMandatory);
|
||||
}, [isMandatory]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
const validationStatus = validate(value);
|
||||
setValidationStatus(validationStatus);
|
||||
setExposedVariable('isValid', validationStatus?.isValid);
|
||||
}, [validate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputType === 'phone') {
|
||||
let code = getCountryCallingCodeSafe(country);
|
||||
setInputValue(`+${code}${properties.value}`);
|
||||
} else {
|
||||
setInputValue(properties.value ?? '');
|
||||
}
|
||||
}, [properties.value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputType !== 'phone') return;
|
||||
setExposedVariable('setValue', async function (value, countryCode = country) {
|
||||
const code = getCountryCallingCodeSafe(country);
|
||||
setInputValue(`+${code}${value}`);
|
||||
setCountry(countryCode);
|
||||
fireEvent('onChange');
|
||||
});
|
||||
}, [inputType, country]);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputType !== 'currency') return;
|
||||
setExposedVariable('setValue', async function (value, countryCode = country) {
|
||||
setInputValue(value);
|
||||
setCountry(countryCode);
|
||||
fireEvent('onChange');
|
||||
});
|
||||
}, [inputType, country]);
|
||||
|
||||
useEffect(() => {
|
||||
const exposedVariables = {
|
||||
...(inputType !== 'phone' && {
|
||||
setText: async function (text) {
|
||||
setInputValue(text);
|
||||
fireEvent('onChange');
|
||||
},
|
||||
}),
|
||||
clear: async function () {
|
||||
setInputValue('');
|
||||
fireEvent('onChange');
|
||||
},
|
||||
setFocus: async function () {
|
||||
inputRef.current.focus();
|
||||
},
|
||||
setBlur: async function () {
|
||||
inputRef.current.blur();
|
||||
},
|
||||
setVisibility: async function (state) {
|
||||
setVisibility(state);
|
||||
setExposedVariable('isVisible', state);
|
||||
},
|
||||
setDisable: async function (disable) {
|
||||
setDisable(disable);
|
||||
setExposedVariable('isDisabled', disable);
|
||||
},
|
||||
setLoading: async function (loading) {
|
||||
setLoading(loading);
|
||||
setExposedVariable('isLoading', loading);
|
||||
},
|
||||
label,
|
||||
isValid,
|
||||
value: properties.value ?? '',
|
||||
isMandatory,
|
||||
isLoading: loading,
|
||||
isVisible: visibility,
|
||||
isDisabled: disable,
|
||||
};
|
||||
|
||||
setExposedVariables(exposedVariables);
|
||||
isInitialRender.current = false;
|
||||
}, []);
|
||||
|
||||
const setInputValue = (value) => {
|
||||
setValue(value);
|
||||
setExposedVariable('value', value);
|
||||
const validationStatus = validate(value);
|
||||
setValidationStatus(validationStatus);
|
||||
setExposedVariable('isValid', validationStatus?.isValid);
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
setInputValue(e.target.value);
|
||||
fireEvent('onChange');
|
||||
};
|
||||
|
||||
const handlePhoneCurrencyInputChange = (value) => {
|
||||
setInputValue(value);
|
||||
fireEvent('onChange');
|
||||
};
|
||||
|
||||
const handleBlur = (e) => {
|
||||
setShowValidationError(true);
|
||||
setIsFocused(false);
|
||||
e.stopPropagation();
|
||||
fireEvent('onBlur');
|
||||
};
|
||||
|
||||
const handleFocus = (e) => {
|
||||
setIsFocused(true);
|
||||
e.stopPropagation();
|
||||
setTimeout(() => {
|
||||
fireEvent('onFocus');
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const handleKeyUp = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
setInputValue(e.target.value);
|
||||
fireEvent('onEnterPressed');
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
inputRef,
|
||||
labelRef,
|
||||
value,
|
||||
visibility,
|
||||
loading,
|
||||
disable,
|
||||
country,
|
||||
setCountry,
|
||||
validationStatus,
|
||||
showValidationError,
|
||||
isFocused,
|
||||
labelWidth,
|
||||
iconVisibility,
|
||||
setIconVisibility,
|
||||
isValid,
|
||||
validationError,
|
||||
isMandatory,
|
||||
setInputValue,
|
||||
handlePhoneCurrencyInputChange,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
handleFocus,
|
||||
handleKeyUp,
|
||||
};
|
||||
};
|
||||
12
frontend/src/AppBuilder/Widgets/EmailInput.jsx
Normal file
12
frontend/src/AppBuilder/Widgets/EmailInput.jsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import { BaseInput } from './BaseComponents/BaseInput';
|
||||
import { useInput } from './BaseComponents/hooks/useInput';
|
||||
|
||||
export const EmailInput = (props) => {
|
||||
const inputLogic = useInput(props);
|
||||
const additionalInputProps = {
|
||||
autocomplete: 'email',
|
||||
name: 'email',
|
||||
};
|
||||
return <BaseInput {...props} {...inputLogic} inputType="email" additionalInputProps={additionalInputProps} />;
|
||||
};
|
||||
|
|
@ -97,6 +97,9 @@ export function generateUIComponents(JSONSchema, advanced, componentName = '') {
|
|||
if (uiComponentsDraft?.length > 0 && uiComponentsDraft[index * 2 + 1]) {
|
||||
switch (typeResolver(value?.type)) {
|
||||
case 'TextInput':
|
||||
case 'EmailInput':
|
||||
case 'PhoneInput':
|
||||
case 'CurrencyInput':
|
||||
if (value?.styles?.backgroundColor)
|
||||
uiComponentsDraft[index * 2 + 1]['definition']['styles']['backgroundColor'] =
|
||||
value?.styles?.backgroundColor;
|
||||
|
|
@ -127,6 +130,15 @@ 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 && ['PhoneInput', 'CurrencyInput'].includes(typeResolver(value?.type))) {
|
||||
uiComponentsDraft[index * 2 + 1]['definition']['properties']['defaultCountry'] = value?.defaultCountry;
|
||||
}
|
||||
|
||||
if (value?.defaultCountry && typeResolver(value?.type) === 'CurrencyInput') {
|
||||
uiComponentsDraft[index * 2 + 1]['definition']['properties']['decimalPlaces'] = value?.decimalPlaces;
|
||||
}
|
||||
|
||||
// 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 +494,12 @@ const typeResolver = (type) => {
|
|||
return 'DropDown';
|
||||
case 'button':
|
||||
return 'Button';
|
||||
case 'emailinput':
|
||||
return 'EmailInput';
|
||||
case 'phoneinput':
|
||||
return 'PhoneInput';
|
||||
case 'currencyinput':
|
||||
return 'CurrencyInput';
|
||||
case 'text':
|
||||
return 'Text';
|
||||
case 'number':
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
169
frontend/src/AppBuilder/Widgets/NumberInput.jsx
Normal file
169
frontend/src/AppBuilder/Widgets/NumberInput.jsx
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { BaseInput } from './BaseComponents/BaseInput';
|
||||
import { useInput } from './BaseComponents/hooks/useInput';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
|
||||
export const NumberInput = (props) => {
|
||||
const inputLogic = useInput({
|
||||
...props,
|
||||
properties: {
|
||||
...props.properties,
|
||||
value: Number(parseFloat(props.properties.value).toFixed(props.properties.decimalPlaces)),
|
||||
},
|
||||
});
|
||||
|
||||
const handleChange = (e) => {
|
||||
if (e.target.value === '') {
|
||||
inputLogic.setInputValue(null);
|
||||
props.fireEvent('onChange');
|
||||
} else {
|
||||
const newValue = Number(parseFloat(e.target.value));
|
||||
inputLogic.setInputValue(newValue);
|
||||
if (!isNaN(newValue)) {
|
||||
props.fireEvent('onChange');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (e) => {
|
||||
const value = Number(parseFloat(e.target.value).toFixed(props.properties.decimalPlaces));
|
||||
inputLogic.setInputValue(value);
|
||||
e.stopPropagation();
|
||||
props.fireEvent('onBlur');
|
||||
inputLogic.setIsFocused(false);
|
||||
};
|
||||
|
||||
const handleIncrement = (e) => {
|
||||
e.preventDefault();
|
||||
const newValue = (inputLogic.value || 0) + 1;
|
||||
inputLogic.setInputValue(newValue);
|
||||
if (!isNaN(newValue)) {
|
||||
props.fireEvent('onChange');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDecrement = (e) => {
|
||||
e.preventDefault();
|
||||
const newValue = (inputLogic.value || 0) - 1;
|
||||
inputLogic.setInputValue(newValue);
|
||||
if (!isNaN(newValue)) {
|
||||
props.fireEvent('onChange');
|
||||
}
|
||||
};
|
||||
|
||||
// Override the base input styles to account for number controls
|
||||
const getCustomStyles = (baseStyles) => {
|
||||
return {
|
||||
...baseStyles,
|
||||
paddingRight: '20px', // Make room for number controls
|
||||
};
|
||||
};
|
||||
|
||||
const numberControls = !inputLogic.isResizing && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right:
|
||||
inputLogic.labelWidth === 0
|
||||
? 0
|
||||
: props.styles.alignment === 'side' && props.styles.direction === 'right'
|
||||
? `${inputLogic.labelWidth}px`
|
||||
: 0,
|
||||
top: 0,
|
||||
height: '100%',
|
||||
width: '20px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
zIndex: 2,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={handleIncrement}
|
||||
style={{
|
||||
height: '50%',
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<SolidIcon
|
||||
width={props.styles.padding === 'default' ? `${props.height / 2 - 1}px` : `${props.height / 2 + 1}px`}
|
||||
height={props.styles.padding === 'default' ? `${props.height / 2 - 1}px` : `${props.height / 2 + 1}px`}
|
||||
fill={'var(--icons-default)'}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top:
|
||||
props.styles.alignment === 'top' && props.properties.label?.length > 0 && props.styles.width > 0
|
||||
? '21px'
|
||||
: '1px',
|
||||
right: '1px',
|
||||
borderLeft:
|
||||
inputLogic.disable || inputLogic.loading
|
||||
? '1px solid var(--borders-weak-disabled)'
|
||||
: '1px solid var(--borders-default)',
|
||||
borderBottom:
|
||||
inputLogic.disable || inputLogic.loading
|
||||
? '1px solid var(--borders-weak-disabled)'
|
||||
: '.5px solid var(--borders-default)',
|
||||
borderTopRightRadius: props.styles.borderRadius - 1,
|
||||
backgroundColor: 'transparent',
|
||||
}}
|
||||
className="numberinput-up-arrow arrow number-input-arrow"
|
||||
name="TriangleDownCenter"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
onClick={handleDecrement}
|
||||
style={{
|
||||
height: '50%',
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<SolidIcon
|
||||
fill={'var(--icons-default)'}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '1px',
|
||||
bottom: '1px',
|
||||
borderLeft:
|
||||
inputLogic.disable || inputLogic.loading
|
||||
? '1px solid var(--borders-weak-disabled)'
|
||||
: '1px solid var(--borders-default)',
|
||||
borderTop:
|
||||
inputLogic.disable || inputLogic.loading
|
||||
? '1px solid var(--borders-weak-disabled)'
|
||||
: '.5px solid var(--borders-default)',
|
||||
borderBottomRightRadius: props.styles.borderRadius - 1,
|
||||
backgroundColor: 'transparent',
|
||||
}}
|
||||
width={props.styles.padding === 'default' ? `${props.height / 2 - 1}px` : `${props.height / 2 + 1}px`}
|
||||
height={props.styles.padding === 'default' ? `${props.height / 2 - 1}px` : `${props.height / 2 + 1}px`}
|
||||
className="numberinput-down-arrow arrow number-input-arrow"
|
||||
name="TriangleUpCenter"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isNaN(inputLogic.value) || inputLogic.value === '') {
|
||||
props.setExposedVariable('value', null);
|
||||
}
|
||||
}, [inputLogic.value]);
|
||||
|
||||
return (
|
||||
<BaseInput
|
||||
{...props}
|
||||
{...inputLogic}
|
||||
inputType="number"
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
additionalInputProps={{
|
||||
min: props.validation?.minValue ?? null,
|
||||
max: props.validation?.maxValue ?? null,
|
||||
}}
|
||||
rightIcon={numberControls}
|
||||
getCustomStyles={getCustomStyles}
|
||||
/>
|
||||
);
|
||||
};
|
||||
43
frontend/src/AppBuilder/Widgets/PasswordInput.jsx
Normal file
43
frontend/src/AppBuilder/Widgets/PasswordInput.jsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
import { BaseInput } from './BaseComponents/BaseInput';
|
||||
import { useInput } from './BaseComponents/hooks/useInput';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
|
||||
export const PasswordInput = (props) => {
|
||||
const inputLogic = useInput(props);
|
||||
|
||||
const toggleVisibility = () => {
|
||||
inputLogic.setIconVisibility(!inputLogic.iconVisibility);
|
||||
};
|
||||
|
||||
const passwordIcon = (
|
||||
<div
|
||||
onClick={toggleVisibility}
|
||||
style={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
position: 'absolute',
|
||||
right: '11px',
|
||||
display: 'flex',
|
||||
zIndex: 3,
|
||||
}}
|
||||
>
|
||||
<SolidIcon
|
||||
width={16}
|
||||
fill={'var(--icons-weak-disabled)'}
|
||||
className="password-component-eye"
|
||||
name={!inputLogic.iconVisibility ? 'eye1' : 'eyedisable'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseInput
|
||||
{...props}
|
||||
{...inputLogic}
|
||||
inputType={inputLogic.iconVisibility ? 'text' : 'password'}
|
||||
additionalInputProps={{ autoComplete: 'new-password' }}
|
||||
rightIcon={!inputLogic.loading && passwordIcon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
141
frontend/src/AppBuilder/Widgets/PhoneCurrency/CountrySelect.jsx
Normal file
141
frontend/src/AppBuilder/Widgets/PhoneCurrency/CountrySelect.jsx
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
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,
|
||||
isCurrencyInput = false,
|
||||
disabledState,
|
||||
borderRadius,
|
||||
isValid,
|
||||
showValidationError,
|
||||
computedStyles,
|
||||
darkMode,
|
||||
filterOption,
|
||||
} = 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' : isCurrencyInput ? '87px' : '93px',
|
||||
width: !isCountryChangeEnabled || disabledState ? '77px' : isCurrencyInput ? '87px' : '93px',
|
||||
height: '100%',
|
||||
}),
|
||||
valueContainer: (provided) => ({
|
||||
...provided,
|
||||
padding: '0px',
|
||||
}),
|
||||
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: `${computedStyles?.backgroundColor} !important`,
|
||||
}),
|
||||
menu: (provided) => ({
|
||||
...provided,
|
||||
width: '208px',
|
||||
height: '236px',
|
||||
borderRadius: '8px',
|
||||
marginTop: '2px',
|
||||
boxShadow: 'var(--elevation-400-box-shadow)',
|
||||
}),
|
||||
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 (
|
||||
<div
|
||||
onClick={() => {
|
||||
if (disabledState || !isCountryChangeEnabled) return;
|
||||
setMenuIsOpen((prev) => !prev);
|
||||
}}
|
||||
ref={dropdownRef}
|
||||
>
|
||||
<Select
|
||||
options={options}
|
||||
value={value}
|
||||
styles={customStyles}
|
||||
onChange={onChange}
|
||||
hasSearch={false}
|
||||
useCustomStyles={true}
|
||||
menuPortalTarget={document.body}
|
||||
isCurrencyInput={isCurrencyInput}
|
||||
isCountryChangeEnabled={isCountryChangeEnabled}
|
||||
{...(filterOption && { filterOption })}
|
||||
components={{
|
||||
MenuList: CustomMenuList,
|
||||
Option: (props) => <CustomOption {...props} />,
|
||||
ValueContainer: (props) => <CustomValueContainer {...props} />, // Add this line
|
||||
IndicatorSeparator: () => null,
|
||||
DropdownIndicator:
|
||||
!isCountryChangeEnabled || disabledState
|
||||
? () => null
|
||||
: () => (
|
||||
<div style={{ position: 'relative', display: 'flex', left: '-2px' }}>
|
||||
{menuIsOpen ? (
|
||||
<SolidIcon name="TriangleDownCenter" width="16" height="16" />
|
||||
) : (
|
||||
<SolidIcon name="TriangleUpCenter" width="16" height="16" />
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
darkMode={darkMode}
|
||||
isDisabled={disabledState}
|
||||
menuIsOpen={menuIsOpen}
|
||||
onMenuOpen={() => setMenuIsOpen(true)}
|
||||
onMenuClose={() => setMenuIsOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
266
frontend/src/AppBuilder/Widgets/PhoneCurrency/CurrencyInput.jsx
Normal file
266
frontend/src/AppBuilder/Widgets/PhoneCurrency/CurrencyInput.jsx
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { default as ReactCurrencyInput } from 'react-currency-input-field';
|
||||
import { useInput } from '../BaseComponents/hooks/useInput';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import Label from '@/_ui/Label';
|
||||
import { CountrySelect } from './CountrySelect';
|
||||
import { CurrencyMap } from './constants';
|
||||
const tinycolor = require('tinycolor2');
|
||||
|
||||
export const CurrencyInput = (props) => {
|
||||
const { properties, styles, componentName, darkMode, setExposedVariables, fireEvent } = props;
|
||||
const transformedProps = {
|
||||
...props,
|
||||
inputType: 'currency',
|
||||
};
|
||||
const inputLogic = useInput(transformedProps);
|
||||
|
||||
const {
|
||||
inputRef,
|
||||
labelRef,
|
||||
visibility,
|
||||
loading,
|
||||
disable,
|
||||
showValidationError,
|
||||
handlePhoneCurrencyInputChange,
|
||||
isFocused,
|
||||
labelWidth,
|
||||
isValid,
|
||||
validationError,
|
||||
isMandatory,
|
||||
handleBlur,
|
||||
handleFocus,
|
||||
value,
|
||||
country,
|
||||
setCountry,
|
||||
} = inputLogic;
|
||||
const { label, placeholder, decimalPlaces, isCountryChangeEnabled, defaultCountry = 'US' } = properties;
|
||||
|
||||
const handleKeyUp = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
fireEvent('onEnterPressed');
|
||||
}
|
||||
};
|
||||
|
||||
const options = useMemo(() => {
|
||||
return Object.keys(CurrencyMap).map((ele) => ({
|
||||
label: `${CurrencyMap[ele].prefix} (${CurrencyMap[ele].currency})`,
|
||||
value: ele,
|
||||
country: CurrencyMap[ele].country,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const onInputValueChange = (value) => {
|
||||
handlePhoneCurrencyInputChange(value);
|
||||
setExposedVariables({
|
||||
country: country,
|
||||
formattedValue: `${CurrencyMap[country]?.prefix} ${inputRef.current?.value}`,
|
||||
});
|
||||
};
|
||||
|
||||
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 disabledState = disable || loading;
|
||||
const isInitialRender = useRef(true);
|
||||
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',
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInitialRender.current) {
|
||||
setCountry(defaultCountry);
|
||||
}
|
||||
}, [defaultCountry]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInitialRender.current) {
|
||||
setExposedVariables({
|
||||
country: country,
|
||||
formattedValue: `${CurrencyMap[country]?.prefix} ${value}`,
|
||||
});
|
||||
}
|
||||
}, [country]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) {
|
||||
setExposedVariables({
|
||||
country: country,
|
||||
formattedValue: `${CurrencyMap[country]?.prefix} ${value}`,
|
||||
value: value,
|
||||
setCountryCode: (code) => {
|
||||
setCountry(code);
|
||||
},
|
||||
});
|
||||
isInitialRender.current = false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
data-cy={`label-${String(componentName).toLowerCase()}`}
|
||||
className={`text-input d-flex phone-input-widget ${
|
||||
defaultAlignment === 'top' &&
|
||||
((width != 0 && label?.length != 0) || (auto && width == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: 'align-items-center'
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
${direction === 'right' && defaultAlignment === 'top' ? 'text-right' : ''}
|
||||
${visibility || 'invisible'}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
label={label}
|
||||
width={width}
|
||||
labelRef={labelRef}
|
||||
darkMode={darkMode}
|
||||
color={color}
|
||||
defaultAlignment={defaultAlignment}
|
||||
direction={direction}
|
||||
auto={auto}
|
||||
isMandatory={isMandatory}
|
||||
_width={_width}
|
||||
labelWidth={labelWidth}
|
||||
/>
|
||||
<div className="d-flex h-100 w-100" style={{ boxShadow, borderRadius: `${borderRadius}px` }}>
|
||||
<CountrySelect
|
||||
value={{
|
||||
label: `${CurrencyMap?.[country]?.prefix} (${CurrencyMap?.[country]?.currency})`,
|
||||
value: country,
|
||||
country: CurrencyMap?.[country]?.country,
|
||||
}}
|
||||
options={options}
|
||||
isCountryChangeEnabled={isCountryChangeEnabled}
|
||||
disabledState={disabledState}
|
||||
borderRadius={borderRadius}
|
||||
isValid={isValid}
|
||||
filterOption={(option, inputValue) => {
|
||||
return (
|
||||
option.label.toLowerCase().includes(inputValue.toLowerCase()) ||
|
||||
option.data.country.toLowerCase().includes(inputValue.toLowerCase())
|
||||
);
|
||||
}}
|
||||
computedStyles={computedStyles}
|
||||
showValidationError={showValidationError}
|
||||
darkMode={darkMode}
|
||||
isCurrencyInput={true}
|
||||
onChange={(selectedOption) => {
|
||||
if (selectedOption) {
|
||||
setCountry(selectedOption.value);
|
||||
fireEvent('onChange');
|
||||
setExposedVariables({
|
||||
country: selectedOption.value,
|
||||
formattedValue: `${CurrencyMap[selectedOption.value]?.prefix} ${selectedOption.value}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ReactCurrencyInput
|
||||
ref={inputRef}
|
||||
placeholder={placeholder}
|
||||
className={`tj-text-input-widget ${
|
||||
!isValid && showValidationError ? 'is-invalid' : ''
|
||||
} validation-without-icon`}
|
||||
value={value}
|
||||
decimalsLimit={decimalPlaces}
|
||||
style={computedStyles}
|
||||
data-ignore-hover={true}
|
||||
onValueChange={(newVal) => {
|
||||
if (newVal === value) return;
|
||||
onInputValueChange(newVal);
|
||||
}}
|
||||
// prefix={`${CurrencyMap?.[country]?.prefix || ''} `}
|
||||
prefix={''}
|
||||
disabled={disabledState}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
</div>
|
||||
{loading && <Loader style={loaderStyle} width="16" />}
|
||||
</div>
|
||||
{showValidationError && visibility && (
|
||||
<div
|
||||
data-cy={`${String(componentName).toLowerCase()}-invalid-feedback`}
|
||||
style={{
|
||||
color: errTextColor !== '#D72D39' ? errTextColor : 'var(--status-error-strong)',
|
||||
textAlign: direction == 'left' && 'end',
|
||||
fontSize: '11px',
|
||||
fontWeight: '400',
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -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 (
|
||||
<div
|
||||
className={cx('dropdown-multiselect-widget-custom-menu-list', {
|
||||
'theme-dark dark-theme': selectProps?.darkMode,
|
||||
})}
|
||||
style={{ height: '236px' }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="dropdown-multiselect-widget-search-box-wrapper">
|
||||
<span>
|
||||
<SolidIcon name="search01" width="14" />
|
||||
</span>
|
||||
<input
|
||||
autoCorrect="off"
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
className="dropdown-multiselect-widget-search-box"
|
||||
value={inputValue}
|
||||
onChange={(e) => {
|
||||
onInputChange(e.currentTarget.value, {
|
||||
action: 'input-change',
|
||||
});
|
||||
}}
|
||||
onMouseDown={(e) => {
|
||||
e.stopPropagation();
|
||||
e.target.focus();
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
e.stopPropagation();
|
||||
e.target.focus();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<components.MenuList {...props}>
|
||||
{children?.length > 0 ? children : <div style={{ padding: '8px', textAlign: 'center' }}>No options</div>}
|
||||
</components.MenuList>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
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 } = props;
|
||||
const { darkMode } = props?.selectProps || {};
|
||||
|
||||
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 (
|
||||
<components.Option {...props}>
|
||||
<div style={optionStyle}>
|
||||
<div>{FlagIcon ? <FlagIcon style={{ width: '22px', height: '16px' }} /> : null}</div>
|
||||
{label}
|
||||
<div style={{ marginLeft: 'auto', display: isSelected ? 'block' : 'none' }}>
|
||||
<TickV3 width="13.33px" height="11.27px" />
|
||||
</div>
|
||||
</div>
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
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';
|
||||
import { CurrencyMap } from './constants';
|
||||
|
||||
export const CustomValueContainer = ({ getValue, ...props }) => {
|
||||
const selectedValue = getValue()[0];
|
||||
const country = selectedValue?.value;
|
||||
const { isCurrencyInput, isCountryChangeEnabled } = props?.selectProps || {};
|
||||
const FlagIcon = selectedValue ? flags[selectedValue.value] : null;
|
||||
const countryCode = getCountryCallingCodeSafe(selectedValue.value);
|
||||
|
||||
return (
|
||||
<components.ValueContainer {...props}>
|
||||
{FlagIcon ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
marginLeft: isCountryChangeEnabled ? '4px' : '0px',
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<FlagIcon style={{ height: '16px' }} />{' '}
|
||||
<span style={{ marginLeft: '6px' }}>
|
||||
{isCurrencyInput ? ` ${CurrencyMap?.[country]?.prefix}` : ` +${countryCode}`}
|
||||
</span>
|
||||
</>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
marginLeft: isCurrencyInput ? '6px' : '17px',
|
||||
marginTop: '4px',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Planet width={24} height={24} />
|
||||
</div>
|
||||
)}
|
||||
</components.ValueContainer>
|
||||
);
|
||||
};
|
||||
254
frontend/src/AppBuilder/Widgets/PhoneCurrency/PhoneInput.jsx
Normal file
254
frontend/src/AppBuilder/Widgets/PhoneCurrency/PhoneInput.jsx
Normal file
|
|
@ -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,
|
||||
handlePhoneCurrencyInputChange,
|
||||
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}`,
|
||||
});
|
||||
handlePhoneCurrencyInputChange(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 (
|
||||
<>
|
||||
<div
|
||||
data-cy={`label-${String(componentName).toLowerCase()}`}
|
||||
className={`text-input d-flex phone-input-widget ${
|
||||
defaultAlignment === 'top' &&
|
||||
((width != 0 && label?.length != 0) || (auto && width == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: 'align-items-center'
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
${direction === 'right' && defaultAlignment === 'top' ? 'text-right' : ''}
|
||||
${visibility || 'invisible'}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
label={label}
|
||||
width={width}
|
||||
labelRef={labelRef}
|
||||
darkMode={darkMode}
|
||||
color={color}
|
||||
defaultAlignment={defaultAlignment}
|
||||
direction={direction}
|
||||
auto={auto}
|
||||
isMandatory={isMandatory}
|
||||
_width={_width}
|
||||
labelWidth={labelWidth}
|
||||
/>
|
||||
<div className="d-flex h-100 w-100" style={{ boxShadow, borderRadius: `${borderRadius}px` }}>
|
||||
<CountrySelect
|
||||
value={{ label: `${en[country]} +${getCountryCallingCodeSafe(country)}`, value: country }}
|
||||
options={options}
|
||||
isCountryChangeEnabled={isCountryChangeEnabled}
|
||||
disabledState={disabledState}
|
||||
borderRadius={borderRadius}
|
||||
isValid={isValid}
|
||||
computedStyles={computedStyles}
|
||||
showValidationError={showValidationError}
|
||||
darkMode={darkMode}
|
||||
onChange={(selectedOption) => {
|
||||
if (selectedOption) {
|
||||
setCountry(selectedOption.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
country={country}
|
||||
international={false}
|
||||
value={value}
|
||||
onChange={onInputValueChange}
|
||||
placeholder={placeholder}
|
||||
style={computedStyles}
|
||||
className={`tj-text-input-widget ${
|
||||
!isValid && showValidationError ? 'is-invalid' : ''
|
||||
} validation-without-icon`}
|
||||
disabled={disabledState}
|
||||
data-ignore-hover={true}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
</div>
|
||||
{loading && <Loader style={loaderStyle} width="16" />}
|
||||
</div>
|
||||
{showValidationError && visibility && (
|
||||
<div
|
||||
data-cy={`${String(componentName).toLowerCase()}-invalid-feedback`}
|
||||
style={{
|
||||
color: errTextColor !== '#D72D39' ? errTextColor : 'var(--status-error-strong)',
|
||||
textAlign: direction == 'left' && 'end',
|
||||
fontSize: '11px',
|
||||
fontWeight: '400',
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
597
frontend/src/AppBuilder/Widgets/PhoneCurrency/constants.js
Normal file
597
frontend/src/AppBuilder/Widgets/PhoneCurrency/constants.js
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
export const CurrencyMap = {
|
||||
AE: {
|
||||
currency: 'AED',
|
||||
prefix: 'د.إ.',
|
||||
country: 'United Arab Emirates',
|
||||
},
|
||||
AF: {
|
||||
currency: 'AFN',
|
||||
prefix: '؋',
|
||||
country: 'Afghanistan',
|
||||
},
|
||||
AL: {
|
||||
currency: 'ALL',
|
||||
prefix: 'Lek',
|
||||
country: 'Albania',
|
||||
},
|
||||
AM: {
|
||||
currency: 'AMD',
|
||||
prefix: 'դր.',
|
||||
country: 'Armenia',
|
||||
},
|
||||
AR: {
|
||||
currency: 'ARS',
|
||||
prefix: '$',
|
||||
country: 'Argentina',
|
||||
},
|
||||
AU: {
|
||||
currency: 'AUD',
|
||||
prefix: '$',
|
||||
country: 'Australia',
|
||||
},
|
||||
AZ: {
|
||||
currency: 'AZN',
|
||||
prefix: 'ман.',
|
||||
country: 'Azerbaijan',
|
||||
},
|
||||
BA: {
|
||||
currency: 'BAM',
|
||||
prefix: 'KM',
|
||||
country: 'Bosnia and Herzegovina',
|
||||
},
|
||||
BD: {
|
||||
currency: 'BDT',
|
||||
prefix: '৳',
|
||||
country: 'Bangladesh',
|
||||
},
|
||||
BG: {
|
||||
currency: 'BGN',
|
||||
prefix: 'лв.',
|
||||
country: 'Bulgaria',
|
||||
},
|
||||
BH: {
|
||||
currency: 'BHD',
|
||||
prefix: 'د.ب.',
|
||||
country: 'Bahrain',
|
||||
},
|
||||
BI: {
|
||||
currency: 'BIF',
|
||||
prefix: 'FBu',
|
||||
country: 'Burundi',
|
||||
},
|
||||
BN: {
|
||||
currency: 'BND',
|
||||
prefix: '$',
|
||||
country: 'Brunei Darussalam',
|
||||
},
|
||||
BO: {
|
||||
currency: 'BOB',
|
||||
prefix: 'Bs',
|
||||
country: 'Bolivia',
|
||||
},
|
||||
BR: {
|
||||
currency: 'BRL',
|
||||
prefix: 'R$',
|
||||
country: 'Brazil',
|
||||
},
|
||||
BV: {
|
||||
currency: 'NOK',
|
||||
prefix: 'kr',
|
||||
country: 'Bouvet Island',
|
||||
},
|
||||
BW: {
|
||||
currency: 'BWP',
|
||||
prefix: 'P',
|
||||
country: 'Botswana',
|
||||
},
|
||||
BY: {
|
||||
currency: 'BYR',
|
||||
prefix: 'BYR',
|
||||
country: 'Belarus',
|
||||
},
|
||||
BZ: {
|
||||
currency: 'BZD',
|
||||
prefix: '$',
|
||||
country: 'Belize',
|
||||
},
|
||||
CA: {
|
||||
currency: 'CAD',
|
||||
prefix: '$',
|
||||
country: 'Canada',
|
||||
},
|
||||
CD: {
|
||||
currency: 'CDF',
|
||||
prefix: 'FrCD',
|
||||
country: 'Congo, Democratic Republic of the',
|
||||
},
|
||||
CF: {
|
||||
currency: 'XAF',
|
||||
prefix: 'FCFA',
|
||||
country: 'Central African Republic',
|
||||
},
|
||||
CH: {
|
||||
currency: 'CHF',
|
||||
prefix: 'CHF',
|
||||
country: 'Switzerland',
|
||||
},
|
||||
CL: {
|
||||
currency: 'CLP',
|
||||
prefix: '$',
|
||||
country: 'Chile',
|
||||
},
|
||||
CN: {
|
||||
currency: 'CNY',
|
||||
prefix: 'CN¥',
|
||||
country: 'China',
|
||||
},
|
||||
CO: {
|
||||
currency: 'COP',
|
||||
prefix: '$',
|
||||
country: 'Colombia',
|
||||
},
|
||||
CR: {
|
||||
currency: 'CRC',
|
||||
prefix: '₡',
|
||||
country: 'Costa Rica',
|
||||
},
|
||||
CV: {
|
||||
currency: 'CVE',
|
||||
prefix: 'CV$',
|
||||
country: 'Cape Verde',
|
||||
},
|
||||
CZ: {
|
||||
currency: 'CZK',
|
||||
prefix: 'Kč',
|
||||
country: 'Czech Republic',
|
||||
},
|
||||
DJ: {
|
||||
currency: 'DJF',
|
||||
prefix: 'Fdj',
|
||||
country: 'Djibouti',
|
||||
},
|
||||
DK: {
|
||||
currency: 'DKK',
|
||||
prefix: 'kr',
|
||||
country: 'Denmark',
|
||||
},
|
||||
DO: {
|
||||
currency: 'DOP',
|
||||
prefix: 'RD$',
|
||||
country: 'Dominican Republic',
|
||||
},
|
||||
DZ: {
|
||||
currency: 'DZD',
|
||||
prefix: 'د.ج.',
|
||||
country: 'Algeria',
|
||||
},
|
||||
EG: {
|
||||
currency: 'EGP',
|
||||
prefix: 'ج.م.',
|
||||
country: 'Egypt',
|
||||
},
|
||||
ER: {
|
||||
currency: 'ERN',
|
||||
prefix: 'Nfk',
|
||||
country: 'Eritrea',
|
||||
},
|
||||
EU: {
|
||||
currency: 'EUR',
|
||||
prefix: '€',
|
||||
country: 'European Union',
|
||||
},
|
||||
ET: {
|
||||
currency: 'ETB',
|
||||
prefix: 'Br',
|
||||
country: 'Ethiopia',
|
||||
},
|
||||
GB: {
|
||||
currency: 'GBP',
|
||||
prefix: '£',
|
||||
country: 'United Kingdom',
|
||||
},
|
||||
GE: {
|
||||
currency: 'GEL',
|
||||
prefix: 'GEL',
|
||||
country: 'Georgia',
|
||||
},
|
||||
GH: {
|
||||
currency: 'GHS',
|
||||
prefix: 'GH₵',
|
||||
country: 'Ghana',
|
||||
},
|
||||
GN: {
|
||||
currency: 'GNF',
|
||||
prefix: 'FG',
|
||||
country: 'Guinea',
|
||||
},
|
||||
GT: {
|
||||
currency: 'GTQ',
|
||||
prefix: 'Q',
|
||||
country: 'Guatemala',
|
||||
},
|
||||
HK: {
|
||||
currency: 'HKD',
|
||||
prefix: '$',
|
||||
country: 'Hong Kong',
|
||||
},
|
||||
HN: {
|
||||
currency: 'HNL',
|
||||
prefix: 'L',
|
||||
country: 'Honduras',
|
||||
},
|
||||
HR: {
|
||||
currency: 'HRK',
|
||||
prefix: 'kn',
|
||||
country: 'Croatia',
|
||||
},
|
||||
HU: {
|
||||
currency: 'HUF',
|
||||
prefix: 'Ft',
|
||||
country: 'Hungary',
|
||||
},
|
||||
ID: {
|
||||
currency: 'IDR',
|
||||
prefix: 'Rp',
|
||||
country: 'Indonesia',
|
||||
},
|
||||
IL: {
|
||||
currency: 'ILS',
|
||||
prefix: '₪',
|
||||
country: 'Israel',
|
||||
},
|
||||
IN: {
|
||||
currency: 'INR',
|
||||
prefix: '₹',
|
||||
country: 'India',
|
||||
},
|
||||
IQ: {
|
||||
currency: 'IQD',
|
||||
prefix: 'د.ع.',
|
||||
country: 'Iraq',
|
||||
},
|
||||
IR: {
|
||||
currency: 'IRR',
|
||||
prefix: '﷼',
|
||||
country: 'Iran, Islamic Republic of',
|
||||
},
|
||||
IS: {
|
||||
currency: 'ISK',
|
||||
prefix: 'kr',
|
||||
country: 'Iceland',
|
||||
},
|
||||
JM: {
|
||||
currency: 'JMD',
|
||||
prefix: '$',
|
||||
country: 'Jamaica',
|
||||
},
|
||||
JO: {
|
||||
currency: 'JOD',
|
||||
prefix: 'د.أ.',
|
||||
country: 'Jordan',
|
||||
},
|
||||
JP: {
|
||||
currency: 'JPY',
|
||||
prefix: '¥',
|
||||
country: 'Japan',
|
||||
},
|
||||
KE: {
|
||||
currency: 'KES',
|
||||
prefix: 'Ksh',
|
||||
country: 'Kenya',
|
||||
},
|
||||
KH: {
|
||||
currency: 'KHR',
|
||||
prefix: '៛',
|
||||
country: 'Cambodia',
|
||||
},
|
||||
KM: {
|
||||
currency: 'KMF',
|
||||
prefix: 'FC',
|
||||
country: 'Comoros',
|
||||
},
|
||||
KR: {
|
||||
currency: 'KRW',
|
||||
prefix: '₩',
|
||||
country: 'Korea, Republic of',
|
||||
},
|
||||
KW: {
|
||||
currency: 'KWD',
|
||||
prefix: 'د.ك.',
|
||||
country: 'Kuwait',
|
||||
},
|
||||
KZ: {
|
||||
currency: 'KZT',
|
||||
prefix: 'тңг.',
|
||||
country: 'Kazakhstan',
|
||||
},
|
||||
LB: {
|
||||
currency: 'LBP',
|
||||
prefix: 'ل.ل.',
|
||||
country: 'Lebanon',
|
||||
},
|
||||
LK: {
|
||||
currency: 'LKR',
|
||||
prefix: 'SL Re',
|
||||
country: 'Sri Lanka',
|
||||
},
|
||||
LT: {
|
||||
currency: 'LTL',
|
||||
prefix: 'Lt',
|
||||
country: 'Lithuania',
|
||||
},
|
||||
LY: {
|
||||
currency: 'LYD',
|
||||
prefix: 'د.ل.',
|
||||
country: 'Libya',
|
||||
},
|
||||
MA: {
|
||||
currency: 'MAD',
|
||||
prefix: 'د.م.',
|
||||
country: 'Morocco',
|
||||
},
|
||||
MD: {
|
||||
currency: 'MDL',
|
||||
prefix: 'MDL',
|
||||
country: 'Moldova, Republic of',
|
||||
},
|
||||
MG: {
|
||||
currency: 'MGA',
|
||||
prefix: 'MGA',
|
||||
country: 'Madagascar',
|
||||
},
|
||||
MK: {
|
||||
currency: 'MKD',
|
||||
prefix: 'MKD',
|
||||
country: 'Macedonia, the Former Yugoslav Republic of',
|
||||
},
|
||||
MM: {
|
||||
currency: 'MMK',
|
||||
prefix: 'K',
|
||||
country: 'Myanmar',
|
||||
},
|
||||
MO: {
|
||||
currency: 'MOP',
|
||||
prefix: 'MOP$',
|
||||
country: 'Macao',
|
||||
},
|
||||
MU: {
|
||||
currency: 'MUR',
|
||||
prefix: 'MURs',
|
||||
country: 'Mauritius',
|
||||
},
|
||||
MX: {
|
||||
currency: 'MXN',
|
||||
prefix: '$',
|
||||
country: 'Mexico',
|
||||
},
|
||||
MY: {
|
||||
currency: 'MYR',
|
||||
prefix: 'RM',
|
||||
country: 'Malaysia',
|
||||
},
|
||||
MZ: {
|
||||
currency: 'MZN',
|
||||
prefix: 'MTn',
|
||||
country: 'Mozambique',
|
||||
},
|
||||
NA: {
|
||||
currency: 'NAD',
|
||||
prefix: 'N$',
|
||||
country: 'Namibia',
|
||||
},
|
||||
NG: {
|
||||
currency: 'NGN',
|
||||
prefix: '₦',
|
||||
country: 'Nigeria',
|
||||
},
|
||||
NI: {
|
||||
currency: 'NIO',
|
||||
prefix: 'C$',
|
||||
country: 'Nicaragua',
|
||||
},
|
||||
NO: {
|
||||
currency: 'NOK',
|
||||
prefix: 'kr',
|
||||
country: 'Norway',
|
||||
},
|
||||
NP: {
|
||||
currency: 'NPR',
|
||||
prefix: 'नेरू',
|
||||
country: 'Nepal',
|
||||
},
|
||||
NZ: {
|
||||
currency: 'NZD',
|
||||
prefix: '$',
|
||||
country: 'New Zealand',
|
||||
},
|
||||
OM: {
|
||||
currency: 'OMR',
|
||||
prefix: 'ر.ع.',
|
||||
country: 'Oman',
|
||||
},
|
||||
PA: {
|
||||
currency: 'PAB',
|
||||
prefix: 'B/.',
|
||||
country: 'Panama',
|
||||
},
|
||||
PE: {
|
||||
currency: 'PEN',
|
||||
prefix: 'S/.',
|
||||
country: 'Peru',
|
||||
},
|
||||
PH: {
|
||||
currency: 'PHP',
|
||||
prefix: '₱',
|
||||
country: 'Philippines',
|
||||
},
|
||||
PK: {
|
||||
currency: 'PKR',
|
||||
prefix: '₨',
|
||||
country: 'Pakistan',
|
||||
},
|
||||
PL: {
|
||||
currency: 'PLN',
|
||||
prefix: 'zł',
|
||||
country: 'Poland',
|
||||
},
|
||||
PY: {
|
||||
currency: 'PYG',
|
||||
prefix: '₲',
|
||||
country: 'Paraguay',
|
||||
},
|
||||
QA: {
|
||||
currency: 'QAR',
|
||||
prefix: 'ر.ق.',
|
||||
country: 'Qatar',
|
||||
},
|
||||
RO: {
|
||||
currency: 'RON',
|
||||
prefix: 'RON',
|
||||
country: 'Romania',
|
||||
},
|
||||
RS: {
|
||||
currency: 'RSD',
|
||||
prefix: 'дин.',
|
||||
country: 'Serbia',
|
||||
},
|
||||
RU: {
|
||||
currency: 'RUB',
|
||||
prefix: '₽',
|
||||
country: 'Russian Federation',
|
||||
},
|
||||
RW: {
|
||||
currency: 'RWF',
|
||||
prefix: 'FR',
|
||||
country: 'Rwanda',
|
||||
},
|
||||
SA: {
|
||||
currency: 'SAR',
|
||||
prefix: 'ر.س.',
|
||||
country: 'Saudi Arabia',
|
||||
},
|
||||
SD: {
|
||||
currency: 'SDG',
|
||||
prefix: 'SDG',
|
||||
country: 'Sudan',
|
||||
},
|
||||
SE: {
|
||||
currency: 'SEK',
|
||||
prefix: 'kr',
|
||||
country: 'Sweden',
|
||||
},
|
||||
SG: {
|
||||
currency: 'SGD',
|
||||
prefix: '$',
|
||||
country: 'Singapore',
|
||||
},
|
||||
SJ: {
|
||||
currency: 'NOK',
|
||||
prefix: 'kr',
|
||||
country: 'Svalbard and Jan Mayen',
|
||||
},
|
||||
SN: {
|
||||
currency: 'XOF',
|
||||
prefix: 'CFA',
|
||||
country: 'Senegal',
|
||||
},
|
||||
SO: {
|
||||
currency: 'SOS',
|
||||
prefix: 'Ssh',
|
||||
country: 'Somalia',
|
||||
},
|
||||
SY: {
|
||||
currency: 'SYP',
|
||||
prefix: 'ل.س.',
|
||||
country: 'Syrian Arab Republic',
|
||||
},
|
||||
TH: {
|
||||
currency: 'THB',
|
||||
prefix: '฿',
|
||||
country: 'Thailand',
|
||||
},
|
||||
TN: {
|
||||
currency: 'TND',
|
||||
prefix: 'د.ت.',
|
||||
country: 'Tunisia',
|
||||
},
|
||||
TO: {
|
||||
currency: 'TOP',
|
||||
prefix: 'T$',
|
||||
country: 'Tonga',
|
||||
},
|
||||
TR: {
|
||||
currency: 'TRY',
|
||||
prefix: 'TL',
|
||||
country: 'Turkey',
|
||||
},
|
||||
TT: {
|
||||
currency: 'TTD',
|
||||
prefix: '$',
|
||||
country: 'Trinidad and Tobago',
|
||||
},
|
||||
TW: {
|
||||
currency: 'TWD',
|
||||
prefix: 'NT$',
|
||||
country: 'Taiwan, Province of China',
|
||||
},
|
||||
TZ: {
|
||||
currency: 'TZS',
|
||||
prefix: 'TSh',
|
||||
country: 'United Republic of Tanzania',
|
||||
},
|
||||
UA: {
|
||||
currency: 'UAH',
|
||||
prefix: '₴',
|
||||
country: 'Ukraine',
|
||||
},
|
||||
UG: {
|
||||
currency: 'UGX',
|
||||
prefix: 'USh',
|
||||
country: 'Uganda',
|
||||
},
|
||||
US: {
|
||||
currency: 'USD',
|
||||
prefix: '$',
|
||||
country: 'United States',
|
||||
},
|
||||
UY: {
|
||||
currency: 'UYU',
|
||||
prefix: '$',
|
||||
country: 'Uruguay',
|
||||
},
|
||||
UZ: {
|
||||
currency: 'UZS',
|
||||
prefix: 'UZS',
|
||||
country: 'Uzbekistan',
|
||||
},
|
||||
VE: {
|
||||
currency: 'VEF',
|
||||
prefix: 'Bs.F.',
|
||||
country: 'Venezuela',
|
||||
},
|
||||
VN: {
|
||||
currency: 'VND',
|
||||
prefix: '₫',
|
||||
country: 'Vietnam',
|
||||
},
|
||||
VU: {
|
||||
currency: 'VUV',
|
||||
prefix: 'VT',
|
||||
country: 'Vanuatu',
|
||||
},
|
||||
YE: {
|
||||
currency: 'YER',
|
||||
prefix: 'ر.ي.',
|
||||
country: 'Yemen',
|
||||
},
|
||||
ZA: {
|
||||
currency: 'ZAR',
|
||||
prefix: 'R',
|
||||
country: 'South Africa',
|
||||
},
|
||||
ZM: {
|
||||
currency: 'ZMK',
|
||||
prefix: 'ZK',
|
||||
country: 'Zambia',
|
||||
},
|
||||
};
|
||||
10
frontend/src/AppBuilder/Widgets/PhoneCurrency/utils.js
Normal file
10
frontend/src/AppBuilder/Widgets/PhoneCurrency/utils.js
Normal file
|
|
@ -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 '';
|
||||
}
|
||||
};
|
||||
256
frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx
Normal file
256
frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
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: `0px ${borderRadius}px ${borderRadius}px 0px`,
|
||||
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 countryCode = getCountryCallingCodeSafe(country);
|
||||
console.log(countryCode);
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
data-cy={`label-${String(componentName).toLowerCase()}`}
|
||||
className={`text-input d-flex phone-input-widget ${
|
||||
defaultAlignment === 'top' &&
|
||||
((width != 0 && label?.length != 0) || (auto && width == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: 'align-items-center'
|
||||
} ${direction === 'right' && defaultAlignment === 'side' ? 'flex-row-reverse' : ''}
|
||||
${direction === 'right' && defaultAlignment === 'top' ? 'text-right' : ''}
|
||||
${visibility || 'invisible'}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
label={label}
|
||||
width={width}
|
||||
labelRef={labelRef}
|
||||
darkMode={darkMode}
|
||||
color={color}
|
||||
defaultAlignment={defaultAlignment}
|
||||
direction={direction}
|
||||
auto={auto}
|
||||
isMandatory={isMandatory}
|
||||
_width={_width}
|
||||
labelWidth={labelWidth}
|
||||
/>
|
||||
<div className="d-flex h-100 w-100" style={{ boxShadow, borderRadius: `${borderRadius}px` }}>
|
||||
<CountrySelect
|
||||
value={{ label: `${en[country]} +${getCountryCallingCodeSafe(country)}`, value: country }}
|
||||
options={options}
|
||||
isCountryChangeEnabled={isCountryChangeEnabled}
|
||||
disabledState={disabledState}
|
||||
borderRadius={borderRadius}
|
||||
isValid={isValid}
|
||||
computedStyles={computedStyles}
|
||||
showValidationError={showValidationError}
|
||||
darkMode={darkMode}
|
||||
onChange={(selectedOption) => {
|
||||
if (selectedOption) {
|
||||
setCountry(selectedOption.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
{...(countryCode && { country: country })}
|
||||
// country={country}
|
||||
international={false}
|
||||
value={value}
|
||||
onChange={onInputValueChange}
|
||||
placeholder={placeholder}
|
||||
style={computedStyles}
|
||||
className={`tj-text-input-widget ${
|
||||
!isValid && showValidationError ? 'is-invalid' : ''
|
||||
} validation-without-icon`}
|
||||
disabled={disabledState}
|
||||
data-ignore-hover={true}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
</div>
|
||||
{loading && <Loader style={loaderStyle} width="16" />}
|
||||
</div>
|
||||
{showValidationError && visibility && (
|
||||
<div
|
||||
data-cy={`${String(componentName).toLowerCase()}-invalid-feedback`}
|
||||
style={{
|
||||
color: errTextColor !== '#D72D39' ? errTextColor : 'var(--status-error-strong)',
|
||||
textAlign: direction == 'left' && 'end',
|
||||
fontSize: '11px',
|
||||
fontWeight: '400',
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
9
frontend/src/AppBuilder/Widgets/TextArea.jsx
Normal file
9
frontend/src/AppBuilder/Widgets/TextArea.jsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react';
|
||||
import { BaseInput } from './BaseComponents/BaseInput';
|
||||
import { useInput } from './BaseComponents/hooks/useInput';
|
||||
|
||||
export const TextArea = (props) => {
|
||||
const inputLogic = useInput(props);
|
||||
|
||||
return <BaseInput {...props} {...inputLogic} inputType="textarea" />;
|
||||
};
|
||||
9
frontend/src/AppBuilder/Widgets/TextInput.jsx
Normal file
9
frontend/src/AppBuilder/Widgets/TextInput.jsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react';
|
||||
import { BaseInput } from './BaseComponents/BaseInput';
|
||||
import { useInput } from './BaseComponents/hooks/useInput';
|
||||
|
||||
export const TextInput = (props) => {
|
||||
const inputLogic = useInput(props);
|
||||
|
||||
return <BaseInput {...props} {...inputLogic} inputType="text" />;
|
||||
};
|
||||
|
|
@ -4,9 +4,9 @@ import { Text } from '@/Editor/Components/Text';
|
|||
// import { Table } from '@/Editor/Components/Table/Table';
|
||||
import { Table } from '@/AppBuilder/Widgets/Table/Table';
|
||||
|
||||
import { TextInput } from '@/Editor/Components/TextInput';
|
||||
import { NumberInput } from '@/Editor/Components/NumberInput';
|
||||
import { TextArea } from '@/Editor/Components/TextArea';
|
||||
import { TextInput } from '@/AppBuilder/Widgets/TextInput';
|
||||
import { TextArea } from '@/AppBuilder/Widgets/TextArea';
|
||||
import { NumberInput } from '@/AppBuilder/Widgets/NumberInput';
|
||||
import { RichTextEditor } from '@/Editor/Components/RichTextEditor';
|
||||
import { DropDown } from '@/Editor/Components/DropDown';
|
||||
import { DropdownV2 } from '@/Editor/Components/DropdownV2/DropdownV2';
|
||||
|
|
@ -29,7 +29,10 @@ import { RadioButtonV2 } from '@/Editor/Components/RadioButtonV2/RadioButtonV2';
|
|||
import { StarRating } from '@/Editor/Components/StarRating';
|
||||
import { Divider } from '@/Editor/Components/Divider';
|
||||
import { FilePicker } from '@/Editor/Components/FilePicker';
|
||||
import { PasswordInput } from '@/Editor/Components/PasswordInput';
|
||||
import { PasswordInput } from '@/AppBuilder/Widgets/PasswordInput';
|
||||
import { EmailInput } from '@/AppBuilder/Widgets/EmailInput';
|
||||
import { PhoneInput } from '@/AppBuilder/Widgets/PhoneCurrency/PhoneInput';
|
||||
import { CurrencyInput } from '@/AppBuilder/Widgets/PhoneCurrency/CurrencyInput';
|
||||
// import { Calendar } from '@/Editor/Components/Calendar';
|
||||
// import { Listview } from '@/Editor/Components/Listview';
|
||||
import { IFrame } from '@/Editor/Components/IFrame';
|
||||
|
|
@ -118,6 +121,9 @@ export const AllComponents = {
|
|||
Divider,
|
||||
FilePicker,
|
||||
PasswordInput,
|
||||
EmailInput,
|
||||
PhoneInput,
|
||||
CurrencyInput,
|
||||
Calendar,
|
||||
IFrame,
|
||||
CodeEditor,
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ export const createComponentsSlice = (set, get) => ({
|
|||
}
|
||||
},
|
||||
|
||||
validateWidget: ({ validationObject, widgetValue, customResolveObjects }) => {
|
||||
validateWidget: ({ validationObject, widgetValue, customResolveObjects, componentType }) => {
|
||||
const { getResolvedValue } = get();
|
||||
let isValid = true;
|
||||
let validationError = null;
|
||||
|
|
@ -455,6 +455,17 @@ export const createComponentsSlice = (set, get) => ({
|
|||
validationRegex = typeof validationRegex === 'string' ? validationRegex : '';
|
||||
const re = new RegExp(validationRegex, 'g');
|
||||
|
||||
if (componentType === 'EmailInput' && widgetValue) {
|
||||
const validationRegex = '^(?!.*\\.\\.)([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$';
|
||||
const emailRegex = new RegExp(validationRegex, 'g');
|
||||
if (!emailRegex.test(widgetValue)) {
|
||||
return {
|
||||
isValid: false,
|
||||
validationError: 'Input should be a valid email',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!re.test(widgetValue)) {
|
||||
return {
|
||||
isValid: false,
|
||||
|
|
@ -1833,6 +1844,9 @@ export const createComponentsSlice = (set, get) => ({
|
|||
![
|
||||
'TextInput',
|
||||
'PasswordInput',
|
||||
'EmailInput',
|
||||
'PhoneInput',
|
||||
'CurrencyInput',
|
||||
'NumberInput',
|
||||
'DropdownV2',
|
||||
'MultiselectV2',
|
||||
|
|
@ -1841,6 +1855,7 @@ export const createComponentsSlice = (set, get) => ({
|
|||
'DaterangePicker',
|
||||
'DatePickerV2',
|
||||
'TimePicker',
|
||||
'TextArea',
|
||||
].includes(componentType)
|
||||
) {
|
||||
return layoutData?.height;
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
export const TextArea = function TextArea({
|
||||
height,
|
||||
properties,
|
||||
styles,
|
||||
setExposedVariable,
|
||||
setExposedVariables,
|
||||
dataCy,
|
||||
}) {
|
||||
const isInitialRender = useRef(true);
|
||||
const [value, setValue] = useState(properties.value);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setValue(properties.value);
|
||||
setExposedVariable('value', properties.value);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [properties.value]);
|
||||
|
||||
useEffect(() => {
|
||||
const exposedVariables = {
|
||||
setText: async function (text) {
|
||||
setValue(text);
|
||||
setExposedVariable('value', text);
|
||||
},
|
||||
clear: async function () {
|
||||
setValue('');
|
||||
setExposedVariable('value', '');
|
||||
},
|
||||
value: properties.value,
|
||||
};
|
||||
setExposedVariables(exposedVariables);
|
||||
setValue(properties.value);
|
||||
isInitialRender.current = false;
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<textarea
|
||||
disabled={styles.disabledState}
|
||||
onChange={(e) => {
|
||||
setValue(e.target.value);
|
||||
setExposedVariable('value', e.target.value);
|
||||
}}
|
||||
type="text"
|
||||
className="form-control textarea"
|
||||
placeholder={properties.placeholder}
|
||||
style={{
|
||||
height,
|
||||
resize: 'none',
|
||||
display: styles.visibility ? '' : 'none',
|
||||
borderRadius: `${styles.borderRadius}px`,
|
||||
boxShadow: styles.boxShadow,
|
||||
}}
|
||||
value={value}
|
||||
data-cy={dataCy}
|
||||
></textarea>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { widgets } from './widgetConfig';
|
||||
import { widgets } from '../../AppBuilder/WidgetManager/configs/widgetConfig';
|
||||
|
||||
const universalProps = {
|
||||
properties: {},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export const textareaConfig = {
|
|||
description: 'Multi-line text input',
|
||||
component: 'TextArea',
|
||||
defaultSize: {
|
||||
width: 6,
|
||||
width: 10,
|
||||
height: 100,
|
||||
},
|
||||
others: {
|
||||
|
|
@ -12,82 +12,291 @@ export const textareaConfig = {
|
|||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'default text',
|
||||
},
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Placeholder text',
|
||||
defaultValue: 'Enter your input',
|
||||
},
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconHome2' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 4,
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setText',
|
||||
displayName: 'Set Text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New Text' }],
|
||||
displayName: 'Set text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'disable',
|
||||
displayName: 'Disable(deprecated)',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'visibility',
|
||||
displayName: 'Visibility(deprecated)',
|
||||
params: [{ handle: 'visibility', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
},
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter your input' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
borderRadius: { value: '{{4}}' },
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CFD3D859' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconHome2' },
|
||||
iconVisibility: { value: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ export const LEGACY_ITEMS = [
|
|||
'MultiselectLegacy',
|
||||
'RadioButtonLegacy',
|
||||
'ModalLegacy',
|
||||
'TextareaLegacy',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2486,7 +2486,9 @@ export const setMultipleComponentsSelected = (components) => {
|
|||
|
||||
export const calculateMoveableBoxHeight = (componentType, layoutData, stylesDefinition, label) => {
|
||||
// Early return for non input components
|
||||
if (!['TextInput', 'PasswordInput', 'NumberInput', 'DropdownV2', 'MultiselectV2'].includes(componentType)) {
|
||||
if (
|
||||
!['TextInput', 'PasswordInput', 'NumberInput', 'DropdownV2', 'MultiselectV2', 'TextArea'].includes(componentType)
|
||||
) {
|
||||
return layoutData?.height;
|
||||
}
|
||||
const { alignment = { value: null }, width = { value: null }, auto = { value: null } } = stylesDefinition ?? {};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { Text } from '@/Editor/Components/Text';
|
|||
import { Table } from '@/Editor/Components/Table/Table';
|
||||
import { TextInput } from '@/Editor/Components/TextInput';
|
||||
import { NumberInput } from '@/Editor/Components/NumberInput';
|
||||
import { TextArea } from '@/Editor/Components/TextArea';
|
||||
import { Container } from '@/Editor/Components/Container';
|
||||
import { Tabs } from '@/Editor/Components/Tabs';
|
||||
import { RichTextEditor } from '@/Editor/Components/RichTextEditor';
|
||||
|
|
@ -81,7 +80,6 @@ export const AllComponents = {
|
|||
TextInput,
|
||||
NumberInput,
|
||||
Table,
|
||||
TextArea,
|
||||
Container,
|
||||
Tabs,
|
||||
RichTextEditor,
|
||||
|
|
|
|||
|
|
@ -15766,6 +15766,11 @@ tbody {
|
|||
/* Set the desired width */
|
||||
}
|
||||
|
||||
textarea.tj-text-input-widget{
|
||||
resize: none !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.tj-text-input-widget {
|
||||
border: 1px solid var(--borders-default);
|
||||
background-color: var(--surfaces-surface-01);
|
||||
|
|
@ -15777,7 +15782,7 @@ tbody {
|
|||
background-color: var(--surfaces-surface-03);
|
||||
}
|
||||
|
||||
&:hover:not(:focus) {
|
||||
&:hover:not(:focus):not([data-ignore-hover="true"]) {
|
||||
border: 1px solid var(--tblr-input-border-color-darker) !important;
|
||||
}
|
||||
|
||||
|
|
@ -18664,6 +18669,16 @@ section.ai-message-prompt-input-wrapper {
|
|||
}
|
||||
}
|
||||
|
||||
.phone-input-widget {
|
||||
.tj-text-input-widget.is-invalid {
|
||||
border-left: none !important;
|
||||
}
|
||||
|
||||
input[type="tel"] {
|
||||
border-top-left-radius: '0px' !important;
|
||||
border-bottom-left-radius: '0px' !important;
|
||||
}
|
||||
}
|
||||
|
||||
.single-line-codehinter-input {
|
||||
.cm-editor {
|
||||
|
|
|
|||
27
frontend/src/_ui/Icon/bulkIcons/Planet.jsx
Normal file
27
frontend/src/_ui/Icon/bulkIcons/Planet.jsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react';
|
||||
|
||||
const Globe = ({ fill = '#C1C8CD', width = '25', className = '', viewBox = '0 0 25 25' }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox={viewBox}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M10.0007 0.833252C10.1655 0.833252 10.3293 0.837601 10.492 0.84619V4.38097C10.492 4.77954 10.3363 5.15899 10.0635 5.43657C9.79126 5.71355 9.42517 5.86654 9.04648 5.86667C8.63079 5.86643 8.21968 5.95133 7.83775 6.1159C7.45585 6.28045 7.11138 6.52109 6.82442 6.82273C6.53749 7.12434 6.31388 7.48082 6.16617 7.87057C6.02018 8.25585 5.95111 8.66633 5.96263 9.07827V10.9704C5.96263 11.1675 5.92448 11.3623 5.85066 11.5436C5.77687 11.7249 5.66908 11.8887 5.53411 12.026C5.39917 12.1633 5.23975 12.2715 5.06535 12.345C4.89095 12.4185 4.70456 12.4561 4.51666 12.4561H1.1669C0.950015 11.6744 0.834106 10.8507 0.834106 9.9999C0.834106 4.9373 4.93815 0.833252 10.0007 0.833252Z"
|
||||
fill="#ACB2B9"
|
||||
/>
|
||||
<path
|
||||
d="M10.0008 19.1667C6.40942 19.1667 3.30045 17.1013 1.79675 14.0937H4.51669C4.92362 14.0937 5.32619 14.012 5.70134 13.854C6.07645 13.6959 6.41635 13.4645 6.702 13.1739C6.98763 12.8832 7.21346 12.539 7.36728 12.1611C7.52111 11.7832 7.60009 11.3787 7.60009 10.9705V9.06607C7.60009 9.0572 7.59995 9.04833 7.59966 9.03946C7.59313 8.83827 7.62646 8.63807 7.69738 8.45092C7.76829 8.26379 7.87513 8.09405 8.0108 7.95142C8.14645 7.80883 8.30811 7.6963 8.48572 7.61977C8.66331 7.54325 8.85367 7.50407 9.04561 7.50419C9.868 7.50419 10.6542 7.17162 11.2314 6.58439C11.808 5.99764 12.1295 5.20482 12.1295 4.38106V1.08179C15.6979 1.93038 18.4579 4.86524 19.0496 8.52639H13.5132C13.489 8.52639 13.4648 8.52747 13.4407 8.5296C12.6407 8.60066 11.8929 8.96189 11.3459 9.54756C10.7984 10.1337 10.492 10.9024 10.492 11.7031C10.492 12.5039 10.7984 13.2725 11.3459 13.8587C11.8929 14.4443 12.6407 14.8056 13.4407 14.8767C13.4679 14.8791 13.4952 14.8802 13.5225 14.8799C13.6425 14.8784 13.7613 14.9005 13.8716 14.9441C13.982 14.9877 14.0811 15.0518 14.1639 15.1318C14.2467 15.2118 14.3114 15.306 14.3552 15.4086C14.3989 15.511 14.4212 15.6203 14.4212 15.7302V18.0323C13.1104 18.7552 11.6036 19.1667 10.0008 19.1667Z"
|
||||
fill="#ACB2B9"
|
||||
/>
|
||||
<path
|
||||
d="M16.0586 16.8795C17.9267 15.2333 19.119 12.8381 19.1659 10.1636H13.553C13.1621 10.2061 12.8033 10.3858 12.5425 10.665C12.2749 10.9514 12.1294 11.3219 12.1294 11.7029C12.1294 12.0839 12.2749 12.4544 12.5425 12.7408C12.8032 13.0199 13.1619 13.1996 13.5527 13.2422C13.8677 13.2446 14.18 13.3051 14.4733 13.4209C14.7816 13.5428 15.0635 13.7237 15.3019 13.9542C15.5404 14.1847 15.7307 14.4602 15.861 14.7653C15.9912 15.0702 16.0586 15.3982 16.0586 15.7299V16.8795Z"
|
||||
fill="#ACB2B9"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Globe;
|
||||
|
|
@ -118,6 +118,7 @@ import Lock from './Lock.jsx';
|
|||
import AddTemplate from './AddTemplate.jsx';
|
||||
import InviteCollaborator from './InviteCollabarator.jsx';
|
||||
import CloseIcon from './CloseIcon.jsx';
|
||||
import Planet from './Planet.jsx';
|
||||
|
||||
const Icon = (props) => {
|
||||
switch (props.name) {
|
||||
|
|
@ -361,7 +362,8 @@ const Icon = (props) => {
|
|||
return <Comments {...props} />;
|
||||
case 'checkcircle':
|
||||
return <CheckCircle {...props} />;
|
||||
|
||||
case 'planet':
|
||||
return <Planet {...props} />;
|
||||
default:
|
||||
return <Apps {...props} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,10 +297,18 @@ input:checked+.slider:before {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.theme-dark {
|
||||
.form-control {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
.react-tel-input .form-control {
|
||||
background-color: inherit !important; // Or any default value you prefer
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
import { Component } from 'src/entities/component.entity';
|
||||
import { processDataInBatches } from '@helpers/migration.helper';
|
||||
import { EntityManager, MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class MoveVisibilityDisabledStatesToPropertiesTextarea1736448327127 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const batchSize = 100;
|
||||
const entityManager = queryRunner.manager;
|
||||
|
||||
await processDataInBatches(
|
||||
entityManager,
|
||||
async (entityManager: EntityManager) => {
|
||||
return await entityManager.find(Component, {
|
||||
where: { type: 'TextArea' },
|
||||
order: { createdAt: 'ASC' },
|
||||
});
|
||||
},
|
||||
async (entityManager: EntityManager, components: Component[]) => {
|
||||
await this.processUpdates(entityManager, components);
|
||||
},
|
||||
batchSize
|
||||
);
|
||||
}
|
||||
|
||||
private async processUpdates(entityManager, components) {
|
||||
for (const component of components) {
|
||||
const properties = component.properties;
|
||||
const styles = component.styles;
|
||||
const general = component.general;
|
||||
const generalStyles = component.generalStyles;
|
||||
const validation = component.validation;
|
||||
|
||||
if (styles.visibility) {
|
||||
properties.visibility = styles?.visibility;
|
||||
delete styles?.visibility;
|
||||
}
|
||||
|
||||
if (styles.disabledState) {
|
||||
properties.disabledState = styles?.disabledState;
|
||||
delete styles?.disabledState;
|
||||
}
|
||||
|
||||
if (generalStyles?.boxShadow) {
|
||||
styles.boxShadow = generalStyles?.boxShadow;
|
||||
delete generalStyles?.boxShadow;
|
||||
}
|
||||
|
||||
// Label and value
|
||||
if (properties.label == undefined || null) {
|
||||
properties.label = '';
|
||||
}
|
||||
|
||||
await entityManager.update(Component, component.id, {
|
||||
properties,
|
||||
styles,
|
||||
general,
|
||||
generalStyles,
|
||||
validation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {}
|
||||
}
|
||||
305
server/src/modules/apps/services/widget-config/currencyinput.js
Normal file
305
server/src/modules/apps/services/widget-config/currencyinput.js
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
export const currencyinputConfig = {
|
||||
name: 'CurrencyInput',
|
||||
displayName: 'Currency Input',
|
||||
description: 'Currency input field',
|
||||
component: 'CurrencyInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter your number',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 0,
|
||||
},
|
||||
},
|
||||
decimalPlaces: {
|
||||
type: 'code',
|
||||
displayName: 'Decimal places',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: '2' },
|
||||
},
|
||||
isCountryChangeEnabled: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable currency change',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minValue: { type: 'code', displayName: 'Min value', placeholder: 'Enter min value' },
|
||||
maxValue: { type: 'code', displayName: 'Max value', placeholder: 'Enter max value' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconHome2' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set Value',
|
||||
params: [
|
||||
{ handle: 'value', displayName: 'value', defaultValue: '' },
|
||||
{ handle: 'country', displayName: 'country', defaultValue: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minValue: { value: '' },
|
||||
maxValue: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '0' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter amount' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
isCountryChangeEnabled: { value: '{{true}}' },
|
||||
decimalPlaces: { value: '2' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CFD3D859' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconHome2' },
|
||||
iconVisibility: { value: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
292
server/src/modules/apps/services/widget-config/emailinput.js
Normal file
292
server/src/modules/apps/services/widget-config/emailinput.js
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
export const emailinputConfig = {
|
||||
name: 'EmailInput',
|
||||
displayName: 'Email Input',
|
||||
description: 'Email input field',
|
||||
component: 'EmailInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter email',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconMailFilled' },
|
||||
accordian: 'field',
|
||||
visibility: true,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setText',
|
||||
displayName: 'Set text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter email' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CCD1D5' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconMailFilled' },
|
||||
iconVisibility: { value: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -58,6 +58,9 @@ import { kanbanBoardConfig } from './kanbanBoard';
|
|||
import { datetimePickerV2Config } from './datetimepickerV2';
|
||||
import { datePickerV2Config } from './datepickerV2';
|
||||
import { timePickerConfig } from './timepicker';
|
||||
import { emailinputConfig } from './emailinput';
|
||||
import { phoneinputConfig } from './phoneinput';
|
||||
import {currencyinputConfig} from './currencyinput';
|
||||
|
||||
const widgets = {
|
||||
buttonConfig,
|
||||
|
|
@ -73,12 +76,15 @@ const widgets = {
|
|||
datetimePickerV2Config,
|
||||
datePickerV2Config,
|
||||
timePickerConfig,
|
||||
emailinputConfig,
|
||||
phoneinputConfig,
|
||||
currencyinputConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig, //!Depreciated
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig, //!Depreciated
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
textareaConfig, //! Deprecated
|
||||
daterangepickerConfig,
|
||||
textConfig,
|
||||
imageConfig,
|
||||
|
|
|
|||
288
server/src/modules/apps/services/widget-config/phoneinput.js
Normal file
288
server/src/modules/apps/services/widget-config/phoneinput.js
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
export const phoneinputConfig = {
|
||||
name: 'PhoneInput',
|
||||
displayName: 'Phone Input',
|
||||
description: 'Phone input field',
|
||||
component: 'PhoneInput',
|
||||
defaultSize: {
|
||||
width: 10,
|
||||
height: 40,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter your input',
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
isCountryChangeEnabled: {
|
||||
type: 'toggle',
|
||||
displayName: 'Enable country change',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set Value',
|
||||
params: [
|
||||
{ handle: 'value', displayName: 'value', defaultValue: '' },
|
||||
{ handle: 'country', displayName: 'country', defaultValue: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
handle: 'setCountryCode',
|
||||
displayName: 'Set country code',
|
||||
params: [{ handle: 'countryCode', displayName: 'Country code', defaultValue: '' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter your phone' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
isCountryChangeEnabled: { value: '{{true}}' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ export const textareaConfig = {
|
|||
description: 'Multi-line text input',
|
||||
component: 'TextArea',
|
||||
defaultSize: {
|
||||
width: 6,
|
||||
width: 10,
|
||||
height: 100,
|
||||
},
|
||||
others: {
|
||||
|
|
@ -12,82 +12,291 @@ export const textareaConfig = {
|
|||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'default text',
|
||||
},
|
||||
displayName: 'Label',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
displayName: 'Placeholder',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Placeholder text',
|
||||
defaultValue: 'Enter your input',
|
||||
},
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
defaultValue: 'Default value',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: false },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
validation: {
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
regex: { type: 'code', displayName: 'Regex', placeholder: '^[a-zA-Z0-9_ -]{3,16}$' },
|
||||
minLength: { type: 'code', displayName: 'Min length', placeholder: 'Enter min length' },
|
||||
maxLength: { type: 'code', displayName: 'Max length', placeholder: 'Enter max length' },
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onChange: { displayName: 'On change' },
|
||||
onEnterPressed: { displayName: 'On enter pressed' },
|
||||
onFocus: { displayName: 'On focus' },
|
||||
onBlur: { displayName: 'On blur' },
|
||||
},
|
||||
styles: {
|
||||
color: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: '',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
width: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#fff' },
|
||||
accordian: 'field',
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
|
||||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
},
|
||||
textColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'field',
|
||||
},
|
||||
errTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Error text',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
|
||||
accordian: 'field',
|
||||
},
|
||||
icon: {
|
||||
type: 'icon',
|
||||
displayName: 'Icon',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'IconHome2' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
},
|
||||
iconColor: {
|
||||
type: 'color',
|
||||
displayName: 'Icon color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
|
||||
accordian: 'field',
|
||||
visibility: false,
|
||||
showLabel: false,
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 6 },
|
||||
accordian: 'field',
|
||||
},
|
||||
boxShadow: {
|
||||
type: 'boxShadow',
|
||||
displayName: 'Box Shadow',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 4,
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: '0px 0px 0px 0px #00000040',
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
value: '',
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setText',
|
||||
displayName: 'Set Text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New Text' }],
|
||||
displayName: 'Set text',
|
||||
params: [{ handle: 'text', displayName: 'text', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'clear',
|
||||
displayName: 'Clear',
|
||||
},
|
||||
{
|
||||
handle: 'setFocus',
|
||||
displayName: 'Set focus',
|
||||
},
|
||||
{
|
||||
handle: 'setBlur',
|
||||
displayName: 'Set blur',
|
||||
},
|
||||
{
|
||||
handle: 'disable',
|
||||
displayName: 'Disable(deprecated)',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'visibility',
|
||||
displayName: 'Visibility(deprecated)',
|
||||
params: [{ handle: 'visibility', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'loading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
regex: { value: '' },
|
||||
minLength: { value: '' },
|
||||
maxLength: { value: '' },
|
||||
customRule: { value: '' },
|
||||
},
|
||||
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
value: {
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
},
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
value: { value: '' },
|
||||
label: { value: 'Label' },
|
||||
placeholder: { value: 'Enter your input' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
tooltip: { value: '' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
borderRadius: { value: '{{4}}' },
|
||||
textColor: { value: '#1B1F24' },
|
||||
borderColor: { value: '#CCD1D5' },
|
||||
accentColor: { value: '#4368E3' },
|
||||
errTextColor: { value: '#D72D39' },
|
||||
borderRadius: { value: '{{6}}' },
|
||||
backgroundColor: { value: '#fff' },
|
||||
iconColor: { value: '#CFD3D859' },
|
||||
direction: { value: 'left' },
|
||||
width: { value: '{{33}}' },
|
||||
alignment: { value: 'side' },
|
||||
color: { value: '#1B1F24' },
|
||||
auto: { value: '{{true}}' },
|
||||
padding: { value: 'default' },
|
||||
boxShadow: { value: '0px 0px 0px 0px #00000040' },
|
||||
icon: { value: 'IconHome2' },
|
||||
iconVisibility: { value: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue