PromucFlow_constructor/app/client/src/components/ads/TextInput.tsx

376 lines
10 KiB
TypeScript
Raw Normal View History

feat: Undo/Redo (#6654) * Scaffolding for undo-redo * undo redo working Poc commit * memory performance improvements by diffing * dont run update on undo/redo" * merging widget postion update and canvas bottom row update into one dsl update. * fix tabs widget * Visible updates per undo redo action (#6838) Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> * resize atomic operation * fix switch control state issue * disallow undo/redo for snipping and comment mode * disallow undo/redo for snipping and comment mode * fix color picker issue in undo/redo * add test for replayDSL * option control fix, adding logs * minor position change undo redo updates * add test cases for replayHelpers * property Upade visual change * remove unused code * global hot key jest test for undo redo * Fixing batch updates on property change.. * add tests for toggle control in property pane * unwanted utils. * add tests for text control * add tests for deletion * add tests for dropping a new widget * adding jest test for replayUtils * add move widget tests * add tests for color picker control * add analytics for undo/redo * add analytics for undo/redo * tab addition atomic * cypress tests for propertyPane, toasts and radiowidget optionControl * replayDSL end of redo stack fix * property update changes * menu option control debounce input * color picker empty undo fix * fix cypress tests * widget add/remove atomic * revert alternative approach to handle atomic operations * update replayDSL test * add some comments * addressing review comments * flash color for property pane controls * Fixing adding of tabs widget as well. * code review comments. * merging widget postion update and canvas bottom row update into one dsl update. * fix ordering of tabs property control * meta property update canvas min height. * fixing failed specs. * Fixing entity explorer update on deleting tab from entity explorer. * address review comments and minor property update changes * fixing failing tests * merge conflicts * changes to cater widget api. * fix suggested widget table issue * draggable list for undo redo * fix widget name focus * excluding canvas updates. * fixing codeEditor update on propertySection collapse * fixed failing test case Co-authored-by: Abhinav Jha <abhinav@appsmith.com> Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-09-21 07:55:56 +00:00
import React, {
EventHandler,
FocusEvent,
forwardRef,
Ref,
useCallback,
useMemo,
useState,
} from "react";
import { Classes, CommonComponentProps, hexToRgba } from "./common";
import styled, { withTheme } from "styled-components";
2020-08-14 04:58:03 +00:00
import Text, { TextType } from "./Text";
import {
ERROR_MESSAGE_NAME_EMPTY,
createMessage,
FORM_VALIDATION_INVALID_EMAIL,
} from "constants/messages";
import { isEmail } from "utils/formhelpers";
import Icon, { IconCollection, IconName, IconSize } from "./Icon";
2021-05-03 05:49:12 +00:00
import { AsyncControllableInput } from "@blueprintjs/core/lib/esm/components/forms/asyncControllableInput";
import _ from "lodash";
export type Validator = (
value: string,
) => {
isValid: boolean;
message: string;
};
export function emailValidator(email: string) {
let isValid = true;
if (email) {
isValid = isEmail(email);
}
return {
isValid: isValid,
message: !isValid ? createMessage(FORM_VALIDATION_INVALID_EMAIL) : "",
};
}
export function notEmptyValidator(value: string) {
const isValid = !!value;
return {
isValid: isValid,
message: !isValid ? createMessage(ERROR_MESSAGE_NAME_EMPTY) : "",
};
}
2020-08-14 04:58:03 +00:00
export type TextInputProps = CommonComponentProps & {
autoFocus?: boolean;
placeholder?: string;
2020-08-14 04:58:03 +00:00
fill?: boolean;
defaultValue?: string;
value?: string;
2020-08-14 04:58:03 +00:00
validator?: (value: string) => { isValid: boolean; message: string };
onChange?: (value: string) => void;
readOnly?: boolean;
dataType?: string;
theme?: any;
leftIcon?: IconName;
helperText?: string;
rightSideComponent?: React.ReactNode;
width?: string;
height?: string;
noBorder?: boolean;
noCaret?: boolean;
feat: Undo/Redo (#6654) * Scaffolding for undo-redo * undo redo working Poc commit * memory performance improvements by diffing * dont run update on undo/redo" * merging widget postion update and canvas bottom row update into one dsl update. * fix tabs widget * Visible updates per undo redo action (#6838) Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> * resize atomic operation * fix switch control state issue * disallow undo/redo for snipping and comment mode * disallow undo/redo for snipping and comment mode * fix color picker issue in undo/redo * add test for replayDSL * option control fix, adding logs * minor position change undo redo updates * add test cases for replayHelpers * property Upade visual change * remove unused code * global hot key jest test for undo redo * Fixing batch updates on property change.. * add tests for toggle control in property pane * unwanted utils. * add tests for text control * add tests for deletion * add tests for dropping a new widget * adding jest test for replayUtils * add move widget tests * add tests for color picker control * add analytics for undo/redo * add analytics for undo/redo * tab addition atomic * cypress tests for propertyPane, toasts and radiowidget optionControl * replayDSL end of redo stack fix * property update changes * menu option control debounce input * color picker empty undo fix * fix cypress tests * widget add/remove atomic * revert alternative approach to handle atomic operations * update replayDSL test * add some comments * addressing review comments * flash color for property pane controls * Fixing adding of tabs widget as well. * code review comments. * merging widget postion update and canvas bottom row update into one dsl update. * fix ordering of tabs property control * meta property update canvas min height. * fixing failed specs. * Fixing entity explorer update on deleting tab from entity explorer. * address review comments and minor property update changes * fixing failing tests * merge conflicts * changes to cater widget api. * fix suggested widget table issue * draggable list for undo redo * fix widget name focus * excluding canvas updates. * fixing codeEditor update on propertySection collapse * fixed failing test case Co-authored-by: Abhinav Jha <abhinav@appsmith.com> Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-09-21 07:55:56 +00:00
onBlur?: EventHandler<FocusEvent<any>>;
onFocus?: EventHandler<FocusEvent<any>>;
};
2020-08-14 04:58:03 +00:00
type boxReturnType = {
bgColor: string;
color: string;
borderColor: string;
};
Homepage redesign with themes (#482) * Updating homepage body color * WIP: Fixing scrolls and adding anchors * Removing divider from bottom of the page. * Adding hover background color to app card * Changing edit and launch icons. * Fixing app name paddding in card. * Fixing workspaces overflow * Adding right padding to applications view * Adding share icon to share btn * Fixing Application card styles. * Fixing text decoration in button. * Adding new workspace button * Fixing new workspace and new app styles. * Adding icon sizes. * Fixing Org Name and Org settings menu. * Application menu working * Fixing overlay visibility on app card * Fixing settings page content width. * Fixing workspace icon * Changing app card colors. * Removing debugger * Adding app icon. * Fixing the spaces in application card * Adding storybook-static folder to gitignore. * Adding other storybook files. * Adding menu items for app * Removing cypress selector from text. * Menu width issue fixed * Default app icon color added * Removing hardcoded colors * Removing hardcoded colors. * Light Mode on! * Showing correct icon and color in menu * Update color working properly. * Updating appIcon * Editable text working. * Adding validator * Adding edit permissions to menu * Removing box shadow on app card. * Fixing context menu fill color * Fixing Menu hover issues. * Fixing menu open close hover issues. * Fixing settings pages * Changed Workspace to org. * Fix: State management in EditableText Component (#540) * Error state height is fixed as per design * savingState prop condition fixed * Fixing createnew. * Fixing saving state for application card. * Fixed application card editable text error. * Fixing issue caused during merge. * Fixing tests in create org. * Removing commented code. * Removing unwanted vars. * Fixing delete duplicate tests. * Latest color palette. * Fixing form and table widget. * Removing switcher from header * Removing unused files * Fixing app card context dropdown * Show overlay fix * Adding localStorage support to theme. * Making dark mode the default. Co-authored-by: Rohit Kumawat <rohit.kumawat@primathon.in>
2020-09-16 11:50:47 +00:00
const boxStyles = (
props: TextInputProps,
isValid: boolean,
theme: any,
): boxReturnType => {
let bgColor = theme.colors.textInput.normal.bg;
let color = theme.colors.textInput.normal.text;
let borderColor = theme.colors.textInput.normal.border;
2020-08-14 04:58:03 +00:00
if (props.disabled) {
bgColor = theme.colors.textInput.disable.bg;
color = theme.colors.textInput.disable.text;
borderColor = theme.colors.textInput.disable.border;
2020-08-14 04:58:03 +00:00
}
if (props.readOnly) {
bgColor = theme.colors.textInput.readOnly.bg;
color = theme.colors.textInput.readOnly.text;
borderColor = theme.colors.textInput.readOnly.border;
}
2020-08-14 04:58:03 +00:00
if (!isValid) {
bgColor = hexToRgba(theme.colors.danger.main, 0.1);
color = theme.colors.danger.main;
borderColor = theme.colors.danger.main;
}
return { bgColor, color, borderColor };
};
const StyledInput = styled((props) => {
// we are removing non input related props before passing them in the components
// eslint-disable @typescript-eslint/no-unused-vars
const { dataType, inputRef, ...inputProps } = props;
const omitProps = [
"hasLeftIcon",
"inputStyle",
"rightSideComponentWidth",
"theme",
"validator",
"isValid",
"cypressSelector",
"leftIcon",
"helperText",
"rightSideComponent",
"noBorder",
"isLoading",
"noCaret",
"fill",
];
return props.asyncControl ? (
<AsyncControllableInput
{..._.omit(inputProps, omitProps)}
datatype={dataType}
inputRef={inputRef}
/>
) : (
<input ref={inputRef} {..._.omit(inputProps, omitProps)} />
);
})<
TextInputProps & {
inputStyle: boxReturnType;
isValid: boolean;
rightSideComponentWidth: number;
hasLeftIcon: boolean;
}
>`
${(props) => (props.noCaret ? "caret-color: white;" : null)}
color: ${(props) => props.inputStyle.color};
width: ${(props) =>
props.value && !props.noBorder && props.isFocused
? "calc(100% - 50px)"
: "100%"};
2020-08-14 04:58:03 +00:00
border-radius: 0;
outline: 0;
box-shadow: none;
border: none;
padding: 0;
padding-right: ${(props) =>
props.rightSideComponentWidth + props.theme.spaces[5]}px;
background-color: transparent;
font-size: ${(props) => props.theme.typography.p1.fontSize}px;
font-weight: ${(props) => props.theme.typography.p1.fontWeight};
line-height: ${(props) => props.theme.typography.p1.lineHeight}px;
letter-spacing: ${(props) => props.theme.typography.p1.letterSpacing}px;
text-overflow: ellipsis;
2020-08-14 04:58:03 +00:00
&::placeholder {
2020-12-24 04:32:25 +00:00
color: ${(props) => props.theme.colors.textInput.placeholder};
2020-08-14 04:58:03 +00:00
}
&:disabled {
cursor: not-allowed;
}
`;
const InputWrapper = styled.div<{
value?: string;
isFocused: boolean;
fill?: number;
noBorder?: boolean;
height?: string;
width?: string;
inputStyle: boxReturnType;
isValid?: boolean;
disabled?: boolean;
}>`
position: relative;
display: flex;
align-items: center;
padding: 0px ${(props) => props.theme.spaces[6]}px;
width: ${(props) =>
props.fill ? "100%" : props.width ? props.width : "260px"};
height: ${(props) => props.height || "36px"};
border: 1.2px solid ${(props) =>
props.noBorder ? "transparent" : props.inputStyle.borderColor};
background-color: ${(props) => props.inputStyle.bgColor};
color: ${(props) => props.inputStyle.color};
2020-12-24 04:32:25 +00:00
${(props) =>
props.isFocused && !props.noBorder
? `
border: 1.2px solid
${
2020-08-14 04:58:03 +00:00
props.isValid
? props.theme.colors.info.main
: props.theme.colors.danger.main
};
`
: null}
2020-08-14 04:58:03 +00:00
.${Classes.TEXT} {
2020-12-24 04:32:25 +00:00
color: ${(props) => props.theme.colors.danger.main};
2020-08-14 04:58:03 +00:00
}
.helper {
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.textInput.helper};
}
}
&:hover {
background-color: ${(props) =>
props.disabled
? props.inputStyle.bgColor
: props.theme.colors.textInput.hover.bg};
}
${(props) => (props.disabled ? "cursor: not-allowed;" : null)}
`;
const MsgWrapper = styled.div`
position: absolute;
bottom: -20px;
left: 0px;
&.helper {
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.textInput.helper};
}
}
2020-08-14 04:58:03 +00:00
`;
const RightSideContainer = styled.div`
position: absolute;
right: 0;
bottom: 0;
top: 0;
display: flex;
align-items: center;
`;
const IconWrapper = styled.div`
.${Classes.ICON} {
margin-right: ${(props) => props.theme.spaces[5]}px;
}
`;
2020-08-14 04:58:03 +00:00
const TextInput = forwardRef(
(props: TextInputProps, ref: Ref<HTMLInputElement>) => {
const initialValidation = () => {
let validationObj = { isValid: true, message: "" };
if (props.defaultValue && props.validator) {
validationObj = props.validator(props.defaultValue);
}
return validationObj;
};
const [validation, setValidation] = useState<{
isValid: boolean;
message: string;
}>(initialValidation());
const [rightSideComponentWidth, setRightSideComponentWidth] = useState(0);
const [isFocused, setIsFocused] = useState(false);
const [inputValue, setInputValue] = useState(props.defaultValue);
const setRightSideRef = useCallback((ref: HTMLDivElement) => {
if (ref) {
const { width } = ref.getBoundingClientRect();
setRightSideComponentWidth(width);
}
}, []);
Homepage redesign with themes (#482) * Updating homepage body color * WIP: Fixing scrolls and adding anchors * Removing divider from bottom of the page. * Adding hover background color to app card * Changing edit and launch icons. * Fixing app name paddding in card. * Fixing workspaces overflow * Adding right padding to applications view * Adding share icon to share btn * Fixing Application card styles. * Fixing text decoration in button. * Adding new workspace button * Fixing new workspace and new app styles. * Adding icon sizes. * Fixing Org Name and Org settings menu. * Application menu working * Fixing overlay visibility on app card * Fixing settings page content width. * Fixing workspace icon * Changing app card colors. * Removing debugger * Adding app icon. * Fixing the spaces in application card * Adding storybook-static folder to gitignore. * Adding other storybook files. * Adding menu items for app * Removing cypress selector from text. * Menu width issue fixed * Default app icon color added * Removing hardcoded colors * Removing hardcoded colors. * Light Mode on! * Showing correct icon and color in menu * Update color working properly. * Updating appIcon * Editable text working. * Adding validator * Adding edit permissions to menu * Removing box shadow on app card. * Fixing context menu fill color * Fixing Menu hover issues. * Fixing menu open close hover issues. * Fixing settings pages * Changed Workspace to org. * Fix: State management in EditableText Component (#540) * Error state height is fixed as per design * savingState prop condition fixed * Fixing createnew. * Fixing saving state for application card. * Fixed application card editable text error. * Fixing issue caused during merge. * Fixing tests in create org. * Removing commented code. * Removing unwanted vars. * Fixing delete duplicate tests. * Latest color palette. * Fixing form and table widget. * Removing switcher from header * Removing unused files * Fixing app card context dropdown * Show overlay fix * Adding localStorage support to theme. * Making dark mode the default. Co-authored-by: Rohit Kumawat <rohit.kumawat@primathon.in>
2020-09-16 11:50:47 +00:00
const inputStyle = useMemo(
() => boxStyles(props, validation.isValid, props.theme),
[props, validation.isValid, props.theme],
Homepage redesign with themes (#482) * Updating homepage body color * WIP: Fixing scrolls and adding anchors * Removing divider from bottom of the page. * Adding hover background color to app card * Changing edit and launch icons. * Fixing app name paddding in card. * Fixing workspaces overflow * Adding right padding to applications view * Adding share icon to share btn * Fixing Application card styles. * Fixing text decoration in button. * Adding new workspace button * Fixing new workspace and new app styles. * Adding icon sizes. * Fixing Org Name and Org settings menu. * Application menu working * Fixing overlay visibility on app card * Fixing settings page content width. * Fixing workspace icon * Changing app card colors. * Removing debugger * Adding app icon. * Fixing the spaces in application card * Adding storybook-static folder to gitignore. * Adding other storybook files. * Adding menu items for app * Removing cypress selector from text. * Menu width issue fixed * Default app icon color added * Removing hardcoded colors * Removing hardcoded colors. * Light Mode on! * Showing correct icon and color in menu * Update color working properly. * Updating appIcon * Editable text working. * Adding validator * Adding edit permissions to menu * Removing box shadow on app card. * Fixing context menu fill color * Fixing Menu hover issues. * Fixing menu open close hover issues. * Fixing settings pages * Changed Workspace to org. * Fix: State management in EditableText Component (#540) * Error state height is fixed as per design * savingState prop condition fixed * Fixing createnew. * Fixing saving state for application card. * Fixed application card editable text error. * Fixing issue caused during merge. * Fixing tests in create org. * Removing commented code. * Removing unwanted vars. * Fixing delete duplicate tests. * Latest color palette. * Fixing form and table widget. * Removing switcher from header * Removing unused files * Fixing app card context dropdown * Show overlay fix * Adding localStorage support to theme. * Making dark mode the default. Co-authored-by: Rohit Kumawat <rohit.kumawat@primathon.in>
2020-09-16 11:50:47 +00:00
);
2020-08-14 04:58:03 +00:00
const memoizedChangeHandler = useCallback(
2020-12-24 04:32:25 +00:00
(el) => {
const inputValue = el.target.value.trim();
setInputValue(inputValue);
const validation = props.validator && props.validator(inputValue);
if (validation) {
props.validator && setValidation(validation);
return (
validation.isValid && props.onChange && props.onChange(inputValue)
);
} else {
return props.onChange && props.onChange(inputValue);
}
2020-08-14 04:58:03 +00:00
},
[props],
);
const ErrorMessage = (
<MsgWrapper>
<Text type={TextType.P3}>{validation.message}</Text>
</MsgWrapper>
);
const HelperMessage = (
<MsgWrapper className="helper">
<Text type={TextType.P3}>* {props.helperText}</Text>
</MsgWrapper>
);
const iconColor = !validation.isValid
? props.theme.colors.danger.main
: props.theme.colors.textInput.icon;
2020-08-14 04:58:03 +00:00
const hasLeftIcon = props.leftIcon
? IconCollection.includes(props.leftIcon)
: false;
2020-08-14 04:58:03 +00:00
return (
<InputWrapper
disabled={props.disabled}
fill={props.fill ? 1 : 0}
height={props.height || undefined}
inputStyle={inputStyle}
isFocused={isFocused}
isValid={validation.isValid}
noBorder={props.noBorder}
value={inputValue}
width={props.width || undefined}
>
{props.leftIcon && (
<IconWrapper className="left-icon">
<Icon
fillColor={iconColor}
name={props.leftIcon}
size={IconSize.MEDIUM}
/>
</IconWrapper>
)}
2020-08-14 04:58:03 +00:00
<StyledInput
autoFocus={props.autoFocus}
defaultValue={props.defaultValue}
2020-08-14 04:58:03 +00:00
inputStyle={inputStyle}
isValid={validation.isValid}
ref={ref}
type={props.dataType || "text"}
2020-08-14 04:58:03 +00:00
{...props}
data-cy={props.cypressSelector}
hasLeftIcon={hasLeftIcon}
inputRef={ref}
onBlur={(e: React.FocusEvent<any>) => {
setIsFocused(false);
if (props.onBlur) props.onBlur(e);
}}
onChange={memoizedChangeHandler}
onFocus={(e: React.FocusEvent<any>) => {
setIsFocused(true);
if (props.onFocus) props.onFocus(e);
}}
placeholder={props.placeholder}
readOnly={props.readOnly}
rightSideComponentWidth={rightSideComponentWidth}
2020-08-14 04:58:03 +00:00
/>
{validation.isValid &&
props.helperText &&
props.helperText.length > 0 &&
HelperMessage}
{ErrorMessage}
<RightSideContainer ref={setRightSideRef}>
{props.rightSideComponent}
</RightSideContainer>
2020-08-14 04:58:03 +00:00
</InputWrapper>
);
},
);
TextInput.displayName = "TextInput";
export default withTheme(TextInput);
export type InputType = "text" | "password" | "number" | "email" | "tel";