From 91679b031debf0c566242765b366b17b794eaa63 Mon Sep 17 00:00:00 2001 From: dgd03146 Date: Fri, 10 May 2024 04:59:44 +0100 Subject: [PATCH] feat: Implement Accordion component with Storybook #16 --- apps/workshop/package.json | 1 + .../stories/Accordion/Accordion.stories.tsx | 83 ++++ apps/workshop/vite.config.mts | 3 +- .../assets/icons/ic-arrow-down-outlined.svg | 3 + .../assets/icons/ic-arrow-left-outlined.svg | 3 + .../icons/ic-arrow-right-more-outlined.svg | 3 + .../assets/icons/ic-arrow-right-outlined.svg | 3 + .../assets/icons/ic-arrow-up-outlined.svg | 3 + .../assets/icons/ic-close-outlined.svg | 3 + .../assets/icons/ic-delete-solid.svg | 5 + .../assets/icons/ic-happy-outlined.svg | 13 + .../assets/icons/ic-happy-solid.svg | 10 + .../assets/icons/ic-heart-solid-2.svg | 3 + .../assets/icons/ic-heart-solid.svg | 10 + .../assets/icons/ic-plus-outlined.svg | 3 + .../assets/icons/ic-pollygon-down.svg | 3 + .../assets/icons/ic-pollygon-up.svg | 3 + .../assets/icons/ic-sad-outlined.svg | 13 + .../assets/icons/ic-sad-solid.svg | 10 + .../assets/icons/ic-smile-outlined.svg | 13 + .../assets/icons/ic-smile-solid.svg | 10 + .../assets/icons/ic-social-apple.svg | 3 + .../assets/icons/ic-social-google.svg | 6 + .../assets/icons/ic-social-kakao.svg | 3 + .../assets/icons/ic-social-naver.svg | 3 + packages/design-system/assets/icons/index.ts | 22 + .../components/Accordion/Accordion.tsx | 24 ++ .../Accordion/AccordionContent.css.ts | 38 ++ .../components/Accordion/AccordionContent.tsx | 45 ++ .../components/Accordion/AccordionItem.css.ts | 14 + .../components/Accordion/AccordionItem.tsx | 30 ++ .../components/Accordion/AccordionPanel.tsx | 30 ++ .../Accordion/AccordionTrigger.css.ts | 19 + .../components/Accordion/AccordionTrigger.tsx | 39 ++ .../Accordion/context/AccordionContext.tsx | 29 ++ .../Accordion/hooks/useExpandableHeight.ts | 16 + .../components/Accordion/index.ts | 14 + packages/design-system/components/index.ts | 2 + packages/design-system/package.json | 1 + packages/design-system/svg.d.ts | 10 + packages/shared/hooks/index.ts | 2 + packages/shared/hooks/useBeforeMatch.ts | 19 + packages/shared/hooks/useToggle.ts | 11 + packages/shared/package.json | 27 +- pnpm-lock.yaml | 405 ++++++++++++++++++ 45 files changed, 1000 insertions(+), 13 deletions(-) create mode 100644 apps/workshop/src/stories/Accordion/Accordion.stories.tsx create mode 100644 packages/design-system/assets/icons/ic-arrow-down-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-arrow-left-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-arrow-right-more-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-arrow-right-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-arrow-up-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-close-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-delete-solid.svg create mode 100644 packages/design-system/assets/icons/ic-happy-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-happy-solid.svg create mode 100644 packages/design-system/assets/icons/ic-heart-solid-2.svg create mode 100644 packages/design-system/assets/icons/ic-heart-solid.svg create mode 100644 packages/design-system/assets/icons/ic-plus-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-pollygon-down.svg create mode 100644 packages/design-system/assets/icons/ic-pollygon-up.svg create mode 100644 packages/design-system/assets/icons/ic-sad-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-sad-solid.svg create mode 100644 packages/design-system/assets/icons/ic-smile-outlined.svg create mode 100644 packages/design-system/assets/icons/ic-smile-solid.svg create mode 100644 packages/design-system/assets/icons/ic-social-apple.svg create mode 100644 packages/design-system/assets/icons/ic-social-google.svg create mode 100644 packages/design-system/assets/icons/ic-social-kakao.svg create mode 100644 packages/design-system/assets/icons/ic-social-naver.svg create mode 100644 packages/design-system/assets/icons/index.ts create mode 100644 packages/design-system/components/Accordion/Accordion.tsx create mode 100644 packages/design-system/components/Accordion/AccordionContent.css.ts create mode 100644 packages/design-system/components/Accordion/AccordionContent.tsx create mode 100644 packages/design-system/components/Accordion/AccordionItem.css.ts create mode 100644 packages/design-system/components/Accordion/AccordionItem.tsx create mode 100644 packages/design-system/components/Accordion/AccordionPanel.tsx create mode 100644 packages/design-system/components/Accordion/AccordionTrigger.css.ts create mode 100644 packages/design-system/components/Accordion/AccordionTrigger.tsx create mode 100644 packages/design-system/components/Accordion/context/AccordionContext.tsx create mode 100644 packages/design-system/components/Accordion/hooks/useExpandableHeight.ts create mode 100644 packages/design-system/components/Accordion/index.ts create mode 100644 packages/design-system/svg.d.ts create mode 100644 packages/shared/hooks/index.ts create mode 100644 packages/shared/hooks/useBeforeMatch.ts create mode 100644 packages/shared/hooks/useToggle.ts diff --git a/apps/workshop/package.json b/apps/workshop/package.json index 0717a7c..3746b60 100644 --- a/apps/workshop/package.json +++ b/apps/workshop/package.json @@ -23,6 +23,7 @@ "@vitest/coverage-v8": "^1.3.1", "@vitest/ui": "^1.3.1", "vitest": "^1.3.1", + "@svgr/rollup": "^8.1.0", "@vanilla-extract/vite-plugin": "latest", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-interactions": "^7.6.17", diff --git a/apps/workshop/src/stories/Accordion/Accordion.stories.tsx b/apps/workshop/src/stories/Accordion/Accordion.stories.tsx new file mode 100644 index 0000000..d8455a4 --- /dev/null +++ b/apps/workshop/src/stories/Accordion/Accordion.stories.tsx @@ -0,0 +1,83 @@ +import { Accordion } from '@jung/design-system'; +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + title: 'Components/Accordion', + component: Accordion, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args) => ( + + + Answered 2024.02.23 | Delete}> + What is the Virtual DOM and how does it work in React? + + + + The Virtual DOM is a lightweight copy of the actual DOM used by + React to optimize the update process. By rendering a virtual + representation of the UI, React can minimize direct DOM + manipulations and improve performance. + + + How does React determine what to re-render in the DOM when state + changes? + + + React uses a diffing algorithm, which compares the previous and the + new versions of the Virtual DOM to determine the minimal set of + changes necessary to update the actual DOM. + + + What are the benefits of using the Virtual DOM compared to direct + DOM manipulation? + + + Using the Virtual DOM reduces the cost of DOM updates, which can be + performance-intensive. It allows for efficient updates by batching + them and only touching the parts of the DOM that actually need to + change. + + + + + Answered 2023.07.19 | Delete}> + Can you explain the difference between `var`, `let`, and `const` in + JavaScript? + + + + `var` is function-scoped, while `let` and `const` are block-scoped. + This scoping difference is crucial for managing variable visibility + and lifecycle in JavaScript applications. + + + What issues might arise from using `var` in modern JavaScript? + + + Using `var` can lead to common issues like variable hoisting and + unintended variable overriding, especially in loops or conditional + blocks, which can introduce bugs and make code maintenance harder. + + + Why might you choose `const` over `let` when declaring a variable? + + + Choosing `const` helps enforce immutability for the variable's + value, which can lead to safer, more predictable code. It's a best + practice when the variable's value should not change after initial + assignment. + + + + + ), +}; diff --git a/apps/workshop/vite.config.mts b/apps/workshop/vite.config.mts index 7bb97c6..29bf350 100644 --- a/apps/workshop/vite.config.mts +++ b/apps/workshop/vite.config.mts @@ -3,11 +3,12 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; +import svgr from '@svgr/rollup'; import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react(), vanillaExtractPlugin()], + plugins: [react(),svgr(), vanillaExtractPlugin()], test: { globals: true, environment: 'jsdom', diff --git a/packages/design-system/assets/icons/ic-arrow-down-outlined.svg b/packages/design-system/assets/icons/ic-arrow-down-outlined.svg new file mode 100644 index 0000000..199ff90 --- /dev/null +++ b/packages/design-system/assets/icons/ic-arrow-down-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-arrow-left-outlined.svg b/packages/design-system/assets/icons/ic-arrow-left-outlined.svg new file mode 100644 index 0000000..b078872 --- /dev/null +++ b/packages/design-system/assets/icons/ic-arrow-left-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-arrow-right-more-outlined.svg b/packages/design-system/assets/icons/ic-arrow-right-more-outlined.svg new file mode 100644 index 0000000..57e5968 --- /dev/null +++ b/packages/design-system/assets/icons/ic-arrow-right-more-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-arrow-right-outlined.svg b/packages/design-system/assets/icons/ic-arrow-right-outlined.svg new file mode 100644 index 0000000..6b33a15 --- /dev/null +++ b/packages/design-system/assets/icons/ic-arrow-right-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-arrow-up-outlined.svg b/packages/design-system/assets/icons/ic-arrow-up-outlined.svg new file mode 100644 index 0000000..c29c583 --- /dev/null +++ b/packages/design-system/assets/icons/ic-arrow-up-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-close-outlined.svg b/packages/design-system/assets/icons/ic-close-outlined.svg new file mode 100644 index 0000000..76b3084 --- /dev/null +++ b/packages/design-system/assets/icons/ic-close-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-delete-solid.svg b/packages/design-system/assets/icons/ic-delete-solid.svg new file mode 100644 index 0000000..780e6a5 --- /dev/null +++ b/packages/design-system/assets/icons/ic-delete-solid.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/design-system/assets/icons/ic-happy-outlined.svg b/packages/design-system/assets/icons/ic-happy-outlined.svg new file mode 100644 index 0000000..8c94465 --- /dev/null +++ b/packages/design-system/assets/icons/ic-happy-outlined.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-happy-solid.svg b/packages/design-system/assets/icons/ic-happy-solid.svg new file mode 100644 index 0000000..59f4551 --- /dev/null +++ b/packages/design-system/assets/icons/ic-happy-solid.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-heart-solid-2.svg b/packages/design-system/assets/icons/ic-heart-solid-2.svg new file mode 100644 index 0000000..a8e52f3 --- /dev/null +++ b/packages/design-system/assets/icons/ic-heart-solid-2.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-heart-solid.svg b/packages/design-system/assets/icons/ic-heart-solid.svg new file mode 100644 index 0000000..56dbc0d --- /dev/null +++ b/packages/design-system/assets/icons/ic-heart-solid.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-plus-outlined.svg b/packages/design-system/assets/icons/ic-plus-outlined.svg new file mode 100644 index 0000000..08f5efa --- /dev/null +++ b/packages/design-system/assets/icons/ic-plus-outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-pollygon-down.svg b/packages/design-system/assets/icons/ic-pollygon-down.svg new file mode 100644 index 0000000..fe892a2 --- /dev/null +++ b/packages/design-system/assets/icons/ic-pollygon-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-pollygon-up.svg b/packages/design-system/assets/icons/ic-pollygon-up.svg new file mode 100644 index 0000000..46694b9 --- /dev/null +++ b/packages/design-system/assets/icons/ic-pollygon-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-sad-outlined.svg b/packages/design-system/assets/icons/ic-sad-outlined.svg new file mode 100644 index 0000000..84893f3 --- /dev/null +++ b/packages/design-system/assets/icons/ic-sad-outlined.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-sad-solid.svg b/packages/design-system/assets/icons/ic-sad-solid.svg new file mode 100644 index 0000000..1c21236 --- /dev/null +++ b/packages/design-system/assets/icons/ic-sad-solid.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-smile-outlined.svg b/packages/design-system/assets/icons/ic-smile-outlined.svg new file mode 100644 index 0000000..23a2fc5 --- /dev/null +++ b/packages/design-system/assets/icons/ic-smile-outlined.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-smile-solid.svg b/packages/design-system/assets/icons/ic-smile-solid.svg new file mode 100644 index 0000000..dca8747 --- /dev/null +++ b/packages/design-system/assets/icons/ic-smile-solid.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/design-system/assets/icons/ic-social-apple.svg b/packages/design-system/assets/icons/ic-social-apple.svg new file mode 100644 index 0000000..e514deb --- /dev/null +++ b/packages/design-system/assets/icons/ic-social-apple.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-social-google.svg b/packages/design-system/assets/icons/ic-social-google.svg new file mode 100644 index 0000000..9c567c6 --- /dev/null +++ b/packages/design-system/assets/icons/ic-social-google.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/design-system/assets/icons/ic-social-kakao.svg b/packages/design-system/assets/icons/ic-social-kakao.svg new file mode 100644 index 0000000..3cabdc7 --- /dev/null +++ b/packages/design-system/assets/icons/ic-social-kakao.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/ic-social-naver.svg b/packages/design-system/assets/icons/ic-social-naver.svg new file mode 100644 index 0000000..ab0aff7 --- /dev/null +++ b/packages/design-system/assets/icons/ic-social-naver.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/design-system/assets/icons/index.ts b/packages/design-system/assets/icons/index.ts new file mode 100644 index 0000000..38606e7 --- /dev/null +++ b/packages/design-system/assets/icons/index.ts @@ -0,0 +1,22 @@ +export { ReactComponent as CloseOutlined } from './ic-close-outlined.svg'; +export { ReactComponent as PlusOutlined } from './ic-plus-outlined.svg'; +export { ReactComponent as HeartSolid } from './ic-heart-solid.svg'; +export { ReactComponent as HeartSolid2 } from './ic-heart-solid-2.svg'; +export { ReactComponent as SmileOutlined } from './ic-smile-outlined.svg'; +export { ReactComponent as SmileSolid } from './ic-smile-solid.svg'; +export { ReactComponent as HappyOutlined } from './ic-happy-outlined.svg'; +export { ReactComponent as HappySolid } from './ic-happy-solid.svg'; +export { ReactComponent as SadOutlined } from './ic-sad-outlined.svg'; +export { ReactComponent as SadSolid } from './ic-sad-solid.svg'; +export { ReactComponent as SocialKakao } from './ic-social-kakao.svg'; +export { ReactComponent as SocialNaver } from './ic-social-naver.svg'; +export { ReactComponent as SocialGoogle } from './ic-social-google.svg'; +export { ReactComponent as SocialApple } from './ic-social-apple.svg'; +export { ReactComponent as DeleteSolid } from './ic-delete-solid.svg'; +export { ReactComponent as ArrowDownOutlined } from './ic-arrow-down-outlined.svg'; +export { ReactComponent as ArrowUpOutlined } from './ic-arrow-up-outlined.svg'; +export { ReactComponent as ArrowRightOutlined } from './ic-arrow-right-outlined.svg'; +export { ReactComponent as ArrowLeftOutlined } from './ic-arrow-left-outlined.svg'; +export { ReactComponent as ArrowRightMoreOutlined } from './ic-arrow-right-more-outlined.svg'; +export { ReactComponent as PollygonUp } from './ic-pollygon-up.svg'; +export { ReactComponent as PollygonDown } from './ic-pollygon-down.svg'; diff --git a/packages/design-system/components/Accordion/Accordion.tsx b/packages/design-system/components/Accordion/Accordion.tsx new file mode 100644 index 0000000..467a409 --- /dev/null +++ b/packages/design-system/components/Accordion/Accordion.tsx @@ -0,0 +1,24 @@ +import { type HTMLAttributes, forwardRef } from 'react'; + +import type { OmitAtomProps } from '../../types/atoms'; +import { Box } from '../Box'; + +export interface AccordionProps + extends HTMLAttributes, + OmitAtomProps {} + +export const Accordion = forwardRef( + ({ children, className, ...restProps }: AccordionProps, ref?) => { + return ( + + {children} + + ); + }, +); diff --git a/packages/design-system/components/Accordion/AccordionContent.css.ts b/packages/design-system/components/Accordion/AccordionContent.css.ts new file mode 100644 index 0000000..43b7213 --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionContent.css.ts @@ -0,0 +1,38 @@ +import { createVar, globalStyle, style } from '@vanilla-extract/css'; + +import { sprinkles } from '../../styles'; + +export const contentHeightVar = createVar(); + +export const content = style([ + sprinkles({ + display: 'flex', + flexDirection: 'column', + rowGap: '4', + overflow: 'hidden', + }), + { + maxHeight: contentHeightVar, + transitionProperty: 'max-height', + transitionDuration: '200ms', + transitionDelay: '100ms', + transitionTimingFunction: 'cubic-bezier(0.37, 0, 0.63, 1)', + }, +]); + +export const contentChild = style([ + sprinkles({ + display: 'flex', + flexDirection: 'column', + rowGap: '4', + }), +]); + +globalStyle(`${contentChild}:first-child`, { + paddingTop: '16px', +}); + +globalStyle(`${contentChild}:not(:last-child)`, { + paddingBottom: '16px', + borderBottom: '0.5px solid #EFEFEF', +}); diff --git a/packages/design-system/components/Accordion/AccordionContent.tsx b/packages/design-system/components/Accordion/AccordionContent.tsx new file mode 100644 index 0000000..e369226 --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionContent.tsx @@ -0,0 +1,45 @@ +import * as S from './AccordionContent.css'; + +import { Children, type HTMLAttributes, forwardRef, useRef } from 'react'; + +import { assignInlineVars } from '@vanilla-extract/dynamic'; + +import { useBeforeMatch } from '@jung/shared/hooks'; +import type { OmitAtomProps } from '../../types/atoms'; +import { Box } from '../Box'; +import { useAccordionContext } from './context/AccordionContext'; +import { useExpandableHeight } from './hooks/useExpandableHeight'; + +export interface AccordionContentProps + extends HTMLAttributes, + OmitAtomProps { + HIDDEN?: string; +} + +export const AccordionContent = forwardRef< + HTMLDivElement, + AccordionContentProps +>(({ className, children, ...restProps }: AccordionContentProps, ref?) => { + const { toggle, handleToggle } = useAccordionContext(); + const contentRef = useRef(null); + useBeforeMatch(contentRef, handleToggle); + const contentHeight = useExpandableHeight(contentRef, toggle); + + return ( + + ); +}); diff --git a/packages/design-system/components/Accordion/AccordionItem.css.ts b/packages/design-system/components/Accordion/AccordionItem.css.ts new file mode 100644 index 0000000..8ab6dbd --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionItem.css.ts @@ -0,0 +1,14 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles } from '../../styles'; + +export const item = style([ + sprinkles({ + display: 'flex', + flexDirection: 'column', + paddingY: '6', + paddingX: '4', + }), + { + borderBottom: '1px solid #EFEFEF', + }, +]); diff --git a/packages/design-system/components/Accordion/AccordionItem.tsx b/packages/design-system/components/Accordion/AccordionItem.tsx new file mode 100644 index 0000000..d4209fe --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionItem.tsx @@ -0,0 +1,30 @@ +import * as S from './AccordionItem.css'; + +import { type HTMLAttributes, forwardRef, useMemo } from 'react'; + +import { useToggle } from '@jung/shared/hooks'; +import type { OmitAtomProps } from '../../types/atoms'; +import { Box } from '../Box'; +import { AccoridonContext } from './context/AccordionContext'; + +export interface AccordionItemProps + extends HTMLAttributes, + OmitAtomProps {} + +export const AccordionItem = forwardRef( + ({ children, ...restProps }: AccordionItemProps, ref?) => { + const { toggle, setToggle, handleToggle } = useToggle(); + + const value = useMemo( + () => ({ toggle, setToggle, handleToggle }), + [handleToggle, setToggle, toggle], + ); + return ( + + + {children} + + + ); + }, +); diff --git a/packages/design-system/components/Accordion/AccordionPanel.tsx b/packages/design-system/components/Accordion/AccordionPanel.tsx new file mode 100644 index 0000000..e9edb17 --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionPanel.tsx @@ -0,0 +1,30 @@ +import { type HTMLAttributes, forwardRef, useRef } from 'react'; + +import type { OmitAtomProps } from '../../types/atoms'; +import { Box } from '../Box'; + +export interface AccordionPanelProps + extends HTMLAttributes, + OmitAtomProps { + title?: string; +} + +export const AccordionPanel = forwardRef( + ({ children, title, ...restProps }: AccordionPanelProps, ref?) => { + const panelRef = useRef(null); + + return ( + + {title && ( + // FIXME: 나중에 Typography 컴포넌트로 변경 + + {title} + + )} + + {children} + + + ); + }, +); diff --git a/packages/design-system/components/Accordion/AccordionTrigger.css.ts b/packages/design-system/components/Accordion/AccordionTrigger.css.ts new file mode 100644 index 0000000..190f124 --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionTrigger.css.ts @@ -0,0 +1,19 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles } from '../../styles'; + +export const trigger = sprinkles({ + display: 'flex', + justifyContent: 'space-between', + cursor: 'pointer', +}); + +export const arrow = style([ + sprinkles({ + height: 'fit', + color: 'gray400', + }), + { + transition: 'cubic-bezier(0.65, 0, 0.35, 1) 100ms', + transitionDelay: '100ms', + }, +]); diff --git a/packages/design-system/components/Accordion/AccordionTrigger.tsx b/packages/design-system/components/Accordion/AccordionTrigger.tsx new file mode 100644 index 0000000..da3f0dd --- /dev/null +++ b/packages/design-system/components/Accordion/AccordionTrigger.tsx @@ -0,0 +1,39 @@ +import * as S from './AccordionTrigger.css'; + +import { type HTMLAttributes, type ReactNode, forwardRef } from 'react'; +import { ArrowDownOutlined, ArrowUpOutlined } from '../../assets/icons'; + +import type { OmitAtomProps } from '../../types/atoms'; +import { Box } from '../Box'; +import { useAccordionContext } from './context/AccordionContext'; + +export interface AccordionTriggerProps + extends HTMLAttributes, + OmitAtomProps<'top'> { + top?: ReactNode; +} + +export const AccordionTrigger = forwardRef< + HTMLDivElement, + AccordionTriggerProps +>(({ children, top, ...restProps }: AccordionTriggerProps, ref?) => { + const { toggle, handleToggle } = useAccordionContext(); + + return ( + + + {top && top} + {children} + + + {toggle ? : } + + + ); +}); diff --git a/packages/design-system/components/Accordion/context/AccordionContext.tsx b/packages/design-system/components/Accordion/context/AccordionContext.tsx new file mode 100644 index 0000000..81b6c9c --- /dev/null +++ b/packages/design-system/components/Accordion/context/AccordionContext.tsx @@ -0,0 +1,29 @@ +import { + type Dispatch, + type SetStateAction, + createContext, + useContext, +} from 'react'; + +type AccordionContextState = { + setToggle: Dispatch>; + toggle: boolean; + handleToggle: () => void; +}; + +const initialState = { + toggle: false, + setToggle: () => {}, + handleToggle: () => {}, +}; + +export const AccoridonContext = + createContext(initialState); + +export const useAccordionContext = () => { + const context = useContext(AccoridonContext); + if (!context) { + throw new Error('It should be rendered in the Accordion component'); + } + return context; +}; diff --git a/packages/design-system/components/Accordion/hooks/useExpandableHeight.ts b/packages/design-system/components/Accordion/hooks/useExpandableHeight.ts new file mode 100644 index 0000000..fce2813 --- /dev/null +++ b/packages/design-system/components/Accordion/hooks/useExpandableHeight.ts @@ -0,0 +1,16 @@ +import { type RefObject, useEffect, useState } from 'react'; + +export const useExpandableHeight = ( + ref: RefObject, + isExpanded: boolean, +): number => { + const [contentHeight, setContentHeight] = useState(0); + + useEffect(() => { + if (ref.current) { + setContentHeight(isExpanded ? ref.current.scrollHeight : 0); + } + }, [ref, isExpanded]); + + return contentHeight; +}; diff --git a/packages/design-system/components/Accordion/index.ts b/packages/design-system/components/Accordion/index.ts new file mode 100644 index 0000000..eb51245 --- /dev/null +++ b/packages/design-system/components/Accordion/index.ts @@ -0,0 +1,14 @@ +import { Accordion } from './Accordion'; +import { AccordionContent } from './AccordionContent'; +import { AccordionItem } from './AccordionItem'; +import { AccordionPanel } from './AccordionPanel'; +import { AccordionTrigger } from './AccordionTrigger'; + +const CompoundAccordion = Object.assign(Accordion, { + Item: AccordionItem, + Trigger: AccordionTrigger, + Content: AccordionContent, + Panel: AccordionPanel, +}); + +export { CompoundAccordion as Accordion }; diff --git a/packages/design-system/components/index.ts b/packages/design-system/components/index.ts index b0c7ee3..5ab3c21 100644 --- a/packages/design-system/components/index.ts +++ b/packages/design-system/components/index.ts @@ -1,3 +1,5 @@ +export { Accordion } from './Accordion'; + export { Input } from './Input/Input'; export { Button } from './Button/Button'; export { Box, type BoxProps } from './Box'; diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 5d2faee..914a22e 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@jung/configs": "workspace:*", "@jung/typescript-config": "workspace:*", + "@jung/shared": "workspace:*", "@turbo/gen": "^1.12.4", "@types/lodash": "^4.17.0", "@types/node": "^20.11.24", diff --git a/packages/design-system/svg.d.ts b/packages/design-system/svg.d.ts new file mode 100644 index 0000000..c7fd06f --- /dev/null +++ b/packages/design-system/svg.d.ts @@ -0,0 +1,10 @@ +type ReactSVGComponent = React.FunctionComponent< + React.SVGProps & { title?: string } +>; + +declare module '*.svg' { + export const ReactComponent: ReactSVGComponent; + + const src: string; + export default src; +} diff --git a/packages/shared/hooks/index.ts b/packages/shared/hooks/index.ts new file mode 100644 index 0000000..c7ec7c2 --- /dev/null +++ b/packages/shared/hooks/index.ts @@ -0,0 +1,2 @@ +export { useToggle } from './useToggle'; +export { useBeforeMatch } from './useBeforeMatch'; diff --git a/packages/shared/hooks/useBeforeMatch.ts b/packages/shared/hooks/useBeforeMatch.ts new file mode 100644 index 0000000..7f82cce --- /dev/null +++ b/packages/shared/hooks/useBeforeMatch.ts @@ -0,0 +1,19 @@ +import { type RefObject, useEffect } from 'react'; + +export const useBeforeMatch = ( + ref: RefObject, + onMatch: (event: Event) => void, +) => { + useEffect(() => { + const handleMatch = (event: Event) => onMatch(event); + const element = ref.current; + if (element) { + element.addEventListener('beforematch', handleMatch); + } + return () => { + if (element) { + element.removeEventListener('beforematch', handleMatch); + } + }; + }, [ref, onMatch]); +}; diff --git a/packages/shared/hooks/useToggle.ts b/packages/shared/hooks/useToggle.ts new file mode 100644 index 0000000..7b9ea76 --- /dev/null +++ b/packages/shared/hooks/useToggle.ts @@ -0,0 +1,11 @@ +import { useCallback, useState } from 'react'; + +export const useToggle = (initialState = false) => { + const [toggle, setToggle] = useState(initialState); + + const handleToggle = useCallback(() => { + setToggle((prev) => !prev); + }, []); + + return { toggle, setToggle, handleToggle }; +}; diff --git a/packages/shared/package.json b/packages/shared/package.json index 5d7d3e7..e1af033 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,14 +1,17 @@ { - "name": "@jung/shared", - "version": "0.0.0", - "private": true, - "scripts": { - "dev": "echo 'Add dev script here'", - "build": "echo 'Add build script here'", - "test": "echo 'Add test script here'", - "lint": "echo 'Add lint script here'" - }, - "dependencies": { - "@jung/typescript-config": "workspace:*" - } + "name": "@jung/shared", + "version": "0.0.0", + "private": true, + "exports": { + "./hooks": "./hooks/index.ts" + }, + "scripts": { + "dev": "echo 'Add dev script here'", + "build": "echo 'Add build script here'", + "test": "echo 'Add test script here'", + "lint": "echo 'Add lint script here'" + }, + "dependencies": { + "@jung/typescript-config": "workspace:*" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a25f61c..7ed677c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,6 +151,9 @@ importers: '@storybook/test': specifier: ^7.6.17 version: 7.6.17(@types/jest@29.5.12)(jest@29.7.0)(vitest@1.3.1) + '@svgr/rollup': + specifier: ^8.1.0 + version: 8.1.0(typescript@5.3.3) '@types/react': specifier: ^18.2.56 version: 18.2.61 @@ -206,6 +209,9 @@ importers: '@jung/configs': specifier: workspace:* version: link:../configs + '@jung/shared': + specifier: workspace:* + version: link:../shared '@jung/typescript-config': specifier: workspace:* version: link:../typescript-config @@ -1228,6 +1234,36 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-transform-react-constant-elements@7.24.1(@babel/core@7.24.0): + resolution: {integrity: sha512-QXp1U9x0R7tkiGB0FOk8o74jhnap0FlZ5gNkRIWdG3eP+SvMFg118e1zaWewDzgABb106QSKpVsD3Wgd8t6ifA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-transform-react-display-name@7.24.1(@babel/core@7.24.0): + resolution: {integrity: sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.24.0): + resolution: {integrity: sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.24.0) + dev: true + /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} engines: {node: '>=6.9.0'} @@ -1248,6 +1284,31 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0): + resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) + '@babel/types': 7.24.0 + dev: true + + /@babel/plugin-transform-react-pure-annotations@7.24.1(@babel/core@7.24.0): + resolution: {integrity: sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} engines: {node: '>=6.9.0'} @@ -1490,6 +1551,21 @@ packages: esutils: 2.0.3 dev: true + /@babel/preset-react@7.24.1(@babel/core@7.24.0): + resolution: {integrity: sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-transform-react-display-name': 7.24.1(@babel/core@7.24.0) + '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.24.0) + '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.24.0) + '@babel/plugin-transform-react-pure-annotations': 7.24.1(@babel/core@7.24.0) + dev: true + /@babel/preset-typescript@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} engines: {node: '>=6.9.0'} @@ -4032,6 +4108,165 @@ packages: file-system-cache: 2.3.0 dev: true + /@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.24.0): + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.24.0): + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + dev: true + + /@svgr/babel-preset@8.1.0(@babel/core@7.24.0): + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.24.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.24.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.24.0) + dev: true + + /@svgr/core@8.1.0(typescript@5.3.3): + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + dependencies: + '@babel/core': 7.24.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.24.0) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.3.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@svgr/hast-util-to-babel-ast@8.0.0: + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + dependencies: + '@babel/types': 7.24.0 + entities: 4.5.0 + dev: true + + /@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0): + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + dependencies: + '@babel/core': 7.24.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.24.0) + '@svgr/core': 8.1.0(typescript@5.3.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0)(typescript@5.3.3): + resolution: {integrity: sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + dependencies: + '@svgr/core': 8.1.0(typescript@5.3.3) + cosmiconfig: 8.3.6(typescript@5.3.3) + deepmerge: 4.3.1 + svgo: 3.3.2 + transitivePeerDependencies: + - typescript + dev: true + + /@svgr/rollup@8.1.0(typescript@5.3.3): + resolution: {integrity: sha512-0XR1poYvPQoPpmfDYLEqUGu5ePAQ4pdgN3VFsZBNAeze7qubVpsIY1o1R6PZpKep/DKu33GSm2NhwpCLkMs2Cw==} + engines: {node: '>=14'} + dependencies: + '@babel/core': 7.24.0 + '@babel/plugin-transform-react-constant-elements': 7.24.1(@babel/core@7.24.0) + '@babel/preset-env': 7.24.0(@babel/core@7.24.0) + '@babel/preset-react': 7.24.1(@babel/core@7.24.0) + '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0) + '@rollup/pluginutils': 5.1.0 + '@svgr/core': 8.1.0(typescript@5.3.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0)(typescript@5.3.3) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + dev: true + /@swc/core-darwin-arm64@1.4.7: resolution: {integrity: sha512-IhfP2Mrrh9WcdlBJQbPNBhfdOhW/SC910SiuzvxaLgJmzq1tw6TVDNUz4Zf85TbK5uzgR0emtPc9hTGxynl57A==} engines: {node: '>=10'} @@ -4277,6 +4512,11 @@ packages: resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} dev: true + /@trysound/sax@0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: true + /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -5557,6 +5797,10 @@ packages: - supports-color dev: true + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + /bplist-parser@0.2.0: resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} engines: {node: '>= 5.10.0'} @@ -5977,6 +6221,11 @@ packages: engines: {node: '>= 6'} dev: true + /commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: true + /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true @@ -6068,6 +6317,22 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true + /cosmiconfig@8.3.6(typescript@5.3.3): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + typescript: 5.3.3 + dev: true + /create-jest@29.7.0(@types/node@20.11.27): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6105,6 +6370,32 @@ packages: engines: {node: '>=8'} dev: true + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + dev: true + + /css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.0.2 + dev: true + + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: true + /css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -6120,6 +6411,13 @@ packages: hasBin: true dev: true + /csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + css-tree: 2.2.1 + dev: true + /cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} dev: true @@ -6402,6 +6700,18 @@ packages: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} dev: true + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: true + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + /domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} @@ -6410,12 +6720,34 @@ packages: webidl-conversions: 7.0.0 dev: true + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: true + /dot-case@2.1.1: resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} dependencies: no-case: 2.3.2 dev: true + /dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + dev: true + /dotenv-expand@10.0.0: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} engines: {node: '>=12'} @@ -7512,6 +7844,14 @@ packages: engines: {node: '>= 4'} dev: true + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -8534,6 +8874,7 @@ packages: /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true dev: true /jsesc@2.5.2: @@ -8757,6 +9098,12 @@ packages: resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} dev: true + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.6.2 + dev: true + /lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} @@ -8861,6 +9208,14 @@ packages: resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==} dev: true + /mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + dev: true + + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: true + /media-query-parser@2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: @@ -9121,6 +9476,13 @@ packages: lower-case: 1.1.4 dev: true + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.6.2 + dev: true + /node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -9196,6 +9558,12 @@ packages: path-key: 4.0.0 dev: true + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + /nwsapi@2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} dev: true @@ -9423,6 +9791,13 @@ packages: no-case: 2.3.2 dev: true + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -10169,6 +10544,11 @@ packages: resolve-from: 5.0.0 dev: true + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -10514,6 +10894,13 @@ packages: no-case: 2.3.2 dev: true + /snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + dev: true + /socks-proxy-agent@8.0.1: resolution: {integrity: sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==} engines: {node: '>= 14'} @@ -10812,6 +11199,24 @@ packages: engines: {node: '>= 0.4'} dev: true + /svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + dev: true + + /svgo@3.3.2: + resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.1.0 + css-tree: 2.3.1 + css-what: 6.1.0 + csso: 5.0.5 + picocolors: 1.0.0 + dev: true + /swap-case@1.1.2: resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} dependencies: