Skip to content
Draft
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
27 changes: 27 additions & 0 deletions @navikt/core/react/src/accordion/Accordion.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposal for change:

  • Use ref on accordion wrapper
  • Call it in effect to make sure everything is settled before warning
  • Use data-attributes on accordion/item, since className currently change based on context
    const accordionRef = useRef<HTMLDivElement | null>(null);
    const mergedRefs = useMergeRefs(accordionRef, ref);

    useEffect(() => {
      const children = accordionRef.current?.querySelectorAll(
        "[data-accordion-item]",
      );

      if (children && children?.length < 2) {
        console.warn(...);
      }

      if (
        accordionRef.current?.nextElementSibling?.hasAttribute("data-accordion")
      ) {
        console.warn(...);
      }
    }, []);

Could also add this nifty utility for warning in dev-enviroments while de-duping the messages:

let set: Set<string>;
if (process.env.NODE_ENV !== 'production') {
  set = new Set<string>();
}

export function warn(...messages: string[]) {
  if (process.env.NODE_ENV !== 'production') {
    const messageKey = messages.join(' ');
    if (!set.has(messageKey)) {
      set.add(messageKey);
      console.warn(`Aksel UI: ${messageKey}`);
    }
  }
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ import { AccordionContext } from "./AccordionContext";
import AccordionHeader, { AccordionHeaderProps } from "./AccordionHeader";
import AccordionItem, { AccordionItemProps } from "./AccordionItem";

let hasWarnedAboutItems = false;

function checkAccordionItems() {
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useEffect(() => {
document.querySelectorAll(".aksel-accordion").forEach((accordion) => {
if (hasWarnedAboutItems || accordion.children.length !== 1) {
return;
}
if (accordion.nextElementSibling?.classList.contains("aksel-accordion")) {
console.warn(
"[Aksel] Do not put multiple accordions directly after each other. Use one <Accordion> with multiple <Accordion.Item> instead.",
);
} else {
console.warn(
"[Aksel] Accordions should have more than one item. Consider using ExpansionPanel instead.",
);
}
hasWarnedAboutItems = true;
});
}, []);
}

interface AccordionComponent
extends React.ForwardRefExoticComponent<
AccordionProps & React.RefAttributes<HTMLDivElement>
Expand Down Expand Up @@ -89,6 +112,10 @@ export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
) => {
const { cn } = useRenameCSS();

if (process.env.NODE_ENV !== "production") {
checkAccordionItems();
}

return (
<AccordionContext.Provider
value={{
Expand Down
Loading