├── .github ├── CODEOWNERS └── workflows │ ├── deploy-storybook.yml │ ├── pull-request-ci.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── README.md ├── RFCs │ ├── 00000000_template.md │ └── README.md ├── assets │ ├── README.md │ ├── formatting_alignment.png │ ├── formatting_anatomy.png │ ├── formatting_sizes.png │ ├── formatting_spacing.png │ ├── icons_alignment.png │ ├── icons_card.png │ ├── icons_card_sizes.png │ ├── icons_illustrations.png │ ├── icons_pictogram.png │ ├── icons_pictogram_fill.png │ ├── icons_pictogram_sizes.png │ ├── icons_spacing.png │ ├── icons_system.png │ ├── icons_system_color-fills.png │ ├── icons_system_neutral-fills.png │ ├── icons_system_sizes.png │ ├── icons_third-party.png │ ├── icons_third-party_sizes.png │ ├── pr-canary-publish-dark.png │ ├── practices_cta-link-1.png │ ├── practices_cta-link-2.png │ ├── practices_danger-1.png │ ├── practices_danger-2.png │ ├── practices_external-link-1.png │ ├── practices_external-link-2.png │ ├── practices_primary-1.png │ ├── practices_primary-2.png │ ├── practices_secondary-1.png │ ├── practices_secondary-2.png │ ├── states_danger.png │ ├── states_primary.png │ ├── states_secondary.png │ ├── states_tertiary.png │ ├── types_cta-link.png │ ├── types_danger.png │ ├── types_external-link.png │ ├── types_primary.png │ ├── types_secondary.png │ └── types_tertiary.png ├── buttons.md ├── color.md └── icon.md ├── lerna.json ├── package.json ├── packages ├── design-tokens │ ├── CHANGELOG.md │ ├── README.md │ ├── config.json │ ├── package.json │ └── tokens │ │ ├── color │ │ ├── background.json │ │ ├── base.json │ │ ├── core.json │ │ ├── font.json │ │ ├── intent.json │ │ └── metrics.json │ │ ├── component │ │ ├── avatar.json │ │ ├── badge.json │ │ ├── button.json │ │ └── inline-alert.json │ │ └── type │ │ ├── family.json │ │ ├── size.json │ │ └── weight.json ├── eslint-config │ ├── .snyk │ ├── CHANGELOG.md │ ├── index.js │ └── package.json ├── icons │ ├── .svgo.yml │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── README.md │ ├── notests.js │ ├── package.json │ ├── src │ │ └── index.ts │ ├── svg │ │ ├── customFill │ │ │ ├── add.svg │ │ │ ├── arrow-down.svg │ │ │ ├── arrow-left.svg │ │ │ ├── arrow-right.svg │ │ │ ├── arrow-up.svg │ │ │ ├── backup.svg │ │ │ ├── bell.svg │ │ │ ├── billing.svg │ │ │ ├── calendar.svg │ │ │ ├── cancel-circle-filled.svg │ │ │ ├── cancel-circle.svg │ │ │ ├── cancel.svg │ │ │ ├── caret-down.svg │ │ │ ├── caret-filled-down.svg │ │ │ ├── caret-filled-right.svg │ │ │ ├── caret-left.svg │ │ │ ├── caret-right.svg │ │ │ ├── caret-up.svg │ │ │ ├── caution-filled.svg │ │ │ ├── caution.svg │ │ │ ├── check-circle-filled.svg │ │ │ ├── check-circle.svg │ │ │ ├── check.svg │ │ │ ├── circle-check-filled.svg │ │ │ ├── circle-filled.svg │ │ │ ├── cluster.svg │ │ │ ├── collapse.svg │ │ │ ├── comment.svg │ │ │ ├── copy.svg │ │ │ ├── credit-card.svg │ │ │ ├── doc.svg │ │ │ ├── download.svg │ │ │ ├── ellipsis-vertical.svg │ │ │ ├── ellipsis.svg │ │ │ ├── email.svg │ │ │ ├── envelope.svg │ │ │ ├── error-circle-filled.svg │ │ │ ├── error-circle.svg │ │ │ ├── expand.svg │ │ │ ├── eye-off.svg │ │ │ ├── eye.svg │ │ │ ├── folder.svg │ │ │ ├── gear-filled.svg │ │ │ ├── gear.svg │ │ │ ├── globe.svg │ │ │ ├── help-circle-filled.svg │ │ │ ├── help-circle.svg │ │ │ ├── info-circle-filled.svg │ │ │ ├── info-circle.svg │ │ │ ├── invalid.svg │ │ │ ├── lightbulb.svg │ │ │ ├── list.svg │ │ │ ├── loading.svg │ │ │ ├── location.svg │ │ │ ├── lock-filled.svg │ │ │ ├── lock.svg │ │ │ ├── minus-circle.svg │ │ │ ├── minus.svg │ │ │ ├── monitoring.svg │ │ │ ├── open.svg │ │ │ ├── org.svg │ │ │ ├── pencil.svg │ │ │ ├── play.svg │ │ │ ├── plus-circle-filled.svg │ │ │ ├── plus-circle.svg │ │ │ ├── plus.svg │ │ │ ├── refresh.svg │ │ │ ├── search.svg │ │ │ ├── sort-arrows.svg │ │ │ ├── stack.svg │ │ │ ├── star.svg │ │ │ ├── switch.svg │ │ │ ├── table.svg │ │ │ ├── terminal.svg │ │ │ ├── time.svg │ │ │ ├── trash.svg │ │ │ ├── user.svg │ │ │ └── world.svg │ │ └── preserveFill │ │ │ ├── amex.svg │ │ │ ├── australia.svg │ │ │ ├── aws.svg │ │ │ ├── azure.svg │ │ │ ├── bahrain.svg │ │ │ ├── belgium.svg │ │ │ ├── brazil.svg │ │ │ ├── canada.svg │ │ │ ├── chile.svg │ │ │ ├── community.svg │ │ │ ├── credit-card.svg │ │ │ ├── datadog.svg │ │ │ ├── dinersclub.svg │ │ │ ├── discover.svg │ │ │ ├── docs.svg │ │ │ ├── feature-flags.svg │ │ │ ├── finland.svg │ │ │ ├── france.svg │ │ │ ├── gcp.svg │ │ │ ├── germany.svg │ │ │ ├── github.svg │ │ │ ├── google.svg │ │ │ ├── hongkong.svg │ │ │ ├── india.svg │ │ │ ├── indonesia.svg │ │ │ ├── ireland.svg │ │ │ ├── israel.svg │ │ │ ├── italy.svg │ │ │ ├── japan.svg │ │ │ ├── jcb.svg │ │ │ ├── k3d.svg │ │ │ ├── korea.svg │ │ │ ├── learning.svg │ │ │ ├── magnifying-glass.svg │ │ │ ├── mastercard.svg │ │ │ ├── menu.svg │ │ │ ├── microsoft.svg │ │ │ ├── netherlands.svg │ │ │ ├── nodes.svg │ │ │ ├── norway.svg │ │ │ ├── not-found.svg │ │ │ ├── poland.svg │ │ │ ├── qatar.svg │ │ │ ├── singapore.svg │ │ │ ├── slack.svg │ │ │ ├── sleepy-moon.svg │ │ │ ├── south-africa.svg │ │ │ ├── spain.svg │ │ │ ├── sweden.svg │ │ │ ├── switzerland.svg │ │ │ ├── taiwan.svg │ │ │ ├── unionpay.svg │ │ │ ├── united-arab-emirates.svg │ │ │ ├── united-kingdom.svg │ │ │ ├── upload.svg │ │ │ ├── usa.svg │ │ │ ├── visa.svg │ │ │ └── zendesk.svg │ ├── tsconfig.esm.json │ └── tsconfig.json ├── storybook-ui-components │ ├── .babelrc.json │ ├── .gitignore │ ├── .storybook │ │ ├── cockroach-theme.js │ │ ├── main.js │ │ ├── manager.js │ │ ├── preview-head.html │ │ └── preview.ts │ ├── README.md │ ├── package.json │ ├── stories │ │ ├── Avatar.stories.tsx │ │ ├── Badge.stories.tsx │ │ ├── Button.stories.tsx │ │ ├── Charts.stories.tsx │ │ ├── ExpandableText.stories.tsx │ │ ├── FuzzyTime.stories.tsx │ │ ├── Icon.stories.tsx │ │ ├── InlineAlert.stories.tsx │ │ ├── Input.stories.tsx │ │ ├── Spinner.stories.tsx │ │ ├── Tooltip.stories.tsx │ │ ├── Typography.stories.tsx │ │ └── layout │ │ │ ├── Label.tsx │ │ │ ├── Sample.tsx │ │ │ ├── StoryContainer.tsx │ │ │ ├── StoryDescription.tsx │ │ │ └── index.ts │ ├── tsconfig.json │ └── utils │ │ └── selectKnobMirror.js └── ui-components │ ├── .eslintignore │ ├── .eslintrc.json │ ├── .hg │ ├── .npmignore │ ├── .npmrc │ ├── .sassrc.json │ ├── .yarnrc │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── jest.lint.config.js │ ├── jest.testing.config.js │ ├── package.json │ ├── prettier.config.js │ ├── src │ ├── Avatar │ │ ├── Avatar.module.scss │ │ ├── Avatar.test.tsx │ │ ├── Avatar.tsx │ │ └── README.md │ ├── Badge │ │ ├── Badge.module.scss │ │ ├── Badge.test.tsx │ │ ├── Badge.tsx │ │ ├── README.md │ │ └── __snapshots__ │ │ │ └── Badge.test.tsx.snap │ ├── Button │ │ ├── Button.module.scss │ │ ├── Button.test.tsx │ │ ├── Button.tsx │ │ └── README.md │ ├── Charts │ │ ├── README.md │ │ ├── barChart.module.scss │ │ ├── barChart.tsx │ │ └── helpers.ts │ ├── ExpandableText │ │ ├── ExpandableText.module.scss │ │ └── ExpandableText.tsx │ ├── FuzzyTime │ │ ├── FuzzyTime.module.scss │ │ ├── FuzzyTime.tsx │ │ ├── constants.ts │ │ ├── util.ts │ │ └── utils.test.ts │ ├── Icon │ │ ├── CreditCard.tsx │ │ ├── Flag.tsx │ │ ├── Icon.module.scss │ │ ├── Icon.test.tsx │ │ ├── Icon.tsx │ │ ├── Illustration.module.scss │ │ ├── Illustration.tsx │ │ ├── Pictogram.module.scss │ │ ├── Pictogram.tsx │ │ ├── ThirdPartyIcon.module.scss │ │ ├── ThirdPartyIcon.tsx │ │ ├── card.module.scss │ │ └── index.ts │ ├── InlineAlert │ │ ├── InlineAlert.module.scss │ │ ├── InlineAlert.test.tsx │ │ └── InlineAlert.tsx │ ├── Input │ │ ├── CheckboxInput.tsx │ │ ├── CommonInput.tsx │ │ ├── EmailPassword.module.scss │ │ ├── EmailPasswordInput.tsx │ │ ├── Field.tsx │ │ ├── NumberInput.tsx │ │ ├── README.md │ │ ├── TextTypeInput.tsx │ │ ├── constants.scss │ │ ├── helpers.tsx │ │ ├── index.ts │ │ ├── input.module.scss │ │ ├── input.test.tsx │ │ ├── number-input.scss │ │ └── styles.module.scss │ ├── README.md │ ├── Spinner │ │ ├── Spinner.module.scss │ │ ├── Spinner.test.tsx │ │ └── Spinner.tsx │ ├── Tooltip │ │ ├── README.md │ │ ├── Tooltip.module.scss │ │ ├── Tooltip.test.tsx │ │ └── Tooltip.tsx │ ├── Typography │ │ ├── Code.module.scss │ │ ├── Code.tsx │ │ ├── Heading.module.scss │ │ ├── Heading.tsx │ │ ├── Text.module.scss │ │ ├── Text.tsx │ │ └── index.ts │ ├── declaration.d.ts │ ├── index.ts │ ├── styles │ │ └── tokens.scss │ └── utils │ │ ├── README.md │ │ ├── isNumber.ts │ │ ├── objectToClassnames.test.ts │ │ ├── objectToClassnames.ts │ │ ├── upperCamelCase.test.ts │ │ └── upperCamelCase.ts │ ├── tsconfig.eslint.json │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── renovate.json5 /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://github.com/blog/2392-introducing-code-owners 2 | # https://help.github.com/articles/about-codeowners/ 3 | # 4 | # Code owners are automatically requested for review when someone 5 | # opens a pull request that modifies code that they own. 6 | # 7 | # Remember, *the last rule to match wins.* 8 | 9 | 10 | * @cockroachdb/CRUX 11 | /docs @annebirzin @rsadres 12 | -------------------------------------------------------------------------------- /.github/workflows/deploy-storybook.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Storybook 2 | 3 | # Controls when the action will run. Triggers the workflow on push 4 | # events where files change in the storybook-ui-components package 5 | # but only for the master branch 6 | on: 7 | push: 8 | branches: [master] 9 | paths: 10 | - "packages/storybook-ui-components/**" 11 | 12 | # Environment variables available to all jobs and steps in this workflow 13 | env: 14 | GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | build-and-deploy-storybook: 19 | if: ${{ github.repository_owner == 'cockroachdb'}} 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | strategy: 24 | matrix: 25 | node-version: [16.x] 26 | 27 | # Steps represent a sequence of tasks that will be executed as part of the job 28 | steps: 29 | - name: Authenticate on GCS 30 | uses: GoogleCloudPlatform/github-actions/setup-gcloud@master 31 | with: 32 | version: "270.0.0" 33 | service_account_key: ${{ secrets.GCP_SA_KEY }} 34 | 35 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 36 | - uses: actions/checkout@v2 37 | 38 | - name: Use Node.js ${{ matrix.node-version }} 39 | uses: actions/setup-node@v1 40 | with: 41 | node-version: ${{ matrix.node-version }} 42 | 43 | - name: Install dependencies and build packages 44 | run: yarn && yarn lerna run build 45 | 46 | - name: Build storybook 47 | run: yarn build-storybook 48 | working-directory: ./packages/storybook-ui-components 49 | 50 | - name: Deploy 51 | run: gsutil cp -r public/* gs://core-components.crdb.io 52 | working-directory: ./packages/storybook-ui-components 53 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-ci.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [16.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - uses: pnpm/action-setup@v2 17 | with: 18 | version: 8.6 19 | 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version: 16 23 | cache: "pnpm" 24 | 25 | - name: Install dependencies 26 | run: pnpm install --frozen-lockfile 27 | 28 | - name: Build packages 29 | run: pnpm build 30 | 31 | - name: Test packages 32 | run: pnpm test 33 | env: 34 | CI: true 35 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Based on https://intuit.github.io/auto/docs/build-platforms/github-actions 2 | name: Release 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | release: 12 | runs-on: ubuntu-latest 13 | if: ${{ !contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci') && !github.event.pull_request.head.repo.fork }} 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: pnpm/action-setup@v3 20 | with: 21 | version: 8.6 22 | 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: 16 26 | cache: "pnpm" 27 | env: 28 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 29 | 30 | - name: Install dependencies 31 | run: pnpm install --frozen-lockfile 32 | 33 | - name: Create Release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 37 | run: | 38 | pnpm build 39 | pnpm release 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File system 2 | .DS_Store 3 | 4 | # Package distribution 5 | dist 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # Dependency directories 16 | node_modules 17 | 18 | # Optional npm cache directory 19 | .npm 20 | 21 | # Optional eslint cache 22 | .eslintcache 23 | 24 | # Output of 'npm pack' 25 | *.tgz 26 | 27 | # Parcel build cache 28 | .parcel-cache 29 | 30 | # Yarn Integrity file 31 | .yarn-integrity 32 | 33 | # dotenv environment variables file 34 | .env 35 | .env.test 36 | 37 | # parcel-bundler cache (https://parceljs.org/) 38 | .cache 39 | 40 | # Local TODO lists 41 | TODO 42 | *.todo 43 | 44 | # Static generated site 45 | public 46 | .now 47 | 48 | # Dev environment 49 | .vscode 50 | 51 | # Icons 52 | # 53 | # We are ignoring the icon components because they are generated from svgs in 54 | # `icons/svgs` by @svgr/cli. See packages/icons/README.md for more info 55 | packages/icons/src/components/ 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 CockroachDB 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | Published assets for Cockroach Labs user interfaces 3 | 4 | This repository is a monorepo of published packages under the `@cockroachlabs` 5 | namespace on [npm](https://www.npmjs.com/). It contains code for packages: 6 | 7 | package | source 8 | --------|-------- 9 | [@cockroachlabs/eslint-config](https://www.npmjs.com/package/@cockroachlabs/eslint-config) | [`/packages/eslint-config`](https://github.com/cockroachdb/ui/tree/master/packages/design-tokens) 10 | [@cockroachlabs/design-tokens](https://www.npmjs.com/package/@cockroachlabs/design-tokens) | [`/packages/design-tokens`](https://github.com/cockroachdb/ui/tree/master/packages/design-tokens) 11 | [@cockroachlabs/icons](https://www.npmjs.com/package/@cockroachlabs/icons) | [`/packages/icons`](https://github.com/cockroachdb/ui/tree/master/packages/icons) 12 | [@cockroachlabs/ui-components](https://www.npmjs.com/package/@cockroachlabs/ui-components) | [`/packages/ui-components`](https://github.com/cockroachdb/ui/tree/master/packages/ui-components) 13 | 14 | ## storybook-ui-components 15 | To run storybook locally, it's required to build all dependent packages and then run Storybook itself: 16 | ``` 17 | pnpm install # install dependencies 18 | pnpm build # run `build` scrips for all workspaces 19 | pnpm --dir packages/storybook-ui-components start # run storybooks 20 | # -or- 21 | pnpm --dir packages/storybook-ui-components build-storybook # build a static version of storybooks 22 | ``` -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Docs 2 | 3 | This directory holds docs about shared frontend resources and frontend 4 | best practices at Cockroach Labs. 5 | 6 | ## Design system guidelines 7 | 8 | The design system docs provide guidance around how to use UI 9 | components (style, behavior, formatting, etc). 10 | 11 | These docs accompany the [Figma Design System file](https://www.figma.com/file/B5AtEGdRbW3VxiBdg62TB8Xw/CRDB-Design-System?node-id=0%3A1), 12 | which Product Designers use to design user interfaces. 13 | 14 | - [Buttons](https://github.com/cockroachdb/ui/blob/master/docs/buttons.md) 15 | - [Color](https://github.com/cockroachdb/ui/blob/master/docs/color.md) 16 | - [Icons](https://github.com/cockroachdb/ui/blob/master/docs/icon.md) 17 | -------------------------------------------------------------------------------- /docs/assets/README.md: -------------------------------------------------------------------------------- 1 | # Assets folder 2 | 3 | This is where we can store screenshot images for docs 4 | -------------------------------------------------------------------------------- /docs/assets/formatting_alignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/formatting_alignment.png -------------------------------------------------------------------------------- /docs/assets/formatting_anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/formatting_anatomy.png -------------------------------------------------------------------------------- /docs/assets/formatting_sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/formatting_sizes.png -------------------------------------------------------------------------------- /docs/assets/formatting_spacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/formatting_spacing.png -------------------------------------------------------------------------------- /docs/assets/icons_alignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_alignment.png -------------------------------------------------------------------------------- /docs/assets/icons_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_card.png -------------------------------------------------------------------------------- /docs/assets/icons_card_sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_card_sizes.png -------------------------------------------------------------------------------- /docs/assets/icons_illustrations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_illustrations.png -------------------------------------------------------------------------------- /docs/assets/icons_pictogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_pictogram.png -------------------------------------------------------------------------------- /docs/assets/icons_pictogram_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_pictogram_fill.png -------------------------------------------------------------------------------- /docs/assets/icons_pictogram_sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_pictogram_sizes.png -------------------------------------------------------------------------------- /docs/assets/icons_spacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_spacing.png -------------------------------------------------------------------------------- /docs/assets/icons_system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_system.png -------------------------------------------------------------------------------- /docs/assets/icons_system_color-fills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_system_color-fills.png -------------------------------------------------------------------------------- /docs/assets/icons_system_neutral-fills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_system_neutral-fills.png -------------------------------------------------------------------------------- /docs/assets/icons_system_sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_system_sizes.png -------------------------------------------------------------------------------- /docs/assets/icons_third-party.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_third-party.png -------------------------------------------------------------------------------- /docs/assets/icons_third-party_sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/icons_third-party_sizes.png -------------------------------------------------------------------------------- /docs/assets/pr-canary-publish-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/pr-canary-publish-dark.png -------------------------------------------------------------------------------- /docs/assets/practices_cta-link-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_cta-link-1.png -------------------------------------------------------------------------------- /docs/assets/practices_cta-link-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_cta-link-2.png -------------------------------------------------------------------------------- /docs/assets/practices_danger-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_danger-1.png -------------------------------------------------------------------------------- /docs/assets/practices_danger-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_danger-2.png -------------------------------------------------------------------------------- /docs/assets/practices_external-link-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_external-link-1.png -------------------------------------------------------------------------------- /docs/assets/practices_external-link-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_external-link-2.png -------------------------------------------------------------------------------- /docs/assets/practices_primary-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_primary-1.png -------------------------------------------------------------------------------- /docs/assets/practices_primary-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_primary-2.png -------------------------------------------------------------------------------- /docs/assets/practices_secondary-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_secondary-1.png -------------------------------------------------------------------------------- /docs/assets/practices_secondary-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/practices_secondary-2.png -------------------------------------------------------------------------------- /docs/assets/states_danger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/states_danger.png -------------------------------------------------------------------------------- /docs/assets/states_primary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/states_primary.png -------------------------------------------------------------------------------- /docs/assets/states_secondary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/states_secondary.png -------------------------------------------------------------------------------- /docs/assets/states_tertiary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/states_tertiary.png -------------------------------------------------------------------------------- /docs/assets/types_cta-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_cta-link.png -------------------------------------------------------------------------------- /docs/assets/types_danger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_danger.png -------------------------------------------------------------------------------- /docs/assets/types_external-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_external-link.png -------------------------------------------------------------------------------- /docs/assets/types_primary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_primary.png -------------------------------------------------------------------------------- /docs/assets/types_secondary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_secondary.png -------------------------------------------------------------------------------- /docs/assets/types_tertiary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cockroachdb/ui/ee6b0f0d614499fe1d9c74b849d58eb3983c5a54/docs/assets/types_tertiary.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "pnpm", 3 | "version": "independent", 4 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 5 | "useNx": false, 6 | "registry": "https://registry.npmjs.org" 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "devDependencies": { 5 | "auto": "11.1.6", 6 | "lerna": "^7.2.0" 7 | }, 8 | "scripts": { 9 | "start": "pnpm run --recursive --parallel start", 10 | "test": "pnpm run --recursive test", 11 | "build": "pnpm run --recursive build", 12 | "release": "auto shipit" 13 | }, 14 | "repository": "cockroachdb/ui", 15 | "author": "Cockroach Labs ", 16 | "auto": { 17 | "plugins": [ 18 | "npm" 19 | ], 20 | "noDefaultLabels": true, 21 | "labels": [ 22 | { 23 | "releaseType": "major", 24 | "name": "🤖 major" 25 | }, 26 | { 27 | "releaseType": "minor", 28 | "name": "🤖 minor" 29 | }, 30 | { 31 | "releaseType": "patch", 32 | "name": "🤖 patch" 33 | }, 34 | { 35 | "releaseType": "major", 36 | "name": "🤖 major" 37 | }, 38 | { 39 | "releaseType": "skip", 40 | "name": "🤖 skip-release" 41 | }, 42 | { 43 | "releaseType": "none", 44 | "name": ":memo: docs", 45 | "changelogTitle": "📝 Documentation" 46 | } 47 | ] 48 | }, 49 | "pnpm": { 50 | "overrides": { 51 | "@types/react-lines-ellipsis>@types/react": "17", 52 | "@types/recharts>@types/react": "17" 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/design-tokens/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.4.10 (Mon Oct 17 2022) 2 | 3 | #### ⚠️ Pushed to `master` 4 | 5 | - Publish ([@nathanstilwell](https://github.com/nathanstilwell)) 6 | - Publish ([@lassenordahl](https://github.com/lassenordahl)) 7 | - Publish ([@laurenbarker](https://github.com/laurenbarker)) 8 | 9 | #### Authors: 3 10 | 11 | - Lasse Nordahl ([@lassenordahl](https://github.com/lassenordahl)) 12 | - Lauren Barker ([@laurenbarker](https://github.com/laurenbarker)) 13 | - Nathan Stilwell ([@nathanstilwell](https://github.com/nathanstilwell)) 14 | -------------------------------------------------------------------------------- /packages/design-tokens/README.md: -------------------------------------------------------------------------------- 1 | # design-tokens 2 | 3 | Uses [style-dictionary](https://github.com/amzn/style-dictionary) to transform tokens defined in json into different formats. 4 | 5 | ## Install dependencies 6 | 7 | ``` 8 | pnpm install 9 | ``` 10 | 11 | ## Generate tokens from json 12 | 13 | ``` 14 | pnpm run build 15 | ``` 16 | 17 | ## Exported Tokens 18 | 19 | ### Sass 20 | 21 | `_tokens.scss` contains exported token values as Sass variables. 22 | 23 | ```sass 24 | @import "~@cockroachlabs/design-tokens/dist/web/tokens" 25 | 26 | .example { 27 | background-color: $color-background-button-primary-success-base; 28 | color: $color-font-button-primary-success-base; 29 | border-width: 1px; 30 | border-style: solid; 31 | border-color: $color-border-button-primary-success-base; 32 | } 33 | ``` 34 | 35 | ### Stylus 36 | 37 | `tokens.styl` contains exported token values as Stylus variables. 38 | 39 | ```stylus 40 | @require "~@cockroachlabs/design-tokens/dist/web/tokens" 41 | 42 | .example 43 | color $color-intent-success-4 44 | background-color $color-intent-success-1 45 | border-radius 3px 46 | ``` 47 | 48 | ### JavaScript 49 | 50 | `tokens.js` contains exported token values as JavaScript constants. 51 | 52 | ```jsx 53 | import { 54 | ColorFont1, 55 | ColorBaseBlue, 56 | ColorBasePurple, 57 | } from "@cockroachlabs/design-tokens"; 58 | 59 | // ... 60 | 61 | ; 66 | ``` 67 | 68 | a `tokens.d.ts` file is also generated to act as types for tokens for TypeScript support. 69 | -------------------------------------------------------------------------------- /packages/design-tokens/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": ["tokens/**/*.json"], 3 | "platforms": { 4 | "scss": { 5 | "transformGroup": "scss", 6 | "buildPath": "dist/web/", 7 | "files": [ 8 | { 9 | "destination": "_tokens.scss", 10 | "format": "scss/variables" 11 | } 12 | ] 13 | }, 14 | "stylus": { 15 | "transformGroup": "css", 16 | "buildPath": "dist/web/", 17 | "files": [ 18 | { 19 | "destination": "tokens.styl", 20 | "format": "stylus/variables" 21 | } 22 | ] 23 | }, 24 | "js": { 25 | "transformGroup": "js", 26 | "buildPath": "dist/web/", 27 | "files": [ 28 | { 29 | "format": "javascript/es6", 30 | "destination": "tokens.js" 31 | } 32 | ] 33 | }, 34 | "ts": { 35 | "transformGroup": "js", 36 | "buildPath": "dist/web/", 37 | "files": [ 38 | { 39 | "format": "javascript/es6", 40 | "destination": "tokens.d.ts" 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/design-tokens/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cockroachlabs/design-tokens", 3 | "version": "0.4.13", 4 | "description": "Design tokens for Cockroach Labs.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/cockroachdb/ui" 8 | }, 9 | "keywords": [ 10 | "tokens" 11 | ], 12 | "main": "dist/web/tokens.js", 13 | "types": "dist/web/tokens.d.ts", 14 | "scripts": { 15 | "build": "style-dictionary build", 16 | "clean": "style-dictionary clean" 17 | }, 18 | "license": "MIT", 19 | "devDependencies": { 20 | "style-dictionary": "3.7.2" 21 | }, 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "gitHead": "a77405daccfaf2d38cc08ef7c322172ee93776fd" 26 | } 27 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/color/background.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "background": { 4 | "base": { "value": "{color.base.white.value}" }, 5 | "success": { "value": "{color.base.green.value}" }, 6 | "error": { "value": "{color.base.red.value}" }, 7 | "warning": { "value": "{color.base.orange.value}" }, 8 | "info": { "value": "{color.base.blue.value}" }, 9 | "danger": { "value": "{color.base.red.value}" } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/color/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "base": { 4 | "white": { "value": "{color.core.neutral.0.value}" }, 5 | "black": { "value": "{color.core.neutral.9.value}" }, 6 | "blue": { "value": "{color.core.blue.3.value}" }, 7 | "purple": { "value": "{color.core.purple.3.value}" }, 8 | "green": { "value": "{color.core.green.3.value}" }, 9 | "yellow": { "value": "{color.core.yellow.3.value}" }, 10 | "orange": { "value": "{color.core.orange.3.value}" }, 11 | "red": { "value": "{color.core.red.3.value}" }, 12 | "primary": { "value": "{color.intent.primary.3.value}" }, 13 | "info": { "value": "{color.intent.info.3.value}" }, 14 | "success": { "value": "{color.intent.success.3.value}" }, 15 | "danger": { "value": "{color.intent.danger.3.value}" }, 16 | "warning": { "value": "{color.intent.warning.3.value}" } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/color/font.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "font": { 4 | "1": { "value": "{color.core.neutral.8.value}" }, 5 | "2": { "value": "{color.core.neutral.7.value}" }, 6 | "3": { "value": "{color.core.neutral.6.value}" }, 7 | "4": { "value": "{color.core.neutral.5.value}" }, 8 | "5": { "value": "{color.base.white.value}" }, 9 | 10 | "inverse": { 11 | "base": { "value": "{color.font.5.value}" } 12 | }, 13 | 14 | "link": { 15 | "base": { "value": "{color.base.blue.value}" }, 16 | "hover": { "value": "{color.core.blue.4.value}" }, 17 | 18 | "inverse": { 19 | "link": { "value": "{color.font.5.value}" } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/color/intent.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "intent": { 4 | "primary": { 5 | "1": { "value": "#e6ddff" }, 6 | "2": { "value": "#cbbcfc" }, 7 | "3": { "value": "#6933ff" }, 8 | "4": { "value": "#501fe5" }, 9 | "5": { "value": "#300d8f" } 10 | }, 11 | "neutral": { 12 | "0": { "value": "#ffffff" }, 13 | "1": { "value": "#f5f7fa" }, 14 | "2": { "value": "#e7ecf3" }, 15 | "3": { "value": "#d6dbe7" }, 16 | "4": { "value": "#c0c6d9" }, 17 | "5": { "value": "#7e89a9" }, 18 | "6": { "value": "#475872" }, 19 | "7": { "value": "#394455" }, 20 | "8": { "value": "#242a35" }, 21 | "9": { "value": "#060c12" } 22 | }, 23 | "info": { 24 | "1": { "value": "#e1ecff" }, 25 | "2": { "value": "#89b0ff" }, 26 | "3": { "value": "#0055ff" }, 27 | "4": { "value": "#0037a5" }, 28 | "5": { "value": "#0c1628" } 29 | }, 30 | "success": { 31 | "1": { "value": "#e3f5e0" }, 32 | "2": { "value": "#a5dd8d" }, 33 | "3": { "value": "#37a806" }, 34 | "4": { "value": "#237300" }, 35 | "5": { "value": "#123d00" } 36 | }, 37 | "danger": { 38 | "1": { "value": "#ffe9eb" }, 39 | "2": { "value": "#f8bfc6" }, 40 | "3": { "value": "#ff3b4e" }, 41 | "4": { "value": "#cd2939" }, 42 | "5": { "value": "#99000f" } 43 | }, 44 | "warning": { 45 | "1": { "value": "#fff4e1" }, 46 | "2": { "value": "#ffd099" }, 47 | "3": { "value": "#ffa53b" }, 48 | "4": { "value": "#b26000" }, 49 | "5": { "value": "#644004" } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/color/metrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "metrics": { 4 | "core": { 5 | "1": { "value": "#003ebd"}, 6 | "2": { "value": "#2aaf44"}, 7 | "3": { "value": "#00a2ff"}, 8 | "4": { "value": "#c813fe"}, 9 | "5": { "value": "#c9cc01"}, 10 | "6": { "value": "#26dcab"}, 11 | "7": { "value": "#050f6d"}, 12 | "8": { "value": "#e38c09"}, 13 | "9": { "value": "#d93946"} 14 | }, 15 | "light": { 16 | "1": { "value": "#eaf1ff"}, 17 | "2": { "value": "#e0fbe5"}, 18 | "3": { "value": "#e7f6ff"}, 19 | "4": { "value": "#f7edff"}, 20 | "5": { "value": "#f8f9e1"}, 21 | "6": { "value": "#d5faf0"}, 22 | "7": { "value": "#edefff"}, 23 | "8": { "value": "#fff0da"}, 24 | "9": { "value": "#ffe4e7"} 25 | }, 26 | "baseline": { 27 | "1": { "value": "#00997f"}, 28 | "2": { "value": "#b92dff"}, 29 | "3": { "value": "#3b4251"}, 30 | "4": { "value": "#458eff"} 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/component/avatar.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": { 3 | "avatar": { 4 | "background-color": { 5 | "default": { "value": "{color.intent.neutral.2.value}" }, 6 | "disabled": { "value": "{color.intent.neutral.2.value}" }, 7 | "pending": { "value": "{color.intent.warning.1.value}" }, 8 | "invalid": { "value": "{color.intent.danger.1.value}" }, 9 | "active": { "value": "{color.intent.info.1.value}" } 10 | }, 11 | "border-color": { 12 | "default": { "value": "{color.intent.neutral.7.value}" }, 13 | "pending": { "value": "{color.intent.warning.4.value}" }, 14 | "invalid": { "value": "{color.intent.danger.4.value}" }, 15 | "active": { "value": "{color.intent.info.3.value}" } 16 | }, 17 | "font-color": { 18 | "default": { "value": "{color.font.2.value}" }, 19 | "pending": { "value": "{color.core.orange.4.value}" }, 20 | "invalid": { "value": "{color.core.red.4.value}" }, 21 | "disabled": { "value": "{color.font.4.value}" }, 22 | "active": { "value": "{color.base.blue.value}" } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/component/badge.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": { 3 | "badge": { 4 | "background-color": { 5 | "neutral": { "value": "{color.intent.neutral.2.value}" }, 6 | "success": { "value": "{color.intent.success.1.value}" }, 7 | "warning": { "value": "{color.intent.warning.1.value}" }, 8 | "danger": { "value": "{color.intent.danger.1.value}" }, 9 | "info": { "value": "{color.intent.info.1.value}" } 10 | }, 11 | "border-color": { 12 | "default": { "value": "{color.intent.neutral.5.value}" } 13 | }, 14 | "font-color": { 15 | "neutral": { "value": "{color.intent.neutral.6.value}" }, 16 | "success": { "value": "{color.intent.success.4.value}" }, 17 | "warning": { "value": "{color.intent.warning.4.value}" }, 18 | "info": { "value": "{color.intent.info.4.value}" }, 19 | "danger": { "value": "{color.intent.danger.4.value}" } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/component/inline-alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": { 3 | "inline-alert": { 4 | "border-color": { 5 | "info": { "value": "{color.intent.info.3.value}" }, 6 | "danger": { "value": "{color.intent.danger.3.value}" }, 7 | "warning": { "value": "{color.intent.warning.3.value}" }, 8 | "success": { "value": "{color.intent.success.3.value}" } 9 | }, 10 | "background-color": { 11 | "info": { "value": "{color.intent.info.1.value}" }, 12 | "danger": { "value": "{color.intent.danger.1.value}" }, 13 | "warning": { "value": "{color.intent.warning.1.value}" }, 14 | "success": { "value": "{color.intent.success.1.value}" } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/type/family.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": { 3 | "family": { 4 | "ui": { 5 | "value": "\"Source Sans Pro\", sans-serif" 6 | }, 7 | "code": { 8 | "value": "\"Roboto Mono\", monospace" 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/type/size.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": { 3 | "size": { 4 | "font": { 5 | "small": { "value": "12px" }, 6 | "medium": { "value": "14px" }, 7 | "tall": { "value": "16px" }, 8 | "large": { "value": "20px" }, 9 | "x-large": { "value": "24px" }, 10 | "xx-large": { "value": "28px" } 11 | }, 12 | "line-height": { 13 | "tiny": { "value": "16px" }, 14 | "small": { "value": "20px" }, 15 | "regular": { "value": "24px" }, 16 | "large": { "value": "32px" }, 17 | "x-large": { "value": "48px" }, 18 | "xx-large": { "value": "64px" } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/design-tokens/tokens/type/weight.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": { 3 | "weight": { 4 | "bold": { "value": 700 }, 5 | "semi-bold": { "value": 600 }, 6 | "medium": { "value": 500 }, 7 | "regular": { "value": 400 } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/eslint-config/.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.15.0 3 | ignore: {} 4 | # patches apply the minimum changes required to fix a vulnerability 5 | patch: 6 | SNYK-JS-LODASH-567746: 7 | - '@typescript-eslint/parser > @typescript-eslint/typescript-estree > lodash': 8 | patched: '2020-06-18T15:55:18.686Z' 9 | - '@typescript-eslint/parser > @typescript-eslint/experimental-utils > @typescript-eslint/typescript-estree > lodash': 10 | patched: '2020-06-18T15:55:18.686Z' 11 | -------------------------------------------------------------------------------- /packages/eslint-config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v1.0.4 (Mon Oct 17 2022) 2 | 3 | #### ⚠️ Pushed to `master` 4 | 5 | - Publish ([@nathanstilwell](https://github.com/nathanstilwell)) 6 | - Publish ([@jocrl](https://github.com/jocrl)) 7 | - Publish ([@laurenbarker](https://github.com/laurenbarker)) 8 | 9 | #### Authors: 3 10 | 11 | - Josephine ([@jocrl](https://github.com/jocrl)) 12 | - Lauren Barker ([@laurenbarker](https://github.com/laurenbarker)) 13 | - Nathan Stilwell ([@nathanstilwell](https://github.com/nathanstilwell)) 14 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cockroachlabs/eslint-config", 3 | "version": "1.0.7", 4 | "description": "Shared eslint config for Cockroach Labs.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/cockroachdb/ui" 8 | }, 9 | "main": "index.js", 10 | "files": [ 11 | "index.js" 12 | ], 13 | "keywords": [ 14 | "eslint", 15 | "prettier" 16 | ], 17 | "license": "MIT", 18 | "dependencies": { 19 | "@typescript-eslint/parser": "6.7.0", 20 | "eslint-config-prettier": "8.6.0" 21 | }, 22 | "devDependencies": { 23 | "@snyk/protect": "1.1111.0", 24 | "eslint": "8.49.0", 25 | "typescript": "5.x" 26 | }, 27 | "peerDependencies": { 28 | "@typescript-eslint/eslint-plugin": ">=6.7.0", 29 | "eslint": ">=8", 30 | "eslint-plugin-prettier": "^4.0.0", 31 | "eslint-plugin-react": "^7.28.0", 32 | "eslint-plugin-react-hooks": "^4.3.0", 33 | "typescript": "5.x" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | }, 38 | "scripts": { 39 | "snyk-protect": "snyk-protect", 40 | "prepare": "snyk-protect" 41 | }, 42 | "snyk": true, 43 | "gitHead": "f9e7778c841194fa776c5dc45d62fb9caf408f22" 44 | } 45 | -------------------------------------------------------------------------------- /packages/icons/.svgo.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - removeAttrs: 3 | attrs: "fill" 4 | -------------------------------------------------------------------------------- /packages/icons/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.5.4 (Mon Oct 17 2022) 2 | 3 | #### ⚠️ Pushed to `master` 4 | 5 | - Publish ([@nathanstilwell](https://github.com/nathanstilwell)) 6 | - Publish ([@laurenbarker](https://github.com/laurenbarker)) 7 | 8 | #### Authors: 2 9 | 10 | - Lauren Barker ([@laurenbarker](https://github.com/laurenbarker)) 11 | - Nathan Stilwell ([@nathanstilwell](https://github.com/nathanstilwell)) 12 | -------------------------------------------------------------------------------- /packages/icons/notests.js: -------------------------------------------------------------------------------- 1 | console.log(` 2 | There are no tests here because this package contains no code. 3 | It is fully dependent on @svgr/cli. Please refer to their 4 | tests at https://github.com/gregberge/svgr/tree/master/packages/cli. 5 | `); 6 | -------------------------------------------------------------------------------- /packages/icons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cockroachlabs/icons", 3 | "version": "0.7.13", 4 | "description": "Icons for Cockroach UI exported as React Components", 5 | "files": [ 6 | "dist/" 7 | ], 8 | "main": "dist/cjs/index.js", 9 | "module": "dist/esm/index.js", 10 | "types": "dist/cjs/index.d.ts", 11 | "scripts": { 12 | "build": "run-s build:generate:stripfill build:generate:preserve build:typescript", 13 | "build:typescript": "run-p build:typescript:*", 14 | "build:typescript:cjs": "tsc -p tsconfig.json", 15 | "build:typescript:esm": "tsc -p tsconfig.esm.json", 16 | "build:generate:stripfill": "svgr --typescript --icon -d src/components svg/customFill", 17 | "build:generate:preserve": "svgr --typescript --icon --no-runtime-config -d src/components svg/preserveFill", 18 | "build:watch": "tsc --watch --preserveWatchOutput", 19 | "clean": "rimraf dist src/components", 20 | "test": "node notests.js", 21 | "start": "pnpm run build:watch" 22 | }, 23 | "license": "MIT", 24 | "devDependencies": { 25 | "@svgr/cli": "5.3.0", 26 | "@types/react": "17.0.53", 27 | "npm-run-all": "4.1.5", 28 | "react": "17.0.2", 29 | "rimraf": "3.0.2", 30 | "typescript": "5.x" 31 | }, 32 | "peerDependencies": { 33 | "react": "^17.0.2" 34 | }, 35 | "gitHead": "f9e7778c841194fa776c5dc45d62fb9caf408f22", 36 | "nathan-test": "foo" 37 | } 38 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/arrow-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/backup.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/bell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/billing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/cancel-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/cancel-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-filled-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-filled-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caret-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caution-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/caution.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/check-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/check-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/circle-check-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/cluster.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/credit-card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/doc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/ellipsis-vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/ellipsis.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/email.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/envelope.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/error-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/error-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/eye-off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/gear-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/help-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/help-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/info-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/info-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/invalid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/lock-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/minus-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/org.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/plus-circle-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/plus-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/sort-arrows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/switch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/table.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/terminal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/time.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/icons/svg/customFill/world.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/bahrain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/belgium.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/brazil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/canada.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/chile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/credit-card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/dinersclub.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/feature-flags.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/finland.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/france.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/gcp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/google.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/india.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/indonesia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/ireland.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/israel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/italy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/japan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/mastercard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/microsoft.svg: -------------------------------------------------------------------------------- 1 | MS-SymbolLockup -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/netherlands.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/norway.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/poland.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/qatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/slack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/south-africa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/spain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/sweden.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/switzerland.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/taiwan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/united-arab-emirates.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/united-kingdom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/usa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/visa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/icons/svg/preserveFill/zendesk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/icons/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm/", 5 | "module": "es2020" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/icons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "sourceMap": false, 5 | "noImplicitAny": true, 6 | "module": "commonjs", 7 | "moduleResolution": "Node", 8 | "target": "es2020", 9 | "jsx": "react", 10 | "esModuleInterop": true, 11 | "declaration": true, 12 | "outDir": "./dist/cjs/", 13 | "skipLibCheck": true, 14 | }, 15 | "exclude": [ 16 | "dist", 17 | ], 18 | } 19 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceType": "unambiguous", 3 | "presets": [ 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "targets": { 8 | "chrome": 100 9 | } 10 | } 11 | ], 12 | "@babel/preset-typescript" 13 | ], 14 | "plugins": [] 15 | } -------------------------------------------------------------------------------- /packages/storybook-ui-components/.gitignore: -------------------------------------------------------------------------------- 1 | /cockroach-data -------------------------------------------------------------------------------- /packages/storybook-ui-components/.storybook/cockroach-theme.js: -------------------------------------------------------------------------------- 1 | import { create } from "@storybook/theming"; 2 | 3 | // 4 | // See https://storybook.js.org/docs/react/configure/theming for details 5 | // 6 | 7 | export default create({ 8 | base: "light", 9 | fontBase: '"Source Sans Pro", sans-serif', 10 | fontCode: '"Roboto Mono", monospace', 11 | textColor: "black", 12 | textInverseColor: "rgba(255,255,255,0.9)", 13 | brandTitle: "Cockroach Labs", 14 | brandUrl: "https://cockroachlabs.com", 15 | }); 16 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ["../stories/**/*.stories.@(tsx|mdx)"], 3 | addons: [ "@storybook/addon-controls", "@storybook/addon-docs" ], 4 | framework: { 5 | name: "@storybook/react-webpack5", 6 | options: {}, 7 | }, 8 | async webpackFinal(config, { configType }) { 9 | if (configType === 'DEVELOPMENT') { 10 | // Silence some of the typical webpack spew when running in watch mode, 11 | // so that a top-level 'pnpm start' is still usable. 12 | config.infrastructureLogging = { 13 | ...config.infrastructureLogging, 14 | level: "error", 15 | }; 16 | } 17 | 18 | return config; 19 | }, 20 | 21 | docs: { 22 | autodocs: "tag", 23 | }, 24 | }; -------------------------------------------------------------------------------- /packages/storybook-ui-components/.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/addons"; 2 | import theme from "./cockroach-theme"; 3 | addons.setConfig({ 4 | theme: theme, 5 | }); 6 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | // .storybook/preview.ts 2 | import "@cockroachlabs/ui-components/dist/cjs/index.css" 3 | 4 | const preview = { 5 | parameters: {}, 6 | }; 7 | 8 | export default preview; 9 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/README.md: -------------------------------------------------------------------------------- 1 | # storybook-ui-components 2 | 3 | ![](https://github.com/cockroachdb/ui/workflows/Build%20and%20Deploy%20Storybook/badge.svg) 4 | 5 | A way to develop `@cockroachlabs/ui-components` in isolation. 6 | 7 | ## Deploy 8 | 9 | The [live site](https://core-components.crdb.io/) is hosted on GCP in a [Cloud Storage bucket](https://cloud.google.com/storage/docs/hosting-static-website) that is managed by the dev-inf team. 10 | 11 | When changes are merged into master it triggers a workflow that copies the `public` dir to the Cloud Storage bucket. The build and deploy workflow is managed with GitHub Actions. See [deploy-storybook.yml](../../.github/workflows/deploy-storybook.yml) for details. 12 | 13 | 14 | 15 | test .... 16 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storybook-ui-components", 3 | "version": "0.7.16", 4 | "description": "Storybook supporting ui-components as a component catalog", 5 | "main": "index.js", 6 | "private": true, 7 | "scripts": { 8 | "build-storybook": "storybook build -c .storybook -o public", 9 | "start": "storybook dev -p 6006" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/cockroachdb/ui.git" 14 | }, 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/cockroachdb/ui/issues" 18 | }, 19 | "homepage": "https://github.com/cockroachdb/ui#readme", 20 | "dependencies": { 21 | "@cockroachlabs/icons": "workspace:../icons", 22 | "@cockroachlabs/ui-components": "workspace:../ui-components", 23 | "ts-loader": "9.4.2", 24 | "typescript": "5.x" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "7.21.0", 28 | "@babel/preset-env": "^7.22.5", 29 | "@babel/preset-react": "^7.22.5", 30 | "@babel/preset-typescript": "^7.22.5", 31 | "@storybook/addon-actions": "7.0.20", 32 | "@storybook/addon-controls": "^7.0.20", 33 | "@storybook/addon-docs": "7.0.20", 34 | "@storybook/addon-knobs": "7.0.2", 35 | "@storybook/addon-links": "7.0.20", 36 | "@storybook/addons": "7.0.20", 37 | "@storybook/react": "7.0.20", 38 | "@storybook/react-webpack5": "7.0.20", 39 | "babel-loader": "8.3.0", 40 | "react": "17", 41 | "react-dom": "17", 42 | "storybook": "7.0.20", 43 | "ts-loader": "9.4.2", 44 | "webpack": "5.75.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/ExpandableText.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { ExpandableText } from "@cockroachlabs/ui-components"; 4 | 5 | const divWidth = "200px"; 6 | const fourLinetext = 7 | "Very very very very very very very very very very very very very very very very very very very long text."; 8 | 9 | export default { 10 | title: "ExpandableText", 11 | }; 12 | 13 | export const Default = () => ( 14 |
15 | 16 |
17 | ); 18 | 19 | export const _2Lines = () => ( 20 |
21 | 22 |
23 | ); 24 | 25 | _2Lines.story = { 26 | name: "2 lines", 27 | }; 28 | 29 | export const TextDoesNotExceedLines = () => ( 30 |
31 | 32 |
33 | ); 34 | 35 | TextDoesNotExceedLines.story = { 36 | name: "Text does not exceed lines", 37 | }; 38 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/layout/Label.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from "react"; 2 | 3 | const Label: FunctionComponent<{ children: string }> = ({ children }) => ( 4 |
5 | {children} 6 |
7 | ); 8 | 9 | export default Label; 10 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/layout/Sample.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent, ReactNode } from "react"; 2 | 3 | const Sample: FunctionComponent<{ children: ReactNode }> = ({ children }) => ( 4 |
{children}
5 | ); 6 | 7 | export default Sample; 8 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/layout/StoryContainer.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from "react"; 2 | 3 | const StoryContainer: FunctionComponent = ({ children }) => ( 4 |
11 | {children} 12 |
13 | ); 14 | 15 | export default StoryContainer; 16 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/layout/StoryDescription.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from "react"; 2 | 3 | const StoryDescription: FunctionComponent = ({ children }) => ( 4 |
12 | {children} 13 |
14 | ); 15 | 16 | export default StoryDescription; 17 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/stories/layout/index.ts: -------------------------------------------------------------------------------- 1 | export { default as StoryContainer } from "./StoryContainer"; 2 | export { default as StoryDescription } from "./StoryDescription"; 3 | export { default as Sample } from "./Sample"; 4 | export { default as Label } from "./Label"; 5 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "lib": ["es5", "es6", "es7", "es2017", "dom"], 6 | "esModuleInterop": true, 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "moduleResolution": "node", 11 | "rootDir": "stories", 12 | "baseUrl": "stories", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noImplicitAny": true, 17 | "strictNullChecks": true, 18 | "suppressImplicitAnyIndexErrors": true, 19 | "noUnusedLocals": true, 20 | "declaration": false, 21 | "allowSyntheticDefaultImports": true, 22 | "experimentalDecorators": true, 23 | "emitDecoratorMetadata": true 24 | }, 25 | "include": ["stories/**/*.tsx"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/storybook-ui-components/utils/selectKnobMirror.js: -------------------------------------------------------------------------------- 1 | const selectKnobMirror = arr => 2 | arr.reduce((m, item) => { 3 | m[item] = item; 4 | return m; 5 | }, {}); 6 | 7 | export default selectKnobMirror; 8 | -------------------------------------------------------------------------------- /packages/ui-components/.eslintignore: -------------------------------------------------------------------------------- 1 | *.config.js 2 | dist/ 3 | node_modules 4 | README.md 5 | *.scss 6 | -------------------------------------------------------------------------------- /packages/ui-components/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@cockroachlabs/eslint-config" 3 | } 4 | -------------------------------------------------------------------------------- /packages/ui-components/.hg: -------------------------------------------------------------------------------- 1 | # This is not a Mercurial repo. 2 | # 3 | # parcel 2.9.3 handles pnpm workspaces strangely, and walks the file system 4 | # upwards looking for a lockfile, a .git file or directory, or a .hg file or 5 | # directory: 6 | # 7 | # https://github.com/parcel-bundler/parcel/blob/5ac45672bb603841bf294c66019930be4354625a/packages/core/core/src/resolveOptions.js#L72 8 | # 9 | # Without this .hg file, parcel would continue walking to the root of this git 10 | # repo (../../ from here) and install dependencies there. We don't actually want 11 | # that, and would prefer if packages installed for a package were listed in that 12 | # package's dependencies. The presence of this file is enough to keep parcel 13 | # properly rooted within this workspace package, so this .hg file must remain. 14 | # I'm sorry for the confusing naming --- it seems like the least-bad option. 15 | # 16 | # There's an open issue in parcel to address this upstream, but it hasn't been 17 | # resolved as-of September 2023: 18 | # 19 | # https://github.com/parcel-bundler/parcel/issues/7206 -------------------------------------------------------------------------------- /packages/ui-components/.npmignore: -------------------------------------------------------------------------------- 1 | # this file 2 | .npmignore 3 | 4 | # all things git 5 | .git* 6 | 7 | # source 8 | src/ 9 | 10 | # source maps 11 | */**/*.js.map 12 | 13 | # eslint 14 | .eslintignore 15 | .eslintrc 16 | 17 | # project configs 18 | *.config.js 19 | tsconfig.json 20 | -------------------------------------------------------------------------------- /packages/ui-components/.npmrc: -------------------------------------------------------------------------------- 1 | access="public" 2 | -------------------------------------------------------------------------------- /packages/ui-components/.sassrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "includePaths": ["node_modules"], 3 | } 4 | -------------------------------------------------------------------------------- /packages/ui-components/.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | lastUpdateCheck 1597418531072 6 | version-tag-prefix "@cockroachlabs/ui-components@" 7 | -------------------------------------------------------------------------------- /packages/ui-components/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.3.11 (Mon Oct 17 2022) 2 | 3 | #### ⚠️ Pushed to `master` 4 | 5 | - Publish ([@nathanstilwell](https://github.com/nathanstilwell)) 6 | - v0.3.8-alpha.2 ([@actions-user](https://github.com/actions-user)) 7 | - v0.3.8-alpha.1 ([@actions-user](https://github.com/actions-user)) 8 | - v0.3.8-alpha.0 ([@actions-user](https://github.com/actions-user)) 9 | - Publish ([@lassenordahl](https://github.com/lassenordahl)) 10 | - v0.3.7-alpha.0 ([@actions-user](https://github.com/actions-user)) 11 | - Publish ([@jocrl](https://github.com/jocrl)) 12 | - v0.3.6-alpha.0 ([@actions-user](https://github.com/actions-user)) 13 | - v0.3.5-alpha.4 ([@actions-user](https://github.com/actions-user)) 14 | - v0.3.5-alpha.3 ([@actions-user](https://github.com/actions-user)) 15 | - v0.3.5-alpha.2 ([@actions-user](https://github.com/actions-user)) 16 | - v0.3.5-alpha.1 ([@actions-user](https://github.com/actions-user)) 17 | - Publish ([@laurenbarker](https://github.com/laurenbarker)) 18 | - v0.3.4-alpha.1 ([@actions-user](https://github.com/actions-user)) 19 | 20 | #### Authors: 5 21 | 22 | - [@actions-user](https://github.com/actions-user) 23 | - Josephine ([@jocrl](https://github.com/jocrl)) 24 | - Lasse Nordahl ([@lassenordahl](https://github.com/lassenordahl)) 25 | - Lauren Barker ([@laurenbarker](https://github.com/laurenbarker)) 26 | - Nathan Stilwell ([@nathanstilwell](https://github.com/nathanstilwell)) 27 | -------------------------------------------------------------------------------- /packages/ui-components/README.md: -------------------------------------------------------------------------------- 1 | # UI Components 2 | 3 | UI Components (`ui-components`) is a reusable component library. It provides the core components for the Cockroach design system. 4 | 5 | ``` 6 | npm install --save-dev @cockroachlabs/ui-components 7 | ``` 8 | 9 | Components are exported individually from the package, 10 | 11 | ```javascript 12 | import { Badge } from "@cockroachlabs/ui-components"; 13 | 14 | export default props => ( 15 |
16 | Cockroach UI Badge 17 |
18 | ); 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/ui-components/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projects: ["jest.testing.config.js", "jest.lint.config.js"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/ui-components/jest.lint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: "lint", 3 | runner: "jest-runner-eslint", 4 | testMatch: ["/src/**/*.{tsx,ts,js}"], 5 | }; 6 | -------------------------------------------------------------------------------- /packages/ui-components/jest.testing.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: "test", 3 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 4 | moduleNameMapper: { 5 | "\\.(css|scss)$": "identity-obj-proxy", 6 | }, 7 | roots: ["/src"], 8 | setupFilesAfterEnv: [ 9 | "@testing-library/jest-dom/extend-expect", 10 | ], 11 | testEnvironment: "jsdom", 12 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", 13 | transform: { 14 | "^.+\\.tsx?$": "ts-jest", 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/ui-components/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: "all", 3 | }; 4 | -------------------------------------------------------------------------------- /packages/ui-components/src/Avatar/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useMemo } from "react"; 2 | import classNames from "classnames/bind"; 3 | 4 | import styles from "./Avatar.module.scss"; 5 | import objectToClassnames from "../utils/objectToClassnames"; 6 | 7 | interface OwnAvatarProps { 8 | size?: AvatarSize; 9 | intent?: AvatarIntent; 10 | disabled?: boolean; 11 | selectable?: boolean; 12 | onClick?: () => void; 13 | transformCase?: AvatarCase; 14 | } 15 | 16 | type NativeDivProps = Omit< 17 | React.HTMLAttributes, 18 | keyof OwnAvatarProps 19 | >; 20 | 21 | export type AvatarProps = NativeDivProps & OwnAvatarProps; 22 | 23 | export type AvatarSize = "default" | "small"; 24 | export type AvatarIntent = "default" | "active" | "pending" | "invalid"; 25 | export type AvatarCase = "none" | "uppercase"; 26 | 27 | const cx = classNames.bind(styles); 28 | 29 | export const Avatar: React.FC = ({ 30 | children, 31 | className, 32 | intent = "default", 33 | size = "default", 34 | disabled = false, 35 | selectable = false, 36 | onClick, 37 | transformCase = "uppercase", 38 | ...rest 39 | }) => { 40 | const classnames = useMemo( 41 | () => 42 | cx( 43 | "avatar", 44 | objectToClassnames({ size, transformCase }), 45 | { 46 | disabled, 47 | selectable: !disabled && selectable, 48 | [`intent-${intent}`]: !disabled, 49 | }, 50 | className, 51 | ), 52 | [intent, size, disabled, selectable, transformCase, className], 53 | ); 54 | 55 | const onClickHandler = useCallback(() => { 56 | if (!disabled && onClick) { 57 | onClick(); 58 | } 59 | }, [onClick, disabled]); 60 | 61 | return ( 62 |
63 | {children} 64 |
65 | ); 66 | }; 67 | 68 | export default Avatar; 69 | -------------------------------------------------------------------------------- /packages/ui-components/src/Avatar/README.md: -------------------------------------------------------------------------------- 1 | [back to components](../README.md) 2 | 3 | # Avatar 4 | 5 | ## Properties 6 | #### children?: string 7 | Content of `Avatar`, can be any arbitrary text. 8 | The length of the text is not limited by component itself. 9 | It has to be truncated by user. 10 | ### size?: AvatarSize 11 | Available options: `"xs" | "s" | "m" | "l"` 12 | 13 | Default option: `"l"` 14 | 15 | Changes the size of avatar 16 | 17 | ### intent?: AvatarIntent 18 | Available options: `"default" | "active" | "pending" | "invalid"` 19 | 20 | Default option: `"default"` 21 | 22 | Changes the color palette of avatar 23 | 24 | ### disabled?: boolean 25 | Default option: `false` 26 | 27 | Disable avatar interaction, events handlers on click, and prevents discards `selectable` option 28 | 29 | ### selectable?: boolean 30 | Default option: `false` 31 | Applies visual styling when mouse hovering on Avatar 32 | 33 | ### onClick?: () => void 34 | Callback function to be called when click on Avatar. 35 | It can be called if `disabled` option isn't set to true. -------------------------------------------------------------------------------- /packages/ui-components/src/Badge/Badge.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .badge { 4 | border-radius: 3px; 5 | display: inline-block; 6 | font-size: 12px; 7 | line-height: 14px; 8 | padding: crl-gutters(0.625) crl-gutters(1); 9 | vertical-align: crl-gutters(0.5); 10 | text-align: center; 11 | white-space: nowrap; 12 | } 13 | 14 | .intent-neutral { 15 | background: $component-badge-background-color-neutral; 16 | color: $component-badge-font-color-neutral; 17 | } 18 | 19 | .intent-success { 20 | background: $component-badge-background-color-success; 21 | color: $component-badge-font-color-success; 22 | } 23 | 24 | .intent-warning { 25 | background: $component-badge-background-color-warning; 26 | color: $component-badge-font-color-warning; 27 | } 28 | 29 | .intent-danger { 30 | background: $component-badge-background-color-danger; 31 | color: $component-badge-font-color-danger; 32 | } 33 | 34 | .intent-info { 35 | background: $component-badge-background-color-info; 36 | color: $component-badge-font-color-info; 37 | } 38 | 39 | .noTransform { 40 | text-transform: none; 41 | } 42 | 43 | .transformCase-none { 44 | text-transform: none; 45 | } 46 | 47 | .transformCase-uppercase { 48 | text-transform: uppercase; 49 | } 50 | -------------------------------------------------------------------------------- /packages/ui-components/src/Badge/Badge.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | 4 | import Badge from "./Badge"; 5 | 6 | describe("Badge content", () => { 7 | const text = "intent test"; 8 | it("should render using children", () => { 9 | const { container } = render(child content); 10 | expect(container).toMatchSnapshot(); 11 | }); 12 | 13 | it("should should return empty div if children is empty", () => { 14 | const { container } = render(); 15 | expect(container).toMatchSnapshot(); 16 | }); 17 | 18 | describe("Badge Intent prop", () => { 19 | it("should render the component with neutral intent by default", () => { 20 | render({text}); 21 | expect(screen.getByText(text)).toHaveClass("intent-neutral"); 22 | }); 23 | 24 | it("should able to change the intent type", () => { 25 | const { rerender } = render({text}); 26 | 27 | // success 28 | rerender({text}); 29 | expect(screen.getByText(text)).toHaveClass("intent-success"); 30 | 31 | // warning 32 | rerender({text}); 33 | expect(screen.getByText(text)).toHaveClass("intent-warning"); 34 | 35 | // danger 36 | rerender({text}); 37 | expect(screen.getByText(text)).toHaveClass("intent-danger"); 38 | 39 | // info 40 | rerender({text}); 41 | expect(screen.getByText(text)).toHaveClass("intent-info"); 42 | }); 43 | }); 44 | 45 | it("should not tranform the text passed as a prop", () => { 46 | render({text}); 47 | expect(screen.getByText(text)).toHaveClass("transformCase-none"); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/ui-components/src/Badge/Badge.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from "react"; 2 | import classNames from "classnames/bind"; 3 | 4 | import objectToClassnames from "../utils/objectToClassnames"; 5 | 6 | import styles from "./Badge.module.scss"; 7 | 8 | export type BadgeCase = "none" | "uppercase"; 9 | export type BadgeIntent = "neutral" | "success" | "warning" | "danger" | "info"; 10 | 11 | interface OwnBadgeProps { 12 | intent?: BadgeIntent; 13 | transformCase?: BadgeCase; 14 | debug?: boolean; 15 | } 16 | type NativeDivProps = Omit< 17 | React.HTMLAttributes, 18 | keyof OwnBadgeProps 19 | >; 20 | 21 | export type BadgeProps = NativeDivProps & OwnBadgeProps; 22 | 23 | const cx = classNames.bind(styles); 24 | 25 | export const Badge: FunctionComponent = ({ 26 | intent = "neutral", 27 | transformCase = "uppercase", 28 | debug = false, 29 | children, 30 | className, 31 | ...props 32 | }) => { 33 | const classnames = cx( 34 | "badge", 35 | objectToClassnames({ intent, transformCase }), 36 | className, 37 | ); 38 | 39 | if (children !== undefined) { 40 | return ( 41 |
42 | {debug && ( 43 |
44 |             intent :: {intent}
45 |             transformCase :: {transformCase}
46 |           
47 | )} 48 | {children} 49 |
50 | ); 51 | } 52 | 53 | return null; 54 | }; 55 | 56 | export default Badge; 57 | -------------------------------------------------------------------------------- /packages/ui-components/src/Badge/README.md: -------------------------------------------------------------------------------- 1 | [back to components](../README.md) 2 | 3 | # Badge 4 | 5 | A Badge is a styled text element used to highlight informative elements or act as a label for other visual elements. 6 | 7 | ```javascript 8 | import React from "react"; 9 | import { Badge } from "@cockroachlabs/ui-components"; 10 | 11 | export const SomeExampleReact = () => ( 12 | Sample 2 13 | Successful sample 14 | Dangerous sample 15 | Meaningful Case Sample v10.3.7-Alpha.0876b
16 | ); 17 | ``` 18 | 19 | ## Properties 20 | 21 | These are the properties that can be provided to the `Badge` component. 22 | 23 | ### `children?: ReactNode` 24 | 25 | The content displayed inside the Badge. 26 | 27 | This prop is **optional**. 28 | 29 | ### `intent?: Enum("neutral", "success", "warning", "danger")` 30 | 31 | **default value: `neutral`** 32 | 33 | Intent will alter the visual style of the Badge by changing the `background-color` and `color` properties of the rendered element. 34 | 35 | This prop is **optional**. 36 | 37 | ### `transformCase?: Enum("uppercase", "none")` 38 | 39 | **default value: `uppercase`** 40 | 41 | This prop alters the letter case of the content of the Badge. The default value is uppercase, but can be set to `none` if the case of content is meaningful and should not be transformed. 42 | 43 | This prop is **optional**. 44 | -------------------------------------------------------------------------------- /packages/ui-components/src/Badge/__snapshots__/Badge.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Badge content should render using children 1`] = ` 4 |
5 |
8 | child content 9 |
10 |
11 | `; 12 | 13 | exports[`Badge content should should return empty div if children is empty 1`] = `
`; 14 | -------------------------------------------------------------------------------- /packages/ui-components/src/Button/README.md: -------------------------------------------------------------------------------- 1 | [back to components](../README.md) 2 | 3 | # Button 4 | 5 | A Button is a styled basic element to handle click-based user interactions. 6 | 7 | A Button can be rendered as any desired DOM or React element by passing in a tag or component name in the `as` prop. This allows it to be rendered as a common `button` element, an anchor, or a React Router `` component. 8 | 9 | ```javascript 10 | import React from "react"; 11 | import { Button } from "@cockroachlabs/ui-components"; 12 | 13 | export const ButtonExample = () => ( 14 | <> 15 | 16 | 17 | 18 | 19 | 20 | 23 | 26 | 27 | ); 28 | ``` 29 | 30 | ## Props 31 | 32 | |Name |Type |Default |Description | 33 | |---|---|---|---| 34 | | `as` | ElementType | `"button"` | Element to render as, could be "a", "div", "button", or a React Component | 35 | | `intent` | "primary"
| "success"
| "danger"
|"secondary"
|"tertiary"
| `"secondary"` | Controls general styling of button according to our color scheme. | 36 | | `size` | "standard"
| "small"
| `"standard"` | Controls size of button | 37 | | `fluid` | boolean | `false` | Determines whether button fills container width 38 | -------------------------------------------------------------------------------- /packages/ui-components/src/Charts/barChart.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .bar-chart { 4 | :global(.recharts-cartesian-axis-tick-value) { 5 | fill: black; 6 | padding-right: 4px; 7 | } 8 | 9 | :global(.recharts-cartesian-axis-line) { 10 | stroke: $color-core-neutral-3; 11 | stroke-width: 2px; 12 | } 13 | 14 | :global(.recharts-cartesian-axis-tick-line) { 15 | stroke: $color-core-neutral-3; 16 | stroke-width: 2px; 17 | } 18 | 19 | :global(.recharts-tooltip-wrapper) { 20 | border-radius: 6px; 21 | overflow: hidden; 22 | border: 0; 23 | outline: 0; 24 | background-color: $color-core-neutral-0; 25 | @include crl-depth(1); 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /packages/ui-components/src/Charts/helpers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ColorMetricsCore1, 3 | ColorMetricsCore2, 4 | ColorMetricsCore3, 5 | ColorMetricsCore4, 6 | ColorMetricsCore5, 7 | ColorMetricsCore6, 8 | ColorMetricsCore7, 9 | ColorMetricsCore8, 10 | ColorMetricsCore9, 11 | } from "@cockroachlabs/design-tokens"; 12 | 13 | export const METRIC_COLORS = [ 14 | ColorMetricsCore1, 15 | ColorMetricsCore2, 16 | ColorMetricsCore3, 17 | ColorMetricsCore4, 18 | ColorMetricsCore5, 19 | ColorMetricsCore6, 20 | ColorMetricsCore7, 21 | ColorMetricsCore8, 22 | ColorMetricsCore9, 23 | ]; 24 | -------------------------------------------------------------------------------- /packages/ui-components/src/ExpandableText/ExpandableText.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .anchor { 4 | color: $color-font-link-base; 5 | fill: $color-font-link-base; 6 | &:hover { 7 | color: $color-font-link-hover; 8 | fill: $color-font-link-hover; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/ui-components/src/FuzzyTime/FuzzyTime.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .fuzzy-time { 4 | font-size: 0.75rem; 5 | line-height: 1.25rem; 6 | letter-spacing: 0.01875rem; 7 | } 8 | -------------------------------------------------------------------------------- /packages/ui-components/src/FuzzyTime/FuzzyTime.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import { fuzzy } from "./util"; 5 | import styles from "./FuzzyTime.module.scss"; 6 | 7 | type OwnFuzzyProps = { 8 | timestamp: Date; 9 | }; 10 | 11 | export type FuzzyTimeProps = OwnFuzzyProps & 12 | React.HTMLAttributes; 13 | 14 | const cx = classnames.bind(styles); 15 | 16 | export const FuzzyTime: FunctionComponent = ({ 17 | timestamp, 18 | ...rest 19 | }) => { 20 | const timeago = fuzzy(timestamp); 21 | const classnames = cx("fuzzy-time"); 22 | 23 | return ( 24 | 25 | {timeago} 26 | 27 | ); 28 | }; 29 | 30 | export * from "./util"; 31 | export default FuzzyTime; 32 | -------------------------------------------------------------------------------- /packages/ui-components/src/FuzzyTime/constants.ts: -------------------------------------------------------------------------------- 1 | export const aSecond = 1000; 2 | export const aMinute = aSecond * 60; 3 | export const anHour = aMinute * 60; 4 | export const aDay = anHour * 24; 5 | export const aMonth = aDay * 30; 6 | export const aYear = aDay * 365; 7 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/CreditCard.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo, SVGProps } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import { Cards } from "@cockroachlabs/icons"; 5 | import styles from "./card.module.scss"; 6 | 7 | import objectToClassNames from "../utils/objectToClassnames"; 8 | 9 | export type CreditCardSize = "tiny" | "small" | "medium" | "large"; 10 | 11 | type OwnCreditCardProps = { 12 | creditCardName?: keyof typeof Cards; 13 | size?: CreditCardSize; 14 | }; 15 | 16 | export type CreditCardProps = SVGProps & OwnCreditCardProps; 17 | 18 | const cx = classnames.bind(styles); 19 | 20 | export const CreditCard = ({ 21 | creditCardName = "CreditCard", 22 | size = "small", 23 | className, 24 | ...props 25 | }: CreditCardProps) => { 26 | const classNames = useMemo( 27 | () => cx("card", objectToClassNames({ size }), className), 28 | [className, size], 29 | ); 30 | const Element = Cards[creditCardName]; 31 | 32 | if (Element == null) { 33 | return null; 34 | } 35 | 36 | return ; 37 | }; 38 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Icon.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .icon { 4 | fill: currentColor; 5 | 6 | &:disabled { 7 | pointer-events: none; 8 | } 9 | } 10 | 11 | .size-xx-large { 12 | height: 64px; 13 | width: 64px; 14 | } 15 | 16 | .size-x-large { 17 | height: 32px; 18 | width: 32px; 19 | } 20 | 21 | .size-large { 22 | height: 24px; 23 | width: 24px; 24 | } 25 | 26 | .size-medium { 27 | height: 20px; 28 | width: 20px; 29 | } 30 | 31 | .size-default, 32 | .size-small { 33 | height: 16px; 34 | width: 16px; 35 | } 36 | 37 | .size-x-small { 38 | height: 12px; 39 | width: 12px; 40 | } 41 | 42 | .size-tiny { 43 | height: 8px; 44 | width: 8px; 45 | } 46 | 47 | .fill-info { 48 | fill: $color-base-blue; 49 | } 50 | 51 | .fill-primary { 52 | fill: $color-base-purple; 53 | } 54 | 55 | .fill-success { 56 | fill: $color-base-green; 57 | } 58 | 59 | .fill-danger { 60 | fill: $color-base-red; 61 | } 62 | 63 | .fill-warning { 64 | fill: $color-base-orange; 65 | } 66 | 67 | .fill-inverted { 68 | fill: $color-base-white; 69 | } 70 | 71 | .fill-default { 72 | fill: $color-core-neutral-7; 73 | } 74 | 75 | .fill-disabled { 76 | fill: $color-core-neutral-5; 77 | 78 | &-light { 79 | fill: $color-core-neutral-4; 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import classNames from "classnames/bind"; 3 | 4 | import { SystemIcons } from "@cockroachlabs/icons"; 5 | import styles from "./Icon.module.scss"; 6 | 7 | import objectToClassnames from "../utils/objectToClassnames"; 8 | 9 | export type IconSize = 10 | | "tiny" 11 | | "x-small" 12 | | "small" 13 | | "default" 14 | | "medium" 15 | | "large" 16 | | "x-large" 17 | | "xx-large"; 18 | 19 | export type IconIntent = 20 | | "danger" 21 | | "default" 22 | | "info" 23 | | "primary" 24 | | "success" 25 | | "warning"; 26 | 27 | // The fill of an icon can be: 28 | // intent based (types are defined in IconIntent) 29 | // inverted (when the icon appears against a dark background) 30 | // disabled (for when the background is neutral-2) 31 | // disabled-light (for when the background is neutral-0) 32 | export type IconFill = IconIntent | "inverted" | "disabled" | "disabled-light"; 33 | 34 | type OwnIconProps = { 35 | iconName: keyof typeof SystemIcons; 36 | size?: IconSize; 37 | fill?: IconFill; 38 | }; 39 | 40 | const cx = classNames.bind(styles); 41 | 42 | type NativeIconProps = Omit, keyof OwnIconProps>; 43 | 44 | export type IconProps = NativeIconProps & OwnIconProps; 45 | 46 | export const Icon = ({ 47 | iconName, 48 | size = "default", 49 | fill = "default", 50 | className, 51 | ...props 52 | }: IconProps) => { 53 | const classnames = useMemo( 54 | () => cx("icon", objectToClassnames({ size, fill }), className), 55 | [className, size, fill], 56 | ); 57 | const Element = SystemIcons[iconName]; 58 | 59 | if (Element == null) { 60 | return null; 61 | } 62 | 63 | return ; 64 | }; 65 | 66 | export default Icon; 67 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Illustration.module.scss: -------------------------------------------------------------------------------- 1 | .illustration { 2 | height: 100%; 3 | max-height: 152px; 4 | max-width: 240px; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Illustration.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo, SVGProps } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import { Illustrations } from "@cockroachlabs/icons"; 5 | import styles from "./Illustration.module.scss"; 6 | 7 | type OwnIllustrationProps = { 8 | illustrationName: keyof typeof Illustrations; 9 | }; 10 | 11 | export type IllustrationProps = SVGProps & OwnIllustrationProps; 12 | 13 | const cx = classnames.bind(styles); 14 | 15 | export const Illustration = ({ 16 | illustrationName, 17 | className, 18 | ...props 19 | }: IllustrationProps) => { 20 | const classNames = useMemo(() => cx("illustration", className), [className]); 21 | 22 | const Element = Illustrations[illustrationName]; 23 | 24 | if (Element == null) { 25 | return null; 26 | } 27 | 28 | return ; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Pictogram.module.scss: -------------------------------------------------------------------------------- 1 | @import "@cockroachlabs/design-tokens/dist/web/_tokens.scss"; 2 | 3 | .size-small { 4 | height: 40px; 5 | width: 40px; 6 | } 7 | 8 | .size-medium { 9 | height: 48px; 10 | width: 48px; 11 | } 12 | 13 | .size-large { 14 | height: 56px; 15 | width: 56px; 16 | } 17 | 18 | .fill-default { 19 | fill: $color-core-neutral-5; 20 | } 21 | .fill-primary { 22 | fill: $color-base-purple; 23 | } 24 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/Pictogram.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import { Pictograms } from "@cockroachlabs/icons"; 5 | import styles from "./Pictogram.module.scss"; 6 | 7 | import objectToClassNames from "../utils/objectToClassnames"; 8 | 9 | export type PictogramSize = "small" | "medium" | "large"; 10 | export type PictogramFill = "default" | "primary"; 11 | 12 | type OwnPictogramProps = { 13 | pictogramName: keyof typeof Pictograms; 14 | size?: PictogramSize; 15 | fill?: PictogramFill; 16 | }; 17 | 18 | type NativePictogramProps = Omit< 19 | React.SVGProps, 20 | keyof OwnPictogramProps 21 | >; 22 | export type PictogramProps = NativePictogramProps & OwnPictogramProps; 23 | 24 | const cx = classnames.bind(styles); 25 | 26 | export const Pictogram = ({ 27 | pictogramName, 28 | size = "medium", 29 | fill = "default", 30 | className, 31 | ...props 32 | }: PictogramProps) => { 33 | const classNames = useMemo( 34 | () => cx("pictogram", objectToClassNames({ size, fill }), className), 35 | [className, size, fill], 36 | ); 37 | const Element = Pictograms[pictogramName]; 38 | 39 | if (Element == null) { 40 | return null; 41 | } 42 | 43 | return ; 44 | }; 45 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/ThirdPartyIcon.module.scss: -------------------------------------------------------------------------------- 1 | .size-tiny { 2 | height: 16px; 3 | width: 16px; 4 | } 5 | 6 | .size-small { 7 | height: 24px; 8 | width: 24px; 9 | } 10 | 11 | .size-medium { 12 | height: 32px; 13 | width: 32px; 14 | } 15 | 16 | .size-large { 17 | height: 48px; 18 | width: 48px; 19 | } 20 | 21 | .size-x-large { 22 | height: 56px; 23 | width: 56px; 24 | } 25 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/ThirdPartyIcon.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo, SVGProps } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import { ThirdParty } from "@cockroachlabs/icons"; 5 | import styles from "./ThirdPartyIcon.module.scss"; 6 | 7 | import objectToClassNames from "../utils/objectToClassnames"; 8 | 9 | export type ThirdPartySize = "tiny" | "small" | "medium" | "large" | "x-large"; 10 | 11 | type OwnThirdPartyIconProps = { 12 | iconName: keyof typeof ThirdParty; 13 | size?: ThirdPartySize; 14 | }; 15 | 16 | export type ThirdPartyIconProps = SVGProps & 17 | OwnThirdPartyIconProps; 18 | 19 | const cx = classnames.bind(styles); 20 | 21 | export const ThirdPartyIcon = ({ 22 | iconName, 23 | size = "large", 24 | className, 25 | ...props 26 | }: ThirdPartyIconProps) => { 27 | const classNames = useMemo( 28 | () => cx("icon", objectToClassNames({ size }), className), 29 | [className, size], 30 | ); 31 | const Element = ThirdParty[iconName]; 32 | 33 | if (Element == null) { 34 | return null; 35 | } 36 | 37 | return ; 38 | }; 39 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/card.module.scss: -------------------------------------------------------------------------------- 1 | .size-tiny { 2 | height: 16px; 3 | width: 16px; 4 | } 5 | .size-small { 6 | height: 24px; 7 | width: 24px; 8 | } 9 | .size-medium { 10 | height: 28px; 11 | width: 28px; 12 | } 13 | .size-large { 14 | height: 32px; 15 | width: 32px; 16 | } 17 | -------------------------------------------------------------------------------- /packages/ui-components/src/Icon/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CreditCard"; 2 | export * from "./Flag"; 3 | export * from "./Icon"; 4 | export * from "./Illustration"; 5 | export * from "./Pictogram"; 6 | export * from "./ThirdPartyIcon"; 7 | -------------------------------------------------------------------------------- /packages/ui-components/src/InlineAlert/InlineAlert.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .root { 4 | display: flex; 5 | flex-direction: row; 6 | flex-grow: 1; 7 | border-left: solid crl-gutters(0.5); 8 | border-radius: crl-gutters(0.5); 9 | padding: crl-gutters(1.5) crl-gutters(3) crl-gutters(1.5) 0; 10 | } 11 | 12 | .container { 13 | display: flex; 14 | flex-direction: column; 15 | flex-grow: 1; 16 | } 17 | 18 | .title { 19 | margin-bottom: 0px; 20 | } 21 | 22 | .icon-container { 23 | padding: 0 crl-gutters(2); 24 | display: flex; 25 | } 26 | 27 | .intent-info { 28 | border-left-color: $component-inline-alert-border-color-info; 29 | background-color: $component-inline-alert-background-color-info; 30 | } 31 | 32 | .intent-danger { 33 | border-left-color: $component-inline-alert-border-color-danger; 34 | background-color: $component-inline-alert-background-color-danger; 35 | } 36 | 37 | .intent-warning { 38 | border-left-color: $component-inline-alert-border-color-warning; 39 | background-color: $component-inline-alert-background-color-warning; 40 | } 41 | 42 | .intent-success { 43 | border-left-color: $component-inline-alert-border-color-success; 44 | background-color: $component-inline-alert-background-color-success; 45 | } 46 | -------------------------------------------------------------------------------- /packages/ui-components/src/InlineAlert/InlineAlert.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | import { InlineAlert, InlineAlertIntent } from "./InlineAlert"; 4 | 5 | describe("InlineAlert", () => { 6 | test("renders with correct intent", () => { 7 | const title = "Hello world!"; 8 | const alertIntents: InlineAlertIntent[] = [ 9 | "warning", 10 | "success", 11 | "danger", 12 | "info", 13 | ]; 14 | alertIntents.forEach((intent) => { 15 | const { container } = render( 16 | , 17 | ); 18 | expect(container.getElementsByClassName(`intent-${intent}`).length).toBe( 19 | 1, 20 | ); 21 | }); 22 | }); 23 | 24 | test("renders with provided title", () => { 25 | const title = "Hello world!"; 26 | render(); 27 | screen.getByText(title); 28 | }); 29 | 30 | test("renders with provided description", () => { 31 | const description = "Hello world!"; 32 | render(); 33 | screen.getByText(description); 34 | }); 35 | 36 | test("renders with provided title and description", () => { 37 | const title = "Hello world!"; 38 | const description = 39 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; 40 | render(); 41 | screen.getByText(title); 42 | screen.getByText(description); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/CheckboxInput.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames"; 3 | import { CommonInputProps, CommonInput } from "./CommonInput"; 4 | 5 | type CheckboxProps = React.InputHTMLAttributes; 6 | 7 | export type CheckboxInputProps = CommonInputProps & CheckboxProps; 8 | 9 | export const CheckboxInput = ({ 10 | id, 11 | className, 12 | error, 13 | invalid, 14 | label, 15 | ariaLabel, 16 | required, 17 | ...rest 18 | }: CheckboxInputProps) => { 19 | const inputProps = { 20 | id: id, 21 | className: classNames("crl-input", className, { 22 | invalid: error || invalid, 23 | }), 24 | ["aria-label"]: ariaLabel, 25 | ["aria-invalid"]: !!error || invalid, 26 | ["aria-required"]: required, 27 | ...rest, 28 | }; 29 | 30 | // this is the input field rendered by CommonInput 31 | const fieldInput = ( 32 |
33 | 34 | 35 |
36 | ); 37 | 38 | return ( 39 | 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/CommonInput.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames"; 3 | import "./input.module.scss"; 4 | import { FieldMetaState } from "react-final-form"; 5 | 6 | export interface CommonInputProps { 7 | // this should be the element containing the input 8 | fieldInput?: JSX.Element; 9 | className?: string; 10 | help?: string | JSX.Element; 11 | // derived from final form type 12 | // error is assigned a value of meta.error 13 | // which has type any 14 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 15 | error?: any; 16 | inline?: boolean; 17 | // FieldValue passed to meta is string for all TextTypeInputs 18 | // boolean for CheckboxInput, and number for NumberInput 19 | meta?: FieldMetaState; 20 | // following are used in Checkbox, TextType Inputs, which render CommonInput 21 | invalid?: boolean; 22 | label?: string | JSX.Element; 23 | ariaLabel?: string; 24 | } 25 | 26 | // a component defining how error and help messages 27 | // are shown in all input types 28 | export const CommonInput = ({ 29 | help, 30 | error, 31 | inline, 32 | fieldInput, 33 | className, 34 | }: CommonInputProps) => { 35 | const helpMsg = !help ? null :
{help}
; 36 | 37 | const errorMsg = 38 | !error || typeof error === "boolean" ? null : ( 39 |
{error}
40 | ); 41 | 42 | return ( 43 |
48 | {fieldInput} 49 |
50 | {errorMsg} 51 | {helpMsg} 52 |
53 |
54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/EmailPassword.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | .new-password-input-container { 4 | position: relative; 5 | margin-bottom: 16px; 6 | } 7 | 8 | .new-password-validation-container { 9 | display: flex; 10 | flex-flow: column wrap; 11 | list-style: none; 12 | margin-bottom: crl-gutters(3); 13 | padding: 0; 14 | } 15 | 16 | .new-password-validation-message { 17 | align-items: flex-start; 18 | display: flex; 19 | font-size: 12px; 20 | } 21 | 22 | .new-password-validation-label { 23 | padding-left: crl-gutters(0.75); 24 | } 25 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/NumberInput.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from "react"; 2 | import classNames from "classnames/bind"; 3 | import { CaretUp, CaretDown } from "@cockroachlabs/icons"; 4 | import { NumberInput, NumberProps } from "./TextTypeInput"; 5 | import styles from "./styles.module.scss"; 6 | import { InputPrefix, InputWrapper } from "./helpers"; 7 | 8 | const cx = classNames.bind(styles); 9 | 10 | export type NumberInputProps = NumberProps & { 11 | onChange?: (value: number) => void; 12 | initialValue: number; 13 | value: number; 14 | }; 15 | 16 | // Use NumberInput instead of this 17 | export const DeprecatedNumberInput = ({ 18 | onChange, 19 | value: outerValue, 20 | initialValue, 21 | prefix, 22 | invalid, 23 | disabled, 24 | ...props 25 | }: NumberInputProps) => { 26 | const [value, setValue] = useState(outerValue || initialValue || 0); 27 | const onSpinClickHandler = useCallback( 28 | (increase: -1 | 1) => () => { 29 | if (disabled) { 30 | return; 31 | } 32 | const nextValue = value + increase; 33 | setValue(nextValue); 34 | onChange(nextValue); 35 | }, 36 | [value, onChange, disabled], 37 | ); 38 | 39 | const spinButtonsGroupClassName = cx("spin-buttons-group"); 40 | const spinButton = cx("spin-button"); 41 | 42 | return ( 43 | 44 | {prefix} 45 | 51 |
52 | 58 | 64 |
65 |
66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/README.md: -------------------------------------------------------------------------------- 1 | [back to components](../README.md) 2 | 3 | # Input components 4 | 5 | Provides `` and `` realizations and `` 6 | unstyled base component to build own custom input components. 7 | 8 | ## Properties 9 | ### `initialValue?: string | number` 10 | Value to be displayed if no `value` is provided or nothing is entered by user. 11 | ### `value?: string | number` 12 | Value to be displayed in input element 13 | ### `onChange?: (value: string | number) => void;` 14 | Handler to be called when input value is changed by user 15 | ### `placeholder?: string;` 16 | Placeholder to be shown when no value is present 17 | ### `disabled?: boolean;` 18 | Disable input 19 | ### `invalid?: boolean;` 20 | Highlight input element with red borders to indicate that entered value is not acceptable. 21 | ### `prefixIcon?: ReactNode` 22 | Expects one of SVG icons (`@cockroachlabs/icons`) to be provided. 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/constants.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | $input-height: 40px; 4 | $input-border-spacing: 3px; 5 | $border-width: 1px; 6 | $input-number-width: 160px; 7 | $input-text-width: 280px; 8 | 9 | // state, hoverColor, focusColor 10 | $state-colors: 11 | "active" $color-core-neutral-5 $color-base-blue, 12 | "invalid" $color-base-red, 13 | "disabled" $color-font-4; 14 | 15 | @function exclBorderWidth($total-width: 0, $spacing: $input-border-spacing, $border: $border-width) { 16 | @return $total-width - ($border + $spacing) * 2; 17 | } 18 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/helpers.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames/bind"; 3 | import styles from "./styles.module.scss"; 4 | import { CommonInputProps } from "./CommonInput"; 5 | 6 | const cx = classNames.bind(styles); 7 | 8 | export type InputWrapperProps = Pick; 9 | 10 | export interface InputPrefixProps { 11 | className?: string; 12 | } 13 | 14 | export const InputPrefix: React.FC = ({ 15 | children, 16 | className, 17 | }) => { 18 | if (!children) { 19 | return null; 20 | } 21 | const classes = cx("prefix", className); 22 | return
{children}
; 23 | }; 24 | 25 | export const InputWrapper: React.FC = ({ 26 | children, 27 | className, 28 | invalid, 29 | }) => { 30 | const wrapperClassName = cx( 31 | "container", 32 | { 33 | active: !invalid, 34 | invalid: invalid, 35 | }, 36 | className, 37 | ); 38 | return
{children}
; 39 | }; 40 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Field"; 2 | export * from "./EmailPasswordInput"; 3 | export * from "./CheckboxInput"; 4 | export { SingleLineTextInput as TextInput, NumberInput } from "./TextTypeInput"; 5 | export type { TextInputProps, NumberProps } from "./TextTypeInput"; 6 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/input.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | import { TextInput } from "./index"; 4 | 5 | const INPUT_LABEL = "Test input"; 6 | 7 | describe("TextInput", () => { 8 | describe("Default props", () => { 9 | it("provides correct default values to inner element", () => { 10 | render(); 11 | const input = screen.getByLabelText(INPUT_LABEL); 12 | expect(input).toBeEnabled(); 13 | expect(input).not.toHaveValue(); 14 | expect(input).not.toHaveAttribute("className"); 15 | expect(input).not.toHaveAttribute("id"); 16 | }); 17 | }); 18 | describe("Style classes", () => { 19 | it("sets disabled prop when Input is disabled", () => { 20 | render(); 21 | expect(screen.getByLabelText(INPUT_LABEL)).toBeDisabled(); 22 | }); 23 | 24 | it("sets invalid prop when Input is disabled", () => { 25 | render(); 26 | expect(screen.getByLabelText(INPUT_LABEL)).toBeInvalid(); 27 | }); 28 | }); 29 | }); 30 | 31 | describe("Input with prefixed Icon", () => { 32 | it("renders Icon with TextInput component", () => { 33 | render(Suffix
} />); 34 | screen.getByText("Suffix"); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/ui-components/src/Input/styles.module.scss: -------------------------------------------------------------------------------- 1 | @import "./input.module.scss"; 2 | @import "./number-input.scss"; 3 | -------------------------------------------------------------------------------- /packages/ui-components/src/README.md: -------------------------------------------------------------------------------- 1 | # ui-components 2 | 3 | Documentation and examples for all components can be found at: https://core-components.crdb.io/. 4 | 5 | - [Avatar](Avatar/README.md) 6 | - [Badge](Badge/README.md) 7 | - [Button](Button/README.md) 8 | - [Icon](Icon/README.md) 9 | - [Input](Input/README.md) 10 | - [Tooltip](Tooltip/README.md) 11 | -------------------------------------------------------------------------------- /packages/ui-components/src/Spinner/Spinner.module.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/tokens.scss"; 2 | 3 | // stroke values depend on viewBox of svg file (viewBox="0 0 100 100") 4 | svg.spinner { 5 | circle { 6 | fill: transparent; 7 | stroke: $color-core-neutral-6; 8 | stroke-linecap: round; 9 | stroke-dasharray: 220; 10 | stroke-dashoffset: 280; 11 | stroke-width: 10px; 12 | transform-origin: 50% 50%; 13 | animation: spinner 3s linear infinite; 14 | } 15 | 16 | &.fill-info circle { 17 | stroke: $color-base-blue; 18 | } 19 | 20 | &.fill-primary circle { 21 | stroke: $color-base-purple; 22 | } 23 | 24 | &.fill-success circle { 25 | stroke: $color-base-green; 26 | } 27 | 28 | &.fill-danger circle { 29 | stroke: $color-base-red; 30 | } 31 | &.fill-warning circle { 32 | stroke: $color-base-orange; 33 | } 34 | &.fill-inverted circle { 35 | stroke: $color-base-white; 36 | } 37 | } 38 | 39 | .size-default { 40 | width: 40px; 41 | height: 40px; 42 | } 43 | 44 | .size-x-small { 45 | width: 12px; 46 | height: 12px; 47 | } 48 | 49 | .size-small { 50 | width: 16px; 51 | height: 16px; 52 | } 53 | .size-medium { 54 | width: 24px; 55 | height: 24px; 56 | } 57 | 58 | .size-large { 59 | width: 64px; 60 | height: 64px; 61 | } 62 | 63 | @keyframes spinner { 64 | 0% { 65 | stroke-dashoffset: 25; 66 | transform: rotate(0deg); 67 | } 68 | 69 | 50% { 70 | stroke-dashoffset: 125; 71 | transform: rotate(720deg); 72 | } 73 | 74 | 100% { 75 | stroke-dashoffset: 25; 76 | transform: rotate(1080deg); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/ui-components/src/Spinner/Spinner.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | import { Spinner, SpinnerSize } from "./Spinner"; 4 | 5 | const spinnerSizes: SpinnerSize[] = ["default", "small", "large"]; 6 | 7 | describe("Spinner", () => { 8 | test("renders on a screen", () => { 9 | render(); 10 | screen.getByLabelText("Loading..."); 11 | }); 12 | 13 | spinnerSizes.forEach((size) => { 14 | test(`renders with provided ${size} size`, () => { 15 | const { container } = render(); 16 | expect(container.getElementsByClassName(`size-${size}`).length).toBe(1); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/ui-components/src/Spinner/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classNames from "classnames/bind"; 3 | import styles from "./Spinner.module.scss"; 4 | import objectToClassnames from "../utils/objectToClassnames"; 5 | import { IconIntent } from "../Icon"; 6 | 7 | const cx = classNames.bind(styles); 8 | 9 | export type SpinnerSize = "default" | "large" | "medium" | "small" | "x-small"; 10 | 11 | export type SpinnerFill = IconIntent | "inverted"; 12 | 13 | type OwnSpinnerProps = { 14 | size?: SpinnerSize; 15 | fill?: SpinnerFill; 16 | className?: string; 17 | }; 18 | 19 | type NativeSpinnerProps = Omit< 20 | React.SVGProps, 21 | keyof OwnSpinnerProps 22 | >; 23 | 24 | export type SpinnerProps = NativeSpinnerProps & OwnSpinnerProps; 25 | 26 | export const Spinner: React.FC = ({ 27 | size = "default", 28 | fill = "default", 29 | className, 30 | "aria-label": ariaLabel = "Loading...", 31 | ...props 32 | }) => { 33 | const classNames = cx( 34 | "spinner", 35 | objectToClassnames({ size, fill }), 36 | className, 37 | ); 38 | return ( 39 | 47 | 59 | 60 | ); 61 | }; 62 | -------------------------------------------------------------------------------- /packages/ui-components/src/Tooltip/README.md: -------------------------------------------------------------------------------- 1 | [back to components](../README.md) 2 | 3 | # Tooltip 4 | 5 | A Tooltip is a styled popover element that can be shown on hover. 6 | 7 | ```javascript 8 | import React from "react"; 9 | import { Tooltip } from "@cockroachlabs/ui-components"; 10 | 11 | export const SomeExampleReact = () => ( 12 | 13 |
hover me
14 |
15 | ); 16 | ``` 17 | 18 | ## Properties 19 | 20 | These are the properties that can be provided to the `Tooltip` component. 21 | 22 | ### `children: ReactNode | text` 23 | 24 | The content hover on what will trigger display of tooltip. 25 | 26 | This prop is **required**. 27 | 28 | ### `position?: Enum("left", "left-start", "left-end", "right", "right-start", "right-end", "top", "top-start", "top-end", "bottom", "bottom-start","bottom-end")` 29 | 30 | **default value: `bottom`** 31 | 32 | Placement of tooltip around anchor content. 33 | 34 | This prop is **optional**. 35 | 36 | ### `style?: Enum("default", "light", "dark", "tableTitle")` 37 | 38 | **default value: `default`** 39 | 40 | Will alter the visual style of the Tooltip by changing the `background-color`, `color`, `border-color` properties of the rendered element. 41 | 42 | This prop is **optional**. 43 | 44 | ### `visible?: boolean` 45 | 46 | **default value: `false`** 47 | 48 | Force tooltip stay visible. 49 | 50 | This prop is **optional**. -------------------------------------------------------------------------------- /packages/ui-components/src/Tooltip/Tooltip.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen, waitFor, fireEvent } from "@testing-library/react"; 3 | 4 | import { Tooltip } from "./Tooltip"; 5 | 6 | const TRIGGER_TEXT = "hover trigger"; 7 | const HOVER_TEXT = "hover text"; 8 | 9 | const TooltipExample = ( 10 | {HOVER_TEXT}}> 11 |
{TRIGGER_TEXT}
12 |
13 | ); 14 | 15 | describe("Tooltip", () => { 16 | it("is shown on hover", () => { 17 | render(TooltipExample); 18 | expect(screen.getByText(HOVER_TEXT)).not.toHaveAttribute("data-show"); 19 | fireEvent.mouseOver(screen.getByText(TRIGGER_TEXT)); 20 | waitFor(() => { 21 | expect(screen.getByText(HOVER_TEXT)).toHaveAttribute("data-show"); 22 | }); 23 | }); 24 | 25 | it("is not shown on hover if content is empty", () => { 26 | const { container } = render( 27 | 28 |
{TRIGGER_TEXT}
29 |
, 30 | ); 31 | expect(container.querySelector('[data-jest="tooltip"]')).toBeNull(); 32 | fireEvent.mouseOver(screen.getByText(TRIGGER_TEXT)); 33 | expect(container.querySelector('[data-jest="tooltip"]')).toBeNull(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Code.module.scss: -------------------------------------------------------------------------------- 1 | @import "@cockroachlabs/design-tokens/dist/web/_tokens.scss"; 2 | 3 | .code { 4 | font-family: $type-family-code; 5 | font-size: $type-size-font-medium; 6 | letter-spacing: 0em; 7 | line-height: $type-size-line-height-regular; 8 | } 9 | 10 | .weight-regular { 11 | font-weight: $type-weight-regular; 12 | } 13 | 14 | .weight-medium { 15 | font-weight: $type-weight-medium; 16 | } 17 | 18 | .weight-bold { 19 | font-weight: $type-weight-bold; 20 | } 21 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Code.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import styles from "./Code.module.scss"; 5 | import objectToClassNames from "../utils/objectToClassnames"; 6 | 7 | interface OwnCodeProps { 8 | weight?: CodeWeight; 9 | } 10 | 11 | export type CodeProps = React.HTMLAttributes & OwnCodeProps; 12 | 13 | export type CodeWeight = "regular" | "medium" | "bold"; 14 | 15 | const cx = classnames.bind(styles); 16 | 17 | export const Code = ({ 18 | weight = "regular", 19 | className = "", 20 | children, 21 | ...rest 22 | }: CodeProps) => { 23 | const classNames = useMemo( 24 | () => cx("code", objectToClassNames({ weight }), className), 25 | [className, weight], 26 | ); 27 | 28 | return ( 29 | 30 | {children} 31 | 32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Heading.module.scss: -------------------------------------------------------------------------------- 1 | @import "@cockroachlabs/design-tokens/dist/web/_tokens.scss"; 2 | 3 | .type-h1 { 4 | font-family: $type-family-ui; 5 | font-size: $type-size-font-xx-large; 6 | line-height: $type-size-line-height-xx-large; 7 | font-weight: $type-weight-regular; 8 | } 9 | 10 | .type-h2 { 11 | font-family: $type-family-ui; 12 | font-size: $type-size-font-x-large; 13 | line-height: $type-size-line-height-x-large; 14 | font-weight: $type-weight-semi-bold; 15 | } 16 | 17 | .type-h3 { 18 | font-family: $type-family-ui; 19 | font-size: $type-size-font-large; 20 | line-height: $type-size-line-height-large; 21 | font-weight: $type-weight-semi-bold; 22 | } 23 | 24 | .type-h4 { 25 | font-family: $type-family-ui; 26 | font-size: $type-size-font-tall; 27 | line-height: $type-size-line-height-regular; 28 | font-weight: $type-weight-regular; 29 | } 30 | 31 | .type-h5 { 32 | font-family: $type-family-ui; 33 | font-size: $type-size-font-tall; 34 | line-height: $type-size-line-height-regular; 35 | font-weight: $type-weight-semi-bold; 36 | } 37 | 38 | .type-h6 { 39 | font-family: $type-family-ui; 40 | font-size: $type-size-font-small; 41 | line-height: $type-size-line-height-tiny; 42 | font-weight: $type-weight-semi-bold; 43 | text-transform: uppercase; 44 | } 45 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Heading.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import styles from "./Heading.module.scss"; 5 | import objectToClassNames from "../utils/objectToClassnames"; 6 | 7 | interface OwnHeadingProps { 8 | type: HeadingType; 9 | } 10 | 11 | export type HeadingProps = React.HTMLAttributes & 12 | OwnHeadingProps; 13 | 14 | export type HeadingType = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; 15 | 16 | const cx = classnames.bind(styles); 17 | 18 | export const Heading = ({ 19 | type, 20 | className, 21 | children, 22 | ...props 23 | }: HeadingProps) => { 24 | const classNames = useMemo( 25 | () => cx(objectToClassNames({ type }), className), 26 | [className, type], 27 | ); 28 | 29 | return React.createElement( 30 | type, 31 | { className: classNames, ...props }, 32 | children, 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Text.module.scss: -------------------------------------------------------------------------------- 1 | @import "@cockroachlabs/design-tokens/dist/web/_tokens.scss"; 2 | 3 | .type-body { 4 | font-family: $type-family-ui; 5 | font-size: $type-size-font-medium; 6 | line-height: $type-size-line-height-regular; 7 | font-weight: $type-weight-regular; 8 | } 9 | 10 | .type-body-strong { 11 | font-family: $type-family-ui; 12 | font-size: $type-size-font-medium; 13 | line-height: $type-size-line-height-regular; 14 | font-weight: $type-weight-semi-bold; 15 | letter-spacing: 0.02em; 16 | } 17 | 18 | .type-caption { 19 | font-family: $type-family-ui; 20 | font-size: $type-size-font-small; 21 | line-height: $type-size-line-height-small; 22 | font-weight: $type-weight-regular; 23 | letter-spacing: 0.02em; 24 | } 25 | 26 | .type-caption-strong { 27 | font-family: $type-family-ui; 28 | font-size: $type-size-font-small; 29 | line-height: $type-size-line-height-small; 30 | font-weight: $type-weight-semi-bold; 31 | letter-spacing: 0.02em; 32 | } 33 | 34 | .type-code { 35 | font-family: $type-family-code; 36 | font-size: $type-size-font-small; 37 | line-height: $type-size-line-height-small; 38 | font-weight: $type-weight-semi-bold; 39 | letter-spacing: normal; 40 | } 41 | 42 | .type-error { 43 | font-family: $type-family-ui; 44 | font-size: $type-size-font-small; 45 | line-height: $type-size-line-height-tiny; 46 | font-weight: $type-weight-semi-bold; 47 | color: $color-base-red; 48 | letter-spacing: 0.02em; 49 | } 50 | 51 | .no-wrap { 52 | display: inline-block; 53 | text-overflow: ellipsis; 54 | white-space: nowrap; 55 | overflow: hidden; 56 | width: 100%; 57 | } 58 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/Text.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import classnames from "classnames/bind"; 3 | 4 | import styles from "./Text.module.scss"; 5 | import objectToClassNames from "../utils/objectToClassnames"; 6 | 7 | interface OwnTextProps { 8 | type?: TextType; 9 | noWrap?: boolean; 10 | } 11 | 12 | export type TextProps = React.HTMLAttributes & OwnTextProps; 13 | 14 | export type TextType = 15 | | "body" 16 | | "body-strong" 17 | | "caption" 18 | | "caption-strong" 19 | | "code"; 20 | 21 | const cx = classnames.bind(styles); 22 | 23 | export const Text = ({ 24 | type = "body", 25 | noWrap = false, 26 | className, 27 | children, 28 | ...rest 29 | }: TextProps) => { 30 | const classNames = useMemo( 31 | () => cx(objectToClassNames({ type }), { "no-wrap": noWrap }, className), 32 | [type, noWrap, className], 33 | ); 34 | 35 | return ( 36 | 37 | {children} 38 | 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /packages/ui-components/src/Typography/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Text"; 2 | export * from "./Heading"; 3 | export * from "./Code"; 4 | -------------------------------------------------------------------------------- /packages/ui-components/src/declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.module.scss" { 2 | const content: { [className: string]: string }; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /packages/ui-components/src/index.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export * from "./Avatar/Avatar"; 3 | export * from "./Badge/Badge"; 4 | export * from "./Button/Button"; 5 | export * from "./Input/"; 6 | export * from "./Tooltip/Tooltip"; 7 | export * from "./Icon/"; 8 | export * from "./FuzzyTime/FuzzyTime"; 9 | export * from "./InlineAlert/InlineAlert"; 10 | export * from "./ExpandableText/ExpandableText"; 11 | export * from "./Spinner/Spinner"; 12 | export * from "./Typography/"; 13 | export * from "./Charts/barChart"; 14 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/README.md: -------------------------------------------------------------------------------- 1 | # UI Component utils 2 | 3 | ## `objectToClassnames(object, delimiter?)` 4 | 5 | `objectToClassnames` takes an object of strings and joins its keys and values using a provided delimiter (`-` by default) returning an array of strings; The base case here is to take a config object for creating CSS classnames. 6 | 7 | ```javascript 8 | import { objectToClassnames } from "utils"; 9 | 10 | const properties = { 11 | tint: "exubrant", 12 | size: "medium", 13 | }; 14 | 15 | const classnames = objectToClassnames(properties); 16 | // classnames = ["tint-exubrant", "size-medium"] 17 | ``` 18 | 19 | ## Params 20 | 21 | ### `object: { [key as string]: string }` 22 | 23 | An object containing strings 24 | 25 | ### `delimiter?: string` 26 | 27 | **default value: `-`** 28 | 29 | A string delimiter to use when concatenating object key to object value 30 | 31 | ```javascript 32 | const obj = { 33 | foo: "bar", 34 | baz: "bim", 35 | }; 36 | 37 | const classnames = objectToClassnames(obj, "(ಠ_ಠ)"); 38 | // classnames is ["foo(ಠ_ಠ)bar", "baz(ಠ_ಠ)bim"] 39 | ``` 40 | 41 | This prop is **optional**. 42 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/isNumber.ts: -------------------------------------------------------------------------------- 1 | const isNumber = (value: unknown) => { 2 | return typeof value === "number" && Number.isFinite(value); 3 | }; 4 | 5 | export default isNumber; 6 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/objectToClassnames.test.ts: -------------------------------------------------------------------------------- 1 | import objectToClassnames from "./objectToClassnames"; 2 | 3 | describe("objectToClassnames", () => { 4 | test("should be a function", () => { 5 | expect(typeof objectToClassnames).toBe("function"); 6 | }); 7 | 8 | test("should return an array", () => { 9 | const className = objectToClassnames({ 10 | foo: "bar", 11 | baz: "bim", 12 | boof: "boof", 13 | }); 14 | expect(Array.isArray(className)).toBe(true); 15 | }); 16 | 17 | test("should return a className array for a given prop", () => { 18 | const className = objectToClassnames({ foo: "bar" }); 19 | expect(className).toStrictEqual(["foo-bar"]); 20 | }); 21 | 22 | test("should return a className string for several props", () => { 23 | const className = objectToClassnames({ 24 | foo: "bar", 25 | baz: "bim", 26 | biff: "boop", 27 | }); 28 | 29 | expect(className).toContain("foo-bar"); 30 | expect(className).toContain("baz-bim"); 31 | expect(className).toContain("biff-boop"); 32 | }); 33 | 34 | test("should return a className string with a custom delimiter", () => { 35 | const className = objectToClassnames({ foo: "bar", baz: "bim" }, "___"); 36 | expect(className).toContain("foo___bar"); 37 | expect(className).toContain("baz___bim"); 38 | }); 39 | 40 | test("should return a className string with an empty delimiter", () => { 41 | const className = objectToClassnames({ foo: "bar", baz: "bim" }, ""); 42 | expect(className).toContain("foobar"); 43 | expect(className).toContain("bazbim"); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/objectToClassnames.ts: -------------------------------------------------------------------------------- 1 | // const classnames = classnames("component", propsToClassNames({ prop1, prop2, prop3 })); 2 | // "[prop1 name]--[prop1 value] [prop2 name]--[prop2 value] [prop3 name]--[prop3 value]"; 3 | 4 | const objectToClassNames = ( 5 | obj: { [key: string]: string }, 6 | delimiter = "-", 7 | ): string[] => 8 | Object.keys(obj).reduce( 9 | (acc, key) => [`${key}${delimiter}${obj[key]}`, ...acc], 10 | [], 11 | ); 12 | 13 | export default objectToClassNames; 14 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/upperCamelCase.test.ts: -------------------------------------------------------------------------------- 1 | import upperCamelCase from "./upperCamelCase"; 2 | 3 | describe("upperCamelCase", () => { 4 | test("should convert a sausage case string to an UpperCamelCase string", () => { 5 | const testString = "cockroach-labs-serverless-database-service"; 6 | const result = upperCamelCase(testString); 7 | const expected = "CockroachLabsServerlessDatabaseService"; 8 | 9 | expect(result).toBe(expected); 10 | }); 11 | 12 | test("should convert a spaced string to an UpperCamelCase string", () => { 13 | const testString = "cockroach labs serverless database service computer"; 14 | const result = upperCamelCase(testString); 15 | const expected = "CockroachLabsServerlessDatabaseServiceComputer"; 16 | 17 | expect(result).toBe(expected); 18 | }); 19 | 20 | test("should convert a camelCase string to an UpperCamelCase string", () => { 21 | const testString = "cockroachLabsServerlessDatabaseComputerServiceCompany"; 22 | const result = upperCamelCase(testString); 23 | const expected = "CockroachLabsServerlessDatabaseComputerServiceCompany"; 24 | 25 | expect(result).toBe(expected); 26 | }); 27 | 28 | test("should convert a mixed string to an UpperCamelCase string", () => { 29 | const testString = 30 | "cockroach..labs serverless database // computer ** company"; 31 | const result = upperCamelCase(testString); 32 | const expected = "CockroachLabsServerlessDatabaseComputerCompany"; 33 | 34 | expect(result).toBe(expected); 35 | }); 36 | 37 | test("should capitalize a single word", () => { 38 | const testString = "cockroach"; 39 | const result = upperCamelCase(testString); 40 | const expected = "Cockroach"; 41 | 42 | expect(result).toBe(expected); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/ui-components/src/utils/upperCamelCase.ts: -------------------------------------------------------------------------------- 1 | import camelCase from "lodash/camelCase"; 2 | 3 | export default function upperCamelCase(s: string) { 4 | return s.charAt(0).toUpperCase() + camelCase(s.slice(1)); 5 | } 6 | -------------------------------------------------------------------------------- /packages/ui-components/tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "node_modules", 5 | "dist", 6 | ], 7 | } 8 | -------------------------------------------------------------------------------- /packages/ui-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "emitDeclarationOnly": true, 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "jsx": "react", 8 | "module": "ESNext", 9 | "moduleResolution": "Node", 10 | "noImplicitAny": true, 11 | "outDir": "./dist/types", 12 | "target": "es6", 13 | "skipLibCheck": true, 14 | "sourceMap": false 15 | }, 16 | "exclude": [ 17 | "node_modules", 18 | "dist", 19 | "**/*.test.*" 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | // Renovate is a service that allows us to group and schedule 2 | // dependency updates. 3 | 4 | // The config can be validated using renovate-config-validator. 5 | // https://docs.renovatebot.com/reconfigure-renovate/#reconfigure-via-pr 6 | { 7 | extends: ["config:base"], 8 | // We currently only use renovate for JavaScript dependencies. 9 | enabledManagers: ["npm"], 10 | ignoreDeps: ["@svgr/cli"], 11 | ignorePaths: [], 12 | schedule: ["on Friday"], 13 | packageRules: [ 14 | { 15 | groupName: "all non-major dependencies", 16 | groupSlug: "all-minor-patch", 17 | // Excluded packages will be submitted as separate PRs. 18 | excludePackageNames: ["typescript", "@testing-library/react"], 19 | matchUpdateTypes: ["patch", "minor"], 20 | }, 21 | ], 22 | major: { 23 | // Using "before x time" format as is listed in the docs is too 24 | // narrow of a window since the job only runs once or twice a day. 25 | schedule: ["on the first day of the month"], 26 | packageRules: [ 27 | { 28 | matchPackagePatterns: ["^eslint"], 29 | groupName: "eslint packages", 30 | }, 31 | { 32 | matchPackagePatterns: ["^typescript"], 33 | matchPackageNames: ["ts-loader"], 34 | groupName: "typescript packages", 35 | }, 36 | { 37 | matchPackagePatterns: ["^webpack"], 38 | groupName: "webpack packages", 39 | }, 40 | { 41 | matchPackagePatterns: ["^sass"], 42 | groupName: "sass packages", 43 | }, 44 | { 45 | matchPackageNames: ["jest", "ts-jest", "@types/jest"], 46 | groupName: "jest packages", 47 | }, 48 | { 49 | // Relevant documentation: 50 | // - https://docs.renovatebot.com/presets-monorepo/ 51 | // - https://docs.renovatebot.com/configuration-options/#matchsourceurlprefixes 52 | matchSourceUrlPrefixes: ["https://github.com/lerna/lerna"], 53 | groupName: "All lerna packages", 54 | }, 55 | ], 56 | }, 57 | } 58 | --------------------------------------------------------------------------------