diff --git a/package.json b/package.json index 2e61529b2..bfe9472af 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@eduzz/houston-workspaces", - "version": "0.63.1-beta.0", + "version": "0.63.0", "workspaces": [ "src/pages/*", "src/dev", diff --git a/src/dev/package.json b/src/dev/package.json index 7baef0984..9d1e85a13 100644 --- a/src/dev/package.json +++ b/src/dev/package.json @@ -1,12 +1,12 @@ { "name": "@eduzz/houston-dev", - "version": "0.63.1-beta.0", + "version": "0.63.0", "private": true, "dependencies": { - "@eduzz/houston-forms": "0.63.1-beta.0", - "@eduzz/houston-hooks": "0.63.1-beta.0", - "@eduzz/houston-icons": "0.63.1-beta.0", - "@eduzz/houston-ui": "0.63.1-beta.0", + "@eduzz/houston-forms": "0.63.0", + "@eduzz/houston-hooks": "0.63.0", + "@eduzz/houston-icons": "0.63.0", + "@eduzz/houston-ui": "0.63.0", "react-dom": "^18", "react-router-dom": "^6.3.0", "react-scripts": "^5.0.1", diff --git a/src/package.json b/src/package.json index 26f4cc44c..44f37f898 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "@eduzz/docs", - "version": "0.63.1-beta.0", + "version": "0.63.0", "private": true, "scripts": { "start": "next dev", @@ -8,10 +8,10 @@ }, "dependencies": { "@chakra-ui/react": "^1.8.8", - "@eduzz/houston-forms": "0.63.1-beta.0", - "@eduzz/houston-hooks": "0.63.1-beta.0", - "@eduzz/houston-icons": "0.63.1-beta.0", - "@eduzz/houston-ui": "0.63.1-beta.0", + "@eduzz/houston-forms": "0.63.0", + "@eduzz/houston-hooks": "0.63.0", + "@eduzz/houston-icons": "0.63.0", + "@eduzz/houston-ui": "0.63.0", "@emotion/react": "^11", "@emotion/styled": "^11", "dokz": "2.0.9", diff --git a/src/pages/eslint-config/package.json b/src/pages/eslint-config/package.json index ebd61f664..3f7c4e75b 100644 --- a/src/pages/eslint-config/package.json +++ b/src/pages/eslint-config/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/eslint-config-houston", "private": false, - "version": "0.63.1-beta.0", + "version": "0.63.0", "description": "Eduzz Houston Eslint Config", "author": "Eduzz Team", "license": "MIT", diff --git a/src/pages/forms/package.json b/src/pages/forms/package.json index e9db83c0d..e122a5f0d 100644 --- a/src/pages/forms/package.json +++ b/src/pages/forms/package.json @@ -1,6 +1,6 @@ { "name": "@eduzz/houston-forms", - "version": "0.63.1-beta.0", + "version": "0.63.0", "description": "Houston Forms", "main": "index.js", "types": "./index.d.ts", @@ -19,7 +19,7 @@ "check-update-deps": "yarn ncu -u" }, "dependencies": { - "@eduzz/houston-hooks": "0.63.1-beta.0", + "@eduzz/houston-hooks": "0.63.0", "@hookform/error-message": "^2.0.0", "@hookform/resolvers": "^2", "formik": "^2.2.9", diff --git a/src/pages/hooks/package.json b/src/pages/hooks/package.json index 1bb137b80..8f1584468 100644 --- a/src/pages/hooks/package.json +++ b/src/pages/hooks/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/houston-hooks", "description": "Eduzz Houston Hooks", - "version": "0.63.1-beta.0", + "version": "0.63.0", "main": "./index.js", "types": "./index.d.ts", "author": "Eduzz Team", diff --git a/src/pages/icons/package.json b/src/pages/icons/package.json index ce1eda879..cc33c955f 100644 --- a/src/pages/icons/package.json +++ b/src/pages/icons/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/houston-icons", "description": "Eduzz Houston Icons", - "version": "0.63.1-beta.0", + "version": "0.63.0", "main": "./index.js", "types": "./index.d.ts", "author": "Eduzz Team", diff --git a/src/pages/styles/package.json b/src/pages/styles/package.json index 0534363f6..688c70966 100644 --- a/src/pages/styles/package.json +++ b/src/pages/styles/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/houston-styles", "description": "Eduzz Houston Style", - "version": "0.63.1-beta.0", + "version": "0.63.0", "main": "./index.js", "types": "./index.d.ts", "author": "Eduzz Team", @@ -19,7 +19,7 @@ "check-update-deps": "yarn ncu -u" }, "dependencies": { - "@eduzz/houston-tokens": "0.63.1-beta.0", + "@eduzz/houston-tokens": "0.63.0", "@emotion/cache": "^11", "@emotion/css": "^11", "@emotion/react": "^11", diff --git a/src/pages/tokens/package.json b/src/pages/tokens/package.json index a67352b5e..ca0a4661c 100644 --- a/src/pages/tokens/package.json +++ b/src/pages/tokens/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/houston-tokens", "description": "Eduzz Houston Tokens", - "version": "0.63.1-beta.0", + "version": "0.63.0", "main": "./index.js", "types": "./index.d.ts", "author": "Eduzz Team", diff --git a/src/pages/ui-components/Card/index.mdx b/src/pages/ui-components/Card/index.mdx new file mode 100644 index 000000000..4fcf7a033 --- /dev/null +++ b/src/pages/ui-components/Card/index.mdx @@ -0,0 +1,207 @@ +--- +name: Card +--- + +import { Playground } from 'dokz'; + +import Box from '../Box'; +import Button from '../Button'; +import Grid from '../Grid'; +import Typography from '../Typography'; +import Card from './'; + +# Card + +Cards são componentes da interface usados para agrupar informações relacionadas dentro de um container/bloco. Os cards funcionam como um contentor para algumas informações curtas e relacionadas. Os cards não possuem uma configuração de estilos para o conteúdo que é apresentado neles. + +### Importação + +```js +import Card from '@eduzz/houston-ui/Card'; +``` + +### Exemplo + + + + + + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + +### Espaçamento + +Você pode alterar o espaçamento interno conforme sua necessidade. + + + {() => { + const spacing = ['xxxs', 'xxs', 'sm']; + return ( + <> + {spacing.map((s, index) => ( + + + + + + + + Padding {s} + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + + + + + Padding {s} + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + + + + + Padding {s} + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + ))} + + ); + }} + + +### Card clicável + +Quando passado a prop `onClick` para o componente, ele ativa alguns comportamentos no `hover`, `focus` e etc... + + + + + alert('Houston Design System')}> + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + console.log('Houston Design System')}> + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + console.log('Houston Design System')}> + + + + + Houston + + + Houston é uma grande metrópole situada no Texas que se estende até a Baía de Galveston. + + + + + + + + + +### Props + +| prop | tipo | obrigatório | padrão | descrição | +| -------- | ----------------- | ----------- | ------ | ------------------------------ | +| children | `React.ReactNode` | `false` | - | - | +| disabled | `boolean` | `false` | - | - | +| padding | `CardPadding` | `false` | `xs` | Padding interno do componente. | diff --git a/src/pages/ui-components/Card/index.tsx b/src/pages/ui-components/Card/index.tsx new file mode 100644 index 000000000..2cd0655c6 --- /dev/null +++ b/src/pages/ui-components/Card/index.tsx @@ -0,0 +1,103 @@ +import styled, { cx, css, StyledProp, CSSInterpolation } from '@eduzz/houston-styles'; +import type { Spacing as HoustonSpacing } from '@eduzz/houston-tokens'; + +type Spacing = Omit; + +export type CardPadding = keyof Spacing; + +export interface CardProps { + children: React.ReactNode; + disabled?: boolean; + /** + * @default `xs` + */ + padding?: CardPadding; +} + +const Card = ({ + children, + padding = 'xs', + disabled = false, + className, + onClick, + ...rest +}: CardProps & StyledProp & React.HTMLAttributes) => { + const clickable = onClick !== undefined; + + return ( +
+ {children} +
+ ); +}; + +export default styled(Card, { label: 'hst-card' })` + ${({ theme }) => { + const modifiers: CSSInterpolation[] = []; + + const availableSpacing: Record = { + quarck: theme.spacing.quarck, + nano: theme.spacing.nano, + xxxs: theme.spacing.xxxs, + xxs: theme.spacing.xxs, + xs: theme.spacing.xs, + sm: theme.spacing.sm, + md: theme.spacing.md, + lg: theme.spacing.lg, + xl: theme.spacing.xl, + xxl: theme.spacing.xxl, + xxxl: theme.spacing.xxxl, + huge: theme.spacing.huge, + giant: theme.spacing.giant + }; + + Object.entries(availableSpacing).forEach(([key, value]) => + modifiers.push(css` + &.--hst-padding-${key} { + padding: ${value}; + } + `) + ); + + return css` + background-color: ${theme.neutralColor.high.pure}; + border: ${theme.border.width.xs} solid ${theme.hexToRgba(theme.brandColor.primary.pure, theme.opacity.level[3])}; + border-radius: ${theme.border.radius.sm}; + + ${modifiers} + + &.--hst-disabled { + cursor: not-allowed; + pointer-events: none; + opacity: ${theme.opacity.level[6]}; + } + + &.--hst-clickable { + transition: 0.3s; + cursor: pointer; + + &:hover { + box-shadow: ${theme.shadow.level[2]}; + } + + &:active { + background-color: ${theme.neutralColor.high.light}; + box-shadow: ${theme.shadow.level[1]}; + } + + &:focus { + outline: solid ${theme.border.width.sm} ${theme.feedbackColor.informative.pure}; + } + } + `; + }} +`; diff --git a/src/pages/ui-components/Dropdown/Root.tsx b/src/pages/ui-components/Dropdown/Root.tsx new file mode 100644 index 000000000..2bbdb5d52 --- /dev/null +++ b/src/pages/ui-components/Dropdown/Root.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; + +export interface DropdownRootProps { + children: React.ReactNode; + arrow: boolean; +} + +const DropdownRoot = ({ children, arrow, ...rest }: DropdownRootProps & React.HTMLAttributes) => { + return ( +
+ {arrow && ( + <> +
+ + )} + + {children} +
+ ); +}; + +export default React.memo(DropdownRoot); diff --git a/src/pages/ui-components/Dropdown/index.mdx b/src/pages/ui-components/Dropdown/index.mdx new file mode 100644 index 000000000..e5632f499 --- /dev/null +++ b/src/pages/ui-components/Dropdown/index.mdx @@ -0,0 +1,122 @@ +--- +name: Dropdown +--- + +import { Playground } from 'dokz'; + +import ArrowRightIcon from '@eduzz/houston-icons/ArrowRight'; +import EditOutlineIcon from '@eduzz/houston-icons/EditOutline'; +import TrashOutlineIcon from '@eduzz/houston-icons/TrashOutline'; + +import Button from '../Button'; +import Column from '../Grid/Column'; +import Row from '../Grid/Row'; +import IconButton from '../IconButton'; +import Thumbnail from '../Image/Thumbnail'; +import List from '../List'; +import Dropdown from './'; + +# Dropdown + +Componente suspenso. Pode ser utilizado para criar listas, menus e outros componentes flutuantes. + +### Importação + +```js +import Dropdown from '@eduzz/houston-ui/Dropdown'; +``` + +### Exemplo + +Clique no botão para exibir o conteúdo. + + + {() => { + const Content = () => ( +
+ + {new Array(3).fill('').map((_, index) => ( + + + + + + + + + + + + ))} + +
+ ); + return ( + }> + + + ); + }} +
+ +### Direção + +Existem 12 possibilidades para se adequar ao conteúdo. + + + {() => { + const Content = () => ( +
+ + + + + + + + + + + + + + +
+ ); + return ( + + + } placement='top'> + + + + + } placement='left'> + + + + + } placement='bottom'> + + + + + } placement='right'> + + + + + ); + }} +
+ +> Todos os lados possuem mais duas direções. Por exemplo: `top`, `top-start` e `top-end`. Sempre adicionando o sufixo (`-start` e `-end`). + +| prop | tipo | obrigatório | padrão | descrição | +| --------- | ------------------- | ----------- | -------------- | --------------------------- | +| placement | `DropdownPlacement` | `false` | `bottom-start` | Posicionamento do conteúdo. | +| content | `React.ReactNode` | `true` | - | Conteúdo oculto. | +| children | `React.ReactNode` | `true` | - | - | +| arrow | `boolean` | `false` | `true` | - | +| onOpen | `function` | `false` | - | - | +| onClose | `function` | `false` | - | - | diff --git a/src/pages/ui-components/Dropdown/index.tsx b/src/pages/ui-components/Dropdown/index.tsx new file mode 100644 index 000000000..b2030ef5b --- /dev/null +++ b/src/pages/ui-components/Dropdown/index.tsx @@ -0,0 +1,207 @@ +import * as React from 'react'; + +import { flushSync } from 'react-dom'; + +import useBoolean from '@eduzz/houston-hooks/useBoolean'; +import styled, { css, StyledProp } from '@eduzz/houston-styles'; + +import Popover from '../Popover'; +import usePopover from '../Popover/usePopover'; +import Root from './Root'; + +export type DropdownPlacement = + | 'bottom-end' + | 'bottom-start' + | 'bottom' + | 'left-end' + | 'left-start' + | 'left' + | 'right-end' + | 'right-start' + | 'right' + | 'top-end' + | 'top-start' + | 'top'; + +export interface DropdownProps { + /** + * Position + * @default `bottom-start` + */ + placement?: DropdownPlacement; + /** + * Hidden content + */ + content: React.ReactNode; + /** + * Display arrow position + * @default `true` + */ + arrow?: boolean; + children: React.ReactNode; + onClose?: () => void; + onOpen?: () => void; +} + +export const ARROW_SIZE = 12; +export const ARROW_HALF_SIZE = ARROW_SIZE / 2; + +const Dropdown = ({ + children, + onOpen, + onClose, + placement = 'bottom-start', + arrow = true, + content, + className, + id: idProp, + ...rest +}: DropdownProps & StyledProp & React.HTMLAttributes) => { + const { openPopover: open, closePopover: close, popoverTargetProps, popoverProps, isPopoverOpened } = usePopover(); + const [dropdownCreated, , createDropdown, deleteDropdown] = useBoolean(); + + const [id] = React.useState(idProp ?? `hst-dropdown-${Math.floor(Math.random() * 1000)}`); + + const onOpenDropdown = React.useCallback(() => { + flushSync(() => { + createDropdown(); + }); + + open(); + onOpen && onOpen(); + }, [onOpen, open, createDropdown]); + + const onCloseDropdown = React.useCallback(() => { + onClose && onClose(); + close(); + deleteDropdown(); + }, [onClose, close, deleteDropdown]); + + const props: Partial> & { ref: React.MutableRefObject } = { + tabIndex: 0, + onClick: onOpenDropdown, + ref: popoverTargetProps.ref, + ...rest + }; + + React.useEffect(() => { + if (!isPopoverOpened && popoverProps.ref?.current) { + onCloseDropdown(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [onCloseDropdown, isPopoverOpened]); + + return ( + <> + {typeof children === 'string' ? ( + {children} + ) : ( + React.cloneElement(children as React.ReactElement, props) + )} + + {dropdownCreated && ( + + {content} + + )} + + ); +}; + +const DropdownWrapper = styled(Dropdown)` + ${({ theme }) => { + const ARROW_SIZE_IN_REM = `${theme.pxToRem(ARROW_SIZE)}rem`; + const ARROW_HALF_SIZE_IN_REM = `${theme.pxToRem(ARROW_HALF_SIZE)}rem`; + const ARROW_DOUBLE_SIZE_IN_REM = `${theme.pxToRem(ARROW_SIZE * 2)}rem`; + + return css` + #hst-dropdown-arrow { + z-index: 1; + position: absolute; + overflow: hidden; + width: ${ARROW_DOUBLE_SIZE_IN_REM}; + height: ${ARROW_DOUBLE_SIZE_IN_REM}; + } + + #hst-dropdown-arrow::before { + content: ''; + position: absolute; + width: ${ARROW_SIZE_IN_REM}; + height: ${ARROW_SIZE_IN_REM}; + left: calc(50% - ${ARROW_HALF_SIZE_IN_REM}); + background: ${theme.neutralColor.high.pure}; + } + + &.popover[data-popper-placement='top'], + &.popover[data-popper-placement='top-start'], + &.popover[data-popper-placement='top-end'] { + & > .__container { + margin-bottom: ${ARROW_HALF_SIZE_IN_REM}; + } + + #hst-dropdown-arrow { + bottom: -${ARROW_DOUBLE_SIZE_IN_REM}; + + &::before { + transform: translateY(-${ARROW_HALF_SIZE_IN_REM}) rotate(45deg); + } + } + } + + &.popover[data-popper-placement='bottom'], + &.popover[data-popper-placement='bottom-start'], + &.popover[data-popper-placement='bottom-end'] { + & > .__container { + margin-top: ${ARROW_HALF_SIZE_IN_REM}; + } + + #hst-dropdown-arrow { + top: -${ARROW_DOUBLE_SIZE_IN_REM}; + + &::before { + bottom: 0; + transform: translateY(${ARROW_HALF_SIZE_IN_REM}) rotate(45deg); + } + } + } + + &.popover[data-popper-placement='left'], + &.popover[data-popper-placement='left-start'], + &.popover[data-popper-placement='left-end'] { + & > .__container { + position: relative; + left: -${ARROW_HALF_SIZE_IN_REM}; + } + + #hst-dropdown-arrow { + right: -${ARROW_DOUBLE_SIZE_IN_REM}; + + &::before { + left: 0; + transform: translate(-${ARROW_HALF_SIZE_IN_REM}, ${ARROW_HALF_SIZE_IN_REM}) rotate(45deg); + } + } + } + + &.popover[data-popper-placement='right'], + &.popover[data-popper-placement='right-start'], + &.popover[data-popper-placement='right-end'] { + & > .__container { + position: relative; + right: -${ARROW_HALF_SIZE_IN_REM}; + } + + #hst-dropdown-arrow { + left: -${ARROW_DOUBLE_SIZE_IN_REM}; + + &::before { + right: 0; + transform: translate(${ARROW_SIZE_IN_REM}, ${ARROW_HALF_SIZE_IN_REM}) rotate(45deg); + } + } + } + `; + }} +`; + +export default React.memo(DropdownWrapper); diff --git a/src/pages/ui-components/Popover/Root.tsx b/src/pages/ui-components/Popover/Root.tsx index 24d1efd9f..784dea580 100644 --- a/src/pages/ui-components/Popover/Root.tsx +++ b/src/pages/ui-components/Popover/Root.tsx @@ -49,7 +49,7 @@ const PopoverRoot = ({ children }: PopoverProps) => { { name: 'offset', options: { - offset: [0, 8] + offset: [0, 12] } } ] diff --git a/src/pages/ui-components/Popover/index.tsx b/src/pages/ui-components/Popover/index.tsx index 6df5bfa99..5846cde44 100644 --- a/src/pages/ui-components/Popover/index.tsx +++ b/src/pages/ui-components/Popover/index.tsx @@ -43,6 +43,7 @@ const Popover = React.forwardRef( } setRender(true); + closeRef.current = setState({ opened: true, target: targetRef.current, @@ -62,9 +63,7 @@ const Popover = React.forwardRef( return (
-
- {render && children} -
+
{render && children}
); } @@ -96,8 +95,8 @@ export default styled(Popover, { label: 'houston-popover' })( overflow-y: auto; overflow-x: hidden; background-color: white; - box-shadow: ${theme.shadow.level[1]}; - border-radius: ${theme.border.radius.xs}; + box-shadow: ${theme.shadow.level[3]}; + border-radius: ${theme.border.radius.sm}; box-sizing: border-box; transform-origin: top center; animation-duration: 0.2s; diff --git a/src/pages/ui-components/package.json b/src/pages/ui-components/package.json index b0d084bfa..fffdc9f03 100644 --- a/src/pages/ui-components/package.json +++ b/src/pages/ui-components/package.json @@ -1,7 +1,7 @@ { "name": "@eduzz/houston-ui", "description": "Eduzz Houston Components UI", - "version": "0.63.1-beta.0", + "version": "0.63.0", "main": "./index.js", "types": "./index.d.ts", "author": "Eduzz Team", @@ -19,10 +19,10 @@ "check-update-deps": "yarn ncu -u" }, "dependencies": { - "@eduzz/houston-forms": "0.63.1-beta.0", - "@eduzz/houston-hooks": "0.63.1-beta.0", - "@eduzz/houston-icons": "0.63.1-beta.0", - "@eduzz/houston-styles": "0.63.1-beta.0", + "@eduzz/houston-forms": "0.63.0", + "@eduzz/houston-hooks": "0.63.0", + "@eduzz/houston-icons": "0.63.0", + "@eduzz/houston-styles": "0.63.0", "@emotion/cache": "^11", "@emotion/css": "^11", "@emotion/react": "^11", @@ -33,7 +33,6 @@ "@popperjs/core": "^2.11.6", "date-fns": "^2", "lodash": "^4", - "rc-picker": "2.6.10", "react-colorful": "^5", "react-toastify": "^9", "tslib": "^2",