From cb4242e7e5df0634547137f68ca0df79f5d4d1e9 Mon Sep 17 00:00:00 2001 From: Paul Li <82799722+wmdev0808@users.noreply.github.com> Date: Tue, 24 Aug 2021 09:53:15 -0400 Subject: [PATCH] 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 --- .../FormWidgets/Button_spec.js | 12 +- app/client/package.json | 2 +- .../appsmith/FilePickerComponent.tsx | 3 +- .../appsmith/IconButtonComponent.tsx | 25 +- .../blueprint/ButtonComponent.tsx | 525 +++++++++++++----- .../editorComponents/DropdownComponent.tsx | 30 +- .../form/fields/DynamicDropdownField.tsx | 3 - .../form/fields/KeyValueFieldArray.tsx | 2 - .../formControls/FilePickerControl.tsx | 3 +- .../BorderRadiusOptionsControl.tsx | 42 +- .../propertyControls/IconSelectControl.tsx | 2 +- app/client/src/constants/Colors.tsx | 3 + .../mockResponses/WidgetConfigResponse.tsx | 7 +- .../Editor/APIEditor/RapidApiEditorForm.tsx | 5 +- .../pages/Editor/DataSourceEditor/DBForm.tsx | 8 +- .../RestAPIDatasourceForm.tsx | 4 +- .../Editor/SaaSEditor/DatasourceCard.tsx | 3 +- .../Editor/SaaSEditor/DatasourceForm.tsx | 4 +- app/client/src/widgets/ButtonWidget.tsx | 286 ++++++++-- app/client/src/widgets/FormButtonWidget.tsx | 13 +- app/client/src/widgets/IconButtonWidget.tsx | 12 +- app/client/yarn.lock | 5 +- 22 files changed, 728 insertions(+), 271 deletions(-) diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Button_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Button_spec.js index 2d260dde24..8a2e23e436 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Button_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Button_spec.js @@ -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"); diff --git a/app/client/package.json b/app/client/package.json index 5ab6aa46c1..21dd4bc8df 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -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", diff --git a/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx b/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx index c7732b0ff0..011aa100be 100644 --- a/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx +++ b/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx @@ -29,9 +29,8 @@ class FilePickerComponent extends React.Component< } return ( { - 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` - 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 = { - primary: "primaryOld", - secondary: "secondaryOld", - error: "error", - grey: "dropdownGreyBg", -}; - -const ButtonWrapper = styled((props: ButtonStyleProps & IButtonProps) => ( -