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:
parent
163192d851
commit
cb4242e7e5
|
|
@ -19,12 +19,20 @@ describe("Button Widget Functionality", function() {
|
|||
|
||||
it("Button-Style Validation", function() {
|
||||
//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
|
||||
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 });
|
||||
// Change to Danger button sytle
|
||||
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 });
|
||||
// Change to Primary button sytle
|
||||
cy.openPropertyPane("buttonwidget");
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@
|
|||
"styled-components": "^5.2.0",
|
||||
"styled-system": "^5.1.5",
|
||||
"tern": "^0.21.0",
|
||||
"tinycolor2": "^1.4.1",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"toposort": "^2.0.2",
|
||||
"ts-loader": "^6.0.4",
|
||||
"tslib": "^2.1.0",
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ class FilePickerComponent extends React.Component<
|
|||
}
|
||||
return (
|
||||
<BaseButton
|
||||
accent="primary"
|
||||
buttonStyle="PRIMARY"
|
||||
disabled={this.props.isDisabled}
|
||||
filled
|
||||
loading={this.props.isLoading}
|
||||
onClick={this.openModal}
|
||||
text={label}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ import { IconName } from "@blueprintjs/icons";
|
|||
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
|
||||
import { ThemeProp } from "components/ads/common";
|
||||
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
||||
import {
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
} from "components/propertyControls/BorderRadiusOptionsControl";
|
||||
import {
|
||||
ButtonBoxShadow,
|
||||
ButtonBoxShadowTypes,
|
||||
} from "components/propertyControls/BoxShadowOptionsControl";
|
||||
|
||||
const IconButtonContainer = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -176,23 +184,6 @@ export enum 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 {
|
||||
iconName?: IconName;
|
||||
buttonStyle: ButtonStyle;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import tinycolor from "tinycolor2";
|
||||
|
||||
import {
|
||||
IButtonProps,
|
||||
MaybeElement,
|
||||
Button,
|
||||
IconName,
|
||||
Alignment,
|
||||
Position,
|
||||
} from "@blueprintjs/core";
|
||||
import { IconName } from "@blueprintjs/icons";
|
||||
|
||||
import Tooltip from "components/ads/Tooltip";
|
||||
import styled, { css } from "styled-components";
|
||||
import { ButtonStyle } from "widgets/ButtonWidget";
|
||||
import { Theme, darkenHover, darkenActive } from "constants/DefaultTheme";
|
||||
import _ from "lodash";
|
||||
import { Theme } from "constants/DefaultTheme";
|
||||
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
|
||||
import { useScript, ScriptStatus } from "utils/hooks/useScript";
|
||||
import {
|
||||
|
|
@ -18,38 +20,126 @@ import {
|
|||
GOOGLE_RECAPTCHA_DOMAIN_ERROR,
|
||||
createMessage,
|
||||
} from "constants/messages";
|
||||
import { Variant } from "components/ads/common";
|
||||
import { ThemeProp, Variant } from "components/ads/common";
|
||||
import { Toaster } from "components/ads/Toast";
|
||||
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) => {
|
||||
if (props.filled) {
|
||||
return props.accent === "grey"
|
||||
? props.theme.colors.textOnGreyBG
|
||||
: props.theme.colors.textOnDarkBG;
|
||||
export enum ButtonStyleTypes {
|
||||
PRIMARY = "PRIMARY",
|
||||
WARNING = "WARNING",
|
||||
DANGER = "DANGER",
|
||||
INFO = "INFO",
|
||||
SECONDARY = "SECONDARY",
|
||||
CUSTOM = "CUSTOM",
|
||||
}
|
||||
export type ButtonStyle = keyof typeof ButtonStyleTypes;
|
||||
|
||||
export enum ButtonVariantTypes {
|
||||
SOLID = "SOLID",
|
||||
OUTLINE = "OUTLINE",
|
||||
GHOST = "GHOST",
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (props.accent) {
|
||||
if (props.accent === "secondary") {
|
||||
return props.theme.colors[AccentColorMap["primary"]];
|
||||
}
|
||||
return props.theme.colors[AccentColorMap[props.accent]];
|
||||
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) => {
|
||||
if (props.filled) {
|
||||
return props.accent === "grey"
|
||||
? props.theme.colors.dropdownIconDarkBg
|
||||
: props.theme.colors.textOnDarkBG;
|
||||
}
|
||||
if (props.accent) {
|
||||
if (props.accent === "secondary") {
|
||||
return props.theme.colors[AccentColorMap["primary"]];
|
||||
}
|
||||
return props.theme.colors[AccentColorMap[props.accent]];
|
||||
}
|
||||
const getCustomBackgroundColor = (
|
||||
theme: Theme,
|
||||
prevButtonStyle?: ButtonStyle,
|
||||
buttonVariant?: ButtonVariant,
|
||||
backgroundColor?: string,
|
||||
) => {
|
||||
return buttonVariant === ButtonVariantTypes.SOLID
|
||||
? backgroundColor
|
||||
? backgroundColor
|
||||
: theme.colors.button[
|
||||
(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`
|
||||
max-width: 350px;
|
||||
`;
|
||||
|
|
@ -64,118 +154,257 @@ const ToolTipWrapper = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const ButtonColorStyles = css<ButtonStyleProps>`
|
||||
color: ${getButtonColorStyles};
|
||||
svg {
|
||||
fill: ${getButtonFillStyles};
|
||||
}
|
||||
`;
|
||||
const ButtonContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
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%;
|
||||
& > button {
|
||||
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;
|
||||
font-weight: ${(props) => props.theme.fontWeights[2]};
|
||||
outline: none;
|
||||
const StyledButton = styled(Button)<ThemeProp & ButtonStyleProps>`
|
||||
height: 100%;
|
||||
background-image: none !important;
|
||||
font-weight: ${(props) => props.theme.fontWeights[2]};
|
||||
outline: none;
|
||||
padding: 0px 10px;
|
||||
|
||||
&.bp3-button {
|
||||
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%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&&:hover,
|
||||
&&:focus {
|
||||
${ButtonColorStyles};
|
||||
background-color: ${(props) => {
|
||||
if (!props.filled) return props.theme.colors.secondaryDarker;
|
||||
if (props.accent !== "secondary" && props.accent) {
|
||||
return darkenHover(props.theme.colors[AccentColorMap[props.accent]]);
|
||||
}
|
||||
}};
|
||||
border-color: ${(props) => {
|
||||
if (!props.filled) return;
|
||||
if (props.accent !== "secondary" && props.accent) {
|
||||
return darkenHover(props.theme.colors[AccentColorMap[props.accent]]);
|
||||
}
|
||||
}};
|
||||
color: ${
|
||||
buttonVariant === ButtonVariantTypes.SOLID
|
||||
? buttonStyle === ButtonStyleTypes.CUSTOM
|
||||
? getCustomTextColor(theme, buttonColor, prevButtonStyle)
|
||||
: `${theme.colors.button.primary.solid.textColor}`
|
||||
: buttonStyle === ButtonStyleTypes.WARNING
|
||||
? `${theme.colors.button.warning.outline.textColor}`
|
||||
: buttonStyle === ButtonStyleTypes.DANGER
|
||||
? `${theme.colors.button.danger.outline.textColor}`
|
||||
: buttonStyle === ButtonStyleTypes.INFO
|
||||
? `${theme.colors.button.info.outline.textColor}`
|
||||
: buttonStyle === ButtonStyleTypes.SECONDARY
|
||||
? `${theme.colors.button.secondary.outline.textColor}`
|
||||
: buttonStyle === ButtonStyleTypes.CUSTOM
|
||||
? getCustomBackgroundColor(
|
||||
theme,
|
||||
prevButtonStyle,
|
||||
ButtonVariantTypes.SOLID,
|
||||
buttonColor,
|
||||
)
|
||||
: `${theme.colors.button.primary.outline.textColor}`
|
||||
} !important;
|
||||
}
|
||||
&&:active {
|
||||
${ButtonColorStyles};
|
||||
background-color: ${(props) => {
|
||||
if (!props.filled) return props.theme.colors.secondaryDarkest;
|
||||
if (props.accent !== "secondary" && props.accent) {
|
||||
return darkenActive(props.theme.colors[AccentColorMap[props.accent]]);
|
||||
}
|
||||
}};
|
||||
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 = {
|
||||
accent?: ButtonStyleName;
|
||||
filled?: boolean;
|
||||
buttonColor?: string;
|
||||
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
|
||||
export function BaseButton(props: IButtonProps & ButtonStyleProps) {
|
||||
const className = props.disabled
|
||||
? `${props.className} bp3-disabled`
|
||||
: props.className;
|
||||
return <ButtonWrapper {...props} className={className} />;
|
||||
const {
|
||||
borderRadius,
|
||||
boxShadow,
|
||||
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 = {
|
||||
accent: "secondary",
|
||||
buttonStyle: "SECONDARY",
|
||||
buttonVariant: "SOLID",
|
||||
disabled: false,
|
||||
text: "Button Text",
|
||||
minimal: true,
|
||||
|
|
@ -194,31 +423,26 @@ interface RecaptchaProps {
|
|||
recaptchaV2?: boolean;
|
||||
}
|
||||
|
||||
interface ButtonContainerProps extends ComponentProps {
|
||||
interface ButtonComponentProps extends ComponentProps {
|
||||
text?: string;
|
||||
icon?: MaybeElement;
|
||||
icon?: IconName | MaybeElement;
|
||||
tooltip?: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
disabled?: boolean;
|
||||
isDisabled?: boolean;
|
||||
buttonStyle?: ButtonStyle;
|
||||
prevButtonStyle?: ButtonStyle;
|
||||
isLoading: boolean;
|
||||
rightIcon?: IconName | MaybeElement;
|
||||
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(
|
||||
props: {
|
||||
children: any;
|
||||
|
|
@ -348,9 +572,7 @@ function BtnWrapper(
|
|||
}
|
||||
|
||||
// To be used with the canvas
|
||||
function ButtonContainer(
|
||||
props: ButtonContainerProps & ButtonStyleProps & RecaptchaProps,
|
||||
) {
|
||||
function ButtonComponent(props: ButtonComponentProps & RecaptchaProps) {
|
||||
const btnWrapper = (
|
||||
<BtnWrapper
|
||||
clickWithRecaptcha={props.clickWithRecaptcha}
|
||||
|
|
@ -359,16 +581,25 @@ function ButtonContainer(
|
|||
onClick={props.onClick}
|
||||
recaptchaV2={props.recaptchaV2}
|
||||
>
|
||||
<BaseButton
|
||||
accent={mapButtonStyleToStyleName(props.buttonStyle)}
|
||||
disabled={props.disabled}
|
||||
filled={props.buttonStyle !== "SECONDARY_BUTTON"}
|
||||
icon={props.icon}
|
||||
loading={props.isLoading}
|
||||
rightIcon={props.rightIcon}
|
||||
text={props.text}
|
||||
type={props.type}
|
||||
/>
|
||||
<ButtonContainer>
|
||||
<BaseButton
|
||||
borderRadius={props.borderRadius}
|
||||
boxShadow={props.boxShadow}
|
||||
boxShadowColor={props.boxShadowColor}
|
||||
buttonColor={props.buttonColor}
|
||||
buttonStyle={props.buttonStyle}
|
||||
buttonVariant={props.buttonVariant}
|
||||
disabled={props.isDisabled}
|
||||
icon={props.icon}
|
||||
iconAlign={props.iconAlign}
|
||||
iconName={props.iconName}
|
||||
loading={props.isLoading}
|
||||
prevButtonStyle={props.prevButtonStyle}
|
||||
rightIcon={props.rightIcon}
|
||||
text={props.text}
|
||||
type={props.type}
|
||||
/>
|
||||
</ButtonContainer>
|
||||
</BtnWrapper>
|
||||
);
|
||||
if (props.tooltip) {
|
||||
|
|
@ -388,4 +619,4 @@ function ButtonContainer(
|
|||
}
|
||||
}
|
||||
|
||||
export default ButtonContainer;
|
||||
export default ButtonComponent;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ import {
|
|||
InputGroup,
|
||||
IMenuProps,
|
||||
} from "@blueprintjs/core";
|
||||
import {
|
||||
BaseButton,
|
||||
ButtonStyleName,
|
||||
} from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import {
|
||||
ItemRenderer,
|
||||
Select,
|
||||
|
|
@ -85,8 +82,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
|
|||
|
||||
const displayMode = (
|
||||
<BaseButton
|
||||
accent="primary"
|
||||
filled
|
||||
buttonStyle="PRIMARY"
|
||||
icon-right="plus"
|
||||
onClick={this.showTextBox}
|
||||
text={addItem?.displayText}
|
||||
|
|
@ -95,11 +91,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
|
|||
const editMode = (
|
||||
<ControlGroup fill>
|
||||
<InputGroup inputRef={this.setNewItemTextInput} />
|
||||
<BaseButton
|
||||
filled
|
||||
onClick={this.handleAddItem}
|
||||
text={addItem?.displayText}
|
||||
/>
|
||||
<BaseButton onClick={this.handleAddItem} text={addItem?.displayText} />
|
||||
</ControlGroup>
|
||||
);
|
||||
return (
|
||||
|
|
@ -154,15 +146,7 @@ class DropdownComponent extends Component<DropdownComponentProps> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
accent,
|
||||
autocomplete,
|
||||
filled,
|
||||
input,
|
||||
options,
|
||||
selected,
|
||||
width,
|
||||
} = this.props;
|
||||
const { autocomplete, input, options, selected, width } = this.props;
|
||||
|
||||
return (
|
||||
<StyledDropdown
|
||||
|
|
@ -181,8 +165,8 @@ class DropdownComponent extends Component<DropdownComponentProps> {
|
|||
{this.props.toggle || (
|
||||
<StyledButtonWrapper width={width}>
|
||||
<BaseButton
|
||||
accent={accent || "secondary"}
|
||||
filled={!!filled}
|
||||
buttonStyle="PRIMARY"
|
||||
buttonVariant="OUTLINE"
|
||||
rightIcon="chevron-down"
|
||||
text={this.getSelectedDisplayText()}
|
||||
/>
|
||||
|
|
@ -207,8 +191,6 @@ export interface DropdownComponentProps {
|
|||
addItemHandler: (name: string) => void;
|
||||
};
|
||||
toggle?: ReactNode;
|
||||
accent?: ButtonStyleName;
|
||||
filled?: boolean;
|
||||
input?: WrappedFieldInputProps;
|
||||
width?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
import React from "react";
|
||||
import { Field, BaseFieldProps } from "redux-form";
|
||||
import DropdownComponent from "components/editorComponents/DropdownComponent";
|
||||
import { ButtonStyleName } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { DropdownOption } from "widgets/DropdownWidget";
|
||||
|
||||
interface DynamicDropdownFieldOptions {
|
||||
options: DropdownOption[];
|
||||
accent?: ButtonStyleName;
|
||||
filled?: boolean;
|
||||
width?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,8 +174,6 @@ function KeyValueRow(props: Props & WrappedFieldArrayProps) {
|
|||
|
||||
<DynamicDropdownFieldWrapper>
|
||||
<DynamicDropdownField
|
||||
accent="grey"
|
||||
filled
|
||||
name={`${field}.type`}
|
||||
options={MULTI_PART_DROPDOWN_OPTIONS}
|
||||
width={DEFAULT_MULTI_PART_DROPDOWN_WIDTH}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ class FieldFileInput extends React.Component<Props, FieldFileInputState> {
|
|||
<div style={{ flexDirection: "row", display: "flex", width: "50vh" }}>
|
||||
<StyledDiv>{value.name}</StyledDiv>
|
||||
<SelectButton
|
||||
accent="secondary"
|
||||
buttonStyle="PRIMARY"
|
||||
buttonVariant="OUTLINE"
|
||||
onClick={() => {
|
||||
this.openModal();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ import { Button, ButtonGroup, IButtonProps } from "@blueprintjs/core";
|
|||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import { ThemeProp } from "components/ads/common";
|
||||
import {
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
} from "components/designSystems/appsmith/IconButtonComponent";
|
||||
|
||||
export enum ButtonBorderRadiusTypes {
|
||||
SHARP = "SHARP",
|
||||
ROUNDED = "ROUNDED",
|
||||
CIRCLE = "CIRCLE",
|
||||
}
|
||||
export type ButtonBorderRadius = keyof typeof ButtonBorderRadiusTypes;
|
||||
|
||||
const StyledButtonGroup = styled(ButtonGroup)`
|
||||
height: 33px;
|
||||
|
|
@ -36,6 +39,7 @@ const StyledButton = styled(Button)<ThemeProp & IButtonProps>`
|
|||
export interface BorderRadiusOptionsControlProps extends ControlProps {
|
||||
propertyValue: ButtonBorderRadius | undefined;
|
||||
onChange: (borderRaidus: ButtonBorderRadius) => void;
|
||||
options: any[];
|
||||
}
|
||||
|
||||
class BorderRadiusOptionsControl extends BaseControl<
|
||||
|
|
@ -50,11 +54,35 @@ class BorderRadiusOptionsControl extends BaseControl<
|
|||
}
|
||||
|
||||
public render() {
|
||||
const { propertyValue } = this.props;
|
||||
const { options, propertyValue } = this.props;
|
||||
|
||||
return (
|
||||
<StyledButtonGroup fill>
|
||||
<StyledButton
|
||||
{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
|
||||
active={active}
|
||||
icon={icon}
|
||||
key={option}
|
||||
large
|
||||
onClick={() => this.toggleOption(option)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{/* <StyledButton
|
||||
active={propertyValue === ButtonBorderRadiusTypes.SHARP || undefined}
|
||||
icon={<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />}
|
||||
large
|
||||
|
|
@ -75,7 +103,7 @@ class BorderRadiusOptionsControl extends BaseControl<
|
|||
}
|
||||
large
|
||||
onClick={() => this.toggleOption(ButtonBorderRadiusTypes.CIRCLE)}
|
||||
/>
|
||||
/> */}
|
||||
</StyledButtonGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ type IconType = IconName | typeof NONE;
|
|||
const ICON_NAMES = Object.keys(IconNames).map<IconType>(
|
||||
(name: string) => IconNames[name as keyof typeof IconNames],
|
||||
);
|
||||
ICON_NAMES.push(NONE);
|
||||
ICON_NAMES.unshift(NONE);
|
||||
|
||||
const TypedSelect = Select.ofType<IconType>();
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ export const Colors = {
|
|||
BOX_SHADOW_DEFAULT_VARIANT3: "rgba(0, 0, 0, 0.5)",
|
||||
BOX_SHADOW_DEFAULT_VARIANT4: "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",
|
||||
};
|
||||
export type Color = typeof Colors[keyof typeof Colors];
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ import {
|
|||
} from "utils/DynamicBindingUtils";
|
||||
import { Colors } from "constants/Colors";
|
||||
import FileDataTypes from "widgets/FileDataTypes";
|
||||
import { ButtonBorderRadiusTypes } from "components/propertyControls/BorderRadiusOptionsControl";
|
||||
import { ButtonBoxShadowTypes } from "components/propertyControls/BoxShadowOptionsControl";
|
||||
import {
|
||||
ButtonBorderRadiusTypes,
|
||||
ButtonBoxShadowTypes,
|
||||
ButtonStyleTypes,
|
||||
ButtonVariantTypes,
|
||||
} from "components/designSystems/appsmith/IconButtonComponent";
|
||||
|
|
@ -33,7 +33,8 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
config: {
|
||||
BUTTON_WIDGET: {
|
||||
text: "Submit",
|
||||
buttonStyle: "PRIMARY_BUTTON",
|
||||
buttonStyle: "PRIMARY",
|
||||
buttonVariant: "SOLID",
|
||||
rows: 1 * GRID_DENSITY_MIGRATION_V1,
|
||||
columns: 2 * GRID_DENSITY_MIGRATION_V1,
|
||||
widgetName: "Button",
|
||||
|
|
|
|||
|
|
@ -163,14 +163,13 @@ function RapidApiEditorForm(props: Props) {
|
|||
|
||||
<ActionButtons>
|
||||
<ActionButton
|
||||
accent="error"
|
||||
buttonStyle="DANGER"
|
||||
loading={isDeleting}
|
||||
onClick={onDeleteClick}
|
||||
text="Delete"
|
||||
/>
|
||||
<ActionButton
|
||||
accent="primary"
|
||||
filled
|
||||
buttonStyle="PRIMARY"
|
||||
loading={isRunning}
|
||||
onClick={() => {
|
||||
onRunClick();
|
||||
|
|
|
|||
|
|
@ -188,7 +188,9 @@ class DatasourceDBEditor extends JSONtoForm<Props> {
|
|||
: undefined}
|
||||
<SaveButtonContainer>
|
||||
<ActionButton
|
||||
accent="error"
|
||||
buttonStyle="DANGER"
|
||||
buttonVariant="SOLID"
|
||||
// accent="error"
|
||||
className="t--delete-datasource"
|
||||
loading={isDeleting}
|
||||
onClick={() => handleDelete(datasourceId)}
|
||||
|
|
@ -196,7 +198,9 @@ class DatasourceDBEditor extends JSONtoForm<Props> {
|
|||
/>
|
||||
|
||||
<ActionButton
|
||||
accent="secondary"
|
||||
// accent="secondary"
|
||||
buttonStyle="PRIMARY"
|
||||
buttonVariant="OUTLINE"
|
||||
className="t--test-datasource"
|
||||
loading={isTesting}
|
||||
onClick={this.test}
|
||||
|
|
|
|||
|
|
@ -332,7 +332,9 @@ class DatasourceRestAPIEditor extends React.Component<Props> {
|
|||
return (
|
||||
<SaveButtonContainer>
|
||||
<ActionButton
|
||||
accent="error"
|
||||
// accent="error"
|
||||
buttonStyle="DANGER"
|
||||
buttonVariant="SOLID"
|
||||
className="t--delete-datasource"
|
||||
loading={isDeleting}
|
||||
onClick={() => deleteDatasource(datasourceId)}
|
||||
|
|
|
|||
|
|
@ -145,9 +145,8 @@ function DatasourceCard(props: DatasourceCardProps) {
|
|||
text="Edit Datasource"
|
||||
/>
|
||||
<ActionButton
|
||||
accent="primary"
|
||||
buttonStyle="PRIMARY"
|
||||
className="t--create-api"
|
||||
filled
|
||||
icon={"plus"}
|
||||
onClick={() => props.onCreate(datasource)}
|
||||
text="New API"
|
||||
|
|
|
|||
|
|
@ -180,7 +180,9 @@ class DatasourceSaaSEditor extends JSONtoForm<Props> {
|
|||
: null}
|
||||
<SaveButtonContainer>
|
||||
<ActionButton
|
||||
accent="error"
|
||||
// accent="error"
|
||||
buttonStyle="DANGER"
|
||||
buttonVariant="SOLID"
|
||||
className="t--delete-datasource"
|
||||
loading={isDeleting}
|
||||
onClick={() =>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,24 @@
|
|||
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 { WidgetType } from "constants/WidgetConstants";
|
||||
import ButtonComponent, {
|
||||
ButtonStyle,
|
||||
ButtonStyleTypes,
|
||||
ButtonType,
|
||||
ButtonVariant,
|
||||
} from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||
import { ValidationTypes } from "constants/WidgetValidation";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import withMeta, { WithMeta } from "./MetaHOC";
|
||||
import { ButtonBoxShadow } from "components/propertyControls/BoxShadowOptionsControl";
|
||||
import {
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
} from "components/propertyControls/BorderRadiusOptionsControl";
|
||||
|
||||
class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
|
||||
onButtonClickBound: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
|
|
@ -36,39 +47,6 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
|
|||
isTriggerProperty: false,
|
||||
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",
|
||||
propertyName: "tooltip",
|
||||
|
|
@ -135,9 +113,223 @@ 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> {
|
||||
return {
|
||||
recaptchaToken: undefined,
|
||||
|
|
@ -188,14 +380,22 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
|
|||
getPageView() {
|
||||
return (
|
||||
<ButtonComponent
|
||||
borderRadius={this.props.borderRadius}
|
||||
boxShadow={this.props.boxShadow}
|
||||
boxShadowColor={this.props.boxShadowColor}
|
||||
buttonColor={this.props.buttonColor}
|
||||
buttonStyle={this.props.buttonStyle}
|
||||
buttonVariant={this.props.buttonVariant}
|
||||
clickWithRecaptcha={this.clickWithRecaptchaBound}
|
||||
disabled={this.props.isDisabled}
|
||||
googleRecaptchaKey={this.props.googleRecaptchaKey}
|
||||
handleRecaptchaV2Loading={this.handleRecaptchaV2Loading}
|
||||
iconAlign={this.props.iconAlign}
|
||||
iconName={this.props.iconName}
|
||||
isDisabled={this.props.isDisabled}
|
||||
isLoading={this.props.isLoading || this.state.isLoading}
|
||||
key={this.props.widgetId}
|
||||
onClick={!this.props.isDisabled ? this.onButtonClickBound : undefined}
|
||||
prevButtonStyle={this.props.prevButtonStyle}
|
||||
recaptchaV2={this.props.recaptchaV2}
|
||||
text={this.props.text}
|
||||
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 {
|
||||
text?: string;
|
||||
buttonStyle?: ButtonStyle;
|
||||
onClick?: string;
|
||||
isDisabled?: boolean;
|
||||
isVisible?: boolean;
|
||||
recaptchaV2?: boolean;
|
||||
buttonType?: ButtonType;
|
||||
googleRecaptchaKey?: string;
|
||||
buttonStyle?: ButtonStyle;
|
||||
prevButtonStyle?: ButtonStyle;
|
||||
buttonVariant?: ButtonVariant;
|
||||
buttonColor?: string;
|
||||
borderRadius?: ButtonBorderRadius;
|
||||
boxShadow?: ButtonBoxShadow;
|
||||
boxShadowColor?: string;
|
||||
iconName?: IconName;
|
||||
iconAlign?: Alignment;
|
||||
}
|
||||
|
||||
interface ButtonWidgetState extends WidgetState {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from "react";
|
|||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||
import { WidgetType } from "constants/WidgetConstants";
|
||||
import ButtonComponent, {
|
||||
ButtonStyle,
|
||||
ButtonType,
|
||||
} from "components/designSystems/blueprint/ButtonComponent";
|
||||
import {
|
||||
|
|
@ -194,8 +195,8 @@ class FormButtonWidget extends BaseWidget<
|
|||
<ButtonComponent
|
||||
buttonStyle={this.props.buttonStyle}
|
||||
clickWithRecaptcha={this.clickWithRecaptchaBound}
|
||||
disabled={disabled}
|
||||
googleRecaptchaKey={this.props.googleRecaptchaKey}
|
||||
isDisabled={disabled}
|
||||
isLoading={this.props.isLoading || this.state.isLoading}
|
||||
key={this.props.widgetId}
|
||||
onClick={!disabled ? this.onButtonClickBound : undefined}
|
||||
|
|
@ -213,11 +214,11 @@ class FormButtonWidget extends BaseWidget<
|
|||
}
|
||||
}
|
||||
|
||||
export type ButtonStyle =
|
||||
| "PRIMARY_BUTTON"
|
||||
| "SECONDARY_BUTTON"
|
||||
| "SUCCESS_BUTTON"
|
||||
| "DANGER_BUTTON";
|
||||
// export type ButtonStyle =
|
||||
// | "PRIMARY_BUTTON"
|
||||
// | "SECONDARY_BUTTON"
|
||||
// | "SUCCESS_BUTTON"
|
||||
// | "DANGER_BUTTON";
|
||||
|
||||
export interface FormButtonWidgetProps extends WidgetProps, WithMeta {
|
||||
text?: string;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,14 @@ import { ValidationTypes } from "constants/WidgetValidation";
|
|||
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||
|
||||
import IconButtonComponent, {
|
||||
ButtonBorderRadius,
|
||||
ButtonBoxShadow,
|
||||
ButtonStyle,
|
||||
ButtonVariant,
|
||||
} from "components/designSystems/appsmith/IconButtonComponent";
|
||||
import {
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
} from "components/propertyControls/BorderRadiusOptionsControl";
|
||||
import { ButtonBoxShadow } from "components/propertyControls/BoxShadowOptionsControl";
|
||||
|
||||
export interface IconButtonWidgetProps extends WidgetProps {
|
||||
iconName?: IconName;
|
||||
|
|
@ -99,6 +102,11 @@ class IconButtonWidget extends BaseWidget<IconButtonWidgetProps, WidgetState> {
|
|||
helpText:
|
||||
"Rounds the corners of the icon button's outer border edge",
|
||||
controlType: "BORDER_RADIUS_OPTIONS",
|
||||
options: [
|
||||
ButtonBorderRadiusTypes.SHARP,
|
||||
ButtonBorderRadiusTypes.ROUNDED,
|
||||
ButtonBorderRadiusTypes.CIRCLE,
|
||||
],
|
||||
isBindProperty: false,
|
||||
isTriggerProperty: false,
|
||||
validation: {
|
||||
|
|
|
|||
|
|
@ -16890,9 +16890,10 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
|||
version "1.0.3"
|
||||
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"
|
||||
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:
|
||||
version "0.0.33"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user