Feat: Style customisation in the button widget (#6052)

Added multiple style props to the button widget:
- Button styles
- The background colour can change with a hex code
- elevation (box-shadow & colour)
- There are button variant contained (solid button), outlined (only borders), text (text buttons)
- Button can have an end icon or start icon
This commit is contained in:
Paul Li 2021-08-24 09:53:15 -04:00 committed by GitHub
parent 163192d851
commit cb4242e7e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 728 additions and 271 deletions

View File

@ -19,12 +19,20 @@ describe("Button Widget Functionality", function() {
it("Button-Style Validation", function() { it("Button-Style Validation", function() {
//Changing the style of the button from the property pane and verify it's color. //Changing the style of the button from the property pane and verify it's color.
// Change to Warning button sytle
cy.changeButtonStyle(2, "rgb(254, 184, 17)", "rgba(0, 0, 0, 0)");
cy.get(publishPage.backToEditor).click({ force: true });
cy.openPropertyPane("buttonwidget");
// Change to Info button sytle
cy.changeButtonStyle(4, "rgb(102, 152, 255)", "rgba(0, 0, 0, 0)");
cy.get(publishPage.backToEditor).click({ force: true });
cy.openPropertyPane("buttonwidget");
// Change to Secondary button sytle // Change to Secondary button sytle
cy.changeButtonStyle(2, "rgba(0, 0, 0, 0)", "rgba(0, 0, 0, 0)"); cy.changeButtonStyle(5, "rgb(133, 130, 130)", "rgba(0, 0, 0, 0)");
cy.get(publishPage.backToEditor).click({ force: true }); cy.get(publishPage.backToEditor).click({ force: true });
// Change to Danger button sytle // Change to Danger button sytle
cy.openPropertyPane("buttonwidget"); cy.openPropertyPane("buttonwidget");
cy.changeButtonStyle(3, "rgb(179, 3, 56)", "rgb(139, 2, 43)"); cy.changeButtonStyle(3, "rgb(242, 43, 43)", "rgb(139, 2, 43)");
cy.get(publishPage.backToEditor).click({ force: true }); cy.get(publishPage.backToEditor).click({ force: true });
// Change to Primary button sytle // Change to Primary button sytle
cy.openPropertyPane("buttonwidget"); cy.openPropertyPane("buttonwidget");

View File

@ -146,7 +146,7 @@
"styled-components": "^5.2.0", "styled-components": "^5.2.0",
"styled-system": "^5.1.5", "styled-system": "^5.1.5",
"tern": "^0.21.0", "tern": "^0.21.0",
"tinycolor2": "^1.4.1", "tinycolor2": "^1.4.2",
"toposort": "^2.0.2", "toposort": "^2.0.2",
"ts-loader": "^6.0.4", "ts-loader": "^6.0.4",
"tslib": "^2.1.0", "tslib": "^2.1.0",

View File

@ -29,9 +29,8 @@ class FilePickerComponent extends React.Component<
} }
return ( return (
<BaseButton <BaseButton
accent="primary" buttonStyle="PRIMARY"
disabled={this.props.isDisabled} disabled={this.props.isDisabled}
filled
loading={this.props.isLoading} loading={this.props.isLoading}
onClick={this.openModal} onClick={this.openModal}
text={label} text={label}

View File

@ -7,6 +7,14 @@ import { IconName } from "@blueprintjs/icons";
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent"; import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
import { ThemeProp } from "components/ads/common"; import { ThemeProp } from "components/ads/common";
import { WIDGET_PADDING } from "constants/WidgetConstants"; import { WIDGET_PADDING } from "constants/WidgetConstants";
import {
ButtonBorderRadius,
ButtonBorderRadiusTypes,
} from "components/propertyControls/BorderRadiusOptionsControl";
import {
ButtonBoxShadow,
ButtonBoxShadowTypes,
} from "components/propertyControls/BoxShadowOptionsControl";
const IconButtonContainer = styled.div` const IconButtonContainer = styled.div`
display: flex; display: flex;
@ -176,23 +184,6 @@ export enum ButtonVariantTypes {
} }
export type ButtonVariant = keyof typeof ButtonVariantTypes; export type ButtonVariant = keyof typeof ButtonVariantTypes;
export enum ButtonBorderRadiusTypes {
SHARP = "SHARP",
ROUNDED = "ROUNDED",
CIRCLE = "CIRCLE",
}
export type ButtonBorderRadius = keyof typeof ButtonBorderRadiusTypes;
export enum ButtonBoxShadowTypes {
NONE = "NONE",
VARIANT1 = "VARIANT1",
VARIANT2 = "VARIANT2",
VARIANT3 = "VARIANT3",
VARIANT4 = "VARIANT4",
VARIANT5 = "VARIANT5",
}
export type ButtonBoxShadow = keyof typeof ButtonBoxShadowTypes;
export interface IconButtonComponentProps extends ComponentProps { export interface IconButtonComponentProps extends ComponentProps {
iconName?: IconName; iconName?: IconName;
buttonStyle: ButtonStyle; buttonStyle: ButtonStyle;

View File

@ -1,16 +1,18 @@
import React, { useRef, useState } from "react"; import React, { useRef, useState } from "react";
import styled from "styled-components";
import tinycolor from "tinycolor2";
import { import {
IButtonProps, IButtonProps,
MaybeElement, MaybeElement,
Button, Button,
IconName, Alignment,
Position, Position,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import { IconName } from "@blueprintjs/icons";
import Tooltip from "components/ads/Tooltip"; import Tooltip from "components/ads/Tooltip";
import styled, { css } from "styled-components"; import { Theme } from "constants/DefaultTheme";
import { ButtonStyle } from "widgets/ButtonWidget";
import { Theme, darkenHover, darkenActive } from "constants/DefaultTheme";
import _ from "lodash";
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent"; import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
import { useScript, ScriptStatus } from "utils/hooks/useScript"; import { useScript, ScriptStatus } from "utils/hooks/useScript";
import { import {
@ -18,38 +20,126 @@ import {
GOOGLE_RECAPTCHA_DOMAIN_ERROR, GOOGLE_RECAPTCHA_DOMAIN_ERROR,
createMessage, createMessage,
} from "constants/messages"; } from "constants/messages";
import { Variant } from "components/ads/common"; import { ThemeProp, Variant } from "components/ads/common";
import { Toaster } from "components/ads/Toast"; import { Toaster } from "components/ads/Toast";
import ReCAPTCHA from "react-google-recaptcha"; import ReCAPTCHA from "react-google-recaptcha";
import {
ButtonBoxShadow,
ButtonBoxShadowTypes,
} from "components/propertyControls/BoxShadowOptionsControl";
import {
ButtonBorderRadius,
ButtonBorderRadiusTypes,
} from "components/propertyControls/BorderRadiusOptionsControl";
const getButtonColorStyles = (props: { theme: Theme } & ButtonStyleProps) => { export enum ButtonStyleTypes {
if (props.filled) { PRIMARY = "PRIMARY",
return props.accent === "grey" WARNING = "WARNING",
? props.theme.colors.textOnGreyBG DANGER = "DANGER",
: props.theme.colors.textOnDarkBG; INFO = "INFO",
SECONDARY = "SECONDARY",
CUSTOM = "CUSTOM",
} }
if (props.accent) { export type ButtonStyle = keyof typeof ButtonStyleTypes;
if (props.accent === "secondary") {
return props.theme.colors[AccentColorMap["primary"]]; export enum ButtonVariantTypes {
SOLID = "SOLID",
OUTLINE = "OUTLINE",
GHOST = "GHOST",
} }
return props.theme.colors[AccentColorMap[props.accent]]; export type ButtonVariant = keyof typeof ButtonVariantTypes;
const getCustomTextColor = (
theme: Theme,
backgroundColor?: string,
prevButtonStyle?: ButtonStyle,
) => {
if (!backgroundColor)
return theme.colors.button[
(prevButtonStyle || ButtonStyleTypes.PRIMARY).toLowerCase()
].solid.textColor;
const isDark = tinycolor(backgroundColor).isDark();
if (isDark) {
return theme.colors.button.custom.solid.light.textColor;
}
return theme.colors.button.custom.solid.dark.textColor;
};
const getCustomHoverColor = (
theme: Theme,
prevButtonStyle?: ButtonStyle,
buttonVariant?: ButtonVariant,
backgroundColor?: string,
) => {
if (!backgroundColor) {
return theme.colors.button[
(prevButtonStyle || ButtonStyleTypes.PRIMARY).toLowerCase()
][(buttonVariant || ButtonVariantTypes.SOLID).toLowerCase()].hoverColor;
}
switch (buttonVariant) {
case ButtonVariantTypes.OUTLINE:
return backgroundColor
? tinycolor(backgroundColor)
.lighten(40)
.toString()
: theme.colors.button.primary.outline.hoverColor;
break;
case ButtonVariantTypes.GHOST:
return backgroundColor
? tinycolor(backgroundColor)
.lighten(40)
.toString()
: theme.colors.button.primary.ghost.hoverColor;
break;
default:
return backgroundColor
? tinycolor(backgroundColor)
.darken(10)
.toString()
: theme.colors.button.primary.solid.hoverColor;
break;
} }
}; };
const getButtonFillStyles = (props: { theme: Theme } & ButtonStyleProps) => { const getCustomBackgroundColor = (
if (props.filled) { theme: Theme,
return props.accent === "grey" prevButtonStyle?: ButtonStyle,
? props.theme.colors.dropdownIconDarkBg buttonVariant?: ButtonVariant,
: props.theme.colors.textOnDarkBG; backgroundColor?: string,
} ) => {
if (props.accent) { return buttonVariant === ButtonVariantTypes.SOLID
if (props.accent === "secondary") { ? backgroundColor
return props.theme.colors[AccentColorMap["primary"]]; ? backgroundColor
} : theme.colors.button[
return props.theme.colors[AccentColorMap[props.accent]]; (prevButtonStyle || ButtonStyleTypes.PRIMARY).toLowerCase()
} ].solid.bgColor
: "none";
}; };
const getCustomBorderColor = (
theme: Theme,
prevButtonStyle?: ButtonStyle,
buttonVariant?: ButtonVariant,
backgroundColor?: string,
) => {
return buttonVariant === ButtonVariantTypes.OUTLINE
? backgroundColor
? backgroundColor
: theme.colors.button[
(prevButtonStyle || ButtonStyleTypes.PRIMARY).toLowerCase()
].outline.borderColor
: "none";
};
const RecaptchaWrapper = styled.div`
position: relative;
.grecaptcha-badge {
visibility: hidden;
}
`;
const ToolTipContent = styled.div` const ToolTipContent = styled.div`
max-width: 350px; max-width: 350px;
`; `;
@ -64,118 +154,257 @@ const ToolTipWrapper = styled.div`
} }
`; `;
const ButtonColorStyles = css<ButtonStyleProps>` const ButtonContainer = styled.div`
color: ${getButtonColorStyles}; display: flex;
svg { align-items: center;
fill: ${getButtonFillStyles}; justify-content: center;
}
`;
const RecaptchaWrapper = styled.div`
position: relative;
.grecaptcha-badge {
visibility: hidden;
}
`;
const AccentColorMap: Record<ButtonStyleName, string> = {
primary: "primaryOld",
secondary: "secondaryOld",
error: "error",
grey: "dropdownGreyBg",
};
const ButtonWrapper = styled((props: ButtonStyleProps & IButtonProps) => (
<Button {..._.omit(props, ["accent", "filled", "disabled"])} />
))<ButtonStyleProps>`
&&&& {
${ButtonColorStyles};
width: 100%;
height: 100%; height: 100%;
transition: background-color 0.2s;
background-color: ${(props) =>
props.filled &&
props.accent &&
props.theme.colors[AccentColorMap[props.accent]]};
border: 1px solid
${(props) =>
props.accent
? props.theme.colors[AccentColorMap[props.accent]]
: props.theme.colors.primary};
border-radius: 0; & > button {
height: 100%;
}
`;
const StyledButton = styled(Button)<ThemeProp & ButtonStyleProps>`
height: 100%;
background-image: none !important;
font-weight: ${(props) => props.theme.fontWeights[2]}; font-weight: ${(props) => props.theme.fontWeights[2]};
outline: none; outline: none;
&.bp3-button {
padding: 0px 10px; padding: 0px 10px;
${({ buttonColor, buttonStyle, buttonVariant, prevButtonStyle, theme }) => `
&:enabled {
background: ${
buttonStyle === ButtonStyleTypes.WARNING
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.warning.solid.bgColor
: "none"
: buttonStyle === ButtonStyleTypes.DANGER
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.danger.solid.bgColor
: "none"
: buttonStyle === ButtonStyleTypes.INFO
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.info.solid.bgColor
: "none"
: buttonStyle === ButtonStyleTypes.SECONDARY
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.secondary.solid.bgColor
: "none"
: buttonStyle === ButtonStyleTypes.CUSTOM
? getCustomBackgroundColor(
theme,
prevButtonStyle,
buttonVariant,
buttonColor,
)
: buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.primary.solid.bgColor
: "none"
} !important;
} }
&& .bp3-button-text {
&:hover:enabled, &:active:enabled {
background: ${
buttonStyle === ButtonStyleTypes.WARNING
? buttonVariant === ButtonVariantTypes.OUTLINE
? theme.colors.button.warning.outline.hoverColor
: buttonVariant === ButtonVariantTypes.GHOST
? theme.colors.button.warning.ghost.hoverColor
: theme.colors.button.warning.solid.hoverColor
: buttonStyle === ButtonStyleTypes.DANGER
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.danger.solid.hoverColor
: theme.colors.button.danger.outline.hoverColor
: buttonStyle === ButtonStyleTypes.INFO
? buttonVariant === ButtonVariantTypes.SOLID
? theme.colors.button.info.solid.hoverColor
: theme.colors.button.info.outline.hoverColor
: buttonStyle === ButtonStyleTypes.SECONDARY
? buttonVariant === ButtonVariantTypes.OUTLINE
? theme.colors.button.secondary.outline.hoverColor
: buttonVariant === ButtonVariantTypes.GHOST
? theme.colors.button.secondary.ghost.hoverColor
: theme.colors.button.secondary.solid.hoverColor
: buttonStyle === ButtonStyleTypes.CUSTOM
? getCustomHoverColor(
theme,
prevButtonStyle,
buttonVariant,
buttonColor,
)
: buttonVariant === ButtonVariantTypes.OUTLINE
? theme.colors.button.primary.outline.hoverColor
: buttonVariant === ButtonVariantTypes.GHOST
? theme.colors.button.primary.ghost.hoverColor
: theme.colors.button.primary.solid.hoverColor
} !important;
}
&:disabled {
background-color: ${theme.colors.button.disabled.bgColor} !important;
color: ${theme.colors.button.disabled.textColor} !important;
}
border: ${
buttonVariant === ButtonVariantTypes.OUTLINE
? buttonStyle === ButtonStyleTypes.WARNING
? `1px solid ${theme.colors.button.warning.outline.borderColor}`
: buttonStyle === ButtonStyleTypes.DANGER
? `1px solid ${theme.colors.button.danger.outline.borderColor}`
: buttonStyle === ButtonStyleTypes.INFO
? `1px solid ${theme.colors.button.info.outline.borderColor}`
: buttonStyle === ButtonStyleTypes.SECONDARY
? `1px solid ${theme.colors.button.secondary.outline.borderColor}`
: buttonStyle === ButtonStyleTypes.CUSTOM
? `1px solid ${getCustomBorderColor(
theme,
prevButtonStyle,
buttonVariant,
buttonColor,
)}`
: `1px solid ${theme.colors.button.primary.outline.borderColor}`
: "none"
} !important;
& > span {
max-height: 100%;
max-width: 99%; max-width: 99%;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; -webkit-line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
max-height: 100%;
overflow: hidden;
}
&&:hover, color: ${
&&:focus { buttonVariant === ButtonVariantTypes.SOLID
${ButtonColorStyles}; ? buttonStyle === ButtonStyleTypes.CUSTOM
background-color: ${(props) => { ? getCustomTextColor(theme, buttonColor, prevButtonStyle)
if (!props.filled) return props.theme.colors.secondaryDarker; : `${theme.colors.button.primary.solid.textColor}`
if (props.accent !== "secondary" && props.accent) { : buttonStyle === ButtonStyleTypes.WARNING
return darkenHover(props.theme.colors[AccentColorMap[props.accent]]); ? `${theme.colors.button.warning.outline.textColor}`
} : buttonStyle === ButtonStyleTypes.DANGER
}}; ? `${theme.colors.button.danger.outline.textColor}`
border-color: ${(props) => { : buttonStyle === ButtonStyleTypes.INFO
if (!props.filled) return; ? `${theme.colors.button.info.outline.textColor}`
if (props.accent !== "secondary" && props.accent) { : buttonStyle === ButtonStyleTypes.SECONDARY
return darkenHover(props.theme.colors[AccentColorMap[props.accent]]); ? `${theme.colors.button.secondary.outline.textColor}`
} : buttonStyle === ButtonStyleTypes.CUSTOM
}}; ? getCustomBackgroundColor(
} theme,
&&:active { prevButtonStyle,
${ButtonColorStyles}; ButtonVariantTypes.SOLID,
background-color: ${(props) => { buttonColor,
if (!props.filled) return props.theme.colors.secondaryDarkest; )
if (props.accent !== "secondary" && props.accent) { : `${theme.colors.button.primary.outline.textColor}`
return darkenActive(props.theme.colors[AccentColorMap[props.accent]]); } !important;
}
}};
border-color: ${(props) => {
if (!props.filled) return;
if (props.accent !== "secondary" && props.accent) {
return darkenActive(props.theme.colors[AccentColorMap[props.accent]]);
}
}};
}
&&.bp3-disabled {
background-color: #d0d7dd;
border: none;
}
} }
`}
border-radius: ${({ borderRadius }) =>
borderRadius === ButtonBorderRadiusTypes.ROUNDED ? "5px" : 0};
box-shadow: ${({ boxShadow, boxShadowColor, theme }) =>
boxShadow === ButtonBoxShadowTypes.VARIANT1
? `0px 0px 4px 3px ${boxShadowColor ||
theme.colors.button.boxShadow.default.variant1}`
: boxShadow === ButtonBoxShadowTypes.VARIANT2
? `3px 3px 4px ${boxShadowColor ||
theme.colors.button.boxShadow.default.variant2}`
: boxShadow === ButtonBoxShadowTypes.VARIANT3
? `0px 1px 3px ${boxShadowColor ||
theme.colors.button.boxShadow.default.variant3}`
: boxShadow === ButtonBoxShadowTypes.VARIANT4
? `2px 2px 0px ${boxShadowColor ||
theme.colors.button.boxShadow.default.variant4}`
: boxShadow === ButtonBoxShadowTypes.VARIANT5
? `-2px -2px 0px ${boxShadowColor ||
theme.colors.button.boxShadow.default.variant5}`
: "none"} !important;
`; `;
export type ButtonStyleName = "primary" | "secondary" | "error" | "grey";
type ButtonStyleProps = { type ButtonStyleProps = {
accent?: ButtonStyleName; buttonColor?: string;
filled?: boolean; buttonStyle?: ButtonStyle;
prevButtonStyle?: ButtonStyle;
buttonVariant?: ButtonVariant;
boxShadow?: ButtonBoxShadow;
boxShadowColor?: string;
borderRadius?: ButtonBorderRadius;
iconName?: IconName;
iconAlign?: Alignment;
}; };
// To be used in any other part of the app // To be used in any other part of the app
export function BaseButton(props: IButtonProps & ButtonStyleProps) { export function BaseButton(props: IButtonProps & ButtonStyleProps) {
const className = props.disabled const {
? `${props.className} bp3-disabled` borderRadius,
: props.className; boxShadow,
return <ButtonWrapper {...props} className={className} />; boxShadowColor,
buttonColor,
buttonStyle,
buttonVariant,
className,
disabled,
icon,
iconAlign,
iconName,
loading,
onClick,
prevButtonStyle,
rightIcon,
text,
} = props;
if (iconAlign === Alignment.RIGHT) {
return (
<StyledButton
alignText={iconName ? Alignment.LEFT : Alignment.CENTER}
borderRadius={borderRadius}
boxShadow={boxShadow}
boxShadowColor={boxShadowColor}
buttonColor={buttonColor}
buttonStyle={buttonStyle}
buttonVariant={buttonVariant}
className={className}
disabled={disabled}
fill
icon={icon}
loading={loading}
onClick={onClick}
prevButtonStyle={prevButtonStyle}
rightIcon={iconName || rightIcon}
text={text}
/>
);
}
return (
<StyledButton
alignText={iconName ? Alignment.RIGHT : Alignment.CENTER}
borderRadius={borderRadius}
boxShadow={boxShadow}
boxShadowColor={boxShadowColor}
buttonColor={buttonColor}
buttonStyle={buttonStyle}
buttonVariant={buttonVariant}
className={className}
disabled={disabled}
fill
icon={iconName || icon}
loading={loading}
onClick={onClick}
prevButtonStyle={prevButtonStyle}
rightIcon={rightIcon}
text={text}
/>
);
} }
BaseButton.defaultProps = { BaseButton.defaultProps = {
accent: "secondary", buttonStyle: "SECONDARY",
buttonVariant: "SOLID",
disabled: false, disabled: false,
text: "Button Text", text: "Button Text",
minimal: true, minimal: true,
@ -194,31 +423,26 @@ interface RecaptchaProps {
recaptchaV2?: boolean; recaptchaV2?: boolean;
} }
interface ButtonContainerProps extends ComponentProps { interface ButtonComponentProps extends ComponentProps {
text?: string; text?: string;
icon?: MaybeElement; icon?: IconName | MaybeElement;
tooltip?: string; tooltip?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void; onClick?: (event: React.MouseEvent<HTMLElement>) => void;
disabled?: boolean; isDisabled?: boolean;
buttonStyle?: ButtonStyle; buttonStyle?: ButtonStyle;
prevButtonStyle?: ButtonStyle;
isLoading: boolean; isLoading: boolean;
rightIcon?: IconName | MaybeElement; rightIcon?: IconName | MaybeElement;
type: ButtonType; type: ButtonType;
buttonColor?: string;
buttonVariant?: ButtonVariant;
borderRadius?: ButtonBorderRadius;
boxShadow?: ButtonBoxShadow;
boxShadowColor?: string;
iconName?: IconName;
iconAlign?: Alignment;
} }
const mapButtonStyleToStyleName = (buttonStyle?: ButtonStyle) => {
switch (buttonStyle) {
case "PRIMARY_BUTTON":
return "primary";
case "SECONDARY_BUTTON":
return "secondary";
case "DANGER_BUTTON":
return "error";
default:
return undefined;
}
};
function RecaptchaV2Component( function RecaptchaV2Component(
props: { props: {
children: any; children: any;
@ -348,9 +572,7 @@ function BtnWrapper(
} }
// To be used with the canvas // To be used with the canvas
function ButtonContainer( function ButtonComponent(props: ButtonComponentProps & RecaptchaProps) {
props: ButtonContainerProps & ButtonStyleProps & RecaptchaProps,
) {
const btnWrapper = ( const btnWrapper = (
<BtnWrapper <BtnWrapper
clickWithRecaptcha={props.clickWithRecaptcha} clickWithRecaptcha={props.clickWithRecaptcha}
@ -359,16 +581,25 @@ function ButtonContainer(
onClick={props.onClick} onClick={props.onClick}
recaptchaV2={props.recaptchaV2} recaptchaV2={props.recaptchaV2}
> >
<ButtonContainer>
<BaseButton <BaseButton
accent={mapButtonStyleToStyleName(props.buttonStyle)} borderRadius={props.borderRadius}
disabled={props.disabled} boxShadow={props.boxShadow}
filled={props.buttonStyle !== "SECONDARY_BUTTON"} boxShadowColor={props.boxShadowColor}
buttonColor={props.buttonColor}
buttonStyle={props.buttonStyle}
buttonVariant={props.buttonVariant}
disabled={props.isDisabled}
icon={props.icon} icon={props.icon}
iconAlign={props.iconAlign}
iconName={props.iconName}
loading={props.isLoading} loading={props.isLoading}
prevButtonStyle={props.prevButtonStyle}
rightIcon={props.rightIcon} rightIcon={props.rightIcon}
text={props.text} text={props.text}
type={props.type} type={props.type}
/> />
</ButtonContainer>
</BtnWrapper> </BtnWrapper>
); );
if (props.tooltip) { if (props.tooltip) {
@ -388,4 +619,4 @@ function ButtonContainer(
} }
} }
export default ButtonContainer; export default ButtonComponent;

View File

@ -7,10 +7,7 @@ import {
InputGroup, InputGroup,
IMenuProps, IMenuProps,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import { import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
BaseButton,
ButtonStyleName,
} from "components/designSystems/blueprint/ButtonComponent";
import { import {
ItemRenderer, ItemRenderer,
Select, Select,
@ -85,8 +82,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
const displayMode = ( const displayMode = (
<BaseButton <BaseButton
accent="primary" buttonStyle="PRIMARY"
filled
icon-right="plus" icon-right="plus"
onClick={this.showTextBox} onClick={this.showTextBox}
text={addItem?.displayText} text={addItem?.displayText}
@ -95,11 +91,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
const editMode = ( const editMode = (
<ControlGroup fill> <ControlGroup fill>
<InputGroup inputRef={this.setNewItemTextInput} /> <InputGroup inputRef={this.setNewItemTextInput} />
<BaseButton <BaseButton onClick={this.handleAddItem} text={addItem?.displayText} />
filled
onClick={this.handleAddItem}
text={addItem?.displayText}
/>
</ControlGroup> </ControlGroup>
); );
return ( return (
@ -154,15 +146,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
}; };
render() { render() {
const { const { autocomplete, input, options, selected, width } = this.props;
accent,
autocomplete,
filled,
input,
options,
selected,
width,
} = this.props;
return ( return (
<StyledDropdown <StyledDropdown
@ -181,8 +165,8 @@ class DropdownComponent extends Component<DropdownComponentProps> {
{this.props.toggle || ( {this.props.toggle || (
<StyledButtonWrapper width={width}> <StyledButtonWrapper width={width}>
<BaseButton <BaseButton
accent={accent || "secondary"} buttonStyle="PRIMARY"
filled={!!filled} buttonVariant="OUTLINE"
rightIcon="chevron-down" rightIcon="chevron-down"
text={this.getSelectedDisplayText()} text={this.getSelectedDisplayText()}
/> />
@ -207,8 +191,6 @@ export interface DropdownComponentProps {
addItemHandler: (name: string) => void; addItemHandler: (name: string) => void;
}; };
toggle?: ReactNode; toggle?: ReactNode;
accent?: ButtonStyleName;
filled?: boolean;
input?: WrappedFieldInputProps; input?: WrappedFieldInputProps;
width?: string; width?: string;
} }

View File

@ -1,13 +1,10 @@
import React from "react"; import React from "react";
import { Field, BaseFieldProps } from "redux-form"; import { Field, BaseFieldProps } from "redux-form";
import DropdownComponent from "components/editorComponents/DropdownComponent"; import DropdownComponent from "components/editorComponents/DropdownComponent";
import { ButtonStyleName } from "components/designSystems/blueprint/ButtonComponent";
import { DropdownOption } from "widgets/DropdownWidget"; import { DropdownOption } from "widgets/DropdownWidget";
interface DynamicDropdownFieldOptions { interface DynamicDropdownFieldOptions {
options: DropdownOption[]; options: DropdownOption[];
accent?: ButtonStyleName;
filled?: boolean;
width?: string; width?: string;
} }

View File

@ -174,8 +174,6 @@ function KeyValueRow(props: Props & WrappedFieldArrayProps) {
<DynamicDropdownFieldWrapper> <DynamicDropdownFieldWrapper>
<DynamicDropdownField <DynamicDropdownField
accent="grey"
filled
name={`${field}.type`} name={`${field}.type`}
options={MULTI_PART_DROPDOWN_OPTIONS} options={MULTI_PART_DROPDOWN_OPTIONS}
width={DEFAULT_MULTI_PART_DROPDOWN_WIDTH} width={DEFAULT_MULTI_PART_DROPDOWN_WIDTH}

View File

@ -101,7 +101,8 @@ class FieldFileInput extends React.Component<Props, FieldFileInputState> {
<div style={{ flexDirection: "row", display: "flex", width: "50vh" }}> <div style={{ flexDirection: "row", display: "flex", width: "50vh" }}>
<StyledDiv>{value.name}</StyledDiv> <StyledDiv>{value.name}</StyledDiv>
<SelectButton <SelectButton
accent="secondary" buttonStyle="PRIMARY"
buttonVariant="OUTLINE"
onClick={() => { onClick={() => {
this.openModal(); this.openModal();
}} }}

View File

@ -5,10 +5,13 @@ import { Button, ButtonGroup, IButtonProps } from "@blueprintjs/core";
import BaseControl, { ControlProps } from "./BaseControl"; import BaseControl, { ControlProps } from "./BaseControl";
import { ControlIcons } from "icons/ControlIcons"; import { ControlIcons } from "icons/ControlIcons";
import { ThemeProp } from "components/ads/common"; import { ThemeProp } from "components/ads/common";
import {
ButtonBorderRadius, export enum ButtonBorderRadiusTypes {
ButtonBorderRadiusTypes, SHARP = "SHARP",
} from "components/designSystems/appsmith/IconButtonComponent"; ROUNDED = "ROUNDED",
CIRCLE = "CIRCLE",
}
export type ButtonBorderRadius = keyof typeof ButtonBorderRadiusTypes;
const StyledButtonGroup = styled(ButtonGroup)` const StyledButtonGroup = styled(ButtonGroup)`
height: 33px; height: 33px;
@ -36,6 +39,7 @@ const StyledButton = styled(Button)<ThemeProp & IButtonProps>`
export interface BorderRadiusOptionsControlProps extends ControlProps { export interface BorderRadiusOptionsControlProps extends ControlProps {
propertyValue: ButtonBorderRadius | undefined; propertyValue: ButtonBorderRadius | undefined;
onChange: (borderRaidus: ButtonBorderRadius) => void; onChange: (borderRaidus: ButtonBorderRadius) => void;
options: any[];
} }
class BorderRadiusOptionsControl extends BaseControl< class BorderRadiusOptionsControl extends BaseControl<
@ -50,11 +54,35 @@ class BorderRadiusOptionsControl extends BaseControl<
} }
public render() { public render() {
const { propertyValue } = this.props; const { options, propertyValue } = this.props;
return ( return (
<StyledButtonGroup fill> <StyledButtonGroup fill>
{options.map((option: ButtonBorderRadius) => {
const active =
option === ButtonBorderRadiusTypes.SHARP
? propertyValue === option || propertyValue === undefined
: propertyValue === option;
const icon =
option === ButtonBorderRadiusTypes.SHARP ? (
<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />
) : option === ButtonBorderRadiusTypes.ROUNDED ? (
<ControlIcons.BORDER_RADIUS_ROUNDED color="#979797" width={15} />
) : (
<ControlIcons.BORDER_RADIUS_CIRCLE color="#979797" width={15} />
);
return (
<StyledButton <StyledButton
active={active}
icon={icon}
key={option}
large
onClick={() => this.toggleOption(option)}
/>
);
})}
{/* <StyledButton
active={propertyValue === ButtonBorderRadiusTypes.SHARP || undefined} active={propertyValue === ButtonBorderRadiusTypes.SHARP || undefined}
icon={<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />} icon={<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />}
large large
@ -75,7 +103,7 @@ class BorderRadiusOptionsControl extends BaseControl<
} }
large large
onClick={() => this.toggleOption(ButtonBorderRadiusTypes.CIRCLE)} onClick={() => this.toggleOption(ButtonBorderRadiusTypes.CIRCLE)}
/> /> */}
</StyledButtonGroup> </StyledButtonGroup>
); );
} }

View File

@ -81,7 +81,7 @@ type IconType = IconName | typeof NONE;
const ICON_NAMES = Object.keys(IconNames).map<IconType>( const ICON_NAMES = Object.keys(IconNames).map<IconType>(
(name: string) => IconNames[name as keyof typeof IconNames], (name: string) => IconNames[name as keyof typeof IconNames],
); );
ICON_NAMES.push(NONE); ICON_NAMES.unshift(NONE);
const TypedSelect = Select.ofType<IconType>(); const TypedSelect = Select.ofType<IconType>();

View File

@ -119,6 +119,9 @@ export const Colors = {
BOX_SHADOW_DEFAULT_VARIANT3: "rgba(0, 0, 0, 0.5)", BOX_SHADOW_DEFAULT_VARIANT3: "rgba(0, 0, 0, 0.5)",
BOX_SHADOW_DEFAULT_VARIANT4: "rgba(0, 0, 0, 0.25)", BOX_SHADOW_DEFAULT_VARIANT4: "rgba(0, 0, 0, 0.25)",
BOX_SHADOW_DEFAULT_VARIANT5: "rgba(0, 0, 0, 0.25)", BOX_SHADOW_DEFAULT_VARIANT5: "rgba(0, 0, 0, 0.25)",
BUTTON_CUSTOM_SOLID_DARK_TEXT_COLOR: "#333",
SELECT_DISABLED: "#ced9e080", SELECT_DISABLED: "#ced9e080",
}; };
export type Color = typeof Colors[keyof typeof Colors]; export type Color = typeof Colors[keyof typeof Colors];

View File

@ -14,9 +14,9 @@ import {
} from "utils/DynamicBindingUtils"; } from "utils/DynamicBindingUtils";
import { Colors } from "constants/Colors"; import { Colors } from "constants/Colors";
import FileDataTypes from "widgets/FileDataTypes"; import FileDataTypes from "widgets/FileDataTypes";
import { ButtonBorderRadiusTypes } from "components/propertyControls/BorderRadiusOptionsControl";
import { ButtonBoxShadowTypes } from "components/propertyControls/BoxShadowOptionsControl";
import { import {
ButtonBorderRadiusTypes,
ButtonBoxShadowTypes,
ButtonStyleTypes, ButtonStyleTypes,
ButtonVariantTypes, ButtonVariantTypes,
} from "components/designSystems/appsmith/IconButtonComponent"; } from "components/designSystems/appsmith/IconButtonComponent";
@ -33,7 +33,8 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
config: { config: {
BUTTON_WIDGET: { BUTTON_WIDGET: {
text: "Submit", text: "Submit",
buttonStyle: "PRIMARY_BUTTON", buttonStyle: "PRIMARY",
buttonVariant: "SOLID",
rows: 1 * GRID_DENSITY_MIGRATION_V1, rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 2 * GRID_DENSITY_MIGRATION_V1, columns: 2 * GRID_DENSITY_MIGRATION_V1,
widgetName: "Button", widgetName: "Button",

View File

@ -163,14 +163,13 @@ function RapidApiEditorForm(props: Props) {
<ActionButtons> <ActionButtons>
<ActionButton <ActionButton
accent="error" buttonStyle="DANGER"
loading={isDeleting} loading={isDeleting}
onClick={onDeleteClick} onClick={onDeleteClick}
text="Delete" text="Delete"
/> />
<ActionButton <ActionButton
accent="primary" buttonStyle="PRIMARY"
filled
loading={isRunning} loading={isRunning}
onClick={() => { onClick={() => {
onRunClick(); onRunClick();

View File

@ -188,7 +188,9 @@ class DatasourceDBEditor extends JSONtoForm<Props> {
: undefined} : undefined}
<SaveButtonContainer> <SaveButtonContainer>
<ActionButton <ActionButton
accent="error" buttonStyle="DANGER"
buttonVariant="SOLID"
// accent="error"
className="t--delete-datasource" className="t--delete-datasource"
loading={isDeleting} loading={isDeleting}
onClick={() => handleDelete(datasourceId)} onClick={() => handleDelete(datasourceId)}
@ -196,7 +198,9 @@ class DatasourceDBEditor extends JSONtoForm<Props> {
/> />
<ActionButton <ActionButton
accent="secondary" // accent="secondary"
buttonStyle="PRIMARY"
buttonVariant="OUTLINE"
className="t--test-datasource" className="t--test-datasource"
loading={isTesting} loading={isTesting}
onClick={this.test} onClick={this.test}

View File

@ -332,7 +332,9 @@ class DatasourceRestAPIEditor extends React.Component<Props> {
return ( return (
<SaveButtonContainer> <SaveButtonContainer>
<ActionButton <ActionButton
accent="error" // accent="error"
buttonStyle="DANGER"
buttonVariant="SOLID"
className="t--delete-datasource" className="t--delete-datasource"
loading={isDeleting} loading={isDeleting}
onClick={() => deleteDatasource(datasourceId)} onClick={() => deleteDatasource(datasourceId)}

View File

@ -145,9 +145,8 @@ function DatasourceCard(props: DatasourceCardProps) {
text="Edit Datasource" text="Edit Datasource"
/> />
<ActionButton <ActionButton
accent="primary" buttonStyle="PRIMARY"
className="t--create-api" className="t--create-api"
filled
icon={"plus"} icon={"plus"}
onClick={() => props.onCreate(datasource)} onClick={() => props.onCreate(datasource)}
text="New API" text="New API"

View File

@ -180,7 +180,9 @@ class DatasourceSaaSEditor extends JSONtoForm<Props> {
: null} : null}
<SaveButtonContainer> <SaveButtonContainer>
<ActionButton <ActionButton
accent="error" // accent="error"
buttonStyle="DANGER"
buttonVariant="SOLID"
className="t--delete-datasource" className="t--delete-datasource"
loading={isDeleting} loading={isDeleting}
onClick={() => onClick={() =>

View File

@ -1,13 +1,24 @@
import React from "react"; import React from "react";
import * as Sentry from "@sentry/react";
import { Alignment } from "@blueprintjs/core";
import { IconName } from "@blueprintjs/icons";
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, {
ButtonStyle,
ButtonStyleTypes,
ButtonType, ButtonType,
ButtonVariant,
} from "components/designSystems/blueprint/ButtonComponent"; } from "components/designSystems/blueprint/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation"; import { ValidationTypes } from "constants/WidgetValidation";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC"; import withMeta, { WithMeta } from "./MetaHOC";
import { ButtonBoxShadow } from "components/propertyControls/BoxShadowOptionsControl";
import {
ButtonBorderRadius,
ButtonBorderRadiusTypes,
} from "components/propertyControls/BorderRadiusOptionsControl";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> { class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
onButtonClickBound: (event: React.MouseEvent<HTMLElement>) => void; onButtonClickBound: (event: React.MouseEvent<HTMLElement>) => void;
@ -36,39 +47,6 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
isTriggerProperty: false, isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT }, validation: { type: ValidationTypes.TEXT },
}, },
{
propertyName: "buttonStyle",
label: "Button Style",
controlType: "DROP_DOWN",
helpText: "Changes the style of the button",
options: [
{
label: "Primary Button",
value: "PRIMARY_BUTTON",
},
{
label: "Secondary Button",
value: "SECONDARY_BUTTON",
},
{
label: "Danger Button",
value: "DANGER_BUTTON",
},
],
isJSConvertible: true,
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: [
"PRIMARY_BUTTON",
"SECONDARY_BUTTON",
"DANGER_BUTTON",
],
},
},
},
{ {
helpText: "Show helper text with button on hover", helpText: "Show helper text with button on hover",
propertyName: "tooltip", propertyName: "tooltip",
@ -135,7 +113,221 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
}, },
], ],
}, },
{
sectionName: "Styles",
children: [
{
propertyName: "buttonStyle",
label: "Button Style",
controlType: "DROP_DOWN",
helpText: "Changes the style of the button",
options: [
{
label: "Primary",
value: "PRIMARY",
},
{
label: "Warning",
value: "WARNING",
},
{
label: "Danger",
value: "DANGER",
},
{
label: "Info",
value: "INFO",
},
{
label: "Secondary",
value: "SECONDARY",
},
{
label: "Custom",
value: "CUSTOM",
},
],
updateHook: (
props: ButtonWidgetProps,
propertyPath: string,
propertyValue: string,
) => {
let propertiesToUpdate = [
{ propertyPath, propertyValue },
{ propertyPath: "prevButtonStyle", propertyValue },
]; ];
if (propertyValue === "CUSTOM") {
propertiesToUpdate = [{ propertyPath, propertyValue }];
}
propertiesToUpdate.push({
propertyPath: "buttonColor",
propertyValue: "",
});
return propertiesToUpdate;
},
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: [
"PRIMARY",
"WARNING",
"DANGER",
"INFO",
"SECONDARY",
"CUSTOM",
],
},
},
},
{
propertyName: "buttonColor",
helpText:
"Sets the custom color preset based on the button variant",
label: "Button Color",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
hidden: (props: ButtonWidgetProps) =>
props.buttonStyle !== ButtonStyleTypes.CUSTOM,
dependencies: ["buttonStyle"],
},
{
propertyName: "buttonVariant",
label: "Button Variant",
controlType: "DROP_DOWN",
helpText: "Sets the variant of the icon button",
options: [
{
label: "Solid",
value: "SOLID",
},
{
label: "Outline",
value: "OUTLINE",
},
{
label: "Ghost",
value: "GHOST",
},
],
isJSConvertible: true,
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedVAlues: ["SOLID", "OUTLINE", "GHOST"],
},
},
},
{
propertyName: "borderRadius",
label: "Border Radius",
helpText:
"Rounds the corners of the icon button's outer border edge",
controlType: "BORDER_RADIUS_OPTIONS",
options: [
ButtonBorderRadiusTypes.SHARP,
ButtonBorderRadiusTypes.ROUNDED,
],
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: ["CIRCLE", "SHARP", "ROUNDED"],
},
},
},
{
propertyName: "boxShadow",
label: "Box Shadow",
helpText:
"Enables you to cast a drop shadow from the frame of the widget",
controlType: "BOX_SHADOW_OPTIONS",
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: [
"NONE",
"VARIANT1",
"VARIANT2",
"VARIANT3",
"VARIANT4",
"VARIANT5",
],
},
},
},
{
propertyName: "boxShadowColor",
helpText: "Sets the shadow color of the widget",
label: "Shadow Color",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
regex: /^(?![<|{{]).+/,
},
},
},
{
propertyName: "iconName",
label: "Icon",
helpText: "Sets the icon to be used for the button",
controlType: "ICON_SELECT",
isBindProperty: false,
isTriggerProperty: false,
updateHook: (
props: ButtonWidgetProps,
propertyPath: string,
propertyValue: string,
) => {
const propertiesToUpdate = [{ propertyPath, propertyValue }];
if (!props.iconAlign) {
propertiesToUpdate.push({
propertyPath: "iconAlign",
propertyValue: Alignment.LEFT,
});
}
return propertiesToUpdate;
},
validation: {
type: ValidationTypes.TEXT,
},
},
{
propertyName: "iconAlign",
label: "Icon Alignment",
helpText: "Sets the icon alignment of the button",
controlType: "ICON_ALIGN",
isBindProperty: false,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: ["center", "left", "right"],
},
},
},
],
},
];
}
static getDefaultPropertiesMap(): Record<string, string> {
return {
prevButtonStyle: "buttonStyle",
};
} }
static getMetaPropertiesMap(): Record<string, any> { static getMetaPropertiesMap(): Record<string, any> {
@ -188,14 +380,22 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
getPageView() { getPageView() {
return ( return (
<ButtonComponent <ButtonComponent
borderRadius={this.props.borderRadius}
boxShadow={this.props.boxShadow}
boxShadowColor={this.props.boxShadowColor}
buttonColor={this.props.buttonColor}
buttonStyle={this.props.buttonStyle} buttonStyle={this.props.buttonStyle}
buttonVariant={this.props.buttonVariant}
clickWithRecaptcha={this.clickWithRecaptchaBound} clickWithRecaptcha={this.clickWithRecaptchaBound}
disabled={this.props.isDisabled}
googleRecaptchaKey={this.props.googleRecaptchaKey} googleRecaptchaKey={this.props.googleRecaptchaKey}
handleRecaptchaV2Loading={this.handleRecaptchaV2Loading} handleRecaptchaV2Loading={this.handleRecaptchaV2Loading}
iconAlign={this.props.iconAlign}
iconName={this.props.iconName}
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading} isLoading={this.props.isLoading || this.state.isLoading}
key={this.props.widgetId} key={this.props.widgetId}
onClick={!this.props.isDisabled ? this.onButtonClickBound : undefined} onClick={!this.props.isDisabled ? this.onButtonClickBound : undefined}
prevButtonStyle={this.props.prevButtonStyle}
recaptchaV2={this.props.recaptchaV2} recaptchaV2={this.props.recaptchaV2}
text={this.props.text} text={this.props.text}
tooltip={this.props.tooltip} tooltip={this.props.tooltip}
@ -211,21 +411,23 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
} }
} }
export type ButtonStyle =
| "PRIMARY_BUTTON"
| "SECONDARY_BUTTON"
| "SUCCESS_BUTTON"
| "DANGER_BUTTON";
export interface ButtonWidgetProps extends WidgetProps, WithMeta { export interface ButtonWidgetProps extends WidgetProps, WithMeta {
text?: string; text?: string;
buttonStyle?: ButtonStyle;
onClick?: string; onClick?: string;
isDisabled?: boolean; isDisabled?: boolean;
isVisible?: boolean; isVisible?: boolean;
recaptchaV2?: boolean; recaptchaV2?: boolean;
buttonType?: ButtonType; buttonType?: ButtonType;
googleRecaptchaKey?: string; googleRecaptchaKey?: string;
buttonStyle?: ButtonStyle;
prevButtonStyle?: ButtonStyle;
buttonVariant?: ButtonVariant;
buttonColor?: string;
borderRadius?: ButtonBorderRadius;
boxShadow?: ButtonBoxShadow;
boxShadowColor?: string;
iconName?: IconName;
iconAlign?: Alignment;
} }
interface ButtonWidgetState extends WidgetState { interface ButtonWidgetState extends WidgetState {

View File

@ -2,6 +2,7 @@ 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, {
ButtonStyle,
ButtonType, ButtonType,
} from "components/designSystems/blueprint/ButtonComponent"; } from "components/designSystems/blueprint/ButtonComponent";
import { import {
@ -194,8 +195,8 @@ class FormButtonWidget extends BaseWidget<
<ButtonComponent <ButtonComponent
buttonStyle={this.props.buttonStyle} buttonStyle={this.props.buttonStyle}
clickWithRecaptcha={this.clickWithRecaptchaBound} clickWithRecaptcha={this.clickWithRecaptchaBound}
disabled={disabled}
googleRecaptchaKey={this.props.googleRecaptchaKey} googleRecaptchaKey={this.props.googleRecaptchaKey}
isDisabled={disabled}
isLoading={this.props.isLoading || this.state.isLoading} isLoading={this.props.isLoading || this.state.isLoading}
key={this.props.widgetId} key={this.props.widgetId}
onClick={!disabled ? this.onButtonClickBound : undefined} onClick={!disabled ? this.onButtonClickBound : undefined}
@ -213,11 +214,11 @@ class FormButtonWidget extends BaseWidget<
} }
} }
export type ButtonStyle = // export type ButtonStyle =
| "PRIMARY_BUTTON" // | "PRIMARY_BUTTON"
| "SECONDARY_BUTTON" // | "SECONDARY_BUTTON"
| "SUCCESS_BUTTON" // | "SUCCESS_BUTTON"
| "DANGER_BUTTON"; // | "DANGER_BUTTON";
export interface FormButtonWidgetProps extends WidgetProps, WithMeta { export interface FormButtonWidgetProps extends WidgetProps, WithMeta {
text?: string; text?: string;

View File

@ -8,11 +8,14 @@ import { ValidationTypes } from "constants/WidgetValidation";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import IconButtonComponent, { import IconButtonComponent, {
ButtonBorderRadius,
ButtonBoxShadow,
ButtonStyle, ButtonStyle,
ButtonVariant, ButtonVariant,
} from "components/designSystems/appsmith/IconButtonComponent"; } from "components/designSystems/appsmith/IconButtonComponent";
import {
ButtonBorderRadius,
ButtonBorderRadiusTypes,
} from "components/propertyControls/BorderRadiusOptionsControl";
import { ButtonBoxShadow } from "components/propertyControls/BoxShadowOptionsControl";
export interface IconButtonWidgetProps extends WidgetProps { export interface IconButtonWidgetProps extends WidgetProps {
iconName?: IconName; iconName?: IconName;
@ -99,6 +102,11 @@ class IconButtonWidget extends BaseWidget<IconButtonWidgetProps, WidgetState> {
helpText: helpText:
"Rounds the corners of the icon button's outer border edge", "Rounds the corners of the icon button's outer border edge",
controlType: "BORDER_RADIUS_OPTIONS", controlType: "BORDER_RADIUS_OPTIONS",
options: [
ButtonBorderRadiusTypes.SHARP,
ButtonBorderRadiusTypes.ROUNDED,
ButtonBorderRadiusTypes.CIRCLE,
],
isBindProperty: false, isBindProperty: false,
isTriggerProperty: false, isTriggerProperty: false,
validation: { validation: {

View File

@ -16890,9 +16890,10 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz"
tinycolor2@^1.4.1: tinycolor2@^1.4.1, tinycolor2@^1.4.2:
version "1.4.2" version "1.4.2"
resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
tmp@^0.0.33: tmp@^0.0.33:
version "0.0.33" version "0.0.33"