Feature/dropdown
This commit is contained in:
parent
3b393a8089
commit
9d659ddff0
|
|
@ -25,6 +25,8 @@ export interface ComponentProps {
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
widgetName?: string;
|
widgetName?: string;
|
||||||
style: BaseStyle;
|
style: BaseStyle;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
isVisibile?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BaseComponent;
|
export default BaseComponent;
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import { Text } from "@blueprintjs/core";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { ComponentProps } from "./BaseComponent";
|
|
||||||
import { Container } from "./ContainerComponent";
|
|
||||||
|
|
||||||
type TextStyleProps = {
|
|
||||||
styleName: "primary" | "secondary" | "error";
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BaseText = styled(Text)<TextStyleProps>`
|
|
||||||
color: ${props => props.theme.colors[props.styleName]};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export interface TextComponentProps extends ComponentProps {
|
|
||||||
text?: string;
|
|
||||||
ellipsize?: boolean;
|
|
||||||
tagName?: keyof JSX.IntrinsicElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextComponent extends React.Component<TextComponentProps> {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Container {...this.props}>
|
|
||||||
<Text ellipsize={this.props.ellipsize} tagName={this.props.tagName}>
|
|
||||||
{this.props.text}
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TextComponent;
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import { ComponentProps } from "../appsmith/BaseComponent";
|
|
||||||
import { Boundary, Breadcrumbs, IBreadcrumbProps } from "@blueprintjs/core";
|
|
||||||
import { Container } from "../appsmith/ContainerComponent";
|
|
||||||
|
|
||||||
class BreadcrumbsComponent extends React.Component<BreadcrumbsComponentProps> {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Container {...this.props}>
|
|
||||||
<Breadcrumbs
|
|
||||||
collapseFrom={this.props.collapseFrom}
|
|
||||||
items={this.props.items}
|
|
||||||
minVisibleItems={this.props.minVisibleItems}
|
|
||||||
className={this.props.className}
|
|
||||||
/>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BreadcrumbsComponentProps extends ComponentProps {
|
|
||||||
width?: number;
|
|
||||||
collapseFrom?: Boundary;
|
|
||||||
className?: string;
|
|
||||||
minVisibleItems?: number;
|
|
||||||
items?: IBreadcrumbProps[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BreadcrumbsComponent;
|
|
||||||
|
|
@ -2,7 +2,8 @@ import React from "react";
|
||||||
import { AnchorButton, IButtonProps, MaybeElement } from "@blueprintjs/core";
|
import { AnchorButton, IButtonProps, MaybeElement } from "@blueprintjs/core";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
import { Container } from "../appsmith/ContainerComponent";
|
import { Container } from "../appsmith/ContainerComponent";
|
||||||
import { TextComponentProps } from "../appsmith/TextViewComponent";
|
import { TextComponentProps } from "./TextComponent";
|
||||||
|
import { ButtonStyle } from "../../widgets/ButtonWidget";
|
||||||
|
|
||||||
const ButtonColorStyles = css<ButtonStyleProps>`
|
const ButtonColorStyles = css<ButtonStyleProps>`
|
||||||
color: ${props => {
|
color: ${props => {
|
||||||
|
|
@ -87,8 +88,22 @@ interface ButtonContainerProps extends TextComponentProps {
|
||||||
icon?: MaybeElement;
|
icon?: MaybeElement;
|
||||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
buttonStyle?: ButtonStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapButtonStyleToStyleName = (buttonStyle?: ButtonStyle) => {
|
||||||
|
switch (buttonStyle) {
|
||||||
|
case "PRIMARY_BUTTON":
|
||||||
|
return "primary";
|
||||||
|
case "SECONDARY_BUTTON":
|
||||||
|
return "secondary";
|
||||||
|
case "DANGER_BUTTON":
|
||||||
|
return "error";
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// To be used with the canvas
|
// To be used with the canvas
|
||||||
const ButtonContainer = (props: ButtonContainerProps & ButtonStyleProps) => {
|
const ButtonContainer = (props: ButtonContainerProps & ButtonStyleProps) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -96,7 +111,8 @@ const ButtonContainer = (props: ButtonContainerProps & ButtonStyleProps) => {
|
||||||
<BaseButton
|
<BaseButton
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
text={props.text}
|
text={props.text}
|
||||||
styleName={props.styleName}
|
filled={props.buttonStyle === "PRIMARY_BUTTON"}
|
||||||
|
styleName={mapButtonStyleToStyleName(props.buttonStyle)}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
125
app/client/src/components/blueprint/DropdownComponent.tsx
Normal file
125
app/client/src/components/blueprint/DropdownComponent.tsx
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { ComponentProps } from "../appsmith/BaseComponent";
|
||||||
|
import { MenuItem, Button } from "@blueprintjs/core";
|
||||||
|
import { Container } from "../appsmith/ContainerComponent";
|
||||||
|
import { SelectionType, DropdownOption } from "../../widgets/DropdownWidget";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
MultiSelect,
|
||||||
|
IItemRendererProps,
|
||||||
|
ItemRenderer,
|
||||||
|
} from "@blueprintjs/select";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
const SingleDropDown = Select.ofType<DropdownOption>();
|
||||||
|
const MultiDropDown = MultiSelect.ofType<DropdownOption>();
|
||||||
|
|
||||||
|
class DropDownComponent extends React.Component<DropDownComponentProps> {
|
||||||
|
constructor(props: DropDownComponentProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const selectedItems = this.props.selectedIndexArr
|
||||||
|
? _.map(this.props.selectedIndexArr, index => {
|
||||||
|
return this.props.options[index];
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
return (
|
||||||
|
<div style={{ textAlign: "center" }}>
|
||||||
|
{this.props.selectionType === "SINGLE_SELECT" ? (
|
||||||
|
<SingleDropDown
|
||||||
|
items={this.props.options}
|
||||||
|
filterable={false}
|
||||||
|
itemRenderer={this.renderItem}
|
||||||
|
onItemSelect={this.onItemSelect}
|
||||||
|
>
|
||||||
|
<Container {...this.props}>
|
||||||
|
<Button
|
||||||
|
intent={"primary"}
|
||||||
|
text={
|
||||||
|
!_.isEmpty(this.props.options)
|
||||||
|
? this.props.options[this.props.selectedIndex].label
|
||||||
|
: "Add options"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
</SingleDropDown>
|
||||||
|
) : (
|
||||||
|
<Container {...this.props}>
|
||||||
|
<MultiDropDown
|
||||||
|
items={this.props.options}
|
||||||
|
placeholder={this.props.placeholder}
|
||||||
|
tagRenderer={this.renderTag}
|
||||||
|
itemRenderer={this.renderItem}
|
||||||
|
selectedItems={selectedItems}
|
||||||
|
tagInputProps={{ onRemove: this.onItemRemoved }}
|
||||||
|
onItemSelect={this.onItemSelect}
|
||||||
|
></MultiDropDown>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onItemSelect = (
|
||||||
|
item: DropdownOption,
|
||||||
|
event?: React.SyntheticEvent<HTMLElement>,
|
||||||
|
): void => {
|
||||||
|
this.props.onOptionSelected(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
onItemRemoved = (_tag: string, index: number) => {
|
||||||
|
this.props.onOptionRemoved(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTag = (option: DropdownOption) => {
|
||||||
|
return option.label;
|
||||||
|
};
|
||||||
|
|
||||||
|
isOptionSelected = (selectedOption: DropdownOption) => {
|
||||||
|
const optionIndex = _.findIndex(this.props.options, option => {
|
||||||
|
return option.value === selectedOption.value;
|
||||||
|
});
|
||||||
|
if (this.props.selectionType === "SINGLE_SELECT") {
|
||||||
|
return optionIndex === this.props.selectedIndex;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
_.findIndex(this.props.selectedIndexArr, index => {
|
||||||
|
return index === optionIndex;
|
||||||
|
}) !== -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderItem = (option: DropdownOption, itemProps: IItemRendererProps) => {
|
||||||
|
if (!itemProps.modifiers.matchesPredicate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const isSelected: boolean = this.isOptionSelected(option);
|
||||||
|
console.log("is selected " + isSelected);
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
icon={isSelected ? "tick" : "blank"}
|
||||||
|
active={itemProps.modifiers.active}
|
||||||
|
key={option.value}
|
||||||
|
onClick={itemProps.handleClick}
|
||||||
|
text={option.label}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropDownComponentProps extends ComponentProps {
|
||||||
|
selectionType: SelectionType;
|
||||||
|
disabled?: boolean;
|
||||||
|
onOptionSelected: (optionSelected: DropdownOption) => void;
|
||||||
|
onOptionRemoved: (removedIndex: number) => void;
|
||||||
|
placeholder?: string;
|
||||||
|
label?: string;
|
||||||
|
selectedIndex: number;
|
||||||
|
selectedIndexArr: number[];
|
||||||
|
options: DropdownOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropDownComponent;
|
||||||
|
|
@ -6,6 +6,9 @@ import {
|
||||||
IconName,
|
IconName,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
Button,
|
Button,
|
||||||
|
Label,
|
||||||
|
Classes,
|
||||||
|
Text,
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
import { Container } from "../appsmith/ContainerComponent";
|
import { Container } from "../appsmith/ContainerComponent";
|
||||||
import { InputType } from "../../widgets/InputWidget";
|
import { InputType } from "../../widgets/InputWidget";
|
||||||
|
|
@ -25,70 +28,99 @@ class InputComponent extends React.Component<
|
||||||
this.state = { showPassword: false };
|
this.state = { showPassword: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
this.props.onValueChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
onNumberChange = (valueAsNum: number, valueAsString: string) => {
|
||||||
|
this.props.onValueChange(valueAsString);
|
||||||
|
};
|
||||||
|
|
||||||
|
isNumberInputType(inputType: InputType) {
|
||||||
|
return (
|
||||||
|
this.props.inputType === "INTEGER" ||
|
||||||
|
this.props.inputType === "PHONE_NUMBER" ||
|
||||||
|
this.props.inputType === "NUMBER" ||
|
||||||
|
this.props.inputType === "CURRENCY"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIcon(inputType: InputType) {
|
||||||
|
switch (inputType) {
|
||||||
|
case "PHONE_NUMBER":
|
||||||
|
return "phone";
|
||||||
|
case "SEARCH":
|
||||||
|
return "search";
|
||||||
|
case "EMAIL":
|
||||||
|
return "envelope";
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getType(inputType: InputType) {
|
||||||
|
switch (inputType) {
|
||||||
|
case "PASSWORD":
|
||||||
|
return this.state.showPassword ? "password" : "text";
|
||||||
|
case "EMAIL":
|
||||||
|
return "email";
|
||||||
|
case "SEARCH":
|
||||||
|
return "search";
|
||||||
|
default:
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Container {...this.props}>
|
<Container {...this.props}>
|
||||||
{this.props.inputType === "INTEGER" ||
|
<Label>
|
||||||
this.props.inputType === "PHONE_NUMBER" ||
|
{this.props.label}
|
||||||
this.props.inputType === "NUMBER" ||
|
{this.isNumberInputType(this.props.inputType) ? (
|
||||||
this.props.inputType === "CURRENCY" ? (
|
<NumericInput
|
||||||
<NumericInput
|
placeholder={this.props.placeholder}
|
||||||
placeholder={this.props.placeholder}
|
min={this.props.minNum}
|
||||||
min={this.props.minNum}
|
max={this.props.maxNum}
|
||||||
max={this.props.maxNum}
|
maxLength={this.props.maxChars}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
intent={this.props.intent}
|
intent={this.props.intent}
|
||||||
defaultValue={this.props.defaultValue}
|
defaultValue={this.props.defaultValue}
|
||||||
leftIcon={
|
onValueChange={this.onNumberChange}
|
||||||
this.props.inputType === "PHONE_NUMBER"
|
leftIcon={
|
||||||
? "phone"
|
this.props.inputType === "PHONE_NUMBER"
|
||||||
: this.props.leftIcon
|
? "phone"
|
||||||
}
|
: this.props.leftIcon
|
||||||
type={this.props.inputType === "PHONE_NUMBER" ? "tel" : undefined}
|
}
|
||||||
allowNumericCharactersOnly={true}
|
type={this.props.inputType === "PHONE_NUMBER" ? "tel" : undefined}
|
||||||
stepSize={this.props.stepSize}
|
allowNumericCharactersOnly={true}
|
||||||
/>
|
stepSize={this.props.stepSize}
|
||||||
) : this.props.inputType === "TEXT" ||
|
/>
|
||||||
this.props.inputType === "EMAIL" ||
|
) : (
|
||||||
this.props.inputType === "PASSWORD" ||
|
<InputGroup
|
||||||
this.props.inputType === "SEARCH" ? (
|
placeholder={this.props.placeholder}
|
||||||
<InputGroup
|
disabled={this.props.disabled}
|
||||||
placeholder={this.props.placeholder}
|
maxLength={this.props.maxChars}
|
||||||
disabled={this.props.disabled}
|
intent={this.props.intent}
|
||||||
intent={this.props.intent}
|
onChange={this.onTextChange}
|
||||||
defaultValue={this.props.defaultValue}
|
defaultValue={this.props.defaultValue}
|
||||||
rightElement={
|
rightElement={
|
||||||
this.props.inputType === "PASSWORD" ? (
|
this.props.inputType === "PASSWORD" ? (
|
||||||
<Button
|
<Button
|
||||||
icon={"lock"}
|
icon={"lock"}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.setState({ showPassword: !this.state.showPassword });
|
this.setState({ showPassword: !this.state.showPassword });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
undefined
|
undefined
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
type={
|
type={this.getType(this.props.inputType)}
|
||||||
this.props.inputType === "PASSWORD" && !this.state.showPassword
|
leftIcon={this.getIcon(this.props.inputType)}
|
||||||
? "password"
|
/>
|
||||||
: this.props.inputType === "EMAIL"
|
)}
|
||||||
? "email"
|
</Label>
|
||||||
: this.props.inputType === "SEARCH"
|
<Text>{this.props.errorMessage}</Text>
|
||||||
? "search"
|
|
||||||
: "text"
|
|
||||||
}
|
|
||||||
leftIcon={
|
|
||||||
this.props.inputType === "SEARCH"
|
|
||||||
? "search"
|
|
||||||
: this.props.inputType === "EMAIL"
|
|
||||||
? "envelope"
|
|
||||||
: this.props.leftIcon
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
undefined
|
|
||||||
)}
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -99,16 +131,19 @@ export interface InputComponentState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InputComponentProps extends ComponentProps {
|
export interface InputComponentProps extends ComponentProps {
|
||||||
inputType?: InputType;
|
inputType: InputType;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
intent?: Intent;
|
intent?: Intent;
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
|
label: string;
|
||||||
leftIcon?: IconName;
|
leftIcon?: IconName;
|
||||||
allowNumericCharactersOnly?: boolean;
|
allowNumericCharactersOnly?: boolean;
|
||||||
fill?: boolean;
|
fill?: boolean;
|
||||||
|
errorMessage?: string;
|
||||||
|
maxChars?: number;
|
||||||
maxNum?: number;
|
maxNum?: number;
|
||||||
minNum?: number;
|
minNum?: number;
|
||||||
onValueChange?: (valueAsNumber: number, valueAsString: string) => void;
|
onValueChange: (valueAsString: string) => void;
|
||||||
stepSize?: number;
|
stepSize?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import { ComponentProps } from "../appsmith/BaseComponent";
|
|
||||||
import { Intent, ITagProps, TagInput, HTMLInputProps } from "@blueprintjs/core";
|
|
||||||
import { Container } from "../appsmith/ContainerComponent";
|
|
||||||
class TagInputComponent extends React.Component<TagInputComponentProps> {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Container {...this.props}>
|
|
||||||
<TagInput
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
values={this.props.values}
|
|
||||||
/>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TagInputComponentProps extends ComponentProps {
|
|
||||||
addOnPaste?: boolean;
|
|
||||||
className?: string;
|
|
||||||
disabled?: boolean;
|
|
||||||
fill?: boolean;
|
|
||||||
inputProps?: HTMLInputProps;
|
|
||||||
inputValue?: string; //Controlled value of the <input> element.
|
|
||||||
intent?: Intent;
|
|
||||||
large?: boolean; //Whether the tag input should use a large size
|
|
||||||
onInputChange?: React.FormEventHandler<HTMLInputElement>;
|
|
||||||
placeholder?: string;
|
|
||||||
rightElement?: JSX.Element;
|
|
||||||
separator?: string | RegExp | false;
|
|
||||||
tagProps?: ITagProps;
|
|
||||||
values?: string[]; //Required field
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TagInputComponent;
|
|
||||||
48
app/client/src/components/blueprint/TextComponent.tsx
Normal file
48
app/client/src/components/blueprint/TextComponent.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { Text, Classes } from "@blueprintjs/core";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { ComponentProps } from "../appsmith/BaseComponent";
|
||||||
|
import { Container } from "../appsmith/ContainerComponent";
|
||||||
|
import { TextStyle } from "../../widgets/TextWidget";
|
||||||
|
|
||||||
|
type TextStyleProps = {
|
||||||
|
styleName: "primary" | "secondary" | "error";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BaseText = styled(Text)<TextStyleProps>``;
|
||||||
|
|
||||||
|
export interface TextComponentProps extends ComponentProps {
|
||||||
|
text?: string;
|
||||||
|
ellipsize?: boolean;
|
||||||
|
textStyle?: TextStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextComponent extends React.Component<TextComponentProps> {
|
||||||
|
getTextClass(textStyle?: TextStyle) {
|
||||||
|
switch (textStyle) {
|
||||||
|
case "HEADING":
|
||||||
|
return Classes.TEXT_LARGE;
|
||||||
|
case "LABEL":
|
||||||
|
return undefined;
|
||||||
|
case "BODY":
|
||||||
|
return Classes.TEXT_SMALL;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Container {...this.props}>
|
||||||
|
<Text
|
||||||
|
className={this.getTextClass(this.props.textStyle)}
|
||||||
|
ellipsize={this.props.ellipsize}
|
||||||
|
>
|
||||||
|
{this.props.text}
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextComponent;
|
||||||
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { withRouter, RouteComponentProps } from "react-router";
|
import { withRouter, RouteComponentProps } from "react-router";
|
||||||
import FormRow from "./FormRow";
|
import FormRow from "./FormRow";
|
||||||
import { BaseText } from "../appsmith/TextViewComponent";
|
import { BaseText } from "../blueprint/TextComponent";
|
||||||
import { BaseTabbedView } from "../appsmith/TabbedView";
|
import { BaseTabbedView } from "../appsmith/TabbedView";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { AppState } from "../../reducers";
|
import { AppState } from "../../reducers";
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ const DraggableComponent = (props: DraggableComponentProps) => {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</DeleteControl>
|
</DeleteControl>
|
||||||
<EditControl className="control" onClick={togglePropertyEditor}>
|
<EditControl className="control" onClick={togglePropertyEditor}>
|
||||||
<Tooltip content="Toggle properties pane" hoverOpenDelay={500}>
|
<Tooltip content="Toggle props" hoverOpenDelay={500}>
|
||||||
{editControlIcon}
|
{editControlIcon}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</EditControl>
|
</EditControl>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
propertyName: "text",
|
propertyName: "text",
|
||||||
label: "Button Text",
|
label: "Button Text",
|
||||||
controlType: "INPUT_TEXT",
|
controlType: "INPUT_TEXT",
|
||||||
placeholderText: "Enter button text here",
|
placeholderText: "Enter button text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "1.2",
|
id: "1.2",
|
||||||
|
|
@ -22,6 +22,7 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
options: [
|
options: [
|
||||||
{ label: "Primary Button", value: "PRIMARY_BUTTON" },
|
{ label: "Primary Button", value: "PRIMARY_BUTTON" },
|
||||||
{ label: "Secondary Button", value: "SECONDARY_BUTTON" },
|
{ label: "Secondary Button", value: "SECONDARY_BUTTON" },
|
||||||
|
{ label: "Danger Button", value: "DANGER_BUTTON" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -61,7 +62,7 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
propertyName: "text",
|
propertyName: "text",
|
||||||
label: "Text",
|
label: "Text",
|
||||||
controlType: "INPUT_TEXT",
|
controlType: "INPUT_TEXT",
|
||||||
placeholderText: "Enter your text here",
|
placeholderText: "Enter your text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "3.2",
|
id: "3.2",
|
||||||
|
|
@ -72,7 +73,6 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
{ label: "Heading", value: "HEADING" },
|
{ label: "Heading", value: "HEADING" },
|
||||||
{ label: "Label", value: "LABEL" },
|
{ label: "Label", value: "LABEL" },
|
||||||
{ label: "Body", value: "BODY" },
|
{ label: "Body", value: "BODY" },
|
||||||
{ label: "Sub text", value: "SUB_TEXT" },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -140,7 +140,6 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
{ label: "Password", value: "PASSWORD" },
|
{ label: "Password", value: "PASSWORD" },
|
||||||
{ label: "Phone Number", value: "PHONE_NUMBER" },
|
{ label: "Phone Number", value: "PHONE_NUMBER" },
|
||||||
{ label: "Email", value: "EMAIL" },
|
{ label: "Email", value: "EMAIL" },
|
||||||
{ label: "Search", value: "SEARCH" },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -148,7 +147,7 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
propertyName: "placeholderText",
|
propertyName: "placeholderText",
|
||||||
label: "Placeholder",
|
label: "Placeholder",
|
||||||
controlType: "INPUT_TEXT",
|
controlType: "INPUT_TEXT",
|
||||||
placeholderText: "Enter your text here",
|
placeholderText: "Enter your text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.4",
|
id: "5.4",
|
||||||
|
|
@ -156,41 +155,32 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
label: "Max Chars",
|
label: "Max Chars",
|
||||||
controlType: "INPUT_TEXT",
|
controlType: "INPUT_TEXT",
|
||||||
inputType: "INTEGER",
|
inputType: "INTEGER",
|
||||||
placeholderText: "Maximum character length",
|
placeholderText: "Enter the max length",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.5",
|
id: "5.5",
|
||||||
propertyName: "validators",
|
propertyName: "regex",
|
||||||
label: "Validators",
|
label: "Regex",
|
||||||
controlType: "VALIDATION_INPUT",
|
controlType: "INPUT_TEXT",
|
||||||
|
inputType: "TEXT",
|
||||||
|
placeholderText: "Enter the regex",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.6",
|
id: "5.6",
|
||||||
children: [
|
propertyName: "errorMessage",
|
||||||
{
|
label: "Error Message",
|
||||||
id: "5.6.1",
|
controlType: "INPUT_TEXT",
|
||||||
propertyName: "focusIndexx",
|
inputType: "TEXT",
|
||||||
label: "Focus Index",
|
placeholderText: "Enter the message",
|
||||||
controlType: "INPUT_TEXT",
|
|
||||||
inputType: "INTEGER",
|
|
||||||
placeholderText: "Enter the order of tab focus",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "5.6.2",
|
|
||||||
propertyName: "autoFocus",
|
|
||||||
label: "Auto Focus",
|
|
||||||
controlType: "SWITCH",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.7",
|
id: "5.8",
|
||||||
propertyName: "isVisible",
|
propertyName: "isVisible",
|
||||||
label: "Visibile",
|
label: "Visibile",
|
||||||
controlType: "SWITCH",
|
controlType: "SWITCH",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "5.8",
|
id: "5.9",
|
||||||
propertyName: "isDisabled",
|
propertyName: "isDisabled",
|
||||||
label: "Disabled",
|
label: "Disabled",
|
||||||
controlType: "SWITCH",
|
controlType: "SWITCH",
|
||||||
|
|
@ -407,7 +397,7 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: "13.1",
|
id: "13.1",
|
||||||
propertyName: "type",
|
propertyName: "selectionType",
|
||||||
label: "Selection Type",
|
label: "Selection Type",
|
||||||
controlType: "DROP_DOWN",
|
controlType: "DROP_DOWN",
|
||||||
options: [
|
options: [
|
||||||
|
|
@ -415,6 +405,12 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
{ label: "Multi Select", value: "MULTI_SELECT" },
|
{ label: "Multi Select", value: "MULTI_SELECT" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "13.4",
|
||||||
|
propertyName: "options",
|
||||||
|
label: "Options",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "13.2",
|
id: "13.2",
|
||||||
propertyName: "label",
|
propertyName: "label",
|
||||||
|
|
@ -429,12 +425,6 @@ const PropertyPaneConfigResponse: PropertyPaneConfigState = {
|
||||||
controlType: "INPUT_TEXT",
|
controlType: "INPUT_TEXT",
|
||||||
placeholderText: "Enter the placeholder",
|
placeholderText: "Enter the placeholder",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "13.4",
|
|
||||||
propertyName: "options",
|
|
||||||
label: "Options",
|
|
||||||
controlType: "OPTION_INPUT",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "13.5",
|
id: "13.5",
|
||||||
propertyName: "isVisible",
|
propertyName: "isVisible",
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
},
|
},
|
||||||
TEXT_WIDGET: {
|
TEXT_WIDGET: {
|
||||||
text: "Not all labels are bad!",
|
text: "Label me",
|
||||||
textStyle: "LABEL",
|
textStyle: "LABEL",
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 3,
|
columns: 4,
|
||||||
widgetName: "Text",
|
widgetName: "Text",
|
||||||
},
|
},
|
||||||
IMAGE_WIDGET: {
|
IMAGE_WIDGET: {
|
||||||
|
|
@ -30,20 +30,20 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
inputType: "TEXT",
|
inputType: "TEXT",
|
||||||
label: "Label me",
|
label: "Label me",
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 3,
|
columns: 5,
|
||||||
widgetName: "Input",
|
widgetName: "Input",
|
||||||
},
|
},
|
||||||
SWITCH_WIDGET: {
|
SWITCH_WIDGET: {
|
||||||
isOn: false,
|
isOn: false,
|
||||||
label: "Turn me on",
|
label: "Switch",
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 4,
|
columns: 4,
|
||||||
widgetName: "Switch",
|
widgetName: "Switch",
|
||||||
},
|
},
|
||||||
CONTAINER_WIDGET: {
|
CONTAINER_WIDGET: {
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
rows: 1,
|
rows: 8,
|
||||||
columns: 4,
|
columns: 8,
|
||||||
widgetName: "Container",
|
widgetName: "Container",
|
||||||
},
|
},
|
||||||
SPINNER_WIDGET: {
|
SPINNER_WIDGET: {
|
||||||
|
|
@ -62,14 +62,19 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
TABLE_WIDGET: {
|
TABLE_WIDGET: {
|
||||||
rows: 5,
|
rows: 5,
|
||||||
columns: 7,
|
columns: 7,
|
||||||
label: "Don't table me!",
|
label: "Data",
|
||||||
widgetName: "Table",
|
widgetName: "Table",
|
||||||
},
|
},
|
||||||
DROP_DOWN_WIDGET: {
|
DROP_DOWN_WIDGET: {
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 3,
|
columns: 3,
|
||||||
selectionType: "SINGLE_SELECT",
|
selectionType: "SINGLE_SELECT",
|
||||||
label: "Pick me!",
|
label: "Select",
|
||||||
|
options: [
|
||||||
|
{ label: "Option 1", value: "1" },
|
||||||
|
{ label: "Option 2", value: "2" },
|
||||||
|
{ label: "Option 3", value: "3" },
|
||||||
|
],
|
||||||
widgetName: "Dropdown",
|
widgetName: "Dropdown",
|
||||||
},
|
},
|
||||||
CHECKBOX_WIDGET: {
|
CHECKBOX_WIDGET: {
|
||||||
|
|
@ -82,7 +87,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
RADIO_GROUP_WIDGET: {
|
RADIO_GROUP_WIDGET: {
|
||||||
rows: 3,
|
rows: 3,
|
||||||
columns: 3,
|
columns: 3,
|
||||||
label: "Alpha - come in!",
|
label: "Labels",
|
||||||
options: [
|
options: [
|
||||||
{ label: "Alpha", value: "1" },
|
{ label: "Alpha", value: "1" },
|
||||||
{ label: "Bravo", value: "2" },
|
{ label: "Bravo", value: "2" },
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import {
|
||||||
fetchEditorConfigs,
|
fetchEditorConfigs,
|
||||||
} from "../../actions/configsActions";
|
} from "../../actions/configsActions";
|
||||||
import { ReduxActionTypes } from "../../constants/ReduxActionConstants";
|
import { ReduxActionTypes } from "../../constants/ReduxActionConstants";
|
||||||
|
import { updateWidgetProperty } from "../../actions/controlActions";
|
||||||
|
|
||||||
const EditorWrapper = styled.div`
|
const EditorWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -59,6 +60,11 @@ type EditorProps = {
|
||||||
fetchCanvasWidgets: Function;
|
fetchCanvasWidgets: Function;
|
||||||
executeAction: (actionPayloads?: ActionPayload[]) => void;
|
executeAction: (actionPayloads?: ActionPayload[]) => void;
|
||||||
updateWidget: Function;
|
updateWidget: Function;
|
||||||
|
updateWidgetProperty: (
|
||||||
|
widgetId: string,
|
||||||
|
propertyName: string,
|
||||||
|
propertyValue: any,
|
||||||
|
) => void;
|
||||||
savePageLayout: Function;
|
savePageLayout: Function;
|
||||||
currentPageName: string;
|
currentPageName: string;
|
||||||
currentPageId: string;
|
currentPageId: string;
|
||||||
|
|
@ -92,6 +98,7 @@ class WidgetsEditor extends React.Component<EditorProps> {
|
||||||
value={{
|
value={{
|
||||||
executeAction: this.props.executeAction,
|
executeAction: this.props.executeAction,
|
||||||
updateWidget: this.props.updateWidget,
|
updateWidget: this.props.updateWidget,
|
||||||
|
updateWidgetProperty: this.props.updateWidgetProperty,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<EditorWrapper>
|
<EditorWrapper>
|
||||||
|
|
@ -123,6 +130,11 @@ const mapStateToProps = (state: AppState) => {
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
|
updateWidgetProperty: (
|
||||||
|
widgetId: string,
|
||||||
|
propertyName: string,
|
||||||
|
propertyValue: any,
|
||||||
|
) => dispatch(updateWidgetProperty(widgetId, propertyName, propertyValue)),
|
||||||
executeAction: (actionPayloads?: ActionPayload[]) =>
|
executeAction: (actionPayloads?: ActionPayload[]) =>
|
||||||
dispatch(executeAction(actionPayloads)),
|
dispatch(executeAction(actionPayloads)),
|
||||||
fetchCanvasWidgets: (pageId: string) =>
|
fetchCanvasWidgets: (pageId: string) =>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import { ControlWrapper, StyledDropDown } from "./StyledControls";
|
||||||
class DropDownControl extends BaseControl<DropDownControlProps> {
|
class DropDownControl extends BaseControl<DropDownControlProps> {
|
||||||
constructor(props: DropDownControlProps) {
|
constructor(props: DropDownControlProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.onItemSelect = this.onItemSelect.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
@ -21,6 +20,7 @@ class DropDownControl extends BaseControl<DropDownControlProps> {
|
||||||
<StyledDropDown
|
<StyledDropDown
|
||||||
items={this.props.options}
|
items={this.props.options}
|
||||||
itemPredicate={this.filterOption}
|
itemPredicate={this.filterOption}
|
||||||
|
filterable={false}
|
||||||
itemRenderer={this.renderItem}
|
itemRenderer={this.renderItem}
|
||||||
onItemSelect={this.onItemSelect}
|
onItemSelect={this.onItemSelect}
|
||||||
noResults={<MenuItem disabled={true} text="No results." />}
|
noResults={<MenuItem disabled={true} text="No results." />}
|
||||||
|
|
@ -34,14 +34,14 @@ class DropDownControl extends BaseControl<DropDownControlProps> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemSelect(
|
onItemSelect = (
|
||||||
item: DropdownOption,
|
item: DropdownOption,
|
||||||
event?: SyntheticEvent<HTMLElement>,
|
event?: SyntheticEvent<HTMLElement>,
|
||||||
): void {
|
): void => {
|
||||||
this.updateProperty(this.props.propertyName, item.value);
|
this.updateProperty(this.props.propertyName, item.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderItem(option: DropdownOption, itemProps: IItemRendererProps) {
|
renderItem = (option: DropdownOption, itemProps: IItemRendererProps) => {
|
||||||
if (!itemProps.modifiers.matchesPredicate) {
|
if (!itemProps.modifiers.matchesPredicate) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -49,12 +49,11 @@ class DropDownControl extends BaseControl<DropDownControlProps> {
|
||||||
<MenuItem
|
<MenuItem
|
||||||
active={itemProps.modifiers.active}
|
active={itemProps.modifiers.active}
|
||||||
key={option.value}
|
key={option.value}
|
||||||
label={option.label}
|
|
||||||
onClick={itemProps.handleClick}
|
onClick={itemProps.handleClick}
|
||||||
text={option.label}
|
text={option.label}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
filterOption(query: string, option: DropdownOption): boolean {
|
filterOption(query: string, option: DropdownOption): boolean {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,27 @@ class InputTextControl extends BaseControl<InputControlProps> {
|
||||||
<ControlWrapper>
|
<ControlWrapper>
|
||||||
<label>{this.props.label}</label>
|
<label>{this.props.label}</label>
|
||||||
<StyledInputGroup
|
<StyledInputGroup
|
||||||
|
type={this.isNumberType(this.props.inputType) ? "number" : "text"}
|
||||||
onChange={this.onTextChange}
|
onChange={this.onTextChange}
|
||||||
|
placeholder={this.props.placeholderText}
|
||||||
defaultValue={this.props.propertyValue}
|
defaultValue={this.props.propertyValue}
|
||||||
/>
|
/>
|
||||||
</ControlWrapper>
|
</ControlWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isNumberType(inputType: InputType): boolean {
|
||||||
|
switch (inputType) {
|
||||||
|
case "CURRENCY":
|
||||||
|
case "INTEGER":
|
||||||
|
case "NUMBER":
|
||||||
|
case "PHONE_NUMBER":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.updateProperty(this.props.propertyName, event.target.value);
|
this.updateProperty(this.props.propertyName, event.target.value);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export const StyledSwitch = styled(Switch)`
|
||||||
|
|
||||||
export const StyledInputGroup = styled(InputGroup)`
|
export const StyledInputGroup = styled(InputGroup)`
|
||||||
& > input {
|
& > input {
|
||||||
|
placeholderText: ${props => props.placeholder}
|
||||||
color: ${props => props.theme.colors.textOnDarkBG};
|
color: ${props => props.theme.colors.textOnDarkBG};
|
||||||
background: ${props => props.theme.colors.paneInputBG};
|
background: ${props => props.theme.colors.paneInputBG};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,16 @@ export interface PropertyPaneConfigState {
|
||||||
config: PropertyConfig;
|
config: PropertyConfig;
|
||||||
configVersion: number;
|
configVersion: number;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Todo: Remove hardcoding of config response
|
||||||
|
*/
|
||||||
|
|
||||||
const propertyPaneConfigReducer = createReducer(initialState, {
|
const propertyPaneConfigReducer = createReducer(initialState, {
|
||||||
[ReduxActionTypes.FETCH_PROPERTY_PANE_CONFIGS_SUCCESS]: (
|
[ReduxActionTypes.FETCH_PROPERTY_PANE_CONFIGS_SUCCESS]: (
|
||||||
state: PropertyPaneConfigState,
|
state: PropertyPaneConfigState,
|
||||||
action: ReduxAction<PropertyPaneConfigState>,
|
action: ReduxAction<PropertyPaneConfigState>,
|
||||||
) => {
|
) => {
|
||||||
|
return { ...PropertyPaneConfigResponse };
|
||||||
return { ...action.payload };
|
return { ...action.payload };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import RadioGroupWidget, {
|
||||||
import WidgetFactory from "./WidgetFactory";
|
import WidgetFactory from "./WidgetFactory";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ButtonWidget, { ButtonWidgetProps } from "../widgets/ButtonWidget";
|
import ButtonWidget, { ButtonWidgetProps } from "../widgets/ButtonWidget";
|
||||||
|
import DropdownWidget, { DropdownWidgetProps } from "../widgets/DropdownWidget";
|
||||||
|
|
||||||
class WidgetBuilderRegistry {
|
class WidgetBuilderRegistry {
|
||||||
static registerWidgetBuilders() {
|
static registerWidgetBuilders() {
|
||||||
|
|
@ -51,6 +52,12 @@ class WidgetBuilderRegistry {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
WidgetFactory.registerWidgetBuilder("DROP_DOWN_WIDGET", {
|
||||||
|
buildWidget(widgetData: DropdownWidgetProps): JSX.Element {
|
||||||
|
return <DropdownWidget {...widgetData} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
WidgetFactory.registerWidgetBuilder("RADIO_GROUP_WIDGET", {
|
WidgetFactory.registerWidgetBuilder("RADIO_GROUP_WIDGET", {
|
||||||
buildWidget(widgetData: RadioGroupWidgetProps): JSX.Element {
|
buildWidget(widgetData: RadioGroupWidgetProps): JSX.Element {
|
||||||
return <RadioGroupWidget {...widgetData} />;
|
return <RadioGroupWidget {...widgetData} />;
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,11 @@ export interface WidgetDataProps {
|
||||||
export interface WidgetFunctions {
|
export interface WidgetFunctions {
|
||||||
executeAction?: (actionPayloads?: ActionPayload[]) => void;
|
executeAction?: (actionPayloads?: ActionPayload[]) => void;
|
||||||
updateWidget?: Function;
|
updateWidget?: Function;
|
||||||
|
updateWidgetProperty?: (
|
||||||
|
widgetId: string,
|
||||||
|
propertyName: string,
|
||||||
|
propertyValue: any,
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WidgetCardProps {
|
export interface WidgetCardProps {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import { WidgetType } from "../constants/WidgetConstants";
|
import { WidgetType } from "../constants/WidgetConstants";
|
||||||
import ButtonComponent, {
|
import ButtonComponent from "../components/blueprint/ButtonComponent";
|
||||||
ButtonStyleName,
|
|
||||||
} from "../components/blueprint/ButtonComponent";
|
|
||||||
import { ActionPayload } from "../constants/ActionConstants";
|
import { ActionPayload } from "../constants/ActionConstants";
|
||||||
|
|
||||||
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
|
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
|
||||||
|
|
@ -19,14 +17,10 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageView() {
|
getPageView() {
|
||||||
// TODO(abhinav): This is a hack. Need to standardize the style names
|
|
||||||
const translatedButtonStyleName: ButtonStyleName | undefined =
|
|
||||||
this.props.buttonStyle &&
|
|
||||||
(this.props.buttonStyle.split("_")[0].toLowerCase() as ButtonStyleName);
|
|
||||||
return (
|
return (
|
||||||
<ButtonComponent
|
<ButtonComponent
|
||||||
style={this.getPositionStyle()}
|
style={this.getPositionStyle()}
|
||||||
styleName={translatedButtonStyleName}
|
buttonStyle={this.props.buttonStyle}
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
widgetName={this.props.widgetName}
|
widgetName={this.props.widgetName}
|
||||||
key={this.props.widgetId}
|
key={this.props.widgetId}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,73 @@ import React from "react";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import { WidgetType } from "../constants/WidgetConstants";
|
import { WidgetType } from "../constants/WidgetConstants";
|
||||||
import { ActionPayload } from "../constants/ActionConstants";
|
import { ActionPayload } from "../constants/ActionConstants";
|
||||||
|
import DropDownComponent from "../components/blueprint/DropdownComponent";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
getPageView() {
|
constructor(props: DropdownWidgetProps) {
|
||||||
return <div />;
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPageView() {
|
||||||
|
return (
|
||||||
|
<DropDownComponent
|
||||||
|
onOptionSelected={this.onOptionSelected}
|
||||||
|
onOptionRemoved={this.onOptionRemoved}
|
||||||
|
widgetId={this.props.widgetId}
|
||||||
|
style={this.getPositionStyle()}
|
||||||
|
placeholder={this.props.placeholderText}
|
||||||
|
options={this.props.options || []}
|
||||||
|
selectionType={this.props.selectionType}
|
||||||
|
selectedIndex={this.props.selectedIndex || 0}
|
||||||
|
selectedIndexArr={this.props.selectedIndexArr || []}
|
||||||
|
label={this.props.label}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOptionSelected = (selectedOption: DropdownOption) => {
|
||||||
|
const selectedIndex = _.findIndex(this.props.options, option => {
|
||||||
|
return option.value === selectedOption.value;
|
||||||
|
});
|
||||||
|
if (this.props.selectionType === "SINGLE_SELECT") {
|
||||||
|
this.context.updateWidgetProperty(
|
||||||
|
this.props.widgetId,
|
||||||
|
"selectedIndex",
|
||||||
|
selectedIndex,
|
||||||
|
);
|
||||||
|
} else if (this.props.selectionType === "MULTI_SELECT") {
|
||||||
|
const selectedIndexArr = this.props.selectedIndexArr || [];
|
||||||
|
const isAlreadySelected =
|
||||||
|
_.find(selectedIndexArr, index => {
|
||||||
|
return index === selectedIndex;
|
||||||
|
}) !== undefined;
|
||||||
|
if (isAlreadySelected) {
|
||||||
|
this.onOptionRemoved(selectedIndex);
|
||||||
|
} else {
|
||||||
|
selectedIndexArr.push(selectedIndex);
|
||||||
|
this.context.updateWidgetProperty(
|
||||||
|
this.props.widgetId,
|
||||||
|
"selectedIndexArr",
|
||||||
|
selectedIndexArr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onOptionRemoved = (removedIndex: number) => {
|
||||||
|
const updateIndexArr = this.props.selectedIndexArr
|
||||||
|
? this.props.selectedIndexArr.filter(index => {
|
||||||
|
return removedIndex !== index;
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
this.context.updateWidgetProperty(
|
||||||
|
this.props.widgetId,
|
||||||
|
"selectedIndexArr",
|
||||||
|
updateIndexArr,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
getWidgetType(): WidgetType {
|
getWidgetType(): WidgetType {
|
||||||
return "DROP_DOWN_WIDGET";
|
return "DROP_DOWN_WIDGET";
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +83,8 @@ export interface DropdownOption {
|
||||||
export interface DropdownWidgetProps extends WidgetProps {
|
export interface DropdownWidgetProps extends WidgetProps {
|
||||||
placeholderText?: string;
|
placeholderText?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
selectedIndex?: number;
|
||||||
|
selectedIndexArr?: number[];
|
||||||
selectionType: SelectionType;
|
selectionType: SelectionType;
|
||||||
options?: DropdownOption[];
|
options?: DropdownOption[];
|
||||||
onOptionSelected?: ActionPayload[];
|
onOptionSelected?: ActionPayload[];
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,55 @@ import { WidgetType } from "../constants/WidgetConstants";
|
||||||
import InputComponent from "../components/blueprint/InputComponent";
|
import InputComponent from "../components/blueprint/InputComponent";
|
||||||
|
|
||||||
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
||||||
|
regex = new RegExp("");
|
||||||
|
|
||||||
|
constructor(props: InputWidgetProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
if (this.props.regex) {
|
||||||
|
try {
|
||||||
|
this.regex = new RegExp(this.props.regex);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("invalid regex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: InputWidgetProps) {
|
||||||
|
super.componentDidUpdate(prevProps);
|
||||||
|
if (this.props.regex !== prevProps.regex && this.props.regex) {
|
||||||
|
try {
|
||||||
|
this.regex = new RegExp(this.props.regex);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("invalid regex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChange = (value: string) => {
|
||||||
|
this.context.updateWidgetProperty(this.props.widgetId, "text", value);
|
||||||
|
};
|
||||||
|
|
||||||
getPageView() {
|
getPageView() {
|
||||||
return (
|
return (
|
||||||
<InputComponent
|
<InputComponent
|
||||||
|
onValueChange={this.onValueChange}
|
||||||
style={this.getPositionStyle()}
|
style={this.getPositionStyle()}
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
|
errorMessage={
|
||||||
|
this.props.regex &&
|
||||||
|
this.props.text &&
|
||||||
|
!this.regex.test(this.props.text)
|
||||||
|
? this.props.errorMessage
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
inputType={this.props.inputType}
|
inputType={this.props.inputType}
|
||||||
disabled={this.props.isDisabled}
|
disabled={this.props.isDisabled}
|
||||||
|
maxChars={this.props.maxChars}
|
||||||
|
label={this.props.label}
|
||||||
defaultValue={this.props.defaultText}
|
defaultValue={this.props.defaultText}
|
||||||
maxNum={this.props.maxNum}
|
maxNum={this.props.maxNum}
|
||||||
minNum={this.props.minNum}
|
minNum={this.props.minNum}
|
||||||
|
|
@ -43,6 +85,9 @@ export interface InputWidgetProps extends WidgetProps {
|
||||||
inputType: InputType;
|
inputType: InputType;
|
||||||
defaultText?: string;
|
defaultText?: string;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
|
text?: string;
|
||||||
|
regex?: string;
|
||||||
|
errorMessage?: string;
|
||||||
placeholderText?: string;
|
placeholderText?: string;
|
||||||
maxChars?: number;
|
maxChars?: number;
|
||||||
minNum?: number;
|
minNum?: number;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import { WidgetType } from "../constants/WidgetConstants";
|
import { WidgetType } from "../constants/WidgetConstants";
|
||||||
import TextViewComponent from "../components/appsmith/TextViewComponent";
|
import TextComponent from "../components/blueprint/TextComponent";
|
||||||
|
|
||||||
class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
|
class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
|
||||||
getPageView() {
|
getPageView() {
|
||||||
return (
|
return (
|
||||||
<TextViewComponent
|
<TextComponent
|
||||||
style={this.getPositionStyle()}
|
style={this.getPositionStyle()}
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
key={this.props.widgetId}
|
key={this.props.widgetId}
|
||||||
|
textStyle={this.props.textStyle}
|
||||||
text={this.props.text}
|
text={this.props.text}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -24,7 +25,7 @@ export type TextStyle = "BODY" | "HEADING" | "LABEL" | "SUB_TEXT";
|
||||||
|
|
||||||
export interface TextWidgetProps extends WidgetProps {
|
export interface TextWidgetProps extends WidgetProps {
|
||||||
text?: string;
|
text?: string;
|
||||||
textStyle?: TextStyle;
|
textStyle: TextStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TextWidget;
|
export default TextWidget;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user