Skip to content

Commit

Permalink
feat: Select the first Tab by default and don't require stopId pr…
Browse files Browse the repository at this point in the history
…op (#597)

BREAKING CHANGE: The first `Tab` is now selected by default. There's no need to pass `selectedId` to `useTabState` anymore.

  If you're already using `selectedId` to select a tab in the initial render, you don't need to change anything as this still works. But, if you want to render tabs with none selected, you should now pass `null` to `selectedId`:

  ```js
  // if you're already using selectedId, there's no need to change anything
  const tab = useTabState({ selectedId: "tab-1" });
  ```

  ```diff
  // when there's no tab selected by default, you now need to explicitly specify it
  - const tab = useTabState();
  + const tab = useTabState({ selectedId: null });
  ```

BREAKING CHANGE: **Most users will not be affected by this**, but `stops`, `register` and `unregister` on the returned object of state hooks have been renamed to `items`, `registerItem` and `unregisterItem`, respectively.

  ```diff
  const tab = useTabState();
  - tab.stops.map(...);
  + tab.items.map(...);
  - tab.register(...);
  + tab.registerItem(...);
  - tab.unregister(...);
  + tab.unregisterItem(...);
  ```
  • Loading branch information
diegohaz authored Mar 13, 2020
1 parent 6a9fca9 commit 528b016
Show file tree
Hide file tree
Showing 23 changed files with 977 additions and 488 deletions.
2 changes: 1 addition & 1 deletion docs/COMPOSITION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ redirect_from:

# Composition

Reakit has been built with composition in mind. In fact, its own components are composed by a few other abstract ones, like [Box](/docs/box/), [Tabbable](/docs/tabbable/) and [Rover](/docs/rover/).
Reakit has been built with composition in mind. In fact, its own components are composed by a few other abstract ones, like [Box](/docs/box/), [Tabbable](/docs/tabbable/) and [Composite](/docs/composite/).

The API isn't different. It's designed so you can create new things based on any existing module.

Expand Down
14 changes: 7 additions & 7 deletions packages/reakit-system/src/createHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ export function createHook<O, P>(options: CreateHookOptions<O, P>) {
if (options.name) {
hookOptions = useOptions(options.name, hookOptions, htmlProps);
}
// Run composed hooks useOptions
if (options.compose) {
composedHooks.forEach(hook => {
hookOptions = hook.__useOptions(hookOptions, htmlProps);
});
}

return hookOptions;
};

Expand All @@ -70,13 +77,6 @@ export function createHook<O, P>(options: CreateHookOptions<O, P>) {
if (!unstable_ignoreUseOptions) {
hookOptions = __useOptions(hookOptions, htmlProps);
}
// We're already calling composed useOptions here
// That's why we ignoreUseOptions for composed hooks
if (options.compose) {
composedHooks.forEach(hook => {
hookOptions = hook.__useOptions(hookOptions, htmlProps);
});
}
// Call the current hook's useProps
if (options.useProps) {
htmlProps = options.useProps(hookOptions, htmlProps);
Expand Down
2 changes: 1 addition & 1 deletion packages/reakit/src/Button/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Learn more in [Accessibility](/docs/accessibility/).

## Composition

- `Button` uses [Tabbable](/docs/tabbable/), and is used by [FormPushButton](/docs/form/), [FormRemoveButton](/docs/form/), [Disclosure](/docs/disclosure/) and all their derivatives.
- `Button` uses [Clickable](/docs/clickable/), and is used by [FormPushButton](/docs/form/), [FormRemoveButton](/docs/form/), [Disclosure](/docs/disclosure/) and all their derivatives.

Learn more in [Composition](/docs/composition/#props-hooks).

Expand Down
2 changes: 1 addition & 1 deletion packages/reakit/src/Checkbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Learn more in [Accessibility](/docs/accessibility/).

## Composition

- `Checkbox` uses [Tabbable](/docs/tabbable/), and is used by [FormCheckbox](/docs/form/) and [MenuItemCheckbox](/docs/menu/).
- `Checkbox` uses [Clickable](/docs/clickable/), and is used by [FormCheckbox](/docs/form/) and [MenuItemCheckbox](/docs/menu/).

Learn more in [Composition](/docs/composition/#props-hooks).

Expand Down
2 changes: 1 addition & 1 deletion packages/reakit/src/Clickable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function Example() {
## Accessibility

- Pressing <kbd>Enter</kbd> or <kbd>Space</kbd> triggers a click event on `Clickable` regardless of its rendered element.
- `Clickable` extends the accessibility features of [Tabbable](/docs/tabbable/).
- `Clickable` extends the accessibility features of [Tabbable](/docs/tabbable/#accessibility).

Learn more in [Accessibility](/docs/accessibility/).

Expand Down
24 changes: 16 additions & 8 deletions packages/reakit/src/Composite/CompositeState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,36 +140,44 @@ export type unstable_CompositeActions = unstable_IdActions & {
/**
* Sets `rtl`.
*/
setRTL: React.Dispatch<unstable_CompositeState["rtl"]>;
setRTL: React.Dispatch<React.SetStateAction<unstable_CompositeState["rtl"]>>;
/**
* Sets `orientation`.
*/
setOrientation: React.Dispatch<unstable_CompositeState["orientation"]>;
setOrientation: React.Dispatch<
React.SetStateAction<unstable_CompositeState["orientation"]>
>;
/**
* Sets `currentId`.
*/
setCurrentId: React.Dispatch<unstable_CompositeState["currentId"]>;
setCurrentId: React.Dispatch<
React.SetStateAction<unstable_CompositeState["currentId"]>
>;
/**
* Sets `loop`.
*/
setLoop: React.Dispatch<unstable_CompositeState["loop"]>;
setLoop: React.Dispatch<
React.SetStateAction<unstable_CompositeState["loop"]>
>;
/**
* Sets `focusWrap`.
*/
setFocusWrap: React.Dispatch<unstable_CompositeState["focusWrap"]>;
setFocusWrap: React.Dispatch<
React.SetStateAction<unstable_CompositeState["focusWrap"]>
>;
/**
* Sets `focusStrategy`.
* @private
*/
unstable_setFocusStrategy: React.Dispatch<
unstable_CompositeState["unstable_focusStrategy"]
React.SetStateAction<unstable_CompositeState["unstable_focusStrategy"]>
>;
/**
* Sets `hasFocusInsideItem`.
* @private
*/
unstable_setHasActiveWidget: React.Dispatch<
unstable_CompositeState["unstable_hasActiveWidget"]
React.SetStateAction<unstable_CompositeState["unstable_hasActiveWidget"]>
>;
};

Expand Down Expand Up @@ -298,7 +306,7 @@ function reducer(
// Finds the item group based on the DOM hierarchy
const group = groups.find(r => r.ref.current?.contains(item.ref.current));
// Group will be null if it's a one-dimensional composite
const nextItem = { ...item, groupId: group?.id };
const nextItem = { groupId: group?.id, ...item };
let nextItems = [...items, nextItem];

if (items.length) {
Expand Down
4 changes: 2 additions & 2 deletions packages/reakit/src/Composite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Learn more in [Accessibility](/docs/accessibility/).

- `Composite` uses [Tabbable](/docs/tabbable/) (when `focusStrategy` is set to `aria-activedescendant`) and [IdGroup](/docs/id/).
- `CompositeGroup` uses [Group](/docs/group/) and [Id](/docs/id/).
- `CompositeItem` uses [Id](/docs/id/) and [Tabbable](/docs/tabbable/).
- `CompositeItem` uses [Id](/docs/id/) and [Clickable](/docs/clickable/).
- `CompositeItemWidget` uses [Box](/docs/box/).

Learn more in [Composition](/docs/composition/#props-hooks).
Expand Down Expand Up @@ -420,7 +420,7 @@ is `true`, the navigation will wrap based on the value of `orientation`:
Moves focus to the last item.

- **`setCurrentId`**
<code>(value: string | null) =&#62; void</code>
<code>(value: SetStateAction&#60;string | null&#62;) =&#62; void</code>

Sets `currentId`.

Expand Down
2 changes: 1 addition & 1 deletion packages/reakit/src/Dialog/DialogBackdrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const useDialogBackdrop = createHook<
useState: useDialogState,

useOptions({ modal = true, ...options }) {
return { modal, ...options };
return { modal, ...options, unstable_setBaseId: undefined };
},

useProps(options, { wrapElement: htmlWrapElement, ...htmlProps }) {
Expand Down
50 changes: 28 additions & 22 deletions packages/reakit/src/Dialog/__tests__/DialogBackdrop-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { render } from "reakit-test-utils";
import { DialogBackdrop } from "../DialogBackdrop";

test("render", () => {
const { baseElement } = render(<DialogBackdrop />);
const { baseElement } = render(<DialogBackdrop baseId="dialog" />);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div />
Expand All @@ -12,6 +12,7 @@ test("render", () => {
>
<div
class="hidden"
data-dialog-ref="dialog"
hidden=""
style="display: none;"
/>
Expand All @@ -21,30 +22,35 @@ test("render", () => {
});

test("render visible", () => {
const { baseElement } = render(<DialogBackdrop visible />);
const { baseElement } = render(<DialogBackdrop baseId="dialog" visible />);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div />
<div
class="__reakit-portal"
>
<div />
</div>
</body>
`);
<body>
<div />
<div
class="__reakit-portal"
>
<div
data-dialog-ref="dialog"
/>
</div>
</body>
`);
});

test("render no modal", () => {
const { baseElement } = render(<DialogBackdrop modal={false} />);
const { baseElement } = render(
<DialogBackdrop baseId="dialog" modal={false} />
);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
class="hidden"
hidden=""
style="display: none;"
/>
</div>
</body>
`);
<body>
<div>
<div
class="hidden"
data-dialog-ref="dialog"
hidden=""
style="display: none;"
/>
</div>
</body>
`);
});
19 changes: 11 additions & 8 deletions packages/reakit/src/Popover/__tests__/PopoverBackdrop-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { render } from "reakit-test-utils";
import { PopoverBackdrop } from "../PopoverBackdrop";

test("render", () => {
const { baseElement } = render(<PopoverBackdrop />);
const { baseElement } = render(<PopoverBackdrop baseId="popover" />);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div
class="hidden"
data-dialog-ref="popover"
hidden=""
style="display: none;"
/>
Expand All @@ -18,12 +19,14 @@ test("render", () => {
});

test("render visible", () => {
const { baseElement } = render(<PopoverBackdrop visible />);
const { baseElement } = render(<PopoverBackdrop baseId="popover" visible />);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
<div />
</div>
</body>
`);
<body>
<div>
<div
data-dialog-ref="popover"
/>
</div>
</body>
`);
});
2 changes: 1 addition & 1 deletion packages/reakit/src/Rover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Learn more in [Accessibility](/docs/accessibility/).

## Composition

- `Rover` uses [Tabbable](/docs/tabbable/), and is used by [MenuItem](/docs/menu/), [Radio](/docs/radio/), [Tab](/docs/tab/) and [ToolbarItem](/docs/toolbar/).
- `Rover` uses [Clickable](/docs/clickable/).

Learn more in [Composition](/docs/composition/#props-hooks).

Expand Down
Loading

0 comments on commit 528b016

Please sign in to comment.