ariakit / ariakit

Toolkit for building accessible web apps with React

Home Page:https://ariakit.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Migrating from v0 to v1

diegohaz opened this issue · comments

commented

Migrating from v0 to v1

I think experimentation is the only way to get things right. In v0, we've been experimenting a lot, often with approaches that were controversial by the time we came up with them. Some of them worked. Some others, not so much. I tried to keep the good things in v1, improve the things that could be improved and discard the ones that weren't good at all.

I've been working on this v1 directly since November 2018, when I started writing this gist as an attempt to come up with a hooks-only API. I even implemented an early version of this in a private project to finally realize that a hooks-only API doesn't provide much ergonomics for most developers, but it's really amazing for composability.

This is intended to be a living document. I'm going to update it over time, and I hope it's finished by the time v1 comes out of beta. If something is missing here, please comment down.

🚨 Important note 🚨

There are many breaking changes. And I understand that people may get a little upset about it. If v0.x is working well for you, there's no need to upgrade to v1 so soon. The same happened to Rebass and Material-UI, for example. I'll keep merging bug fixes into the v0 branch and you can keep accessing the v0 docs. Take your time and make a gradual migration only when necessary (for example, if you need some new feature that's only available in v1).

Gradual migration

You can leverage Yarn's ability to install multiple versions of a package:

yarn add reakit-next@npm:reakit@1.0.0-beta.0
import { Provider as ReakitProvider } from "reakit"; // v0
import { Provider as NextReakitProvider } from "reakit-next"; // v1

Alternatively, if it's not enough, there may be a Reakit v0 version with a /next path.

No styled-components

Dependency on styled-components has been removed, which means we don't re-export its members anymore. You're free to use any version of SC or another CSS library without worrying about bundle size.

Before:

import { styled, Box } from "reakit";

After:

import { Box } from "reakit";
import styled from "styled-components";

Primitives

Since the core library doesn't care about styles anymore, these styled components have been removed. They can be re-created with styled-components.

Before:

import { Block, Flex, Grid, Inline, InlineBlock, InlineFlex } from "reakit";

After:

import { Box } from "reakit";
import styled from "styled-components";

const Block = styled(Box)`display: block;`;
const Flex = styled(Box)`display: flex;`;
const Grid = styled(Box)`display: grid;`;
const Inline = styled(Box)`display: inline;`;
const InlineBlock = styled(Box)`display: inline-block;`;
const InlineFlex = styled(Box)`display: inline-flex;`;

CSS Props

Since the core library doesn't care about styles anymore, these props have been removed. You can use inline style directly.

Before:

<Box marginRight={100} color="red" />

After:

<Box style={{ marginRight: 100, color: "red" }} />

as/use props

In v0.16, we introduced the use prop as a replacement to the as prop. The main motivation behind this change was that the as prop conflicted with the styled-components' one. And, since Reakit's one behaved differently (by accepting an array of components, for example), that made sense to rename the prop.

Now that we're not limited to styled-components anymore and this works exactly like in other libraries (accepting only one component), we're back to the as prop for consistency.

Before:

<Hidden use="div" />
<Hidden use={Button} />
<Hidden use={[Button, "div"]} />

After:

<Hidden as="div" />
<Hidden as={Button} />
// using render props: https://reakit.io/docs/basic-concepts/#render-props
<Hidden>{props => <Button as="div" {...props} />}</Hidden>

Theming

Reakit doesn't depend on styled-components anymore. You can use Reakit v0 theme by wrapping components with your own version of styled-components.

Before:

import { Provider, Button, css } from "reakit";

const theme = {
  Button: css`
    color: red;
  `;
};

<Provider theme={theme}>
  <Button />
</Provider>

After:

import { Button as ReakitButton } from "reakit";
import { ThemeProvider, styled, css } from "styled-components";

const theme = {
  Button: css`
    color: red;
  `;
};

const Button = styled(ReakitButton)(props => props.theme.Button);

<ThemeProvider theme={theme}>
  <Button />
</ThemeProvider>

Hidden

Hidden.Container has been replaced by the useHiddenState hook. Hidden.Show, Hidden.Hide and Hidden.Toggle have been removed. HiddenDisclosure can be used instead.

Before:

import { Hidden } from "reakit";

function MyHidden() {
  return (
    <Hidden.Container>
      {hidden => (
        <>
          <Hidden.Show {...hidden}>Show</Hidden.Show>
          <Hidden.Hide {...hidden}>Hide</Hidden.Hide>
          <Hidden.Toggle {...hidden}>Toggle</Hidden.Toggle>
          <Hidden {...hidden}>Hidden</Hidden>
        </>
      )}
    </Hidden.Container>
  );
}

After:

import { useHiddenState, Hidden, HiddenDisclosure } from "reakit";

function MyHidden() {
  const hidden = useHiddenState();
  return (
    <>
      <button onClick={hidden.show}>Show</button>
      <button onClick={hidden.hide}>Hide</button>
      <HiddenDisclosure {...hidden}>Toggle</HiddenDisclosure>
      <Hidden {...hidden}>Hidden</Hidden>
    </>
  );
}

Overlay

Overlay has been replaced by Dialog.

Before:

import { Overlay, Backdrop } from "reakit";

function MyOverlay() {
  return (
    <Overlay.Container>
      {overlay => (
        <>
          <Overlay.Show {...overlay}>Click me</Overlay.Show>
          <Backdrop use={Overlay.Hide} {...overlay} />
          <Overlay {...overlay}>Overlay</Overlay>
        </>
      )}
    </Overlay.Container>
  );
}

After:

import { useDialogState, Dialog, DialogDisclosure, DialogBackdrop } from "reakit";

function MyOverlay() {
  const dialog = useDialogState();
  return (
    <>
      <DialogDisclosure {...dialog}>Click me</DialogDisclosure>
      <DialogBackdrop {...dialog} />
      <Dialog {...dialog} aria-label="My overlay">Dialog</Dialog>
    </>
  );
}

Popover

TODO

Sidebar

Before:

import { Button, Backdrop, Sidebar } from "reakit";

function MySidebar() {
  return (
    <Sidebar.Container>
      {sidebar => (
        <>
          <Button use={Sidebar.Show} {...sidebar}>
            Open sidebar
          </Button>
          <Backdrop use={Sidebar.Hide} {...sidebar} />
          <Sidebar {...sidebar}>Sidebar</Sidebar>
        </>
      )}
    </Sidebar.Container>
  );
}

After:

import { useDialogState, Dialog, DialogDisclosure, DialogBackdrop } from "reakit";
import styled from "styled-components";

const Sidebar = styled(Dialog)`
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  overflow: auto;
`;

function MySidebar() {
  const dialog = useDialogState();
  return (
    <>
      <DialogDisclosure {...dialog}>Open sidebar</DialogDisclosure>
      <DialogBackdrop {...dialog} />
      <Sidebar {...dialog}>Sidebar</Sidebar>
    </>
  );
}

Step

If people find it useful, it's possible to have this component in Reakit again in v1. In the meanwhile, it can be re-created with Hidden and useRoverState.

Before:

import { Step, Button } from "reakit";

function MyStep() {
  return (
    <Step.Container initialState={{ current: 0 }}>
      {step => (
        <>
          <Button use={Step.Previous} {...step}>Previous</Button>
          <Button use={Step.Next} {...step}>Next</Button>
          <Step step="Step 1" {...step}>Step 1</Step>
          <Step step="Step 2" {...step}>Step 2</Step>
          <Step step="Step 3" {...step}>Step 3</Step>
        </>
      )}
    </Step.Container>
  );
}

After:

import { useRoverState, Hidden } from "reakit";

function Step(props) {
  const ref = React.useRef();
  
  React.useEffect(() => {
    props.register(props.step, ref);
    return () => props.unregister(props.step);
  }, [props.register, props.unregister, props.step]);
  
  return (
    <Hidden
      ref={ref}
      visible={props.step === props.currentId}
      {...props}
    />
  );
}

function MyStep() {
  const rover = useRoverState({ currentId: "step1" });
  return (
    <>
      <button onClick={rover.previous}>Previous</button>
      <button onClick={rover.next}>Next</button>
      <Step step="step1" {...rover}>Step 1</Step>
      <Step step="step2" {...rover}>Step 2</Step>
      <Step step="step3" {...rover}>Step 3</Step>
    </>
  );
}

Tabs

TODO

Toolbar

TODO

Tooltip

TODO

Backdrop

TODO

Button

TODO

Divider

It has been replaced by Separator to match the WAI-ARIA role.

Before:

import { Divider } from "reakit";

<Divider vertical />

After:

import { Separator } from "reakit";

<Separator orientation="vertical" />

Half of all components since 0.16.0 seem to be gone (Grid, Image, Flex etc).

When I try the Box component, the CSS props functionality (marginRight={100}) as well seem to be gone.

I absolutely love experimentation as well. I do it daily. You're doing an amazing job with all libraries out there, but just want to let you know that this is (for me) mostly a completely new library from an API point of view.

Any suggestion how to mitigate the situation when heavily dependent on the components/functionality prior to 1.0?

commented

@axhamre I'm sorry about that. This is not a different library. It's just more focused.

The components that have been removed were pretty minimal. They can be easily implemented in the user land. I've written a simple guide to CSS props. Please, tell me if you need more details on that.

Also, please list the components you rely on the most so I can prioritize them for the guide (same for anyone reading this).

Jesus Christ, I just migrated from 0.15 to 0.16 (with lots of breaking changes, such as the use="" instead of as="") and now I see that as is back and most of the components written with reakit need to be basically re-written. Absolutely crazy!!!!!!! Why would you remove Flex and Grid as they were immensely useful alongside with casually dropping a backgroundColor="" when you needed it, instead of creating a style for that? You say you are more focused. Fine, but I am not sure you have asked your users enough what they liked about Reakit and what they used it for. Very disappointed fan here!

commented

@paulbalogh Reading your comment makes me sad as I've worked hard to make this release the best for everyone.

Fine, but I am not sure you have asked your users enough what they liked about Reakit and what they used it for.

I did, but I don't see your feedback on #261 or #288 or #345 or here. I can't find you on any of our communities so I could've asked privately as I did with some people. I can't find your email listed in our mailing list so I could tell you about the v1.0.0-alpha release more than a month ago. I've been tweeting about this release since v0.16.0 got released. Where were you? If you care that much, why didn't you get involved?

Regardless, if a version is working well for you, why do you need to upgrade it? Why not just stick with 0.16? I'll keep merging bug fixes into the v0 branch. If you need features that are only available in v1, you can use the technique described in the Gradual migration section and import only that component.

That said, most of the things that changed can be re-created in just one file (for everything). List the components you rely on the most, and I do my best to provide a comprehensive guide for them.

Reakit has a codemod which was used in order to ease the transition from 0.15 to 0.16 (https://www.npmjs.com/package/reakit-codemods). We all provided ways to make users life easy, to make it reasonable to use. This library also followed semver strictly, where prior v1, everything can be considered as a breaking change.

@diegohaz - look, I probably need to apologise, these rants are not constructive especially when we are talking about a free library, maintained by the hard work of many people (btw, we are not only consuming, we are also contributing back, one of the members of our team is among your contributors). I have not seen the discussion threads you mention, even though I used reakit daily and I used the docs all the time to check the APIs I need. I have not seen any information on the upcoming v1. Took me entirely by surprise. Hence my shock last night on discovering the new version. (btw: neither the website nor the readme on git say anything about the current version or that v1 is still beta).

That being said, I only want to add this: the migration seems a massive pain. Especially if you don't have a big frontend team behind. We are a startup that switched from Semantic UI to reakit and loved what we found. I not sure now how or whether we will switch to v1. That is the only message I have. We may not be the only other user contemplating these choices.

commented

Comment that its pretty much a new library is a valid one; I'm in production and needed changes for upgrade are pretty huge. Especially when some of the components are plain missing in the new version. Ie, Sidebar is not a one liner userland fix.

Having said that, @diegohaz its perfectly fine you're driving this in direction you see best, but please pin a link for documentation of the 0.x version somewhere visible. This isnt an overnight change for users of your lib, and we still need an old docs.

commented

Added examples on Sidebar and made v0 references on README more evident. There's no final API for animations/transitions in v1 yet. There's an unstable_animated prop, but it's likely to change (hence the unstable_ prefix).

Please, keep listing the things so I can prioritize them on the guide.

commented

Please, keep listing the things so I can prioritize them on the guide.

Thank you. I would, but we're using pretty much every single thing on that list :) So take your time in this, we'll have to stick to 0.x until we have a clear upgrade plan and some cycles to actually do it.

Started upgrading to the beta today and hopefully will have most done by the end of the weekend.
Since my site is currently in a complete client-side rewrite I will go through everything. No gradual migration, going straight on the new version and dealing with what comes my way. 🚀

So far I'm missing from this guide components like Paragraph, Heading, Image (probably only needs a short mention) and themes.

commented

@StorytellerCZ Could you describe a bit how you used the themes? There are many ways to approach this, but I believe the most straight forward is to just use styled-components + styled-tools directly (if you're using styled-components).

I'm gonna update the post with this soon.

@paulbalogh You can install from a specific version and remove ^ from your package.json

@diegohaz Yes, I'm using styled-components with styled-tools. If I remember corectly I'm using the same approach as the old Reakit docs.

Missing:
Divider => Separator

Before

import { Divider } from 'reakit';

<Divider vertical />

After

import { Separator } from 'reakit';

<Separator orientation="vertical" />
commented

Added Divider. Thank you @StorytellerCZ

@diegohaz Thank you for all your hard work on the v1 of reakit! I'm loving the direction of v1 so far. I was wondering if you had any advice for Input since it is no longer provided? Should I just do

const Input = styled.input` /* styles here */ `
commented

Hey @stramel. We have plans to provide an abstract Input component in the future (once v1 gets out of beta, where we're focusing more on fixing bugs).

In the meanwhile, I suggest you to look at the code from v0:

reakit:
https://github.com/reakit/reakit/blob/fd10c8bd0c55f04a36c3b8f7d949c181a8b30d96/packages/reakit/src/Input/Input.ts#L1-L18

reakit-theme-default:
https://github.com/reakit/reakit/blob/fd10c8bd0c55f04a36c3b8f7d949c181a8b30d96/packages/reakit-theme-default/src/index.ts#L201-L225

Hello! I'm following the migration guide and installing reakit@1.0.0-beta5 as reakit-next. I'm running into the following issue:

TypeScript error in /Users/andresrodriguez/CFS/roadside-app/node_modules/reakit-system/src/createComponent.ts(3,30):
Cannot find module 'reakit/Box/Box'.  TS2307

    1 | // TODO: Refactor
    2 | import * as React from "react";
  > 3 | import { BoxHTMLProps } from "reakit/Box/Box";
      |                              ^
    4 | import { As, PropsWithAs } from "reakit-utils/types";
    5 | import { splitProps } from "reakit-utils/splitProps";
    6 | import { memo } from "./__utils/memo";
commented

@AndresRodH Could you please create a new issue? Don't forget to include your TypeScript version and trying 1.0.0-beta.4 just to make sure it's not a problem with the new release. Thanks! :)

@diegohaz sure thing! I'll downgrade and try again.

@diegohaz I just wanted to say that I use Reakit in production, and while a lot of stuff got broken in .15 to .16 and now again (and I haven't upgraded yet) - on paper a lot of what you've written out here makes sense and I'm excited to upgrade. Especially ditching Flex, FlexInline, etc, I see as a great choice. Keep up the great work!

Questions

  • Is the Link element removed? Is the equivalent <Box as="a">{children}</Box> ?
  • Are fade and slide no longer a valid properties on <Popover /> ? I feel these were really helpful.

Comments

Popover

Popover works extremely differently. For example, identical placement yields entirely different results. I'm not sure how to replicate the .16 behavior. (I'll make a separate ticket for this)

commented

@Slapbox

Is the Link element removed? Is the equivalent <Box as="a">{children}</Box> ?

Yep! You can use Box for this.

Are fade and slide no longer a valid properties on <Popover />? I feel these were really helpful.

They were removed because they relied on styles and the core library doesn't have styles anymore (only the necessary for accessibility).

There's an experimental unstable_animated option that you can pass to useHiddenState (and all its derivative modules, such as usePopoverState) in order to produce the same behavior. This is still not as simple as passing a fade/slide prop, but in the future we may have a separate package to handle those animations more easily within Reakit (see how reakit-system-palette handles colors, for instance).

Here's an example using unstable_animated with code comments: https://codesandbox.io/s/reakit-animated-mm5u8

Popover works extremely differently.

It should work similarly. Will wait for the specific ticket.

Thank you so much for your contribution :)

Thanks for the reply! I agree it makes sense to move those features off to a secondary package like reakit-system-palette, I just hope some portion of the Reakit ecosystem supports them.

Because popovers enter and leave the screen, I feel those options are helpful to providing a system that "just works," even if the implementations are suboptimal or hosted outside of reakit core, or whatever else. I think the Dialog element could benefit from the same, though I don't personally use it.

If you had to guess, what's the future of reakit-system-palette look like? I'm okay with unstable as long as it's likely to continue to be developed and not disappear. And where exactly does it fit in with emotion-theming?

Thanks again!

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.