diff --git a/app/client/.storybook/addons.js b/app/client/.storybook/addons.js deleted file mode 100644 index 0503703e342a..000000000000 --- a/app/client/.storybook/addons.js +++ /dev/null @@ -1,6 +0,0 @@ -import "@storybook/addon-knobs/register"; -import "@storybook/addon-notes/register"; -import "@storybook/addon-contexts/register"; -import "storybook-addon-designs/register"; -import '@storybook/addon-backgrounds/register'; -import '@storybook/addon-actions/register'; \ No newline at end of file diff --git a/app/client/.storybook/config.js b/app/client/.storybook/config.js deleted file mode 100644 index 5fea97567787..000000000000 --- a/app/client/.storybook/config.js +++ /dev/null @@ -1,15 +0,0 @@ -import { configure, addDecorator, addParameters } from "@storybook/react"; -import { withContexts } from "@storybook/addon-contexts/react"; -import { contexts } from "./configs/contexts"; -import { } from '@storybook/react'; // <- or your storybook framework -import "../src/index.css"; - - -addDecorator(withContexts(contexts)); -addParameters({ - backgrounds: [ - { name: 'dark', value: '#090707', default: true }, - { name: 'light', value: '#fff' }, - ], -}); -configure(require.context("../src", true, /\.stories\.tsx$/), module); diff --git a/app/client/.storybook/configs/contexts.js b/app/client/.storybook/configs/contexts.js deleted file mode 100644 index 00c5acb54878..000000000000 --- a/app/client/.storybook/configs/contexts.js +++ /dev/null @@ -1,36 +0,0 @@ -import { ThemeProvider, theme } from "../../src/constants/DefaultTheme"; -import { light, dark } from "constants/DefaultTheme"; - -export const contexts = [ - { - icon: "box", - title: "Themes", - components: [ThemeProvider], - params: [ - { - name: "lightTheme", - props: { - theme: { - ...theme, - colors: { - ...theme.colors, - ...light, - }, - }, - }, - }, - { - name: "darkTheme", - props: { - theme: { - ...theme, - colors: { - ...theme.colors, - ...dark, - }, - }, - }, - }, - ], - }, -]; diff --git a/app/client/.storybook/configs/index.js b/app/client/.storybook/configs/index.js new file mode 100644 index 000000000000..3ac45490619f --- /dev/null +++ b/app/client/.storybook/configs/index.js @@ -0,0 +1,6 @@ +import { ThemeProvider, theme } from "../../src/constants/DefaultTheme"; +import { light } from "constants/DefaultTheme"; + +const DefaultTheme = { ...theme, colors: { ...theme.colors, ...light } }; + +export { DefaultTheme, ThemeProvider } \ No newline at end of file diff --git a/app/client/.storybook/main.js b/app/client/.storybook/main.js new file mode 100644 index 000000000000..df0e90c3e302 --- /dev/null +++ b/app/client/.storybook/main.js @@ -0,0 +1,12 @@ +module.exports = { + "stories": [ + "../src/**/*.stories.mdx", + "../src/**/*.stories.@(js|jsx|ts|tsx)" + ], + "addons": [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/preset-create-react-app", + "@etchteam/storybook-addon-status", + ] +} \ No newline at end of file diff --git a/app/client/.storybook/presets.js b/app/client/.storybook/presets.js deleted file mode 100644 index c2b5e265efa8..000000000000 --- a/app/client/.storybook/presets.js +++ /dev/null @@ -1,18 +0,0 @@ -const path = require("path"); -module.exports = [ - { - name: "@storybook/preset-create-react-app", - options: { - tsDocgenLoaderOptions: { - tsconfigPath: path.resolve(__dirname, "../tsconfig.json") - } - } - }, - { - name: "@storybook/addon-docs/preset", - options: { - configureJSX: true, - sourceLoaderOptions: null - } - } -]; diff --git a/app/client/.storybook/preview-body.html b/app/client/.storybook/preview-body.html new file mode 100644 index 000000000000..734e83ba2ea0 --- /dev/null +++ b/app/client/.storybook/preview-body.html @@ -0,0 +1,72 @@ + +
\ No newline at end of file diff --git a/app/client/.storybook/preview.js b/app/client/.storybook/preview.js new file mode 100644 index 000000000000..3549f92a5fe8 --- /dev/null +++ b/app/client/.storybook/preview.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { DefaultTheme, ThemeProvider } from "./configs"; +import store from "../src/store"; +import { Provider } from "react-redux"; +import GlobalStyles from "../src/globalStyles/index"; +import "../src/index.css"; + +export const parameters = { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +} + +export const decorators = [ + (Story) => ( + + + + + + + ), +]; \ No newline at end of file diff --git a/app/client/package.json b/app/client/package.json index a3077ce3a8b6..4a91442e36cd 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -171,16 +171,26 @@ "cytest": "REACT_APP_TESTING=TESTING REACT_APP_ENVIRONMENT=DEVELOPMENT craco start & ./node_modules/.bin/cypress open", "test:unit": "$(npm bin)/jest -b --colors --no-cache --coverage --collectCoverage=true --coverageDirectory='../../' --coverageReporters='json-summary'", "test:jest": "$(npm bin)/jest --watch", - "storybook": "start-storybook -p 9009 -s public", - "build-storybook": "build-storybook -s public", - "postinstall": "patch-package" + "postinstall": "patch-package", + "storybook": "start-storybook -p 6006 -s public", + "build-storybook": "build-storybook -s public" }, "resolution": { "jest": "24.8.0" }, "eslintConfig": { "extends": "react-app", - "parser": "@typescript-eslint/parser" + "parser": "@typescript-eslint/parser", + "overrides": [ + { + "files": [ + "**/*.stories.*" + ], + "rules": { + "import/no-anonymous-default-export": "off" + } + } + ] }, "browserslist": [ ">0.2%", @@ -190,16 +200,14 @@ ], "devDependencies": { "@babel/core": "^7.7.4", - "@storybook/addon-actions": "^5.3.19", - "@storybook/addon-backgrounds": "^5.3.19", - "@storybook/addon-contexts": "^5.3.19", - "@storybook/addon-docs": "^5.3.19", - "@storybook/addon-knobs": "^5.3.19", - "@storybook/addon-links": "^5.3.19", - "@storybook/addon-notes": "^5.3.19", - "@storybook/addons": "^5.3.19", - "@storybook/preset-create-react-app": "^3.1.4", - "@storybook/react": "^5.3.19", + "@etchteam/storybook-addon-status": "^4.0.0", + "@storybook/addon-actions": "^6.3.7", + "@storybook/addon-essentials": "^6.3.7", + "@storybook/addon-knobs": "^6.3.0", + "@storybook/addon-links": "^6.3.7", + "@storybook/node-logger": "^6.3.7", + "@storybook/preset-create-react-app": "^3.2.0", + "@storybook/react": "^6.3.7", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.2.6", "@testing-library/user-event": "^13.1.1", @@ -260,7 +268,7 @@ "redux-devtools": "^3.5.0", "redux-devtools-extension": "^2.13.8", "redux-mock-store": "^1.5.4", - "storybook-addon-designs": "^5.4.0", + "storybook-addon-designs": "^6.0.1", "ts-jest": "^26.5.4", "webpack-merge": "^4.2.2", "workbox-webpack-plugin": "^5.1.2" diff --git a/app/client/src/components/ads/Button.tsx b/app/client/src/components/ads/Button.tsx index ba0d1107dc12..fa996e18b919 100644 --- a/app/client/src/components/ads/Button.tsx +++ b/app/client/src/components/ads/Button.tsx @@ -49,7 +49,7 @@ type BtnFontType = { height: number; }; -type ButtonProps = CommonComponentProps & { +export type ButtonProps = CommonComponentProps & { onClick?: (event: React.MouseEvent) => void; text?: string; category?: Category; diff --git a/app/client/src/components/ads/Callout.tsx b/app/client/src/components/ads/Callout.tsx index 9e57b0e2578d..517b8553725d 100644 --- a/app/client/src/components/ads/Callout.tsx +++ b/app/client/src/components/ads/Callout.tsx @@ -5,7 +5,7 @@ import Icon, { IconSize } from "./Icon"; import { Colors } from "constants/Colors"; import Text, { TextType } from "./Text"; -type CalloutProps = CommonComponentProps & { +export type CalloutProps = CommonComponentProps & { variant?: Variant; fill?: boolean; closeButton?: boolean; diff --git a/app/client/src/components/ads/Checkbox.tsx b/app/client/src/components/ads/Checkbox.tsx index c9041b0aef98..6a90affe3b8a 100644 --- a/app/client/src/components/ads/Checkbox.tsx +++ b/app/client/src/components/ads/Checkbox.tsx @@ -28,13 +28,17 @@ const Checkmark = styled.span<{ ? props.disabled ? props.theme.colors.checkbox.disabled : props.backgroundColor || props.theme.colors.info.main + : props.disabled + ? props.theme.colors.checkbox.disabled : "transparent"}; - border: 2px solid + border: 1.8px solid ${(props) => props.isChecked ? props.disabled ? props.theme.colors.checkbox.disabled : props.backgroundColor || props.theme.colors.info.main + : props.disabled + ? props.theme.colors.checkbox.disabled : props.theme.colors.checkbox.unchecked}; &::after { diff --git a/app/client/src/components/ads/ColorSelector.tsx b/app/client/src/components/ads/ColorSelector.tsx index 3a7ee9650474..2870bf77b049 100644 --- a/app/client/src/components/ads/ColorSelector.tsx +++ b/app/client/src/components/ads/ColorSelector.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import styled from "styled-components"; import { CommonComponentProps } from "./common"; -type ColorSelectorProps = CommonComponentProps & { +export type ColorSelectorProps = CommonComponentProps & { onSelect?: (hex: string) => void; colorPalette: string[]; fill?: boolean; diff --git a/app/client/src/components/ads/Dropdown.tsx b/app/client/src/components/ads/Dropdown.tsx index 40b1ab403f32..6aab0ddbc479 100644 --- a/app/client/src/components/ads/Dropdown.tsx +++ b/app/client/src/components/ads/Dropdown.tsx @@ -66,6 +66,7 @@ export type DropdownProps = CommonComponentProps & renderOption?: RenderOption; isLoading?: boolean; errorMsg?: string; // If errorMsg is defined, we show dropDown's error state with the message. + placeholder?: string; helperText?: string; }; export interface DefaultDropDownValueNodeProps { @@ -74,6 +75,8 @@ export interface DefaultDropDownValueNodeProps { isOpen?: boolean; errorMsg?: string; renderNode?: RenderOption; + placeholder?: string; + showDropIcon?: boolean; } export interface RenderDropdownOptionType { @@ -81,8 +84,9 @@ export interface RenderDropdownOptionType { optionClickHandler?: (dropdownOption: DropdownOption) => void; } -export const DropdownContainer = styled.div<{ width: string }>` +export const DropdownContainer = styled.div<{ width: string; height?: string }>` width: ${(props) => props.width}; + height: ${(props) => props.height || `36px`}; position: relative; `; @@ -111,6 +115,7 @@ const Selected = styled.div<{ height: string; bgColor?: string; hasError?: boolean; + selected?: boolean; isLoading?: boolean; }>` padding: ${(props) => props.theme.spaces[2]}px @@ -123,9 +128,11 @@ const Selected = styled.div<{ } return !!props.bgColor ? props.bgColor - : props.theme.colors.dropdown.header.bg; + : props.selected + ? props.theme.colors.dropdown.header.bg + : props.theme.colors.dropdown.header.defaultBg; }}; - + box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; @@ -134,7 +141,15 @@ const Selected = styled.div<{ cursor: ${(props) => props.disabled || props.isLoading ? "not-allowed" : "pointer"}; ${(props) => - props.isOpen + props.hasError + ? `.sub-text { + color: ${props.theme.colors.danger.main} !important; + }` + : ""} + ${(props) => + props.hasError + ? `border: 1px solid ${props.theme.colors.danger.main}` + : props.isOpen ? `border: 1px solid ${ !!props.bgColor ? props.bgColor : props.theme.colors.info.main }` @@ -146,9 +161,7 @@ const Selected = styled.div<{ : props.theme.colors.dropdown.header.bg }`}; ${(props) => - props.isOpen && !props.disabled ? "box-sizing: border-box" : null}; - ${(props) => - props.isOpen && !props.disabled && !props.bgColor + props.isOpen && !props.disabled && !props.bgColor && !props.hasError ? "box-shadow: 0px 0px 4px 4px rgba(203, 72, 16, 0.18)" : null}; .${Classes.TEXT} { @@ -162,9 +175,17 @@ const Selected = styled.div<{ : `color: ${ !!props.bgColor ? Colors.WHITE + : props.selected + ? props.theme.colors.dropdown.selected.text : props.theme.colors.dropdown.header.text }`}; } + &:hover { + background: ${(props) => + props.hasError + ? Colors.FAIR_PINK + : props.theme.colors.dropdown.hovered.bg}; + } `; const DropdownSelect = styled.div``; @@ -173,8 +194,10 @@ export const DropdownWrapper = styled.div<{ width: string; }>` width: ${(props) => props.width}; + height: fit-content; z-index: 1; - background-color: ${(props) => props.theme.colors.propertyPane.radioGroupBg}; + background-color: ${(props) => props.theme.colors.dropdown.menuBg}; + box-shadow: ${(props) => props.theme.colors.dropdown.menuShadow}; margin-top: ${(props) => -props.theme.spaces[3]}px; padding: ${(props) => props.theme.spaces[3]}px 0; .dropdown-search { @@ -213,7 +236,10 @@ const OptionWrapper = styled.div<{ } .${Classes.TEXT} { - color: ${(props) => props.theme.colors.propertyPane.label}; + color: ${(props) => + props.selected + ? props.theme.colors.dropdown.menu.hoverText + : props.theme.colors.dropdown.menu.text}; } .${Classes.ICON} { @@ -229,7 +255,7 @@ const OptionWrapper = styled.div<{ } &:hover { - background-color: ${(props) => props.theme.colors.dropdown.hovered.bg}; + background-color: ${(props) => props.theme.colors.dropdown.menu.hover}; &&& svg { rect { @@ -238,7 +264,7 @@ const OptionWrapper = styled.div<{ } .${Classes.TEXT} { - color: ${(props) => props.theme.colors.textOnDarkBG}; + color: ${(props) => props.theme.colors.dropdown.menu.hoverText}; } .${Classes.ICON} { @@ -265,10 +291,17 @@ const LabelWrapper = styled.div<{ label?: string }>` } `; -const StyledSubText = styled(Text)` +const StyledSubText = styled(Text)<{ + showDropIcon?: boolean; +}>` margin-left: auto; && { - color: ${(props) => props.theme.colors.apiPane.body.text}; + color: ${(props) => props.theme.colors.dropdown.menu.subText}; + } + &.sub-text { + color: ${(props) => props.theme.colors.dropdown.selected.subtext}; + position: absolute; + right: ${(props) => (props.showDropIcon ? "39px" : "12px")}; } `; @@ -318,6 +351,27 @@ const SelectedIcon = styled(Icon)` } } } + + svg { + path { + fill: ${(props) => + props.fillColor + ? props.fillColor + : props.theme.colors.dropdown.selected.icon}; + } + } +`; + +const DropdownIcon = styled(Icon)` + margin-right: 7px; + svg { + path { + fill: ${(props) => + props.fillColor + ? props.fillColor + : props.theme.colors.dropdown.icon} !important; + } + } `; const ErrorMsg = styled.span` @@ -326,6 +380,12 @@ const ErrorMsg = styled.span` margin-top: ${(props) => props.theme.spaces[3]}px; `; +const HelperMsg = styled.span` + ${(props) => getTypographyByKey(props, "p3")}; + color: ${(props) => props.theme.colors.dropdown.menu.subText}; + margin: 6px 0px 10px; +`; + const ErrorLabel = styled.span` ${(props) => getTypographyByKey(props, "p1")}; color: ${Colors.POMEGRANATE2}; @@ -339,11 +399,19 @@ const HelperText = styled.span` function DefaultDropDownValueNode({ errorMsg, + placeholder, renderNode, selected, + showDropIcon, showLabelOnly, }: DefaultDropDownValueNodeProps) { - const LabelText = showLabelOnly ? selected.label : selected.value; + const LabelText = selected + ? showLabelOnly + ? selected.label + : selected.value + : placeholder + ? placeholder + : "Please select a option."; function Label() { return errorMsg ? ( {LabelText} @@ -358,15 +426,26 @@ function DefaultDropDownValueNode({ renderNode({ isSelectedNode: true, option: selected, errorMsg }) ) : ( <> - {selected.icon ? ( + {selected?.icon ? ( ) : null}