├── .babelrc.json ├── .changeset └── config.json ├── .dependency-cruiser.js ├── .editorconfig ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-report.md └── workflows │ ├── dependencies-check-actions.yml │ ├── deploy-storybook-actions.yml │ ├── release-actions.yml │ └── test-actions.yml ├── .gitignore ├── .pnp.cjs ├── .pnp.loader.mjs ├── .prettierrc.json ├── .storybook ├── main.js └── preview.js ├── .yarn ├── plugins │ └── @yarnpkg │ │ └── plugin-workspace-tools.cjs └── releases │ └── yarn-3.3.1.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── jest.config.ts ├── package.json ├── packages ├── box │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ └── Box.tsx │ │ ├── index.ts │ │ └── types.ts │ ├── stories │ │ └── box.stories.jsx │ ├── tests │ │ └── Box.test.tsx │ └── tsconfig.json ├── button │ ├── .babelrc.json │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ └── Button.tsx │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types │ │ │ ├── base.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ └── props.ts │ ├── stories │ │ └── button.stories.jsx │ ├── tests │ │ └── button.test.tsx │ └── tsconfig.json ├── card │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Card.tsx │ │ │ ├── CardBody.tsx │ │ │ ├── CardContainer.tsx │ │ │ ├── CardDivider.tsx │ │ │ ├── CardFooter.tsx │ │ │ ├── CardHeader.tsx │ │ │ └── CardProvider.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── index.ts │ │ ├── styles │ │ │ ├── createCardStyle.ts │ │ │ ├── createContentStyle.ts │ │ │ ├── createDividerStyle.ts │ │ │ └── createFlexStyle.ts │ │ ├── types │ │ │ ├── base.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ ├── props.ts │ │ │ └── styleProps.ts │ │ └── utils │ │ │ └── omitProps.ts │ ├── stories │ │ └── card.stories.jsx │ ├── tests │ │ └── Card.test.tsx │ └── tsconfig.json ├── checkbox │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Checkbox.tsx │ │ │ └── CheckboxGroup.tsx │ │ ├── context.ts │ │ ├── hooks │ │ │ └── useKeyboardHandler.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── checkbox.stories.jsx │ ├── tests │ │ └── checkbox.test.tsx │ └── tsconfig.json ├── drawer │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Drawer.tsx │ │ │ ├── DrawerPortal.tsx │ │ │ └── DrawerTrigger.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ └── useToggleLayer.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── drawer.stories.jsx │ ├── tests │ │ └── Drawer.test.tsx │ └── tsconfig.json ├── dropdown │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Dropdown.tsx │ │ │ ├── DropdownDivider.tsx │ │ │ ├── DropdownMenu.tsx │ │ │ ├── DropdownMenuItem.tsx │ │ │ ├── DropdownSubMenu.tsx │ │ │ ├── DropdownSubMenuItem.tsx │ │ │ └── DropdownTrigger.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── useArrowKeyDown.ts │ │ │ ├── useCloseKeyDown.ts │ │ │ ├── useKeyboardHandler.ts │ │ │ ├── useOpenKeyDown.ts │ │ │ ├── useSelectItem.ts │ │ │ └── useToggleOpen.ts │ │ ├── index.ts │ │ ├── style.ts │ │ └── types │ │ │ ├── base.ts │ │ │ ├── index.ts │ │ │ └── props.ts │ ├── stories │ │ └── dropdown.stories.jsx │ ├── tests │ │ └── dropdown.test.tsx │ └── tsconfig.json ├── flex │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Flex.tsx │ │ │ └── FlexItem.tsx │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── flex.stories.jsx │ ├── tests │ │ └── flex.test.tsx │ └── tsconfig.json ├── icons │ ├── .babelrc.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Activity.tsx │ │ │ ├── Alert.tsx │ │ │ ├── Archive.tsx │ │ │ ├── ArrowBottom.tsx │ │ │ ├── ArrowLeft.tsx │ │ │ ├── ArrowRight.tsx │ │ │ ├── ArrowTop.tsx │ │ │ ├── BackWards.tsx │ │ │ ├── Bag.tsx │ │ │ ├── Ban.tsx │ │ │ ├── Bell.tsx │ │ │ ├── Book.tsx │ │ │ ├── Bookmark.tsx │ │ │ ├── Calendar.tsx │ │ │ ├── Camera.tsx │ │ │ ├── CaretBottom.tsx │ │ │ ├── CaretLeft.tsx │ │ │ ├── CaretRight.tsx │ │ │ ├── CaretTop.tsx │ │ │ ├── Cart.tsx │ │ │ ├── Checkmark.tsx │ │ │ ├── ChevronBottom.tsx │ │ │ ├── ChevronLeft.tsx │ │ │ ├── ChevronRight.tsx │ │ │ ├── ChevronTop.tsx │ │ │ ├── Clipboard.tsx │ │ │ ├── Clock.tsx │ │ │ ├── Close.tsx │ │ │ ├── Code.tsx │ │ │ ├── Compose.tsx │ │ │ ├── Creditcard.tsx │ │ │ ├── Desktop.tsx │ │ │ ├── Download.tsx │ │ │ ├── Edit.tsx │ │ │ ├── Eject.tsx │ │ │ ├── EllipsisHorizontal.tsx │ │ │ ├── EllipsisVertical.tsx │ │ │ ├── End.tsx │ │ │ ├── Export.tsx │ │ │ ├── External.tsx │ │ │ ├── Eye.tsx │ │ │ ├── Feed.tsx │ │ │ ├── File.tsx │ │ │ ├── Filter.tsx │ │ │ ├── Flag.tsx │ │ │ ├── Folder.tsx │ │ │ ├── FolderOpen.tsx │ │ │ ├── Forwards.tsx │ │ │ ├── Fullscreen.tsx │ │ │ ├── FullscreenExit.tsx │ │ │ ├── Gift.tsx │ │ │ ├── Github.tsx │ │ │ ├── Heart.tsx │ │ │ ├── Home.tsx │ │ │ ├── Import.tsx │ │ │ ├── Inbox.tsx │ │ │ ├── Info.tsx │ │ │ ├── Lightning.tsx │ │ │ ├── Link.tsx │ │ │ ├── Location.tsx │ │ │ ├── Lock.tsx │ │ │ ├── Mail.tsx │ │ │ ├── Menu.tsx │ │ │ ├── Message.tsx │ │ │ ├── Microphone.tsx │ │ │ ├── Minus.tsx │ │ │ ├── Mobile.tsx │ │ │ ├── Moon.tsx │ │ │ ├── Move.tsx │ │ │ ├── Music.tsx │ │ │ ├── Mute.tsx │ │ │ ├── Options.tsx │ │ │ ├── Paperclip.tsx │ │ │ ├── Pause.tsx │ │ │ ├── Photo.tsx │ │ │ ├── Play.tsx │ │ │ ├── Plus.tsx │ │ │ ├── Portfolio.tsx │ │ │ ├── Print.tsx │ │ │ ├── Reload.tsx │ │ │ ├── Reply.tsx │ │ │ ├── Search.tsx │ │ │ ├── Send.tsx │ │ │ ├── Settings.tsx │ │ │ ├── SignIn.tsx │ │ │ ├── SignOut.tsx │ │ │ ├── Star.tsx │ │ │ ├── Start.tsx │ │ │ ├── Tag.tsx │ │ │ ├── Telephone.tsx │ │ │ ├── Trash.tsx │ │ │ ├── Twitter.tsx │ │ │ ├── Unlock.tsx │ │ │ ├── Upload.tsx │ │ │ ├── User.tsx │ │ │ ├── Video.tsx │ │ │ ├── Volume.tsx │ │ │ ├── Work.tsx │ │ │ ├── ZoomIn.tsx │ │ │ ├── ZoomOut.tsx │ │ │ └── ZoomReset.tsx │ │ └── index.ts │ └── tsconfig.json ├── input │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── InputLabel.tsx │ │ │ ├── InputMessage.tsx │ │ │ └── TextInput.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── input.stories.jsx │ ├── tests │ │ └── input.test.tsx │ └── tsconfig.json ├── j-provider │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── public │ │ └── fonts │ │ │ ├── NotoSansKR-Black-Alphabetic.woff2 │ │ │ ├── NotoSansKR-Bold-Alphabetic.woff2 │ │ │ ├── NotoSansKR-Light-Alphabetic.woff2 │ │ │ ├── NotoSansKR-Medium-Alphabetic.woff2 │ │ │ ├── NotoSansKR-Regular-Alphabetic.woff2 │ │ │ └── NotoSansKR-Thin-Alphabetic.woff2 │ ├── src │ │ ├── ThemeProvider.tsx │ │ ├── context.ts │ │ ├── index.ts │ │ ├── preset.ts │ │ ├── styles │ │ │ └── reset.ts │ │ └── types.ts │ └── tsconfig.json ├── modal │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Modal.tsx │ │ │ ├── ModalPortal.tsx │ │ │ └── ModalTrigger.tsx │ │ ├── context.ts │ │ ├── hooks │ │ │ └── useToggleLayer.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── modal.stories.jsx │ ├── tests │ │ └── modal.test.tsx │ └── tsconfig.json ├── popover │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Popover.tsx │ │ │ ├── PopoverBody.tsx │ │ │ ├── PopoverContent.tsx │ │ │ ├── PopoverFooter.tsx │ │ │ ├── PopoverHeader.tsx │ │ │ ├── PopoverOverlay.tsx │ │ │ ├── PopoverProvider.tsx │ │ │ └── PopoverTrigger.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── useInitialRender.ts │ │ │ ├── useOpenClosePopover.ts │ │ │ └── usePopoverControl.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ ├── types │ │ │ ├── base.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ └── props.ts │ │ ├── useStyle.ts │ │ └── utils │ │ │ ├── calculateSize.ts │ │ │ └── handleEscapeKey.ts │ ├── stories │ │ └── popover.stories.jsx │ ├── tests │ │ └── Popover.test.tsx │ └── tsconfig.json ├── radio │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Radio.tsx │ │ │ ├── RadioGroup.tsx │ │ │ ├── RadioLabel.tsx │ │ │ └── RadioProvider.tsx │ │ ├── constants.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── useRadio.ts │ │ │ └── useRadioGroup.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ ├── types │ │ │ ├── base.ts │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ └── props.ts │ │ └── utils │ │ │ └── validateEventHandlers.ts │ ├── stories │ │ └── radio.stories.jsx │ ├── tests │ │ └── Radio.test.tsx │ └── tsconfig.json ├── react-utils │ ├── .babelrc.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Overlay.tsx │ │ │ ├── Portal.tsx │ │ │ └── Trigger.tsx │ │ ├── hooks │ │ │ ├── useInitialRender.ts │ │ │ └── useOutsideClick.ts │ │ ├── index.ts │ │ ├── mixins │ │ │ ├── keyboard │ │ │ │ ├── arrowKeyNavigationHandler.ts │ │ │ │ └── spaceKeyToggleHandler.ts │ │ │ ├── styles │ │ │ │ └── usePlacementStyle.ts │ │ │ └── transition │ │ │ │ └── useRipple.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── filterComponent.ts │ │ │ ├── getChildrenValidValues.ts │ │ │ ├── getComponentText.ts │ │ │ └── hasComponent.ts │ └── tsconfig.json ├── react │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── select │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── ComboboxOption.tsx │ │ │ ├── SearchNotfound.tsx │ │ │ ├── Select.tsx │ │ │ ├── SelectContainer.tsx │ │ │ ├── SelectInput.tsx │ │ │ ├── SelectOption.tsx │ │ │ └── SelectTrigger.tsx │ │ ├── constants.ts │ │ ├── hooks │ │ │ ├── SelectContext.tsx │ │ │ ├── useKeyboardNavigation.ts │ │ │ ├── useSearchOptions.ts │ │ │ └── useSelect.ts │ │ ├── index.ts │ │ ├── styles │ │ │ ├── createComboboxStyle.ts │ │ │ ├── createSelectStyle.ts │ │ │ └── createSelectTriggerStyle.ts │ │ └── types.ts │ ├── stories │ │ └── select.stories.jsx │ ├── tests │ │ └── Select.test.tsx │ └── tsconfig.json ├── stack │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ └── Stack.tsx │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── styles │ │ │ ├── createResponsiveStyle.ts │ │ │ ├── createStackStyle.ts │ │ │ └── setMarginStyle.ts │ │ └── types.ts │ ├── stories │ │ └── stack.stories.jsx │ ├── tests │ │ └── Stack.test.tsx │ └── tsconfig.json ├── tabs │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── TabContent.tsx │ │ │ ├── TabList.tsx │ │ │ ├── TabTrigger.tsx │ │ │ └── Tabs.tsx │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── useSelectKeyDown.ts │ │ │ └── useTabChangeHandle.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── tabs.stories.jsx │ ├── tests │ │ └── tabs.test.tsx │ └── tsconfig.json ├── text │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── Text.tsx │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── styles │ │ │ ├── createFontStyle.ts │ │ │ └── typography.ts │ │ └── types.ts │ ├── stories │ │ └── Text.stories.jsx │ └── tsconfig.json ├── textarea │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Textarea.tsx │ │ │ ├── TextareaContainer.tsx │ │ │ ├── TextareaContext.tsx │ │ │ └── TextareaLabel.tsx │ │ ├── constants.ts │ │ ├── hooks │ │ │ ├── useSmart.ts │ │ │ └── useTextarea.ts │ │ ├── index.ts │ │ ├── styles │ │ │ ├── createLabelStyle.ts │ │ │ ├── createTextareaStyle.ts │ │ │ └── createWrapperStyle.ts │ │ └── types.ts │ ├── stories │ │ └── textarea.stories.jsx │ ├── tests │ │ └── Textarea.test.tsx │ └── tsconfig.json ├── theme │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── token │ │ │ ├── colors.ts │ │ │ ├── opacity.ts │ │ │ ├── shadows.ts │ │ │ ├── spacings.ts │ │ │ └── zIndices.ts │ │ ├── types │ │ │ ├── classVariants.ts │ │ │ ├── color.ts │ │ │ └── spacings.ts │ │ └── utils │ │ │ ├── createClassVariant.ts │ │ │ ├── getColorByTokenOrHex.ts │ │ │ ├── getColorbyToken.ts │ │ │ └── setTextColorByBackground.ts │ └── tsconfig.json ├── tooltip │ ├── .babelrc.json │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── setup-jest.ts │ ├── src │ │ ├── components │ │ │ ├── Tooltip.tsx │ │ │ ├── TooltipContent.tsx │ │ │ └── TooltipTarget.tsx │ │ ├── context.ts │ │ ├── index.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── stories │ │ └── tooltip.stories.jsx │ ├── tests │ │ └── tooltip.test.tsx │ └── tsconfig.json └── utils │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ ├── calculateElementPosition.ts │ ├── combineClassNames.ts │ ├── event.ts │ ├── eventTypes.ts │ └── index.ts │ └── tsconfig.json ├── setup-jest.ts ├── tsconfig.json ├── tsupconfig.ts └── yarn.lock /.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]], 3 | "plugins": ["@emotion/babel-plugin"] 4 | } 5 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,yml}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: 기능 동작 버그 리포트 4 | title: '' 5 | labels: Issue 6 | assignees: '' 7 | 8 | --- 9 | 10 | **상세 설명** 11 | A clear and concise description of what the bug is. 12 | 13 | **상황 재현** 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **예상 동작** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **스크린샷** 23 | If applicable, add screenshots to help explain your problem. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Report 3 | about: 기능 추가 리포트 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Work 11 | - [ ] work1 12 | - [ ] work2.. 13 | -------------------------------------------------------------------------------- /.github/workflows/dependencies-check-actions.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Check Action 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | jobs: 7 | dependency-check: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: checkout 11 | uses: actions/checkout@v2 12 | - name: Use Node.js 16.x 13 | uses: actions/setup-node@v2 14 | with: 15 | node-version: '16.x' 16 | cache: 'yarn' 17 | token: ${{ secrets.WORKFLOW_TOKEN }} 18 | - name: Install dependencies 19 | env: 20 | YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' 21 | run: yarn install 22 | - name: Check dependencies 23 | run: yarn dependency-cruiser packages 24 | -------------------------------------------------------------------------------- /.github/workflows/test-actions.yml: -------------------------------------------------------------------------------- 1 | name: Test Action 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Use Node.js 16.x 13 | uses: actions/setup-node@v2 14 | with: 15 | node-version: '16.x' 16 | cache: 'yarn' 17 | token: ${{ secrets.WORKFLOW_TOKEN }} 18 | - name: Install dependencies 19 | env: 20 | YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' 21 | run: yarn install 22 | - name: Run tests 23 | env: 24 | NODE_OPTIONS: '--max_old_space_size=4096' 25 | run: yarn test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yarn/* 2 | !.yarn/patches 3 | !.yarn/plugins 4 | !.yarn/releases 5 | .yarn/sdks 6 | !.yarn/versions 7 | 8 | # Swap the comments on the following lines if you don't wish to use zero-installs 9 | # Documentation here: https://yarnpkg.com/features/zero-installs 10 | .yarn/cache 11 | #.pnp.* 12 | 13 | **/node_modules 14 | /storybook-static 15 | **.test.tsx.snap 16 | dist/ 17 | .vscode 18 | packages/*/package.json.backup 19 | packages/*/package.tgz 20 | /coverage 21 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "bracketSpacing": true, 4 | "printWidth": 120, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "arrowParens": "avoid", 8 | "trailingComma": "none" 9 | } 10 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | 4 | function getStories(pkg) { 5 | const scope = pkg ? [pkg] : fs.readdirSync('packages'); 6 | return scope 7 | .map(package => `packages/${package}/stories`) 8 | .filter(storyDir => fs.existsSync(storyDir)) 9 | .map(storyDir => `../${storyDir}/*.stories.@(js|jsx|ts|tsx)`); 10 | } 11 | 12 | module.exports = { 13 | stories: getStories(), 14 | // stories: ['../packages/button/stories/.stories.mdx', '../packages/button/stories/.stories.@(js|jsx|ts|tsx)'], 15 | addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], 16 | framework: '@storybook/react' 17 | }; 18 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { ThemeProvider } from '@jdesignlab/j-provider'; 2 | export const decorators = [ 3 | Story => ( 4 | 5 | 6 | 7 | ) 8 | ]; 9 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: pnp 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 5 | spec: '@yarnpkg/plugin-workspace-tools' 6 | 7 | yarnPath: .yarn/releases/yarn-3.3.1.cjs 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 DesignSystemLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | verbose: true, 5 | rootDir: './', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | projects: ['/packages/*/jest.config.ts'] 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /packages/box/README.md: -------------------------------------------------------------------------------- 1 | # Box 2 | 3 | Box는 스타일링을 위한 기본적인 UI 컴포넌트입니다. 기본적으로 `div`로 렌더링되며, `as` 속성을 사용하여 원하는 요소로 변경할 수 있습니다. 4 | 5 | ## Usage 6 | 7 | [Storybook](https://designsystemlab.github.io/design-system/?path=/docs/layout-box--basic) 8 | 9 | ```jsx 10 | Some Content.. 11 | ``` 12 | 13 | ## Props 14 | 15 | ### Box 16 | 17 | | Property | Allow Types | Description | Default | 18 | | --------------- | ------------------- | ----------------------------- | ------------- | 19 | | as | `React.ElementType` | Elemenet Type | `div` | 20 | | backgroundColor | `ColorToken` | Background 색상을 지정합니다. | `transparent` | 21 | | color | `CorlorToken` | Color 색상을 지정합니다. | | 22 | | style | `CssObject` | 추가적인 스타일을 지정합니다. | | 23 | -------------------------------------------------------------------------------- /packages/box/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/box/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/box/src/components/Box.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { getColorByToken, setTextColorByBackground, createClassVariant } from '@jdesignlab/theme'; 3 | import { BoxProps } from '../types'; 4 | 5 | export const Box = (props: BoxProps) => { 6 | const { 7 | children, 8 | as = 'div', 9 | color, 10 | backgroundColor = 'shades-transparent', 11 | style = {}, 12 | className, 13 | role = 'presentation', 14 | ...restProps 15 | } = props; 16 | const Component = as; 17 | const defaultClassName = createClassVariant('box', 'wrapper'); 18 | const boxClassName = className ? `${defaultClassName} ${className}` : defaultClassName; 19 | const defaultBackgroundColor = getColorByToken(backgroundColor); 20 | const defaultTextColor = setTextColorByBackground(defaultBackgroundColor); 21 | style.backgroundColor = defaultBackgroundColor; 22 | style.color = color ? getColorByToken(color) : defaultTextColor; 23 | 24 | return ( 25 | 26 | {children} 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/box/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Box'; 2 | -------------------------------------------------------------------------------- /packages/box/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, HTMLAttributes } from 'react'; 2 | import type { CSSObject } from '@emotion/react'; 3 | import type { ColorToken } from '@jdesignlab/theme'; 4 | 5 | export type AsElement = React.ElementType; 6 | export type ExternalStyle = CSSObject & CSSProperties; 7 | 8 | export interface BoxProps extends HTMLAttributes { 9 | children?: React.ReactNode; 10 | as?: AsElement; 11 | backgroundColor?: ColorToken; 12 | color?: ColorToken; 13 | style?: ExternalStyle; 14 | } 15 | -------------------------------------------------------------------------------- /packages/box/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/button/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]], 3 | "plugins": ["@emotion/babel-plugin"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/button/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/button/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/button/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Button'; 2 | -------------------------------------------------------------------------------- /packages/button/src/types/base.ts: -------------------------------------------------------------------------------- 1 | export type ButtonVariant = 'solid' | 'ghost' | 'outline' | 'link' | 'unstyled'; 2 | export type ButtonSize = 'sm' | 'md' | 'lg' | 'xl'; 3 | -------------------------------------------------------------------------------- /packages/button/src/types/context.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/button/src/types/context.ts -------------------------------------------------------------------------------- /packages/button/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base'; 2 | export * from './props'; 3 | -------------------------------------------------------------------------------- /packages/button/src/types/props.ts: -------------------------------------------------------------------------------- 1 | import { ButtonSize, ButtonVariant } from './base'; 2 | import type { ColorToken } from '@jdesignlab/theme'; 3 | 4 | export interface ButtonProps extends React.ButtonHTMLAttributes { 5 | children?: React.ReactNode; 6 | variant?: ButtonVariant; 7 | size?: ButtonSize; 8 | disabled?: boolean; 9 | color?: ColorToken; 10 | full?: boolean; 11 | icon?: JSX.Element; 12 | as?: React.ElementType; 13 | } 14 | -------------------------------------------------------------------------------- /packages/button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/card/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/card/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/card/src/components/Card.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { CardProvider } from './CardProvider'; 3 | import { CardContainer } from './CardContainer'; 4 | import { CardHeader } from './CardHeader'; 5 | import { CardBody } from './CardBody'; 6 | import { CardFooter } from './CardFooter'; 7 | import { CardDivider } from './CardDivider'; 8 | import { REQUIRED_CARD_PROPS } from '../constants'; 9 | import omitProps from '../utils/omitProps'; 10 | import type { CardProps } from '../types'; 11 | 12 | export const Card = (props: CardProps) => { 13 | const { children, ...propsWithoutChildren } = props; 14 | const domAttributes = omitProps(propsWithoutChildren, REQUIRED_CARD_PROPS); 15 | 16 | return ( 17 | 18 | {props.children} 19 | 20 | ); 21 | }; 22 | Card.displayName = 'Card'; 23 | Card.Header = CardHeader; 24 | Card.Body = CardBody; 25 | Card.Footer = CardFooter; 26 | Card.Divider = CardDivider; 27 | -------------------------------------------------------------------------------- /packages/card/src/components/CardBody.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { jsx } from '@emotion/react'; 3 | import { useContext } from 'react'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import { CardContext } from '../context'; 6 | import createContentStyle from '../styles/createContentStyle'; 7 | import { DEFAULT_BORDER_COLOR } from '../constants'; 8 | import type { CardBodyProps } from '../types'; 9 | 10 | export const CardBody = (props: CardBodyProps) => { 11 | const { children, as = 'div', className = '', ...restProps } = props; 12 | const { direction } = useContext(CardContext).styleProps; 13 | return jsx( 14 | as, 15 | { 16 | css: createContentStyle(direction, DEFAULT_BORDER_COLOR), 17 | className: `${createClassVariant('card', 'content')} ${className}`, 18 | ...restProps 19 | }, 20 | children 21 | ); 22 | }; 23 | 24 | CardBody.displayName = 'CardBody'; 25 | -------------------------------------------------------------------------------- /packages/card/src/components/CardDivider.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { useContext } from 'react'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | import createDividerStyle from '../styles/createDividerStyle'; 5 | import { CardContext } from '../context'; 6 | 7 | export const CardDivider = () => { 8 | const { direction } = useContext(CardContext).styleProps; 9 | return ( 10 |
15 | ); 16 | }; 17 | 18 | CardDivider.displayName = 'CardDivider'; 19 | -------------------------------------------------------------------------------- /packages/card/src/components/CardFooter.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { jsx } from '@emotion/react'; 3 | import { useContext } from 'react'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import { DEFAULT_BORDER_COLOR } from '../constants'; 6 | import { CardContext } from '../context'; 7 | import createContentStyle from '../styles/createContentStyle'; 8 | import type { CardFooterProps } from '../types'; 9 | 10 | export const CardFooter = (props: CardFooterProps) => { 11 | const { direction } = useContext(CardContext).styleProps; 12 | const { children, as = 'footer', className = '', ...restProps } = props; 13 | return jsx( 14 | as, 15 | { 16 | css: createContentStyle(direction, DEFAULT_BORDER_COLOR), 17 | className: `${className} ${createClassVariant('card', 'footer')}`, 18 | ...restProps 19 | }, 20 | children 21 | ); 22 | }; 23 | 24 | CardFooter.displayName = 'CardFooter'; 25 | -------------------------------------------------------------------------------- /packages/card/src/components/CardHeader.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css, jsx } from '@emotion/react'; 3 | import { useContext } from 'react'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import { CardContext } from '../context'; 6 | import createContentStyle from '../styles/createContentStyle'; 7 | import type { CardHeaderProps } from '../types'; 8 | import { DEFAULT_BORDER_COLOR } from '../constants'; 9 | 10 | export const CardHeader = (props: CardHeaderProps) => { 11 | const { children, as = 'header', role = 'heading', className = '', ...restProps } = props; 12 | const { direction } = useContext(CardContext).styleProps; 13 | 14 | return jsx( 15 | as, 16 | { 17 | css: [createContentStyle(direction, DEFAULT_BORDER_COLOR)], 18 | className: `${className} ${createClassVariant('card', 'footer')}`, 19 | ...restProps 20 | }, 21 | children 22 | ); 23 | }; 24 | 25 | CardHeader.displayName = 'CardHeader'; 26 | -------------------------------------------------------------------------------- /packages/card/src/components/CardProvider.tsx: -------------------------------------------------------------------------------- 1 | import { defaultContextValues, CardContext } from '../context'; 2 | 3 | export const CardProvider = ({ ...props }) => { 4 | const { cardProps } = props; 5 | const defaultStyleProps = defaultContextValues.styleProps; 6 | 7 | const { 8 | align = defaultStyleProps.align, 9 | color = defaultStyleProps.color, 10 | direction = defaultStyleProps.direction, 11 | justify = defaultStyleProps.justify, 12 | size = defaultStyleProps.size, 13 | variant = defaultStyleProps.variant, 14 | ...restProps 15 | } = cardProps; 16 | 17 | return ( 18 | 24 | {props.children} 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/card/src/constants.ts: -------------------------------------------------------------------------------- 1 | import type { ColorToken } from '@jdesignlab/theme'; 2 | import type { StyleProps } from './types'; 3 | 4 | const REQUIRED_CARD_PROPS: (keyof StyleProps)[] = ['align', 'color', 'direction', 'justify', 'size', 'variant']; 5 | const DEFAULT_CARD_STYLE: Required = { 6 | color: 'primary-500', 7 | align: 'start', 8 | justify: 'start', 9 | direction: 'vertical', 10 | size: 'md', 11 | variant: 'elevated' 12 | }; 13 | const DEFAULT_BORDER_COLOR: ColorToken = 'border'; 14 | 15 | export { REQUIRED_CARD_PROPS, DEFAULT_CARD_STYLE, DEFAULT_BORDER_COLOR }; 16 | -------------------------------------------------------------------------------- /packages/card/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { DEFAULT_CARD_STYLE } from './constants'; 3 | import type { ReturnContext } from './types'; 4 | 5 | export const defaultContextValues: ReturnContext = { 6 | cardProps: {}, 7 | styleProps: DEFAULT_CARD_STYLE 8 | }; 9 | 10 | export const CardContext = createContext(defaultContextValues); 11 | -------------------------------------------------------------------------------- /packages/card/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Card'; 2 | -------------------------------------------------------------------------------- /packages/card/src/styles/createContentStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import type { ColorToken } from '@jdesignlab/theme'; 3 | import type { Direction } from '../types'; 4 | 5 | const createContentStyle = (direction: Direction, borderColor: ColorToken) => { 6 | if (direction === 'horizontal') { 7 | return css({ 8 | boxSizing: 'border-box', 9 | borderRight: `1px solid ${borderColor}`, 10 | maxWidth: '33%', 11 | wordWrap: 'break-word' 12 | }); 13 | } 14 | 15 | return css({ 16 | borderTop: `1px solid ${borderColor}`, 17 | wordWrap: 'break-word', 18 | maxWidth: '100%', 19 | boxSizing: 'border-box' 20 | }); 21 | }; 22 | 23 | export default createContentStyle; 24 | -------------------------------------------------------------------------------- /packages/card/src/styles/createDividerStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import { getColorByToken } from '@jdesignlab/theme'; 3 | import { DEFAULT_BORDER_COLOR } from '../constants'; 4 | import { Direction } from '../types'; 5 | 6 | const createDividerStyle = (direction: Direction) => { 7 | const dividerColor = getColorByToken(DEFAULT_BORDER_COLOR); 8 | 9 | if (direction === 'vertical') { 10 | return css({ 11 | width: '100%', 12 | height: 0, 13 | margin: '12px 0', 14 | borderTop: `${dividerColor} solid 1px` 15 | }); 16 | } 17 | return css({ 18 | height: '64px', 19 | width: '1px', 20 | margin: '0 4px', 21 | borderLeft: `${dividerColor} solid 1px` 22 | }); 23 | }; 24 | 25 | export default createDividerStyle; 26 | -------------------------------------------------------------------------------- /packages/card/src/styles/createFlexStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import type { Direction, FlexMap, FlexToken } from '../types'; 3 | 4 | const createFlexStyle = (justify: FlexToken, align: FlexToken, direction: Direction) => { 5 | const flexMap: FlexMap = { 6 | stretch: 'stretch', 7 | start: 'flex-start', 8 | end: 'flex-end', 9 | center: 'center', 10 | between: 'space-between', 11 | around: 'space-around' 12 | }; 13 | 14 | return css({ 15 | display: 'flex', 16 | flexDirection: direction === 'horizontal' ? 'row' : 'column', 17 | alignItems: `${flexMap[align]}`, 18 | justifyContent: `${flexMap[justify]}`, 19 | borderRadius: '8px' 20 | }); 21 | }; 22 | 23 | export default createFlexStyle; 24 | -------------------------------------------------------------------------------- /packages/card/src/types/base.ts: -------------------------------------------------------------------------------- 1 | export type FlexToken = 'start' | 'end' | 'center' | 'between' | 'around' | 'stretch'; 2 | export type FlexMap = Record; 3 | 4 | export type Variant = 'elevated' | 'outlined' | 'filled'; 5 | export type Size = 'sm' | 'md' | 'lg'; 6 | export type Direction = 'horizontal' | 'vertical'; 7 | export type AsElement = React.ElementType; 8 | -------------------------------------------------------------------------------- /packages/card/src/types/context.ts: -------------------------------------------------------------------------------- 1 | import { CardProps } from './props'; 2 | import { StyleProps } from './styleProps'; 3 | 4 | export interface ReturnContext { 5 | cardProps: CardProps; 6 | styleProps: StyleProps; 7 | } 8 | -------------------------------------------------------------------------------- /packages/card/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base'; 2 | export * from './props'; 3 | export * from './context'; 4 | export * from './styleProps'; 5 | -------------------------------------------------------------------------------- /packages/card/src/types/styleProps.ts: -------------------------------------------------------------------------------- 1 | import { CardProps } from './props'; 2 | 3 | export type CardStyle = 'variant' | 'color' | 'align' | 'justify' | 'direction' | 'size'; 4 | export type StyleProps = Required>; 5 | -------------------------------------------------------------------------------- /packages/card/src/utils/omitProps.ts: -------------------------------------------------------------------------------- 1 | const filterProps = (props: P, keys: K[]) => { 2 | const result = {} as Record]>; 3 | for (const prop in props) { 4 | if (!keys.includes(prop as unknown as K)) { 5 | result[prop] = props[prop]; 6 | } 7 | } 8 | return result; 9 | }; 10 | 11 | export default filterProps; 12 | -------------------------------------------------------------------------------- /packages/card/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/checkbox/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/checkbox/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/checkbox/src/components/CheckboxGroup.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { createClassVariant } from '@jdesignlab/theme'; 3 | import { CheckboxGroupContext } from '../context'; 4 | import type { CheckboxGroupProps } from '../types'; 5 | 6 | export const CheckboxGroup = (props: CheckboxGroupProps) => { 7 | const { children, defaultValue, ...otherProps } = props; 8 | const contextValue = { 9 | defaultValues: props.defaultValue ?? [] 10 | }; 11 | 12 | return ( 13 | 14 |
15 | {children} 16 |
17 |
18 | ); 19 | }; 20 | 21 | CheckboxGroup.displayName = 'Checkbox.Group'; 22 | -------------------------------------------------------------------------------- /packages/checkbox/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { CheckboxValue } from './types'; 3 | export const CheckboxGroupContext = createContext({ 4 | defaultValues: undefined as CheckboxValue 5 | }); 6 | -------------------------------------------------------------------------------- /packages/checkbox/src/hooks/useKeyboardHandler.ts: -------------------------------------------------------------------------------- 1 | import { spaceKeyToggleHandler, arrowKeyNavigationHandler } from '@jdesignlab/react-utils'; 2 | 3 | export const useKeyboardHandler = (props: { 4 | event: React.KeyboardEvent; 5 | parentScope: string; 6 | selectorOfList: string; 7 | }) => { 8 | const { event, parentScope, selectorOfList } = props; 9 | const el = event.target as HTMLInputElement; 10 | 11 | const spaceKeyAction = () => { 12 | el.checked = !el.checked; 13 | }; 14 | 15 | spaceKeyToggleHandler({ event, action: spaceKeyAction }); 16 | arrowKeyNavigationHandler({ event, parentScope, selectorOfList }); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/checkbox/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Checkbox'; 2 | -------------------------------------------------------------------------------- /packages/checkbox/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ColorToken } from '@jdesignlab/theme'; 2 | 3 | export type CheckboxSize = 'sm' | 'md' | 'lg' | 'xl'; 4 | export type CheckboxValue = number[] | string[] | undefined; 5 | 6 | export interface CheckboxProps extends React.InputHTMLAttributes { 7 | children?: React.ReactNode; 8 | color?: ColorToken; 9 | value?: string | number; 10 | } 11 | 12 | export interface CheckboxGroupProps { 13 | children?: React.ReactNode; 14 | defaultValue?: string[] | number[]; 15 | } 16 | -------------------------------------------------------------------------------- /packages/checkbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/drawer/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/drawer/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/drawer/src/components/DrawerTrigger.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { Trigger } from '@jdesignlab/react-utils'; 3 | import { useContext } from 'react'; 4 | import { DrawerContext } from '../context'; 5 | 6 | export const DrawerTrigger = (props: any) => { 7 | const { children } = props; 8 | const { id, onOpen } = useContext(DrawerContext); 9 | 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }; 16 | 17 | DrawerTrigger.displayName = 'Drawer.Trigger'; 18 | -------------------------------------------------------------------------------- /packages/drawer/src/constants.ts: -------------------------------------------------------------------------------- 1 | import type { ColorToken } from '@jdesignlab/theme'; 2 | import type { DrawerProps } from './types'; 3 | 4 | type DrwaerOption = Pick; 5 | 6 | const DEFAULT_OPTIONS: Required = { 7 | open: false, 8 | full: false, 9 | placement: 'left' 10 | }; 11 | 12 | const DRAWER_OVERRAY_BACKGROUND: ColorToken = 'shades-black'; 13 | const DRAWER_BACKROUND: ColorToken = 'shades-white'; 14 | const DRAWER_ID_PREFIX: string = 'jds-drawer'; 15 | 16 | export { DEFAULT_OPTIONS, DRAWER_OVERRAY_BACKGROUND, DRAWER_BACKROUND, DRAWER_ID_PREFIX }; 17 | -------------------------------------------------------------------------------- /packages/drawer/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { DrawerContextProps } from './types'; 3 | 4 | export const defaultContextValues: DrawerContextProps = { 5 | id: '', 6 | isOpen: false, 7 | onOpen: () => {}, 8 | onClose: () => {}, 9 | hasCloseIcon: true, 10 | disableOverlayClose: false, 11 | placement: 'right', 12 | full: false 13 | }; 14 | 15 | export const DrawerContext = createContext(defaultContextValues); 16 | -------------------------------------------------------------------------------- /packages/drawer/src/hooks/useToggleLayer.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from 'react'; 2 | 3 | export const useToggleLayer = ( 4 | openProp: boolean | undefined, 5 | onOpenProp: (() => void) | undefined, 6 | onCloseProp: (() => void) | undefined 7 | ) => { 8 | const [isOpen, setIsOpen] = useState(!!openProp); 9 | const isControlled = openProp !== undefined; 10 | 11 | useEffect(() => { 12 | setIsOpen(!!openProp); 13 | }, [openProp]); 14 | 15 | const onToggle = () => { 16 | setIsOpen(prev => !prev); 17 | if (isOpen) onCloseProp?.(); 18 | else onOpenProp?.(); 19 | }; 20 | 21 | const onOpen = () => { 22 | isControlled ? onOpenProp?.() : onToggle(); 23 | }; 24 | 25 | const onClose = () => { 26 | isControlled ? onCloseProp?.() : onToggle(); 27 | }; 28 | 29 | return { isOpen, onOpen, onClose }; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/drawer/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '../src/components/Drawer'; 2 | -------------------------------------------------------------------------------- /packages/drawer/src/types.ts: -------------------------------------------------------------------------------- 1 | export type Placement = 'top' | 'right' | 'bottom' | 'left'; 2 | 3 | export interface DrawerContextProps { 4 | id: string; 5 | isOpen: boolean; 6 | onOpen(): void; 7 | onClose(): void; 8 | hasCloseIcon: boolean; 9 | disableOverlayClose: boolean; 10 | placement: Placement; 11 | full: boolean; 12 | } 13 | 14 | export interface DrawerProps { 15 | children?: React.ReactNode; 16 | open?: boolean; 17 | onOpen?: () => void; 18 | onClose?: () => void; 19 | hasCloseIcon?: boolean; 20 | disableOverlayClose?: boolean; 21 | placement?: Placement; 22 | full?: boolean; 23 | } 24 | 25 | export interface DrawerTriggerProps { 26 | children?: React.ReactNode; 27 | onClick?: () => void; 28 | } 29 | -------------------------------------------------------------------------------- /packages/drawer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/dropdown/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/dropdown/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/dropdown/src/components/DropdownDivider.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | 3 | import { dropdownDividerStyle } from '../style'; 4 | 5 | export const Divider = () => { 6 | return
; 7 | }; 8 | 9 | Divider.displayName = 'Dropdown.Divider' -------------------------------------------------------------------------------- /packages/dropdown/src/constants.ts: -------------------------------------------------------------------------------- 1 | /** DOM */ 2 | export const DROPDOWN_ROLE_QUERY = "[role='menu']"; 3 | export const NOT_DISABLED_DROPDOWN_MENU_QUERY = '.menu_item:not([disabled])'; 4 | export const NOT_DISABLED_DROPDOWN_SUB_ITEM_QUERY = '.menu_item:not([disabled])'; 5 | export const DROPDOWN_MENU_WRAPPER_CLASS = '.menu_wrapper'; 6 | export const DROPDOWN_MENU_OPEN_CLASS_NAME = 'menu_open'; 7 | -------------------------------------------------------------------------------- /packages/dropdown/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const DropdownContext = createContext({ 4 | width: 0, 5 | placement: 'top', 6 | triggerWidth: 0, 7 | setTriggerWidth: (w: any) => {}, 8 | triggerHeight: 0, 9 | setTriggerHeight: (h: any) => {}, 10 | gap: 0 11 | }); 12 | 13 | export const DropdownSubContext = createContext({ 14 | subOpen: false, 15 | setSubOpen: (value: boolean) => {} 16 | }); 17 | -------------------------------------------------------------------------------- /packages/dropdown/src/hooks/useCloseKeyDown.ts: -------------------------------------------------------------------------------- 1 | import React, { useContext, useCallback, RefObject } from 'react'; 2 | import { useToggleOpen } from './useToggleOpen'; 3 | 4 | const useCloseKeyDown = () => (event: React.KeyboardEvent) => { 5 | const el = event.currentTarget; 6 | switch (event.key) { 7 | case 'Escape': 8 | case 'Esc': 9 | event.preventDefault(); 10 | useToggleOpen(el); 11 | return; 12 | } 13 | }; 14 | 15 | export default useCloseKeyDown; 16 | -------------------------------------------------------------------------------- /packages/dropdown/src/hooks/useKeyboardHandler.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from 'react'; 2 | import { spaceKeyToggleHandler, arrowKeyNavigationHandler } from '@jdesignlab/react-utils'; 3 | import { useSelectItem } from './useSelectItem'; 4 | 5 | export const useKeyboardHandler = (props: { 6 | event: React.KeyboardEvent; 7 | parentScope: string; 8 | selectorOfList: string; 9 | state?: boolean; 10 | setState?: Dispatch>; 11 | onClick?: () => void; 12 | }) => { 13 | const { event, parentScope, selectorOfList, setState, onClick } = props; 14 | if (event.key === 'Enter' && onClick) { 15 | useSelectItem(event, onClick); 16 | } 17 | spaceKeyToggleHandler({ event, setState }); 18 | arrowKeyNavigationHandler({ event, parentScope, selectorOfList }); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/dropdown/src/hooks/useOpenKeyDown.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from 'react'; 2 | import React, { useContext, useCallback, RefObject } from 'react'; 3 | import { useToggleOpen } from './useToggleOpen'; 4 | 5 | const MENU_WRAPPER_SELECTOR = '.menu_wrapper'; 6 | const MENU_ITEM_SELECTOR = '.menu_item:not([disabled])'; 7 | 8 | const useOpenKeyDown = (event: React.KeyboardEvent) => { 9 | const el = event.currentTarget; 10 | switch (event.key) { 11 | case 'ArrowUp': 12 | case 'ArrowDown': 13 | case 'ArrowLeft': 14 | case 'ArrowRight': 15 | case 'Space': 16 | case ' ': 17 | case 'Enter': 18 | event.preventDefault(); 19 | useToggleOpen(el); 20 | const firstItem = el.closest(MENU_WRAPPER_SELECTOR)?.querySelector(MENU_ITEM_SELECTOR); 21 | firstItem?.focus(); 22 | } 23 | }; 24 | 25 | export default useOpenKeyDown; 26 | -------------------------------------------------------------------------------- /packages/dropdown/src/hooks/useSelectItem.ts: -------------------------------------------------------------------------------- 1 | import { useToggleOpen } from './useToggleOpen'; 2 | 3 | export const useSelectItem = ( 4 | event: React.MouseEvent | React.KeyboardEvent, 5 | onClick?: () => void 6 | ) => { 7 | if (onClick) onClick(); 8 | useToggleOpen(event.currentTarget); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/dropdown/src/hooks/useToggleOpen.ts: -------------------------------------------------------------------------------- 1 | export const useToggleOpen = (dropdownMenu: HTMLElement) => { 2 | if (dropdownMenu) { 3 | dropdownMenu.classList.toggle('menu_close'); 4 | dropdownMenu.classList.toggle('menu_open'); 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /packages/dropdown/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Dropdown'; 2 | -------------------------------------------------------------------------------- /packages/dropdown/src/types/base.ts: -------------------------------------------------------------------------------- 1 | export type DropdownAnchor = 'top' | 'right' | 'bottom' | 'left'; 2 | -------------------------------------------------------------------------------- /packages/dropdown/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base'; 2 | export * from './props'; 3 | -------------------------------------------------------------------------------- /packages/dropdown/src/types/props.ts: -------------------------------------------------------------------------------- 1 | import { DropdownAnchor } from './base'; 2 | 3 | export interface DropdownProps { 4 | children?: React.ReactNode; 5 | width?: number; 6 | placement?: DropdownAnchor; 7 | gap?: number | string; 8 | } 9 | 10 | export interface DropdownTriggerProps { 11 | children?: React.ReactNode; 12 | } 13 | 14 | export interface DropdownSubMenuProps { 15 | children?: React.ReactNode; 16 | } 17 | 18 | export interface DropdownMenuProps { 19 | children?: React.ReactNode; 20 | } 21 | 22 | export interface DropdownMenuItemProps { 23 | children?: React.ReactNode; 24 | disabled?: boolean; 25 | onClick?: () => void; 26 | hasSub?: boolean; 27 | } 28 | 29 | export interface DropdownSubMenuItemProps { 30 | children?: React.ReactNode; 31 | disabled?: boolean; 32 | onClick?: () => void; 33 | } 34 | -------------------------------------------------------------------------------- /packages/dropdown/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/flex/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/flex/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/flex/src/components/Flex.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { createClassVariant } from '@jdesignlab/theme'; 3 | import { containerStyle } from '../styles'; 4 | import type { FlexContainerProps } from '../types'; 5 | import { FlexItem } from './FlexItem'; 6 | 7 | export const Flex = (props: FlexContainerProps) => { 8 | const { children, style, as = 'div', ...otherProps } = props; 9 | const FlexContainer = as; 10 | 11 | return ( 12 | 17 | {children} 18 | 19 | ); 20 | }; 21 | 22 | Flex.Item = FlexItem; 23 | Flex.displayName = 'Flex'; 24 | -------------------------------------------------------------------------------- /packages/flex/src/components/FlexItem.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { createClassVariant } from '@jdesignlab/theme'; 3 | import { itemStyle } from '../styles'; 4 | import type { FlexItemProps } from '../types'; 5 | 6 | export const FlexItem = (props: FlexItemProps) => { 7 | const { children, as = 'div', style, flex, self, order, ...otherProps } = props; 8 | const FlexItemComponent = as; 9 | 10 | return ( 11 | 16 | {children} 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/flex/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Flex'; 2 | -------------------------------------------------------------------------------- /packages/flex/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import type { FlexContainerProps, Self } from './types'; 3 | 4 | export const containerStyle = (props: FlexContainerProps) => { 5 | return css({ 6 | ...props.style, 7 | display: 'flex', 8 | flexDirection: props.direction || 'row', 9 | flexWrap: props.wrap || 'nowrap', 10 | justifyContent: props.justify, 11 | alignItems: props.items, 12 | alignContent: props.content, 13 | gap: props.gap 14 | }); 15 | }; 16 | 17 | export const itemStyle = (flex?: number, self?: Self, order?: number) => { 18 | return css({ 19 | flexGrow: flex, 20 | alignSelf: self, 21 | order: order 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/flex/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/icons/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]], 3 | "plugins": ["@emotion/babel-plugin"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/icons/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @jdesignlab/react-icons 2 | 3 | ## 0.7.0 4 | 5 | ### Minor Changes 6 | 7 | - allow to get rest properties 8 | 9 | ## 0.6.0 10 | 11 | ### Minor Changes 12 | 13 | - remove rollup dependency, added icons 14 | 15 | ## 0.5.0 16 | 17 | ### Minor Changes 18 | 19 | - remove clean-package 20 | 21 | ## 0.4.0 22 | 23 | ### Minor Changes 24 | 25 | - change publish config 26 | 27 | ## 0.3.0 28 | 29 | ### Minor Changes 30 | 31 | - minor 32 | -------------------------------------------------------------------------------- /packages/icons/README.md: -------------------------------------------------------------------------------- 1 | # icons 2 | -------------------------------------------------------------------------------- /packages/icons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jdesignlab/react-icons", 3 | "version": "0.7.0", 4 | "packageManager": "yarn@3.3.1", 5 | "main": "src/index.ts", 6 | "files": [ 7 | "dist" 8 | ], 9 | "scripts": { 10 | "build": "tsup src --dts --format esm,cjs", 11 | "build:clean": "rimraf dist/" 12 | }, 13 | "devDependencies": { 14 | "@emotion/react": "^11.10.6", 15 | "@types/react": "18.0.27", 16 | "@types/react-dom": "^18.0.10", 17 | "react": "^18.2.0", 18 | "rimraf": "4.1.2", 19 | "tslib": "^2.5.0", 20 | "tsup": "^6.7.0", 21 | "typescript": "^4.9.5" 22 | }, 23 | "peerDependencies": { 24 | "@emtoion/react": "~11" 25 | }, 26 | "publishConfig": { 27 | "access": "public", 28 | "directory": "_release/package", 29 | "main": "./dist/index.js", 30 | "module": "./dist/index.mjs", 31 | "types": "./dist/index.d.ts" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/icons/src/components/Activity.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Activity = (props: React.SVGProps) => { 4 | return ( 5 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Alert.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const Alert = (props: React.SVGProps) => { 3 | return ( 4 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Archive.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Archive = (props: React.SVGProps) => { 4 | return ( 5 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/ArrowBottom.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const ArrowBottom = (props: React.SVGProps) => { 4 | return ( 5 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/ArrowLeft.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowLeft = (props: React.SVGProps) => { 2 | return ( 3 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ArrowRight.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowRight = (props: React.SVGProps) => { 2 | return ( 3 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ArrowTop.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowTop = (props: React.SVGProps) => { 2 | return ( 3 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/BackWards.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const BackWards = (props: React.SVGProps) => { 3 | return ( 4 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Bag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const Bag = (props: React.SVGProps) => { 3 | return ( 4 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Ban.tsx: -------------------------------------------------------------------------------- 1 | export const Ban = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Bell.tsx: -------------------------------------------------------------------------------- 1 | export const Bell = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Book.tsx: -------------------------------------------------------------------------------- 1 | export const Book = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Bookmark.tsx: -------------------------------------------------------------------------------- 1 | export const Bookmark = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Calendar.tsx: -------------------------------------------------------------------------------- 1 | export const Calendar = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Camera.tsx: -------------------------------------------------------------------------------- 1 | export const Camera = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/CaretBottom.tsx: -------------------------------------------------------------------------------- 1 | export const CaretBottom = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/CaretLeft.tsx: -------------------------------------------------------------------------------- 1 | export const CaretLeft = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/CaretRight.tsx: -------------------------------------------------------------------------------- 1 | export const CaretRight = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/CaretTop.tsx: -------------------------------------------------------------------------------- 1 | export const CaretTop = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Cart.tsx: -------------------------------------------------------------------------------- 1 | export const Cart = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/icons/src/components/Checkmark.tsx: -------------------------------------------------------------------------------- 1 | export const Checkmark = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ChevronBottom.tsx: -------------------------------------------------------------------------------- 1 | export const ChevronBottom = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ChevronLeft.tsx: -------------------------------------------------------------------------------- 1 | export const ChevronLeft = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ChevronRight.tsx: -------------------------------------------------------------------------------- 1 | export const ChevronRight = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ChevronTop.tsx: -------------------------------------------------------------------------------- 1 | export const ChevronTop = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Clipboard.tsx: -------------------------------------------------------------------------------- 1 | export const Clipboard = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Clock.tsx: -------------------------------------------------------------------------------- 1 | export const Clock = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Close.tsx: -------------------------------------------------------------------------------- 1 | export const Close = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Code.tsx: -------------------------------------------------------------------------------- 1 | export const Code = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Compose.tsx: -------------------------------------------------------------------------------- 1 | export const Compose = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Creditcard.tsx: -------------------------------------------------------------------------------- 1 | export const Creditcard = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Desktop.tsx: -------------------------------------------------------------------------------- 1 | export const Desktop = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Download.tsx: -------------------------------------------------------------------------------- 1 | export const Download = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Edit.tsx: -------------------------------------------------------------------------------- 1 | export const Edit = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Eject.tsx: -------------------------------------------------------------------------------- 1 | export const Eject = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/EllipsisHorizontal.tsx: -------------------------------------------------------------------------------- 1 | export const EllipsisHorizontal = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/EllipsisVertical.tsx: -------------------------------------------------------------------------------- 1 | export const EllipsisVertical = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/End.tsx: -------------------------------------------------------------------------------- 1 | export const End = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Export.tsx: -------------------------------------------------------------------------------- 1 | export const Export = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/External.tsx: -------------------------------------------------------------------------------- 1 | export const External = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Eye.tsx: -------------------------------------------------------------------------------- 1 | export const Eye = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Feed.tsx: -------------------------------------------------------------------------------- 1 | export const Feed = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/File.tsx: -------------------------------------------------------------------------------- 1 | export const File = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Filter.tsx: -------------------------------------------------------------------------------- 1 | export const Filter = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Flag.tsx: -------------------------------------------------------------------------------- 1 | export const Flag = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Folder.tsx: -------------------------------------------------------------------------------- 1 | export const Folder = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/FolderOpen.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const FolderOpen = (props: React.SVGProps) => { 3 | return ( 4 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Forwards.tsx: -------------------------------------------------------------------------------- 1 | export const Forwards = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Fullscreen.tsx: -------------------------------------------------------------------------------- 1 | export const Fullscreen = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/FullscreenExit.tsx: -------------------------------------------------------------------------------- 1 | export const FullscreenExit = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/Gift.tsx: -------------------------------------------------------------------------------- 1 | export const Gift = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Github.tsx: -------------------------------------------------------------------------------- 1 | export const Github = (props: React.SVGProps) => { 2 | return ( 3 | 4 | 5 | 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/icons/src/components/Heart.tsx: -------------------------------------------------------------------------------- 1 | export const Heart = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Home.tsx: -------------------------------------------------------------------------------- 1 | export const Home = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Import.tsx: -------------------------------------------------------------------------------- 1 | export const Import = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Inbox.tsx: -------------------------------------------------------------------------------- 1 | export const Inbox = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Info.tsx: -------------------------------------------------------------------------------- 1 | export const Info = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Lightning.tsx: -------------------------------------------------------------------------------- 1 | export const Lightning = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Link.tsx: -------------------------------------------------------------------------------- 1 | export const Link = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Location.tsx: -------------------------------------------------------------------------------- 1 | export const Location = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Lock.tsx: -------------------------------------------------------------------------------- 1 | export const Lock = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Mail.tsx: -------------------------------------------------------------------------------- 1 | export const Mail = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Menu.tsx: -------------------------------------------------------------------------------- 1 | export const Menu = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Message.tsx: -------------------------------------------------------------------------------- 1 | export const Message = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Microphone.tsx: -------------------------------------------------------------------------------- 1 | export const Microphone = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/Minus.tsx: -------------------------------------------------------------------------------- 1 | export const Minus = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Mobile.tsx: -------------------------------------------------------------------------------- 1 | export const Mobile = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Moon.tsx: -------------------------------------------------------------------------------- 1 | export const Moon = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Move.tsx: -------------------------------------------------------------------------------- 1 | export const Move = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/icons/src/components/Music.tsx: -------------------------------------------------------------------------------- 1 | export const Music = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/Mute.tsx: -------------------------------------------------------------------------------- 1 | export const Mute = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Options.tsx: -------------------------------------------------------------------------------- 1 | export const Options = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Paperclip.tsx: -------------------------------------------------------------------------------- 1 | export const Paperclip = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Pause.tsx: -------------------------------------------------------------------------------- 1 | export const Pause = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Photo.tsx: -------------------------------------------------------------------------------- 1 | export const Photo = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/Play.tsx: -------------------------------------------------------------------------------- 1 | export const Play = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Plus.tsx: -------------------------------------------------------------------------------- 1 | export const Plus = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Portfolio.tsx: -------------------------------------------------------------------------------- 1 | export const Portfolio = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/icons/src/components/Print.tsx: -------------------------------------------------------------------------------- 1 | export const Print = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/icons/src/components/Reload.tsx: -------------------------------------------------------------------------------- 1 | export const Reload = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Reply.tsx: -------------------------------------------------------------------------------- 1 | export const Reply = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Search.tsx: -------------------------------------------------------------------------------- 1 | export const Search = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Send.tsx: -------------------------------------------------------------------------------- 1 | export const Send = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Settings.tsx: -------------------------------------------------------------------------------- 1 | export const Settings = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/SignIn.tsx: -------------------------------------------------------------------------------- 1 | export const SignIn = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/SignOut.tsx: -------------------------------------------------------------------------------- 1 | export const SignOut = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Star.tsx: -------------------------------------------------------------------------------- 1 | export const Star = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Start.tsx: -------------------------------------------------------------------------------- 1 | export const Start = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Tag.tsx: -------------------------------------------------------------------------------- 1 | export const Tag = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Telephone.tsx: -------------------------------------------------------------------------------- 1 | export const Telephone = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/icons/src/components/Trash.tsx: -------------------------------------------------------------------------------- 1 | export const Trash = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Twitter.tsx: -------------------------------------------------------------------------------- 1 | export const Twitter = (props: React.SVGProps) => { 2 | return ( 3 | 4 | 5 | 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/icons/src/components/Unlock.tsx: -------------------------------------------------------------------------------- 1 | export const Unlock = (props: React.SVGProps) => { 2 | return ( 3 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Upload.tsx: -------------------------------------------------------------------------------- 1 | export const Upload = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/User.tsx: -------------------------------------------------------------------------------- 1 | export const User = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Video.tsx: -------------------------------------------------------------------------------- 1 | export const Video = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/Volume.tsx: -------------------------------------------------------------------------------- 1 | export const Volume = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/Work.tsx: -------------------------------------------------------------------------------- 1 | export const Work = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/icons/src/components/ZoomIn.tsx: -------------------------------------------------------------------------------- 1 | export const ZoomIn = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/ZoomOut.tsx: -------------------------------------------------------------------------------- 1 | export const ZoomOut = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/icons/src/components/ZoomReset.tsx: -------------------------------------------------------------------------------- 1 | export const ZoomReset = (props: React.SVGProps) => { 2 | return ( 3 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/icons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "jsx": "react-jsx" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/input/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/input/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/input/src/components/InputLabel.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import type { InputLabelProps } from '../types'; 3 | import { useContext } from 'react'; 4 | import { inputLabelStyle } from '../styles'; 5 | import { InputContext } from '../context'; 6 | import { createClassVariant } from '@jdesignlab/theme'; 7 | import { combineClassNames } from '@jdesignlab/utils'; 8 | 9 | export const Label = (props: InputLabelProps) => { 10 | const { id } = useContext(InputContext); 11 | const { children, className, ...otherProps } = props; 12 | 13 | return ( 14 | 22 | ); 23 | }; 24 | 25 | Label.displayName = 'TextInput.Label'; 26 | -------------------------------------------------------------------------------- /packages/input/src/components/InputMessage.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import type { InputMessageProps } from '../types'; 3 | import { inputMessageStyle } from '../styles'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import { combineClassNames } from '@jdesignlab/utils'; 6 | 7 | export const Message = (props: InputMessageProps) => { 8 | const { className, consistent, ...otherProps } = props; 9 | 10 | return ( 11 |
16 | {props.children} 17 |
18 | ); 19 | }; 20 | 21 | Message.displayName = 'TextInput.Message'; 22 | -------------------------------------------------------------------------------- /packages/input/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const VISIBLE_ICON_CLASSNAME = 'input_visible_icon'; 2 | export const CLEARABLE_ICON_CLASSNAME = 'input_clearable_icon'; 3 | -------------------------------------------------------------------------------- /packages/input/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const InputContext = createContext({ 4 | id: '', 5 | clearable: false 6 | }); 7 | -------------------------------------------------------------------------------- /packages/input/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/TextInput'; 2 | -------------------------------------------------------------------------------- /packages/input/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ThemePreset } from '@jdesignlab/j-provider'; 2 | import type { ColorToken } from '@jdesignlab/theme'; 3 | 4 | export type InputSize = 'sm' | 'md' | 'lg'; 5 | 6 | export interface InputProps extends Omit, 'size' | 'type'> { 7 | children?: React.ReactElement | React.ReactElement[]; 8 | type?: 'text' | 'password'; 9 | className?: string; 10 | size?: InputSize; 11 | clearable?: boolean; 12 | width?: number; 13 | maxLength?: number; 14 | icon?: JSX.Element; 15 | } 16 | 17 | export interface InputLabelProps { 18 | children?: string; 19 | className?: string; 20 | } 21 | 22 | export interface InputMessageProps { 23 | children?: string; 24 | className?: string; 25 | consistent?: boolean; 26 | } 27 | 28 | export interface InputStyleProps { 29 | themePreset: ThemePreset; 30 | size: InputSize; 31 | hasLabel: boolean; 32 | hasIcon: boolean; 33 | full?: boolean; 34 | width?: number; 35 | clearable?: boolean; 36 | type?: 'text' | 'password'; 37 | color?: ColorToken; 38 | } 39 | -------------------------------------------------------------------------------- /packages/input/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/j-provider/README.md: -------------------------------------------------------------------------------- 1 | # j-provider 2 | -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Black-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Black-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Bold-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Bold-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Light-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Light-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Medium-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Medium-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Regular-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Regular-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/public/fonts/NotoSansKR-Thin-Alphabetic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesignSystemLab/design-system/b47e12d874498c1c44be23f41eda33f956311c16/packages/j-provider/public/fonts/NotoSansKR-Thin-Alphabetic.woff2 -------------------------------------------------------------------------------- /packages/j-provider/src/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { Global } from '@emotion/react'; 3 | import { ThemeContext } from './context'; 4 | import { preset } from './preset'; 5 | import reset from './styles/reset'; 6 | 7 | export const ThemeProvider = (props: { children: React.ReactNode; presetConfig?: any }) => { 8 | return ( 9 | 10 | 11 | {props.children} 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/j-provider/src/context.ts: -------------------------------------------------------------------------------- 1 | import { preset } from './preset'; 2 | import { createContext } from 'react'; 3 | import type { Preset } from './types'; 4 | 5 | export const themePreset = preset[preset.theme]; 6 | export const ThemeContext = createContext(themePreset); 7 | -------------------------------------------------------------------------------- /packages/j-provider/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './preset'; 2 | export * from './context'; 3 | export * from './ThemeProvider'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /packages/j-provider/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { HEX } from '@jdesignlab/theme'; 2 | export interface ThemePreset { 3 | color: { 4 | background: HEX; 5 | fontColor: HEX; 6 | primary: HEX; 7 | secondary: HEX; 8 | success: HEX; 9 | info: HEX; 10 | warning: HEX; 11 | error: HEX; 12 | disabled: HEX; 13 | font: HEX; 14 | }; 15 | effect: { 16 | disabledOpacity: string | number; 17 | hoverGhostOpacity: string | number; 18 | hoverSolidOpacity: string | number; 19 | focusOpacity: string | number; 20 | selectedOpacity: string | number; 21 | activatedOpacity: string | number; 22 | pressedOpacity: string | number; 23 | draggedOpacity: string | number; 24 | }; 25 | } 26 | export interface Preset { 27 | theme: 'light' | 'dark'; 28 | light: ThemePreset; 29 | dark: ThemePreset; 30 | } 31 | -------------------------------------------------------------------------------- /packages/j-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/modal/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/modal/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/modal/src/components/ModalTrigger.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { Trigger } from '@jdesignlab/react-utils'; 3 | import { useContext } from 'react'; 4 | import { ModalContext } from '../context'; 5 | import { ModalTriggerProps } from '../types'; 6 | 7 | export const ModalTrigger = (props: ModalTriggerProps) => { 8 | const { children } = props; 9 | const { id, onOpen } = useContext(ModalContext); 10 | 11 | return ( 12 | 13 | {children} 14 | 15 | ); 16 | }; 17 | 18 | ModalTrigger.displayName = 'Modal.Trigger'; 19 | -------------------------------------------------------------------------------- /packages/modal/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | interface ModalContext { 3 | id: string; 4 | isOpen: boolean; 5 | onOpen(): void; 6 | onClose(): void; 7 | hasCloseIcon: boolean; 8 | disableOverlayClose: boolean; 9 | } 10 | 11 | export const ModalContext = createContext({ 12 | id: '', 13 | isOpen: false, 14 | onOpen: () => {}, 15 | onClose: () => {}, 16 | hasCloseIcon: true, 17 | disableOverlayClose: false 18 | }); 19 | -------------------------------------------------------------------------------- /packages/modal/src/hooks/useToggleLayer.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from 'react'; 2 | 3 | export const useToggleLayer = ( 4 | openProp: boolean | undefined, 5 | onOpenProp: (() => void) | undefined, 6 | onCloseProp: (() => void) | undefined 7 | ) => { 8 | const [isOpen, setIsOpen] = useState(!!openProp); 9 | const isControlled = openProp !== undefined; 10 | 11 | useEffect(() => { 12 | setIsOpen(!!openProp); 13 | }, [openProp]); 14 | 15 | const onToggle = useCallback(() => { 16 | setIsOpen(prev => !prev); 17 | if (isOpen) onCloseProp?.(); 18 | else onOpenProp?.(); 19 | }, [isOpen, onOpenProp, onCloseProp]); 20 | 21 | const onOpen = () => { 22 | isControlled ? onOpenProp?.() : onToggle(); 23 | }; 24 | 25 | const onClose = () => { 26 | isControlled ? onCloseProp?.() : onToggle(); 27 | }; 28 | 29 | return { isOpen, onOpen, onClose }; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/modal/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Modal'; 2 | -------------------------------------------------------------------------------- /packages/modal/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import { SEMATIC_COLOR_HOVER, SHADOW_MODAL, Z_INDEX_MODAL } from '@jdesignlab/theme'; 3 | 4 | export const portal = (width: number, height: number) => { 5 | return css({ 6 | zIndex: Z_INDEX_MODAL, 7 | position: 'fixed', 8 | top: '50%', 9 | left: '50%', 10 | transform: 'translate(-50%, -50%)', 11 | display: 'block', 12 | background: 'white', 13 | width: `${width}px`, 14 | height: `${height}px`, 15 | borderRadius: '6px', 16 | padding: '12px', 17 | boxShadow: SHADOW_MODAL 18 | }); 19 | }; 20 | 21 | export const closeIconWrapper = css({ 22 | position: 'absolute', 23 | right: '6px', 24 | top: '6px', 25 | width: '24px', 26 | height: '24px', 27 | display: 'flex', 28 | justifyContent: 'center', 29 | alignItems: 'center', 30 | padding: '8px', 31 | borderRadius: '100%', 32 | cursor: 'pointer', 33 | '&:hover': { 34 | background: SEMATIC_COLOR_HOVER 35 | } 36 | }); 37 | 38 | export const closeIcon = css({ 39 | padding: 0 40 | }); 41 | -------------------------------------------------------------------------------- /packages/modal/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ModalProps { 2 | children?: React.ReactNode; 3 | hasCloseIcon?: boolean; 4 | open?: boolean; 5 | onClose?(): void; 6 | onOpen?(): void; 7 | disableOverlayClose?: boolean; 8 | } 9 | 10 | export interface ModalTriggerProps { 11 | children: React.ReactNode; 12 | } 13 | 14 | export interface ModalPortalProps { 15 | children: React.ReactNode; 16 | width?: number; 17 | height?: number; 18 | } 19 | -------------------------------------------------------------------------------- /packages/modal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/popover/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | snapshotSerializers: ['@emotion/jest/serializer'], 8 | transform: { 9 | '^.+\\.[jt]sx?$': 'ts-jest', 10 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 11 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /packages/popover/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverBody.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | import { POPOVER_BORDER_COLOR } from '../constants'; 5 | 6 | export const PopoverBody = (props: { children: React.ReactNode }) => { 7 | return ( 8 |
9 | {props.children} 10 |
11 | ); 12 | }; 13 | 14 | PopoverBody.displayName = 'PopoverBody'; 15 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverFooter.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | 5 | export const popoverFooter = (props: { children: React.ReactNode }) => { 6 | return ( 7 |
8 | {props.children} 9 |
10 | ); 11 | }; 12 | 13 | popoverFooter.displayName = 'PopoverFooter'; 14 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverHeader.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | import { POPOVER_BORDER_COLOR } from '../constants'; 5 | 6 | export const PopoverHeader = (props: { children?: React.ReactNode }) => { 7 | return ( 8 |
9 | {props.children} 10 |
11 | ); 12 | }; 13 | 14 | PopoverHeader.displayName = 'PopoverHeader'; 15 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverOverlay.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import { useContext } from 'react'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import { PopoverContext } from '../context'; 6 | import usePopoverControl from '../hooks/usePopoverControl'; 7 | 8 | export const PopoverOverlay = () => { 9 | const context = useContext(PopoverContext); 10 | const { onClosePopover } = usePopoverControl(context); 11 | 12 | return ( 13 |
19 | ); 20 | }; 21 | 22 | PopoverOverlay.displayName = 'PopoverOverlay'; 23 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverProvider.tsx: -------------------------------------------------------------------------------- 1 | import { RefObject, useState } from 'react'; 2 | import { PopoverContext, defaultContextValues } from '../context'; 3 | 4 | export const PopoverProvider = ({ ...props }) => { 5 | const [triggerRef, setTriggerRef] = useState | null>(null); 6 | const { popoverProps } = props; 7 | const [isOpen, setOpen] = useState(popoverProps.open); 8 | const defaultPopoverProps = defaultContextValues.popoverProps; 9 | const { 10 | open = defaultPopoverProps.open, 11 | placement = defaultPopoverProps.placement, 12 | arrow = defaultPopoverProps.arrow 13 | } = popoverProps; 14 | 15 | return ( 16 | 25 | {props.children} 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/popover/src/components/PopoverTrigger.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import React, { useContext, Children, useEffect, useRef } from 'react'; 4 | import { createClassVariant } from '@jdesignlab/theme'; 5 | import usePopoverControl from '../hooks/usePopoverControl'; 6 | import { PopoverContext } from '../context'; 7 | 8 | export const PopoverTrigger = (props: { children: React.ReactNode }) => { 9 | const context = useContext(PopoverContext); 10 | const children = Children.only(props.children); 11 | const triggerRef = useRef(null); 12 | const { onTogglePopover } = usePopoverControl(context); 13 | 14 | useEffect(() => { 15 | if (triggerRef.current) { 16 | context.setTriggerRef(triggerRef); 17 | } 18 | }, [triggerRef]); 19 | 20 | return ( 21 |
29 | {children} 30 |
31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/popover/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { getColorByToken } from '@jdesignlab/theme'; 2 | import type { PopoverProps } from './types'; 3 | 4 | type PopoverOption = Required>; 5 | 6 | const DEFAULT_OPTIONS: PopoverOption = { 7 | arrow: true, 8 | open: false, 9 | placement: 'bottom' 10 | }; 11 | 12 | const POPOVER_BACKGROUND = getColorByToken('shades-white'); 13 | const POPOVER_BORDER_COLOR = getColorByToken('grey-lighten1'); 14 | 15 | export { DEFAULT_OPTIONS, POPOVER_BACKGROUND, POPOVER_BORDER_COLOR }; 16 | -------------------------------------------------------------------------------- /packages/popover/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, RefObject, useState } from 'react'; 2 | import { DEFAULT_OPTIONS } from './constants'; 3 | import type { ReturnContext } from './types'; 4 | 5 | export const defaultContextValues: ReturnContext = { 6 | isOpen: false, 7 | setOpen: () => {}, 8 | triggerRef: null, 9 | setTriggerRef: () => {}, 10 | popoverProps: { 11 | onClose: () => {}, 12 | onOpen: () => {}, 13 | arrow: DEFAULT_OPTIONS.arrow, 14 | open: DEFAULT_OPTIONS.open, 15 | placement: DEFAULT_OPTIONS.placement 16 | } 17 | }; 18 | 19 | export const PopoverContext = createContext(defaultContextValues); 20 | -------------------------------------------------------------------------------- /packages/popover/src/hooks/useInitialRender.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | const useInitialRender = () => { 4 | const isInitial = useRef(true); 5 | 6 | if (isInitial.current) { 7 | isInitial.current = false; 8 | return true; 9 | } 10 | 11 | return isInitial.current; 12 | }; 13 | 14 | export default useInitialRender; 15 | -------------------------------------------------------------------------------- /packages/popover/src/hooks/useOpenClosePopover.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import type { ReturnContext } from '../types'; 3 | 4 | const useOpenClosePopover = (context: ReturnContext, init: boolean) => { 5 | const { popoverProps, isOpen, setOpen } = context; 6 | const { onOpen, onClose, open } = popoverProps; 7 | 8 | useEffect(() => { 9 | setOpen(open); 10 | }, [open]); 11 | 12 | useEffect(() => { 13 | if (isOpen && onOpen) { 14 | onOpen(); 15 | return; 16 | } 17 | if (!init) { 18 | if (!isOpen && onClose) { 19 | onClose(); 20 | } 21 | 22 | if (isOpen && onOpen) { 23 | onOpen(); 24 | } 25 | } 26 | }, [isOpen]); 27 | }; 28 | 29 | export default useOpenClosePopover; 30 | -------------------------------------------------------------------------------- /packages/popover/src/hooks/usePopoverControl.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from 'react'; 2 | import type { ReturnContext } from '../types'; 3 | 4 | const usePopoverControl = (context: ReturnContext) => { 5 | const { setOpen } = context; 6 | 7 | const onTogglePopover = useCallback(() => { 8 | setOpen(prev => !prev); 9 | }, [setOpen]); 10 | 11 | const onClosePopover = useCallback(() => { 12 | setOpen(false); 13 | }, [setOpen]); 14 | 15 | const onOpenPopover = useCallback(() => { 16 | setOpen(true); 17 | }, [setOpen]); 18 | 19 | return { onTogglePopover, onClosePopover, onOpenPopover }; 20 | }; 21 | 22 | export default usePopoverControl; 23 | -------------------------------------------------------------------------------- /packages/popover/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Popover'; 2 | -------------------------------------------------------------------------------- /packages/popover/src/types/base.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedStyles } from '@emotion/react'; 2 | 3 | export type StyleProps = Record; 4 | export type Placement = 'top' | 'right' | 'bottom' | 'left'; 5 | export type PopoverTrigger = Record<'width' | 'height', number>; 6 | -------------------------------------------------------------------------------- /packages/popover/src/types/context.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, RefObject, SetStateAction } from 'react'; 2 | import type { PopoverProps } from './props'; 3 | 4 | export interface TriggerRef { 5 | triggerRef: RefObject | null; 6 | setTriggerRef: Dispatch>; 7 | } 8 | 9 | export interface ReturnContext extends TriggerRef { 10 | isOpen: boolean; 11 | setOpen: Dispatch>; 12 | popoverProps: Required>; 13 | } 14 | -------------------------------------------------------------------------------- /packages/popover/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base'; 2 | export * from './context'; 3 | export * from './props'; 4 | -------------------------------------------------------------------------------- /packages/popover/src/types/props.ts: -------------------------------------------------------------------------------- 1 | import type { Placement } from './base'; 2 | 3 | export interface PopoverHandler { 4 | onOpen?: () => void; 5 | onClose?: () => void; 6 | } 7 | 8 | export interface PopoverProps extends PopoverHandler { 9 | children?: React.ReactNode; 10 | placement?: Placement; 11 | arrow?: boolean; 12 | open?: boolean; 13 | } 14 | -------------------------------------------------------------------------------- /packages/popover/src/utils/calculateSize.ts: -------------------------------------------------------------------------------- 1 | import type { RefObject } from 'react'; 2 | 3 | const calculateSize = (ref: RefObject | null) => { 4 | let height = 0; 5 | let width = 0; 6 | if (ref?.current) { 7 | width = parseFloat(getComputedStyle(ref.current).width); 8 | height = parseFloat(getComputedStyle(ref.current).height); 9 | } 10 | 11 | return { 12 | height: Math.round(height), 13 | width: Math.round(width) 14 | }; 15 | }; 16 | 17 | export default calculateSize; 18 | -------------------------------------------------------------------------------- /packages/popover/src/utils/handleEscapeKey.ts: -------------------------------------------------------------------------------- 1 | import type { KeyboardEvent } from 'react'; 2 | 3 | const handleEscapeKey = (event: React.KeyboardEvent, onClose: () => void) => { 4 | event.stopPropagation(); 5 | if (event.key === 'Escape') { 6 | onClose(); 7 | return; 8 | } 9 | }; 10 | export default handleEscapeKey; 11 | -------------------------------------------------------------------------------- /packages/popover/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/radio/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/radio/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/radio/src/components/RadioGroup.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from 'react'; 2 | import { createClassVariant } from '@jdesignlab/theme'; 3 | import { RadioProvider } from './RadioProvider'; 4 | import useRadioGroup from '../hooks/useRadioGroup'; 5 | import type { RadioGroupProps } from '../types'; 6 | 7 | const RadioGroup = Object.assign( 8 | forwardRef((props: RadioGroupProps, ref) => { 9 | const { children, defaultValue = null, ...restProps } = props; 10 | const radioGroupRef = useRadioGroup(defaultValue, ref); 11 | 12 | return ( 13 | 14 |
15 | {children} 16 |
17 |
18 | ); 19 | }) 20 | ); 21 | 22 | RadioGroup.displayName = 'RadioGroup'; 23 | export default RadioGroup; 24 | -------------------------------------------------------------------------------- /packages/radio/src/components/RadioLabel.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import * as Style from '../styles'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | import { DEFAULT_FONT_COLOR } from '../constants'; 5 | import type { RadioLabelProps } from '../types'; 6 | 7 | const RadioLabel = (props: RadioLabelProps) => { 8 | const { id, children, size } = props; 9 | const labelStyle = Style.createLabel(size, DEFAULT_FONT_COLOR); 10 | return ( 11 | 14 | ); 15 | }; 16 | 17 | RadioLabel.displayName = 'RadioLabel'; 18 | export default RadioLabel; 19 | -------------------------------------------------------------------------------- /packages/radio/src/components/RadioProvider.tsx: -------------------------------------------------------------------------------- 1 | import { RadioContext } from '../context'; 2 | import { useId, useState } from 'react'; 3 | import { RADIO_NAME_PREFIX } from '../constants'; 4 | 5 | export const RadioProvider = ({ ...props }) => { 6 | const { children, defaultValue = null, rootProps = null } = props; 7 | const defaultName = rootProps && rootProps.name ? rootProps.name : `${RADIO_NAME_PREFIX}_${useId()}`; 8 | const [value, setValue] = useState(''); 9 | 10 | return ( 11 | 20 | {children} 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/radio/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { themePreset } from '@jdesignlab/j-provider'; 2 | import type { HEX } from '@jdesignlab/theme'; 3 | 4 | const RADIO_ID_PREFIX: string = 'j-radio'; 5 | const RADIO_NAME_PREFIX: string = 'j-radio-name'; 6 | const DEFAULT_COLOR: HEX = themePreset.color.primary; 7 | const DEFAULT_FONT_COLOR: HEX = themePreset.color.fontColor; 8 | const DEFAULT_DISABLED_COLOR: HEX = themePreset.color.disabled; 9 | 10 | export { RADIO_ID_PREFIX, RADIO_NAME_PREFIX, DEFAULT_COLOR, DEFAULT_DISABLED_COLOR, DEFAULT_FONT_COLOR }; 11 | -------------------------------------------------------------------------------- /packages/radio/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { ReturnContext } from './types'; 3 | 4 | export const RadioContext = createContext(null); 5 | -------------------------------------------------------------------------------- /packages/radio/src/hooks/useRadioGroup.ts: -------------------------------------------------------------------------------- 1 | import { ForwardedRef, useCallback, useEffect, useRef } from 'react'; 2 | 3 | const useRadioGroup = (defalutValue: string | null, externalRef?: ForwardedRef) => { 4 | const ref = useRef(null); 5 | 6 | const setDefaultValueCheck = useCallback( 7 | (el: HTMLInputElement, targetValue: string | null, externalRef?: ForwardedRef) => { 8 | const isUnavailable = el.hasAttribute('readonly') || el.hasAttribute('disabled'); 9 | if (targetValue && targetValue === el.value && !isUnavailable) { 10 | el.checked = true; 11 | } 12 | if (externalRef && typeof externalRef === 'function') { 13 | externalRef(el); 14 | } 15 | }, 16 | [ref] 17 | ); 18 | 19 | useEffect(() => { 20 | if (ref.current) { 21 | const radioElements = ref.current.querySelectorAll('input[type="radio"]') as NodeListOf; 22 | radioElements.forEach(el => { 23 | setDefaultValueCheck(el, defalutValue, externalRef); 24 | }); 25 | } 26 | }, [ref]); 27 | 28 | return ref; 29 | }; 30 | 31 | export default useRadioGroup; 32 | -------------------------------------------------------------------------------- /packages/radio/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Radio'; 2 | -------------------------------------------------------------------------------- /packages/radio/src/types/base.ts: -------------------------------------------------------------------------------- 1 | export type RadioSize = 'sm' | 'md' | 'lg'; 2 | export type RadioValueType = string | number | boolean; 3 | -------------------------------------------------------------------------------- /packages/radio/src/types/context.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from 'react'; 2 | import type { EventType } from '@jdesignlab/utils'; 3 | import type { RadioValueType } from './base'; 4 | 5 | export type RadioAttributes = { [key: string]: string | ((event: EventType) => void) }; 6 | export interface ReturnContext { 7 | defaultValue?: string; 8 | name: string; 9 | rootProps: RadioAttributes | null; 10 | setValue: Dispatch> | null; 11 | value: RadioValueType | null; 12 | } 13 | -------------------------------------------------------------------------------- /packages/radio/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base'; 2 | export * from './context'; 3 | export * from './props'; 4 | -------------------------------------------------------------------------------- /packages/radio/src/types/props.ts: -------------------------------------------------------------------------------- 1 | import { RadioSize, RadioValueType } from './base'; 2 | import type { ColorToken } from '@jdesignlab/theme'; 3 | 4 | export interface RadioLabelProps { 5 | id: string; 6 | size: RadioSize; 7 | children: React.ReactNode; 8 | } 9 | 10 | export interface RadioGroupProps extends React.HTMLAttributes { 11 | defaultValue?: string; 12 | } 13 | 14 | export interface RadioProps extends React.HTMLAttributes { 15 | children?: React.ReactNode; 16 | color?: ColorToken; 17 | disabled?: boolean; 18 | readonly?: boolean; 19 | size?: RadioSize; 20 | name?: string; 21 | value?: RadioValueType; 22 | } 23 | -------------------------------------------------------------------------------- /packages/radio/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/react-utils/.babelrc.json: -------------------------------------------------------------------------------- 1 | // { 2 | // "presets": ["@babel/env", ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]], 3 | // "plugins": ["@emotion/babel-plugin"] 4 | // } 5 | -------------------------------------------------------------------------------- /packages/react-utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @jdesignlab/react-utils 2 | 3 | ## 0.9.0 4 | 5 | ### Minor Changes 6 | 7 | - Add useOutsideClick hook for external clicks 8 | 9 | ## 0.8.0 10 | 11 | ### Minor Changes 12 | 13 | - Remove rollup packages and configure files 14 | 15 | ## 0.7.0 16 | 17 | ### Minor Changes 18 | 19 | - supply react hook form 20 | 21 | ## 0.6.0 22 | 23 | ### Minor Changes 24 | 25 | - add number type from getComponentText 26 | 27 | ## 0.5.0 28 | 29 | ### Minor Changes 30 | 31 | - remove clean-package 32 | 33 | ### Patch Changes 34 | 35 | - Updated dependencies 36 | - @jdesignlab/utils@0.5.0 37 | 38 | ## 0.4.0 39 | 40 | ### Minor Changes 41 | 42 | - change publish config 43 | 44 | ### Patch Changes 45 | 46 | - Updated dependencies 47 | - @jdesignlab/utils@0.4.0 48 | 49 | ## 0.3.0 50 | 51 | ### Minor Changes 52 | 53 | - minor 54 | 55 | ### Patch Changes 56 | 57 | - Updated dependencies 58 | - @jdesignlab/utils@0.3.0 59 | -------------------------------------------------------------------------------- /packages/react-utils/README.md: -------------------------------------------------------------------------------- 1 | # react-utils 2 | -------------------------------------------------------------------------------- /packages/react-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jdesignlab/react-utils", 3 | "packageManager": "yarn@3.3.1", 4 | "version": "0.9.0", 5 | "main": "src/index.ts", 6 | "sideEffects": false, 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "build": "tsup src --dts --format esm,cjs", 12 | "build:clean": "rimraf dist/" 13 | }, 14 | "devDependencies": { 15 | "@emotion/babel-plugin": "^11.10.5", 16 | "@emotion/babel-preset-css-prop": "^11.10.0", 17 | "@emotion/react": "^11.10.5", 18 | "@types/react": "18.0.27", 19 | "@types/react-dom": "^18.2.7", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "rimraf": "^4.1.2", 23 | "tslib": "^2.5.0", 24 | "tsup": "^6.7.0", 25 | "typescript": "^4.9.4" 26 | }, 27 | "peerDependencies": { 28 | "@emotion/react": "~11", 29 | "react": "~18" 30 | }, 31 | "dependencies": { 32 | "@jdesignlab/theme": "*", 33 | "@jdesignlab/utils": "*" 34 | }, 35 | "publishConfig": { 36 | "access": "public", 37 | "directory": "_release/package", 38 | "main": "./dist/index.js", 39 | "module": "./dist/index.mjs", 40 | "types": "./dist/index.d.ts" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/react-utils/src/components/Overlay.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import { ClassNameVariant, SEMATIC_COLOR_OVERLAY, Z_INDEX_OVERLAY } from '@jdesignlab/theme'; 4 | 5 | interface OverlayProps { 6 | onClick?(): void; 7 | className?: ClassNameVariant; 8 | } 9 | 10 | const overlayStyle = css({ 11 | zIndex: Z_INDEX_OVERLAY, 12 | position: 'fixed', 13 | top: 0, 14 | left: 0, 15 | width: '100vw', 16 | height: '100vh', 17 | background: SEMATIC_COLOR_OVERLAY 18 | }); 19 | 20 | export const Overlay = (props: OverlayProps) => { 21 | const { onClick, ...rest } = props; 22 | return
; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react-utils/src/components/Portal.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { ClassNameVariant } from '@jdesignlab/theme'; 3 | import { ReactNode } from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | 6 | interface PortalProps { 7 | children: ReactNode; 8 | className?: ClassNameVariant; 9 | } 10 | const PORTAL_CONTAINER = document?.body; 11 | export const Portal = (props: PortalProps) => { 12 | const { children } = props; 13 | return ReactDOM.createPortal(<>{children}, PORTAL_CONTAINER); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-utils/src/components/Trigger.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { css } from '@emotion/react'; 3 | import { ReactNode } from 'react'; 4 | 5 | interface TriggerProps { 6 | children: ReactNode; 7 | onClick(): void; 8 | id?: string; 9 | } 10 | 11 | const triggerStyle = css({ 12 | display: 'inline-block', 13 | cursor: 'pointer' 14 | }); 15 | 16 | export const Trigger = (props: TriggerProps) => { 17 | const { children, onClick, id, ...rest } = props; 18 | const ariaControl = id ? { 'aria-control': id } : {}; 19 | 20 | return ( 21 |
22 | {children} 23 |
24 | ); 25 | }; 26 | 27 | Trigger.displayName = 'Trigger'; 28 | -------------------------------------------------------------------------------- /packages/react-utils/src/hooks/useInitialRender.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | export const useInitialRender = () => { 4 | const isInitial = useRef(true); 5 | 6 | if (isInitial.current) { 7 | isInitial.current = false; 8 | return true; 9 | } 10 | 11 | return isInitial.current; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react-utils/src/hooks/useOutsideClick.ts: -------------------------------------------------------------------------------- 1 | import { RefObject, useEffect } from 'react'; 2 | 3 | type Props = { 4 | ref: RefObject; 5 | handler: (event: MouseEvent) => void; 6 | }; 7 | 8 | export const useOutsideClick = ({ ref, handler }: Props) => { 9 | useEffect(() => { 10 | const listener = (event: MouseEvent) => { 11 | if (!ref.current || ref.current.contains(event.target as Node)) { 12 | return; 13 | } 14 | handler(event); 15 | }; 16 | 17 | document.addEventListener('mousedown', listener); 18 | return () => { 19 | document.removeEventListener('mousedown', listener); 20 | }; 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | /** components */ 2 | export * from './components/Overlay'; 3 | export * from './components/Portal'; 4 | export * from './components/Trigger'; 5 | 6 | /** mixins */ 7 | export * from './mixins/transition/useRipple'; 8 | export * from './mixins/keyboard/spaceKeyToggleHandler'; 9 | export * from './mixins/keyboard/arrowKeyNavigationHandler'; 10 | export * from './mixins/styles/usePlacementStyle'; 11 | 12 | /** utils */ 13 | export * from './utils/filterComponent'; 14 | export * from './utils/getComponentText'; 15 | export * from './utils/hasComponent'; 16 | export * from './utils/getChildrenValidValues'; 17 | 18 | /** types */ 19 | export * from './types'; 20 | export * from './mixins/styles/usePlacementStyle'; 21 | 22 | /** hooks */ 23 | export * from './hooks/useInitialRender'; 24 | export * from './hooks/useOutsideClick'; 25 | -------------------------------------------------------------------------------- /packages/react-utils/src/mixins/keyboard/spaceKeyToggleHandler.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from 'react'; 2 | 3 | export const spaceKeyToggleHandler = (props: { 4 | event: React.KeyboardEvent; 5 | setState?: Dispatch>; 6 | action?: () => void; 7 | }) => { 8 | const { event, setState, action } = props; 9 | if (event.key === 'Space' || event.key === ' ') { 10 | event.preventDefault(); 11 | action && action(); 12 | setState && setState((prev: boolean) => !prev); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-utils/src/types.ts: -------------------------------------------------------------------------------- 1 | export type Ripple = { 2 | x: number; 3 | y: number; 4 | size: number; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react-utils/src/utils/filterComponent.ts: -------------------------------------------------------------------------------- 1 | import { Children, isValidElement } from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export const filterComponent = ( 5 | children: ReactNode | ReactNode[], 6 | compoenent: (props: any) => ReactNode, 7 | isEqual: boolean 8 | ) => { 9 | return Children.toArray(children).filter(child => { 10 | if (isValidElement(child)) { 11 | return isEqual ? child.type === compoenent : child.type !== compoenent; 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-utils/src/utils/getChildrenValidValues.ts: -------------------------------------------------------------------------------- 1 | export const getChildrenValidValues = (children: React.ReactElement | React.ReactElement[], componentName: string) => { 2 | const values = [] as any[]; 3 | if (children) { 4 | if (Array.isArray(children)) { 5 | children.forEach((child: React.ReactElement) => { 6 | const tagName = typeof child.type === 'function' ? child.type.name : child.type; 7 | if (tagName === componentName && !child.props.disabled) { 8 | values.push(child.props.value); 9 | } 10 | }); 11 | } else { 12 | const tagName = typeof children.type === 'function' ? children.type.name : children.type; 13 | if (tagName === componentName && !children.props.disabled) { 14 | values.push(children.props.value); 15 | } 16 | } 17 | } 18 | return values; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/react-utils/src/utils/getComponentText.ts: -------------------------------------------------------------------------------- 1 | import { Children, isValidElement } from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export const getComponentText = (children: ReactNode) => { 5 | let childText = ''; 6 | if (children) { 7 | Children.forEach(children, child => { 8 | if (isValidElement(child)) { 9 | return typeof child.props.children === 'string' 10 | ? (childText += child.props.children) 11 | : (childText += getComponentText(child.props.children)); 12 | } else if (typeof child === 'string') { 13 | childText += child; 14 | } 15 | }); 16 | } 17 | return childText; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/react-utils/src/utils/hasComponent.ts: -------------------------------------------------------------------------------- 1 | export const hasComponent = (children: React.ReactElement | React.ReactElement[], componentName: string) => { 2 | let having = false; 3 | if (children) { 4 | if (Array.isArray(children)) { 5 | children.forEach((child: React.ReactElement) => { 6 | const tagName = typeof child.type === 'function' ? child.type.name : child.type; 7 | if (tagName === componentName) having = true; 8 | }); 9 | } else { 10 | const tagName = typeof children.type === 'function' ? children.type.name : children.type; 11 | if (tagName === componentName) having = true; 12 | } 13 | } 14 | return having; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/react/README.md: -------------------------------------------------------------------------------- 1 | # react 2 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@jdesignlab/box'; 2 | export * from '@jdesignlab/button'; 3 | export * from '@jdesignlab/card'; 4 | export * from '@jdesignlab/checkbox'; 5 | export * from '@jdesignlab/drawer'; 6 | export * from '@jdesignlab/dropdown'; 7 | export * from '@jdesignlab/flex'; 8 | export * from '@jdesignlab/input'; 9 | export * from '@jdesignlab/j-provider'; 10 | export * from '@jdesignlab/modal'; 11 | export * from '@jdesignlab/popover'; 12 | export * from '@jdesignlab/radio'; 13 | export * from '@jdesignlab/react-utils'; 14 | export * from '@jdesignlab/select'; 15 | export * from '@jdesignlab/stack'; 16 | export * from '@jdesignlab/tabs'; 17 | export * from '@jdesignlab/textarea'; 18 | export * from '@jdesignlab/theme'; 19 | export * from '@jdesignlab/tooltip'; 20 | export * from '@jdesignlab/typography'; 21 | export * from '@jdesignlab/j-provider'; 22 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src/**/*"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "importHelpers": true, 7 | "jsx": "react-jsx", 8 | "jsxImportSource": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/select/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/select/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/select/src/components/SearchNotfound.tsx: -------------------------------------------------------------------------------- 1 | import { createSelectStyle } from '../styles/createSelectStyle'; 2 | 3 | /** @jsxImportSource @emotion/react */ 4 | export const SelectNotfound = () => { 5 | const { notfound } = createSelectStyle(); 6 | return ( 7 |
  • 8 | 검색 결과가 없습니다. 9 |
  • 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/select/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { ColorToken } from '@jdesignlab/theme'; 2 | 3 | const SELECT_ID_PREFIX: string = 'jdesignlab-select-list'; 4 | const FONT_COLOR: ColorToken = 'font'; 5 | const BORDER_COLOR: ColorToken = 'border'; 6 | const DISABLED_COLOR: ColorToken = 'disabled'; 7 | const FOCUS_COLOR: ColorToken = 'primary-500'; 8 | const BORDER_RADIUS: number = 4; 9 | 10 | export { FONT_COLOR, BORDER_COLOR, BORDER_RADIUS, DISABLED_COLOR, FOCUS_COLOR, SELECT_ID_PREFIX }; 11 | -------------------------------------------------------------------------------- /packages/select/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Select'; 2 | -------------------------------------------------------------------------------- /packages/select/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/stack/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/stack/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/stack/src/components/Stack.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { jsx } from '@emotion/react'; 3 | import { createClassVariant } from '@jdesignlab/theme'; 4 | import { MAX_WIDTH_MEDIA_QUERY } from '../constants'; 5 | import { createStackStyle } from '../styles/createStackStyle'; 6 | import { createResponsiveStyle } from '../styles/createResponsiveStyle'; 7 | import { setMarginStyle } from '../styles/setMarginStyle'; 8 | import type { StackProps } from '../types'; 9 | 10 | export const Stack = (stackProps: StackProps) => { 11 | const { as = 'div', children, ...styleProps } = stackProps; 12 | const baseStyle = createStackStyle(styleProps); 13 | const responsiveStyle = createResponsiveStyle(styleProps.responsive, MAX_WIDTH_MEDIA_QUERY); 14 | const cloneElements = setMarginStyle(styleProps, MAX_WIDTH_MEDIA_QUERY, children); 15 | 16 | return jsx( 17 | as, 18 | { css: [baseStyle, responsiveStyle], className: `${createClassVariant('stack', 'ul')}`, role: 'list' }, 19 | cloneElements 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/stack/src/constants.ts: -------------------------------------------------------------------------------- 1 | const MAX_WIDTH_MEDIA_QUERY = '@media (max-width: 480px)'; 2 | 3 | export { MAX_WIDTH_MEDIA_QUERY }; 4 | -------------------------------------------------------------------------------- /packages/stack/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Stack'; 2 | -------------------------------------------------------------------------------- /packages/stack/src/styles/createResponsiveStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | 3 | export const createResponsiveStyle = (responsive: boolean = false, mqMaxWidth: string) => { 4 | const responsiveStyle = () => { 5 | if (responsive) { 6 | return css({ 7 | [mqMaxWidth]: { 8 | flexDirection: 'column' 9 | } 10 | }); 11 | } 12 | return css({}); 13 | }; 14 | 15 | return responsiveStyle(); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/stack/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @todo: Will be add to 'utils' package 3 | */ 4 | type StyleUnit = '%' | 'px' | 'em' | 'vh' | 'vw'; 5 | export type SpacingToken = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | `${number}${StyleUnit}`; 6 | export type FlexToken = 'start' | 'end' | 'center' | 'between' | 'around' | 'stretch'; 7 | export type AsElement = React.ElementType; 8 | 9 | export type Direction = 'horizontal' | 'vertical'; 10 | export type FlexMap = Record; 11 | export type SpacingMap = Record; 12 | 13 | export type StyleProps = Omit; 14 | 15 | export interface StackProps { 16 | as?: AsElement; 17 | children?: React.ReactNode; 18 | spacing?: SpacingToken; 19 | align?: FlexToken; 20 | justify?: FlexToken; 21 | direction?: Direction; 22 | responsive?: boolean; 23 | wrap?: boolean; 24 | } 25 | -------------------------------------------------------------------------------- /packages/stack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/tabs/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; -------------------------------------------------------------------------------- /packages/tabs/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/tabs/src/context.ts: -------------------------------------------------------------------------------- 1 | import type { TabVariant, TabSize } from './types'; 2 | import { createContext } from 'react'; 3 | import { ColorToken } from '@jdesignlab/theme'; 4 | 5 | const TabsContext = createContext({ 6 | defaultValue: '', 7 | selectedTab: '', 8 | setSelectedTab: (value: string) => {}, 9 | variant: 'underline' as TabVariant, 10 | size: 'md' as TabSize, 11 | lazy: false, 12 | full: false, 13 | baseColor: 'primary-100' as ColorToken, 14 | accentColor: 'primary-600' as ColorToken 15 | }); 16 | 17 | export default TabsContext; 18 | -------------------------------------------------------------------------------- /packages/tabs/src/hooks/useSelectKeyDown.ts: -------------------------------------------------------------------------------- 1 | import type { Dispatch, SetStateAction } from 'react'; 2 | 3 | export const useSelectKeyDown = ( 4 | event: React.KeyboardEvent, 5 | value: string, 6 | setSelectedTab: Dispatch> 7 | ) => { 8 | if (event.key === 'Enter') { 9 | event.preventDefault(); 10 | setSelectedTab(value); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/tabs/src/hooks/useTabChangeHandle.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import type { TabChangeHandleProps } from '../types'; 3 | 4 | const useTabChangeHandle = ({ onChange, setHasTouched, selectedTab, hasTouched }: TabChangeHandleProps) => { 5 | useEffect(() => { 6 | if (onChange && hasTouched) { 7 | onChange(); 8 | } 9 | setHasTouched(true); 10 | }, [selectedTab]); 11 | }; 12 | 13 | export default useTabChangeHandle; 14 | -------------------------------------------------------------------------------- /packages/tabs/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Tabs'; 2 | -------------------------------------------------------------------------------- /packages/tabs/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ColorToken } from '@jdesignlab/theme'; 2 | import type { Dispatch, SetStateAction } from 'react'; 3 | 4 | export type TabVariant = 'enclosed' | 'underline' | 'unstyled'; 5 | export type TabSize = 'sm' | 'md' | 'lg'; 6 | 7 | export interface TabsProps { 8 | children: React.ReactNode; 9 | defaultValue?: string; 10 | variant?: TabVariant; 11 | onChange?: () => void; 12 | size?: TabSize; 13 | lazy?: boolean; 14 | full?: boolean; 15 | baseColor?: ColorToken; 16 | accentColor?: ColorToken; 17 | } 18 | 19 | export interface TabsListProps { 20 | children: React.ReactNode; 21 | } 22 | 23 | export interface TabsTriggerProps { 24 | children: React.ReactNode; 25 | value: string; 26 | disabled?: boolean; 27 | } 28 | 29 | export interface TabsContentProps { 30 | children: React.ReactNode; 31 | value: string; 32 | } 33 | 34 | export interface TabChangeHandleProps { 35 | selectedTab: string | undefined; 36 | hasTouched: boolean; 37 | setHasTouched: Dispatch>; 38 | onChange?: () => void; 39 | } 40 | -------------------------------------------------------------------------------- /packages/tabs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/text/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/text/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/text/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { LineHeightMapType, FontSizeMap, ElementMap } from './types'; 2 | import { themePreset } from '@jdesignlab/j-provider'; 3 | import type { HEX } from '@jdesignlab/theme'; 4 | 5 | const DEFAULT_COLOR: HEX = themePreset.color.fontColor; 6 | const ELEMENT_MAP: ElementMap = { 7 | paragraph: 'p', 8 | label: 'p', 9 | 'heading-2xl': 'h1', 10 | 'heading-xl': 'h2', 11 | 'heading-lg': 'h3', 12 | 'heading-md': 'h4', 13 | 'heading-sm': 'h5' 14 | }; 15 | const LINE_HEIGHT_MAP: LineHeightMapType = { 16 | heading: '1.4', 17 | label: '1.5', 18 | paragraph: '1.6' 19 | }; 20 | 21 | const FONT_SIZE_MAP: FontSizeMap = { 22 | sm: '12', 23 | md: '16', 24 | lg: '21', 25 | xl: '28', 26 | '2xl': '38' 27 | }; 28 | 29 | export { LINE_HEIGHT_MAP, FONT_SIZE_MAP, ELEMENT_MAP, DEFAULT_COLOR }; 30 | -------------------------------------------------------------------------------- /packages/text/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Text'; 2 | -------------------------------------------------------------------------------- /packages/text/src/styles/createFontStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import { HEX } from '@jdesignlab/theme'; 3 | import type { FontTransformToken, FontStyleToken, FontDecoration, FontAlign } from '../types'; 4 | 5 | export const createFontStyle = ( 6 | transform: FontTransformToken, 7 | style: FontStyleToken, 8 | decoration: FontDecoration, 9 | align: FontAlign, 10 | color: HEX, 11 | truncate: boolean 12 | ) => { 13 | let truncateStyle = {}; 14 | if (truncate) { 15 | truncateStyle = { 16 | whiteSpace: 'nowrap', 17 | overflow: 'hidden', 18 | textOverflow: 'ellipsis' 19 | }; 20 | } 21 | return css({ 22 | ...truncateStyle, 23 | textTransform: transform, 24 | fontStyle: style, 25 | textDecoration: decoration, 26 | textAlign: align, 27 | color 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/text/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/textarea/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/textarea/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/textarea/src/components/Textarea.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { forwardRef } from 'react'; 3 | import { filterComponent } from '@jdesignlab/react-utils'; 4 | import { useTextarea } from '../hooks/useTextarea'; 5 | import { TextareaProvider } from './TextareaContext'; 6 | import { TextareaContainer } from './TextareaContainer'; 7 | import { TextareaLabel } from './TextareaLabel'; 8 | import type { TextAreaProps } from '../types'; 9 | 10 | type ExtendedTextAreaProps = TextAreaProps & { Label?: typeof TextareaLabel }; 11 | export const Textarea = Object.assign( 12 | forwardRef((textAreaProps, ref) => { 13 | const { children, ...propsWithoutChildren } = textAreaProps; 14 | const textareaLabel = filterComponent(children, TextareaLabel, true); 15 | return ( 16 | 17 | 18 | 19 | ); 20 | }), 21 | { 22 | Label: TextareaLabel 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /packages/textarea/src/components/TextareaLabel.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { useContext } from 'react'; 3 | import { Text } from '@jdesignlab/typography'; 4 | import { TEXTAREA_LABEL_COLOR } from '../constants'; 5 | import { createLabelStyle } from '../styles/createLabelStyle'; 6 | import { TextareaContext } from './TextareaContext'; 7 | import { useTextarea } from '../hooks/useTextarea'; 8 | import type { TextareaLabelProps } from '../types'; 9 | 10 | export const TextareaLabel = (props: TextareaLabelProps) => { 11 | const { children, ...attributesWithoutChildren } = props; 12 | const { getChildText } = useTextarea(); 13 | const { textareaId } = useContext(TextareaContext); 14 | const labelStype = createLabelStyle(TEXTAREA_LABEL_COLOR); 15 | const labelText = getChildText(props.children); 16 | 17 | return ( 18 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/textarea/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { StyleProps } from './types'; 2 | import type { ColorToken, HEX } from '@jdesignlab/theme'; 3 | 4 | const DEFAULT_STYLE: Required = { 5 | label: '', 6 | resize: 'none', 7 | color: 'grey-base', 8 | appearance: 'standard', 9 | width: 320, 10 | height: 64, 11 | maxWidth: 480, 12 | maxHeight: 120, 13 | maxLength: null 14 | }; 15 | 16 | const TEXTAREA_TEXT_COLOR: HEX = '#444444'; 17 | const TEXTAREA_PLACEHOLDER_COLOR: ColorToken = 'grey-lighten1'; 18 | const TEXTAREA_LABEL_COLOR: ColorToken = 'grey-darken2'; 19 | const TEXTAREA_ID_PREFIX: string = 'jds-textarea'; 20 | 21 | export { TEXTAREA_TEXT_COLOR, DEFAULT_STYLE, TEXTAREA_ID_PREFIX, TEXTAREA_LABEL_COLOR, TEXTAREA_PLACEHOLDER_COLOR }; 22 | -------------------------------------------------------------------------------- /packages/textarea/src/hooks/useSmart.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useRef } from 'react'; 2 | import { callHandler } from '@jdesignlab/utils'; 3 | import type { ChangeEvent, FormEventHandler } from 'react'; 4 | import type { ResizeProps } from '../types'; 5 | 6 | export const useSmart = (onChange: FormEventHandler | undefined, resize: ResizeProps) => { 7 | const textareaRef = useRef(null); 8 | 9 | const handleResizeHeight = useCallback(() => { 10 | const textArea = textareaRef.current; 11 | if (textArea) { 12 | textArea.style.height = '0px'; 13 | textArea.style.height = `${textArea.scrollHeight}px`; 14 | } 15 | }, [textareaRef]); 16 | 17 | const handleChange = () => { 18 | if (resize === 'smart') { 19 | return callHandler(handleResizeHeight, onChange); 20 | } 21 | return onChange; 22 | }; 23 | 24 | return { textareaRef, handleChange }; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/textarea/src/hooks/useTextarea.ts: -------------------------------------------------------------------------------- 1 | import { Children, isValidElement } from 'react'; 2 | 3 | export const useTextarea = () => { 4 | const getChildText = (children: React.ReactNode) => { 5 | let childText = ''; 6 | if (children) { 7 | Children.forEach(children, child => { 8 | if (isValidElement(child)) { 9 | return typeof child.props.children === 'string' 10 | ? (childText += child.props.children) 11 | : (childText += getChildText(child.props.children)); 12 | } else if (typeof child === 'string') { 13 | childText += child; 14 | } 15 | }); 16 | } 17 | return childText; 18 | }; 19 | 20 | const getLabelId = (children: React.ReactNode) => { 21 | let labelId = ''; 22 | Children.forEach(children, child => { 23 | if (isValidElement(child) && child.props.id) { 24 | labelId = child.props.id; 25 | } 26 | }); 27 | return labelId || null; 28 | }; 29 | 30 | return { getChildText, getLabelId }; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/textarea/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Textarea'; 2 | -------------------------------------------------------------------------------- /packages/textarea/src/styles/createLabelStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | import { getColorByToken } from '@jdesignlab/theme'; 3 | import type { ColorToken } from '@jdesignlab/theme'; 4 | 5 | export const createLabelStyle = (labelColor: ColorToken) => { 6 | const upsideLabel = { 7 | top: 0, 8 | lineHeight: '0.3', 9 | fontSize: '14px', 10 | background: 'white', 11 | color: `${getColorByToken(labelColor)}` 12 | }; 13 | 14 | return css({ 15 | ...upsideLabel, 16 | fontWeight: 'bold', 17 | position: 'absolute', 18 | left: '16px', 19 | display: 'block', 20 | transform: 'translateY(-50%)', 21 | transition: 'all .15s' 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/textarea/src/styles/createWrapperStyle.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | 3 | export const createWrapperStyle = (width: number) => { 4 | return css({ 5 | position: 'relative', 6 | display: 'inline-block', 7 | width: width ? `${width}px` : '100%' 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/textarea/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ColorToken } from '@jdesignlab/theme'; 2 | import type { ReactNode, HTMLAttributes } from 'react'; 3 | 4 | export interface ReturnContext { 5 | textareaId: string; 6 | styleProps: Required; 7 | textareaProps: HTMLAttributes; 8 | } 9 | export type ResizeProps = 'vertical' | 'horizontal' | 'smart' | 'none'; 10 | export type ApperanceProps = 'standard' | 'none'; 11 | export type StyleProps = Pick< 12 | TextAreaProps, 13 | 'width' | 'maxWidth' | 'maxHeight' | 'maxLength' | 'color' | 'resize' | 'appearance' | 'label' | 'height' 14 | >; 15 | 16 | export interface TextareaLabelProps extends HTMLAttributes { 17 | children: ReactNode; 18 | } 19 | 20 | export interface TextAreaProps extends HTMLAttributes { 21 | label?: string; 22 | width?: number; 23 | height?: number; 24 | maxWidth?: number; 25 | maxHeight?: number; 26 | maxLength?: number | null; 27 | color?: ColorToken; 28 | resize?: ResizeProps; 29 | appearance?: ApperanceProps; 30 | children?: ReactNode; 31 | disabled?: boolean; 32 | } 33 | -------------------------------------------------------------------------------- /packages/textarea/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop", "@types/jest", "@testing-library/jest-dom"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/theme/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @jdesignlab/theme 2 | 3 | ## 0.7.0 4 | 5 | ### Minor Changes 6 | 7 | - change text color by background 8 | 9 | ## 0.6.0 10 | 11 | ### Minor Changes 12 | 13 | - black color removal and colors token utilization 14 | 15 | ## 0.5.0 16 | 17 | ### Minor Changes 18 | 19 | - remove clean-package 20 | 21 | ## 0.4.0 22 | 23 | ### Minor Changes 24 | 25 | - change publish config 26 | 27 | ## 0.3.0 28 | 29 | ### Minor Changes 30 | 31 | - minor 32 | -------------------------------------------------------------------------------- /packages/theme/README.md: -------------------------------------------------------------------------------- 1 | # theme 2 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jdesignlab/theme", 3 | "version": "0.7.0", 4 | "packageManager": "yarn@3.3.1", 5 | "main": "src/index.ts", 6 | "sideEffects": false, 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "build": "tsup src --dts --format esm,cjs", 12 | "build:clean": "rimraf dist/" 13 | }, 14 | "devDependencies": { 15 | "rimraf": "^5.0.1", 16 | "ts-node": "^10.9.1", 17 | "tslib": "^2.5.0", 18 | "tsup": "^6.7.0", 19 | "typescript": "^4.9.5" 20 | }, 21 | "publishConfig": { 22 | "access": "public", 23 | "directory": "_release/package", 24 | "main": "./dist/index.js", 25 | "module": "./dist/index.mjs", 26 | "types": "./dist/index.d.ts" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/theme/src/index.ts: -------------------------------------------------------------------------------- 1 | /**types */ 2 | export * from './types/color'; 3 | export * from './types/spacings'; 4 | export * from './types/classVariants'; 5 | /**token constants */ 6 | export * from './token/colors'; 7 | export * from './token/opacity'; 8 | export * from './token/spacings'; 9 | export * from './token/zIndices'; 10 | export * from './token/shadows'; 11 | /**utils */ 12 | export * from './utils/getColorbyToken'; 13 | export * from './utils/getColorByTokenOrHex'; 14 | export * from './utils/createClassVariant'; 15 | export * from './utils/setTextColorByBackground'; 16 | -------------------------------------------------------------------------------- /packages/theme/src/token/opacity.ts: -------------------------------------------------------------------------------- 1 | export const OPACITY_0 = '00'; 2 | export const OPACITY_10 = '1a'; 3 | export const OPACITY_20 = '33'; 4 | export const OPACITY_25 = '40'; 5 | export const OPACITY_30 = '4d'; 6 | export const OPACITY_40 = '66'; 7 | export const OPACITY_50 = '7f'; 8 | export const OPACITY_60 = '99'; 9 | export const OPACITY_70 = 'b3'; 10 | export const OPACITY_75 = 'bf'; 11 | export const OPACITY_80 = 'cc'; 12 | export const OPACITY_90 = 'e5'; 13 | export const OPACITY_100 = 'ff'; 14 | -------------------------------------------------------------------------------- /packages/theme/src/token/spacings.ts: -------------------------------------------------------------------------------- 1 | import { SpacingType } from '../types/spacings'; 2 | 3 | const BASE_SPACING: number = 4; 4 | const SAPCING_LENGTH: number = 16; 5 | 6 | const generateSpacingToken = (spacing: number) => { 7 | return `${spacing * BASE_SPACING}px`; 8 | }; 9 | 10 | const spacingFactory = (length: number): SpacingType => { 11 | let spacingTokens: SpacingType = {}; 12 | for (let i = 1; i <= length; i++) { 13 | spacingTokens[i] = generateSpacingToken(i); 14 | } 15 | return spacingTokens; 16 | }; 17 | 18 | export default Object.freeze(spacingFactory(SAPCING_LENGTH)); 19 | -------------------------------------------------------------------------------- /packages/theme/src/token/zIndices.ts: -------------------------------------------------------------------------------- 1 | export const Z_INDEX_HIDE = 1; 2 | export const Z_INDEX_AUTO = 'auto'; 3 | export const Z_INDEX_BASE = 0; 4 | export const Z_INDEX_DOCKED = 10; 5 | export const Z_INDEX_DROPDOWN = 1000; 6 | export const Z_INDEX_STICKY = 1100; 7 | export const Z_INDEX_BANNER = 1200; 8 | export const Z_INDEX_OVERLAY = 1300; 9 | export const Z_INDEX_MODAL = 1400; 10 | export const Z_INDEX_POPOVER = 1500; 11 | export const Z_INDEX_SKIPLINK = 1600; 12 | export const Z_INDEX_TOAST = 1700; 13 | export const Z_INDEX_TOOLTIP = 1800; 14 | -------------------------------------------------------------------------------- /packages/theme/src/types/classVariants.ts: -------------------------------------------------------------------------------- 1 | export type JDesignSystemComponent = 2 | | 'box' 3 | | 'checkbox' 4 | | 'flex' 5 | | 'modal' 6 | | 'tabs' 7 | | 'tooltip' 8 | | 'button' 9 | | 'drawer' 10 | | 'select' 11 | | 'popover' 12 | | 'textarea' 13 | | 'card' 14 | | 'dropdown' 15 | | 'input' 16 | | 'radio' 17 | | 'stack'; 18 | 19 | export type JDesignSystemElementRoles = 20 | | 'overlay' 21 | | 'wrapper' 22 | | 'group' 23 | | 'content' 24 | | 'label' 25 | | 'ul' 26 | | 'ol' 27 | | 'item' 28 | | 'footer' 29 | | 'header' 30 | | 'trigger' 31 | | 'message' 32 | | 'article' 33 | | 'button' 34 | | 'input' 35 | | 'portal' 36 | | 'icon'; 37 | 38 | export type ClassNameVariant = 39 | | `j-${JDesignSystemComponent}__${string}-${JDesignSystemElementRoles}` 40 | | `j-${JDesignSystemComponent}__${JDesignSystemElementRoles}`; 41 | -------------------------------------------------------------------------------- /packages/theme/src/types/spacings.ts: -------------------------------------------------------------------------------- 1 | export type SpacingType = { [key: number]: string }; 2 | -------------------------------------------------------------------------------- /packages/theme/src/utils/createClassVariant.ts: -------------------------------------------------------------------------------- 1 | import type { JDesignSystemComponent, JDesignSystemElementRoles, ClassNameVariant } from '../types/classVariants'; 2 | 3 | export const createClassVariant = ( 4 | component: JDesignSystemComponent, 5 | element: JDesignSystemElementRoles, 6 | modifier?: string 7 | ): ClassNameVariant => { 8 | return modifier ? `j-${component}__${modifier}-${element}` : `j-${component}__${element}`; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/theme/src/utils/getColorByTokenOrHex.ts: -------------------------------------------------------------------------------- 1 | import { ColorToken, HEX } from '../types/color'; 2 | import { getColorByToken } from './getColorbyToken'; 3 | 4 | const isHexType = (color: ColorToken | HEX): color is HEX => { 5 | const hexRegex = /^#([A-Fa-f0-9]{3}){1,2}$/; 6 | return hexRegex.test(color); 7 | }; 8 | 9 | export const getColorByTokenOrHex = (color: ColorToken | HEX) => { 10 | if (isHexType(color)) { 11 | return color; 12 | } 13 | return getColorByToken(color); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/theme/src/utils/getColorbyToken.ts: -------------------------------------------------------------------------------- 1 | import { variantPresetColors } from '../token/colors'; 2 | import type { HEX, ColorToken } from '../types/color'; 3 | 4 | export const getColorByToken = (colorToken: ColorToken): HEX => { 5 | const [prefix, suffix] = colorToken.split('-'); 6 | return prefix && suffix ? variantPresetColors[prefix][suffix] : variantPresetColors[prefix]; 7 | }; 8 | 9 | export const hexToRgba = (hex: HEX, opacity: number) => { 10 | return `rgba(${parseInt(hex.substring(1, 3), 16)},${parseInt(hex.substring(3, 5), 16)},${parseInt( 11 | hex.substring(5, 7), 12 | 16 13 | )},${opacity})`; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/theme/src/utils/setTextColorByBackground.ts: -------------------------------------------------------------------------------- 1 | import { variantPresetColors } from '../token/colors'; 2 | import type { HEX } from '../types/color'; 3 | 4 | export const setTextColorByBackground = (color: HEX | string) => { 5 | const hexValue = color.replace('#', ''); 6 | const rgbValues = hexValue.match(/.{1,2}/g)?.map(value => parseInt(value, 16)) ?? []; 7 | const brightness = (rgbValues[0] + rgbValues[1] + rgbValues[2]) / 3; 8 | if (brightness < 200) { 9 | return variantPresetColors.grey.lighten4; 10 | } else { 11 | return variantPresetColors.font; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/theme/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/tooltip/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", ["@babel/preset-react", { "runtime": "automatic", "importSource": "@emotion/react" }]], 3 | "plugins": ["@emotion/babel-plugin"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/tooltip/README.md: -------------------------------------------------------------------------------- 1 | # Tooltip 2 | 3 | 사용자에게 모달(팝업) 형태로 컨텐츠를 표시하는 UI요소입니다. 4 | 5 | ## Usage 6 | 7 | [Storybook](https://designsystemlab.github.io/design-system/?path=/docs/data-display-tooltip--basic) 8 | 9 | ```jsx 10 | 11 | 12 | 13 | 14 | ``` 15 | 16 | ## Props 17 | 18 | ### Tooltip 19 | 20 | | Property | Allow Types | Description | Default | 21 | | --------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------- | 22 | | placement | `top-left` `top` `top-right` `right` `right-top` `right-bottom` `left` `left-top` `left-bottom` `bottom-right` `bottom` `bottom-left` | 툴팁이 나타날 위치를 조정합니다. | `top` | 23 | | gap | `number` | 툴팁의 간격을 조정합니다. | `4` | 24 | -------------------------------------------------------------------------------- /packages/tooltip/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | setupFilesAfterEnv: ['/setup-jest.ts'], 7 | transform: { 8 | '^.+\\.[jt]sx?$': 'ts-jest', 9 | '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', 10 | '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file' 11 | } 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /packages/tooltip/setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /packages/tooltip/src/components/Tooltip.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { tooltipWrapperStyle } from '../styles'; 3 | import type { TooltipProps } from '../types'; 4 | import { useState, useRef, useId } from 'react'; 5 | import TooltipContext from '../context'; 6 | import Target from './TooltipTarget'; 7 | import Content from './TooltipContent'; 8 | 9 | export const Tooltip = (props: TooltipProps) => { 10 | const { children } = props; 11 | const [isHovering, setIsHovering] = useState(false); 12 | const [targetEl, setTargetEl] = useState(null); 13 | const id = useId(); 14 | const gap = Number(props.gap) || 4; 15 | 16 | const providerValue = { 17 | id: `tooltip-${id}`, 18 | targetEl, 19 | setTargetEl, 20 | placement: props.placement ?? 'top', 21 | gap, 22 | isHovering, 23 | setIsHovering 24 | }; 25 | 26 | return ( 27 | 28 |
    {children}
    29 |
    30 | ); 31 | }; 32 | 33 | Tooltip.displayName = 'Tooltip'; 34 | Tooltip.Target = Target; 35 | Tooltip.Content = Content; 36 | -------------------------------------------------------------------------------- /packages/tooltip/src/components/TooltipTarget.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxImportSource @emotion/react */ 2 | import { tooltipTargetStyle } from '../styles'; 3 | import type { TooltipTargetPrpos } from '../types'; 4 | import { useContext } from 'react'; 5 | import TooltipContext from '../context'; 6 | 7 | const Target = (props: TooltipTargetPrpos) => { 8 | const { children } = props; 9 | const { id, setIsHovering, setTargetEl } = useContext(TooltipContext); 10 | 11 | const onMouseEnter = () => { 12 | setIsHovering(true); 13 | }; 14 | 15 | const onMouseLeave = () => { 16 | setIsHovering(false); 17 | }; 18 | 19 | return ( 20 |
    31 | {children} 32 |
    33 | ); 34 | }; 35 | 36 | Target.displayName = 'Tooltip.Target'; 37 | export default Target; 38 | -------------------------------------------------------------------------------- /packages/tooltip/src/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import type { TooltipAnchor } from './types'; 3 | 4 | const TooltipContext = createContext({ 5 | id: '', 6 | targetEl: null, 7 | setTargetEl: (value: HTMLDivElement) => {}, 8 | placement: 'top' as TooltipAnchor, 9 | isHovering: false, 10 | setIsHovering: (value: boolean) => {}, 11 | gap: 0 12 | }); 13 | export default TooltipContext; 14 | -------------------------------------------------------------------------------- /packages/tooltip/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/Tooltip'; 2 | -------------------------------------------------------------------------------- /packages/tooltip/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/react'; 2 | 3 | export const tooltipWrapperStyle = css({ 4 | position: 'relative' 5 | }); 6 | export const tooltipContentStyle = css({ 7 | position: 'absolute', 8 | backgroundColor: '#000000ad', 9 | color: '#ffffffc7', 10 | zIndex: '100', 11 | display: 'none', 12 | padding: '4px 8px', 13 | border: 'solid gray 1px', 14 | borderRadius: '2px', 15 | whiteSpace: 'pre', 16 | '&.tooltip_open': { 17 | display: 'inline' 18 | } 19 | }); 20 | 21 | export const tooltipTargetStyle = {}; 22 | -------------------------------------------------------------------------------- /packages/tooltip/src/types.ts: -------------------------------------------------------------------------------- 1 | import { CSSObject } from '@emotion/react'; 2 | 3 | export type TooltipAnchor = 4 | | 'top-left' 5 | | 'top' 6 | | 'top-right' 7 | | 'right' 8 | | 'right-top' 9 | | 'right-bottom' 10 | | 'left' 11 | | 'left-top' 12 | | 'left-bottom' 13 | | 'bottom-right' 14 | | 'bottom' 15 | | 'bottom-left'; 16 | 17 | export interface TooltipProps extends CSSObject { 18 | [propertiesName: string]: any; 19 | children?: React.ReactNode; 20 | placement?: TooltipAnchor; 21 | gap?: number | string; 22 | } 23 | 24 | export interface TooltipContentProps extends CSSObject { 25 | children?: string; 26 | style?: CSSObject; 27 | } 28 | 29 | export interface TooltipTargetPrpos { 30 | children?: React.ReactNode; 31 | } 32 | -------------------------------------------------------------------------------- /packages/tooltip/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "isolatedModules": false, 7 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 8 | "importHelpers": true, 9 | "types": ["@emotion/react/types/css-prop"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "@emotion/react" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @jdesignlab/utils 2 | 3 | ## 0.5.0 4 | 5 | ### Minor Changes 6 | 7 | - remove clean-package 8 | 9 | ## 0.4.0 10 | 11 | ### Minor Changes 12 | 13 | - change publish config 14 | 15 | ## 0.3.0 16 | 17 | ### Minor Changes 18 | 19 | - minor 20 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | # utils 2 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jdesignlab/utils", 3 | "version": "0.5.0", 4 | "packageManager": "yarn@3.3.1", 5 | "main": "src/index.ts", 6 | "sideEffects": false, 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "build": "tsup src --dts --format esm,cjs", 12 | "build:clean": "rimraf dist/" 13 | }, 14 | "devDependencies": { 15 | "@types/react": "^18.0.27", 16 | "@types/react-dom": "^18.0.10", 17 | "rimraf": "^5.0.1", 18 | "tslib": "^2.5.0", 19 | "tsup": "^6.7.0", 20 | "typescript": "^4.9.4" 21 | }, 22 | "publishConfig": { 23 | "access": "public", 24 | "directory": "_release/package", 25 | "main": "./dist/index.js", 26 | "module": "./dist/index.mjs", 27 | "types": "./dist/index.d.ts" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/utils/src/calculateElementPosition.ts: -------------------------------------------------------------------------------- 1 | export const calculateElementPosition = (targetEl: HTMLElement, contentEl: HTMLElement, gap: number) => { 2 | const targetW = targetEl.offsetWidth; 3 | const targetH = targetEl.offsetHeight; 4 | 5 | const contentW = contentEl.offsetWidth; 6 | const contentH = contentEl.offsetHeight; 7 | 8 | const centerX = { left: targetW / 2, transform: `translateX(-${contentW / 2}px)` }; 9 | const centerY = { bottom: targetH / 2, transform: `translateY(${contentH / 2}px)` }; 10 | const moveTop = { bottom: `${targetH + gap}px` }; 11 | const moveBottom = { top: `${targetH + gap}px` }; 12 | const moveRight = { left: `${targetW + gap}px` }; 13 | const moveLeft = { left: `-${contentW + gap}px` }; 14 | const onRight = { left: targetW - contentW }; 15 | const onBottom = { top: targetH - contentH }; 16 | 17 | return { centerX, centerY, moveTop, moveBottom, moveRight, moveLeft, onRight, onBottom }; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/utils/src/combineClassNames.ts: -------------------------------------------------------------------------------- 1 | export const combineClassNames = (classVariant: string, customClass: string | undefined) => { 2 | if (!customClass) return classVariant; 3 | else return `${customClass} ${classVariant}`; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/utils/src/event.ts: -------------------------------------------------------------------------------- 1 | import type { EventType } from './eventTypes'; 2 | 3 | export const callHandler = void>(defaultHandler: T, handler: T | undefined) => { 4 | return (event: EventType) => { 5 | defaultHandler?.(event); 6 | handler?.(event); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/utils/src/eventTypes.ts: -------------------------------------------------------------------------------- 1 | export type EventType = React.ChangeEvent & 2 | React.MouseEvent & 3 | React.ChangeEvent & 4 | React.KeyboardEvent; 5 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './event'; 2 | export * from './eventTypes'; 3 | export { calculateElementPosition } from './calculateElementPosition'; 4 | export { combineClassNames } from './combineClassNames'; 5 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src"], 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | "declaration": true, 7 | "isolatedModules": false, 8 | "esModuleInterop": true, // es module이 아니어도 import export 쓸 수 있게 함 9 | "importHelpers": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /setup-jest.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/'; 2 | -------------------------------------------------------------------------------- /tsupconfig.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | entry: ['src'], 5 | clean: true, 6 | format: ['esm', 'cjs'] 7 | }); 8 | --------------------------------------------------------------------------------