From 758056d998072f73326e987f52e2b01ba9922e59 Mon Sep 17 00:00:00 2001 From: Tatiana Cherednichenko Date: Wed, 5 May 2021 14:55:32 +0300 Subject: [PATCH 1/2] feat: implement box-model and rewrite ButtonIcon --- src/static/icons/close.svg | 3 +++ src/static/icons/index.ts | 2 +- src/static/icons/search.svg | 4 +-- src/ui/atoms/button-icon/index.tsx | 31 +++++++++++++++++------ src/ui/elements/quarks/box/index.tsx | 37 ++++++++++++++++++++++++++++ src/ui/elements/quarks/index.ts | 1 + 6 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/static/icons/close.svg create mode 100644 src/ui/elements/quarks/box/index.tsx diff --git a/src/static/icons/close.svg b/src/static/icons/close.svg new file mode 100644 index 00000000..69474a5b --- /dev/null +++ b/src/static/icons/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/static/icons/index.ts b/src/static/icons/index.ts index 61af235e..131766f4 100644 --- a/src/static/icons/index.ts +++ b/src/static/icons/index.ts @@ -3,7 +3,7 @@ export { default as ArrowLeft } from './arrow-left.svg'; export { default as Check } from './check.svg'; export { default as CheckIcon } from './icon_check.svg'; export { default as ClosedEyeIcon } from './closed-eye.svg'; -export { default as CloseIcon } from './close-small.svg'; +export { default as CloseIcon } from './close.svg'; export { default as InfoIcon } from './info.svg'; export { default as MoreIcon } from './more.svg'; export { default as OpenedEyeIcon } from './opened-eye.svg'; diff --git a/src/static/icons/search.svg b/src/static/icons/search.svg index e14246f6..cd1f58df 100644 --- a/src/static/icons/search.svg +++ b/src/static/icons/search.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/ui/atoms/button-icon/index.tsx b/src/ui/atoms/button-icon/index.tsx index 20631786..9fa80dac 100644 --- a/src/ui/atoms/button-icon/index.tsx +++ b/src/ui/atoms/button-icon/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled, { StyledComponent } from 'styled-components'; import { Variant } from 'lib/types'; +import { box } from 'ui/elements/quarks'; interface Props extends React.ButtonHTMLAttributes { className?: string; @@ -22,15 +23,27 @@ const ButtonIconBase: React.FC = ({ ); export const ButtonIcon = styled(ButtonIconBase)` + ${box} + --local-vertical: calc( + 1px * var(--woly-component-level) * var(--woly-main-level) + ); + --local-shape-color: var(--woly-canvas-default); - --local-icon-size: var(--woly-line-height); - --local-icon-color: var(--woly-canvas-text-default); - --local-padding: calc(1px * var(--woly-component-level) * var(--woly-main-level)); + --local-icon-size: calc(var(--woly-line-height)); + --local-button-size: calc(var(--local-icon-size) + (var(--local-vertical) * 2)); + --local-icon-color: var(--woly-shape-default); + + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; - border: var(--woly-border) solid var(--local-shape-color); - border-radius: var(--woly-rounding, 4px); + width: var(--local-button-size); + height: var(--local-button-size); + + border: var(--woly-border-width) solid var(--local-shape-color); + border-radius: var(--woly-rounding); cursor: pointer; - padding: var(--local-padding); background: var(--local-shape-color); outline: none; @@ -38,8 +51,10 @@ export const ButtonIcon = styled(ButtonIconBase)` display: flex; align-items: center; justify-content: center; - width: var(--local-icon-size); - height: var(--local-icon-size); + svg { + width: var(--local-icon-size); + height: var(--local-icon-size); + } svg > path { fill: var(--local-icon-color); diff --git a/src/ui/elements/quarks/box/index.tsx b/src/ui/elements/quarks/box/index.tsx new file mode 100644 index 00000000..3fd851c1 --- /dev/null +++ b/src/ui/elements/quarks/box/index.tsx @@ -0,0 +1,37 @@ +import { css } from 'styled-components'; + +export const box = css` + --local-vertical: calc( + 1px * var(--woly-component-level) * var(--woly-main-level) - var(--woly-border-width) + ); + --local-horizontal: calc( + var(--woly-const-m) + (1px * var(--woly-main-level)) + var(--local-vertical) - + var(--woly-border-width) + ); + --local-gap: calc(1px * var(--woly-component-level) * var(--woly-main-level)); + --local-compensate: var(--local-vertical); + + & > * { + padding-top: var(--local-vertical); + padding-bottom: var(--local-vertical); + } + + & > :first-child { + padding-left: var(--local-horizontal); + } + + & > :last-child { + padding-right: var(--local-horizontal); + } + + & > [data-icon]:first-child { + padding-left: var(--local-compensate); + } + & > [data-icon]:last-child { + padding-right: var(--local-compensate); + } + + & > :not(:first-child) { + margin-left: var(--local-gap); + } +`; diff --git a/src/ui/elements/quarks/index.ts b/src/ui/elements/quarks/index.ts index 858e080c..66dd5ce8 100644 --- a/src/ui/elements/quarks/index.ts +++ b/src/ui/elements/quarks/index.ts @@ -1,2 +1,3 @@ +export { box } from './box'; export { InputContainer } from './input-container'; export { InputElement } from './input-element'; From 857c80474dcb383d9d08e5c8c5a0bc1da8f544e0 Mon Sep 17 00:00:00 2001 From: Tatiana Cherednichenko Date: Wed, 5 May 2021 18:31:29 +0300 Subject: [PATCH 2/2] fix: rewrite Chip on box-model --- src/lib/box-styles.tsx | 11 +- src/ui/atoms/chip/index.tsx | 203 +++++++++--------------------------- src/ui/atoms/chip/usage.mdx | 162 ++++++++++++++++++---------- 3 files changed, 168 insertions(+), 208 deletions(-) diff --git a/src/lib/box-styles.tsx b/src/lib/box-styles.tsx index e19b9260..d2bdafea 100644 --- a/src/lib/box-styles.tsx +++ b/src/lib/box-styles.tsx @@ -6,6 +6,11 @@ export const Global = styled.div` font-family: 'Helvetica Neue', sans-serif; } + button { + padding: 0; + margin: 0; + } + --palette-snow-1000: #000000; --palette-snow-500: #c0c0c0; --palette-snow-300: #e5e5e5; @@ -211,8 +216,10 @@ const Container = styled.div` } &[data-dir='horizontal'] { flex-direction: row; - & > * + * { - margin-left: 0.5rem; + flex-wrap: wrap; + & > * { + margin-right: 0.5rem; + margin-bottom: 0.5rem; } } `; diff --git a/src/ui/atoms/chip/index.tsx b/src/ui/atoms/chip/index.tsx index e50868fa..17de88f2 100644 --- a/src/ui/atoms/chip/index.tsx +++ b/src/ui/atoms/chip/index.tsx @@ -1,197 +1,96 @@ import * as React from 'react'; import styled, { StyledComponent } from 'styled-components'; import { Variant } from 'lib/types'; - -/** - * --woly-rounding — in pixels - * --woly-font-size - * --woly-line-height - * --woly-border-width - * - * --woly-background - * --woly-border - * --woly-color - * - * --woly-background-hover - * --woly-border-hover - * --woly-color-hover - * - * --woly-background-focus - * --woly-border-focus - * --woly-color-focus - * - * --woly-background-disabled - * --woly-border-disabled - * --woly-color-disabled - * - */ +import { box } from 'ui/elements/quarks'; interface ChipProps { - action?: React.ReactNode; children?: string; className?: string; disabled?: boolean; - icon?: React.ReactNode; - onActionClick?: (event: React.MouseEvent) => void; - onClick?: (event: React.MouseEvent) => void; + leftIcon?: React.ReactNode; + onClick?: React.EventHandler; + rightIcon?: React.ReactNode; } const ChipBase: React.FC = ({ - action, children, className, disabled, - icon, - onActionClick, + leftIcon, onClick, + rightIcon, variant = 'secondary', }) => { const chipRole = onClick ? 'button' : 'div'; - const chipTabIndex = onClick ? 1 : 0; + const chipTabIndex = onClick ? 0 : -1; + + const onKeyDown = React.useCallback( + (event) => { + if (event.key === 'Enter' && onClick) { + onClick(event); + } + }, + [onClick], + ); return ( -
-
- {icon &&
{icon}
} +
+ {leftIcon && ( +
+ {leftIcon} +
+ )} +
{children} - {action && ( - <> - -
- - )}
+ {rightIcon &&
{rightIcon}
}
); }; export const Chip = styled(ChipBase)` - --woly-vertical: calc(1px * var(--woly-component-level) * var(--woly-main-level)); - --woly-horizontal: calc( - var(--woly-const-m) + (1px * var(--woly-main-level)) + var(--woly-vertical) - ); - --woly-line-height: 24px; - - position: relative; + ${box} + --local-background: var(--woly-shape-default); + --local-icon-size: var(--woly-line-height); + --local-color: var(--woly-shape-text-default); + --local-border-color: var(--woly-shape-default); box-sizing: border-box; - display: flex; align-items: center; - - background-color: var(--woly-background, #b0a3f4); - color: var(--woly-color, #ffffff); - - border-radius: var(--woly-rounding, 3px); - - [role] { - width: 100%; - - display: flex; - align-items: center; - justify-content: center; - - font-size: var(--woly-font-size, 12px); - line-height: var(--woly-line-height, 20px); - - border-radius: var(--woly-rounding, 3px); - - padding: 0 var(--woly-horizontal, 6px); - + background-color: var(--local-background); + color: var(--local-color); + border-radius: var(--woly-rounding); + font-size: var(--woly-font-size); + outline: none; + border: var(--woly-border-width) solid var(--local-border-color); + + [data-text] { outline: none; + line-height: var(--woly-line-height); } - [role='button']:active { - color: var(--woly-color-focus, #ffffff); - background-color: var(--woly-background-focus, #9381f1); - border-color: var(--woly-border-focus, transparent); - } + &[role='button']:focus-within { + --local-background: var(--woly-focus); + --local-border-color: var(--woly-shape-active); - [role='button']:focus { - box-shadow: 0 0 0 var(--woly-border-width) var(--woly-border-focus, #9381f1); + box-shadow: 0 0 0 var(--woly-border-width) var(--woly-shape-default); } - [role='button']:hover { - color: var(--woly-color-hover, #ffffff); - background-color: var(--woly-background-hover, #9381f1); - opacity: 0.5; - border-color: var(--woly-border-hover, transparent); - outline: none; + &[role='button']:hover { + --local-background: var(--woly-shape-hover); + --local-border-color: var(--woly-shape-hover); } &[data-disabled='true'] { - color: var(--woly-color-disabled, #c0c0c0); - background: var(--woly-background-disabled, #f5f5f5); - border-color: var(--woly-background-disabled, transparent); - pointer-events: none; + --local-background: var(--woly-shape-disabled); + --local-text: var(--woly-shape-text-disabled); + --local-border-color: var(--woly-shape-disabled); - [data-icon] { - svg > path { - fill: var(--woly-color, #c0c0c0); - } - } + pointer-events: none; } - [data-icon], - [data-type='stub'] { + [data-icon] { + --woly-component-level: 0; display: flex; - align-items: center; - justify-content: center; - - width: var(--woly-line-height, 24px); - height: var(--woly-line-height, 24px); - - background: var(--woly-background-disabled, transparent); - - border-color: var(--woly-border, transparent); - border-style: solid; - border-width: var(--woly-border-width); - border-radius: var(--woly-rounding, 3px); - - outline: none; - - svg > path { - fill: var(--woly-color, #ffffff); - } - } - - [data-type='stub'] { - visibility: hidden; - position: static; - flex-shrink: 0; - } - - [data-icon='right'] { - position: absolute; - right: 0; - z-index: 1; - top: 50%; - transform: translateY(-50%); - - &:hover { - background-color: var(--woly-background-hover, #9381f1); - opacity: 0.5; - } - - &:active { - background-color: var(--woly-background-hover, #9381f1); - } - - &:focus { - box-shadow: 0 0 0 var(--woly-border-width) var(--woly-border-focus, #9381f1); - } } ` as StyledComponent<'div', Record, ChipProps & Variant>; diff --git a/src/ui/atoms/chip/usage.mdx b/src/ui/atoms/chip/usage.mdx index ebd60fa0..3d28e135 100644 --- a/src/ui/atoms/chip/usage.mdx +++ b/src/ui/atoms/chip/usage.mdx @@ -6,7 +6,8 @@ package: 'woly' import { Chip } from './index'; import { CloseIcon, PlusIcon } from 'icons'; -import { Playground } from 'box-styles' +import { ButtonIcon } from 'ui' +import { block, Playground } from 'box-styles' `Chip` is used for categorizing or markup. Chips allow users to enter information, make selections, filter content, or trigger actions. @@ -27,7 +28,9 @@ As a standalone component, the most common use will be in some form of input, so ### Example - Simple Chip + + Simple Chip + ### Clickable @@ -39,25 +42,55 @@ In case when chip is clickable, it defined change appearance on focus, hover, an If chip consists another clickable component (eg button), this property defined will display a component which changes appearance on hover. - console.info('click')}> - Cklicked Chip - - } - onActionClick={() => console.info('ActionIcon clicked')} - > - Cklicked Icon - - console.info('click')} - action={} - onActionClick={() => console.info('ActionIcon clicked')} - disabled - > - Disabled Chip - + + console.info('click')} + rightIcon={ + } + onClick={() => console.info('CloseIcon clicked')} + variant="primary" + filled + /> + } + > + Clicked Chip + + + + console.info('click')} + variant="primary" + rightIcon={ + } + onClick={() => console.info('CloseIcon clicked')} + variant="primary" + filled + /> + } + > + Clicked Icon + + + + } + onClick={() => console.info('CloseIcon clicked')} + variant="primary" + filled + disabled + /> + } + > + Disabled Chip + + ### Icons/Buttons @@ -67,31 +100,51 @@ Chip can be used with icon on the left side or button on the right side. Even chip can be used with both options. - }> - Chip with Icon - - } onClick={() => console.info('click')}> - Cklicked Chip - - } - onClick={() => console.info('click')} - action={} - onActionClick={() => console.info('ActionIcon clicked')} - > - Cklicked Icon - - } - onClick={() => console.info('click')} - action={} - onActionClick={() => console.info('ActionIcon clicked')} - disabled - > - Disabled Chip - + + }> + Chip with Icon + + + + } onClick={() => console.info('click')}> + Clicked Chip + + + + } + onClick={() => console.info('click')} + rightIcon={ + } + onClick={(event) => console.info('CloseIcon clicked')} + variant="primary" + filled + /> + } + > + Clicked Icon + + + + } + disabled + rightIcon={ + } + onClick={(event) => console.info('CloseIcon clicked')} + variant="primary" + filled + disabled + /> + } + > + Disabled Chip + + ### Kinds @@ -102,11 +155,12 @@ Even chip can be used with both options. ### Props -| Name | Type | Default | Description | -| --------------- | ------------------------------------- | ------------- | -------------------------------------------------- | -| `children` | `string` | | Text inside chip | -| `action` | `React.ReactNode` | `null` | Icon to show on the right side of the text | -| `onActionClick` | `React.MouseEvent` | `null` | Callback when chip is clicked | -| `onClick` | `React.MouseEvent` | `null` | Callback when chip is clicked | -| `variant` | `string` | `'secondary'` | Variant prop to style Chip component | -| `...` | `HTMLButtonElement` | `{}` | Other props are inherited from `HTMLButtonElement` | +| Name | Type | Default | Description | +| ----------- | ---------------------------------- | ------------- | -------------------------------------------------- | +| `children` | `string` | | Text inside chip | +| `disabled` | `boolean` | | Attribute to disable chip | +| `leftIcon` | `React.ReactNode` | `null` | Icon to show on the left side of the text | +| `onClick` | `React.MouseEvent` | `null` | Callback when chip is clicked | +| `rightIcon` | `React.ReactNode` | `null` | Icon to show on the right side of the text | +| `variant` | `string` | `'secondary'` | Variant prop to style Chip component | +| `...` | `HTMLButtonElement` | `{}` | Other props are inherited from `HTMLButtonElement` |