From cdd7bcb7a5f9dc05e56300143e2b5103d15bdcc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadeusz=20Miesi=C4=85c?= <tadeusz.miesiac@gmail.com>
Date: Thu, 5 Oct 2023 17:15:13 +0800
Subject: [PATCH] feat(accordion component): added accordion component and
 example

---
 package-lock.json                             | 10 ++++++
 package.json                                  |  5 +--
 pages/accordion-test.tsx                      | 32 +++++++++++++++++++
 pages/index.tsx                               |  1 -
 pages/redux-api-poc.tsx                       | 26 ---------------
 src/shared/Accordion/Accordion.component.tsx  | 31 ++++++++++++++++++
 .../AccordionItem/AccordionItem.component.tsx | 25 +++++++++++++++
 src/shared/Accordion/AccordionItem/index.ts   |  1 +
 .../AccordionItemButton.component.tsx         | 14 ++++++++
 .../AccordionItemButton.style.css             |  3 ++
 .../Accordion/AccordionItemButton/index.ts    |  1 +
 .../AccordionItemHeading.component.tsx        |  9 ++++++
 .../Accordion/AccordionItemHeading/index.ts   |  1 +
 .../AccordionItemPanel.component.tsx          |  9 ++++++
 .../Accordion/AccordionItemPanel/index.ts     |  1 +
 src/shared/Accordion/index.ts                 |  5 +++
 16 files changed, 145 insertions(+), 29 deletions(-)
 create mode 100644 pages/accordion-test.tsx
 delete mode 100644 pages/redux-api-poc.tsx
 create mode 100644 src/shared/Accordion/Accordion.component.tsx
 create mode 100644 src/shared/Accordion/AccordionItem/AccordionItem.component.tsx
 create mode 100644 src/shared/Accordion/AccordionItem/index.ts
 create mode 100644 src/shared/Accordion/AccordionItemButton/AccordionItemButton.component.tsx
 create mode 100644 src/shared/Accordion/AccordionItemButton/AccordionItemButton.style.css
 create mode 100644 src/shared/Accordion/AccordionItemButton/index.ts
 create mode 100644 src/shared/Accordion/AccordionItemHeading/AccordionItemHeading.component.tsx
 create mode 100644 src/shared/Accordion/AccordionItemHeading/index.ts
 create mode 100644 src/shared/Accordion/AccordionItemPanel/AccordionItemPanel.component.tsx
 create mode 100644 src/shared/Accordion/AccordionItemPanel/index.ts
 create mode 100644 src/shared/Accordion/index.ts

diff --git a/package-lock.json b/package-lock.json
index 80bd76c5..790d099b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,6 +21,7 @@
         "next": "13.4.19",
         "postcss": "8.4.29",
         "react": "18.2.0",
+        "react-accessible-accordion": "^5.0.0",
         "react-dom": "18.2.0",
         "react-redux": "^8.1.2",
         "tailwind-merge": "^1.14.0",
@@ -10308,6 +10309,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-accessible-accordion": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/react-accessible-accordion/-/react-accessible-accordion-5.0.0.tgz",
+      "integrity": "sha512-MT2obYpTgLIIfPr9d7hEyvPB5rg8uJcHpgA83JSRlEUHvzH48+8HJPvzSs+nM+XprTugDgLfhozO5qyJpBvYRQ==",
+      "peerDependencies": {
+        "react": "^16.3.2 || ^17.0.0 || ^18.0.0",
+        "react-dom": "^16.3.3 || ^17.0.0 || ^18.0.0"
+      }
+    },
     "node_modules/react-dom": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
diff --git a/package.json b/package.json
index ba33ffe0..c4ee3467 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
     "next": "13.4.19",
     "postcss": "8.4.29",
     "react": "18.2.0",
+    "react-accessible-accordion": "^5.0.0",
     "react-dom": "18.2.0",
     "react-redux": "^8.1.2",
     "tailwind-merge": "^1.14.0",
@@ -79,9 +80,9 @@
     "lint-staged": "^14.0.1",
     "prettier": "^3.0.3",
     "prettier-2": "npm:prettier@^2",
+    "prettier-plugin-tailwindcss": "^0.5.4",
     "typescript": "^5.2.2",
-    "zod-fixture": "^2.5.0",
-    "prettier-plugin-tailwindcss": "^0.5.4"
+    "zod-fixture": "^2.5.0"
   },
   "config": {
     "commitizen": {
diff --git a/pages/accordion-test.tsx b/pages/accordion-test.tsx
new file mode 100644
index 00000000..2050582d
--- /dev/null
+++ b/pages/accordion-test.tsx
@@ -0,0 +1,32 @@
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemHeading,
+  AccordionItemButton,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+
+const AccordionPage = (): JSX.Element => (
+  <div>
+    <div className="w-52 bg-primary-100  p-10">
+      <div className="bg-white">
+        <Accordion allowZeroExpanded>
+          <AccordionItem>
+            <AccordionItemHeading>
+              <AccordionItemButton>What harsh truths do you prefer to ignore?</AccordionItemButton>
+            </AccordionItemHeading>
+            <AccordionItemPanel>
+              <p>
+                Exercitation in fugiat est ut ad ea cupidatat ut in cupidatat occaecat ut occaecat
+                consequat est minim minim esse tempor laborum consequat esse adipisicing eu
+                reprehenderit enim.
+              </p>
+            </AccordionItemPanel>
+          </AccordionItem>
+        </Accordion>
+      </div>
+    </div>
+  </div>
+);
+
+export default AccordionPage;
diff --git a/pages/index.tsx b/pages/index.tsx
index 929f1328..0c103a3f 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,4 +1,3 @@
 import { MinervaSPA } from '@/components/SPA';
-import '@/styles/index.css';
 
 export default MinervaSPA;
diff --git a/pages/redux-api-poc.tsx b/pages/redux-api-poc.tsx
deleted file mode 100644
index 2811cf8a..00000000
--- a/pages/redux-api-poc.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { useSelector } from 'react-redux';
-import { selectSearchValue } from '@/redux/search/search.selectors';
-import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
-import { getDrugs } from '@/redux/drugs/drugs.thunks';
-import { getMirnas } from '@/redux/mirnas/mirnas.thunks';
-
-const ReduxPage = (): JSX.Element => {
-  const dispatch = useAppDispatch();
-  const searchValue = useSelector(selectSearchValue);
-
-  const triggerSyncUpdate = (): void => {
-    dispatch(getDrugs('aspirin'));
-    dispatch(getMirnas('hsa-miR-302b-3p'));
-  };
-
-  return (
-    <div>
-      {searchValue}
-      <button type="button" onClick={triggerSyncUpdate}>
-        sync update
-      </button>
-    </div>
-  );
-};
-
-export default ReduxPage;
diff --git a/src/shared/Accordion/Accordion.component.tsx b/src/shared/Accordion/Accordion.component.tsx
new file mode 100644
index 00000000..f0de2a3e
--- /dev/null
+++ b/src/shared/Accordion/Accordion.component.tsx
@@ -0,0 +1,31 @@
+import { Accordion as Ac } from 'react-accessible-accordion';
+import { DivAttributes } from 'react-accessible-accordion/dist/types/helpers/types';
+
+type ID = string | number;
+
+type AccordionProps = Pick<DivAttributes, Exclude<keyof DivAttributes, 'onChange'>> & {
+  children: React.ReactNode;
+  preExpanded?: ID[];
+  allowMultipleExpanded?: boolean;
+  allowZeroExpanded?: boolean;
+  onChange?(args: ID[]): void;
+};
+
+export const Accordion = ({
+  children,
+  preExpanded,
+  allowMultipleExpanded,
+  allowZeroExpanded,
+  onChange,
+  ...rest
+}: AccordionProps): JSX.Element => (
+  <Ac
+    preExpanded={preExpanded}
+    allowMultipleExpanded={allowMultipleExpanded}
+    allowZeroExpanded={allowZeroExpanded}
+    onChange={onChange}
+    {...rest}
+  >
+    {children}
+  </Ac>
+);
diff --git a/src/shared/Accordion/AccordionItem/AccordionItem.component.tsx b/src/shared/Accordion/AccordionItem/AccordionItem.component.tsx
new file mode 100644
index 00000000..a5ca5060
--- /dev/null
+++ b/src/shared/Accordion/AccordionItem/AccordionItem.component.tsx
@@ -0,0 +1,25 @@
+import { AccordionItem as AccItem } from 'react-accessible-accordion';
+
+interface AccordionItemProps extends React.HTMLAttributes<HTMLDivElement> {
+  uuid?: string | number;
+  activeClassName?: string;
+  dangerouslySetExpanded?: boolean;
+  children: React.ReactNode;
+}
+
+export const AccordionItem = ({
+  uuid: customUuid,
+  dangerouslySetExpanded,
+  children,
+  ...rest
+}: AccordionItemProps): JSX.Element => (
+  <AccItem
+    uuid={customUuid}
+    dangerouslySetExpanded={dangerouslySetExpanded}
+    {...rest}
+    className="border-b"
+    activeClassName=""
+  >
+    {children}
+  </AccItem>
+);
diff --git a/src/shared/Accordion/AccordionItem/index.ts b/src/shared/Accordion/AccordionItem/index.ts
new file mode 100644
index 00000000..4940ad37
--- /dev/null
+++ b/src/shared/Accordion/AccordionItem/index.ts
@@ -0,0 +1 @@
+export { AccordionItem } from './AccordionItem.component';
diff --git a/src/shared/Accordion/AccordionItemButton/AccordionItemButton.component.tsx b/src/shared/Accordion/AccordionItemButton/AccordionItemButton.component.tsx
new file mode 100644
index 00000000..32942ae9
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemButton/AccordionItemButton.component.tsx
@@ -0,0 +1,14 @@
+import { Icon } from '@/shared/Icon';
+import { AccordionItemButton as AIB } from 'react-accessible-accordion';
+import './AccordionItemButton.style.css';
+
+interface AccordionItemButtonProps {
+  children: React.ReactNode;
+}
+
+export const AccordionItemButton = ({ children }: AccordionItemButtonProps): JSX.Element => (
+  <AIB className="accordion-button flex flex-row flex-nowrap justify-between">
+    {children}
+    <Icon name="chevron-down" className="arrow-button h-6 w-6 fill-font-500" />
+  </AIB>
+);
diff --git a/src/shared/Accordion/AccordionItemButton/AccordionItemButton.style.css b/src/shared/Accordion/AccordionItemButton/AccordionItemButton.style.css
new file mode 100644
index 00000000..ee300f20
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemButton/AccordionItemButton.style.css
@@ -0,0 +1,3 @@
+.accordion-button[aria-expanded='true'] > .arrow-button {
+  @apply rotate-180;
+}
diff --git a/src/shared/Accordion/AccordionItemButton/index.ts b/src/shared/Accordion/AccordionItemButton/index.ts
new file mode 100644
index 00000000..24541a1a
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemButton/index.ts
@@ -0,0 +1 @@
+export { AccordionItemButton } from './AccordionItemButton.component';
diff --git a/src/shared/Accordion/AccordionItemHeading/AccordionItemHeading.component.tsx b/src/shared/Accordion/AccordionItemHeading/AccordionItemHeading.component.tsx
new file mode 100644
index 00000000..a2e1af34
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemHeading/AccordionItemHeading.component.tsx
@@ -0,0 +1,9 @@
+import { AccordionItemHeading as AIH } from 'react-accessible-accordion';
+
+interface AccordionItemHeadingProps {
+  children: React.ReactNode;
+}
+
+export const AccordionItemHeading = ({ children }: AccordionItemHeadingProps): JSX.Element => (
+  <AIH className="py-4">{children}</AIH>
+);
diff --git a/src/shared/Accordion/AccordionItemHeading/index.ts b/src/shared/Accordion/AccordionItemHeading/index.ts
new file mode 100644
index 00000000..9eb4999c
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemHeading/index.ts
@@ -0,0 +1 @@
+export { AccordionItemHeading } from './AccordionItemHeading.component';
diff --git a/src/shared/Accordion/AccordionItemPanel/AccordionItemPanel.component.tsx b/src/shared/Accordion/AccordionItemPanel/AccordionItemPanel.component.tsx
new file mode 100644
index 00000000..d0ef686d
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemPanel/AccordionItemPanel.component.tsx
@@ -0,0 +1,9 @@
+import { AccordionItemPanel as AIP } from 'react-accessible-accordion';
+
+interface AccordionItemPanelProps {
+  children: React.ReactNode;
+}
+
+export const AccordionItemPanel = ({ children }: AccordionItemPanelProps): JSX.Element => (
+  <AIP className="pb-4">{children}</AIP>
+);
diff --git a/src/shared/Accordion/AccordionItemPanel/index.ts b/src/shared/Accordion/AccordionItemPanel/index.ts
new file mode 100644
index 00000000..d45a4338
--- /dev/null
+++ b/src/shared/Accordion/AccordionItemPanel/index.ts
@@ -0,0 +1 @@
+export { AccordionItemPanel } from './AccordionItemPanel.component';
diff --git a/src/shared/Accordion/index.ts b/src/shared/Accordion/index.ts
new file mode 100644
index 00000000..244e2026
--- /dev/null
+++ b/src/shared/Accordion/index.ts
@@ -0,0 +1,5 @@
+export { AccordionItem } from '@/shared/Accordion/AccordionItem';
+export { AccordionItemButton } from '@/shared/Accordion/AccordionItemButton';
+export { AccordionItemHeading } from '@/shared/Accordion/AccordionItemHeading';
+export { Accordion } from './Accordion.component';
+export { AccordionItemPanel } from '@/shared/Accordion/AccordionItemPanel';
-- 
GitLab