Skip to content

Commit

Permalink
feat(Buttons)!: Introduce ButtonPrimitive, implementing planned break…
Browse files Browse the repository at this point in the history
…ing changes (#1522)

Refactored Button and ButtonLink to ButtonPrimitive to share common DOM structure, functionality and properties.

BREAKING CHANGE:
removing unsafe className (deprecated, not public API)
removing icon property (deprecated)
changing type of width to string (planned)
  • Loading branch information
mainframev committed Apr 23, 2020
1 parent 6432a83 commit ca4a641
Show file tree
Hide file tree
Showing 94 changed files with 1,522 additions and 1,329 deletions.
2 changes: 1 addition & 1 deletion src/Alert/index.js
Expand Up @@ -234,7 +234,7 @@ const AlertCloseButton = ({ hasChildren, dataTest, onClick, icon }) => {
dataTest={dataTest}
onClick={onClick}
size="small"
icon={icon}
iconLeft={icon}
type="secondary"
transparent
title={translate("button_close")}
Expand Down
2 changes: 1 addition & 1 deletion src/Button/Button.stories.js
Expand Up @@ -306,7 +306,7 @@ storiesOf("Button", module)
"RTL",
() => (
<RenderInRtl>
<Button type="info" icon={<Icons.Airplane />}>
<Button type="info" iconLeft={<Icons.Airplane />}>
Button
</Button>
</RenderInRtl>
Expand Down
3 changes: 1 addition & 2 deletions src/Button/README.md
Expand Up @@ -29,7 +29,6 @@ Table below contains all types of the props available in Button component.
| disabled | `boolean` | `false` | If `true`, the Button will be disabled. |
| external | `boolean` | `false` | If `true`, the Button opens link in a new tab. [See Functional specs](#functional-specs) |
| href | `string` | | The URL of the link to open when Button is clicked. [See Functional specs](#functional-specs) |
| icon | `React.Node` | | The displayed icon (will be removed in the future, use iconLeft instead). |
| iconLeft | `React.Node` | | The displayed icon on the left. |
| iconRight | `React.Node` | | The displayed icon on the right. |
| loading | `boolean` | `false` | If `true`, the loading glyph will be displayed. |
Expand All @@ -42,7 +41,7 @@ Table below contains all types of the props available in Button component.
| tabIndex | `string` | | Specifies the tab order of an element. |
| title | `string` | | Adds `aria-label`. |
| **type** | [`enum`](#enum) | `"primary"` | The type of Button. |
| width | `number` | `0` | The width of the Button. Number is defined in `px`. |
| width | `string` | | The width of the Button. Can be any string - `100px`, `20%`. |

### enum

Expand Down
103 changes: 0 additions & 103 deletions src/Button/__tests__/index.test.js

This file was deleted.

8 changes: 0 additions & 8 deletions src/Button/consts.js
Expand Up @@ -27,7 +27,6 @@ export const TOKENS = {
paddingButtonWithIcons: "paddingButtonWithIcons",
paddingButtonWithLeftIcon: "paddingButtonWithLeftIcon",
paddingButtonWithRightIcon: "paddingButtonWithRightIcon",
marginRightIcon: "marginRightIcon",
// Type tokens
backgroundButton: "backgroundButton",
backgroundButtonHover: "backgroundButtonHover",
Expand All @@ -47,10 +46,3 @@ export const TOKENS = {
borderColorButtonActive: "borderColorButtonActive",
borderColorButtonFocus: "borderColorButtonFocus",
};

export const BUTTON_STATES = {
DEFAULT: "default",
HOVER: "hover",
ACTIVE: "active",
FOCUS: "focus",
};
56 changes: 18 additions & 38 deletions src/Button/helpers/getButtonBoxShadow.js
@@ -1,9 +1,9 @@
// @flow
import { css } from "styled-components";
import convertHexToRgba from "@kiwicom/orbit-design-tokens/lib/convertHexToRgba";

import { TOKENS, TYPE_OPTIONS, BUTTON_STATES } from "../consts";
import getTypeToken from "./getTypeToken";
import { TOKENS, TYPE_OPTIONS } from "../consts";
import { BUTTON_STATES } from "../../primitives/ButtonPrimitive/common/consts";
import getButtonTypeToken from "./getButtonTypeToken";
import type { GetButtonBoxShadow } from "./getButtonBoxShadow";

const opacity = {
Expand Down Expand Up @@ -31,52 +31,32 @@ const opacity = {
},
};

const getButtonBoxShadow: GetButtonBoxShadow = state => ({ disabled, bordered, theme, type }) => {
const getButtonBoxShadow: GetButtonBoxShadow = (state, disabled, bordered, theme, type) => {
const wrappedButtonTypeToken = name => getButtonTypeToken(name, type, theme);
if (disabled) {
return null;
}
if (state === BUTTON_STATES.DEFAULT && bordered) {
return css`
box-shadow: inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButton)};
`;
return `inset 0 0 0 1px ${wrappedButtonTypeToken(TOKENS.borderColorButton)}`;
}
if (state === BUTTON_STATES.HOVER && bordered) {
return css`
box-shadow: inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButtonHover)};
`;
return `inset 0 0 0 1px ${wrappedButtonTypeToken(TOKENS.borderColorButtonHover)}`;
}
if (state === BUTTON_STATES.ACTIVE) {
if (bordered) {
return css`
box-shadow: inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButtonActive)},
inset 0 0 6px 3px
${convertHexToRgba(theme.orbit.paletteInkNormal, opacity.bordered[type])}; // TODO: Create token
`;
return `inset 0 0 0 1px ${wrappedButtonTypeToken(TOKENS.borderColorButtonActive)},
inset 0 0 6px 3px ${convertHexToRgba(
theme.orbit.paletteInkNormal,
opacity.bordered[type],
)}`;
}
return css`
box-shadow: inset 0 0 6px 3px
${convertHexToRgba(theme.orbit.paletteInkNormal, opacity.default[type])}; // TODO: Create token
`;
return `inset 0 0 6px 3px ${convertHexToRgba(
theme.orbit.paletteInkNormal,
opacity.default[type],
)};`;
}
if (state === BUTTON_STATES.FOCUS) {
return css`
${!bordered &&
css`
box-shadow: 0 0 0 3px ${getTypeToken(TOKENS.borderColorButtonFocus)};
`}
&:active {
${bordered
? css`
box-shadow: inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButtonActive)},
inset 0 0 6px 3px
${convertHexToRgba(theme.orbit.paletteInkNormal, opacity.bordered[type])}; // TODO: create token
`
: css`
box-shadow: inset 0 0 6px 3px
${convertHexToRgba(theme.orbit.paletteInkNormal, opacity.default[type])}; // TODO: create token
`};
}
`;
if (state === BUTTON_STATES.FOCUS && !bordered) {
return `0 0 0 3px ${wrappedButtonTypeToken(TOKENS.borderColorButtonFocus)}`;
}
return null;
};
Expand Down
12 changes: 7 additions & 5 deletions src/Button/helpers/getButtonBoxShadow.js.flow
@@ -1,13 +1,15 @@
// @flow
import type { Interpolation } from "styled-components";

import type { Props, Type } from "../index";
import type { ThemeProps } from "../../defaultTheme";
import type { Type } from "../index";
import type { Theme } from "../../defaultTheme";

type State = "default" | "focus" | "active" | "hover";

export type GetButtonBoxShadow = (
state: State,
) => ({ ...Props, type: Type, ...ThemeProps }) => ?(Interpolation[]);
disabled: boolean,
bordered: boolean,
theme: Theme,
type: Type,
) => ?string;

declare export default GetButtonBoxShadow;
22 changes: 22 additions & 0 deletions src/Button/helpers/getButtonIconForeground.js
@@ -0,0 +1,22 @@
// @flow
import { TOKENS } from "../consts";
import getButtonTypeToken from "./getButtonTypeToken";
import type { GetButtonIconForeground } from "./getButtonIconForeground";

const getButtonIconForeground: GetButtonIconForeground = ({ bordered, theme, type }) => {
const wrappedTypeToken = name => getButtonTypeToken(name, type, theme);
if (bordered) {
return {
foreground: wrappedTypeToken(TOKENS.colorTextButtonBordered),
foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonBorderedHover),
foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonBorderedActive),
};
}
return {
foreground: wrappedTypeToken(TOKENS.colorTextButton),
foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonHover),
foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonActive),
};
};

export default getButtonIconForeground;
12 changes: 12 additions & 0 deletions src/Button/helpers/getButtonIconForeground.js.flow
@@ -0,0 +1,12 @@
// @flow
import type { ThemeProps } from "../../defaultTheme";
import type { Type } from "../index";
import type { IconForeground } from "../../primitives/ButtonPrimitive";

export type GetButtonIconForeground = ({
bordered: boolean,
type: Type,
...ThemeProps,
}) => IconForeground;

declare export default GetButtonIconForeground;
12 changes: 0 additions & 12 deletions src/Button/helpers/getButtonSpacing.js.flow

This file was deleted.

41 changes: 41 additions & 0 deletions src/Button/helpers/getButtonStyles.js
@@ -0,0 +1,41 @@
// @flow
import { BUTTON_STATES } from "../../primitives/ButtonPrimitive/common/consts";
import getButtonTypeToken from "./getButtonTypeToken";
import { TOKENS } from "../consts";
import getButtonBoxShadow from "./getButtonBoxShadow";
import type { GetButtonStyles } from "./getButtonStyles";

const getButtonStyles: GetButtonStyles = ({ disabled, bordered, theme, type }) => {
const wrappedBoxShadow = state => getButtonBoxShadow(state, disabled, bordered, theme, type);
const wrappedTypeToken = name => getButtonTypeToken(name, type, theme);
const boxShadow = {
boxShadow: wrappedBoxShadow(BUTTON_STATES.DEFAULT),
boxShadowHover: wrappedBoxShadow(BUTTON_STATES.HOVER),
boxShadowActive: wrappedBoxShadow(BUTTON_STATES.ACTIVE),
boxShadowFocus: wrappedBoxShadow(BUTTON_STATES.FOCUS),
};
if (bordered) {
return {
background: wrappedTypeToken(TOKENS.backgroundButtonBordered),
backgroundHover: wrappedTypeToken(TOKENS.backgroundButtonBorderedHover),
backgroundActive: wrappedTypeToken(TOKENS.backgroundButtonBorderedActive),
backgroundFocus: wrappedTypeToken(TOKENS.backgroundButtonFocus),
foreground: wrappedTypeToken(TOKENS.colorTextButtonBordered),
foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonBorderedHover),
foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonBorderedActive),
...boxShadow,
};
}
return {
background: wrappedTypeToken(TOKENS.backgroundButton),
backgroundHover: wrappedTypeToken(TOKENS.backgroundButtonHover),
backgroundActive: wrappedTypeToken(TOKENS.backgroundButtonActive),
backgroundFocus: null,
foreground: wrappedTypeToken(TOKENS.colorTextButton),
foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonHover),
foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonActive),
...boxShadow,
};
};

export default getButtonStyles;
18 changes: 18 additions & 0 deletions src/Button/helpers/getButtonStyles.js.flow
@@ -0,0 +1,18 @@
// @flow

import type { ThemeProps } from "../../defaultTheme";
import type { Type } from "../index";
import type { Background, BoxShadow, Foreground } from "../../primitives/ButtonPrimitive";

export type GetButtonStyles = ({
disabled: boolean,
bordered: boolean,
type: Type,
...ThemeProps,
}) => {|
...Background,
...Foreground,
...BoxShadow,
|};

declare export default GetButtonStyles;
Expand Up @@ -2,9 +2,9 @@
import convertHexToRgba from "@kiwicom/orbit-design-tokens/lib/convertHexToRgba";

import { TOKENS, TYPE_OPTIONS } from "../consts";
import type { GetTypeToken } from "./getTypeToken";
import type { GetButtonTypeToken } from "./getButtonTypeToken";

const getTypeToken: GetTypeToken = name => ({ theme, type }) => {
const getButtonTypeToken: GetButtonTypeToken = (name, type, theme) => {
const tokens = {
[TOKENS.backgroundButton]: {
[TYPE_OPTIONS.PRIMARY]: theme.orbit.backgroundButtonPrimary,
Expand Down Expand Up @@ -197,4 +197,4 @@ const getTypeToken: GetTypeToken = name => ({ theme, type }) => {
return tokens[name][type];
};

export default getTypeToken;
export default getButtonTypeToken;

0 comments on commit ca4a641

Please sign in to comment.