├── .babelrc.json ├── .editorconfig ├── .eslintrc ├── .github ├── chroma@2x.png ├── lifeomic-probot.yml └── workflows │ ├── code-scanning-2022-06-29.yml │ ├── pr-branch-build.yml │ ├── release.yml │ └── storybook.yml ├── .gitignore ├── .storybook ├── logo.svg ├── main.js ├── manager-head.html ├── preview-head.html └── preview.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.js ├── lint-staged.config.js ├── package.json ├── prettier.config.js ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── chroma@2x.png ├── storybook-16x16.png ├── storybook-32x32.png └── storybook.ico ├── release.config.js ├── src ├── assets │ ├── Insights.tsx │ ├── Logo.tsx │ ├── PageLayoutDefaultHero.svg │ ├── Subjects.tsx │ ├── example-avatar-1.jpg │ └── example-avatar-2.jpg ├── colors │ ├── black.ts │ ├── blue.ts │ ├── charcoal.ts │ ├── colorOptions.tsx │ ├── darkGraphite.ts │ ├── graphite.ts │ ├── green.ts │ ├── grey.ts │ ├── navy.ts │ ├── orange.ts │ ├── purple.ts │ ├── red.ts │ ├── text.ts │ ├── types.ts │ └── yellow.ts ├── components │ ├── Alert │ │ ├── Alert.stories.tsx │ │ ├── Alert.test.tsx │ │ ├── Alert.tsx │ │ ├── AlertActionsRow.test.tsx │ │ ├── AlertActionsRow.tsx │ │ ├── AlertBody.test.tsx │ │ ├── AlertBody.tsx │ │ ├── AlertIcon.test.tsx │ │ ├── AlertIcon.tsx │ │ └── index.ts │ ├── Avatar │ │ ├── Avatar.stories.tsx │ │ ├── Avatar.test.tsx │ │ ├── Avatar.tsx │ │ ├── AvatarBadge.test.tsx │ │ ├── AvatarBadge.tsx │ │ ├── AvatarSizeContext.tsx │ │ └── index.ts │ ├── Box │ │ ├── Box.stories.tsx │ │ ├── Box.test.tsx │ │ ├── Box.tsx │ │ └── index.ts │ ├── Breadcrumbs │ │ ├── BreadCrumbNav.test.tsx │ │ ├── Breadcrumb.test.tsx │ │ ├── Breadcrumb.tsx │ │ ├── BreadcrumbNav.tsx │ │ ├── Breadcrumbs.stories.tsx │ │ ├── Breadcrumbs.test.tsx │ │ ├── Breadcrumbs.tsx │ │ └── index.ts │ ├── Button │ │ ├── Button.stories.tsx │ │ ├── Button.test.tsx │ │ ├── Button.tsx │ │ └── index.ts │ ├── ButtonFilePicker │ │ ├── ButtonFilePicker.stories.tsx │ │ ├── ButtonFilePicker.test.tsx │ │ ├── ButtonFilePicker.tsx │ │ └── index.ts │ ├── ButtonFloat │ │ ├── ButtonFloat.stories.tsx │ │ ├── ButtonFloat.test.tsx │ │ ├── ButtonFloat.tsx │ │ └── index.ts │ ├── ButtonLink │ │ ├── ButtonLink.stories.tsx │ │ ├── ButtonLink.test.tsx │ │ ├── ButtonLink.tsx │ │ └── index.ts │ ├── ButtonUnstyled │ │ ├── ButtonUnstyled.stories.tsx │ │ ├── ButtonUnstyled.test.tsx │ │ ├── ButtonUnstyled.tsx │ │ └── index.ts │ ├── Checkbox │ │ ├── Checkbox.stories.tsx │ │ ├── Checkbox.test.tsx │ │ ├── Checkbox.tsx │ │ └── index.ts │ ├── Chip │ │ ├── Chip.stories.tsx │ │ ├── Chip.test.tsx │ │ ├── Chip.tsx │ │ └── index.ts │ ├── ColorPicker │ │ ├── ColorPicker.stories.tsx │ │ ├── ColorPicker.test.tsx │ │ ├── ColorPicker.tsx │ │ └── index.ts │ ├── DayPicker │ │ ├── DayPicker.stories.tsx │ │ ├── DayPicker.test.tsx │ │ ├── DayPicker.tsx │ │ └── index.ts │ ├── DescriptionList │ │ ├── DescriptionDetails.tsx │ │ ├── DescriptionDivider.tsx │ │ ├── DescriptionList.stories.tsx │ │ ├── DescriptionList.test.tsx │ │ ├── DescriptionList.tsx │ │ ├── DescriptionListGroupHeading.tsx │ │ ├── DescriptionTerm.tsx │ │ └── index.ts │ ├── Divider │ │ ├── Divider.stories.tsx │ │ ├── Divider.test.tsx │ │ ├── Divider.tsx │ │ └── index.ts │ ├── DotLoader │ │ ├── DotLoader.stories.tsx │ │ ├── DotLoader.test.tsx │ │ ├── DotLoader.tsx │ │ └── index.ts │ ├── ExpansionPanel │ │ ├── ExpansionPanel.stories.tsx │ │ ├── ExpansionPanel.test.tsx │ │ ├── ExpansionPanel.tsx │ │ └── index.ts │ ├── FormBox │ │ ├── FormBox.stories.tsx │ │ ├── FormBox.test.tsx │ │ ├── FormBox.tsx │ │ └── index.ts │ ├── Header │ │ ├── Header.stories.tsx │ │ ├── Header.test.tsx │ │ ├── Header.tsx │ │ └── index.ts │ ├── IconButton │ │ ├── IconButton.stories.tsx │ │ ├── IconButton.test.tsx │ │ ├── IconButton.tsx │ │ └── index.ts │ ├── IconButtonFloat │ │ ├── IconButtonFloat.stories.tsx │ │ ├── IconButtonFloat.test.tsx │ │ ├── IconButtonFloat.tsx │ │ └── index.ts │ ├── IconButtonLink │ │ ├── IconButtonLink.stories.tsx │ │ ├── IconButtonLink.test.tsx │ │ ├── IconButtonLink.tsx │ │ └── index.ts │ ├── IconTile │ │ ├── IconTile.stories.tsx │ │ ├── IconTile.test.tsx │ │ ├── IconTile.tsx │ │ ├── IconTileBadge.test.tsx │ │ ├── IconTileBadge.tsx │ │ ├── IconTileContent.test.tsx │ │ ├── IconTileContent.tsx │ │ ├── IconTileHero.test.tsx │ │ ├── IconTileHero.tsx │ │ └── index.ts │ ├── InfiniteScroll │ │ ├── InfiniteScroll.stories.tsx │ │ ├── InfiniteScroll.test.tsx │ │ ├── InfiniteScroll.tsx │ │ └── index.ts │ ├── KeymapHelp │ │ ├── KeymapHelp.stories.tsx │ │ ├── KeymapHelp.test.tsx │ │ ├── KeymapHelp.tsx │ │ └── index.ts │ ├── LayoutManager │ │ ├── LayoutManager.stories.tsx │ │ ├── LayoutManager.test.tsx │ │ ├── LayoutManager.tsx │ │ ├── LayoutManagerContext.ts │ │ ├── canAccessLocalStorage.ts │ │ └── index.ts │ ├── LinearProgress │ │ ├── LinearProgress.stories.tsx │ │ ├── LinearProgress.test.tsx │ │ ├── LinearProgress.tsx │ │ └── index.ts │ ├── Link │ │ ├── Link.stories.tsx │ │ ├── Link.test.tsx │ │ ├── Link.tsx │ │ └── index.ts │ ├── List │ │ ├── List.stories.tsx │ │ ├── List.test.tsx │ │ ├── List.tsx │ │ ├── ListGroupHeading.tsx │ │ ├── ListItem.tsx │ │ └── index.ts │ ├── Menu │ │ ├── Menu.stories.tsx │ │ ├── Menu.test.tsx │ │ ├── Menu.tsx │ │ ├── MenuButton.test.tsx │ │ ├── MenuButton.tsx │ │ ├── MenuGroupHeading.tsx │ │ ├── MenuItem.stories.tsx │ │ ├── MenuItem.tsx │ │ └── index.ts │ ├── Modal │ │ ├── Modal.stories.tsx │ │ ├── Modal.test.tsx │ │ ├── Modal.tsx │ │ ├── ModalActions.tsx │ │ ├── helpers.ts │ │ └── index.ts │ ├── NumberFormat │ │ ├── PercentFormatField.stories.tsx │ │ ├── PhoneNumberFormatField.stories.tsx │ │ ├── PhoneNumberFormatField.test.tsx │ │ ├── PhoneNumberFormatField.tsx │ │ ├── PriceFormatField.stories.tsx │ │ ├── UnitNumberFormatField.stories.tsx │ │ ├── UnitNumberFormatField.test.tsx │ │ ├── UnitNumberFormatField.tsx │ │ └── index.ts │ ├── PageHeader │ │ ├── PageHeader.test.tsx │ │ ├── PageHeader.tsx │ │ └── index.ts │ ├── PageLayout │ │ ├── PageLayout.stories.tsx │ │ ├── PageLayout.test.tsx │ │ ├── PageLayout.tsx │ │ ├── hero.svg │ │ └── index.ts │ ├── Paper │ │ ├── Paper.stories.tsx │ │ ├── Paper.test.tsx │ │ ├── Paper.tsx │ │ └── index.ts │ ├── Pill │ │ ├── Pill.stories.tsx │ │ ├── Pill.test.tsx │ │ ├── Pill.tsx │ │ └── index.ts │ ├── Popover │ │ ├── Popover.stories.tsx │ │ ├── Popover.test.tsx │ │ ├── Popover.tsx │ │ ├── PopoverActions.test.tsx │ │ ├── PopoverActions.tsx │ │ ├── PopoverContent.test.tsx │ │ ├── PopoverContent.tsx │ │ ├── PopoverItem.test.tsx │ │ ├── PopoverItem.tsx │ │ ├── PopoverList.test.tsx │ │ ├── PopoverList.tsx │ │ └── index.ts │ ├── PrimaryNavigation │ │ ├── PrimaryNavigation.stories.tsx │ │ ├── PrimaryNavigation.test.tsx │ │ ├── PrimaryNavigation.tsx │ │ ├── PrimaryNavigationExpansionItem.test.tsx │ │ ├── PrimaryNavigationExpansionItem.tsx │ │ ├── PrimaryNavigationItem.test.tsx │ │ ├── PrimaryNavigationItem.tsx │ │ ├── PrimaryNavigationSubItem.test.tsx │ │ ├── PrimaryNavigationSubItem.tsx │ │ ├── _private │ │ │ ├── NavOrExternalLink.tsx │ │ │ └── common.ts │ │ └── index.ts │ ├── Radio │ │ ├── Radio.stories.tsx │ │ ├── Radio.test.tsx │ │ ├── Radio.tsx │ │ ├── RadioGroup.stories.tsx │ │ ├── RadioGroup.test.tsx │ │ ├── RadioGroup.tsx │ │ ├── RadioGroupMinimal.stories.tsx │ │ ├── RadioGroupMinimal.test.tsx │ │ ├── RadioGroupMinimal.tsx │ │ ├── index.ts │ │ └── useRadioGroup.ts │ ├── SearchField │ │ ├── SearchField.stories.tsx │ │ ├── SearchField.test.tsx │ │ ├── SearchField.tsx │ │ ├── clipPaths.ts │ │ └── index.ts │ ├── SecondaryNavigation │ │ ├── SecondaryNavigation.stories.tsx │ │ ├── SecondaryNavigation.test.tsx │ │ ├── SecondaryNavigation.tsx │ │ ├── SecondaryNavigationItem.stories.tsx │ │ ├── SecondaryNavigationItem.test.tsx │ │ ├── SecondaryNavigationItem.tsx │ │ └── index.ts │ ├── Select │ │ ├── ComboBox.stories.tsx │ │ ├── ComboBox.test.tsx │ │ ├── ComboBox.tsx │ │ ├── GroupHeading.test.tsx │ │ ├── GroupHeading.tsx │ │ ├── RoverOption.test.tsx │ │ ├── RoverOption.tsx │ │ ├── Select.stories.tsx │ │ ├── Select.test.tsx │ │ ├── Select.tsx │ │ ├── SelectOption.test.tsx │ │ ├── SelectOption.tsx │ │ ├── index.ts │ │ └── useWindowSize.ts │ ├── Skeleton │ │ ├── Skeleton.stories.tsx │ │ ├── Skeleton.test.tsx │ │ ├── Skeleton.tsx │ │ └── index.ts │ ├── SlideOver │ │ ├── Actions.test.tsx │ │ ├── Actions.tsx │ │ ├── Body.test.tsx │ │ ├── Body.tsx │ │ ├── Header.test.tsx │ │ ├── Header.tsx │ │ ├── SlideOver.stories.tsx │ │ ├── SlideOver.test.tsx │ │ ├── SlideOver.tsx │ │ └── index.ts │ ├── Slider │ │ ├── Slider.stories.tsx │ │ ├── Slider.test.tsx │ │ ├── Slider.tsx │ │ └── index.ts │ ├── SmallTile │ │ ├── SmallTile.stories.tsx │ │ ├── SmallTile.test.tsx │ │ ├── SmallTile.tsx │ │ ├── SmallTileContent.test.tsx │ │ ├── SmallTileContent.tsx │ │ ├── SmallTileFooter.test.tsx │ │ ├── SmallTileFooter.tsx │ │ └── index.ts │ ├── Snackbar │ │ ├── Snackbar.stories.tsx │ │ ├── Snackbar.test.tsx │ │ ├── Snackbar.tsx │ │ └── index.ts │ ├── SpinButton │ │ ├── SpinButton.stories.tsx │ │ ├── SpinButton.test.tsx │ │ ├── SpinButton.tsx │ │ └── index.tsx │ ├── Stepper │ │ ├── Step.test.tsx │ │ ├── Step.tsx │ │ ├── StepConnector.test.tsx │ │ ├── StepConnector.tsx │ │ ├── Stepper.stories.tsx │ │ ├── Stepper.test.tsx │ │ ├── Stepper.tsx │ │ └── index.ts │ ├── TableModule │ │ ├── TableActionDivider.test.tsx │ │ ├── TableActionDivider.tsx │ │ ├── TableHeaderCell.test.tsx │ │ ├── TableHeaderCell.tsx │ │ ├── TableModule.stories.tsx │ │ ├── TableModule.test.tsx │ │ ├── TableModule.tsx │ │ ├── TableModuleActions.test.tsx │ │ ├── TableModuleActions.tsx │ │ ├── TableModuleCell.test.tsx │ │ ├── TableModuleCell.tsx │ │ ├── TableModuleRow.test.tsx │ │ ├── TableModuleRow.tsx │ │ ├── config.ts │ │ ├── configSort.ts │ │ ├── index.ts │ │ ├── storyData.ts │ │ └── types.ts │ ├── Tabs │ │ ├── Tab.tsx │ │ ├── TabList.tsx │ │ ├── TabPanel.tsx │ │ ├── Tabs.stories.tsx │ │ ├── Tabs.test.tsx │ │ ├── Tabs.tsx │ │ ├── TabsContext.tsx │ │ ├── index.ts │ │ └── types.ts │ ├── Text │ │ ├── Text.stories.tsx │ │ ├── Text.test.tsx │ │ ├── Text.tsx │ │ └── index.ts │ ├── TextArea │ │ ├── TextArea.stories.tsx │ │ ├── TextArea.test.tsx │ │ ├── TextArea.tsx │ │ └── index.ts │ ├── TextField │ │ ├── TextField.stories.tsx │ │ ├── TextField.test.tsx │ │ ├── TextField.tsx │ │ └── index.ts │ ├── Toggle │ │ ├── Toggle.stories.tsx │ │ ├── Toggle.test.tsx │ │ ├── Toggle.tsx │ │ └── index.ts │ ├── Tooltip │ │ ├── Tooltip.stories.tsx │ │ ├── Tooltip.test.tsx │ │ ├── Tooltip.tsx │ │ └── index.ts │ ├── _private │ │ ├── ConditionalWrapper.tsx │ │ ├── LinkOrExternalLink.tsx │ │ ├── UniqueId.ts │ │ ├── forms │ │ │ ├── FormElementUtils.ts │ │ │ ├── FormErrorMessage.tsx │ │ │ ├── FormHelpMessage.tsx │ │ │ └── index.ts │ │ └── notificationTypes.ts │ └── index.ts ├── hooks │ ├── events │ │ ├── useInfiniteScroll.tsx │ │ ├── useWindowSize.test.tsx │ │ └── useWindowSize.tsx │ └── utils │ │ ├── useInterval.test.tsx │ │ └── useInterval.tsx ├── jest.js ├── styles │ ├── __snapshots__ │ │ └── createTheme.test.ts.snap │ ├── createBoxShadows.ts │ ├── createPalette.ts │ ├── createStyles.ts │ ├── createTheme.test.ts │ ├── createTheme.ts │ ├── createTypography.ts │ ├── createZIndex.ts │ ├── index.ts │ ├── makeStyles.ts │ ├── overrides │ │ ├── ChromaComponents.ts │ │ ├── ChromaOverrides.ts │ │ ├── ChromaProps.ts │ │ ├── MuiButton.ts │ │ ├── MuiTab.ts │ │ ├── MuiTabs.ts │ │ ├── MuiTooltip.ts │ │ └── index.ts │ ├── screenreaderOnly.ts │ ├── useMediaQuery.tsx │ ├── utils │ │ ├── colorManipulator.test.ts │ │ └── colorManipulator.ts │ ├── withStyles.ts │ └── withTheme.ts ├── testUtils │ ├── IconComponent.tsx │ ├── getTestProps.ts │ └── renderWithTheme.tsx ├── typeUtils.ts ├── typings │ └── assets.d.ts └── utils │ ├── event-handlers.ts │ ├── index.ts │ └── warning.ts ├── stories ├── _recipes │ ├── formik.stories.mdx │ ├── react-hook-form.stories.mdx │ └── redux-form.stories.mdx ├── assets │ ├── legoman.jpg │ └── sampleBackground.svg ├── styles │ ├── boxShadows │ │ └── boxShadows.stories.tsx │ ├── color │ │ ├── ColorValue.tsx │ │ ├── Palette.tsx │ │ ├── PaletteGrid.tsx │ │ └── color.stories.tsx │ └── theme │ │ └── theme.stories.tsx └── typings │ └── assets.d.ts ├── test ├── documentRangeMock.js ├── emptyMock.js ├── imageMock.js └── mockMuiStyles.js ├── tsconfig.build.json ├── tsconfig.docs.json ├── tsconfig.json └── yarn.lock /.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceType": "unambiguous", 3 | "presets": [ 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "targets": { 8 | "chrome": 100, 9 | "safari": 15, 10 | "firefox": 91 11 | } 12 | } 13 | ], 14 | "@babel/preset-typescript", 15 | "@babel/preset-react" 16 | ], 17 | "plugins": [] 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{js,json,yml}] 10 | indent_size = 2 11 | indent_style = space 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es2020": true 7 | }, 8 | "settings": { 9 | "react": { 10 | "version": "detect" 11 | } 12 | }, 13 | "parserOptions": { 14 | "sourceType": "module", 15 | "ecmaFeatures": { 16 | "jsx": true, 17 | "modules": true 18 | }, 19 | "ecmaVersion": 2020 20 | }, 21 | "extends": [ 22 | "plugin:react/recommended", 23 | "prettier", 24 | "plugin:prettier/recommended" 25 | ], 26 | "ignorePatterns": ["node_modules/", "dist/"], 27 | "parser": "@typescript-eslint/parser", 28 | "plugins": ["react", "react-hooks", "prettier", "jsx-a11y"], 29 | "rules": { 30 | "@typescript-eslint/no-empty-interface": "off", 31 | "react-hooks/exhaustive-deps": "warn", 32 | "react-hooks/rules-of-hooks": "error", 33 | "react/display-name": "off", 34 | "react/jsx-no-target-blank": "error", 35 | "react/jsx-uses-react": "error", 36 | "react/jsx-uses-vars": "error", 37 | "react/prop-types": "off", 38 | "jsx-a11y/no-static-element-interactions": "error", 39 | "jsx-a11y/aria-role": "error", 40 | "jsx-a11y/no-autofocus": "error" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/chroma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/.github/chroma@2x.png -------------------------------------------------------------------------------- /.github/lifeomic-probot.yml: -------------------------------------------------------------------------------- 1 | enforceSemanticCommits: true 2 | requestIndividualReviewersFromTeam: '@lifeomic/chroma' 3 | reportWorkflowFailures: 4 | Release: 5 | # This is #open-source 6 | slackChannel: C04928K3H5Z 7 | -------------------------------------------------------------------------------- /.github/workflows/pr-branch-build.yml: -------------------------------------------------------------------------------- 1 | name: PR Branch Build and Test 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | include: 14 | - group: 1 15 | node-version: 16.x 16 | run: | 17 | yarn test --ci --reporters="github-actions" --color 18 | yarn build 19 | - group: 2 20 | node-version: 18.x 21 | run: | 22 | yarn test --ci --reporters="github-actions" --color 23 | yarn build 24 | - group: 3 25 | node-version: 20.x 26 | run: | 27 | yarn test --ci --reporters="github-actions" --color 28 | yarn build 29 | - group: 4 30 | node-version: 18.x 31 | run: | 32 | yarn run docs:build 33 | steps: 34 | - uses: actions/checkout@v3 35 | - uses: actions/setup-node@v3 36 | with: 37 | node-version: ${{ matrix.node-version }} 38 | cache-dependency-path: 'yarn.lock' 39 | cache: 'yarn' 40 | - name: Lint 41 | run: | 42 | yarn 43 | yarn lint 44 | - name: Test 45 | run: ${{ matrix.run }} 46 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | environment: npm 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 16 17 | cache: 'yarn' 18 | - name: Lint, test, and build 19 | run: | 20 | yarn 21 | yarn lint 22 | yarn test --silent 23 | yarn build 24 | - name: Publish 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | NPM_TOKEN: ${{secrets.LIFEOMIC_NPM_TOKEN}} 28 | run: | 29 | yarn build 30 | npx semantic-release 31 | -------------------------------------------------------------------------------- /.github/workflows/storybook.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Storybook to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Exit if not on master branch 14 | if: endsWith(github.ref, 'master') == false 15 | run: exit 0 16 | - uses: actions/setup-node@v1 17 | with: 18 | node-version: 16 19 | registry-url: https://registry.npmjs.org 20 | - name: Install deps and deploy to GitHub Pages 21 | run: | 22 | yarn 23 | yarn docs:deploy -- --ci 24 | env: 25 | GH_TOKEN: ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | .iml/ 4 | .npmrc 5 | .nyc_output/ 6 | .vscode/ 7 | .yarnclean 8 | .cache/ 9 | *.log 10 | deploy/dist/ 11 | deploy/node_modules/ 12 | deploy/terraform/build/ 13 | dist/ 14 | node_modules/ 15 | work/ 16 | coverage/ 17 | cjs/ 18 | esm/ 19 | docs/ 20 | deploy/docs 21 | build/ 22 | 23 | storybook-static/ 24 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | '../stories/**/*.stories.@(mdx|ts|tsx)', 4 | '../src/**/*.stories.@(ts|tsx)', 5 | ], 6 | addons: [ 7 | '@storybook/addon-links', 8 | '@storybook/addon-essentials', 9 | '@storybook/addon-a11y', 10 | '@storybook/addon-interactions', 11 | '@storybook/addon-docs', 12 | ], 13 | framework: { 14 | name: '@storybook/react-webpack5', 15 | options: {}, 16 | }, 17 | webpackFinal: async (config) => { 18 | config.module.rules.push({ 19 | resolve: { fullySpecified: false }, 20 | }); 21 | return config; 22 | }, 23 | docs: { 24 | autodocs: true, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /.storybook/manager-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 17 | 23 | 29 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { create } from '@storybook/theming'; 3 | import logo from './logo.svg'; 4 | import { CssBaseline } from '@mui/material'; 5 | import { 6 | createTheme, 7 | StyledEngineProvider, 8 | ThemeProvider, 9 | } from '../src/styles'; 10 | 11 | export const parameters = { 12 | actions: { argTypesRegex: '^on[A-Z].*' }, 13 | controls: { 14 | matchers: { 15 | color: /(background|color)$/i, 16 | date: /Date$/, 17 | }, 18 | }, 19 | options: { 20 | theme: create({ 21 | base: 'light', 22 | brandTitle: 'Chroma Design System', 23 | brandImage: logo, 24 | }), 25 | isFullscreen: false, 26 | storySort: { 27 | method: 'alphabetical', 28 | }, 29 | }, 30 | backgrounds: { 31 | default: 'white', 32 | values: [ 33 | { 34 | name: 'white', 35 | value: '#FFFFFF', 36 | }, 37 | { 38 | name: 'dark', 39 | value: '#484049', 40 | }, 41 | { 42 | name: 'blue', 43 | value: '#006eb7', 44 | }, 45 | ], 46 | }, 47 | }; 48 | 49 | export const decorators = [ 50 | (story) => ( 51 | 52 | 53 | 54 | 55 | {story()} 56 | 57 | 58 | 59 | ), 60 | ]; 61 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. 4 | 5 | ## How can I contribute? 6 | 7 | If you're interested in contributing to Chroma, we encourage you to submit a pull request! 8 | 9 | Make sure at least one commit in your pull request matches [the conventional commits spec](https://www.conventionalcommits.org/en/v1.0.0/), so that your change 10 | can be versioned correctly. 11 | 12 | ## Releases 13 | 14 | This project releases using [`semantic-release`](https://github.com/semantic-release/semantic-release). Merged PRs are released immediately based on commit messages matching [the conventional commits spec](https://www.conventionalcommits.org/en/v1.0.0/). 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 LifeOmic 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.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'jsdom', 3 | transform: { 4 | '^.+\\.tsx?$': 'ts-jest', 5 | }, 6 | testMatch: [ 7 | '/src/**/*.test.{js,jsx,ts,tsx}', 8 | '/test/**/*.test.{js,jsx,ts,tsx}', 9 | ], 10 | moduleFileExtensions: ['js', 'json', 'ts', 'tsx', 'jsx', 'node', 'mjs'], 11 | clearMocks: true, 12 | collectCoverage: true, 13 | collectCoverageFrom: [ 14 | '/src/components/**/*.{ts,tsx,js,jsx}', 15 | '/src/hooks/**/*.{ts,tsx,js,jsx}', 16 | '/src/styles/**/*.{ts,tsx,js,jsx}', 17 | '!/src/styles/overrides/*.{ts,tsx,js,jsx}', 18 | '!/src/components/index.ts', 19 | '!/src/styles/index.ts', 20 | '!/src/components/**/index.ts', 21 | ], 22 | testPathIgnorePatterns: ['/node_modules/', '/dist/'], 23 | setupFilesAfterEnv: [ 24 | '@testing-library/jest-dom', 25 | '/test/mockMuiStyles.js', 26 | '/test/documentRangeMock.js', 27 | '/src/jest.js', 28 | ], 29 | coverageThreshold: { 30 | global: { 31 | branches: 80, 32 | statements: 80, 33 | functions: 80, 34 | lines: 80, 35 | }, 36 | }, 37 | coveragePathIgnorePatterns: ['.stories.tsx'], 38 | moduleNameMapper: { 39 | '\\.(jpg|jpeg|png|gif|svg)$': '/test/imageMock.js', 40 | '\\.(css)$': '/test/emptyMock.js', 41 | }, 42 | reporters: ['default', 'github-actions'], 43 | }; 44 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{ts,tsx}': [ 3 | 'prettier --write', 4 | 'eslint --ext .ts,.tsx.js,.jsx . --fix', 5 | 'git add', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'es5', 3 | endOfLine: 'lf', 4 | tabWidth: 2, 5 | semi: true, 6 | singleQuote: true, 7 | arrowParens: 'always', 8 | bracketSpacing: true, 9 | }; 10 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/chroma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/chroma@2x.png -------------------------------------------------------------------------------- /public/storybook-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/storybook-16x16.png -------------------------------------------------------------------------------- /public/storybook-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/storybook-32x32.png -------------------------------------------------------------------------------- /public/storybook.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/public/storybook.ico -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branches: ['master'], 3 | plugins: [ 4 | ['@semantic-release/commit-analyzer', { preset: 'conventionalcommits' }], 5 | ['@semantic-release/npm', { pkgRoot: 'dist/' }], 6 | [ 7 | '@semantic-release/github', 8 | { 9 | // Setting this to false disables the default behavior 10 | // of opening a GitHub issue when a release fails. 11 | // We can enable this later if we want. 12 | failComment: false, 13 | }, 14 | ], 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /src/assets/Insights.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export const Insights: React.FC> = (props) => ( 4 | 12 | 16 | 20 | 21 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 44 | 45 | ); 46 | -------------------------------------------------------------------------------- /src/assets/Subjects.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export const Subjects: React.FC> = (props) => ( 4 | 12 | 16 | 20 | 21 | 29 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 44 | 45 | ); 46 | -------------------------------------------------------------------------------- /src/assets/example-avatar-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/src/assets/example-avatar-1.jpg -------------------------------------------------------------------------------- /src/assets/example-avatar-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lifeomic/chroma-react/7f253614eb17adef57db4c4f197017c91f40efb5/src/assets/example-avatar-2.jpg -------------------------------------------------------------------------------- /src/colors/black.ts: -------------------------------------------------------------------------------- 1 | import gray from './grey'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#eeeeee', 6 | 100: '#d1d5d8', 7 | 200: '#b2b9c0', 8 | 300: '#929da9', 9 | 400: '#7b8996', 10 | 500: '#637585', 11 | 600: '#576674', 12 | 700: '#47535e', 13 | 800: '#384049', 14 | 900: '#262c32', 15 | }; 16 | 17 | const black: Color & SimplePaletteColorOptions = { 18 | ...shades, 19 | main: shades[900], 20 | light: shades[700], 21 | contrastText: gray[200], 22 | }; 23 | 24 | export default black; 25 | -------------------------------------------------------------------------------- /src/colors/blue.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#def4fc', 6 | 100: '#aae3f8', 7 | 200: '#6dd1f4', 8 | 300: '#0abff1', 9 | 400: '#00b2f1', 10 | 500: '#00a4ef', 11 | 600: '#0096e1', 12 | 700: '#0083ce', 13 | 800: '#006eb7', 14 | 900: '#00539a', 15 | }; 16 | 17 | const blue: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[800], 20 | light: shades[300], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default blue; 25 | -------------------------------------------------------------------------------- /src/colors/charcoal.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#ebebeb', 6 | 100: '#d6d7d8', 7 | 200: '#c2c3c5', 8 | 300: '#aeafb1', 9 | 400: '#9a9c9e', 10 | 500: '#85888a', 11 | 600: '#717477', 12 | 700: '#5d6063', 13 | 800: '#494d50', 14 | 900: '#35393d', 15 | }; 16 | 17 | const charcoal: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[900], 20 | light: shades[600], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default charcoal; 25 | -------------------------------------------------------------------------------- /src/colors/darkGraphite.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#eeeef0', 6 | 100: '#dcdde1', 7 | 200: '#cbccd2', 8 | 300: '#b9bbc3', 9 | 400: '#a8aab4', 10 | 500: '#9799a5', 11 | 600: '#868996', 12 | 700: '#747787', 13 | 800: '#636779', 14 | 900: '#52566a', 15 | }; 16 | 17 | const darkGraphite: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[900], 20 | light: shades[600], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default darkGraphite; 25 | -------------------------------------------------------------------------------- /src/colors/graphite.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#f2f3f6', 6 | 100: '#e6e7ed', 7 | 200: '#dadbe4', 8 | 300: '#cdcfdb', 9 | 400: '#c1c4d2', 10 | 500: '#b5b8c9', 11 | 600: '#a9acc0', 12 | 700: '#9ca0b7', 13 | 800: '#9095af', 14 | 900: '#8489a6', 15 | }; 16 | 17 | const graphite: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[900], 20 | light: shades[600], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default graphite; 25 | -------------------------------------------------------------------------------- /src/colors/green.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#f0f9e8', 6 | 100: '#d9f0c5', 7 | 200: '#c0e59f', 8 | 300: '#a6db77', 9 | 400: '#91d357', 10 | 500: '#7dcb35', 11 | 600: '#6dba2d', 12 | 700: '#58a623', 13 | 800: '#387f15', 14 | 900: '#0f7000', 15 | }; 16 | 17 | const green: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[800], 20 | light: shades[500], 21 | dark: shades[900], 22 | contrastText: text.contrast, 23 | }; 24 | 25 | export default green; 26 | -------------------------------------------------------------------------------- /src/colors/grey.ts: -------------------------------------------------------------------------------- 1 | import { Color, SimplePaletteColorOptions } from './types'; 2 | 3 | const shades: Color = { 4 | 50: '#fafafa', 5 | 100: '#f1f7f9', 6 | 200: '#f8f8f8', 7 | 300: '#e9e9e9', 8 | 400: '#dbdbdb', 9 | 500: '#cacaca', 10 | 600: '#9c9c9c', 11 | 700: '#595959', 12 | 800: '#35393d', 13 | 900: '#292c2f', 14 | }; 15 | 16 | const grey: SimplePaletteColorOptions & Color = { 17 | ...shades, 18 | main: shades[900], 19 | light: shades[600], 20 | }; 21 | 22 | export default grey; 23 | -------------------------------------------------------------------------------- /src/colors/navy.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#eceef0', 6 | 100: '#d9dde1', 7 | 200: '#c7ccd2', 8 | 300: '#b4bbc3', 9 | 400: '#a2abb4', 10 | 500: '#8f9aa5', 11 | 600: '#7d8996', 12 | 700: '#6a7887', 13 | 800: '#576878', 14 | 900: '#455769', 15 | }; 16 | 17 | const navy: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[900], 20 | light: shades[700], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default navy; 25 | -------------------------------------------------------------------------------- /src/colors/orange.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#fdf1e6', 6 | 100: '#fce4cc', 7 | 200: '#fbd7b3', 8 | 300: '#f9c999', 9 | 400: '#f8bc80', 10 | 500: '#f7af66', 11 | 600: '#f5a24d', 12 | 700: '#f49433', 13 | 800: '#f27a00', 14 | 900: '#b14800', 15 | }; 16 | 17 | const orange: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[800], 20 | light: shades[600], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default orange; 25 | -------------------------------------------------------------------------------- /src/colors/purple.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#f4e7fe', 6 | 100: '#e8cffe', 7 | 200: '#ddb8fe', 8 | 300: '#d2a0fe', 9 | 400: '#c789fe', 10 | 500: '#bc71fe', 11 | 600: '#b15afe', 12 | 700: '#a642fe', 13 | 800: '#9013fe', 14 | 900: '#5500c9', 15 | }; 16 | 17 | const purple: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[800], 20 | light: shades[600], 21 | contrastText: text.contrast, 22 | }; 23 | 24 | export default purple; 25 | -------------------------------------------------------------------------------- /src/colors/red.ts: -------------------------------------------------------------------------------- 1 | import text from './text'; 2 | import { Color, SimplePaletteColorOptions } from './types'; 3 | 4 | const shades: Color = { 5 | 50: '#fdeaef', 6 | 100: '#fccbd5', 7 | 200: '#eb969f', 8 | 300: '#e06e79', 9 | 400: '#eb495a', 10 | 500: '#f13343', 11 | 600: '#e22941', 12 | 700: '#d01e3a', 13 | 800: '#c31533', 14 | 900: '#b40027', 15 | }; 16 | 17 | const red: SimplePaletteColorOptions & Color = { 18 | ...shades, 19 | main: shades[800], 20 | light: shades[600], 21 | dark: shades[900], 22 | contrastText: text.contrast, 23 | }; 24 | 25 | export default red; 26 | -------------------------------------------------------------------------------- /src/colors/text.ts: -------------------------------------------------------------------------------- 1 | import black from './black'; 2 | import gray from './grey'; 3 | import { TypeText } from './types'; 4 | 5 | const text: TypeText & { hint: string } = { 6 | primary: black[900], 7 | secondary: black[700], 8 | hint: black[600], 9 | disabled: black[400], 10 | contrast: gray[200], 11 | dark: black[900], 12 | }; 13 | 14 | export default text; 15 | -------------------------------------------------------------------------------- /src/colors/types.ts: -------------------------------------------------------------------------------- 1 | import { Color as MUIColor } from '@mui/material'; 2 | import { 3 | SimplePaletteColorOptions, 4 | TypeText as MuiTypeText, 5 | } from '@mui/material/styles/createPalette'; 6 | 7 | export { SimplePaletteColorOptions }; 8 | 9 | export type Color = Omit; 10 | 11 | export interface TypeText extends MuiTypeText { 12 | contrast: string; 13 | dark: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/colors/yellow.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ColorPartial, 3 | SimplePaletteColorOptions, 4 | } from '@mui/material/styles/createPalette'; 5 | import text from './text'; 6 | 7 | const shades: ColorPartial = { 8 | 50: '#fefce8', 9 | 100: '#fdfad1', 10 | 200: '#fcf7bb', 11 | 300: '#fcf5a4', 12 | 400: '#fbf38d', 13 | 500: '#faf076', 14 | 600: '#faee60', 15 | 700: '#f9eb49', 16 | 800: '#f7bf4d', 17 | 900: '#916800', 18 | }; 19 | 20 | const yellow: SimplePaletteColorOptions & ColorPartial = { 21 | ...shades, 22 | main: shades[800]!, 23 | light: shades[600], 24 | contrastText: text.contrast, 25 | }; 26 | 27 | export default yellow; 28 | -------------------------------------------------------------------------------- /src/components/Alert/AlertActionsRow.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 3 | import { AlertActionsRow } from './index'; 4 | 5 | const testId = 'AlertActionsRow'; 6 | 7 | test('it renders an AlertActionsRow', async () => { 8 | const { findByTestId } = renderWithTheme( 9 | 10 | ); 11 | 12 | const actionRow = await findByTestId(testId); 13 | expect(actionRow).toBeInTheDocument(); 14 | expect(actionRow).toHaveClass('ChromaAlertActionsRow-root'); 15 | }); 16 | 17 | test('it applies the provided className', async () => { 18 | const { findByTestId } = renderWithTheme( 19 | 20 | ); 21 | 22 | const actionRow = await findByTestId(testId); 23 | expect(actionRow).toHaveClass('custom-class-name'); 24 | }); 25 | -------------------------------------------------------------------------------- /src/components/Alert/AlertActionsRow.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { makeStyles } from '../../styles'; 3 | import { GetClasses } from '../../typeUtils'; 4 | import clsx from 'clsx'; 5 | 6 | export const AlertActionsRowStylesKey = 'ChromaAlertActionsRow'; 7 | 8 | export const useStyles = makeStyles( 9 | () => ({ 10 | root: { 11 | marginTop: '0.5rem', 12 | marginLeft: '-0.625rem', 13 | marginRight: '-0.625rem', 14 | '& > button, a': { 15 | '&:not(:last-child)': { 16 | marginRight: '0.25rem', 17 | }, 18 | }, 19 | }, 20 | }), 21 | { name: AlertActionsRowStylesKey } 22 | ); 23 | 24 | export type AlertActionsRowClasses = GetClasses; 25 | 26 | export interface AlertActionsRowProps { 27 | children?: React.ReactNode; 28 | className?: string; 29 | } 30 | 31 | export const AlertActionsRow: React.FC = ({ 32 | className, 33 | children, 34 | ...rootProps 35 | }) => { 36 | const classes = useStyles({}); 37 | return ( 38 |
39 | {children} 40 |
41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /src/components/Alert/AlertBody.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 3 | import { AlertBody } from './index'; 4 | 5 | const testId = 'AlertBody'; 6 | 7 | test('it renders an AlertBody', async () => { 8 | const { findByTestId } = renderWithTheme(); 9 | 10 | const body = await findByTestId(testId); 11 | expect(body).toBeInTheDocument(); 12 | expect(body).toHaveClass('ChromaAlertBody-root'); 13 | }); 14 | 15 | test('it applies the provided className', async () => { 16 | const { findByTestId } = renderWithTheme( 17 | 18 | ); 19 | 20 | const body = await findByTestId(testId); 21 | expect(body).toHaveClass('custom-class-name'); 22 | }); 23 | 24 | test('it applies the space-between class', async () => { 25 | const { findByTestId } = renderWithTheme( 26 | 27 | ); 28 | 29 | const body = await findByTestId(testId); 30 | expect(body).toHaveClass('ChromaAlertBody-spaceBetween'); 31 | }); 32 | -------------------------------------------------------------------------------- /src/components/Alert/AlertIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { IconComponent } from '../../testUtils/IconComponent'; 3 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 4 | import { AlertIcon } from './index'; 5 | 6 | const testId = 'AlertIcon'; 7 | 8 | test('it renders an AlertIcon', async () => { 9 | const { findByTestId, findByRole } = renderWithTheme( 10 | 11 | ); 12 | 13 | const iconWrapper = await findByTestId(testId); 14 | expect(iconWrapper).toBeInTheDocument(); 15 | expect(iconWrapper).toHaveClass('ChromaAlertIcon-root'); 16 | 17 | const icon = await findByRole('img', { hidden: true }); 18 | expect(icon).toBeInTheDocument(); 19 | }); 20 | 21 | test('it applies the provided className', async () => { 22 | const { findByTestId } = renderWithTheme( 23 | 24 | ); 25 | 26 | const body = await findByTestId(testId); 27 | expect(body).toHaveClass('custom-class-name'); 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/Alert/AlertIcon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { makeStyles } from '../../styles'; 3 | import { GetClasses } from '../../typeUtils'; 4 | import clsx from 'clsx'; 5 | 6 | export const AlertIconStylesKey = 'ChromaAlertIcon'; 7 | 8 | export const useStyles = makeStyles( 9 | () => ({ 10 | root: { 11 | color: 'inherit', 12 | display: 'flex', 13 | flexShrink: 0, 14 | marginTop: '-0.0625rem', 15 | marginRight: '0.75rem', 16 | height: '1.5rem', 17 | width: '1.5rem', 18 | }, 19 | }), 20 | { name: AlertIconStylesKey } 21 | ); 22 | 23 | export type AlertIconClasses = GetClasses; 24 | 25 | export interface AlertIconProps { 26 | children?: React.ReactNode; 27 | className?: string; 28 | icon?: React.MemoExoticComponent< 29 | (props: React.SVGProps) => JSX.Element 30 | >; 31 | } 32 | 33 | export const AlertIcon: React.FC = ({ 34 | className, 35 | children, 36 | icon: Icon, 37 | ...rootProps 38 | }) => { 39 | const classes = useStyles({}); 40 | return ( 41 |
42 | {Icon && } 43 | {children} 44 |
45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /src/components/Alert/index.ts: -------------------------------------------------------------------------------- 1 | export { Alert, AlertProps, AlertStylesKey, AlertClasses } from './Alert'; 2 | export { 3 | AlertActionsRow, 4 | AlertActionsRowProps, 5 | AlertActionsRowStylesKey, 6 | AlertActionsRowClasses, 7 | } from './AlertActionsRow'; 8 | 9 | export { 10 | AlertBody, 11 | AlertBodyProps, 12 | AlertBodyStylesKey, 13 | AlertBodyClasses, 14 | } from './AlertBody'; 15 | 16 | export { 17 | AlertIcon, 18 | AlertIconProps, 19 | AlertIconStylesKey, 20 | AlertIconClasses, 21 | } from './AlertIcon'; 22 | -------------------------------------------------------------------------------- /src/components/Avatar/AvatarSizeContext.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { AvatarProps } from './Avatar'; 3 | 4 | interface AvatarSizeValue { 5 | size?: AvatarProps['size']; 6 | } 7 | 8 | export const AvatarSizeContext = React.createContext({ 9 | size: 1, 10 | }); 11 | 12 | export const useAvatarSize = () => React.useContext(AvatarSizeContext); 13 | -------------------------------------------------------------------------------- /src/components/Avatar/index.ts: -------------------------------------------------------------------------------- 1 | export { Avatar, AvatarProps, AvatarClasses, AvatarStylesKey } from './Avatar'; 2 | export { 3 | AvatarBadge, 4 | AvatarBadgeProps, 5 | AvatarBadgeClasses, 6 | AvatarBadgeStylesKey, 7 | } from './AvatarBadge'; 8 | -------------------------------------------------------------------------------- /src/components/Box/index.ts: -------------------------------------------------------------------------------- 1 | export { Box, BoxClasses, BoxProps, BoxStylesKey } from './Box'; 2 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/BreadCrumbNav.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 3 | import { BreadcrumbNav } from './index'; 4 | 5 | const testId = 'BreadcrumbNav'; 6 | 7 | test('it renders a BreadcrumbNav', async () => { 8 | const { findByTestId } = renderWithTheme( 9 | 10 | ); 11 | const breadcrumbNav = await findByTestId(testId); 12 | expect(breadcrumbNav).toBeInTheDocument(); 13 | }); 14 | 15 | test('it applies the provided className', async () => { 16 | const { findByTestId } = renderWithTheme( 17 | 18 | ); 19 | const breadcrumbNav = await findByTestId(testId); 20 | expect(breadcrumbNav).toHaveClass('custom-class-name'); 21 | }); 22 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/BreadcrumbNav.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import * as React from 'react'; 3 | import { makeStyles } from '../../styles/index'; 4 | import { GetClasses } from '../../typeUtils'; 5 | 6 | export const BreadcrumbNavStylesKey = 'ChromaBreadcrumbNav'; 7 | 8 | export const useStyles = makeStyles( 9 | (theme) => ({ 10 | root: {}, 11 | ol: { 12 | margin: theme.spacing(0), 13 | paddingLeft: theme.spacing(0), 14 | listStyle: 'none', 15 | }, 16 | }), 17 | { name: BreadcrumbNavStylesKey } 18 | ); 19 | 20 | export type BreadcrumbNavClasses = GetClasses; 21 | 22 | export interface BreadcrumbNavProps 23 | extends React.DetailedHTMLProps< 24 | React.HTMLAttributes, 25 | HTMLElement 26 | > { 27 | children?: React.ReactNode; 28 | } 29 | 30 | export const BreadcrumbNav: React.FC = ({ 31 | className, 32 | children, 33 | ...rootProps 34 | }) => { 35 | const classes = useStyles({}); 36 | return ( 37 | 44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/Breadcrumbs.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, Meta } from '@storybook/react'; 3 | import { MemoryRouter } from 'react-router-dom'; 4 | 5 | import { Breadcrumbs } from './Breadcrumbs'; 6 | 7 | const meta: Meta = { 8 | component: Breadcrumbs, 9 | args: { 10 | crumbs: [ 11 | { 12 | text: 'Parent', 13 | url: 'root', 14 | }, 15 | { 16 | text: 'Child', 17 | url: 'root/child', 18 | }, 19 | { 20 | text: 'GrandChild', 21 | url: 'root/child/grand', 22 | }, 23 | ], 24 | }, 25 | decorators: [(story) => {story()}], 26 | }; 27 | export default meta; 28 | type Story = StoryObj; 29 | 30 | export const Default: Story = {}; 31 | 32 | export const InverseDark = { 33 | parameters: { 34 | backgrounds: { default: 'dark' }, 35 | }, 36 | args: { 37 | color: 'inverse', 38 | }, 39 | }; 40 | 41 | export const InverseBlue = { 42 | parameters: { 43 | backgrounds: { default: 'blue' }, 44 | }, 45 | 46 | args: { 47 | color: 'inverse', 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/Breadcrumbs.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { MemoryRouter } from 'react-router-dom'; 3 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 4 | import { Breadcrumbs, BreadcrumbsProps } from './index'; 5 | 6 | const testId = 'Breadcrumbs'; 7 | 8 | const getBaseProps = (): BreadcrumbsProps => ({ 9 | crumbs: [ 10 | { text: 'parent', url: 'p' }, 11 | { text: 'child', url: 'c' }, 12 | ], 13 | }); 14 | 15 | test('it renders Breadcrumbs', async () => { 16 | const props = getBaseProps(); 17 | const { findByTestId, findByText } = renderWithTheme( 18 | 19 | 20 | 21 | ); 22 | const breadcrumbs = await findByTestId(testId); 23 | expect(breadcrumbs).toBeInTheDocument(); 24 | 25 | const parentLink = await findByText(props.crumbs[0].text); 26 | expect(parentLink).toBeInTheDocument(); 27 | 28 | const childLink = await findByText(props.crumbs[1].text); 29 | expect(childLink).toBeInTheDocument(); 30 | }); 31 | 32 | test('it applies the provided className', async () => { 33 | const props = getBaseProps(); 34 | const { findByTestId } = renderWithTheme( 35 | 36 | 41 | 42 | ); 43 | const breadcrumbs = await findByTestId(testId); 44 | expect(breadcrumbs).toHaveClass('custom-class-name'); 45 | }); 46 | 47 | test('it applies `color="inverse"`', async () => { 48 | const props = getBaseProps(); 49 | const { findByTestId } = renderWithTheme( 50 | 51 | 52 | 53 | ); 54 | const breadcrumbs = await findByTestId(testId); 55 | expect(breadcrumbs).toHaveClass(' ChromaBreadcrumbs-inverse'); 56 | }); 57 | -------------------------------------------------------------------------------- /src/components/Breadcrumbs/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Breadcrumbs, 3 | BreadcrumbsClasses, 4 | BreadcrumbsProps, 5 | BreadcrumbsStylesKey, 6 | } from './Breadcrumbs'; 7 | 8 | export { 9 | Breadcrumb, 10 | BreadcrumbClasses, 11 | BreadcrumbProps, 12 | BreadcrumbStylesKey, 13 | } from './Breadcrumb'; 14 | 15 | export { 16 | BreadcrumbNav, 17 | BreadcrumbNavClasses, 18 | BreadcrumbNavProps, 19 | BreadcrumbNavStylesKey, 20 | } from './BreadcrumbNav'; 21 | -------------------------------------------------------------------------------- /src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export { Button, ButtonProps, ButtonStylesKey, ButtonClasses } from './Button'; 2 | -------------------------------------------------------------------------------- /src/components/ButtonFilePicker/ButtonFilePicker.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, StoryFn, Meta } from '@storybook/react'; 3 | 4 | import { ButtonFilePicker } from './ButtonFilePicker'; 5 | import { Edit } from '@lifeomic/chromicons'; 6 | const meta: Meta = { 7 | component: ButtonFilePicker, 8 | }; 9 | export default meta; 10 | type Story = StoryObj; 11 | 12 | const Template: StoryFn = (args) => ( 13 | Button File Picker 14 | ); 15 | 16 | export const Default: Story = { 17 | render: Template, 18 | }; 19 | 20 | export const Accept: Story = { 21 | render: Template, 22 | args: { 23 | accept: '.jpg,.jpeg', 24 | }, 25 | parameters: { 26 | docs: { 27 | description: { 28 | story: 29 | 'A CSV list of the type of file extension(s) the file picker should accept.', 30 | }, 31 | }, 32 | }, 33 | }; 34 | 35 | export const Disabled: Story = { 36 | render: Template, 37 | args: { 38 | disabled: true, 39 | }, 40 | }; 41 | 42 | export const Icon: Story = { 43 | render: Template, 44 | args: { 45 | icon: Edit, 46 | }, 47 | }; 48 | 49 | export const InverseDark: Story = { 50 | render: Template, 51 | args: { 52 | color: 'inverse', 53 | }, 54 | parameters: { 55 | backgrounds: { default: 'dark' }, 56 | }, 57 | }; 58 | 59 | export const InverseBlue: Story = { 60 | render: Template, 61 | args: { 62 | color: 'inverse', 63 | }, 64 | parameters: { 65 | backgrounds: { default: 'blue' }, 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /src/components/ButtonFilePicker/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ButtonFilePicker, 3 | ButtonFilePickerProps, 4 | ButtonFilePickerStylesKey, 5 | ButtonFilePickerClasses, 6 | } from './ButtonFilePicker'; 7 | -------------------------------------------------------------------------------- /src/components/ButtonFloat/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ButtonFloat, 3 | ButtonFloatClasses, 4 | ButtonFloatProps, 5 | ButtonFloatStylesKey, 6 | } from './ButtonFloat'; 7 | -------------------------------------------------------------------------------- /src/components/ButtonLink/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ButtonLink, 3 | ButtonLinkClasses, 4 | ButtonLinkProps, 5 | ButtonLinkStylesKey, 6 | } from './ButtonLink'; 7 | -------------------------------------------------------------------------------- /src/components/ButtonUnstyled/ButtonUnstyled.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, StoryFn, Meta } from '@storybook/react'; 3 | 4 | import { ButtonUnstyled } from './ButtonUnstyled'; 5 | 6 | const meta: Meta = { 7 | component: ButtonUnstyled, 8 | argTypes: { 9 | onClick: { action: 'clicked' }, 10 | }, 11 | }; 12 | export default meta; 13 | type Story = StoryObj; 14 | 15 | const Template: StoryFn = (args) => ( 16 | Button Unstyled 17 | ); 18 | 19 | export const Default: Story = { 20 | render: Template, 21 | }; 22 | -------------------------------------------------------------------------------- /src/components/ButtonUnstyled/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ButtonUnstyled, 3 | ButtonUnstyledProps, 4 | ButtonUnstyledStylesKey, 5 | ButtonUnstyledClasses, 6 | } from './ButtonUnstyled'; 7 | -------------------------------------------------------------------------------- /src/components/Checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Checkbox, 3 | CheckboxClasses, 4 | CheckboxProps, 5 | CheckboxStylesKey, 6 | } from './Checkbox'; 7 | -------------------------------------------------------------------------------- /src/components/Chip/Chip.stories.tsx: -------------------------------------------------------------------------------- 1 | import { StoryObj, Meta } from '@storybook/react'; 2 | 3 | import { Chip } from './Chip'; 4 | 5 | const meta: Meta = { 6 | component: Chip, 7 | args: { 8 | label: 'Chip', 9 | }, 10 | }; 11 | export default meta; 12 | type Story = StoryObj; 13 | 14 | export const Default: Story = {}; 15 | 16 | export const OnDelete: Story = { 17 | parameters: { 18 | docs: { 19 | description: { 20 | story: 21 | 'The function to call when the removal button is clicked. Note that this does not ' + 22 | 'actually do anything to the Chip component, removing the element from the DOM is ' + 23 | 'up to the consumer to take care of.\n\n' + 24 | 'To display a Chip, but not display the removal button, do not provide this prop.', 25 | }, 26 | }, 27 | }, 28 | }; 29 | 30 | export const DisableDelete: Story = { 31 | args: { 32 | disableDelete: true, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/components/Chip/index.ts: -------------------------------------------------------------------------------- 1 | export { Chip, ChipClasses, ChipProps, ChipStylesKey } from './Chip'; 2 | -------------------------------------------------------------------------------- /src/components/ColorPicker/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ColorPicker, 3 | ColorPickerClasses, 4 | ColorPickerProps, 5 | ColorPickerStylesKey, 6 | isValidHexColor, 7 | } from './ColorPicker'; 8 | -------------------------------------------------------------------------------- /src/components/DayPicker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DayPicker'; 2 | -------------------------------------------------------------------------------- /src/components/DescriptionList/DescriptionDivider.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import * as React from 'react'; 3 | import { makeStyles } from '../../styles'; 4 | import { GetClasses } from '../../typeUtils'; 5 | 6 | export const DescriptionDividerStylesKey = 'ChromaDescriptionDivider'; 7 | 8 | export const useStyles = makeStyles( 9 | (theme) => ({ 10 | root: { 11 | backgroundColor: theme.palette.divider, 12 | border: 'none', 13 | flexShrink: 0, 14 | gridColumn: '1/-1', 15 | margin: 0, 16 | height: 1, 17 | width: '100%', 18 | }, 19 | }), 20 | { name: DescriptionDividerStylesKey } 21 | ); 22 | 23 | export interface DescriptionDividerOwnProps 24 | extends React.DetailedHTMLProps< 25 | React.HTMLAttributes, 26 | HTMLLIElement 27 | > {} 28 | 29 | export type DescriptionDividerClasses = GetClasses; 30 | 31 | export interface DescriptionDividerProps extends DescriptionDividerOwnProps {} 32 | 33 | /** 34 | * A `DescriptionDivider` is a thin line that groups content in description lists. The divider 35 | * renders as an `
  • `. 36 | * 37 | * ### Links 38 | * 39 | * - [Component Source](https://github.com/lifeomic/chroma-react/blob/master/src/components/DescriptionDivider/DescriptionDivider.tsx) 40 | * - [Story Source](https://github.com/lifeomic/chroma-react/blob/master/stories/components/DescriptionDivider/DescriptionDivider.stories.tsx) 41 | */ 42 | export const DescriptionDivider = React.forwardRef< 43 | HTMLLIElement, 44 | DescriptionDividerProps 45 | >(({ className, ...rootProps }, ref) => { 46 | const classes = useStyles({}); 47 | 48 | return ( 49 |
  • 50 | ); 51 | }); 52 | -------------------------------------------------------------------------------- /src/components/DescriptionList/DescriptionListGroupHeading.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import * as React from 'react'; 3 | import { makeStyles } from '../../styles'; 4 | import { GetClasses } from '../../typeUtils'; 5 | import { lighten } from '@mui/material/styles'; 6 | 7 | export const DescriptionListGroupHeadingStylesKey = 'ChromaListGroupHeading'; 8 | 9 | export const useStyles = makeStyles( 10 | (theme) => ({ 11 | root: { 12 | borderBottom: `solid ${theme.pxToRem(3)} ${lighten( 13 | theme.palette.divider, 14 | 0.4 15 | )}`, 16 | color: theme.palette.text.hint, 17 | fontSize: theme.pxToRem(10), 18 | fontWeight: theme.typography.fontWeightBold, 19 | gridColumn: '1/-1', 20 | letterSpacing: theme.pxToRem(1), 21 | padding: theme.spacing(1.25, 0), 22 | marginTop: theme.spacing(1), 23 | textTransform: 'uppercase', 24 | '&:first-child': { 25 | marginTop: 0, 26 | paddingTop: 0, 27 | }, 28 | }, 29 | }), 30 | { name: DescriptionListGroupHeadingStylesKey } 31 | ); 32 | 33 | export type DescriptionListGroupHeadingClasses = GetClasses; 34 | 35 | export type DescriptionListGroupHeadingProps = { 36 | className?: string; 37 | children?: React.ReactNode; 38 | }; 39 | 40 | export const DescriptionListGroupHeading: React.FC = ({ 41 | className, 42 | children, 43 | }) => { 44 | const classes = useStyles({}); 45 | return
  • {children}
  • ; 46 | }; 47 | -------------------------------------------------------------------------------- /src/components/DescriptionList/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | DescriptionList, 3 | DescriptionListClasses, 4 | DescriptionListProps, 5 | DescriptionListStylesKey, 6 | } from './DescriptionList'; 7 | 8 | export { 9 | DescriptionTerm, 10 | DescriptionTermClasses, 11 | DescriptionTermProps, 12 | DescriptionTermStylesKey, 13 | } from './DescriptionTerm'; 14 | 15 | export { 16 | DescriptionDetails, 17 | DescriptionDetailsClasses, 18 | DescriptionDetailsProps, 19 | DescriptionDetailsStylesKey, 20 | } from './DescriptionDetails'; 21 | 22 | export { 23 | DescriptionListGroupHeading, 24 | DescriptionListGroupHeadingClasses, 25 | DescriptionListGroupHeadingProps, 26 | DescriptionListGroupHeadingStylesKey, 27 | } from './DescriptionListGroupHeading'; 28 | 29 | export { 30 | DescriptionDivider, 31 | DescriptionDividerClasses, 32 | DescriptionDividerProps, 33 | DescriptionDividerStylesKey, 34 | } from './DescriptionDivider'; 35 | -------------------------------------------------------------------------------- /src/components/Divider/Divider.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, Meta } from '@storybook/react'; 3 | 4 | import { Divider } from './Divider'; 5 | 6 | const meta: Meta = { 7 | title: 'Layout/Divider', 8 | component: Divider, 9 | }; 10 | export default meta; 11 | type Story = StoryObj; 12 | 13 | export const Default: Story = {}; 14 | 15 | export const InverseDark: Story = { 16 | parameters: { 17 | backgrounds: { default: 'dark' }, 18 | }, 19 | args: { 20 | color: 'inverse', 21 | }, 22 | }; 23 | 24 | export const InverseBlue: Story = { 25 | parameters: { 26 | backgrounds: { default: 'blue' }, 27 | }, 28 | args: { 29 | color: 'inverse', 30 | }, 31 | }; 32 | 33 | export const Direction: Story = { 34 | args: { 35 | direction: 'row', 36 | }, 37 | decorators: [ 38 | (story: Function) =>
    {story()}
    , 39 | ], 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/Divider/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Divider, 3 | DividerProps, 4 | DividerClasses, 5 | DividerStylesKey, 6 | } from './Divider'; 7 | -------------------------------------------------------------------------------- /src/components/DotLoader/DotLoader.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, StoryFn, Meta } from '@storybook/react'; 3 | import { makeStyles } from '../../styles'; 4 | 5 | import { DotLoader } from './DotLoader'; 6 | 7 | const useStyles = makeStyles(() => ({ 8 | styledLoader: { 9 | fill: 'black', 10 | }, 11 | })); 12 | 13 | const meta: Meta = { 14 | title: 'Components/DotLoader', 15 | component: DotLoader, 16 | argTypes: {}, 17 | } as Meta; 18 | export default meta; 19 | type Story = StoryObj; 20 | 21 | const Template: StoryFn = (args) => { 22 | const classes = useStyles({}); 23 | return ; 24 | }; 25 | 26 | export const Default: Story = {}; 27 | 28 | export const Small: Story = { 29 | args: { 30 | size: 1, 31 | }, 32 | }; 33 | 34 | export const Styled: Story = { 35 | render: Template, 36 | }; 37 | -------------------------------------------------------------------------------- /src/components/DotLoader/DotLoader.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { renderWithTheme } from '../../testUtils/renderWithTheme'; 3 | import { DotLoader } from './'; 4 | 5 | const testId = 'DotLoader'; 6 | 7 | test('it renders a DotLoader', async () => { 8 | const { findByTestId, findByRole } = renderWithTheme( 9 | 10 | ); 11 | 12 | const root = await findByTestId(testId); 13 | expect(root).toBeInTheDocument(); 14 | 15 | const ariaRole = await findByRole('progressbar'); 16 | expect(ariaRole).toBeTruthy(); 17 | }); 18 | 19 | test('it renders a DotLoader with "size={0}"', async () => { 20 | const { findByTestId } = renderWithTheme( 21 | 22 | ); 23 | 24 | const root = await findByTestId(testId); 25 | expect(root).toHaveClass('ChromaDotLoader-size0'); 26 | }); 27 | 28 | test('it renders a DotLoader with "size={1}"', async () => { 29 | const { findByTestId } = renderWithTheme( 30 | 31 | ); 32 | 33 | const root = await findByTestId(testId); 34 | expect(root).toHaveClass('ChromaDotLoader-size1'); 35 | }); 36 | -------------------------------------------------------------------------------- /src/components/DotLoader/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | DotLoader, 3 | DotLoaderProps, 4 | DotLoaderStylesKey, 5 | DotLoaderClasses, 6 | } from './DotLoader'; 7 | -------------------------------------------------------------------------------- /src/components/ExpansionPanel/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ExpansionPanel, 3 | ExpansionPanelProps, 4 | ExpansionPanelClasses, 5 | ExpansionPanelStylesKey, 6 | } from './ExpansionPanel'; 7 | -------------------------------------------------------------------------------- /src/components/FormBox/FormBox.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StoryObj, StoryFn, Meta } from '@storybook/react'; 3 | 4 | import { FormBox } from './FormBox'; 5 | import { TextField } from '../TextField'; 6 | import { TextArea } from '../TextArea'; 7 | 8 | const meta: Meta = { 9 | title: 'Form Components/FormBox', 10 | component: FormBox, 11 | argTypes: {}, 12 | }; 13 | export default meta; 14 | type Story = StoryObj; 15 | 16 | const Template: StoryFn = (args) => ( 17 | 18 | 19 |