Skip to content

Commit

Permalink
refactor(accordion): ♻️ move functions to the bottom of the components
Browse files Browse the repository at this point in the history
  • Loading branch information
navin-moorthy committed Oct 14, 2020
1 parent 341b5c7 commit d525a8f
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 57 deletions.
18 changes: 9 additions & 9 deletions src/accordion/AccordionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@ export type AccordionItemHTMLProps = ButtonHTMLProps & CompositeItemHTMLProps;

export type AccordionItemProps = AccordionItemOptions & AccordionItemHTMLProps;

function useAccordionPanelId(options: AccordionItemOptions) {
const { panels, id } = options;

return React.useMemo(
() => panels?.find(panel => panel.groupId === id)?.id || undefined,
[panels, id],
);
}

export const useAccordionItem = createHook<
AccordionItemOptions,
AccordionItemHTMLProps
Expand Down Expand Up @@ -146,3 +137,12 @@ function isAccordionSelected(options: AccordionItemOptions) {
if (!allowMultiple) return selectedId === id;
return selectedIds?.includes(id);
}

function useAccordionPanelId(options: AccordionItemOptions) {
const { panels, id } = options;

return React.useMemo(
() => panels?.find(panel => panel.groupId === id)?.id || undefined,
[panels, id],
);
}
96 changes: 48 additions & 48 deletions src/accordion/AccordionPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,54 +37,6 @@ export type AccordionPanelHTMLProps = DisclosureContentHTMLProps &
export type AccordionPanelProps = AccordionPanelOptions &
AccordionPanelHTMLProps;

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,
);
}

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

/**
* 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;
}

export const useAccordionPanel = createHook<
AccordionPanelOptions,
AccordionPanelHTMLProps
Expand Down Expand Up @@ -128,6 +80,54 @@ 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,
);
}

function isPanelVisible(options: AccordionPanelOptions) {
const { allowMultiple, selectedId, selectedIds } = options;
const accordionId = getAccordionId(options);
Expand Down

0 comments on commit d525a8f

Please sign in to comment.