feat: WDS icon button widget integration (#27928)

## Description
Adds WDSIconButton Widget.

#### PR fixes following issue(s)
Fixes #27538
> if no issue exists, please create an issue and ask the maintainers
about this first
>
>
#### Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video
>
>
#### Type of change
> Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update
>
>
>
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed

---------

Co-authored-by: Pawan Kumar <pawan.stardust@gmail.com>
This commit is contained in:
Dhruvik Neharia 2023-10-23 21:51:20 +05:30 committed by GitHub
parent 8b5269fef1
commit 3ea74ec78e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 368 additions and 0 deletions

View File

@ -2,6 +2,7 @@ export const WDS_V2_WIDGET_MAP = {
BUTTON_WIDGET: "WDS_BUTTON_WIDGET",
INPUT_WIDGET_V2: "WDS_INPUT_WIDGET",
CHECKBOX_WIDGET: "WDS_CHECKBOX_WIDGET",
ICON_BUTTON_WIDGET: "WDS_ICON_BUTTON_WIDGET",
TEXT_WIDGET: "WDS_TEXT_WIDGET",
TABLE_WIDGET_V2: "WDS_TABLE_WIDGET",
};

View File

@ -60,6 +60,7 @@ import ListWidgetV2 from "./ListWidgetV2";
import { WDSButtonWidget } from "./wds/WDSButtonWidget";
import { WDSInputWidget } from "./wds/WDSInputWidget";
import { WDSCheckboxWidget } from "./wds/WDSCheckboxWidget";
import { WDSIconButtonWidget } from "./wds/WDSIconButtonWidget";
import { WDSTextWidget } from "./wds/WDSTextWidget";
import type BaseWidget from "./BaseWidget";
import { WDSTableWidget } from "./wds/WDSTableWidget";
@ -117,6 +118,7 @@ const Widgets = [
WDSButtonWidget,
WDSInputWidget,
WDSCheckboxWidget,
WDSIconButtonWidget,
WDSTextWidget,
WDSTableWidget,

View File

@ -0,0 +1,19 @@
import React from "react";
import { Icon as BIcon } from "@blueprintjs/core";
import { IconButton, Tooltip } from "@design-system/widgets";
import type { IconButtonComponentProps } from "./types";
export const IconButtonComponent = (props: IconButtonComponentProps) => {
const { iconName, tooltip, ...rest } = props;
const icon =
iconName &&
(() => {
return <BIcon icon={iconName} />;
});
return (
<Tooltip tooltip={tooltip}>
<IconButton icon={icon} {...rest} />
</Tooltip>
);
};

View File

@ -0,0 +1,16 @@
import type { IconName } from "@blueprintjs/icons";
import type { IconButtonProps } from "@design-system/widgets";
export interface IconButtonComponentProps {
tooltip?: string;
visuallyDisabled?: boolean;
isLoading: boolean;
iconName?: IconName;
isDisabled?: boolean;
variant?: IconButtonProps["variant"];
color?: IconButtonProps["color"];
onPress?: IconButtonProps["onPress"];
minWidth?: number;
maxWidth?: number;
minHeight?: number;
}

View File

@ -0,0 +1,8 @@
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
export const autocompleteConfig = {
"!doc":
"Icon button widget is just an icon, along with all other button properties.",
"!url": "https://docs.appsmith.com/widget-reference/icon-button",
isVisible: DefaultAutocompleteDefinitions.isVisible,
};

View File

@ -0,0 +1,19 @@
import { BUTTON_VARIANTS, COLORS } from "@design-system/widgets";
import { IconNames } from "@blueprintjs/icons";
import { ResponsiveBehavior } from "layoutSystems/common/utils/constants";
import { ICON_BUTTON_MIN_WIDTH } from "constants/minWidthConstants";
export const defaultsConfig = {
iconName: IconNames.PLUS,
buttonVariant: BUTTON_VARIANTS.filled,
buttonColor: COLORS.accent,
isDisabled: false,
isVisible: true,
rows: 4,
columns: 4,
widgetName: "IconButton",
version: 1,
animateLoading: true,
responsiveBehavior: ResponsiveBehavior.Hug,
minWidth: ICON_BUTTON_MIN_WIDTH,
};

View File

@ -0,0 +1,5 @@
export * from "./propertyPaneConfig";
export { autocompleteConfig } from "./autocompleteConfig";
export { defaultsConfig } from "./defaultsConfig";
export { metaConfig } from "./metaConfig";
export { settersConfig } from "./settersConfig";

View File

@ -0,0 +1,9 @@
import IconSVG from "../icon.svg";
import { WIDGET_TAGS } from "constants/WidgetConstants";
export const metaConfig = {
name: "Icon button",
iconSVG: IconSVG,
tags: [WIDGET_TAGS.BUTTONS],
searchTags: ["click", "submit"],
};

View File

@ -0,0 +1,87 @@
import { ValidationTypes } from "constants/WidgetValidation";
import { IconNames } from "@blueprintjs/icons";
const ICON_NAMES = Object.keys(IconNames).map(
(name: string) => IconNames[name as keyof typeof IconNames],
);
export const propertyPaneContentConfig = [
{
sectionName: "Basic",
children: [
{
propertyName: "iconName",
label: "Icon",
helpText: "Sets the icon to be used for the icon button",
controlType: "ICON_SELECT",
defaultIconName: "plus",
hideNoneIcon: true,
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: ICON_NAMES,
default: IconNames.PLUS,
},
},
},
{
helpText: "when the button is clicked",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
{
sectionName: "General",
children: [
{
helpText: "Show helper text with button on hover",
propertyName: "tooltip",
label: "Tooltip",
controlType: "INPUT_TEXT",
placeholderText: "Add Input Field",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "isVisible",
helpText: "Controls the visibility of the widget",
label: "Visible",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
helpText: "Disables input to the widget",
label: "Disabled",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "animateLoading",
label: "Animate loading",
controlType: "SWITCH",
helpText: "Controls the loading of the widget",
defaultValue: true,
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
];

View File

@ -0,0 +1,2 @@
export { propertyPaneContentConfig } from "./contentConfig";
export { propertyPaneStyleConfig } from "./styleConfig";

View File

@ -0,0 +1,53 @@
import { capitalize } from "lodash";
import { BUTTON_VARIANTS, COLORS } from "@design-system/widgets";
import { ValidationTypes } from "constants/WidgetValidation";
export const propertyPaneStyleConfig = [
{
sectionName: "General",
children: [
{
propertyName: "buttonVariant",
label: "Button variant",
controlType: "ICON_TABS",
fullWidth: true,
helpText: "Sets the variant of the button",
options: Object.values(BUTTON_VARIANTS).map((variant) => ({
label: capitalize(variant),
value: variant,
})),
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: Object.values(BUTTON_VARIANTS),
default: BUTTON_VARIANTS.filled,
},
},
},
{
propertyName: "buttonColor",
label: "Button color",
controlType: "DROP_DOWN",
fullWidth: true,
helpText: "Sets the semantic color of the button",
options: Object.values(COLORS).map((semantic) => ({
label: capitalize(semantic),
value: semantic,
})),
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
allowedValues: Object.values(COLORS),
default: COLORS.accent,
},
},
},
],
},
];

View File

@ -0,0 +1,12 @@
export const settersConfig = {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 23.0001C18.0751 23.0001 23 18.0752 23 12.0001C23 5.92494 18.0751 1.00006 12 1.00006C5.92487 1.00006 1 5.92494 1 12.0001C1 18.0752 5.92487 23.0001 12 23.0001ZM13.0001 11V6.50007H11V11H6.00001V13.0001H11V18.0001H13.0001V13.0001H17.5001V11H13.0001Z" fill="#4C5664"/>
</svg>

After

Width:  |  Height:  |  Size: 420 B

View File

@ -0,0 +1,3 @@
import { WDSIconButtonWidget } from "./widget";
export { WDSIconButtonWidget };

View File

@ -0,0 +1,113 @@
import React from "react";
import type { SetterConfig } from "entities/AppTheming";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import BaseWidget from "widgets/BaseWidget";
import {
metaConfig,
defaultsConfig,
autocompleteConfig,
propertyPaneContentConfig,
propertyPaneStyleConfig,
settersConfig,
} from "./../config";
import type { IconButtonWidgetProps, IconButtonWidgetState } from "./types";
import { IconButtonComponent } from "../component";
class WDSIconButtonWidget extends BaseWidget<
IconButtonWidgetProps,
IconButtonWidgetState
> {
constructor(props: IconButtonWidgetProps) {
super(props);
this.state = {
isLoading: false,
};
}
static type = "WDS_ICON_BUTTON_WIDGET";
static getConfig() {
return metaConfig;
}
static getDefaults() {
return defaultsConfig;
}
static getAutoLayoutConfig() {
return {};
}
static getAutocompleteDefinitions() {
return autocompleteConfig;
}
static getPropertyPaneContentConfig() {
return propertyPaneContentConfig;
}
static getPropertyPaneStyleConfig() {
return propertyPaneStyleConfig;
}
static getSetterConfig(): SetterConfig {
return settersConfig;
}
hasOnClickAction = () => {
const { isDisabled, onClick } = this.props;
return Boolean(onClick && !isDisabled);
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
onButtonClick = () => {
const { onClick } = this.props;
if (onClick) {
this.setState({ isLoading: true });
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
return;
}
};
getWidgetView() {
const onPress = (() => {
if (this.hasOnClickAction()) {
return this.onButtonClick;
}
return undefined;
})();
return (
<IconButtonComponent
color={this.props.buttonColor}
iconName={this.props.iconName}
isDisabled={this.props.isDisabled}
isLoading={this.state.isLoading}
key={this.props.widgetId}
onPress={onPress}
tooltip={this.props.tooltip}
variant={this.props.buttonVariant}
/>
);
}
}
export { WDSIconButtonWidget };

View File

@ -0,0 +1,16 @@
import type { IconButtonProps } from "@design-system/widgets";
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
import type { IconName } from "@blueprintjs/icons";
export interface IconButtonWidgetProps extends WidgetProps {
iconName: IconName;
buttonColor: IconButtonProps["color"];
buttonVariant: IconButtonProps["variant"];
isDisabled: boolean;
isVisible: boolean;
onClick?: string;
}
export interface IconButtonWidgetState extends WidgetState {
isLoading: boolean;
}