diff --git a/.github/ISSUE_TEMPLATE/tech-feature-request.yml b/.github/ISSUE_TEMPLATE/tech-feature-request.yml index 653f177c59..15ab0d3967 100644 --- a/.github/ISSUE_TEMPLATE/tech-feature-request.yml +++ b/.github/ISSUE_TEMPLATE/tech-feature-request.yml @@ -35,4 +35,4 @@ body: attributes: label: 'Implementation' description: 'If possible, describe how this feature could be implemented.' - placeholder: 'See [CONTRIBUTING.mdx](https://github.com/reakit/reakit/blob/master/CONTRIBUTING.mdx)' + placeholder: 'See [CONTRIBUTING.mdx](https://github.com/WTTJ/welcome-ui/blob/master/CONTRIBUTING.mdx)' diff --git a/README.md b/README.md index 77cc425c84..8bf1d960b7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -Welcome to the _Welcome UI library_ created by [Welcome to the jungle](https://www.welcometothejungle.com), a customizable design system with react • typescript • styled-components • styled-system and reakit. +Welcome to the _Welcome UI library_ created by [Welcome to the jungle](https://www.welcometothejungle.com), a customizable design system with react • typescript • styled-components • styled-system and ariakit. Here you'll find all the core components you need to create a delightful webapp. diff --git a/docs/components/GlobalStyle.js b/docs/components/GlobalStyle.js index 56a87de103..72b8221ee4 100644 --- a/docs/components/GlobalStyle.js +++ b/docs/components/GlobalStyle.js @@ -14,6 +14,8 @@ export const GlobalStyle = createGlobalStyle` } .DocSearch { + transition: none !important; + &-Button { margin: 0; width: 100%; diff --git a/docs/components/Head.js b/docs/components/Head.js index ecb092f977..dd58cf8e4c 100644 --- a/docs/components/Head.js +++ b/docs/components/Head.js @@ -25,13 +25,13 @@ export function Head() { diff --git a/docs/components/Header/ThemeSelector.js b/docs/components/Header/ThemeSelector.js index 77cdbb3648..d762ef0150 100644 --- a/docs/components/Header/ThemeSelector.js +++ b/docs/components/Header/ThemeSelector.js @@ -1,5 +1,5 @@ import React from 'react' -import { DropdownMenu, useDropdownMenuState } from '@welcome-ui/dropdown-menu' +import { DropdownMenu, useDropdownMenu } from '@welcome-ui/dropdown-menu' import { Box } from '@welcome-ui/box' import { CrescentMoonIcon, StarIcon, StarOutlineIcon, SunIcon } from '@welcome-ui/icons' import { Button } from '@welcome-ui/button' @@ -9,12 +9,12 @@ import { useSetThemeContext, useThemeContext } from '../../context/theme' export const ThemeSelector = props => { const setTheme = useSetThemeContext() - const menuState = useDropdownMenuState({ gutter: 10 }) + const dropdownMenu = useDropdownMenu() const theme = useThemeContext() const handleSetTheme = theme => { setTheme(theme) - menuState.hide() + dropdownMenu.hide() } const options = [ @@ -26,17 +26,23 @@ export const ThemeSelector = props => { return ( <> - + - + {options?.map(({ icon: Icon, isBeta, label, value }) => ( handleSetTheme(value)} - state={menuState} > {label} diff --git a/docs/components/Header/index.js b/docs/components/Header/index.js index 70494b65d1..7d4ee087ac 100644 --- a/docs/components/Header/index.js +++ b/docs/components/Header/index.js @@ -1,9 +1,9 @@ -import React, { useEffect, useState } from 'react' +import React from 'react' import { Box } from '@welcome-ui/box' import { InformationIcon, MenuIcon } from '@welcome-ui/icons' import NextLink from 'next/link' -import { Drawer, useDrawerState } from '@welcome-ui/drawer' -import { useModalState } from '@welcome-ui/modal' +import { Drawer, useDrawer } from '@welcome-ui/drawer' +import { useModal } from '@welcome-ui/modal' import { Button } from '@welcome-ui/button' import { CrossIcon } from '@welcome-ui/icons' import { DocSearch } from '@docsearch/react' @@ -19,22 +19,16 @@ import * as S from './styles' import { NavBar } from './NavBar' export const Header = () => { - const mobileMenuDrawerState = useDrawerState() - const modalState = useModalState() + const mobileMenuDrawer = useDrawer() + const modal = useModal() const { pathname } = useRouter() const variants = { '/': 'gray', } const variant = variants[pathname] - const [hasBeenHydrated, setHasBeenHydrated] = useState(false) - - // Workaround for hydration warning UI for Reakit dialog (fix in ariakit 2.0) - useEffect(() => { - setHasBeenHydrated(true) - }, []) function openThemeHelper() { - modalState.show() + modal.show() } return ( @@ -54,32 +48,42 @@ export const Header = () => { placeholder="Search the docs" /> - - - {hasBeenHydrated && ( - <> - - {mobileMenuDrawerState.visible ? : } - - - - - mobileMenuDrawerState.hide()} /> - - - - )} - + <> + + {mobileMenuDrawer.open ? : } + + + + mobileMenuDrawer.hide()} /> + + + ) } diff --git a/docs/components/Header/styles.js b/docs/components/Header/styles.js index bee4b25797..01658007c6 100644 --- a/docs/components/Header/styles.js +++ b/docs/components/Header/styles.js @@ -44,7 +44,7 @@ export const Header = styled.header( ) export const MenuMobileDrawer = styled(WUIDrawer)` - top: ${`calc(${headerHeight} - 1px)`} !important; + margin-top: ${`calc(${headerHeight} - 1px)`} !important; width: 100% !important; padding: lg; diff --git a/docs/components/Homepage/Expectations.js b/docs/components/Homepage/Expectations.js index 0d84c3470d..51965ae893 100644 --- a/docs/components/Homepage/Expectations.js +++ b/docs/components/Homepage/Expectations.js @@ -42,7 +42,7 @@ const expectations = [ title: 'Accessibility', icon: UserIcon, description: - 'We are trying to offer an accessible experience as much as we can, using Reakit for instance.', + 'We are trying to offer an accessible experience as much as we can, using Ariakit for instance.', }, { title: 'Typing', diff --git a/docs/components/Mdx/Code/index.js b/docs/components/Mdx/Code/index.js index d95a44a55d..87100fec2c 100644 --- a/docs/components/Mdx/Code/index.js +++ b/docs/components/Mdx/Code/index.js @@ -11,7 +11,7 @@ import { yupResolver } from '@hookform/resolvers/yup' import dynamic from 'next/dynamic' // Welcome UI -import { Accordion } from '@welcome-ui/accordion' +import * as Accordion from '@welcome-ui/accordion' import { Alert } from '@welcome-ui/alert' import { AspectRatio } from '@welcome-ui/aspect-ratio' import { Avatar } from '@welcome-ui/avatar' @@ -121,7 +121,7 @@ export const Code = ({ language, transformCode: () => transformCode(editorCode, row), scope: { - Accordion, + ...Accordion, Alert, AspectRatio, Avatar, diff --git a/docs/components/Mdx/Code/styles.js b/docs/components/Mdx/Code/styles.js index 170f4adc5e..a25e57cbf3 100644 --- a/docs/components/Mdx/Code/styles.js +++ b/docs/components/Mdx/Code/styles.js @@ -19,6 +19,14 @@ export const LiveEditorContent = styled(ReactLiveEditor)( `} overflow-x: auto; + .inserted-sign { + color: sub-5 !important; + } + + .deleted-sign { + color: danger-300 !important; + } + textarea, pre { background-color: black !important; diff --git a/docs/components/Mdx/InlineCode.js b/docs/components/Mdx/InlineCode.js index 442d3a3796..bf04120162 100644 --- a/docs/components/Mdx/InlineCode.js +++ b/docs/components/Mdx/InlineCode.js @@ -4,6 +4,6 @@ export const InlineCode = styled.code` background-color: transparent; font-family: inherit; font-size: inherit; - font-weight: bold; - color: sub-3; + font-weight: medium; + color: sub-2; ` diff --git a/docs/components/Mdx/Showcase/index.js b/docs/components/Mdx/Showcase/index.js index 45d0a88e1c..1f3515d39c 100644 --- a/docs/components/Mdx/Showcase/index.js +++ b/docs/components/Mdx/Showcase/index.js @@ -21,7 +21,7 @@ export function Showcase({

- {pageName || component} + {component?.split(',')?.[0]}

{description && {description}} diff --git a/docs/components/ThemeHelper.js b/docs/components/ThemeHelper.js index 4d55ba8303..186de56da0 100644 --- a/docs/components/ThemeHelper.js +++ b/docs/components/ThemeHelper.js @@ -1,8 +1,8 @@ import { Box } from '@welcome-ui/box' import { Modal } from '@welcome-ui/modal' -import { Tab, useTabState } from '@welcome-ui/tabs' +import { Tab, useTab } from '@welcome-ui/tabs' import { Text } from '@welcome-ui/text' -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import { useThemeContext } from '../context/theme' @@ -10,21 +10,19 @@ import { ThemeConfiguration } from './ThemeConfiguration' const KEY_CODE_HELP = 'KeyI' -export const ThemeHelper = ({ modalState }) => { +export const ThemeHelper = ({ modalStore }) => { const currentTheme = useThemeContext() - const [hasBeenHydrated, setHasBeenHydrated] = useState(false) - const tabState = useTabState({ orientation: 'vertical' }) + const tab = useTab({ orientation: 'vertical' }) const categories = ['colors', 'space', 'screens', 'fontSizes', 'fontWeights'] const [defaultTab] = categories const title = `${currentTheme.at(0).toUpperCase()}${currentTheme.slice(1)} Theme` - // Workaround for hydration warning UI for Reakit dialog (fix in ariakit 2.0) useEffect(() => { - setHasBeenHydrated(true) - const onKeyboardEvent = event => { - if (event.metaKey && event.code === KEY_CODE_HELP) modal.show() + if (event.metaKey && event.code === KEY_CODE_HELP) { + modalStore.show() + } } window.addEventListener('keydown', onKeyboardEvent) @@ -33,49 +31,47 @@ export const ThemeHelper = ({ modalState }) => { }, []) useEffect(() => { - tabState.select(defaultTab) + tab.select(defaultTab) }, [currentTheme]) return ( <> - {hasBeenHydrated && ( - - - - - - - {categories.map(category => ( - - {category} - - ))} - - + + + + + + {categories.map(category => ( - - - - Key - - - Value - - - - + + {category} + ))} - - - - - )} + + + {categories.map(category => ( + + + + Key + + + Value + + + + + ))} + + + + ) } diff --git a/docs/package.json b/docs/package.json index 3158c98940..ebae9c648b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,7 +14,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/docs/pages/_app.js b/docs/pages/_app.js index adb2d21dfc..0e2ad6c541 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -1,6 +1,5 @@ /* eslint-disable react/display-name */ import React from 'react' -import { Provider } from 'reakit' import { ThemeProvider } from '../context/theme' import { App } from '../components/App' @@ -10,9 +9,7 @@ require('@welcome-ui/icons.font/fonts/welcome-icon-font.css') const NextApp = ({ Component, pageProps }) => { return ( - - - + ) } diff --git a/docs/pages/components/accordion.mdx b/docs/pages/components/accordion.mdx index 9628f260c2..e4048c41ea 100644 --- a/docs/pages/components/accordion.mdx +++ b/docs/pages/components/accordion.mdx @@ -17,40 +17,56 @@ import { ## About -Built with [Reakit](https://reakit.io/docs/disclosure/) for a better accessibility 🌈 +Built with [Ariakit](https://ariakit.org/components/disclosure) for a better accessibility 🌈 ## Usage ```jsx - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - - - - - - Accordion title - - - } -> - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - +function () { + const accordion = useAccordion() + const accordion2 = useAccordion() + + return ( + <> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + + + Accordion title + +
+ } + > + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + ) +} ``` -## Visible at start +## Open at start -Add `visible` property to open at start the accordion +Add `defaultOpen` options on `useAccordion` to open at start the accordion ```jsx - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris - nisi ut aliquip ex ea commodo consequat. - +function () { + const accordion = useAccordion({ defaultOpen: true }) + + return ( + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. + + ) +} ``` ## With a custom icon @@ -60,13 +76,32 @@ Customize the icon with a node element on property `icon` Note that the custom icon's size property will be set to small ```jsx -}> - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris - nisi ut aliquip ex ea commodo consequat. - +function () { + const accordion = useAccordion() + + return ( + }> + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. + + ) +} ``` +## useAccordion + +We use `useDisclosureStore` from [Ariakit Disclosure](https://ariakit.org/reference/use-disclosure-store) for the state of the accordion with the `animated` flag set to `true` by default. + +Pass options to `useAccordion`: + +- `defaultOpen`: e.g. `const accordion = useAccordion({ defaultOpen: true })` + +And the hook returns (among other things): + +- `useState('open')`: whether the accordion is currently open +- `hide`: a function to hide the accordion + ## Properties diff --git a/docs/pages/components/button.mdx b/docs/pages/components/button.mdx index 8981b9a37b..0f57c91452 100644 --- a/docs/pages/components/button.mdx +++ b/docs/pages/components/button.mdx @@ -17,7 +17,7 @@ import { ## About -Built with [Reakit](https://reakit.io/docs/button/) for a better accessibility 🥰 +Built with [Ariakit](https://ariakit.org/components/button) for a better accessibility 🥰 ## Variants diff --git a/docs/pages/components/drawer.mdx b/docs/pages/components/drawer.mdx index a3262bc920..7937f3cf6d 100644 --- a/docs/pages/components/drawer.mdx +++ b/docs/pages/components/drawer.mdx @@ -17,28 +17,25 @@ import { ## About -Drawer based on [Reakit's dialog](https://reakit.io/docs/dialog/) with a really nice theme 💅 +Drawer based on [Ariakit dialog](https://ariakit.org/components/dialog) with a really nice theme 💅 ## Usage -The most basic drawer needs `useDrawerState()`, ``, `` and ``. **Please note you have to wrap your `` with a ``**. If you don't want this `` to be visible, please provide it a `backdropVisible` prop set to `false`. Backdrop allows us to have a smooth scroll across all browsers by wrapping the Drawer. This way, the Drawer can be absolutely positioned in the fixed Backdrop wrapper. +The most basic drawer needs `useDrawer()`, `` and ``. If you don't want a backdrop to be visible, please provide it a `withBackdrop` prop set to `false`. Backdrop allows us to have a smooth scroll across all browsers by wrapping the Drawer. This way, the Drawer can be absolutely positioned in the fixed Backdrop wrapper. ```jsx function DefaultDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - + Open Drawer - - - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam - nec, convallis sit amet erat. Mauris auctor blandit porta. - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam + nec, convallis sit amet erat. Mauris auctor blandit porta. + ) } @@ -46,24 +43,21 @@ function DefaultDrawer() { ## Backdrop -You have to wrap `` with ``. It can be either visible or not, thanks to the `backdropVisible` prop (which is true by default). It corresponds to [Reakit Dialog's Backdrop](https://reakit.io/docs/dialog/#backdrop) with custom styling. +You have to add on `` a prop `withBackdrop`. This adds our backdrop `` on the drawer. You can also add a custom wrapper with the property `backdrop`. ```jsx function BackdropDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - - Open Drawer + + Open Drawer with backdrop - - - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam - nec, convallis sit amet erat. Mauris auctor blandit porta. - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam + nec, convallis sit amet erat. Mauris auctor blandit porta. + ) } @@ -71,30 +65,27 @@ function BackdropDrawer() { ## Layout -We provide basic layout components for your drawer: ``, ``, `` and ``. They're all optionnal. If you're using `` along with ``, please make sure to position `` first in your code, for styling purpose. +We provide basic layout components for your drawer: ``, `` and ``. They are all optional. By default, you have a close button `` that you can remove by setting the `withCloseButton` property to `false`. If you're using `` along with ``, please make sure to position `` first in your code for styling purposes. ```jsx function ContentDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - + Open Drawer - - - - Hello - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. - - - - - - + + Hello + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis + aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. + + + + + ) } @@ -106,7 +97,7 @@ By default the `placement` of the drawer will be on the `right` but you can set ```jsx function PlacementDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() const [placement, setPlacement] = React.useState('right') return ( @@ -115,7 +106,7 @@ function PlacementDrawer() { setPlacement(e.target.value)} + onChange={setPlacement} options={[ { value: 'top', label: 'Top' }, { value: 'right', label: 'Right' }, @@ -125,15 +116,13 @@ function PlacementDrawer() { />
- + Open Drawer - - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam + nec, convallis sit amet erat. Mauris auctor blandit porta. + ) } @@ -145,7 +134,7 @@ By default the `size` of the drawer will be `lg` which is set in the theme. We p ```jsx function SizeDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() const [size, setSize] = React.useState('lg') const [placement, setPlacement] = React.useState('right') @@ -155,7 +144,7 @@ function SizeDrawer() { setSize(e.target.value)} + onChange={setSize} options={[ { value: 'sm', label: 'sm' }, { value: 'md', label: 'md' }, @@ -176,7 +165,7 @@ function SizeDrawer() { setPlacement(e.target.value)} + onChange={setPlacement} options={[ { value: 'top', label: 'Top' }, { value: 'right', label: 'Right' }, @@ -186,15 +175,19 @@ function SizeDrawer() { /> - + Open Drawer - - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam + nec, convallis sit amet erat. Mauris auctor blandit porta. + ) } @@ -206,50 +199,53 @@ All the elements can be styled as you see fit, by extending drawer's theme or di ```jsx function StylingDrawer() { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - + Open Drawer - - - - - Hello - - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. - - - - - - - - - + + + + Hello + + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis + aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. + + + + + + + + ) } ``` -## useDrawerState +## useDrawer -We use `useDialogState` from [Reakit Dialog](https://reakit.io/docs/dialog/#usedialogstate) for the state of the drawer with the `animated` flag set to `true` by default. +We use `useDialogStore` from [Ariakit Dialog](https://ariakit.org/reference/use-dialog-store) for the state of the drawer with the `animated` flag set to `true` by default. -Pass options to `useDrawerState` : +Pass options to `useDrawer`: -- `visible`: e.g. `const modal = useDrawerState({ visible: true })` +- `defaultOpen`: e.g. `const drawer = useDrawer({ defaultOpen: true })` And the hook returns (among other things): -- `visible` : whether the drawer is currently visible -- `hide` : a function to hide the drawer +- `useState('open')`: whether the drawer is currently open +- `hide`: a function to hide the drawer ## Properties @@ -257,10 +253,6 @@ And the hook returns (among other things): -### Drawer.Backdrop - - - ## Packages ### Dependencies diff --git a/docs/pages/components/dropdown-menu.mdx b/docs/pages/components/dropdown-menu.mdx index 2e9eecd462..a410bf5737 100644 --- a/docs/pages/components/dropdown-menu.mdx +++ b/docs/pages/components/dropdown-menu.mdx @@ -10,7 +10,6 @@ import { { console.log(`Clicked on ${e.target.innerText}`) - dropdownMenuState.hide() + dropdownMenu.hide() } return ( <> - + Dropdown Menu - - + + Twitter - + Facebook - + Instagram - - + + Github @@ -62,11 +59,11 @@ function() { ```jsx function() { - const dropdownMenuState = useDropdownMenuState({ gutter: 10, placement: 'bottom-end' }) + const dropdownMenu = useDropdownMenu({ placement: 'bottom-end' }) const handleClick = e => { console.log(`Clicked on ${e.target.innerText}`) - dropdownMenuState.hide() + dropdownMenu.hide() } return ( @@ -76,16 +73,16 @@ function() { First Action - - {dropdownMenuState.open ? : } + + {dropdownMenu.open ? : } - - + + Second Action - + Third Action @@ -101,33 +98,31 @@ Use `DropdownMenu.Arrow` to add an arrow to the dropdown menu ```jsx function() { - const dropdownMenuState = useDropdownMenuState({ - gutter: 10 - }) + const dropdownMenu = useDropdownMenu() const handleClick = e => { console.log(`Clicked on ${e.target.innerText}`) - dropdownMenuState.hide() + dropdownMenu.hide() } return ( <> - + Dropdown Menu - - - + + + Twitter - + Facebook - + Instagram - - + + Github @@ -136,6 +131,19 @@ function() { } ``` +## useDropdownMenu + +We use `useMenuStore` from [Ariakit Menu](https://ariakit.org/reference/use-menu-store) for the state of the dropdown menu with the `animated` flag set to `true` by default. + +Pass options to `useDropdownMenu`: + +- `defaultOpen`: e.g. `const dropdownMenu = useDropdownMenu({ defaultOpen: true })` + +And the hook returns (among other things): + +- `useState('open')`: whether the dropdown menu is currently open +- `hide`: a function to hide the dropdown menu + ## Properties diff --git a/docs/pages/components/emoji-picker.mdx b/docs/pages/components/emoji-picker.mdx index 2f52474ac6..2f3a772ed5 100644 --- a/docs/pages/components/emoji-picker.mdx +++ b/docs/pages/components/emoji-picker.mdx @@ -17,9 +17,9 @@ import { ## About -EmojiPicker is a form element that extends [Popover](https://www.welcome-ui.com/components/popover) and [react-window](https://github.com/bvaughn/react-window) to efficiently render large list of images. +EmojiPicker is a form element that extends [Popover](popover) and [react-window](https://github.com/bvaughn/react-window) to efficiently render large lists of images. -It takes `value` & `onChange` props, its value being an emoji wrapped with colon, using the same pattern as Slack. The data is from [emoji-data](https://github.com/iamcal/emoji-data). +It takes `value` and `onChange` props, its value being an emoji wrapped with a colon, using the same pattern as Slack. The data is from [emoji-data](https://github.com/iamcal/emoji-data). ## Usage @@ -27,16 +27,16 @@ The most basic emoji picker needs `useEmojiPicker()`, `` ```jsx function Default() { - const emojiPickerState = useEmojiPicker() + const emojiPicker = useEmojiPicker() const [emoji, setEmoji] = React.useState() return ( <> - + {emoji ? : 'Open Emoji Picker'} - + ) } @@ -48,16 +48,16 @@ function Default() { ```jsx function Default() { - const emojiPickerState = useEmojiPicker() + const emojiPicker = useEmojiPicker() const [emoji, setEmoji] = React.useState(':dog:') return ( <> - + {emoji ? : 'Open Emoji Picker'} - + ) } @@ -65,27 +65,27 @@ function Default() { ## Tabs -`` can take multiple children that have to be instances of ``. They have a `name` prop which will be used for the content of the tab, their children will be the wrapped in `< Tab.Panel />`. `` also takes a `defaultTabState` prop that will be passed to `useTabState`, it can be useful to choose a default tab for instance. +`` can take multiple children that have to be instances of ``. They have a `name` prop, which will be used for the content of the tab; their children will be the wrapped in `< Tab.Panel />`. `` also takes a `defaultTabStore` prop that will be passed to `useTab` and can be useful to choose a default tab, for instance. ```jsx function Tabs() { - const emojiPickerState = useEmojiPicker() + const emojiPicker = useEmojiPicker() const [emoji, setEmoji] = React.useState() - const defaultTabState = { - selectedId: 'Second tab', + const defaultTabStore = { + defaultSelectedId: 'Second tab', } return ( <> - + {emoji ? : 'Open Emoji Picker'} @@ -122,7 +122,7 @@ All the field, with the expection of `url`, will be used for the search. ```jsx function Custom() { - const emojiPickerState = useEmojiPicker() + const emojiPicker = useEmojiPicker() const [emoji, setEmoji] = React.useState() const emojis = [ @@ -141,7 +141,7 @@ function Custom() { return ( <> - + {currentEmoji ? ( ) : ( @@ -149,7 +149,7 @@ function Custom() { )} - + @@ -165,16 +165,16 @@ When using `` witjout children, it will automatically add ` - + {emoji ? : 'Open Emoji Picker'} - + @@ -191,7 +191,7 @@ function BasicList() { value={emoji} onChange={e => setEmoji(e.target.value)} /> - + @@ -206,16 +206,16 @@ You can set some props on `` & `` to change s ```jsx function BasicList() { - const emojiPickerState = useEmojiPicker() + const emojiPicker = useEmojiPicker() const [emoji, setEmoji] = React.useState() return ( <> - + {emoji ? : "Ouvrir l'Emoji Picker"} - + @@ -225,6 +225,14 @@ function BasicList() { } ``` +## useEmojiPicker + +We use `usePopover` from [Popover](popover). + +Pass options to `useEmojiPicker` : + +- `defaultOpen`: e.g. `const emojiPicker = useEmojiPicker({ defaultOpen: true })` + ## Properties ### EmojiPicker diff --git a/docs/pages/components/modal.mdx b/docs/pages/components/modal.mdx index aa43232b89..759cdc0cfa 100644 --- a/docs/pages/components/modal.mdx +++ b/docs/pages/components/modal.mdx @@ -17,33 +17,33 @@ import { ## About -Modal from [Reakit](https://reakit.io/docs/dialog/) with a really nice theme 👀 +Modal from [Ariakit dialog](https://ariakit.org/components/dialog) with a really nice theme 👀 ## Usage -Use `useModalState`, `Modal`, `Modal.Trigger` and `Modal.Body` to create a simple Modal. To ensure good spacing between modal's sub-components, they must be wrapped with `Modal.Content`. +Use `useModal`, `Modal`, `Modal.Trigger` and `Modal.Body` to create a simple Modal. To ensure good spacing between modal's sub-components, they must be wrapped with `Modal.Content`. ```jsx function() { - const modalState = useModalState() + const modal = useModal() return ( <> - + Open modal - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum - nunc. Integer suscipit sodales ex, ut lobortis orci rutrum id. Vestibulum scelerisque, - felis ut sollicitudin elementum, dolor nibh faucibus orci, eu aliquet felis diam sed - eros. Donec eget sapien lacinia, viverra felis in, placerat urna. Vestibulum sed viverra - orci. Donec id tellus eget dui porta lobortis ac eu metus. Praesent id ultricies odio. - In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur - quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu - ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. + aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum + nunc. Integer suscipit sodales ex, ut lobortis orci rutrum id. Vestibulum scelerisque, + felis ut sollicitudin elementum, dolor nibh faucibus orci, eu aliquet felis diam sed + eros. Donec eget sapien lacinia, viverra felis in, placerat urna. Vestibulum sed viverra + orci. Donec id tellus eget dui porta lobortis ac eu metus. Praesent id ultricies odio. + In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur + quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu + ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. @@ -58,28 +58,28 @@ By default size is set to `lg`. If you don't want a size (fit on content), set s ```jsx function() { - const modalState = useModalState() + const modal = useModal() const [size, setSize] = React.useState() return ( - setSize('xs')}> + setSize('xs')}> xs - setSize('sm')}> + setSize('sm')}> sm - setSize('md')}> + setSize('md')}> md - setSize('lg')}> + setSize('lg')}> lg - setSize('auto')}> + setSize('auto')}> auto - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum @@ -104,9 +104,9 @@ Use `Modal.Header` and `Modal.Footer` to style your Modal. ```jsx function() { - const modalState = useModalState() - const modalState2 = useModalState() - const modalState3 = useModalState() + const modal = useModal() + const modal2 = useModal() + const modal3 = useModal() const title = "Nullam non lacinia" const subtitle = "Praesent sit amet quam ac velit faucibus dapibus, quisque sapien ligula." const icon = @@ -117,33 +117,148 @@ function() { return ( - - + + Example modal - - + + - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum - nunc. Integer suscipit sodales ex, ut lobortis orci rutrum id. Vestibulum scelerisque, - felis ut sollicitudin elementum, dolor nibh faucibus orci, eu aliquet felis diam sed - eros. Donec eget sapien lacinia, viverra felis in, placerat urna. Vestibulum sed viverra - orci. Donec id tellus eget dui porta lobortis ac eu metus. Praesent id ultricies odio. - In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur - quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu - ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. - - Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis - aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum - nunc. Integer suscipit sodales ex, ut lobortis orci rutrum id. Vestibulum scelerisque, - felis ut sollicitudin elementum, dolor nibh faucibus orci, eu aliquet felis diam sed - eros. Donec eget sapien lacinia, viverra felis in, placerat urna. Vestibulum sed viverra - orci. Donec id tellus eget dui porta lobortis ac eu metus. Praesent id ultricies odio. - In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur - quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu - ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pretium leo orci, sed + finibus justo iaculis non. Quisque scelerisque congue feugiat. Vivamus ac accumsan odio. + Suspendisse potenti. Morbi scelerisque condimentum ex vitae convallis. Sed egestas + pulvinar tellus, eget sagittis dolor sagittis quis. Donec convallis lorem iaculis, + vulputate risus sit amet, faucibus ligula. Nulla et leo eros. Vestibulum sagittis bibendum + cursus. Integer iaculis laoreet eleifend. Aliquam et purus finibus, convallis nisi in, + cursus eros. Quisque tellus tortor, feugiat quis pretium tristique, accumsan in libero. + Integer tristique risus eu felis malesuada commodo. Aliquam sed egestas enim. Aenean a + ultricies enim, quis blandit augue. Nam consectetur ligula in auctor ornare. Etiam posuere + hendrerit mauris, rhoncus elementum leo. Ut non erat quis orci ultrices viverra ac id + libero. Sed eget sem ut sem pretium posuere. Aenean orci erat, faucibus nec enim aliquam, + faucibus pretium lacus. Nulla eu tincidunt orci. Sed bibendum tempus pulvinar. Duis + elementum justo et mattis elementum. Nullam non odio sodales, ornare purus at, vulputate + mauris. Sed venenatis metus dui, quis bibendum nulla tincidunt faucibus. Morbi + sollicitudin magna at odio fermentum maximus. Pellentesque scelerisque hendrerit risus, + eget cursus felis tincidunt ac. Sed vestibulum blandit posuere. Donec accumsan pulvinar + felis in feugiat. Morbi vel diam consequat, pulvinar nisi in, efficitur nisi. Morbi luctus + tempor est a bibendum. Phasellus vitae nisi nunc. Vestibulum ante ipsum primis in faucibus + orci luctus et ultrices posuere cubilia curae; Donec posuere nec nibh at mattis. Curabitur + odio turpis, egestas non ligula ac, ultricies vulputate augue. Phasellus a neque vitae + velit mattis tempor. Nunc nulla massa, porta at nisl ac, consequat lobortis arcu. Aliquam + blandit nibh ut tincidunt bibendum. Maecenas mollis dolor sed sapien tincidunt, ac + molestie dolor laoreet. Integer scelerisque dui risus, sed convallis mi bibendum quis. + Donec luctus vel mauris sit amet feugiat. Etiam nec lorem in purus ultricies convallis. + Quisque tristique, leo quis suscipit aliquet, nisi nisl euismod sapien, eu porttitor nunc + odio eu nisl. Nam ut nibh ut augue volutpat congue. Nam hendrerit ut libero eget + porttitor. In dictum neque erat, in vestibulum sapien tincidunt nec. In vestibulum odio + dignissim, ultricies lorem at, tincidunt nunc. Mauris rutrum orci nec malesuada commodo. + Nam maximus diam dapibus, suscipit odio vel, blandit magna. Aenean in arcu sit amet enim + facilisis hendrerit vitae quis justo. In mollis molestie mi malesuada semper. Donec + pellentesque erat vitae est dictum rutrum. Pellentesque habitant morbi tristique senectus + et netus et malesuada fames ac turpis egestas. Nam sagittis sagittis sapien, at posuere + diam viverra ut. Praesent eu facilisis nisi, at efficitur velit. In commodo purus libero, + non imperdiet nisi mollis non.Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Nullam pretium leo orci, sed finibus justo iaculis non. Quisque scelerisque congue + feugiat. Vivamus ac accumsan odio. Suspendisse potenti. Morbi scelerisque condimentum ex + vitae convallis. Sed egestas pulvinar tellus, eget sagittis dolor sagittis quis. Donec + convallis lorem iaculis, vulputate risus sit amet, faucibus ligula. Nulla et leo eros. + Vestibulum sagittis bibendum cursus. Integer iaculis laoreet eleifend. Aliquam et purus + finibus, convallis nisi in, cursus eros. Quisque tellus tortor, feugiat quis pretium + tristique, accumsan in libero. Integer tristique risus eu felis malesuada commodo. Aliquam + sed egestas enim. Aenean a ultricies enim, quis blandit augue. Nam consectetur ligula in + auctor ornare. Etiam posuere hendrerit mauris, rhoncus elementum leo. Ut non erat quis + orci ultrices viverra ac id libero. Sed eget sem ut sem pretium posuere. Aenean orci erat, + faucibus nec enim aliquam, faucibus pretium lacus. Nulla eu tincidunt orci. Sed bibendum + tempus pulvinar. Duis elementum justo et mattis elementum. Nullam non odio sodales, ornare + purus at, vulputate mauris. Sed venenatis metus dui, quis bibendum nulla tincidunt + faucibus. Morbi sollicitudin magna at odio fermentum maximus. Pellentesque scelerisque + hendrerit risus, eget cursus felis tincidunt ac. Sed vestibulum blandit posuere. Donec + accumsan pulvinar felis in feugiat. Morbi vel diam consequat, pulvinar nisi in, efficitur + nisi. Morbi luctus tempor est a bibendum. Phasellus vitae nisi nunc. Vestibulum ante ipsum + primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec posuere nec nibh + at mattis. Curabitur odio turpis, egestas non ligula ac, ultricies vulputate augue. + Phasellus a neque vitae velit mattis tempor. Nunc nulla massa, porta at nisl ac, consequat + lobortis arcu. Aliquam blandit nibh ut tincidunt bibendum. Maecenas mollis dolor sed + sapien tincidunt, ac molestie dolor laoreet. Integer scelerisque dui risus, sed convallis + mi bibendum quis. Donec luctus vel mauris sit amet feugiat. Etiam nec lorem in purus + ultricies convallis. Quisque tristique, leo quis suscipit aliquet, nisi nisl euismod + sapien, eu porttitor nunc odio eu nisl. Nam ut nibh ut augue volutpat congue. Nam + hendrerit ut libero eget porttitor. In dictum neque erat, in vestibulum sapien tincidunt + nec. In vestibulum odio dignissim, ultricies lorem at, tincidunt nunc. Mauris rutrum orci + nec malesuada commodo. Nam maximus diam dapibus, suscipit odio vel, blandit magna. Aenean + in arcu sit amet enim facilisis hendrerit vitae quis justo. In mollis molestie mi + malesuada semper. Donec pellentesque erat vitae est dictum rutrum. Pellentesque habitant + morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam sagittis + sagittis sapien, at posuere diam viverra ut. Praesent eu facilisis nisi, at efficitur + velit. In commodo purus libero, non imperdiet nisi mollis non.Lorem ipsum dolor sit amet, + consectetur adipiscing elit. Nullam pretium leo orci, sed finibus justo iaculis non. + Quisque scelerisque congue feugiat. Vivamus ac accumsan odio. Suspendisse potenti. Morbi + scelerisque condimentum ex vitae convallis. Sed egestas pulvinar tellus, eget sagittis + dolor sagittis quis. Donec convallis lorem iaculis, vulputate risus sit amet, faucibus + ligula. Nulla et leo eros. Vestibulum sagittis bibendum cursus. Integer iaculis laoreet + eleifend. Aliquam et purus finibus, convallis nisi in, cursus eros. Quisque tellus tortor, + feugiat quis pretium tristique, accumsan in libero. Integer tristique risus eu felis + malesuada commodo. Aliquam sed egestas enim. Aenean a ultricies enim, quis blandit augue. + Nam consectetur ligula in auctor ornare. Etiam posuere hendrerit mauris, rhoncus elementum + leo. Ut non erat quis orci ultrices viverra ac id libero. Sed eget sem ut sem pretium + posuere. Aenean orci erat, faucibus nec enim aliquam, faucibus pretium lacus. Nulla eu + tincidunt orci. Sed bibendum tempus pulvinar. Duis elementum justo et mattis elementum. + Nullam non odio sodales, ornare purus at, vulputate mauris. Sed venenatis metus dui, quis + bibendum nulla tincidunt faucibus. Morbi sollicitudin magna at odio fermentum maximus. + Pellentesque scelerisque hendrerit risus, eget cursus felis tincidunt ac. Sed vestibulum + blandit posuere. Donec accumsan pulvinar felis in feugiat. Morbi vel diam consequat, + pulvinar nisi in, efficitur nisi. Morbi luctus tempor est a bibendum. Phasellus vitae nisi + nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia + curae; Donec posuere nec nibh at mattis. Curabitur odio turpis, egestas non ligula ac, + ultricies vulputate augue. Phasellus a neque vitae velit mattis tempor. Nunc nulla massa, + porta at nisl ac, consequat lobortis arcu. Aliquam blandit nibh ut tincidunt bibendum. + Maecenas mollis dolor sed sapien tincidunt, ac molestie dolor laoreet. Integer scelerisque + dui risus, sed convallis mi bibendum quis. Donec luctus vel mauris sit amet feugiat. Etiam + nec lorem in purus ultricies convallis. Quisque tristique, leo quis suscipit aliquet, nisi + nisl euismod sapien, eu porttitor nunc odio eu nisl. Nam ut nibh ut augue volutpat congue. + Nam hendrerit ut libero eget porttitor. In dictum neque erat, in vestibulum sapien + tincidunt nec. In vestibulum odio dignissim, ultricies lorem at, tincidunt nunc. Mauris + rutrum orci nec malesuada commodo. Nam maximus diam dapibus, suscipit odio vel, blandit + magna. Aenean in arcu sit amet enim facilisis hendrerit vitae quis justo. In mollis + molestie mi malesuada semper. Donec pellentesque erat vitae est dictum rutrum. + Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis + egestas. Nam sagittis sagittis sapien, at posuere diam viverra ut. Praesent eu facilisis + nisi, at efficitur velit. In commodo purus libero, non imperdiet nisi mollis non.Lorem + ipsum dolor sit amet, consectetur adipiscing elit. Nullam pretium leo orci, sed finibus + justo iaculis non. Quisque scelerisque congue feugiat. Vivamus ac accumsan odio. + Suspendisse potenti. Morbi scelerisque condimentum ex vitae convallis. Sed egestas + pulvinar tellus, eget sagittis dolor sagittis quis. Donec convallis lorem iaculis, + vulputate risus sit amet, faucibus ligula. Nulla et leo eros. Vestibulum sagittis bibendum + cursus. Integer iaculis laoreet eleifend. Aliquam et purus finibus, convallis nisi in, + cursus eros. Quisque tellus tortor, feugiat quis pretium tristique, accumsan in libero. + Integer tristique risus eu felis malesuada commodo. Aliquam sed egestas enim. Aenean a + ultricies enim, quis blandit augue. Nam consectetur ligula in auctor ornare. Etiam posuere + hendrerit mauris, rhoncus elementum leo. Ut non erat quis orci ultrices viverra ac id + libero. Sed eget sem ut sem pretium posuere. Aenean orci erat, faucibus nec enim aliquam, + faucibus pretium lacus. Nulla eu tincidunt orci. Sed bibendum tempus pulvinar. Duis + elementum justo et mattis elementum. Nullam non odio sodales, ornare purus at, vulputate + mauris. Sed venenatis metus dui, quis bibendum nulla tincidunt faucibus. Morbi + sollicitudin magna at odio fermentum maximus. Pellentesque scelerisque hendrerit risus, + eget cursus felis tincidunt ac. Sed vestibulum blandit posuere. Donec accumsan pulvinar + felis in feugiat. Morbi vel diam consequat, pulvinar nisi in, efficitur nisi. Morbi luctus + tempor est a bibendum. Phasellus vitae nisi nunc. Vestibulum ante ipsum primis in faucibus + orci luctus et ultrices posuere cubilia curae; Donec posuere nec nibh at mattis. Curabitur + odio turpis, egestas non ligula ac, ultricies vulputate augue. Phasellus a neque vitae + velit mattis tempor. Nunc nulla massa, porta at nisl ac, consequat lobortis arcu. Aliquam + blandit nibh ut tincidunt bibendum. Maecenas mollis dolor sed sapien tincidunt, ac + molestie dolor laoreet. Integer scelerisque dui risus, sed convallis mi bibendum quis. + Donec luctus vel mauris sit amet feugiat. Etiam nec lorem in purus ultricies convallis. + Quisque tristique, leo quis suscipit aliquet, nisi nisl euismod sapien, eu porttitor nunc + odio eu nisl. Nam ut nibh ut augue volutpat congue. Nam hendrerit ut libero eget + porttitor. In dictum neque erat, in vestibulum sapien tincidunt nec. In vestibulum odio + dignissim, ultricies lorem at, tincidunt nunc. Mauris rutrum orci nec malesuada commodo. + Nam maximus diam dapibus, suscipit odio vel, blandit magna. Aenean in arcu sit amet enim + facilisis hendrerit vitae quis justo. In mollis molestie mi malesuada semper. Donec + pellentesque erat vitae est dictum rutrum. Pellentesque habitant morbi tristique senectus + et netus et malesuada fames ac turpis egestas. Nam sagittis sagittis sapien, at posuere + diam viverra ut. Praesent eu facilisis nisi, at efficitur velit. In commodo purus libero, + non imperdiet nisi mollis non. @@ -154,11 +269,11 @@ function() { - + Example modal 2 - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis @@ -184,17 +299,17 @@ function() { - + - + Example modal 3 - - + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis @@ -206,6 +321,16 @@ function() { In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. + + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis + aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. In imperdiet rutrum + nunc. Integer suscipit sodales ex, ut lobortis orci rutrum id. Vestibulum scelerisque, + felis ut sollicitudin elementum, dolor nibh faucibus orci, eu aliquet felis diam sed + eros. Donec eget sapien lacinia, viverra felis in, placerat urna. Vestibulum sed viverra + orci. Donec id tellus eget dui porta lobortis ac eu metus. Praesent id ultricies odio. + In hac habitasse platea dictumst. Sed lorem lacus, hendrerit non sodales id, consectetur + quis magna. Nullam non lacinia risus, ut varius est. Nam nec pulvinar tellus, eu + ultrices elit. Cras tincidunt et purus eu condimentum. Nunc vitae consequat nibh. @@ -215,19 +340,19 @@ function() { } ``` -## useModalState +## useModal -We use `useDialogState` from [Reakit Dialog](https://reakit.io/docs/dialog/#usedialogstate) for the state of the modal. +We use `useDialogStore` from [Ariakit Dialog](https://ariakit.org/reference/use-dialog-store) for the state of the modal. -Pass options to `useModalState` : +Pass options to `useModal`: -- `visible`: e.g. `const modal = useModalState({ visible: true })` -- `onClose`: e.g. `const modal = useModalState({ onClose: () => console.log('closing the modal') })` +- `defaultOpen`: e.g. `const modal = useModal({ defaultOpen: true })` +- `onClose`: e.g. `const modal = useModal({ onClose: () => console.log('closing the modal') })` And the hook returns (among other things): -- `visible` : whether the modal is currently visible -- `hide` : a function to hide the modal +- `useState('open')`: whether the modal is currently open +- `hide`: a function to hide the modal ## Properties diff --git a/docs/pages/components/popover.mdx b/docs/pages/components/popover.mdx index 60eed5a77a..aec213b9d8 100644 --- a/docs/pages/components/popover.mdx +++ b/docs/pages/components/popover.mdx @@ -10,7 +10,6 @@ import { - + Open Popover - + Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis aliquam nec, convallis sit amet erat. Mauris auctor blandit porta. @@ -50,14 +49,14 @@ Use `Popover.Title` props to create a predefined title block. ```jsx function() { - const popoverState = usePopoverState({ placement: 'top' }) + const popover = usePopover({ placement: 'top' }) return ( <> - + Open Popover - + Amazing title Praesent sit amet quam ac velit faucibus dapibus. Quisque sapien ligula, rutrum quis @@ -75,14 +74,14 @@ function() { ```jsx function() { - const popoverState = usePopoverState({ withCloseButton: true }) + const popover = usePopover({ withCloseButton: true }) return ( <> - + Open Popover - + Amazing title Praesent sit amet quam ac velit faucibus dapibus.
@@ -97,18 +96,18 @@ function() { ## Hover to open -Use `triggerMethod='hover'` on `usePopoverState` to open and close the popover by hovering it. +Use `triggerMethod: 'hover'` on `usePopover` to open and close the popover by hovering it. ```jsx function() { - const popoverState = usePopoverState({ triggerMethod: 'hover' }) + const popover = usePopover({ triggerMethod: 'hover' }) return ( <> - + Open Popover - + Amazing title Praesent sit amet quam ac velit faucibus dapibus.
@@ -121,15 +120,15 @@ function() { } ``` -## usePopoverState +## usePopover -We use `usePopoverState` from [Reakit Popover](https://reakit.io/docs/popover/#usepopoverstate) for the state of the popover. +We use `usePopover` from [Ariakit Popover](https://ariakit.org/reference/use-popover-store) for the state of the popover. -Pass options to `usePopoverState` : +Pass options to `usePopover`: -- `visible`: e.g. `const popover = usePopoverState({ visible: true })` -- `triggerMethod` : `click` or `hover` -- `withCloseButton` : `bool`, show/hide cross to close popover +- `defaultOpen`: e.g. `const popover = usePopover({ defaultOpen: true })` +- `triggerMethod`: `click` or `hover` +- `withCloseButton`: `bool`, show/hide cross to close popover When `triggerMethod` is set to hover @@ -138,9 +137,8 @@ When `triggerMethod` is set to hover And the hook returns (among other things): -- `visible` : whether the popover is currently visible -- `hide` : a function to hide the popover -- for the others options, go to [Reakit Popover](https://reakit.io/docs/popover/#usepopoverstate) +- `useState('open')`: whether the popover is currently open +- `hide`: a function to hide the popover ## Properties diff --git a/docs/pages/components/radio-group.mdx b/docs/pages/components/radio-group.mdx index e242eb63f3..90c48f842d 100644 --- a/docs/pages/components/radio-group.mdx +++ b/docs/pages/components/radio-group.mdx @@ -21,16 +21,12 @@ import { function () { const [value, setValue] = React.useState('github') - const handleChange = event => { - setValue(event.target.value) - } - return ( - + ) } @@ -44,17 +40,13 @@ Add flexDirection to `row` to Field to add the inline style for radios group function () { const [value, setValue] = React.useState('github') - const handleChange = event => { - setValue(event.target.value) - } - return ( - + ) } @@ -102,10 +94,6 @@ function () { function () { const [value, setValue] = React.useState(null) - const handleChange = event => { - setValue(event.target.value) - } - return ( diff --git a/docs/pages/components/radio-tab.mdx b/docs/pages/components/radio-tab.mdx index ac57e5f3fd..329b79c372 100644 --- a/docs/pages/components/radio-tab.mdx +++ b/docs/pages/components/radio-tab.mdx @@ -19,15 +19,11 @@ import { ```jsx function () { - const [value, setValue] = React.useState('twitter') - - const handleChange = event => { - setValue(event.target.value) - } + const [value, setValue] = React.useState('behance') return ( - + ) } @@ -37,15 +33,11 @@ function () { ```jsx function () { - const [value, setValue] = React.useState('twitter') - - const handleChange = event => { - setValue(event.target.value) - } + const [value, setValue] = React.useState('behance') return ( - + ) } diff --git a/docs/pages/components/tabs.mdx b/docs/pages/components/tabs.mdx index bc1d19bf29..5e6216a4ca 100644 --- a/docs/pages/components/tabs.mdx +++ b/docs/pages/components/tabs.mdx @@ -10,7 +10,6 @@ import { - - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab 4 - + Tab 5 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 - + Tab.Panel 4 - + Tab.Panel 5 @@ -73,49 +72,49 @@ Size is set on Tab.List. Available sizes are `sm` and `md`. By default size is s ```jsx function() { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3
- - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 @@ -129,40 +128,40 @@ The border on `Tab.List` is an inset shadow that you can customize or disable vi ```jsx function() { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab 4 - + Tab 5 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 - + Tab.Panel 4 - + Tab.Panel 5 @@ -176,19 +175,21 @@ Add badges, icons and images in tab. ```jsx function() { - const tabState = useTabState({ selectedId: 'tab2' }) - const getVariant = item => (tabState.selectedId === item ? 'primary' : 'default') + const tab = useTab({ defaultSelectedId: 'tab2' }) + const selectedId = tab.useState('selectedId') + + const getVariant = item => (selectedId === item ? 'primary' : 'default') return ( <> - - + + Tab 1 new - + Tab 2 old @@ -197,25 +198,25 @@ function() { 2 - + Tab 3 - + Tab 4 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 - + Tab.Panel 4 @@ -229,28 +230,28 @@ Use another component in tab. ```jsx function() { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 @@ -264,16 +265,16 @@ Active bar doesn't display with only one tab. ```jsx function() { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Tab.Panel 1 @@ -287,34 +288,34 @@ Set the tab orientation by providing the `orientation` prop to the tab state ```jsx function() { - const tabState = useTabState({ orientation: 'vertical', selectedId: 'tab2' }) + const tab = useTab({ orientation: 'vertical', defaultSelectedId: 'tab2' }) return ( - - + + Tab 1 - + Tab 2 - + Tab 3 - + Tab 4 - + Tab.Panel 1 - + Tab.Panel 2 - + Tab.Panel 3 - + Tab.Panel 4 @@ -322,6 +323,14 @@ function() { } ``` +## useTab + +We use `useTab` from [Ariakit Tab](https://ariakit.org/reference/use-tab-store) for the state of the Tab. + +Pass options to `useTab`: + +- `defaultSelectedId`: e.g. `const store = useTab({ defaultSelectedId: 'tab2' })` + ## Properties ### Tab diff --git a/docs/pages/components/toast.mdx b/docs/pages/components/toast.mdx index 576f4d82e7..311c9718d2 100644 --- a/docs/pages/components/toast.mdx +++ b/docs/pages/components/toast.mdx @@ -10,7 +10,6 @@ import { ``` -Maybe you don't want the tooltip to follow the cursor… +Maybe you don't want the tooltip to follow the cursor set by `fixed` property ```jsx @@ -39,6 +39,7 @@ Set a `max-width` for long text ```jsx lorem ipsum dolor sit amet, consectetur adipiscing elit} > @@ -51,14 +52,14 @@ Set a `max-width` for long text We're adding a wrapper around the button when it's disabled otherwise the tooltip does not trigger. ```jsx - + ``` -## With a fixed position +## Placement -Using the `fixed` prop in combination with `placement` will enable a translate animation on your tooltip. The direction works with these values for `placement`. +Using only with the `fixed` prop, `placement` will enable a translate animation on your tooltip. The direction works with these values for `placement`. ```jsx diff --git a/docs/pages/index.js b/docs/pages/index.js index 0d86528d90..2414aa53b6 100644 --- a/docs/pages/index.js +++ b/docs/pages/index.js @@ -25,7 +25,7 @@ export default function Home() { Welcome UI is a customizable design system library made with react, typescript, - styled-components, reakit and a lot of love 💛 + styled-components, ariakit and a lot of love 💛 ) - const button = getByTestId('button') + + render() + + const button = screen.getByTestId('button') expect(button).toHaveTextContent(content) expect(button).not.toBeDisabled() @@ -24,13 +26,14 @@ describe(' ) - const eventElement = getByText(content) + const eventElement = screen.getByText(content) fireEvent.click(eventElement) expect(onClick).toHaveBeenCalledTimes(1) @@ -38,12 +41,13 @@ describe(' ) - const button = getByTestId('button') + const button = screen.getByTestId('button') expect(button).toHaveStyleRule('width', theme.buttons.sizes.sm.height) expect(button).toHaveStyleRule('height', theme.buttons.sizes.sm.height) @@ -51,12 +55,13 @@ describe(' ) - const button = getByTestId('button') + const button = screen.getByTestId('button') expect(button).toHaveStyleRule('height', theme.buttons.sizes.sm.height) }) @@ -64,13 +69,14 @@ describe(' ) - const eventElement = getByText(content) + const eventElement = screen.getByText(content) fireEvent.click(eventElement) expect(onClick).toHaveBeenCalledTimes(0) @@ -78,13 +84,14 @@ describe(' ) - const button = getByTestId('button') + const button = screen.getByTestId('button') expect(button).toBeDisabled() expect(button).toHaveStyleRule('background-color', theme.colors['nude-400']) @@ -93,37 +100,39 @@ describe(' ) - const button = getByTestId('button') + const button = screen.getByTestId('button') + expect(button.tagName.toLowerCase()).toBe('div') }) it('should forward as a', () => { - const { getByTestId } = render( + render( ) - const button = getByTestId('button') + const button = screen.getByTestId('button') expect(button.tagName.toLowerCase()).toBe('a') expect(button).toHaveAttribute('href', content) }) it('should forward as Link', () => { - const { getByTestId } = render( + render( ) - const button = getByTestId('button') + const button = screen.getByTestId('button') + expect(button.tagName.toLowerCase()).toBe('a') expect(button).toHaveClass('wui-test') expect(button).toHaveAttribute('rel', 'noopener noreferrer') // added by target="_blank" on Link @@ -131,15 +140,17 @@ describe(' ) - const button = getByTestId('button') - const icon = getByTestId('icon-sun') + const button = screen.getByTestId('button') + const icon = screen.getByTestId('icon-sun') + expect(button).toHaveStyleRule('height', theme.buttons.sizes.sm.height) expect(icon).toHaveStyle({ width: theme.buttons.icon.default.sm, @@ -150,14 +161,16 @@ describe(' ) - const button = getByTestId('button') - const icon = getByTestId('icon-sun') + const button = screen.getByTestId('button') + const icon = screen.getByTestId('icon-sun') + expect(button).toHaveStyleRule('height', theme.buttons.sizes.md.height) expect(icon).toHaveStyle({ width: theme.buttons.icon.only.md, @@ -168,15 +181,17 @@ describe(' ) - const button = getByTestId('button') - const icon = getByTestId('icon-font-sun') + const button = screen.getByTestId('button') + const icon = screen.getByTestId('icon-font-sun') + expect(button).toHaveStyleRule('height', theme.buttons.sizes.sm.height) expect(icon).toHaveStyle({ width: theme.buttons.icon.default.sm, @@ -187,14 +202,16 @@ describe(' ) - const button = getByTestId('button') - const icon = getByTestId('icon-font-sun') + const button = screen.getByTestId('button') + const icon = screen.getByTestId('icon-font-sun') + expect(button).toHaveStyleRule('height', theme.buttons.sizes.md.height) expect(icon).toHaveStyle({ width: theme.buttons.icon.only.md, diff --git a/packages/ButtonGroup/package.json b/packages/ButtonGroup/package.json index cb870d956e..8a9069168e 100644 --- a/packages/ButtonGroup/package.json +++ b/packages/ButtonGroup/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Card/package.json b/packages/Card/package.json index d1208fb97f..073421a77d 100644 --- a/packages/Card/package.json +++ b/packages/Card/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/card", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Checkbox/package.json b/packages/Checkbox/package.json index 944f1bc681..c3c4cf5c8f 100644 --- a/packages/Checkbox/package.json +++ b/packages/Checkbox/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/checkbox", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,9 +46,9 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Checkbox/src/styles.ts b/packages/Checkbox/src/styles.ts index d042042603..b829bd1ec2 100644 --- a/packages/Checkbox/src/styles.ts +++ b/packages/Checkbox/src/styles.ts @@ -1,5 +1,5 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { Checkbox as ReakitCheckbox } from 'reakit' +import * as Ariakit from '@ariakit/react' import { shouldForwardProp } from '@welcome-ui/system' import { defaultFieldStyles } from '@welcome-ui/utils' @@ -7,7 +7,7 @@ import { CheckboxProps } from './index' /* /!\ WARNING /!\ Don't add style after pseudo selector, it won't apply because of the dynamic color injected in the fill of the content */ -export const Checkbox = styled(ReakitCheckbox).withConfig({ +export const Checkbox = styled(Ariakit.Checkbox).withConfig({ shouldForwardProp, })( ({ indeterminate, order = '-1', size, theme, variant }) => css` diff --git a/packages/Checkbox/tests/index.test.tsx b/packages/Checkbox/tests/index.test.tsx index b0fac6edde..068c4bd78d 100644 --- a/packages/Checkbox/tests/index.test.tsx +++ b/packages/Checkbox/tests/index.test.tsx @@ -1,10 +1,10 @@ import React, { useState } from 'react' -import { fireEvent } from '@testing-library/react' +import { fireEvent, screen } from '@testing-library/react' import { render } from '../../../utils/tests' import { Checkbox, CheckboxOptions } from '../src' -const CheckboxWrapper: React.FC = props => { +const CheckboxWrapper = (props: CheckboxOptions) => { const [value, setValue] = useState(false) const handleChange = () => { @@ -22,15 +22,27 @@ const CheckboxWrapper: React.FC = props => { ) } -test(' toggles on input click', () => { - const { getByTestId } = render() - const checkbox = getByTestId('checkbox') +describe('', () => { + test('should toggle checked attribute on click', () => { + render() + const checkbox = screen.getByTestId('checkbox') - expect(checkbox.getAttribute('aria-checked')).toBe('false') + expect(checkbox.getAttribute('aria-checked')).toBe('false') - fireEvent.click(checkbox) - expect(checkbox.getAttribute('aria-checked')).toBe('true') + fireEvent.click(checkbox) + expect(checkbox.getAttribute('aria-checked')).toBe('true') - fireEvent.click(checkbox) - expect(checkbox.getAttribute('aria-checked')).toBe('false') + fireEvent.click(checkbox) + expect(checkbox.getAttribute('aria-checked')).toBe('false') + }) + + test('should do nothing on click on disabled checkbox', () => { + render() + const checkbox = screen.getByTestId('checkbox') + + expect(checkbox.getAttribute('aria-checked')).toBe('false') + + fireEvent.click(checkbox) + expect(checkbox.getAttribute('aria-checked')).toBe('false') + }) }) diff --git a/packages/ClearButton/package.json b/packages/ClearButton/package.json index c47a5fa1c6..b5ea82f075 100644 --- a/packages/ClearButton/package.json +++ b/packages/ClearButton/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/clear-button", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/CloseButton/package.json b/packages/CloseButton/package.json index 8eb17a68bf..daa3866892 100644 --- a/packages/CloseButton/package.json +++ b/packages/CloseButton/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/close-button", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Copy/package.json b/packages/Copy/package.json index d64ac8fe08..61e37cdf96 100644 --- a/packages/Copy/package.json +++ b/packages/Copy/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/utils.copy", "version": "5.0.0-alpha.37", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -31,7 +31,7 @@ "clipboard", "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Core/package.json b/packages/Core/package.json index af5638a34b..3e8fab3508 100644 --- a/packages/Core/package.json +++ b/packages/Core/package.json @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Core/src/theme/drawers.ts b/packages/Core/src/theme/drawers.ts index 2d7fb6354a..2e00c7018f 100644 --- a/packages/Core/src/theme/drawers.ts +++ b/packages/Core/src/theme/drawers.ts @@ -27,10 +27,7 @@ export const getDrawers = (theme: WuiTheme): ThemeDrawers => { default: { zIndex: 999, }, - closeButton: { - marginRight: `${space.xl}`, - marginTop: `${space.xl}`, - }, + closeButton: {}, title: { margin: 0, backgroundColor: colors['light-900'], diff --git a/packages/Core/src/theme/modals.ts b/packages/Core/src/theme/modals.ts index 0f5cb8657c..991c361e67 100644 --- a/packages/Core/src/theme/modals.ts +++ b/packages/Core/src/theme/modals.ts @@ -39,7 +39,6 @@ export const getModals = (theme: WuiTheme): ThemeModals => { }, body: { color: colors['dark-900'], - paddingTop: space.xxl, paddingRight: space['3xl'], paddingBottom: space.xxl, paddingLeft: space.xxl, diff --git a/packages/DatePicker/package.json b/packages/DatePicker/package.json index f4ffb493b7..bc887caca6 100644 --- a/packages/DatePicker/package.json +++ b/packages/DatePicker/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/date-picker", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/DateTimePicker/package.json b/packages/DateTimePicker/package.json index a929d05ff6..27209fed5d 100644 --- a/packages/DateTimePicker/package.json +++ b/packages/DateTimePicker/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/date-time-picker", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/DateTimePickerCommon/package.json b/packages/DateTimePickerCommon/package.json index a24e132f90..61fbfeeb47 100644 --- a/packages/DateTimePickerCommon/package.json +++ b/packages/DateTimePickerCommon/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/date-time-picker-common", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Drawer/package.json b/packages/Drawer/package.json index e9e1045046..f01ccb5229 100644 --- a/packages/Drawer/package.json +++ b/packages/Drawer/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/drawer", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,12 +46,12 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/close-button": "^5.0.0-alpha.43", "@welcome-ui/system": "^5.0.0-alpha.40", "@welcome-ui/text": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Drawer/src/Close.tsx b/packages/Drawer/src/Close.tsx new file mode 100644 index 0000000000..fbaa60a722 --- /dev/null +++ b/packages/Drawer/src/Close.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import * as Ariakit from '@ariakit/react' +import { CloseButtonProps } from '@welcome-ui/close-button' +import { useTheme } from '@xstyled/styled-components' +import { Box } from '@welcome-ui/box' + +import * as S from './styles' + +export type CloseProps = Ariakit.DialogDismissProps & CloseButtonProps + +export const Close: React.FC = ({ zIndex = '2', ...props }) => { + const theme = useTheme() + + return ( + + + } + /> + + ) +} diff --git a/packages/Drawer/src/Content.tsx b/packages/Drawer/src/Content.tsx new file mode 100644 index 0000000000..dfcbb0a873 --- /dev/null +++ b/packages/Drawer/src/Content.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import { BoxProps } from '@welcome-ui/box' + +import * as S from './styles' + +export const Content: React.FC = props => { + return +} diff --git a/packages/Drawer/src/Footer.tsx b/packages/Drawer/src/Footer.tsx new file mode 100644 index 0000000000..f05f288430 --- /dev/null +++ b/packages/Drawer/src/Footer.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import { BoxProps } from '@welcome-ui/box' + +import * as S from './styles' + +export const Footer: React.FC = props => { + return ( + + ) +} diff --git a/packages/Drawer/src/Title.tsx b/packages/Drawer/src/Title.tsx new file mode 100644 index 0000000000..d240b586b0 --- /dev/null +++ b/packages/Drawer/src/Title.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { Text, TextProps } from '@welcome-ui/text' + +import * as S from './styles' + +export const Title: React.FC = ({ children, zIndex = '1', ...props }) => { + return ( + + + {children} + + + ) +} diff --git a/packages/Drawer/src/index.tsx b/packages/Drawer/src/index.tsx index 0b0e523d79..bdd5709192 100644 --- a/packages/Drawer/src/index.tsx +++ b/packages/Drawer/src/index.tsx @@ -1,170 +1,87 @@ -import React, { cloneElement } from 'react' -import { - Dialog, - DialogBackdropProps, - DialogDisclosure, - DialogInitialState, - DialogOptions, - DialogProps, - DialogStateReturn, - useDialogState, -} from 'reakit' -import { Box, BoxProps } from '@welcome-ui/box' -import { CloseButtonProps } from '@welcome-ui/close-button' -import { Text, TextProps } from '@welcome-ui/text' -import { As, CreateWuiProps, forwardRef, OmitReakitState } from '@welcome-ui/system' - +import React from 'react' +import * as Ariakit from '@ariakit/react' +import { As, CreateWuiProps, forwardRef } from '@welcome-ui/system' + +import { Close } from './Close' +import { Content } from './Content' +import { Footer } from './Footer' +import { Title } from './Title' import * as S from './styles' export type Placement = 'top' | 'right' | 'bottom' | 'left' export type Size = 'sm' | 'md' | 'lg' | 'auto' | string -export interface DrawerOptions { +export interface DrawerOptions extends Ariakit.DialogProps { placement?: Placement size?: Size - state: DialogStateReturn + withBackdrop?: boolean + withCloseButton?: boolean } -export type DrawerProps = CreateWuiProps<'div', OmitReakitState> +export type DrawerProps = CreateWuiProps<'div', DrawerOptions> const DrawerComponent = forwardRef<'div', DrawerProps>( - ({ as, children, placement = 'right', size = 'lg', state, ...rest }, ref) => { + ( + { + children, + hideOnInteractOutside = true, + placement = 'right', + size = 'lg', + store, + withBackdrop = false, + withCloseButton = true, + ...rest + }, + ref + ) => { return ( - // Needed to allow to style the backdrop - // see: https://reakit.io/docs/styling/#css-in-js - - {props => ( - - {children} - - )} - + : false + } + hideOnInteractOutside={hideOnInteractOutside} + modal={withBackdrop} + ref={ref} + render={} + store={store} + {...rest} + > + <> + {withCloseButton && } + {children} + + ) } ) -export type DrawerStateReturn = DialogStateReturn & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: DialogStateReturn['visible'] - open: DialogStateReturn['visible'] -} -export type DrawerInitialState = DialogInitialState & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: DialogInitialState['visible'] - /** - * Open the drawer on load - */ - open?: DialogInitialState['visible'] -} +export type DrawerStoreReturn = Ariakit.DialogStore +export type DrawerStoreProps = Ariakit.DialogStoreProps -export function useDrawerState(options?: DrawerInitialState): DrawerStateReturn { - const { open, visible, ...restOptions } = options || {} - const dialogState = useDialogState({ animated: true, visible: visible || open, ...restOptions }) +export function useDrawer(options: DrawerStoreProps = {}): DrawerStoreReturn { + const dialog = Ariakit.useDialogStore({ animated: true, ...options }) - return { open: dialogState.visible, ...dialogState } + return dialog } export interface DrawerBackdropOptions { - hideOnClickOutside?: boolean - backdropVisible?: boolean - state: DialogBackdropProps - children: React.ReactElement + hideOnInteractOutside?: boolean } -export type DrawerBackdropProps = DrawerBackdropOptions - -// Needed to allow to style the backdrop -// see: https://reakit.io/docs/styling/#css-in-js /** * @name Drawer.Backdrop */ -export const DrawerBackdrop: React.FC = ({ - backdropVisible = true, - children, - hideOnClickOutside = true, - state, - ...rest +export const DrawerBackdrop: React.FC = ({ + hideOnInteractOutside = true, + ...props }) => { - const Wrapper = backdropVisible ? S.Backdrop : S.NoBackdropWrapper - const placement = children?.props?.placement || 'right' - const size = children?.props?.size || 'lg' - const optionalWrapperProps = { - size, - placement, - } - - return ( - - {cloneElement(children, { hideOnClickOutside })} - - ) -} - -export type CloseOptions = { state: DialogProps } -export type CloseProps = CloseOptions & CloseButtonProps - -export const Close: React.FC = ({ state, zIndex = '2', ...props }) => { - const { hide } = state - - return ( - - - - ) -} - -export const Title: React.FC = ({ children, zIndex = '1', ...props }) => { - return ( - - - {children} - - - ) -} - -export const Content: React.FC = props => { - return -} - -export const Footer: React.FC = props => { - return ( - - ) + return } -type TriggerProps = { state: DialogStateReturn; children: React.ReactNode; as?: As } +type TriggerProps = { store: Ariakit.DialogStore; children: React.ReactNode; as?: As } -export const Trigger = forwardRef<'button', TriggerProps>(({ as, state, ...rest }, ref) => { - return +export const Trigger = forwardRef<'button', TriggerProps>(({ as, store, ...rest }, ref) => { + return }) export const Drawer = Object.assign(DrawerComponent, { diff --git a/packages/Drawer/src/styles.ts b/packages/Drawer/src/styles.ts index f34840c399..f09d29cb5f 100644 --- a/packages/Drawer/src/styles.ts +++ b/packages/Drawer/src/styles.ts @@ -1,43 +1,10 @@ -import styled, { css, th } from '@xstyled/styled-components' +import styled, { css, system, th } from '@xstyled/styled-components' import { cardStyles } from '@welcome-ui/utils' import { CloseButton as WUICloseButton } from '@welcome-ui/close-button' -import { DialogBackdrop } from 'reakit' +import * as Ariakit from '@ariakit/react' import { DrawerOptions, Placement, Size } from '.' -type DrawerWrapperProps = { - hideOnClickOutside: boolean - placement?: Placement - size?: Size -} - -export const Backdrop = styled(DialogBackdrop).withConfig({ - shouldForwardProp: prop => !['hideOnClickOutside'].includes(prop), -})( - ({ hideOnClickOutside }) => css` - ${th('drawers.backdrop')}; - display: flex; - align-items: center; - justify-content: center; - position: fixed; - top: 0; - right: 0; - left: 0; - bottom: 0; - opacity: 0; - transition: fast; - ${hideOnClickOutside && - css` - cursor: pointer; - `} - - /* on open dialog for animation */ - &[data-enter] { - opacity: 1; - } - ` -) - const getPlacementStyle = (placement: Placement) => { switch (placement) { case 'top': @@ -45,7 +12,6 @@ const getPlacementStyle = (placement: Placement) => { top: '0 !important', right: 0, left: 0, - // Used for animation transform: 'translateY(-100%)', } case 'right': @@ -73,6 +39,7 @@ const getPlacementStyle = (placement: Placement) => { } const SIZES = ['sm', 'md', 'lg'] + const getSizeStyle = (size: Size, placement: Placement) => { switch (placement) { case 'top': @@ -94,29 +61,22 @@ const getSizeStyle = (size: Size, placement: Placement) => { } } -export const Drawer = styled.box( +export const Drawer = styled.divBox>( ({ placement, size }) => css` ${cardStyles}; ${th('drawers.default')}; ${getPlacementStyle(placement)} ${getSizeStyle(size, placement)} - position: absolute; + position: fixed; display: flex; flex-direction: column; - max-width: 100%; - max-height: 100%; + flex-direction: column; + overflow: auto; + opacity: 0; transition: medium; - cursor: auto; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - - &:focus { - /* important for firefox */ - outline: none !important; - } - /* on open/close dialog for animation */ &[data-enter] { + opacity: 1; transform: translate(0, 0); } @@ -126,75 +86,43 @@ export const Drawer = styled.box( ` ) -const getBackdropWrapperPlacementStyle = (placement: Placement) => { - switch (placement) { - case 'top': - return { - top: 0, - right: 0, - left: 0, - } - case 'right': - return { - top: 0, - right: 0, - bottom: 0, - } - case 'bottom': - return { - right: 0, - bottom: 0, - left: 0, - } - case 'left': - return { - top: 0, - bottom: 0, - left: 0, - } - } -} - -export const NoBackdropWrapper = styled(DialogBackdrop).withConfig({ - shouldForwardProp: prop => !['hideOnClickOutside'].includes(prop), -})( - ({ hideOnClickOutside, placement, size }) => css` +export const Backdrop = styled.div.withConfig({ + shouldForwardProp: prop => !['hideOnInteractOutside'].includes(prop), +})<{ hideOnInteractOutside: Ariakit.DialogProps['hideOnInteractOutside'] }>( + ({ hideOnInteractOutside }) => css` ${th('drawers.backdrop')}; - ${getBackdropWrapperPlacementStyle(placement)} - ${getSizeStyle(size, placement)} - background-color: transparent; - display: flex; - align-items: center; - justify-content: center; position: fixed; - max-width: 100%; - max-height: 100%; + top: 0; + right: 0; + left: 0; + bottom: 0; opacity: 0; - transition: fast; - ${hideOnClickOutside && + transition: opacity 150ms ease-in-out; + ${system}; + + ${hideOnInteractOutside && css` cursor: pointer; `} - /* on open dialog for animation */ &[data-enter] { opacity: 1; } ` ) -export const Title = styled.box` - ${({ theme }) => theme.drawers.title} +export const Title = styled.divBox` + ${th('drawers.title')}; ` -export const Content = styled.box` - ${({ theme }) => theme.drawers.content} +export const Content = styled.divBox` + ${th('drawers.content')}; ` export const CloseButton = styled(WUICloseButton)` - ${({ theme }) => theme.drawers.closeButton} + ${th('drawers.closeButton')}; ` -export const Footer = styled.box` - ${({ theme }) => theme.drawers.footer} +export const Footer = styled.divBox` + ${th('drawers.footer')}; ` diff --git a/packages/Drawer/tests/index.test.tsx b/packages/Drawer/tests/index.test.tsx index 18f29b837d..c60bf4a153 100644 --- a/packages/Drawer/tests/index.test.tsx +++ b/packages/Drawer/tests/index.test.tsx @@ -2,17 +2,17 @@ import React from 'react' import { fireEvent } from '@testing-library/react' import { render } from '../../../utils/tests' -import { Drawer, useDrawerState } from '../src' +import { Drawer, useDrawer } from '../src' describe('', () => { it('should render correctly', () => { const Test = () => { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - open - + open + test @@ -27,12 +27,12 @@ describe('', () => { it('should render its size & placement correctly', () => { const Test = () => { - const drawerState = useDrawerState() + const drawer = useDrawer() return ( <> - open - + open + test @@ -46,14 +46,15 @@ describe('', () => { it('should render "as" correctly', () => { const Test = () => { - const drawerState = useDrawerState() + const drawer = useDrawer() + const onClick = jest.fn() return ( <> - null} state={drawerState}> + open - + test diff --git a/packages/DropdownMenu/README.md b/packages/DropdownMenu/README.md index 96d89bc525..e7d77caac7 100644 --- a/packages/DropdownMenu/README.md +++ b/packages/DropdownMenu/README.md @@ -10,7 +10,7 @@ The [DropdownMenu](https://welcome-ui.com/components/dropdown-menu) component fr ## Import - import { DropdownMenu, useDropdownMenuState } from '@welcome-ui/dropdown-menu' + import { DropdownMenu, useDropdownMenu } from '@welcome-ui/dropdown-menu' ## Documentation diff --git a/packages/DropdownMenu/package.json b/packages/DropdownMenu/package.json index 9bbae1f7d1..67d6a14b0d 100644 --- a/packages/DropdownMenu/package.json +++ b/packages/DropdownMenu/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,10 +46,10 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", @@ -58,6 +58,6 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "DropdownMenu, useDropdownMenuState", + "component": "DropdownMenu, useDropdownMenu", "homepage": "https://welcome-ui.com/components/dropdown-menu" } diff --git a/packages/DropdownMenu/src/Arrow.styled.ts b/packages/DropdownMenu/src/Arrow.styled.ts index dad17fe5fe..54ffb03b5c 100644 --- a/packages/DropdownMenu/src/Arrow.styled.ts +++ b/packages/DropdownMenu/src/Arrow.styled.ts @@ -1,10 +1,10 @@ import styled, { css, th } from '@xstyled/styled-components' -import { MenuArrow } from 'reakit' -export const Arrow = styled(MenuArrow)` +export const Arrow = styled.divBox` display: flex; z-index: 2; color: ${th('defaultCards.backgroundColor')}; + stroke-width: 0 !important; #stroke { color: ${th('defaultCards.borderColor')}; diff --git a/packages/DropdownMenu/src/Arrow.tsx b/packages/DropdownMenu/src/Arrow.tsx index 4a2af0c70f..69c7debe3f 100644 --- a/packages/DropdownMenu/src/Arrow.tsx +++ b/packages/DropdownMenu/src/Arrow.tsx @@ -1,11 +1,9 @@ import React from 'react' -import { MenuArrowOptions } from 'reakit' +import * as Ariakit from '@ariakit/react' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './Arrow.styled' -import { DropdownMenuOptions } from '.' - const transformMap: Record = { top: 'rotateZ(180deg)', right: 'rotateZ(-90deg)', @@ -13,22 +11,16 @@ const transformMap: Record = { left: 'rotateZ(90deg)', } -export type ArrowProps = CreateWuiProps< - 'div', - MenuArrowOptions & { state: DropdownMenuOptions['state'] } -> +export type ArrowProps = CreateWuiProps<'div', Ariakit.MenuArrowProps> -export const Arrow = forwardRef<'div', ArrowProps>(({ state, ...rest }, ref) => { - // get the correct transform style for arrow - const { placement } = state - // get the parent placement (top, bottom...) - const [parentPlacement] = placement.split('-') - const transform = transformMap[parentPlacement] +export const Arrow = forwardRef<'div', ArrowProps>(({ store }, ref) => { + const currentPlacement = store?.useState('currentPlacement') + const [placement] = currentPlacement.split('-') return ( - + }> (({ state, ...rest }, ref) => - + ) }) diff --git a/packages/DropdownMenu/src/Item.styled.ts b/packages/DropdownMenu/src/Item.styled.ts index 54902f93a1..c894443dc1 100644 --- a/packages/DropdownMenu/src/Item.styled.ts +++ b/packages/DropdownMenu/src/Item.styled.ts @@ -12,11 +12,6 @@ export const Item = styled.button` text-decoration: none; padding: md; - &[type='button'] { - appearance: none; - } - - &:hover, &:focus { outline: none !important; /* important for firefox */ } diff --git a/packages/DropdownMenu/src/Item.tsx b/packages/DropdownMenu/src/Item.tsx index 28a877be12..51ea7d9e8e 100644 --- a/packages/DropdownMenu/src/Item.tsx +++ b/packages/DropdownMenu/src/Item.tsx @@ -1,28 +1,13 @@ import React from 'react' -import { MenuItem, MenuItemProps } from 'reakit' +import * as Ariakit from '@ariakit/react' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './Item.styled' -import { DropdownMenuOptions } from '.' +export type ItemProps = CreateWuiProps<'button', Ariakit.MenuItemProps> -type ItemOptions = Pick & - Partial> - -export type ItemProps = CreateWuiProps<'button', ItemOptions> - -export const Item = forwardRef<'button', ItemProps>(({ as, children, state, ...rest }, ref) => { - return ( - - {menuItemProps => { - return ( - - {children} - - ) - }} - - ) +export const Item = forwardRef<'button', ItemProps>(({ as, ...rest }, ref) => { + return } /> }) Item.displayName = 'Item' diff --git a/packages/DropdownMenu/src/Separator.tsx b/packages/DropdownMenu/src/Separator.tsx index 3dded533d7..f991438b23 100644 --- a/packages/DropdownMenu/src/Separator.tsx +++ b/packages/DropdownMenu/src/Separator.tsx @@ -1,16 +1,11 @@ import React from 'react' -import { MenuSeparator, MenuSeparatorProps } from 'reakit' +import * as Ariakit from '@ariakit/react' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './Separator.styled' -import { DropdownMenuOptions } from '.' +export type SeparatorProps = CreateWuiProps<'div', Ariakit.MenuSeparatorProps> -export type SeparatorProps = CreateWuiProps< - 'div', - MenuSeparatorProps & { state: DropdownMenuOptions['state'] } -> - -export const Separator = forwardRef<'div', SeparatorProps>(({ state, ...rest }, ref) => { - return +export const Separator = forwardRef<'div', SeparatorProps>((props, ref) => { + return }) diff --git a/packages/DropdownMenu/src/index.tsx b/packages/DropdownMenu/src/index.tsx index addedf5517..b8995d231e 100644 --- a/packages/DropdownMenu/src/index.tsx +++ b/packages/DropdownMenu/src/index.tsx @@ -1,108 +1,61 @@ import React from 'react' -import { - MenuButton, - MenuInitialState, - MenuOptions, - MenuStateReturn, - Menu as ReakitMenu, - useMenuState, -} from 'reakit' -import { useNextFrame } from '@welcome-ui/utils' -import { As, CreateWuiProps, forwardRef, OmitReakitState, WuiProps } from '@welcome-ui/system' +import * as Ariakit from '@ariakit/react' +import { As, CreateWuiProps, forwardRef, WuiProps } from '@welcome-ui/system' import { Arrow } from './Arrow' import { Item } from './Item' import { Separator } from './Separator' import * as S from './styles' -export interface DropdownMenuOptions { +export interface DropdownMenuOptions extends Ariakit.MenuProps { /** add custom props from styled system on DropdownMenu inner */ innerProps?: WuiProps - state: MenuStateReturn & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: MenuOptions['visible'] - /** - * Open the menu on load - */ - open?: MenuOptions['visible'] - } } -export type DropdownMenuProps = CreateWuiProps< - 'div', - OmitReakitState -> +export type DropdownMenuProps = CreateWuiProps<'div', DropdownMenuOptions> const DropdownMenuComponent = forwardRef<'div', DropdownMenuProps>( - ({ children, dataTestId, innerProps = {}, state = {}, ...props }, ref) => { - const { open, visible } = state - const delayedVisible = useNextFrame(open || visible) + ({ children, dataTestId, innerProps = {}, store, gutter = 10, ...rest }, ref) => { + const arrowElement = store.useState('arrowElement') + const isOpen = store.useState('open') return ( - - {menuProps => ( - )} - style={{ - ...menuProps.style, - opacity: delayedVisible ? 1 : 0, - }} - > - {children} - - )} - + isOpen && ( + } + store={store} + tabIndex={0} + {...rest} + > + {children} + + ) ) } ) -export type DropdownMenuStateReturn = MenuStateReturn & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: MenuStateReturn['visible'] - open: MenuStateReturn['visible'] -} -export type DropdownMenuInitialState = MenuInitialState & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: MenuInitialState['visible'] - /** - * Open the drawer on load - */ - open?: MenuInitialState['visible'] -} +export type UseDropdownMenu = Ariakit.MenuStore +export type UseDropdownMenuState = Ariakit.MenuStoreState +export type UseDropdownMenuOptions = Ariakit.MenuStoreProps -export function useDropdownMenuState(options?: DropdownMenuInitialState): DropdownMenuStateReturn { - const { open, visible, ...restOptions } = options || {} - const dropdownMenuState = useMenuState({ +export function useDropdownMenu(options: UseDropdownMenuOptions = {}): UseDropdownMenu { + const dropdownMenu = Ariakit.useMenuStore({ animated: true, - visible: visible || open, - ...restOptions, + ...options, }) - return { open: dropdownMenuState.visible, ...dropdownMenuState } + return dropdownMenu } -type TriggerProps = { state: MenuStateReturn; children: React.ReactNode; as?: As } +type TriggerProps = { store: UseDropdownMenu; children: React.ReactNode; as?: As } -export const Trigger = forwardRef<'button', TriggerProps>(({ as, state, ...rest }, ref) => { - return +export const Trigger = forwardRef<'button', TriggerProps>(({ as, store, ...rest }, ref) => { + return }) export const DropdownMenu = Object.assign(DropdownMenuComponent, { diff --git a/packages/DropdownMenu/src/styles.ts b/packages/DropdownMenu/src/styles.ts index e81020906c..3ef17639b8 100644 --- a/packages/DropdownMenu/src/styles.ts +++ b/packages/DropdownMenu/src/styles.ts @@ -6,15 +6,11 @@ export const Inner = styled(Box)` ${cardStyles}; ${th('dropdownMenu.inner')}; z-index: 1; - transition: opacity 200ms; + opacity: 0; + transition: opacity 150ms ease-in-out; + ${system}; - &:focus { - outline: none !important; /* important for firefox */ + &[data-enter] { + opacity: 1; } - - &[hidden] { - display: none; - } - - ${system} ` diff --git a/packages/DropdownMenu/tests/index.test.tsx b/packages/DropdownMenu/tests/index.test.tsx index 229328a306..f5fb06e28f 100644 --- a/packages/DropdownMenu/tests/index.test.tsx +++ b/packages/DropdownMenu/tests/index.test.tsx @@ -2,7 +2,7 @@ import React from 'react' import { renderHook } from '@testing-library/react-hooks' import { render } from '../../../utils/tests' -import { DropdownMenu, useDropdownMenuState } from '../src' +import { DropdownMenu, useDropdownMenu } from '../src' const content = 'jungle' @@ -10,11 +10,11 @@ describe('', () => { it('should render correctly', () => { const dataTestId = 'dropdownMenu' const { - result: { current: menuState }, - } = renderHook(() => useDropdownMenuState()) + result: { current: dropdownMenu }, + } = renderHook(() => useDropdownMenu({ open: true })) const { getByTestId } = render( - + {content} ) diff --git a/packages/Emoji/package.json b/packages/Emoji/package.json index 79ae3e76ae..0f5286614e 100644 --- a/packages/Emoji/package.json +++ b/packages/Emoji/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/emoji", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -31,7 +31,7 @@ "emoji", "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/EmojiPicker/package.json b/packages/EmojiPicker/package.json index 5ba793dfc1..0f827e0943 100644 --- a/packages/EmojiPicker/package.json +++ b/packages/EmojiPicker/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/emoji-picker", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -69,6 +69,6 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "EmojiPicker", + "component": "EmojiPicker, useEmojiPicker", "homepage": "https://welcome-ui.com/components/emoji-picker" } diff --git a/packages/EmojiPicker/src/List.tsx b/packages/EmojiPicker/src/List.tsx index 577ecc1037..87589e016e 100644 --- a/packages/EmojiPicker/src/List.tsx +++ b/packages/EmojiPicker/src/List.tsx @@ -32,7 +32,7 @@ export interface ListOptions { emojis: Emoji[] emptyList: React.ReactNode inputSearchPlaceholder: string - isVisible: boolean + isOpen: boolean onChange: (value: string) => void value: string } @@ -43,7 +43,7 @@ export const List: React.FC = ({ emojis, emptyList, inputSearchPlaceholder, - isVisible, + isOpen, onChange, value, }) => { @@ -52,10 +52,10 @@ export const List: React.FC = ({ const inputRef = useRef(null) useEffect(() => { - if (isVisible) { + if (isOpen) { inputRef?.current?.focus() } - }, [isVisible]) + }, [isOpen]) const [query, setQuery] = useState() const handleChangeQuery = useCallback((e: React.ChangeEvent) => { @@ -203,7 +203,7 @@ export const List: React.FC = ({ const isJustOpened = useRef(true) const listRef = useRef>() useIsomorphicLayoutEffect(() => { - if (!isVisible || !listRef.current) return + if (!isOpen || !listRef.current) return let rowIndex = currentRowIndex // Show the value on open @@ -223,15 +223,15 @@ export const List: React.FC = ({ const align = isJustOpened.current ? 'start' : 'auto' listRef.current.scrollToItem(index, align) isJustOpened.current = false - }, [currentColIndex, currentRowIndex, isVisible]) + }, [currentColIndex, currentRowIndex, isOpen]) const initialScrollOffset = useMemo(() => { - if (!isVisible) return 0 + if (!isOpen) return 0 // We can't use `currentPosition[0]` directly because we would skip the categories const index = rows.findIndex(emojis => emojis.some(emoji => emoji.rowIndex === currentRowIndex)) return index * ROW_HEIGHT - }, [currentRowIndex, isVisible, rows]) + }, [currentRowIndex, isOpen, rows]) return ( @@ -255,7 +255,7 @@ export const List: React.FC = ({ rows, currentColIndex, currentRowIndex, - isVisible, + isOpen, onClick: onChange, onMouseMove: handleMouseMove, }} @@ -280,7 +280,7 @@ interface EmojiRowData { rows: InternalEmoji[][] currentRowIndex: number currentColIndex: number - isVisible: boolean + isOpen: boolean onClick: (alias: string) => void onMouseMove: (emoji: InternalEmoji) => void } @@ -313,7 +313,7 @@ const EmojiRow: React.FC = ({ data, index, style }) => { const alias = getEmojiAlias(emoji) // We want `null` instead of false to prevent to add the attribute to be in the DOM const isActive = - data.isVisible && + data.isOpen && emoji.rowIndex === data.currentRowIndex && emoji.colIndex === data.currentColIndex ? true diff --git a/packages/EmojiPicker/src/index.tsx b/packages/EmojiPicker/src/index.tsx index da8d80f97b..402df64418 100644 --- a/packages/EmojiPicker/src/index.tsx +++ b/packages/EmojiPicker/src/index.tsx @@ -1,15 +1,14 @@ import React, { Children, cloneElement, useCallback, useMemo } from 'react' -import { useTabState } from '@welcome-ui/tabs' +import { Tab, useTab } from '@welcome-ui/tabs' import { Popover, - PopoverOptions, - usePopoverState, - UsePopoverStateOptions, - UsePopoverStateReturn, + UsePopover, + usePopover, + UsePopoverProps, + UsePopoverState, } from '@welcome-ui/popover' -import { Tab } from '@welcome-ui/tabs' -import { TabInitialState } from 'reakit' -import { CreateWuiProps, forwardRef, OmitReakitState } from '@welcome-ui/system' +import { CreateWuiProps, forwardRef } from '@welcome-ui/system' +import * as Ariakit from '@ariakit/react' import * as S from './styles' import { List } from './List' @@ -18,39 +17,39 @@ import { BasicList } from './BasicList' import { EmojiTab, EmojiTabProps } from './Tab' export interface EmojiPickerOptions { - defaultTabState?: TabInitialState + defaultTabStore?: Ariakit.TabStoreProps emptyList?: string inputSearchPlaceholder?: string onChange?: (value: string) => void popoverAriaLabel?: string tabListAriaLabel?: string value: string | null - state: UsePopoverStateReturn + store: UseEmojiPicker } -export type EmojiPickerProps = CreateWuiProps< - 'div', - OmitReakitState -> +export type EmojiPickerProps = CreateWuiProps<'div', EmojiPickerOptions> const EmojiPickerComponent = forwardRef<'div', EmojiPickerProps>( ( { children, - defaultTabState = {}, + defaultTabStore = {}, emptyList = 'No emojis found for your query 😔', inputSearchPlaceholder = 'Search an emoji', onChange, popoverAriaLabel = 'Emoji picker', tabListAriaLabel = 'Emoji picker tabs', value, - state, + store, }, ref ) => { - const tabState = useTabState(defaultTabState) + const tab = useTab(defaultTabStore) + + const hidePopover = useMemo(() => store.hide, [store.hide]) + const isOpen = store.useState('open') + const tabSelectedId = tab.useState('selectedId') - const hidePopover = useMemo(() => state.hide, [state.hide]) const handleChange = useCallback( (value: string) => { hidePopover() @@ -68,7 +67,7 @@ const EmojiPickerComponent = forwardRef<'div', EmojiPickerProps>( // Disabling type check since missing props are injected below with the "cloneElement" // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - + ), }, ] @@ -88,8 +87,7 @@ const EmojiPickerComponent = forwardRef<'div', EmojiPickerProps>( content: cloneElement(child, { emptyList, inputSearchPlaceholder, - isVisible: - state.visible && (!tabState.selectedId || tabState.selectedId === tab.props.name), + isVisible: isOpen && (!tabSelectedId || tabSelectedId === tab.props.name), onChange: handleChange, value, ...child.props, @@ -102,32 +100,24 @@ const EmojiPickerComponent = forwardRef<'div', EmojiPickerProps>( content: tab.props.children, } }) - }, [ - children, - emptyList, - handleChange, - inputSearchPlaceholder, - state.visible, - tabState.selectedId, - value, - ]) + }, [children, emptyList, handleChange, inputSearchPlaceholder, isOpen, tabSelectedId, value]) const hasTabs = tabs.length > 1 const onlyTabContent = tabs[0].content return ( - + {hasTabs && ( <> - - {tabs.map(tab => ( - - {tab.name} + + {tabs.map(item => ( + + {item.name} ))} - {tabs.map(tab => ( - - {tab.content} + {tabs.map(item => ( + + {item.content} ))} @@ -140,8 +130,12 @@ const EmojiPickerComponent = forwardRef<'div', EmojiPickerProps>( EmojiPickerComponent.displayName = 'EmojiPicker' -export function useEmojiPicker(options?: UsePopoverStateOptions): UsePopoverStateReturn { - return usePopoverState({ +export type UseEmojiPicker = UsePopover +export type UseEmojiPickerProps = UsePopoverProps +export type UseEmojiPickerState = UsePopoverState + +export function useEmojiPicker(options?: UseEmojiPickerProps): UseEmojiPicker { + return usePopover({ placement: 'bottom-start', ...options, }) diff --git a/packages/EmojiPicker/src/styles.ts b/packages/EmojiPicker/src/styles.ts index d4771d9267..4538e93516 100644 --- a/packages/EmojiPicker/src/styles.ts +++ b/packages/EmojiPicker/src/styles.ts @@ -1,9 +1,9 @@ import styled, { system, th } from '@xstyled/styled-components' import { Tab } from '@welcome-ui/tabs' -import { Popover as WUIPopover } from '@welcome-ui/popover' +import * as WUIPopover from '@welcome-ui/popover' import { Box } from '@welcome-ui/box' -export const Popover = styled(WUIPopover)` +export const Popover = styled(WUIPopover.Popover)` background-color: ${th('defaultCards.backgroundColor')}; border-width: sm; border-style: solid; diff --git a/packages/EmojiPicker/tests/index.test.tsx b/packages/EmojiPicker/tests/index.test.tsx index 8df5669bd6..bb9ba3cd07 100644 --- a/packages/EmojiPicker/tests/index.test.tsx +++ b/packages/EmojiPicker/tests/index.test.tsx @@ -1,25 +1,31 @@ import React from 'react' -import { fireEvent } from '@testing-library/react' +import { fireEvent, screen } from '@testing-library/react' import { render } from '../../../utils/tests' import { EmojiPicker, useEmojiPicker } from '../src' +const buttonText = 'open' + +const EmojiPickerWrapper = () => { + const emojiPicker = useEmojiPicker() + + return ( + <> + {buttonText} + + + ) +} + describe('', () => { it('should render correctly', () => { - const Test = () => { - const emojiPickerState = useEmojiPicker() - - return ( - <> - open - - - ) - } - - const { getByText, queryByRole } = render() - expect(queryByRole('dialog')).toBeNull() - fireEvent.click(getByText('open')) - expect(queryByRole('dialog')).toHaveTextContent('Smileys & Emotion') + render() + + const dialogText = screen.getByText('Smileys & Emotion') + const button = screen.getByText(buttonText) + + fireEvent.click(button) + + expect(dialogText).toBeInTheDocument() }) }) diff --git a/packages/Field/package.json b/packages/Field/package.json index 86dcc412cd..f1d18040f3 100644 --- a/packages/Field/package.json +++ b/packages/Field/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/field", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/FieldGroup/package.json b/packages/FieldGroup/package.json index 87f925485b..1afebdd164 100644 --- a/packages/FieldGroup/package.json +++ b/packages/FieldGroup/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/field-group", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/FileDrop/package.json b/packages/FileDrop/package.json index 9c8230590e..622e901a21 100644 --- a/packages/FileDrop/package.json +++ b/packages/FileDrop/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/file-drop", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/FileUpload/package.json b/packages/FileUpload/package.json index 0bfecb1ece..d8f50e3b5c 100644 --- a/packages/FileUpload/package.json +++ b/packages/FileUpload/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/file-upload", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Files/package.json b/packages/Files/package.json index cf9474db3d..b3a296d96e 100644 --- a/packages/Files/package.json +++ b/packages/Files/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/files", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Flex/package.json b/packages/Flex/package.json index 630f0bd4c2..cf9a540139 100644 --- a/packages/Flex/package.json +++ b/packages/Flex/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/flex", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Grid/package.json b/packages/Grid/package.json index 5f08953036..bbf9bb1d0a 100644 --- a/packages/Grid/package.json +++ b/packages/Grid/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/grid", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Hint/package.json b/packages/Hint/package.json index 7eefa9d23b..79c5f20397 100644 --- a/packages/Hint/package.json +++ b/packages/Hint/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/hint", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Icon/package.json b/packages/Icon/package.json index ccc31c38d6..f3860b964c 100644 --- a/packages/Icon/package.json +++ b/packages/Icon/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/icon", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/IconFont/package.json b/packages/IconFont/package.json index fc477bf562..6941122704 100644 --- a/packages/IconFont/package.json +++ b/packages/IconFont/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/icons.font", "version": "5.0.0-alpha.41", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -29,7 +29,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/InputText/package.json b/packages/InputText/package.json index b1970e1561..244f28b22a 100644 --- a/packages/InputText/package.json +++ b/packages/InputText/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Label/package.json b/packages/Label/package.json index 251a8e7006..b543b71ff8 100644 --- a/packages/Label/package.json +++ b/packages/Label/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/label", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Link/package.json b/packages/Link/package.json index 3bc67de6e1..b2c1760f24 100644 --- a/packages/Link/package.json +++ b/packages/Link/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/link", "version": "5.0.0-alpha.41", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Loader/package.json b/packages/Loader/package.json index 46edffe92a..64bd32a103 100644 --- a/packages/Loader/package.json +++ b/packages/Loader/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/loader", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/MarkdownEditor/package.json b/packages/MarkdownEditor/package.json index 8bd3b3de87..9c8eba12c6 100644 --- a/packages/MarkdownEditor/package.json +++ b/packages/MarkdownEditor/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/markdown-editor", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Modal/package.json b/packages/Modal/package.json index 5719a1f08d..54d4d8e1e5 100644 --- a/packages/Modal/package.json +++ b/packages/Modal/package.json @@ -32,7 +32,7 @@ "dialog", "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -48,14 +48,13 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/close-button": "^5.0.0-alpha.43", "@welcome-ui/shape": "^5.0.0-alpha.43", "@welcome-ui/system": "^5.0.0-alpha.40", "@welcome-ui/text": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "body-scroll-lock": "=3.1.5 ", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", @@ -64,7 +63,7 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "Modal", + "component": "Modal, useModal", "homepage": "https://welcome-ui.com/components/modal", "devDependencies": { "@types/body-scroll-lock": "^3.1.0" diff --git a/packages/Modal/src/Close.tsx b/packages/Modal/src/Close.tsx index df137919bf..7bcc581572 100644 --- a/packages/Modal/src/Close.tsx +++ b/packages/Modal/src/Close.tsx @@ -1,14 +1,31 @@ import { CloseButton, CloseButtonProps } from '@welcome-ui/close-button' import React from 'react' +import * as Ariakit from '@ariakit/react' +import { useTheme } from '@xstyled/styled-components' + +type CloseProps = CloseButtonProps & { + isOnHeader?: boolean +} + +export const Close = ({ isOnHeader, ...rest }: CloseProps) => { + const theme = useTheme() -export const Close: React.FC = props => { return ( - + } /> ) } diff --git a/packages/Modal/src/Content.tsx b/packages/Modal/src/Content.tsx index 4ddb858a77..07414d4571 100644 --- a/packages/Modal/src/Content.tsx +++ b/packages/Modal/src/Content.tsx @@ -1,25 +1,28 @@ import React, { Children, cloneElement, useEffect, useMemo, useState } from 'react' import { useTheme } from '@xstyled/styled-components' import { forwardRef } from '@welcome-ui/system' -import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock' import * as S from './styles' -import { useModal } from './context' +import { Close } from './Close' + +import { UseModal } from '.' export interface ContentOptions { children: React.ReactNode } -export type ContentProps = ContentOptions +export type ContentProps = ContentOptions & { + store: UseModal +} /** * @name Modal.Content */ -export const Content = forwardRef<'div', ContentProps>(({ children, ...rest }, ref) => { +export const Content = forwardRef<'div', ContentProps>(({ children, store, ...rest }, ref) => { const { borderWidths, space } = useTheme() - const modalState = useModal() - - const [bodyRef, setBodyRef] = useState(null) + const [borderOnFooter, setBorderOnFooter] = useState(false) + const contentElement = store.useState('contentElement') + const open = store.useState('open') const components = useMemo( () => @@ -33,26 +36,6 @@ export const Content = forwardRef<'div', ContentProps>(({ children, ...rest }, r [children] ) - /** - * As Reakit doesn't handle scrolling content we have to forward the modalState to the Modal.Content - * in order to check when the modal is visible and enable the scroll. - * @link https://github.com/ariakit/ariakit/issues/469 - * TODO: remove with the migration to ariakit - */ - useEffect(() => { - if (modalState.visible && bodyRef) { - disableBodyScroll(bodyRef) - } - return () => bodyRef && enableBodyScroll(bodyRef) - }, [bodyRef, modalState.visible]) - - const setRef = (name?: string) => { - if (name === 'Body') { - return setBodyRef - } - return undefined - } - const getStyles = (name?: string) => { if (name === 'Header') { return { @@ -64,32 +47,41 @@ export const Content = forwardRef<'div', ContentProps>(({ children, ...rest }, r : space.xxl, } } + if (name === 'Body') { return { pb: components.includes('Footer') ? space.lg : null, pr: components.includes('Header') ? space.xxl : null, - pt: components.includes('Header') ? 0 : null, } } if (name === 'Footer') { return { pt: components.includes('Header') || components.includes('Body') ? null : space.lg, - borderWidth: bodyRef && bodyRef.scrollHeight > bodyRef.offsetHeight ? borderWidths.sm : '0', + borderWidth: borderOnFooter ? borderWidths.sm : '0', } } return {} } + // we need to calculate when the modal open the contentElement height + useEffect(() => { + if (!open) { + setBorderOnFooter(false) + } else { + setBorderOnFooter(contentElement.scrollHeight > contentElement.offsetHeight) + } + }, [store, open, contentElement.scrollHeight, contentElement.offsetHeight]) + return ( + {components.includes('Header') ? null : } {Children.map(children, (child: JSX.Element) => { if (!child) return null const name = child?.type?.displayName || child?.type?.name return cloneElement(child, { - ref: setRef(name), ...getStyles(name), ...child.props, }) diff --git a/packages/Modal/src/Header.tsx b/packages/Modal/src/Header.tsx index 595ef9e1c6..0e1ce97d80 100644 --- a/packages/Modal/src/Header.tsx +++ b/packages/Modal/src/Header.tsx @@ -4,6 +4,7 @@ import { Text } from '@welcome-ui/text' import { forwardRef } from '@welcome-ui/system' import * as S from './styles' +import { Close } from './Close' export interface HeaderOptions { title: string | JSX.Element @@ -19,6 +20,7 @@ export type HeaderProps = HeaderOptions & Omit export const Header = forwardRef<'div', HeaderProps>(({ icon, subtitle, title, ...rest }, ref) => { return ( + {icon} {title} diff --git a/packages/Modal/src/context.tsx b/packages/Modal/src/context.tsx deleted file mode 100644 index 664d314f34..0000000000 --- a/packages/Modal/src/context.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { createContext, ReactNode, useContext, useMemo } from 'react' - -import { ModalStateReturn } from './index' - -type ModalProviderProps = { - children?: ReactNode - state: ModalStateReturn -} - -export const ModalContext = createContext({} as ModalStateReturn) - -/** - * As Reakit doesn't handle scrolling content we have to forward the modalState to the Modal.Content - * in order to check when the modal is visible and enable the scroll. - * @link https://github.com/ariakit/ariakit/issues/469 - */ -export const ModalProvider = ({ children, state }: ModalProviderProps) => { - const modalState = useMemo(() => state, [state]) - - return {children} -} - -export function useModal() { - return useContext(ModalContext) -} diff --git a/packages/Modal/src/index.tsx b/packages/Modal/src/index.tsx index c7455654d8..31a1e27a45 100644 --- a/packages/Modal/src/index.tsx +++ b/packages/Modal/src/index.tsx @@ -1,98 +1,64 @@ import React from 'react' -import { - DialogDisclosure, - DialogInitialState, - DialogOptions, - DialogStateReturn, - useDialogState, -} from 'reakit' +import * as Ariakit from '@ariakit/react' import { BoxProps } from '@welcome-ui/box' -import { As, CreateWuiProps, forwardRef, OmitReakitState } from '@welcome-ui/system' +import { As, CreateWuiProps, forwardRef } from '@welcome-ui/system' import { useTheme } from '@xstyled/styled-components' import { Shape, ShapeProps } from '@welcome-ui/shape' import * as S from './styles' -import { Close } from './Close' import { Header } from './Header' import { Footer } from './Footer' import { Content } from './Content' -import { ModalProvider } from './context' export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'auto' -export type ModalStateReturn = DialogStateReturn & { open: DialogStateReturn['visible'] } - export interface ModalOptions { ariaLabel: string - closeElement?: React.ElementType - hideOnClickOutside?: boolean + hideOnInteractOutside?: boolean size?: Size - state: ModalStateReturn + store: Ariakit.DialogStore children: React.ReactElement } - -export type ModalProps = CreateWuiProps<'div', OmitReakitState> - -export type ModalInitialState = DialogInitialState & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: DialogInitialState['visible'] +export type ModalProps = CreateWuiProps<'div', ModalOptions> +export type UseModal = Ariakit.DialogStore +export type UseModalProps = Ariakit.DialogStoreProps & { /** - * Open the drawer on load - */ - open?: DialogInitialState['visible'] - /** - * Call a fonction before closing the modal + * Call a function before closing the modal */ onClose?: () => void } +export type UseModalState = Ariakit.DialogStoreState -export function useModalState(options?: ModalInitialState): ModalStateReturn { - const { onClose, open, visible, ...restOptions } = options || {} - const dialogState = useDialogState({ animated: true, visible: visible || open, ...restOptions }) +export function useModal(options?: UseModalProps): UseModal { + const { onClose, ...storeOptions } = options || {} + + const dialog = Ariakit.useDialogStore({ + animated: true, + ...storeOptions, + }) return { - ...dialogState, - open: dialogState.visible, + ...dialog, hide: () => { - dialogState.hide() + dialog.hide() onClose?.() }, } } const ModalComponent = forwardRef<'div', ModalProps>( - ( - { - ariaLabel, - hideOnClickOutside = true, - closeElement: CloseElement = Close, - size = 'lg', - children, - state, - ...rest - }, - ref - ) => { + ({ ariaLabel, children, hideOnInteractOutside = true, size = 'lg', store }, ref) => { return ( - - - - state.hide()} /> - {children} - - - + } + hideOnInteractOutside={hideOnInteractOutside} + ref={ref} + size={size} + store={store} + > + {children} + ) } ) @@ -113,10 +79,10 @@ const Cover: React.FC = props => { ) } -type TriggerProps = { state: DialogStateReturn; children: React.ReactNode; as?: As } +type TriggerProps = { store: Ariakit.DialogStore; children: React.ReactNode; as?: As } -export const Trigger = forwardRef<'button', TriggerProps>(({ as, state, ...rest }, ref) => { - return +export const Trigger = forwardRef<'button', TriggerProps>(({ as, store, ...rest }, ref) => { + return }) // Nested exports diff --git a/packages/Modal/src/styles.ts b/packages/Modal/src/styles.ts index b653537852..8e9d3c4e47 100644 --- a/packages/Modal/src/styles.ts +++ b/packages/Modal/src/styles.ts @@ -2,18 +2,15 @@ import styled, { css, system, th, up } from '@xstyled/styled-components' import { Box } from '@welcome-ui/box' import { Text } from '@welcome-ui/text' import { cardStyles } from '@welcome-ui/utils' -import { DialogBackdrop, Dialog as ReakitDialog } from 'reakit' +import * as Ariakit from '@ariakit/react' import { Size } from './index' -export const Backdrop = styled(DialogBackdrop).withConfig({ - shouldForwardProp: prop => !['hideOnClickOutside'].includes(prop), -})<{ hideOnClickOutside: boolean }>( - ({ hideOnClickOutside }) => css` +export const Backdrop = styled.div.withConfig({ + shouldForwardProp: prop => !['hideOnInteractOutside'].includes(prop), +})<{ hideOnInteractOutside: boolean }>( + ({ hideOnInteractOutside }) => css` ${th('modals.backdrop')}; - display: flex; - align-items: center; - justify-content: center; position: fixed; top: 0; right: 0; @@ -23,41 +20,37 @@ export const Backdrop = styled(DialogBackdrop).withConfig({ transition: opacity 150ms ease-in-out; ${system}; - ${hideOnClickOutside && + ${hideOnInteractOutside && css` cursor: pointer; `} - /* on open dialog for animation */ &[data-enter] { opacity: 1; } ` ) -export const Dialog = styled(ReakitDialog)<{ size: Size }>( - ({ size }) => css` +export const Dialog = styled(Ariakit.Dialog)( + ({ size }: { size: Size }) => css` ${cardStyles}; ${th('modals.default')}; - position: relative; + position: fixed; + inset: 0; + z-index: 50; + margin: auto; + margin-top: xl; + top: 50%; + transform: translate3d(0, -50%, 0); display: flex; flex-direction: column; - margin-top: xl; - opacity: 0; + align-self: center; height: 100%; max-height: 100%; - width: 100%; - overflow: hidden; - + overflow: auto; + opacity: 0; transition: opacity 250ms ease-in-out, margin-top 250ms ease-in-out; - cursor: auto; - ${system}; - &:focus { - outline: none !important; /* important for firefox */ - } - - /* on open dialog for animation */ &[data-enter] { opacity: 1; margin-top: 0; @@ -66,53 +59,44 @@ export const Dialog = styled(ReakitDialog)<{ size: Size }>( ${up( 'md', css` - height: auto; - max-height: 90%; + height: fit-content; + max-height: calc(100vh - ${th('space.xl')} * 2); ${th(`modals.sizes.${size}`)}; ` )} ` ) -export const Content = styled(Box)` - display: flex; - flex-direction: column; - height: 100%; +export const Content = styled.divBox`` + +export const Body = styled.sectionBox` max-height: 100%; - overflow: hidden; + ${th('modals.body')}; ` export const Header = styled.headerBox` - ${({ theme }) => css` - flex-shrink: 0; - ${theme.modals.header} - `} + position: sticky; + top: 0; + flex-shrink: 0; + ${th('modals.header')}; ` export const HeaderSubtitle = styled(Text)` - ${({ theme }) => theme.modals.header.subtitle} -` - -export const Body = styled.sectionBox` - ${({ theme }) => css` - max-height: 100%; - overflow-y: auto; - ${theme.modals.body} - `} + ${th('.modals.header.subtitle')}; + margin-bottom: 0; ` export const Footer = styled.footerBox` - ${({ theme }) => css` - margin-top: auto; - flex-shrink: 0; - ${theme.modals.footer} - `} + position: sticky; + bottom: 0; + flex-shrink: 0; + ${th('modals.footer')}; ` export const FooterChildrenWrapper = styled(Box)` - ${({ theme }) => theme.modals.footer.children} + ${th('modals.footer.children')}; ` export const FooterInformation = styled.divBox` - ${({ theme }) => theme.modals.footer.information} + ${th('modals.footer.information')}; ` diff --git a/packages/Modal/tests/index.test.tsx b/packages/Modal/tests/index.test.tsx index 3b2e9948fe..649cef06be 100644 --- a/packages/Modal/tests/index.test.tsx +++ b/packages/Modal/tests/index.test.tsx @@ -2,17 +2,17 @@ import React from 'react' import { fireEvent } from '@testing-library/react' import { render } from '../../../utils/tests' -import { Modal, useModalState } from '../src' +import { Modal, useModal } from '../src' describe('', () => { it('should render correctly', () => { const Test = () => { - const modalState = useModalState() + const modal = useModal() return ( <> - open - + open +
Modal open
@@ -27,16 +27,16 @@ describe('', () => { it('should render conditionally', () => { const ModalTest = () => { - const modalState = useModalState() + const modal = useModal() const shouldRender = false return ( <> - + open - - + + {shouldRender && Modal.Body exist?} diff --git a/packages/Pagination/package.json b/packages/Pagination/package.json index 896518c3a6..ae22df093d 100644 --- a/packages/Pagination/package.json +++ b/packages/Pagination/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/pagination", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -48,8 +48,7 @@ "dependencies": { "@welcome-ui/icons": "^5.0.0-alpha.41", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Pagination/src/index.tsx b/packages/Pagination/src/index.tsx index 9fb353eb8f..b00f7c3152 100644 --- a/packages/Pagination/src/index.tsx +++ b/packages/Pagination/src/index.tsx @@ -1,5 +1,4 @@ import React, { useCallback, useRef } from 'react' -import { Rover, RoverInitialState, useRoverState } from 'reakit' import { LeftIcon, RightIcon } from '@welcome-ui/icons' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' @@ -8,14 +7,13 @@ import * as S from './styles' export interface PaginationOptions { 'aria-label': string - getHref?: (page: string | number) => string + getHref: (page: string | number) => string leftArrow?: React.ReactElement onChange: (page: string | number) => void page: number pageCount: number rangeDisplay?: number rightArrow?: React.ReactElement - baseId?: RoverInitialState['baseId'] } export type PaginationProps = CreateWuiProps<'ul', PaginationOptions> @@ -24,7 +22,6 @@ export const Pagination = forwardRef<'ul', PaginationProps>( ( { 'aria-label': ariaLabel, - baseId, dataTestId, getHref, leftArrow, @@ -37,10 +34,12 @@ export const Pagination = forwardRef<'ul', PaginationProps>( }, ref ) => { - const rover = useRoverState({ baseId }) const pages = usePages({ page, pageCount, rangeDisplay }) - const firstPageRef = useRef(null) - const lastPageRef = useRef(null) + const firstPageRef = useRef(null) + const lastPageRef = useRef(null) + const isPrevButtonDisabled = page === 1 + const isNextButtonDisabled = page === pageCount + const handlePrevious = useCallback( (event: React.MouseEvent) => { event.preventDefault() @@ -52,6 +51,7 @@ export const Pagination = forwardRef<'ul', PaginationProps>( }, [page, onChange] ) + const handleNext = useCallback( (event: React.MouseEvent) => { event.preventDefault() @@ -74,18 +74,15 @@ export const Pagination = forwardRef<'ul', PaginationProps>( > - - {roverProps => ( - - {leftArrow || } - - )} - + + {leftArrow || } + {pages.map((iPage: string | number, i: number) => iPage === '-' ? ( @@ -95,41 +92,30 @@ export const Pagination = forwardRef<'ul', PaginationProps>( ) : ( - { + event.preventDefault() + onChange(iPage) + }} > - {roverProps => ( - { - event.preventDefault() - onChange(iPage) - }} - > - {iPage} - - )} - + {iPage} + ) )} - - {roverProps => ( - - {rightArrow || } - - )} - + + {rightArrow || } + diff --git a/packages/Pagination/src/styles.ts b/packages/Pagination/src/styles.ts index 007f10a685..b9aa0c298a 100644 --- a/packages/Pagination/src/styles.ts +++ b/packages/Pagination/src/styles.ts @@ -27,7 +27,7 @@ export const Dots = styled.span` align-items: center; ` -export const AbstractLink = styled.a` +export const abstractLinkStyle = css` ${th('paginations.default')}; ${th('paginations.item')}; border-radius: 50%; @@ -47,9 +47,10 @@ export const AbstractLink = styled.a` } ` -export const ArrowLink = styled(AbstractLink)<{ isDisabled: boolean }>( - ({ isDisabled }) => css` - ${isDisabled && +export const ArrowLink = styled.a( + props => css` + ${abstractLinkStyle}; + ${props['aria-disabled'] && css` color: nude-700; background-color: nude-400; @@ -57,8 +58,9 @@ export const ArrowLink = styled(AbstractLink)<{ isDisabled: boolean }>( ` ) -export const PageLink = styled(AbstractLink)( +export const PageLink = styled.a( props => css` + ${abstractLinkStyle}; ${props['aria-current'] && th('paginations.active')} ` ) diff --git a/packages/Pagination/tests/index.test.tsx b/packages/Pagination/tests/index.test.tsx new file mode 100644 index 0000000000..c7e5fa684f --- /dev/null +++ b/packages/Pagination/tests/index.test.tsx @@ -0,0 +1,101 @@ +import React from 'react' +import { fireEvent, screen } from '@testing-library/react' +import { renderHook } from '@testing-library/react-hooks' + +import { render } from '../../../utils/tests' +import { Pagination } from '../src' +import { usePages } from '../src/utils' + +describe('', () => { + it('should render correctly', () => { + const onChange = jest.fn() + const getHref = jest.fn() + + render( + + ) + + const prevButton = screen.getByTestId('pagination-arrow-prev') + const nextButton = screen.getByTestId('pagination-arrow-next') + const currentPage = screen.getByText('1') + const nextPage = screen.getByText('2') + + expect(prevButton).toHaveAttribute('aria-disabled', 'true') + expect(nextButton).toHaveAttribute('aria-disabled', 'false') + expect(currentPage).toHaveAttribute('aria-current', 'true') + expect(nextPage).toHaveAttribute('aria-current', 'false') + + /** Click on next button */ + fireEvent.click(nextButton) + + expect(onChange).toHaveBeenCalledWith(2) + + /** Click on a page 3 button */ + fireEvent.click(screen.getByText('3')) + + expect(onChange).toHaveBeenCalledWith(3) + }) + + it('should render correctly with prev Button', () => { + const onChange = jest.fn() + const getHref = jest.fn() + + render( + + ) + + const prevButton = screen.getByTestId('pagination-arrow-prev') + const nextButton = screen.getByTestId('pagination-arrow-next') + const currentPage = screen.getByText('10') + const prevPage = screen.getByText('9') + + expect(prevButton).toHaveAttribute('aria-disabled', 'false') + expect(nextButton).toHaveAttribute('aria-disabled', 'true') + expect(currentPage).toHaveAttribute('aria-current', 'true') + expect(prevPage).toHaveAttribute('aria-current', 'false') + + /** Click on prev button */ + fireEvent.click(prevButton) + + expect(onChange).toHaveBeenCalledWith(9) + + /** Click on a page 3 button */ + fireEvent.click(screen.getByText('10')) + + expect(onChange).toHaveBeenCalledWith(10) + }) + + describe('usePages', () => { + it('should return correct values', () => { + const { result } = renderHook(() => usePages({ page: 1, pageCount: 10, rangeDisplay: 5 })) + + expect(result.current).toStrictEqual([1, 2, 3, 4, 5, '-', 10]) + }) + + it('should return correct values in middle', () => { + const { result } = renderHook(() => usePages({ page: 5, pageCount: 10, rangeDisplay: 5 })) + + expect(result.current).toStrictEqual([1, '-', 4, 5, 6, '-', 10]) + }) + + it('should return correct values with small pagination', () => { + const { result } = renderHook(() => usePages({ page: 1, pageCount: 5, rangeDisplay: 5 })) + + expect(result.current).toStrictEqual([1, 2, 3, 4, 5]) + }) + }) +}) diff --git a/packages/PasswordInput/package.json b/packages/PasswordInput/package.json index 111b33400d..2659891ca2 100644 --- a/packages/PasswordInput/package.json +++ b/packages/PasswordInput/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/password-input", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Picker/package.json b/packages/Picker/package.json index fdc9707819..0152ae18b1 100644 --- a/packages/Picker/package.json +++ b/packages/Picker/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,12 +46,12 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/field-group": "^5.0.0-alpha.43", "@welcome-ui/label": "^5.0.0-alpha.43", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Picker/src/index.tsx b/packages/Picker/src/index.tsx index 6806e8a1bb..427f266a56 100644 --- a/packages/Picker/src/index.tsx +++ b/packages/Picker/src/index.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { RadioGroup as ReakitRadioGroup } from 'reakit' +import * as Ariakit from '@ariakit/react' import { FieldGroup, FieldGroupOptions } from '@welcome-ui/field-group' import { Label } from '@welcome-ui/label' import { Box } from '@welcome-ui/box' @@ -26,6 +26,8 @@ export type PickerProps = CreateWuiProps< export const Picker = forwardRef<'fieldset', PickerProps>( ({ dataTestId, label, name, onChange, options, required, value, ...rest }, ref) => { + const store = Ariakit.useRadioStore({ defaultValue: value }) + const handleClick: React.MouseEventHandler = e => { e.stopPropagation() onChange && onChange(e) @@ -34,11 +36,12 @@ export const Picker = forwardRef<'fieldset', PickerProps>( return ( {options.map(({ element: Component, value: optValue }) => ( diff --git a/packages/Picker/src/styles.ts b/packages/Picker/src/styles.ts index c04b2faa6b..dec0dc3353 100644 --- a/packages/Picker/src/styles.ts +++ b/packages/Picker/src/styles.ts @@ -1,8 +1,12 @@ import styled, { system } from '@xstyled/styled-components' import { shouldForwardProp } from '@welcome-ui/system' -import { Radio as ReakitRadio } from 'reakit' +import * as Ariakit from '@ariakit/react' + +export const Radio = styled(Ariakit.Radio).withConfig({ shouldForwardProp })` + position: absolute; + top: 0; + left: 0; + opacity: 0; -export const Radio = styled(ReakitRadio).withConfig({ shouldForwardProp })` - display: none; ${system}; ` diff --git a/packages/Popover/package.json b/packages/Popover/package.json index 898e56dfe8..bcc49f83d1 100644 --- a/packages/Popover/package.json +++ b/packages/Popover/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,12 +46,11 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/button": "^5.0.0-alpha.43", "@welcome-ui/icons": "^5.0.0-alpha.41", - "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/system": "^5.0.0-alpha.40" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", @@ -60,6 +59,6 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "Popover, usePopoverState", + "component": "Popover, usePopover", "homepage": "https://welcome-ui.com/components/popover" } diff --git a/packages/Popover/src/Trigger.tsx b/packages/Popover/src/Trigger.tsx index 175a7a461d..e2af2ebb3b 100644 --- a/packages/Popover/src/Trigger.tsx +++ b/packages/Popover/src/Trigger.tsx @@ -1,68 +1,57 @@ import { CreateWuiProps, forwardRef } from '@welcome-ui/system' -import React, { useRef } from 'react' +import React from 'react' import { useIsomorphicLayoutEffect } from '@welcome-ui/utils' -import { UsePopoverStateReturn } from './usePopoverState' +import { UsePopover } from './usePopover' import * as S from './styles' -export type TriggerProps = CreateWuiProps<'button', { state: UsePopoverStateReturn }> +export type TriggerProps = CreateWuiProps<'button', { store: UsePopover }> -export const Trigger = forwardRef<'button', TriggerProps>(({ as, state, ...rest }, ref) => { - const { triggerMethod } = state - const hoverable = triggerMethod === 'hover' - const disclosureRef = useRef(null) - const popoverRef = state.unstable_popoverRef +export const Trigger = forwardRef<'button', TriggerProps>(({ as, store, ...rest }, ref) => { + const { triggerMethod } = store + const isHoverMethod = triggerMethod === 'hover' + const disclosureRef = store.useState('disclosureElement') + const popoverRef = store.useState('popoverElement') const showPopover: () => void = () => { - if (hoverable) { + if (isHoverMethod) { // remove listeners on mouseenter - disclosureRef.current?.removeEventListener('mouseenter', showPopover) - popoverRef.current?.removeEventListener('mouseenter', showPopover) + disclosureRef?.removeEventListener('mouseenter', showPopover) + popoverRef?.removeEventListener('mouseenter', showPopover) // add listeners on mouseleave - disclosureRef.current?.addEventListener('mouseleave', hidePopover) - popoverRef.current?.addEventListener('mouseleave', hidePopover) + disclosureRef?.addEventListener('mouseleave', hidePopover) + popoverRef?.addEventListener('mouseleave', hidePopover) // show popover - state.show() - } - } - - const setRef = (triggerElement: HTMLButtonElement) => { - disclosureRef.current = triggerElement - state.unstable_disclosureRef.current = triggerElement - if (typeof ref === 'function') { - ref(triggerElement) - } else if (ref?.current) { - ref.current = triggerElement + store.show() } } const hidePopover: () => void = () => { - if (hoverable) { + if (isHoverMethod) { // remove listeners on mouseleave - disclosureRef.current?.removeEventListener('mouseleave', hidePopover) - popoverRef.current?.removeEventListener('mouseleave', hidePopover) + disclosureRef?.removeEventListener('mouseleave', hidePopover) + popoverRef?.removeEventListener('mouseleave', hidePopover) // add listeners on mouseenter - disclosureRef.current?.addEventListener('mouseenter', showPopover) - popoverRef.current?.addEventListener('mouseenter', showPopover) + disclosureRef?.addEventListener('mouseenter', showPopover) + popoverRef?.addEventListener('mouseenter', showPopover) // hide popover - state.hide() + store.hide() } } useIsomorphicLayoutEffect(() => { - const disclosure = disclosureRef.current - if (hoverable && disclosure) { + if (isHoverMethod && disclosureRef) { // add listeners on mount - disclosure.addEventListener('mouseenter', showPopover) - disclosure.addEventListener('mouseleave', hidePopover) + disclosureRef.addEventListener('mouseenter', showPopover) + disclosureRef.addEventListener('mouseleave', hidePopover) return () => { // remove listeners on unmount - disclosure.removeEventListener('mouseenter', showPopover) - disclosure.removeEventListener('mouseleave', hidePopover) + disclosureRef.removeEventListener('mouseenter', showPopover) + disclosureRef.removeEventListener('mouseleave', hidePopover) } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [disclosureRef]) - return + return }) diff --git a/packages/Popover/src/index.tsx b/packages/Popover/src/index.tsx index e4fdc9b045..847c32bd35 100644 --- a/packages/Popover/src/index.tsx +++ b/packages/Popover/src/index.tsx @@ -2,33 +2,30 @@ import React from 'react' import { Box } from '@welcome-ui/box' import { Button } from '@welcome-ui/button' import { CrossIcon } from '@welcome-ui/icons' -import { CreateWuiProps, forwardRef, OmitReakitState } from '@welcome-ui/system' -import { PopoverOptions as ReakitPopoverOptions } from 'reakit' +import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './styles' import { Trigger } from './Trigger' -import { UsePopoverStateReturn } from './usePopoverState' +import { UsePopover } from './usePopover' export interface PopoverOptions { /** call a function when popover closed */ onClose?: () => void - state: UsePopoverStateReturn + store: UsePopover } -export type PopoverProps = CreateWuiProps< - 'div', - OmitReakitState -> +export type PopoverProps = CreateWuiProps<'div', PopoverOptions> /* eslint-disable @typescript-eslint/no-unused-vars */ export const PopoverComponent = forwardRef<'div', PopoverProps>( - ({ children, onClose, state, ...rest }, ref) => { + ({ children, onClose, store, ...rest }, ref) => { const closePopover = () => { if (onClose) onClose() - state?.hide() + store?.hide() } - const { placement, withCloseButton } = state + const placement = store.useState('currentPlacement') + const { withCloseButton } = store // get the correct transform style for arrow const [parentPlacement] = placement.split('-') const transformMap: { [key: string]: string } = { @@ -40,9 +37,9 @@ export const PopoverComponent = forwardRef<'div', PopoverProps>( const transform = transformMap[parentPlacement] return ( - + - + @@ -76,4 +73,4 @@ export const Popover = Object.assign(PopoverComponent, { Trigger: Trigger, }) -export * from './usePopoverState' +export * from './usePopover' diff --git a/packages/Popover/src/styles.ts b/packages/Popover/src/styles.ts index ddbf165eda..2d8fb7edf5 100644 --- a/packages/Popover/src/styles.ts +++ b/packages/Popover/src/styles.ts @@ -1,7 +1,7 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { Popover as BasePopover, PopoverArrow, PopoverDisclosure } from 'reakit' +import * as Ariakit from '@ariakit/react' -export const Arrow = styled(PopoverArrow)` +export const Arrow = styled(Ariakit.PopoverArrow)` color: ${th('popovers.default.backgroundColor')}; ` @@ -20,7 +20,7 @@ export const Title = styled.h6` ${th('popovers.title')}; ` -export const Popover = styled(BasePopover)<{ $withCloseButton: boolean }>( +export const Popover = styled(Ariakit.Popover)<{ $withCloseButton: boolean }>( ({ $withCloseButton }) => css` ${th('popovers.default')}; outline: none; @@ -42,6 +42,6 @@ export const Popover = styled(BasePopover)<{ $withCloseButton: boolean }>( ` ) -export const PopoverTrigger = styled(PopoverDisclosure)` +export const PopoverTrigger = styled(Ariakit.PopoverDisclosure)` ${system} ` diff --git a/packages/Popover/src/usePopover.ts b/packages/Popover/src/usePopover.ts new file mode 100644 index 0000000000..407227ddbd --- /dev/null +++ b/packages/Popover/src/usePopover.ts @@ -0,0 +1,71 @@ +import { useCallback, useRef } from 'react' +import * as Ariakit from '@ariakit/react' + +export interface UsePopoverProps extends Ariakit.PopoverStoreProps { + hideTimeout?: number + showTimeout?: number + triggerMethod?: 'hover' | 'click' + withCloseButton?: boolean +} + +export type UsePopover = Ariakit.PopoverStore & + Pick & { + /** + * Custom hide function who call ariakit hide after a timeout if is hoverable, or not + **/ + hide: () => void + /** + * Custom show function who call ariakit show after a timeout if is hoverable, or not + **/ + show: () => void + } + +export type UsePopoverState = Ariakit.PopoverStoreState + +export const usePopover: (props?: UsePopoverProps) => UsePopover = ({ + animated = 150, + hideTimeout = 300, + showTimeout = 500, + triggerMethod = 'click', + withCloseButton = false, + ...options +} = {}) => { + const store = Ariakit.usePopoverStore({ + animated, + ...options, + }) + const isOpen = store.useState('open') + const closeCountdownRef = useRef() + const openCountdownRef = useRef() + const isHoverable = triggerMethod === 'hover' + + const hide = useCallback(() => { + if (isHoverable) { + if (!isOpen && openCountdownRef.current) { + clearTimeout(openCountdownRef.current) + } + closeCountdownRef.current = setTimeout(() => store.hide(), hideTimeout) + } else { + store.hide() + } + }, [isHoverable, isOpen, hideTimeout, store]) + + const show = useCallback(() => { + if (isHoverable) { + openCountdownRef.current = setTimeout(() => store.show(), showTimeout) + if (closeCountdownRef.current) { + clearTimeout(closeCountdownRef.current) + } + } else { + store.show() + } + }, [isHoverable, showTimeout, store]) + + return { + ...store, + show, + hide, + triggerMethod, + withCloseButton, + } +} diff --git a/packages/Popover/src/usePopoverState.ts b/packages/Popover/src/usePopoverState.ts deleted file mode 100644 index 75a52a8a66..0000000000 --- a/packages/Popover/src/usePopoverState.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { useCallback, useRef } from 'react' -import { - PopoverInitialState as ReakitPopoverInitialState, - PopoverStateReturn as ReakitPopoverStateReturn, - usePopoverState as useReakitPopoverState, -} from 'reakit' - -export interface UsePopoverStateOptions extends ReakitPopoverInitialState { - hideTimeout?: number - showTimeout?: number - triggerMethod?: 'hover' | 'click' - withCloseButton?: boolean - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: ReakitPopoverInitialState['visible'] - /** - * Open the popover on load - */ - open?: ReakitPopoverInitialState['visible'] -} - -export type UsePopoverStateReturn = ReakitPopoverStateReturn & - Pick & { - /** - * @deprecated - * will be replace by open on ariakit (reakit v2) - **/ - visible?: ReakitPopoverStateReturn['visible'] - /** - * Open the popover on load - **/ - open?: ReakitPopoverStateReturn['visible'] - /** - * Custom hide function who call reakit hide after a timeout if is hoverable, or not - **/ - hide: () => void - /** - * Custom show function who call reakit show after a timeout if is hoverable, or not - **/ - show: () => void - } - -export const usePopoverState: (props?: UsePopoverStateOptions) => UsePopoverStateReturn = ({ - animated = 150, - hideTimeout = 300, - showTimeout = 500, - triggerMethod = 'click', - withCloseButton = false, - ...options -} = {}) => { - const { open, visible } = options - const popover = useReakitPopoverState({ - animated, - visible: visible || open, - ...options, - }) - const closeCountdownRef = useRef() - const openCountdownRef = useRef() - const isHoverable = triggerMethod === 'hover' - - const hide = useCallback(() => { - if (isHoverable) { - if (!popover.visible && openCountdownRef.current) { - clearTimeout(openCountdownRef.current) - } - closeCountdownRef.current = setTimeout(() => popover.hide(), hideTimeout) - } else { - popover.hide() - } - }, [isHoverable, popover, hideTimeout]) - - const show = useCallback(() => { - if (isHoverable) { - openCountdownRef.current = setTimeout(() => popover.show(), showTimeout) - if (closeCountdownRef.current) { - clearTimeout(closeCountdownRef.current) - } - } else { - popover.show() - } - }, [isHoverable, showTimeout, popover]) - - return { - ...popover, - open: popover.visible, - hide, - show, - triggerMethod, - withCloseButton, - } -} diff --git a/packages/Popover/tests/index.test.tsx b/packages/Popover/tests/index.test.tsx index a560160993..cdefa76aad 100644 --- a/packages/Popover/tests/index.test.tsx +++ b/packages/Popover/tests/index.test.tsx @@ -1,27 +1,39 @@ import React from 'react' -import { fireEvent } from '@testing-library/react' +import { fireEvent, screen } from '@testing-library/react' import { render } from '../../../utils/tests' -import { Popover, usePopoverState } from '../src' +import { Popover, usePopover } from '../src' + +const contentText = 'Popover open' +const buttonText = 'open' + +const PopoverWrapper = () => { + const store = usePopover() + + return ( + <> + {buttonText} + + {contentText} + + + ) +} describe('', () => { - it('should render correctly', () => { - const Test = () => { - const popoverState = usePopoverState() - - return ( - <> - open - - Popover open - - - ) - } - - const { getByText, queryByRole } = render() - expect(queryByRole('dialog')).toBeNull() - fireEvent.click(getByText('open')) - expect(queryByRole('dialog')).toHaveTextContent('Popover open') + it('should render correctly on click on popover trigger button', () => { + render() + + expect(screen.queryByRole('dialog')).toBeNull() + + const button = screen.getByText(buttonText) + const dialog = screen.getByText(contentText) + + expect(button).toHaveAttribute('aria-expanded', 'false') + expect(dialog).toBeInTheDocument() + + fireEvent.click(button) + + expect(button).toHaveAttribute('aria-expanded', 'true') }) }) diff --git a/packages/Radio/package.json b/packages/Radio/package.json index e8d2cc855b..19b6bba7bb 100644 --- a/packages/Radio/package.json +++ b/packages/Radio/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/radio", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,12 +46,12 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/box": "^5.0.0-alpha.40", "@welcome-ui/hint": "^5.0.0-alpha.43", "@welcome-ui/label": "^5.0.0-alpha.43", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Radio/src/index.tsx b/packages/Radio/src/index.tsx index 711fecea69..0338550641 100644 --- a/packages/Radio/src/index.tsx +++ b/packages/Radio/src/index.tsx @@ -62,9 +62,11 @@ export const Radio = forwardRef<'input', RadioProps>( {...rest} /> -
{label}
+
{label}
- {hint && {hint}} + {hint && ( + {hint} + )} ) } diff --git a/packages/Radio/src/styles.ts b/packages/Radio/src/styles.ts index fd611b5840..a5d31ac029 100644 --- a/packages/Radio/src/styles.ts +++ b/packages/Radio/src/styles.ts @@ -4,13 +4,13 @@ import { shouldForwardProp } from '@welcome-ui/system' import { defaultFieldStyles } from '@welcome-ui/utils' import { Hint as HintWUI } from '@welcome-ui/hint' import { Label as WUILabel } from '@welcome-ui/label' -import { Radio as ReakitRadio } from 'reakit' +import * as Ariakit from '@ariakit/react' import { RadioProps } from './index' /* /!\ WARNING /!\ Don't add style after pseudo selector, it won't apply because of the dynamic color injected in the fill of the content */ -export const Radio = styled(ReakitRadio).withConfig({ shouldForwardProp })( +export const Radio = styled(Ariakit.Radio).withConfig({ shouldForwardProp })( ({ order = '-1', size, variant }) => css` ${defaultFieldStyles({ size, variant })}; ${th('radios.default')} @@ -60,6 +60,8 @@ export const Label = styled(WUILabel)<{ ${withHint && th('radios.withHint.default')}; max-width: 100%; align-items: flex-start; + /** we need to reset margin-bottom from Label component */ + margin-bottom: 0 !important; ${system} ` ) diff --git a/packages/Radio/tests/index.test.tsx b/packages/Radio/tests/index.test.tsx new file mode 100644 index 0000000000..b74e087ebd --- /dev/null +++ b/packages/Radio/tests/index.test.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { screen } from '@testing-library/react' + +import { render } from '../../../utils/tests' +import { Radio } from '../src' + +const content = 'Jungle' + +describe('', () => { + it('should render correctly', () => { + render() + + const radio = screen.getByTestId('radio') + const label = screen.getByTestId('radio-label') + + expect(radio).toHaveAttribute('label', content) + expect(radio).toHaveAttribute('type', 'radio') + expect(label).toHaveTextContent(content) + }) + + it('should render correctly with an hint', () => { + render() + + const hint = screen.getByTestId('radio-hint') + + expect(hint).toHaveTextContent('hint') + }) +}) diff --git a/packages/RadioGroup/package.json b/packages/RadioGroup/package.json index 01cfeff4dd..00e4d3c6b1 100644 --- a/packages/RadioGroup/package.json +++ b/packages/RadioGroup/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/radio-group", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,10 +46,10 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/field-group": "^5.0.0-alpha.43", "@welcome-ui/radio": "^5.0.0-alpha.43", - "@welcome-ui/system": "^5.0.0-alpha.40", - "reakit": "^1.3.11" + "@welcome-ui/system": "^5.0.0-alpha.40" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/RadioGroup/src/index.tsx b/packages/RadioGroup/src/index.tsx index fe638be35f..aa9f41bdfa 100644 --- a/packages/RadioGroup/src/index.tsx +++ b/packages/RadioGroup/src/index.tsx @@ -1,29 +1,28 @@ import React from 'react' -import { - RadioGroup as ReakitRadioGroup, - RadioGroupOptions as ReakitRadioGroupOptions, - useRadioState, -} from 'reakit' +import * as Ariakit from '@ariakit/react' import { FieldGroup, FieldGroupOptions } from '@welcome-ui/field-group' import { Radio } from '@welcome-ui/radio' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './styles' +export type Option = { + label: string | number + value: string | number + hint?: string +} + export interface RadioGroupOptions { - name?: string - options?: { - label: string | number - value: string | number - hint?: string - }[] + name: string + options: Option[] renderOption?: React.ElementType value?: string + onChange?: (value: Option['value']) => void } export type RadioGroupProps = CreateWuiProps< 'fieldset', - Omit & Partial & RadioGroupOptions + Omit & RadioGroupOptions > export const RadioGroup = forwardRef<'fieldset', RadioGroupProps>( @@ -36,31 +35,50 @@ export const RadioGroup = forwardRef<'fieldset', RadioGroupProps>( options = [], renderOption: Component = Radio, required, + dataTestId, + onChange, value, ...rest }, ref ) => { - const radio = useRadioState({ currentId: value }) - const withHint = options.findIndex(obj => Object.keys(obj).includes('hint')) !== -1 + const store = Ariakit.useRadioStore({ defaultValue: value }) + const activeValue = store.useState('value') + + const handleChange = (valueSelected: Option['value']) => { + if (rest.disabled) return + + store.setValue(valueSelected) + onChange?.(valueSelected) + } + + const withHint = options.some((obj: Option) => 'hint' in obj) return ( - + - {options.map(option => ( + {options.map((option: Option) => ( handleChange(option.value)} value={option.value} withHint={withHint} - {...radio} + {...rest} /> ))} diff --git a/packages/RadioGroup/src/styles.ts b/packages/RadioGroup/src/styles.ts index 5fd18bdc41..ecf451a7af 100644 --- a/packages/RadioGroup/src/styles.ts +++ b/packages/RadioGroup/src/styles.ts @@ -8,11 +8,8 @@ export const Radios = styled.div<{ display: flex; flex-direction: ${flexDirection}; flex-wrap: wrap; - margin-bottom: ${flexDirection === 'column' ? '-md' : '-xs'}; - ${system}; + gap: xs; - > *:not(:last-child) { - margin-bottom: xs; - } + ${system}; ` ) diff --git a/packages/RadioGroup/tests/index.test.tsx b/packages/RadioGroup/tests/index.test.tsx new file mode 100644 index 0000000000..cf8adc4bde --- /dev/null +++ b/packages/RadioGroup/tests/index.test.tsx @@ -0,0 +1,97 @@ +import React from 'react' +import { fireEvent, screen } from '@testing-library/react' + +import { render } from '../../../utils/tests' +import { RadioGroup } from '../src' +import { RadioTab } from '../../RadioTab' + +const options = [ + { label: 'label1', value: 'value1' }, + { label: 'label2', value: 'value2' }, + { label: 'label3', value: 'value3' }, +] + +const name = 'radio-group' + +describe('', () => { + it('should render correctly', () => { + const onChange = jest.fn() + + render() + + const radio3 = screen.getByTestId('radio-group-value3') + const label = screen.getByTestId('radio-group-value3-label') + + expect(radio3).toHaveAttribute('value', 'value3') + expect(label).toHaveTextContent('label3') + + fireEvent.click(radio3) + + expect(radio3).toHaveAttribute('aria-checked', 'true') + expect(onChange).toBeCalledWith('value3') + }) + + it('should render correctly with default value', () => { + const onChange = jest.fn() + + render( + + ) + + const radioSelected = screen.getByTestId('radio-group-value1') + + expect(radioSelected).toHaveAttribute('aria-checked', 'true') + }) + + it('should render correctly with hint', () => { + const onChange = jest.fn() + + render( + + ) + + const radio = screen.getByTestId('radio-group-valueHint') + const label = screen.getByTestId('radio-group-valueHint-label') + const hint = screen.getByTestId('radio-group-valueHint-hint') + + expect(radio).toHaveAttribute('value', 'valueHint') + expect(label).toHaveTextContent('labelHint') + expect(hint).toHaveTextContent('hint') + }) + + it('should render correctly with a renderOption component', () => { + const onChange = jest.fn() + + render( + + ) + + const radio = screen.getByTestId('radio-group-value3') + const input = screen.getByTestId('radio-group-value3-input') + + expect(input).toHaveAttribute('value', 'value3') + expect(radio).toHaveTextContent('label3') + + fireEvent.click(radio) + + expect(input).toHaveAttribute('aria-checked', 'true') + expect(onChange).toBeCalledWith('value3') + }) +}) diff --git a/packages/RadioTab/package.json b/packages/RadioTab/package.json index 1fcf954f24..e4360a360e 100644 --- a/packages/RadioTab/package.json +++ b/packages/RadioTab/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/radio-tab", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,9 +46,10 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", + "@welcome-ui/button": "^5.0.0-alpha.40", "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "reakit": "^1.3.11" + "@welcome-ui/utils": "^5.0.0-alpha.43" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/RadioTab/src/index.tsx b/packages/RadioTab/src/index.tsx index 391b68ac7a..adf98b4412 100644 --- a/packages/RadioTab/src/index.tsx +++ b/packages/RadioTab/src/index.tsx @@ -1,7 +1,8 @@ import React from 'react' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import { DefaultFieldStylesProps } from '@welcome-ui/utils' -import { RadioProps } from 'reakit' +import { Button } from '@welcome-ui/button' +import * as Ariakit from '@ariakit/react' import * as S from './styles' @@ -10,59 +11,36 @@ export interface RadioTabsOptions extends DefaultFieldStylesProps { disabled?: boolean disabledIcon?: React.ReactElement label: React.ReactElement - onChange?: (event: React.MouseEvent) => void - onClick?: (event: React.MouseEvent) => void + onChange?: (event: React.MouseEvent) => void + value: Ariakit.RadioStoreState['value'] } -export type RadioTabsProps = CreateWuiProps< - 'input', - RadioTabsOptions & Omit -> +export type RadioTabsProps = CreateWuiProps<'input', RadioTabsOptions> -export const RadioTab = forwardRef<'input', RadioTabsProps>((props, ref) => { - const { - checked, - dataTestId, - disabled, - disabledIcon, - flexDirection, - label, - onChange, - onClick, - size = 'md', - variant, - ...radioProps - } = props - - const handleClick = (event: React.MouseEvent) => { - event.stopPropagation() - onClick && onClick(event) - onChange && onChange(event) - } - - return ( - - +export const RadioTab = forwardRef<'input', RadioTabsProps>( + ({ checked, dataTestId, disabled, id, label, onChange, value }, ref) => { + return ( + + ) + } +) RadioTab.displayName = 'RadioTab' diff --git a/packages/RadioTab/src/styles.ts b/packages/RadioTab/src/styles.ts index 77166cb0fb..f807811e21 100644 --- a/packages/RadioTab/src/styles.ts +++ b/packages/RadioTab/src/styles.ts @@ -1,15 +1,14 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { Radio as ReakitRadio } from 'reakit' +import * as Ariakit from '@ariakit/react' import { shouldForwardProp } from '@welcome-ui/system' import { defaultFieldStyles, DefaultFieldStylesProps, overflowEllipsis } from '@welcome-ui/utils' import { WuiProps } from '@welcome-ui/system' -export const Radio = styled(ReakitRadio).withConfig({ shouldForwardProp })` +export const Radio = styled(Ariakit.Radio).withConfig({ shouldForwardProp })` position: absolute; top: 0; left: 0; - visibility: hidden; - ${system}; + opacity: 0; ` const columnStyles = css` diff --git a/packages/Search/package.json b/packages/Search/package.json index f18d33f094..d9482211d7 100644 --- a/packages/Search/package.json +++ b/packages/Search/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/search", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Select/package.json b/packages/Select/package.json index cfd51a956b..39d572816d 100644 --- a/packages/Select/package.json +++ b/packages/Select/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/select", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Shape/package.json b/packages/Shape/package.json index 4772fb5ff3..ac1134a4cd 100644 --- a/packages/Shape/package.json +++ b/packages/Shape/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/shape", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Slider/package.json b/packages/Slider/package.json index 8e9ff90f40..0a5dd86a14 100644 --- a/packages/Slider/package.json +++ b/packages/Slider/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/slider", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Stack/package.json b/packages/Stack/package.json index e87f481e9e..673e002b23 100644 --- a/packages/Stack/package.json +++ b/packages/Stack/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/stack", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Swiper/package.json b/packages/Swiper/package.json index 9006abae27..597d67e861 100644 --- a/packages/Swiper/package.json +++ b/packages/Swiper/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/swiper", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -59,6 +59,6 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "Swiper", + "component": "Swiper, useSwiper", "homepage": "https://welcome-ui.com/components/swiper" } diff --git a/packages/System/package.json b/packages/System/package.json index a4f20c359e..2c9c69cbe0 100644 --- a/packages/System/package.json +++ b/packages/System/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/system", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/System/src/index.tsx b/packages/System/src/index.tsx index 9547890f3f..45667b282d 100644 --- a/packages/System/src/index.tsx +++ b/packages/System/src/index.tsx @@ -158,9 +158,3 @@ export const forwardRef = ( } export type ExtraSize = number | string - -/* utility type to remove state properties from options (will be corrected when migrating to ariakit) */ -export type OmitReakitState< - ComponentOptions extends { state: unknown }, - ReakitOptions -> = ComponentOptions & Omit diff --git a/packages/Table/package.json b/packages/Table/package.json index 2e72d90200..dfebcb7d90 100644 --- a/packages/Table/package.json +++ b/packages/Table/package.json @@ -31,7 +31,7 @@ "table", "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Tabs/package.json b/packages/Tabs/package.json index c103357f9f..a9d4a2289a 100644 --- a/packages/Tabs/package.json +++ b/packages/Tabs/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/tabs", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,10 +46,10 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/system": "^5.0.0-alpha.40", "@welcome-ui/utils": "^5.0.0-alpha.43", - "react-flatten-children": "^1.0.0", - "reakit": "^1.3.11" + "react-flatten-children": "^1.0.0" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", @@ -58,6 +58,6 @@ }, "gitHead": "974e7bfd71f8cfe846cbffd678c3860a8952f9e9", "sideEffects": false, - "component": "Tabs, useTabState", + "component": "Tabs, useTab", "homepage": "https://welcome-ui.com/components/tabs" } diff --git a/packages/Tabs/src/ActiveBar.tsx b/packages/Tabs/src/ActiveBar.tsx index a8c41889e4..c84a7b76cb 100644 --- a/packages/Tabs/src/ActiveBar.tsx +++ b/packages/Tabs/src/ActiveBar.tsx @@ -1,21 +1,22 @@ import React, { useState } from 'react' import { useViewportSize } from '@welcome-ui/utils' -import { TabStateReturn } from 'reakit' import { useIsomorphicLayoutEffect } from '@welcome-ui/utils' import * as S from './styles' -export interface ActiveBarStateReturn { +import { UseTabState } from '.' + +export interface ActiveBarReturn { offset?: number size?: number - orientation?: TabStateReturn['orientation'] + orientation?: UseTabState['orientation'] } -function useActiveBarState( +function useActiveBar( listRef: React.MutableRefObject, activeTab: HTMLElement, - orientation: TabStateReturn['orientation'] -): ActiveBarStateReturn { + orientation: UseTabState['orientation'] +): ActiveBarReturn { const [state, setState] = useState({}) const { height: viewportHeight, width: viewportWidth } = useViewportSize() @@ -53,10 +54,10 @@ export interface ActiveBarOptions { listRef: React.MutableRefObject } -export type ActiveBarProps = Pick & ActiveBarOptions +export type ActiveBarProps = Pick & ActiveBarOptions export const ActiveBar: React.FC = ({ activeTab, listRef, orientation }) => { - const activeBar = useActiveBarState(listRef, activeTab, orientation) + const activeBar = useActiveBar(listRef, activeTab, orientation) return } diff --git a/packages/Tabs/src/TabList.tsx b/packages/Tabs/src/TabList.tsx index fd01581803..1bdef62703 100644 --- a/packages/Tabs/src/TabList.tsx +++ b/packages/Tabs/src/TabList.tsx @@ -1,5 +1,5 @@ import React, { cloneElement, useRef, useState } from 'react' -import { TabList as ReakitTabList, TabStateReturn } from 'reakit' +import * as Ariakit from '@ariakit/react' import reactFlattenChildren from 'react-flatten-children' import { useForkRef } from '@welcome-ui/utils' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' @@ -7,19 +7,21 @@ import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import { ActiveBar } from './ActiveBar' import * as S from './styles' +import { UseTab, UseTabState } from '.' + // because of the compatibility of esm standard. Since this lib is no longer maintained, no issue was created // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const flattenChildren = reactFlattenChildren.default || reactFlattenChildren function useTrackActiveTabs( - state: Pick, + selectedId: UseTabState['selectedId'], children: React.ReactNode ): [ReturnType, HTMLElement] { const [activeTab, setActiveTab] = useState(null) const tabs = flattenChildren(children).map((child: React.ReactElement) => { - if (child.props.id === state.selectedId) { + if (child.props.id === selectedId) { return cloneElement(child, { ref: setActiveTab }) } return child @@ -32,7 +34,7 @@ export interface SizeOptions { } export type TabListOptions = SizeOptions & { - state: Pick + store: UseTab } export type TabListProps = CreateWuiProps<'div', TabListOptions> @@ -40,18 +42,18 @@ export type TabListProps = CreateWuiProps<'div', TabListOptions> * @name Tabs.TabList */ export const TabList = forwardRef<'div', TabListProps>( - ({ as, children, size = 'md', state = {}, ...rest }, ref) => { + ({ as, children, size = 'md', store, ...rest }, ref) => { const listRef = useRef() const listForkedRef = useForkRef(ref, listRef) - const { orientation } = state - const [tabs, activeTab] = useTrackActiveTabs({ selectedId: state.selectedId }, children) + const { orientation, selectedId } = store.useState() + const [tabs, activeTab] = useTrackActiveTabs(selectedId, children) return ( - {tabListProps => ( @@ -62,7 +64,7 @@ export const TabList = forwardRef<'div', TabListProps>( )}
)} - + ) } ) diff --git a/packages/Tabs/src/TabPanel.tsx b/packages/Tabs/src/TabPanel.tsx index 24138e618c..3de52dc9b2 100644 --- a/packages/Tabs/src/TabPanel.tsx +++ b/packages/Tabs/src/TabPanel.tsx @@ -1,25 +1,29 @@ import React from 'react' -import { TabPanel as ReakitTabPanel, TabStateReturn } from 'reakit' +import * as Ariakit from '@ariakit/react' import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import * as S from './styles' -export type TabPanelOptions = { state: TabStateReturn } -export type TabPanelProps = CreateWuiProps +import { UseTab } from '.' + +export type TabPanelOptions = { store: UseTab } +export type TabPanelProps = CreateWuiProps /** * @name Tabs.TabPanel */ export const TabPanel = forwardRef<'div', TabPanelProps>( - ({ as, children, state, tabId, ...rest }, ref) => { + ({ as, children, store, tabId, ...rest }, ref) => { + const orientation = store.useState('orientation') + return ( - + {tabPanelProps => ( - + {children} )} - + ) } ) diff --git a/packages/Tabs/src/index.tsx b/packages/Tabs/src/index.tsx index f63dc8efc2..49be69d277 100644 --- a/packages/Tabs/src/index.tsx +++ b/packages/Tabs/src/index.tsx @@ -1,27 +1,27 @@ import React from 'react' -import { Tab as ReakitTab, TabOptions as ReakitTabOptions, TabStateReturn } from 'reakit' -import { CreateWuiProps, forwardRef, OmitReakitState } from '@welcome-ui/system' +import * as Ariakit from '@ariakit/react' +import { CreateWuiProps, forwardRef } from '@welcome-ui/system' import { TabList } from './TabList' import { TabPanel } from './TabPanel' import * as S from './styles' -export type TabOptions = { state: TabStateReturn } -export type TabProps = CreateWuiProps<'button', OmitReakitState> +export type TabOptions = { store: UseTab } +export type TabProps = CreateWuiProps<'button', TabOptions> /** * @name Tabs */ export const TabComponent = forwardRef<'button', TabProps>( - ({ as, children, id, state, ...rest }, ref) => { + ({ as, children, id, store, ...rest }, ref) => { return ( - + {tabProps => ( {children} )} - + ) } ) @@ -30,4 +30,10 @@ TabComponent.displayName = 'Tab' export const Tab = Object.assign(TabComponent, { List: TabList, Panel: TabPanel }) -export { useTabState } from 'reakit' +export type UseTab = Ariakit.TabStore +export type UseTabProps = Ariakit.TabStoreProps +export type UseTabState = Ariakit.TabStoreState + +export function useTab(options?: UseTabProps): UseTab { + return Ariakit.useTabStore(options) +} diff --git a/packages/Tabs/src/styles.ts b/packages/Tabs/src/styles.ts index cf15af97a7..2b5123dfc8 100644 --- a/packages/Tabs/src/styles.ts +++ b/packages/Tabs/src/styles.ts @@ -1,9 +1,10 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { TabStateReturn } from 'reakit' -import { ActiveBarStateReturn } from './ActiveBar' +import { ActiveBarReturn } from './ActiveBar' import { SizeOptions } from './TabList' +import { UseTabState } from '.' + export const TabList = styled.div<{ size: SizeOptions }>( ({ size }) => css` position: relative; @@ -69,7 +70,7 @@ export const Tab = styled.button` } ` -export const TabPanel = styled.div>( +export const TabPanel = styled.div>( ({ orientation }) => css` ${orientation === 'vertical' ? th('tabs.panel.vertical') : th('tabs.panel.horizontal')}; ` @@ -91,7 +92,7 @@ const activeBarVerticalStyles = ({ offset = 0, size = 0 }) => css` transform: translateY(${offset}px); ` -export const ActiveBar = styled.span( +export const ActiveBar = styled.span( ({ orientation, ...rest }) => css` position: absolute; ${orientation === 'vertical' ? activeBarVerticalStyles(rest) : activeBarHorizontalStyles(rest)} diff --git a/packages/Tabs/tests/index.test.tsx b/packages/Tabs/tests/index.test.tsx index f9cb3ba8c5..b821d62ff2 100644 --- a/packages/Tabs/tests/index.test.tsx +++ b/packages/Tabs/tests/index.test.tsx @@ -2,7 +2,7 @@ import React from 'react' import userEvent from '@testing-library/user-event' import { render } from '../../../utils/tests' -import { Tab, useTabState } from '../src' +import { Tab, useTab } from '../src' function getActiveBar({ getByRole }: { getByRole: (id: string) => HTMLElement }) { const tabList = getByRole('tablist') @@ -12,27 +12,27 @@ function getActiveBar({ getByRole }: { getByRole: (id: string) => HTMLElement }) describe('Tabs', () => { it('renders an accessible structure', async () => { const Tabs = () => { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Tab 2 - + Tab 3 - + Panel 1 - + Panel 2 - + Panel 3 @@ -80,15 +80,15 @@ describe('Tabs', () => { describe('with one tab', () => { it('does not render active bar', () => { const Tabs = () => { - const tabState = useTabState({ selectedId: 'tab1' }) + const tab = useTab({ defaultSelectedId: 'tab1' }) return ( <> - - + + Tab 1 - + Panel 1 diff --git a/packages/Tag/package.json b/packages/Tag/package.json index 9825a8aa71..9d055fb316 100644 --- a/packages/Tag/package.json +++ b/packages/Tag/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/tag", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Text/package.json b/packages/Text/package.json index 01097a67d9..6f890794de 100644 --- a/packages/Text/package.json +++ b/packages/Text/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/text", "version": "5.0.0-alpha.40", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Textarea/package.json b/packages/Textarea/package.json index 4ec0e68379..84b43dc7b3 100644 --- a/packages/Textarea/package.json +++ b/packages/Textarea/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/textarea", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Themes/Dark/package.json b/packages/Themes/Dark/package.json index 1a0c63ebe4..a8d88fcbd0 100644 --- a/packages/Themes/Dark/package.json +++ b/packages/Themes/Dark/package.json @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Themes/Welcome/package.json b/packages/Themes/Welcome/package.json index 1b35beb39a..b3ed07d27e 100644 --- a/packages/Themes/Welcome/package.json +++ b/packages/Themes/Welcome/package.json @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Themes/WelcomeDark/package.json b/packages/Themes/WelcomeDark/package.json index c1b5954029..6fed4a519f 100644 --- a/packages/Themes/WelcomeDark/package.json +++ b/packages/Themes/WelcomeDark/package.json @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/TimePicker/package.json b/packages/TimePicker/package.json index bd9cf0b05b..2f59f98bb7 100644 --- a/packages/TimePicker/package.json +++ b/packages/TimePicker/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/time-picker", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Toast/package.json b/packages/Toast/package.json index dd7a9d842b..251df2804c 100644 --- a/packages/Toast/package.json +++ b/packages/Toast/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/toast", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -33,7 +33,7 @@ "snackbar", "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Toggle/package.json b/packages/Toggle/package.json index 93899b6883..1d86e24123 100644 --- a/packages/Toggle/package.json +++ b/packages/Toggle/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,9 +46,9 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { + "@ariakit/react": "0.2.14", "@welcome-ui/checkbox": "^5.0.0-alpha.43", - "@welcome-ui/system": "^5.0.0-alpha.40", - "reakit": "^1.3.11" + "@welcome-ui/system": "^5.0.0-alpha.40" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Toggle/src/styles.ts b/packages/Toggle/src/styles.ts index fab4a2dee6..6bd44440da 100644 --- a/packages/Toggle/src/styles.ts +++ b/packages/Toggle/src/styles.ts @@ -1,10 +1,10 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { Checkbox as ReakitCheckbox } from 'reakit' +import * as Ariakit from '@ariakit/react' import { shouldForwardProp } from '@welcome-ui/system' import { ToggleOptions } from './index' -export const Toggle = styled(ReakitCheckbox).withConfig({ shouldForwardProp })( +export const Toggle = styled(Ariakit.Checkbox).withConfig({ shouldForwardProp })( ({ order = '-1' }) => css` ${th('toggles.item.default')}; position: relative; diff --git a/packages/Tooltip/package.json b/packages/Tooltip/package.json index 05d0a54bd7..c0feaa7203 100644 --- a/packages/Tooltip/package.json +++ b/packages/Tooltip/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", @@ -46,11 +46,7 @@ "url": "https://github.com/WTTJ/welcome-ui/issues" }, "dependencies": { - "@welcome-ui/box": "^5.0.0-alpha.40", - "@welcome-ui/system": "^5.0.0-alpha.40", - "@welcome-ui/utils": "^5.0.0-alpha.43", - "popper.js": "^1.16.1", - "reakit": "^1.3.11" + "@ariakit/react": "0.2.14" }, "peerDependencies": { "@xstyled/styled-components": "^3.7.3", diff --git a/packages/Tooltip/src/index.tsx b/packages/Tooltip/src/index.tsx index 69d1c08350..616633f757 100644 --- a/packages/Tooltip/src/index.tsx +++ b/packages/Tooltip/src/index.tsx @@ -1,153 +1,73 @@ -import React, { cloneElement, useCallback, useEffect, useRef, useState } from 'react' -import Popper, { Placement } from 'popper.js' -import { TooltipReference, useTooltipState } from 'reakit' -import { useDialogState } from 'reakit' -import { CreateWuiProps, forwardRef } from '@welcome-ui/system' -import { Box } from '@welcome-ui/box' -import { useIsomorphicLayoutEffect } from '@welcome-ui/utils' +import React, { ReactElement, useEffect, useState } from 'react' +import * as Ariakit from '@ariakit/react' import * as S from './styles' -const useMouseTooltipState = ({ - placement: originalPlacement, - ...rest -}: { placement?: Placement } = {}) => { - const popper = useRef(null) - const referenceRef = useRef(null) - const mouseRef = useRef(null) - const popoverRef = useRef(null) - - const [placement, setPlacement] = useState(originalPlacement) - const [popoverStyles, setPopoverStyles] = useState({}) +export type TooltipProps = { + children: React.ReactNode + content: string | JSX.Element + fixed?: boolean + placement?: Ariakit.TooltipStoreProps['placement'] +} - const dialog = useDialogState(rest) +export const Tooltip = ({ + children, + content, + fixed = false, + placement = fixed ? 'top' : 'bottom', +}: TooltipProps): React.ReactElement => { + const tooltip = Ariakit.useTooltipStore({ placement, animated: true }) + const [position, setPosition] = useState({ x: 0, y: 0 }) + const getState = tooltip.getState + const render = tooltip.render + + const updatePosition = () => { + const { mounted, popoverElement } = getState() + + if (!popoverElement) return + + Object.assign(popoverElement.style, { + display: mounted ? 'block' : 'none', + position: 'absolute', + left: `${position.x}px`, + top: `${position.y + window.scrollY + 20}px`, + }) + } - const createPopper = useCallback(() => { - if ((mouseRef.current || referenceRef.current) && popoverRef.current) { - popper.current = new Popper(mouseRef.current || referenceRef.current, popoverRef.current, { - placement: originalPlacement, - eventsEnabled: dialog.visible, - modifiers: { - applyStyle: { enabled: false }, - updateStateModifier: { - order: 900, - enabled: true, - fn: data => { - setPlacement(data.placement) - setPopoverStyles(data.styles) - return data - }, - }, - }, - }) - } - }, [originalPlacement, dialog.visible]) + const child = (children as JSX.Element)?.props?.disabled + ? React.Children.only({children}) + : children - useIsomorphicLayoutEffect(() => { - createPopper() - return () => { - if (popper.current) { - popper.current.destroy() - } + useEffect(() => { + function onMouseMove({ clientX, clientY }: { clientX: number; clientY: number }) { + setPosition({ x: clientX, y: clientY }) + render() } - }, [createPopper]) - useEffect(() => { - const reference = referenceRef.current + const { anchorElement } = getState() - const paddingTop = placement.startsWith('top') ? 5 : 0 - const paddingBottom = placement.startsWith('bottom') ? 20 : 0 - const paddingLeft = placement.startsWith('left') ? 5 : 0 - const paddingRight = placement.startsWith('right') ? 15 : 0 + if (anchorElement && !fixed) { + anchorElement.addEventListener('mousemove', onMouseMove) - const onMouseMove = (event: MouseEvent) => { - mouseRef.current = { - getBoundingClientRect: () => ({ - ...reference.getBoundingClientRect(), - top: event.clientY - paddingTop, - bottom: event.clientY + paddingBottom, - left: event.clientX - paddingLeft, - right: event.clientX + paddingRight, - }), - } - createPopper() - } - if (reference) { - reference.addEventListener('mousemove', onMouseMove) - } - return () => { - mouseRef.current = null - if (reference) { - reference.removeEventListener('mousemove', onMouseMove) + return () => { + anchorElement.removeEventListener('mousemove', onMouseMove) } } - }, [createPopper, placement]) + }, [render, fixed, getState]) - return { - ...dialog, - unstable_referenceRef: referenceRef, - unstable_popoverRef: popoverRef, - unstable_popoverStyles: popoverStyles, - placement, - } -} - -export type PlacementOptions = - | 'auto-start' - | 'auto' - | 'auto-end' - | 'top-start' - | 'top' - | 'top-end' - | 'right-start' - | 'right' - | 'right-end' - | 'bottom-end' - | 'bottom' - | 'bottom-start' - | 'left-end' - | 'left' - | 'left-start' - -export interface TooltipOptions { - children: React.ReactNode - content: string | JSX.Element - fixed?: boolean - placement?: PlacementOptions -} - -export type TooltipProps = CreateWuiProps<'div', TooltipOptions> - -export const Tooltip = forwardRef<'div', TooltipProps>((props, ref): React.ReactElement => { - const { - children, - content, - fixed = false, - placement = fixed ? 'top' : 'bottom-start', - ...rest - } = props - const useCorrectTooltipState = fixed ? useTooltipState : useMouseTooltipState - const tooltip = useCorrectTooltipState({ placement, animated: true }) // If no content, simply return the children if (!content) { return children as React.ReactElement } - const child = (children as JSX.Element)?.props?.disabled - ? React.Children.only({children}) - : children - return ( <> - - {referenceProps => cloneElement(child as JSX.Element, referenceProps)} - - - + + {content} - + ) -}) +} diff --git a/packages/Tooltip/src/styles.ts b/packages/Tooltip/src/styles.ts index 0a5d70362e..fc6d1325da 100644 --- a/packages/Tooltip/src/styles.ts +++ b/packages/Tooltip/src/styles.ts @@ -1,14 +1,7 @@ import styled, { css, system, th } from '@xstyled/styled-components' -import { Tooltip as ReakitTooltip } from 'reakit' -import { filterSystemProps } from '@welcome-ui/system' -import { PlacementOptions } from './index' +import { TooltipProps } from './index' -export const Tooltip = styled(ReakitTooltip).withConfig({ shouldForwardProp: filterSystemProps })( - () => css` - ${system}; - ` -) const transformDirection = { top: 'translate3d(0, -4px, 0)', right: 'translate3d(4px, 0, 0)', @@ -33,25 +26,43 @@ const getFadeInDirection = (placement: string) => { } } -export const FadeIn = styled.div<{ - placement?: PlacementOptions +const fadeInStyle = css` + visibility: visible; + opacity: 1; + transform: translate3d(0, 0, 0); +` + +type FadeIn = { + placement?: TooltipProps['placement'] fixed?: boolean -}>` - ${th('tooltips')}; - ${system}; - transition: opacity ${th.transition('medium')}, transform ${th.transition('medium')}, - visibility ${th.transition('medium')}; - visibility: hidden; - opacity: 0; - transform-origin: top center; - transform: ${({ fixed, placement }) => { - if (!fixed) return - return getFadeInDirection(placement) - // return transformDirection[placementOption] - }}; - [data-enter] & { - visibility: visible; - opacity: 1; - transform: translate3d(0, 0, 0); - } + isOpen?: boolean +} + +export const FadeIn = styled.div( + ({ fixed, isOpen, placement }) => css` + ${th('tooltips')}; + ${system}; + transition: opacity ${th.transition('medium')}, transform ${th.transition('medium')}, + visibility ${th.transition('medium')}; + visibility: hidden; + opacity: 0; + transform-origin: top center; + ${fixed && + css` + transform: ${getFadeInDirection(placement)}; + `} + + [data-enter] & { + ${fadeInStyle} + } + + ${isOpen && + css` + ${fadeInStyle} + `} + ` +) + +export const ChildItem = styled.div` + display: inline-block; ` diff --git a/packages/UniversalLink/package.json b/packages/UniversalLink/package.json index 819632b357..b089a965af 100644 --- a/packages/UniversalLink/package.json +++ b/packages/UniversalLink/package.json @@ -30,7 +30,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/Utils/package.json b/packages/Utils/package.json index f7fa5e8152..bad0fada5e 100644 --- a/packages/Utils/package.json +++ b/packages/Utils/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/utils", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/packages/VariantIcon/package.json b/packages/VariantIcon/package.json index 6708ff37fb..da405b49ec 100644 --- a/packages/VariantIcon/package.json +++ b/packages/VariantIcon/package.json @@ -1,7 +1,7 @@ { "name": "@welcome-ui/variant-icon", "version": "5.0.0-alpha.43", - "description": "Customizable design system with react • styled-components • styled-system and reakit.", + "description": "Customizable design system with react • styled-components • styled-system and ariakit.", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/types/index.d.ts", @@ -27,7 +27,7 @@ "keywords": [ "design-system", "react", - "reakit", + "ariakit", "styled-components", "styled-system", "ui-library", diff --git a/scripts/doc-props.js b/scripts/doc-props.js index f9a762ec21..36a387e161 100644 --- a/scripts/doc-props.js +++ b/scripts/doc-props.js @@ -12,7 +12,7 @@ const shouldDisplayPropsFiles = [ 'packages/Utils/dist/types/field-styles.d.ts', 'packages/Button/dist/types/index.d.ts', 'packages/InputText/dist/types/index.d.ts', - 'welcome-ui/node_modules/reakit/ts/Tab/TabState.d.ts', + 'welcome-ui/node_modules/ariakit/ts/Tab/TabStore.d.ts', ] // Get only ComponentOptions declarations for prevent all WuiProps diff --git a/scripts/watch.js b/scripts/watch.js index a922d485a3..4547b14a05 100644 --- a/scripts/watch.js +++ b/scripts/watch.js @@ -16,22 +16,6 @@ const handleFileChange = () => { const { component, name } = require(`${packagePath}/package.json`) console.log(`Building ${component}…`.grey) - exec(`npx lerna run build --scope ${name}`, err => { - if (err) { - console.error(err) - return - } - console.log(date, '-', '(っ◔◡◔)っ success'.green.bold, `(${component})`) - }) - - exec(`npx lerna run doc --scope ${name}`, err => { - if (err) { - console.error(err) - return - } - console.log(date, '-', '(っ◔◡◔)っ types success'.green.bold, `(${component})`) - }) - if (file === 'theme.ts') { console.log('Building Core…'.grey) exec('npx lerna run build --scope @welcome-ui/core', err => { @@ -42,14 +26,46 @@ const handleFileChange = () => { console.log(date, '-', '(っ◔◡◔)っ success'.green.bold, '(core)') }) - exec('npx lerna run doc --scope @welcome-ui/core', err => { + exec('npx lerna run types --scope @welcome-ui/core', err => { if (err) { console.error(err) return } console.log(date, '-', '(っ◔◡◔)っ types success'.green.bold, '(core)') }) + + exec('npx lerna run doc --scope @welcome-ui/core', err => { + if (err) { + console.error(err) + return + } + console.log(date, '-', '(っ◔◡◔)っ doc success'.green.bold, `(${component})`) + }) } + + exec(`npx lerna run build --scope ${name}`, err => { + if (err) { + console.error(err) + return + } + console.log(date, '-', '(っ◔◡◔)っ success'.green.bold, `(${component})`) + }) + + exec(`npx lerna run types --scope ${name}`, err => { + if (err) { + console.error(err) + return + } + console.log(date, '-', '(っ◔◡◔)っ types success'.green.bold, `(${component})`) + }) + + exec(`npx lerna run doc --scope ${name}`, err => { + if (err) { + console.error(err) + return + } + console.log(date, '-', '(っ◔◡◔)っ doc success'.green.bold, `(${component})`) + }) } } diff --git a/yarn.lock b/yarn.lock index ed3b7dbd72..48df00747c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -146,6 +146,27 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@ariakit/core@0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@ariakit/core/-/core-0.2.7.tgz#b7ee9d44ec552f3010201ed01c4f40f18afc48c3" + integrity sha512-Hs0N1EMYq88WW4v9xnSIHNR38TvbQuoUX6FYFmeLCZSTIXQBiET7lr1DQXwOOmdEtRtlxQ5HsxbTkxeOkPv+eg== + +"@ariakit/react-core@0.2.14": + version "0.2.14" + resolved "https://registry.yarnpkg.com/@ariakit/react-core/-/react-core-0.2.14.tgz#edd6f50fd7dea2e98d189797be963b45872da3e3" + integrity sha512-eJ7dMuReQwf3Fyn5enb7owFQ9hsvizBV9Uyze86HLLKehkeQ1fhikZxVbIoDBmO7y8UolEPYAGE595fVTx+Oig== + dependencies: + "@ariakit/core" "0.2.7" + "@floating-ui/dom" "^1.0.0" + use-sync-external-store "^1.2.0" + +"@ariakit/react@0.2.14": + version "0.2.14" + resolved "https://registry.yarnpkg.com/@ariakit/react/-/react-0.2.14.tgz#ef965f51b2cc31d76619ee4baaf2bc790ea75297" + integrity sha512-Q5YU8QJYqRL2/CQr/jDRt5QuRn+xZMf1VGDnbfnqjOEgwMdllR3HRiOYBXDGOoF7rlMdaiej6VMfyp0DvW87bQ== + dependencies: + "@ariakit/react-core" "0.2.14" + "@babel/cli@7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.22.5.tgz#eb323bd69f50297792c2b7c205a97306a305d703" @@ -2014,6 +2035,18 @@ p-limit "^3.1.0" readable-stream "^4.0.0" +"@floating-ui/core@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.3.1.tgz#4d795b649cc3b1cbb760d191c80dcb4353c9a366" + integrity sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g== + +"@floating-ui/dom@^1.0.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.4.2.tgz#eb3a37f7506c4f95ef735967dc3496b5012e11cb" + integrity sha512-VKmvHVatWnewmGGy+7Mdy4cTJX71Pli6v/Wjb5RQBuq5wjUYx+Ef+kRThi8qggZqDgD8CogCpqhRoVp3+yQk+g== + dependencies: + "@floating-ui/core" "^1.3.1" + "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -3893,7 +3926,7 @@ "@pnpm/network.ca-file" "^1.0.1" config-chain "^1.1.11" -"@popperjs/core@^2.5.4", "@popperjs/core@^2.9.2": +"@popperjs/core@^2.9.2": version "2.11.6" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== @@ -5873,11 +5906,6 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -"body-scroll-lock@=3.1.5 ", body-scroll-lock@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz#c1392d9217ed2c3e237fee1e910f6cdd80b7aaec" - integrity sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg== - boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -15288,7 +15316,7 @@ rc@1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-animate-height@^3.1.1: +react-animate-height@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/react-animate-height/-/react-animate-height-3.2.2.tgz#ae15d3ef6396f45140c60af4081d43d7dd093cda" integrity sha512-uUOS+RhYVgyJEWcuAJgelVwhcJ2chsMk7HZCpu+wtjSlFAGSFsHU0r4lMTt47HQ1RdQfI5MmFRt43yHTP9lfmQ== @@ -15653,36 +15681,6 @@ readdirp@^3.4.0, readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -reakit-system@^0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/reakit-system/-/reakit-system-0.15.2.tgz#a485fab84b3942acbed6212c3b56a6ef8611c457" - integrity sha512-TvRthEz0DmD0rcJkGamMYx+bATwnGNWJpe/lc8UV2Js8nnPvkaxrHk5fX9cVASFrWbaIyegZHCWUBfxr30bmmA== - dependencies: - reakit-utils "^0.15.2" - -reakit-utils@^0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/reakit-utils/-/reakit-utils-0.15.2.tgz#b4d5836e534576bfd175171541d43182ad97f2d2" - integrity sha512-i/RYkq+W6hvfFmXw5QW7zvfJJT/K8a4qZ0hjA79T61JAFPGt23DsfxwyBbyK91GZrJ9HMrXFVXWMovsKBc1qEQ== - -reakit-warning@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/reakit-warning/-/reakit-warning-0.6.2.tgz#9c346ae483eb1f284f2088653f90cabd26dbee56" - integrity sha512-z/3fvuc46DJyD3nJAUOto6inz2EbSQTjvI/KBQDqxwB0y02HDyeP8IWOJxvkuAUGkWpeSx+H3QWQFSNiPcHtmw== - dependencies: - reakit-utils "^0.15.2" - -reakit@^1.3.11: - version "1.3.11" - resolved "https://registry.yarnpkg.com/reakit/-/reakit-1.3.11.tgz#c15360ac43e94fbe4291d233af3ac5040428252e" - integrity sha512-mYxw2z0fsJNOQKAEn5FJCPTU3rcrY33YZ/HzoWqZX0G7FwySp1wkCYW79WhuYMNIUFQ8s3Baob1RtsEywmZSig== - dependencies: - "@popperjs/core" "^2.5.4" - body-scroll-lock "^3.1.5" - reakit-system "^0.15.2" - reakit-utils "^0.15.2" - reakit-warning "^0.6.2" - real-require@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" @@ -18136,7 +18134,7 @@ use-editable@^2.3.3: resolved "https://registry.yarnpkg.com/use-editable/-/use-editable-2.3.3.tgz#a292fe9ba4c291cd28d1cc2728c75a5fc8d9a33f" integrity sha512-7wVD2JbfAFJ3DK0vITvXBdpd9JAz5BcKAAolsnLBuBn6UDDwBGuCIAGvR3yA2BNKm578vAMVHFCWaOcA+BhhiA== -use-sync-external-store@1.2.0: +use-sync-external-store@1.2.0, use-sync-external-store@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==