Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(accordion): 🏷️ update type declaration for prop generation #163

Merged
merged 1 commit into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/Accordion.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ form elements. In this case, only `aria-disabled` will be set.
- **`groups`** <code>Group[]</code> Lists all the composite groups with their
`id` and DOM `ref`. This state is automatically updated when `registerGroup`
and `unregisterGroup` are called.
- **`move`** <code>(id: string | null) =&#62; void</code> Moves focus to a given
item ID.
- **`items`** <code>Item[]</code> Lists all the composite items with their `id`,
DOM `ref`, `disabled` state and `groupId` if any. This state is automatically
updated when `registerItem` and `unregisterItem` are called.
- **`move`** <code>(id: string | null) =&#62; void</code> Moves focus to a given
item ID.
- **`setCurrentId`**
<code title="(value: SetStateAction&#60;string | null | undefined&#62;) =&#62; void">(value:
SetStateAction&#60;string | null | undefine...</code> Sets `currentId`. This
Expand All @@ -152,6 +152,7 @@ form elements. In this case, only `aria-disabled` will be set.

### `AccordionPanel`

- **`accordionId`** <code>string | undefined</code> Accordion's id
- **`visible`** <code>boolean</code> Whether it's visible or not.
- **`animating`** <code>boolean</code> Whether it's animating or not.
- **`animated`** <code>number | boolean</code> If `true`, `animating` will be
Expand All @@ -162,7 +163,6 @@ form elements. In this case, only `aria-disabled` will be set.
- **`stopAnimation`** <code>() =&#62; void</code> Stops animation. It's called
automatically if there's a CSS transition.
- **`id`** <code>string | undefined</code> Same as the HTML attribute.
- **`accordionId`** <code>string | undefined</code> Accordion's id
<details><summary>8 state props</summary>
> These props are returned by the state hook. You can spread them into this component (`{...state}`) or pass them separately. You can also provide these props from your own state logic.

Expand Down Expand Up @@ -224,13 +224,13 @@ form elements. In this case, only `aria-disabled` will be set.
navigate out of it using arrow keys.
- If `currentId` is initially set to `null`, the base composite element itself
will have focus and users will be able to navigate to it using arrow keys.
- **`items`** <code>Item[]</code> Lists all the composite items with their `id`,
DOM `ref`, `disabled` state and `groupId` if any. This state is automatically
updated when `registerItem` and `unregisterItem` are called.
- **`registerItem`** <code>(item: Item) =&#62; void</code> Registers a composite
item.
- **`unregisterItem`** <code>(id: string) =&#62; void</code> Unregisters a
composite item.
- **`items`** <code>Item[]</code> Lists all the composite items with their `id`,
DOM `ref`, `disabled` state and `groupId` if any. This state is automatically
updated when `registerItem` and `unregisterItem` are called.
- **`setCurrentId`**
<code title="(value: SetStateAction&#60;string | null | undefined&#62;) =&#62; void">(value:
SetStateAction&#60;string | null | undefine...</code> Sets `currentId`. This
Expand Down
116 changes: 1 addition & 115 deletions docs/Calendar.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,119 +199,5 @@ Accessible `Calendar` component.
### Example

```js
import React from "react";

import {
useCalendarState,
Calendar as CalendarWrapper,
CalendarButton,
CalendarCell,
CalendarCellButton,
CalendarGrid,
CalendarHeader,
CalendarWeekTitle,
} from "renderless-components";

export const App = props => {
const state = useCalendarState(props);

return (
<CalendarWrapper {...state} className="calendar">
<div className="header">
<CalendarButton {...state} goto="previousYear" className="prev-year">
<DoubleChevronLeft />
</CalendarButton>
<CalendarButton {...state} goto="previousMonth" className="prev-month">
<ChevronLeft />
</CalendarButton>
<CalendarHeader {...state} />
<CalendarButton {...state} goto="nextMonth" className="next-month">
<ChevronRight />
</CalendarButton>
<CalendarButton {...state} goto="nextYear" className="next-year">
<DoubleChevronRight />
</CalendarButton>
</div>

<CalendarGrid {...state} as="table" className="dates">
<thead>
<tr>
{state.weekDays.map((day, dayIndex) => {
return (
<CalendarWeekTitle
{...state}
as="th"
scope="col"
key={dayIndex}
dayIndex={dayIndex}
>
<abbr title={day.title}>{day.abbr}</abbr>
</CalendarWeekTitle>
);
})}
</tr>
</thead>
<tbody>
{state.daysInMonth.map((week, weekIndex) => (
<tr key={weekIndex}>
{week.map((day, dayIndex) => (
<CalendarCell {...state} as="td" key={dayIndex} date={day}>
<CalendarCellButton {...state} date={day} />
</CalendarCell>
))}
</tr>
))}
</tbody>
</CalendarGrid>
</CalendarWrapper>
);
};

export default App;

const DoubleChevronLeft = props => {
return (
<svg
{...props}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15 19l-7-7 7-7"
/>
</svg>
);
};

const ChevronLeft = props => {
return (
<svg
{...props}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
);
};

const ChevronRight = props => (
<ChevronLeft style={{ transform: "rotate(180deg)" }} {...props} />
);

const DoubleChevronRight = props => (
<DoubleChevronLeft style={{ transform: "rotate(180deg)" }} {...props} />
);

```
12 changes: 6 additions & 6 deletions src/accordion/Accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ import { CompositeOptions, CompositeHTMLProps, useComposite } from "reakit";

import { ACCORDION_KEYS } from "./__keys";

export type AccordionOptions = CompositeOptions;

export type AccordionHTMLProps = CompositeHTMLProps;

export type AccordionProps = AccordionOptions & AccordionHTMLProps;

export const useAccordion = createHook<AccordionOptions, AccordionHTMLProps>({
name: "Accordion",
compose: useComposite,
Expand All @@ -33,3 +27,9 @@ export const Accordion = createComponent({
memo: true,
useHook: useAccordion,
});

export type AccordionOptions = CompositeOptions;

export type AccordionHTMLProps = CompositeHTMLProps;

export type AccordionProps = AccordionOptions & AccordionHTMLProps;
105 changes: 25 additions & 80 deletions src/accordion/AccordionPanel.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,18 @@
import {
DisclosureContentOptions,
DisclosureContentHTMLProps,
useDisclosureContent,
unstable_useId,
unstable_IdOptions,
unstable_IdHTMLProps,
useDisclosureContent,
DisclosureContentOptions,
DisclosureContentHTMLProps,
} from "reakit";
import * as React from "react";
import { useForkRef } from "reakit-utils";
import { createHook, createComponent } from "reakit-system";

import { ACCORDION_PANEL_KEYS } from "./__keys";
import { AccordionStateReturn } from "./AccordionState";

export type AccordionPanelOptions = DisclosureContentOptions &
unstable_IdOptions &
Pick<
AccordionStateReturn,
| "registerPanel"
| "unregisterPanel"
| "panels"
| "items"
| "allowMultiple"
| "selectedId"
| "selectedIds"
> & {
/**
* Accordion's id
*/
accordionId?: string;
};

export type AccordionPanelHTMLProps = DisclosureContentHTMLProps &
unstable_IdHTMLProps;

export type AccordionPanelProps = AccordionPanelOptions &
AccordionPanelHTMLProps;
import { getAccordionId, isPanelVisible } from "./helpers";

export const useAccordionPanel = createHook<
AccordionPanelOptions,
Expand Down Expand Up @@ -80,58 +57,26 @@ export const AccordionPanel = createComponent({
useHook: useAccordionPanel,
});

/**
* When <AccordionPanel> is used without accordionId:
*
* - First render: getAccordionId will return undefined because options.panels
* doesn't contain the current panel yet (registerPanel wasn't called yet).
* Thus registerPanel will be called without groupId (accordionId).
*
* - Second render: options.panels already contains the current panel (because
* registerPanel was called in the previous render). This means that we'll be
* able to get the related accordionId with the accordion panel index. Basically,
* we filter out all the accordions and panels that have already matched. In this
* phase, registerPanel will be called again with the proper groupId (accordionId).
*
* - In the third render, panel.groupId will be already defined, so we just
* return it. registerPanel is not called.
*/
function getAccordionId(options: AccordionPanelOptions) {
const { panels, id, items } = options;
const panel = panels?.find(p => p.id === id);
const accordionId = options.accordionId || panel?.groupId;
if (accordionId || !panel || !panels || !items) {
return accordionId;
}

const panelIndex = getPanelIndex(panels, panel);
const accordionsWithoutPanel = getAccordionsWithoutPanel(items, panels);
return accordionsWithoutPanel[panelIndex]?.id || undefined;
}

function getPanelIndex(
panels: AccordionPanelOptions["panels"],
panel: typeof panels[number],
) {
const panelsWithoutAccordionId = panels.filter(p => !p.groupId);
return panelsWithoutAccordionId.indexOf(panel);
}

function getAccordionsWithoutPanel(
accordions: AccordionPanelOptions["items"],
panels: AccordionPanelOptions["panels"],
) {
const panelsAccordionIds = panels.map(panel => panel.groupId).filter(Boolean);

return accordions.filter(
item => panelsAccordionIds.indexOf(item.id || undefined) === -1,
);
}
export type AccordionPanelOptions = {
/**
* Accordion's id
*/
accordionId?: string;
} & DisclosureContentOptions &
unstable_IdOptions &
Pick<
AccordionStateReturn,
| "registerPanel"
| "unregisterPanel"
| "panels"
| "items"
| "allowMultiple"
| "selectedId"
| "selectedIds"
>;

function isPanelVisible(options: AccordionPanelOptions) {
const { allowMultiple, selectedId, selectedIds } = options;
const accordionId = getAccordionId(options);
export type AccordionPanelHTMLProps = DisclosureContentHTMLProps &
unstable_IdHTMLProps;

if (!allowMultiple) return accordionId ? selectedId === accordionId : false;
return accordionId ? selectedIds?.includes(accordionId) : false;
}
export type AccordionPanelProps = AccordionPanelOptions &
AccordionPanelHTMLProps;
37 changes: 19 additions & 18 deletions src/accordion/AccordionState.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,19 @@
import * as React from "react";
import { useControllableState } from "@chakra-ui/hooks";
import { CompositeInitialState, useCompositeState } from "reakit";

import {
AccordionState,
SelectedIdPair,
AccordionState,
AccordionActions,
AccordionReturns,
MultiOverloadReturn,
SingleOverloadReturn,
AccordionPropsUnion,
MultiOverloadReturn,
MultiAccordionProps,
SingleOverloadReturn,
SingleAccordionProps,
} from "./types";

export type AccordionInitialState = Partial<
AccordionPropsUnion & CompositeInitialState
>;
export type AccordionInitialStateSingle = Partial<
SingleAccordionProps & CompositeInitialState
>;
export type AccordionInitialStateMulti = Partial<
MultiAccordionProps & CompositeInitialState
>;

export type AccordionStateReturn = AccordionActions &
AccordionState &
AccordionReturns &
SelectedIdPair;

export function useAccordionState(
props: AccordionInitialStateSingle,
): SingleOverloadReturn;
Expand Down Expand Up @@ -156,3 +142,18 @@ export function useAccordionState(
...common,
};
}

export type AccordionInitialState = Partial<
AccordionPropsUnion & CompositeInitialState
>;
export type AccordionInitialStateSingle = Partial<
SingleAccordionProps & CompositeInitialState
>;
export type AccordionInitialStateMulti = Partial<
MultiAccordionProps & CompositeInitialState
>;

export type AccordionStateReturn = AccordionState &
AccordionActions &
AccordionReturns &
SelectedIdPair;
Loading