├── .eslintignore ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yaml │ ├── config.yaml │ └── feature-request.yaml ├── pull_request_template.md └── workflows │ ├── build.yaml │ ├── lint.yaml │ └── release.yaml ├── .gitignore ├── .prettierrc.json ├── .storybook ├── main.js ├── manager.js ├── preview.js └── tremorTheme.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── License ├── README.md ├── babel.config.js ├── images ├── banner-github-readme.png ├── example-dark.png ├── example-light.png ├── tremor-logo-dark.svg └── tremor-logo-light.svg ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── rollup.config.js ├── setupTests.js ├── src ├── assets │ ├── ArrowDownHeadIcon.tsx │ ├── ArrowDownIcon.tsx │ ├── ArrowDownRightIcon.tsx │ ├── ArrowLeftHeadIcon.tsx │ ├── ArrowRightHeadIcon.tsx │ ├── ArrowRightIcon.tsx │ ├── ArrowUpHeadIcon.tsx │ ├── ArrowUpIcon.tsx │ ├── ArrowUpRightIcon.tsx │ ├── CalendarIcon.tsx │ ├── ChevronLeftFill.tsx │ ├── ChevronRightFill.tsx │ ├── DoubleArrowLeftHeadIcon.tsx │ ├── DoubleArrowRightHeadIcon.tsx │ ├── ExclamationFilledIcon.tsx │ ├── EyeIcon.tsx │ ├── EyeOffIcon.tsx │ ├── LoadingSpinner.tsx │ ├── MinusIcon.tsx │ ├── PlusIcon.tsx │ ├── SearchIcon.tsx │ ├── XCircleIcon.tsx │ ├── XIcon.tsx │ └── index.ts ├── components │ ├── chart-elements │ │ ├── AreaChart │ │ │ ├── AreaChart.tsx │ │ │ └── index.ts │ │ ├── BarChart │ │ │ ├── BarChart.tsx │ │ │ └── index.ts │ │ ├── DonutChart │ │ │ ├── DonutChart.tsx │ │ │ ├── DonutChartTooltip.tsx │ │ │ ├── index.ts │ │ │ └── inputParser.ts │ │ ├── FunnelChart │ │ │ ├── FunnelChart.tsx │ │ │ └── index.ts │ │ ├── LineChart │ │ │ ├── LineChart.tsx │ │ │ └── index.ts │ │ ├── ScatterChart │ │ │ ├── ScatterChart.tsx │ │ │ ├── ScatterChartTooltip.tsx │ │ │ └── index.tsx │ │ ├── common │ │ │ ├── BaseAnimationTimingProps.tsx │ │ │ ├── BaseChartProps.tsx │ │ │ ├── ChartLegend.tsx │ │ │ ├── ChartTooltip.tsx │ │ │ ├── CustomTooltipProps.tsx │ │ │ ├── NoData.tsx │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ └── index.ts │ ├── icon-elements │ │ ├── Badge │ │ │ ├── Badge.tsx │ │ │ ├── index.ts │ │ │ └── styles.ts │ │ ├── BadgeDelta │ │ │ ├── BadgeDelta.tsx │ │ │ ├── index.ts │ │ │ └── styles.ts │ │ ├── Icon │ │ │ ├── Icon.tsx │ │ │ ├── index.ts │ │ │ └── styles.ts │ │ └── index.ts │ ├── index.ts │ ├── input-elements │ │ ├── BaseInput.tsx │ │ ├── Button │ │ │ ├── Button.tsx │ │ │ ├── index.ts │ │ │ └── styles.ts │ │ ├── Calendar │ │ │ ├── Calendar.tsx │ │ │ ├── NavButton.tsx │ │ │ └── index.ts │ │ ├── DatePicker │ │ │ ├── DatePicker.tsx │ │ │ ├── datePickerUtils.tsx │ │ │ └── index.ts │ │ ├── DateRangePicker │ │ │ ├── DateRangePicker.tsx │ │ │ ├── DateRangePickerItem.tsx │ │ │ ├── dateRangePickerUtils.tsx │ │ │ └── index.ts │ │ ├── MultiSelect │ │ │ ├── MultiSelect.tsx │ │ │ ├── MultiSelectItem.tsx │ │ │ └── index.ts │ │ ├── NumberInput │ │ │ ├── NumberInput.tsx │ │ │ └── index.ts │ │ ├── SearchSelect │ │ │ ├── SearchSelect.tsx │ │ │ ├── SearchSelectItem.tsx │ │ │ └── index.ts │ │ ├── Select │ │ │ ├── Select.tsx │ │ │ ├── SelectItem.tsx │ │ │ └── index.ts │ │ ├── Switch │ │ │ ├── Switch.tsx │ │ │ └── index.ts │ │ ├── Tabs │ │ │ ├── Tab.tsx │ │ │ ├── TabGroup.tsx │ │ │ ├── TabList.tsx │ │ │ ├── TabPanel.tsx │ │ │ ├── TabPanels.tsx │ │ │ └── index.ts │ │ ├── TextInput │ │ │ ├── TextInput.tsx │ │ │ └── index.ts │ │ ├── Textarea │ │ │ ├── Textarea.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ └── selectUtils.ts │ ├── layout-elements │ │ ├── Accordion │ │ │ ├── Accordion.tsx │ │ │ ├── AccordionBody.tsx │ │ │ ├── AccordionHeader.tsx │ │ │ ├── AccordionList.tsx │ │ │ └── index.ts │ │ ├── Card │ │ │ ├── Card.tsx │ │ │ └── index.ts │ │ ├── Dialog │ │ │ ├── Dialog.tsx │ │ │ ├── DialogPanel.tsx │ │ │ └── index.ts │ │ ├── Divider │ │ │ ├── Divider.tsx │ │ │ └── index.ts │ │ ├── Flex │ │ │ ├── Flex.tsx │ │ │ └── index.ts │ │ ├── Grid │ │ │ ├── Col.tsx │ │ │ ├── Grid.tsx │ │ │ ├── index.ts │ │ │ └── styles.ts │ │ └── index.ts │ ├── list-elements │ │ ├── List │ │ │ ├── List.tsx │ │ │ ├── ListItem.tsx │ │ │ └── index.ts │ │ ├── Table │ │ │ ├── Table.tsx │ │ │ ├── TableBody.tsx │ │ │ ├── TableCell.tsx │ │ │ ├── TableFoot.tsx │ │ │ ├── TableFooterCell.tsx │ │ │ ├── TableHead.tsx │ │ │ ├── TableHeaderCell.tsx │ │ │ ├── TableRow.tsx │ │ │ └── index.ts │ │ └── index.ts │ ├── spark-elements │ │ ├── SparkAreaChart │ │ │ ├── SparkAreaChart.tsx │ │ │ └── index.ts │ │ ├── SparkBarChart │ │ │ ├── SparkBarChart.tsx │ │ │ └── index.ts │ │ ├── SparkLineChart │ │ │ ├── SparkLineChart.tsx │ │ │ └── index.ts │ │ ├── common │ │ │ └── BaseSparkChartProps.tsx │ │ └── index.ts │ ├── text-elements │ │ ├── Bold │ │ │ ├── Bold.tsx │ │ │ └── index.ts │ │ ├── Callout │ │ │ ├── Callout.tsx │ │ │ └── index.ts │ │ ├── Italic │ │ │ ├── Italic.tsx │ │ │ └── index.ts │ │ ├── Legend │ │ │ ├── Legend.tsx │ │ │ └── index.ts │ │ ├── Metric │ │ │ ├── Metric.tsx │ │ │ └── index.ts │ │ ├── Subtitle │ │ │ ├── Subtitle.tsx │ │ │ └── index.ts │ │ ├── Text │ │ │ ├── Text.tsx │ │ │ └── index.ts │ │ ├── Title │ │ │ ├── Title.tsx │ │ │ └── index.ts │ │ └── index.ts │ ├── util-elements │ │ ├── Tooltip │ │ │ ├── Tooltip.tsx │ │ │ └── index.ts │ │ └── index.ts │ └── vis-elements │ │ ├── BarList │ │ ├── BarList.tsx │ │ └── index.ts │ │ ├── CategoryBar │ │ ├── CategoryBar.tsx │ │ └── index.ts │ │ ├── DeltaBar │ │ ├── DeltaBar.tsx │ │ ├── index.ts │ │ └── styles.ts │ │ ├── MarkerBar │ │ ├── MarkerBar.tsx │ │ └── index.ts │ │ ├── ProgressBar │ │ ├── ProgressBar.tsx │ │ └── index.ts │ │ ├── ProgressCircle │ │ ├── ProgressCircle.tsx │ │ └── index.ts │ │ ├── Tracker │ │ ├── Tracker.tsx │ │ └── index.ts │ │ └── index.ts ├── contexts │ ├── BaseColorContext.tsx │ ├── IndexContext.tsx │ ├── RootStylesContext.tsx │ ├── SelectedValueContext.tsx │ └── index.ts ├── hooks │ ├── index.ts │ ├── useInternalState.tsx │ └── useOnWindowResize.tsx ├── index.ts ├── lib │ ├── constants.ts │ ├── index.ts │ ├── inputTypes.ts │ ├── theme.ts │ ├── tremorTwMerge.ts │ └── utils.tsx ├── stories │ ├── assets │ │ ├── code-brackets.svg │ │ ├── colors.svg │ │ ├── comments.svg │ │ ├── direction.svg │ │ ├── flow.svg │ │ ├── plugin.svg │ │ ├── repo.svg │ │ └── stackalt.svg │ ├── chart-elements │ │ ├── AreaChart.stories.tsx │ │ ├── BarChart.stories.tsx │ │ ├── DonutChart.stories.tsx │ │ ├── FunnelChart.stories.tsx │ │ ├── LineChart.stories.tsx │ │ ├── ScatterChart.stories.tsx │ │ └── helpers │ │ │ ├── testData.tsx │ │ │ ├── testDataScatterChart.tsx │ │ │ └── utils.ts │ ├── icon-elements │ │ ├── Badge.stories.tsx │ │ ├── BadgeDelta.stories.tsx │ │ └── Icon.stories.tsx │ ├── input-elements │ │ ├── Button.stories.tsx │ │ ├── DatePicker.stories.tsx │ │ ├── DateRangePicker.stories.tsx │ │ ├── MultiSelect.stories.tsx │ │ ├── NumberInput.stories.tsx │ │ ├── SearchSelect.stories.tsx │ │ ├── Select.stories.tsx │ │ ├── Switch.stories.tsx │ │ ├── Tabs.stories.tsx │ │ ├── TextArea.stories.tsx │ │ ├── TextInput.stories.tsx │ │ └── helpers │ │ │ ├── SimpleMultiSelect.tsx │ │ │ ├── SimpleNumberInput.tsx │ │ │ ├── SimpleSearchSelect.tsx │ │ │ ├── SimpleSelect.tsx │ │ │ ├── SimpleSwitch.tsx │ │ │ ├── SimpleTextInput.tsx │ │ │ └── testData.ts │ ├── layout-elements │ │ ├── Accordion.stories.tsx │ │ ├── AccordionList.stories.tsx │ │ ├── Card.stories.tsx │ │ ├── Dialog.stories.tsx │ │ ├── Divider.stories.tsx │ │ ├── Flex.stories.tsx │ │ ├── Grid.stories.tsx │ │ └── helpers │ │ │ ├── SimpleAccordion.tsx │ │ │ ├── SimpleCard.tsx │ │ │ └── SimpleText.tsx │ ├── list-elements │ │ ├── List.stories.tsx │ │ └── Table.stories.tsx │ ├── spark-elements │ │ ├── SparkAreaChart.stories.tsx │ │ ├── SparkBarChart.stories.tsx │ │ ├── SparkLineChart.stories.tsx │ │ └── helpers │ │ │ ├── ExampleCard.tsx │ │ │ └── testData.ts │ ├── text-elements │ │ ├── Callout.stories.tsx │ │ ├── Legend.stories.tsx │ │ ├── Metric.stories.tsx │ │ ├── Subtitle.stories.tsx │ │ ├── Text.stories.tsx │ │ ├── TextElements.stories.tsx │ │ └── Title.stories.tsx │ └── vis-elements │ │ ├── BarList.stories.tsx │ │ ├── CategoryBar.stories.tsx │ │ ├── DeltaBar.stories.tsx │ │ ├── MarkerBar.stories.tsx │ │ ├── ProgressBar.stories.tsx │ │ ├── ProgressCircle.stories.tsx │ │ └── Tracker.stories.tsx ├── styles.css └── tests │ ├── chart-elements │ ├── AreaChart.test.tsx │ └── BarChart.test.tsx │ ├── icon-elements │ ├── Badge.test.tsx │ ├── BadgeDelta.test.tsx │ └── Icon.test.tsx │ ├── input-elements │ ├── Button.test.tsx │ ├── DatePicker.test.tsx │ ├── DateRangePicker.test.tsx │ ├── MultiSelect.test.tsx │ ├── NumberInput.test.tsx │ ├── SearchSelect.test.tsx │ ├── Select.test.tsx │ ├── Switch.text.tsx │ ├── Tabs.test.tsx │ ├── TextInput.test.tsx │ └── Textarea.test.tsx │ ├── layout-elements │ ├── Accordion.test.tsx │ ├── AccordionList.test.tsx │ ├── Card.test.tsx │ ├── Dialog.test.tsx │ ├── Divider.test.tsx │ ├── Flex.test.tsx │ └── Grid.test.tsx │ ├── list-elements │ ├── List.test.tsx │ └── Table.test.tsx │ ├── spark-elements │ └── SparkAreaChart.test.tsx │ ├── text-elements │ ├── Callout.test.tsx │ ├── Legend.test.tsx │ ├── Metric.test.tsx │ ├── Subtitle.test.tsx │ ├── Text.test.tsx │ └── Title.test.tsx │ └── vis-elements │ ├── BarList.test.tsx │ ├── CategoryBar.test.tsx │ ├── DeltaBar.test.tsx │ ├── MarkerBar.test.tsx │ ├── ProgressBar.test.tsx │ ├── ProgressCircle.text.tsx │ └── Tracker.test.tsx ├── tailwind.config.js └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | types -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "prettier", 5 | "plugin:prettier/recommended", 6 | "eslint:recommended", 7 | "plugin:react/recommended", 8 | "plugin:@typescript-eslint/eslint-recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "plugins": [ 13 | "@typescript-eslint", 14 | "prettier", 15 | "react", 16 | "react-hooks" 17 | ], 18 | "rules": { 19 | "react/button-has-type": "error", 20 | "react-hooks/rules-of-hooks": "error", 21 | "react-hooks/exhaustive-deps": "warn", 22 | "@typescript-eslint/no-non-null-assertion": "off", 23 | "@typescript-eslint/ban-ts-comment": "off", 24 | "@typescript-eslint/no-explicit-any": "off", 25 | "react/prop-types": "off" 26 | }, 27 | "settings": { 28 | "react": { 29 | "version": "detect" 30 | } 31 | }, 32 | "env": { 33 | "browser": true, 34 | "node": true 35 | }, 36 | "globals": { 37 | "JSX": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Slack Community 4 | url: https://join.slack.com/t/tremor-community/shared_invite/zt-1u8jqmcmq-Fdr9B6MbnO7u8FkGh~2Ylg 5 | about: Please ask and answer usage questions here. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yaml: -------------------------------------------------------------------------------- 1 | name: "\U0001F680 New feature proposal" 2 | description: Suggest an idea for this project 3 | title: "[Feature]: " 4 | labels: ["Triage"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | **Before submitting a feature request** 10 | 11 | The issue list is reserved for bug reports and feature requests. If you have a usage question, you can: 12 | 13 | - Read the [documentation](https://npm.tremor.so/docs/getting-started/installation) 14 | - Ask questions on [Slack](https://join.slack.com/t/tremor-community/shared_invite/zt-1u8jqmcmq-Fdr9B6MbnO7u8FkGh~2Ylg) 15 | 16 | Also try to search for your issue/feature - another user may have already requested something similar, thanks! 17 | 18 | - type: textarea 19 | id: problem-description 20 | attributes: 21 | label: What problem does this feature solve? 22 | description: | 23 | Explain your use case, context, and rationale behind this feature request. 24 | 25 | An important design goal of Tremor is keeping the API small. The problem should be common enough to justify the addition. 26 | placeholder: Problem description 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: proposed-API 31 | attributes: 32 | label: What does the proposed API look like? 33 | description: | 34 | Describe how you propose to solve the problem and provide code samples of how the API would work once implemented. Note that you can use [Markdown](https://guides.github.com/features/mastering-markdown/) to format your code blocks. 35 | placeholder: Assumed API 36 | - type: markdown 37 | attributes: 38 | value: | 39 | This bug report template was inspired by the feature template from [vuejs](https://github.com/vuejs/core) 40 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: "Build" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | push: 10 | branches: 11 | - "**" 12 | - "!main" 13 | 14 | jobs: 15 | build: 16 | name: Build dist 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: checkout 20 | uses: actions/checkout@v4 21 | - name: node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 20 25 | registry-url: https://registry.npmjs.org 26 | - name: install react 27 | run: npm i react 28 | - name: install dependencies 29 | run: npm ci 30 | - name: lint checks 31 | run: npm run lint 32 | - name: unit tests 33 | run: npm run tests 34 | - name: build 35 | run: npm run build 36 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: "Lint PR" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | pull_request_target: 10 | types: 11 | - opened 12 | - edited 13 | - synchronize 14 | 15 | jobs: 16 | lint-pr: 17 | name: Validate PR title 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Lint PR 21 | uses: amannn/action-semantic-pull-request@v4.6.0 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: "Release" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - beta 8 | - beta-** 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: checkout 16 | uses: actions/checkout@v4 17 | - name: node 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | registry-url: https://registry.npmjs.org 22 | - name: install react 23 | run: npm i react 24 | - name: install dependencies 25 | run: npm ci 26 | - name: build 27 | run: npm run build 28 | - name: release 29 | env: 30 | NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | run: npx semantic-release 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | storybook-static 5 | package-lock.json 6 | .vscode 7 | yarn.lock -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "singleQuote": false, 4 | "trailingComma": "all", 5 | "tabWidth": 2, 6 | "semi": true, 7 | "printWidth": 100, 8 | "jsxSingleQuote": false, 9 | "endOfLine": "auto" 10 | } 11 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = { 4 | stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"], 5 | 6 | addons: [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions", 10 | "@storybook/addon-styling-webpack", 11 | "@storybook/addon-themes", 12 | "@storybook/addon-a11y", 13 | { 14 | name: "@storybook/addon-styling-webpack", 15 | options: { 16 | rules: [ 17 | { 18 | test: /\.css$/, 19 | sideEffects: true, 20 | use: [ 21 | require.resolve("style-loader"), 22 | { 23 | loader: require.resolve("css-loader"), 24 | options: { 25 | importLoaders: 1, 26 | }, 27 | }, 28 | { 29 | loader: require.resolve("postcss-loader"), 30 | options: { 31 | implementation: require.resolve("postcss"), 32 | }, 33 | }, 34 | ], 35 | }, 36 | ], 37 | }, 38 | }, 39 | "@storybook/addon-webpack5-compiler-babel", 40 | "@chromatic-com/storybook", 41 | ], 42 | 43 | framework: { 44 | name: "@storybook/react-webpack5", 45 | options: {}, 46 | }, 47 | 48 | features: { 49 | previewMdx2: true, 50 | }, 51 | 52 | webpackFinal: async (config) => { 53 | config.resolve.modules = [...(config.resolve.modules || []), path.resolve(__dirname, "../src")]; 54 | 55 | return config; 56 | }, 57 | 58 | docs: {}, 59 | 60 | typescript: { 61 | reactDocgen: "react-docgen-typescript", 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/manager-api"; 2 | import { themes } from "@storybook/theming"; 3 | import tremorTheme from "./tremorTheme"; 4 | 5 | addons.setConfig({ 6 | theme: tremorTheme, 7 | }); 8 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import "../src/styles.css"; 2 | import { withThemeByDataAttribute } from "@storybook/addon-themes"; 3 | 4 | export const parameters = { 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | backgrounds: { 12 | default: "light", 13 | values: [ 14 | { 15 | name: "light", 16 | value: "#ffffff", 17 | }, 18 | { 19 | name: "dark", 20 | value: "#0f172a", 21 | }, 22 | ], 23 | }, 24 | }; 25 | 26 | export const decorators = [ 27 | withThemeByDataAttribute({ 28 | themes: { 29 | light: "light", 30 | dark: "dark", 31 | }, 32 | defaultTheme: "light", 33 | attributeName: "data-mode", 34 | }), 35 | ]; 36 | export const tags = ["autodocs"]; 37 | -------------------------------------------------------------------------------- /.storybook/tremorTheme.js: -------------------------------------------------------------------------------- 1 | import { create } from "@storybook/theming/create"; 2 | 3 | export default create({ 4 | base: "light", 5 | brandTitle: "Tremor Storybook", 6 | brandUrl: "https://storybook.tremor.so", 7 | // brandImage: 'images/tremor-logo.svg', 8 | brandTarget: "_self", 9 | // 10 | colorSecondary: "#3b82f6", 11 | 12 | // UI 13 | appBg: "#ffffff", 14 | appContentBg: "#ffffff", 15 | // appBorderColor: '#585C6D', 16 | appBorderRadius: 0, 17 | // 18 | barTextColor: "#9E9E9E", 19 | barSelectedColor: "#3b82f6", 20 | barBg: "#ffffff", 21 | }); 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | presets: ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"], 4 | }; 5 | -------------------------------------------------------------------------------- /images/banner-github-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tremorlabs/tremor-npm/7613bff631f713616b7b2ae52fb96dbc8e3dcc97/images/banner-github-readme.png -------------------------------------------------------------------------------- /images/example-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tremorlabs/tremor-npm/7613bff631f713616b7b2ae52fb96dbc8e3dcc97/images/example-dark.png -------------------------------------------------------------------------------- /images/example-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tremorlabs/tremor-npm/7613bff631f713616b7b2ae52fb96dbc8e3dcc97/images/example-light.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | testEnvironment: "jsdom", 4 | moduleDirectories: ["node_modules", "src"], 5 | moduleNameMapper: { 6 | ".(css|less|scss)$": "identity-obj-proxy", 7 | "components/(.*)": "/src/components/$1", 8 | "assets/(.*)": "/src/assets/$1", 9 | }, 10 | transformIgnorePatterns: ["/node_modules/(?!react-dnd|dnd-core|@react-dnd)"], 11 | }; 12 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | plugins: { 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | /* eslint-disable no-undef */ 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import resolve from "@rollup/plugin-node-resolve"; 5 | import typescript from "@rollup/plugin-typescript"; 6 | 7 | import dts from "rollup-plugin-dts"; 8 | import peerDepsExternal from "rollup-plugin-peer-deps-external"; 9 | import { typescriptPaths } from "rollup-plugin-typescript-paths"; 10 | import terser from "@rollup/plugin-terser"; 11 | import preserveDirectives from "rollup-plugin-preserve-directives"; 12 | 13 | const outputOptions = { 14 | sourcemap: false, 15 | preserveModules: true, 16 | preserveModulesRoot: "src", 17 | }; 18 | 19 | export default [ 20 | { 21 | input: "src/index.ts", 22 | output: [ 23 | { 24 | dir: "dist", 25 | format: "cjs", 26 | entryFileNames: "[name].cjs", 27 | exports: "auto", 28 | ...outputOptions, 29 | }, 30 | { 31 | dir: "dist", 32 | format: "esm", 33 | ...outputOptions, 34 | }, 35 | ], 36 | external: [/node_modules/], 37 | plugins: [ 38 | peerDepsExternal(), 39 | resolve(), 40 | commonjs(), 41 | preserveDirectives(), 42 | terser(), 43 | typescript({ 44 | tsconfig: "./tsconfig.json", 45 | exclude: ["**/stories/**", "**/tests/**", "./styles.css"], 46 | }), 47 | typescriptPaths(), 48 | ], 49 | }, 50 | { 51 | input: "dist/index.d.ts", 52 | output: [{ file: "dist/index.d.ts", format: "esm" }], 53 | plugins: [dts()], 54 | external: [/\.css$/], 55 | }, 56 | ]; 57 | -------------------------------------------------------------------------------- /setupTests.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-require-imports */ 2 | /* eslint-disable no-undef */ 3 | global.ResizeObserver = require("resize-observer-polyfill"); 4 | -------------------------------------------------------------------------------- /src/assets/ArrowDownHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowDownHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowDownHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowDownIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowDownIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowDownIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowDownRightIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowDownRightIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowDownRightIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowLeftHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowLeftHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowLeftHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowRightHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowRightHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowRightHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowRightIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowRightIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowRightIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowUpHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowUpHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowUpHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowUpIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowUpIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowUpIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ArrowUpRightIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ArrowUpRightIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ArrowUpRightIcon; 10 | -------------------------------------------------------------------------------- /src/assets/CalendarIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const CalendarIcon = ({ ...props }) => ( 4 | 5 | 10 | 11 | ); 12 | 13 | export default CalendarIcon; 14 | -------------------------------------------------------------------------------- /src/assets/ChevronLeftFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ChevronLeftFill = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ChevronLeftFill; 10 | -------------------------------------------------------------------------------- /src/assets/ChevronRightFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ChevronRightFill = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ChevronRightFill; 10 | -------------------------------------------------------------------------------- /src/assets/DoubleArrowLeftHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DoubleArrowLeftHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default DoubleArrowLeftHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/DoubleArrowRightHeadIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DoubleArrowRightHeadIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default DoubleArrowRightHeadIcon; 10 | -------------------------------------------------------------------------------- /src/assets/ExclamationFilledIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ExclamationFilledIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default ExclamationFilledIcon; 10 | -------------------------------------------------------------------------------- /src/assets/EyeIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const EyeIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default EyeIcon; 10 | -------------------------------------------------------------------------------- /src/assets/EyeOffIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const EyeOffIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default EyeOffIcon; 10 | -------------------------------------------------------------------------------- /src/assets/LoadingSpinner.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LoadingSpinner = ({ ...props }) => ( 4 | 5 | 6 | 7 | 8 | ); 9 | 10 | export default LoadingSpinner; 11 | -------------------------------------------------------------------------------- /src/assets/MinusIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const MinusIcon = ({ ...props }) => ( 4 | 12 | 13 | 14 | ); 15 | 16 | export default MinusIcon; 17 | -------------------------------------------------------------------------------- /src/assets/PlusIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PlusIcon = ({ ...props }) => ( 4 | 12 | 13 | 14 | ); 15 | 16 | export default PlusIcon; 17 | -------------------------------------------------------------------------------- /src/assets/SearchIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const SearchIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default SearchIcon; 10 | -------------------------------------------------------------------------------- /src/assets/XCircleIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const XCircleIcon = ({ ...props }) => ( 4 | 5 | 6 | 7 | ); 8 | 9 | export default XCircleIcon; 10 | -------------------------------------------------------------------------------- /src/assets/XIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const XIcon = ({ ...props }) => { 4 | return ( 5 | 17 | 18 | 19 | 20 | ); 21 | }; 22 | 23 | export default XIcon; 24 | -------------------------------------------------------------------------------- /src/assets/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ArrowDownHeadIcon } from "./ArrowDownHeadIcon"; 2 | export { default as ArrowDownIcon } from "./ArrowDownIcon"; 3 | export { default as ArrowDownRightIcon } from "./ArrowDownRightIcon"; 4 | export { default as ArrowLeftHeadIcon } from "./ArrowLeftHeadIcon"; 5 | export { default as ArrowRightHeadIcon } from "./ArrowRightHeadIcon"; 6 | export { default as ArrowRightIcon } from "./ArrowRightIcon"; 7 | export { default as ArrowUpHeadIcon } from "./ArrowUpHeadIcon"; 8 | export { default as ArrowUpIcon } from "./ArrowUpIcon"; 9 | export { default as ArrowUpRightIcon } from "./ArrowUpRightIcon"; 10 | export { default as CalendarIcon } from "./CalendarIcon"; 11 | export { default as DoubleArrowLeftHeadIcon } from "./DoubleArrowLeftHeadIcon"; 12 | export { default as DoubleArrowRightHeadIcon } from "./DoubleArrowRightHeadIcon"; 13 | export { default as ExclamationFilledIcon } from "./ExclamationFilledIcon"; 14 | export { default as EyeIcon } from "./EyeIcon"; 15 | export { default as EyeOffIcon } from "./EyeOffIcon"; 16 | export { default as LoadingSpinner } from "./LoadingSpinner"; 17 | export { default as SearchIcon } from "./SearchIcon"; 18 | export { default as XCircleIcon } from "./XCircleIcon"; 19 | export { default as PlusIcon } from "./PlusIcon"; 20 | export { default as MinusIcon } from "./MinusIcon"; 21 | export { default as ChevronLeftFill } from "./ChevronLeftFill"; 22 | export { default as ChevronRightFill } from "./ChevronRightFill"; 23 | -------------------------------------------------------------------------------- /src/components/chart-elements/AreaChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as AreaChart } from "./AreaChart"; 2 | export type { AreaChartProps } from "./AreaChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/BarChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BarChart } from "./BarChart"; 2 | export type { BarChartProps } from "./BarChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/DonutChart/DonutChartTooltip.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { tremorTwMerge, ValueFormatter } from "lib"; 3 | 4 | import { ChartTooltipFrame, ChartTooltipRow } from "components/chart-elements/common/ChartTooltip"; 5 | 6 | export interface DonutChartTooltipProps { 7 | active: boolean | undefined; 8 | payload: any; 9 | valueFormatter: ValueFormatter; 10 | } 11 | 12 | export const DonutChartTooltip = ({ active, payload, valueFormatter }: DonutChartTooltipProps) => { 13 | if (active && payload?.[0]) { 14 | const payloadRow = payload?.[0]; 15 | return ( 16 | 17 |
18 | 23 |
24 |
25 | ); 26 | } 27 | return null; 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/chart-elements/DonutChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DonutChart } from "./DonutChart"; 2 | export type { DonutChartProps } from "./DonutChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/DonutChart/inputParser.ts: -------------------------------------------------------------------------------- 1 | import { BaseColors, colorPalette, getColorClassNames, sumNumericArray } from "lib"; 2 | import { Color, ValueFormatter } from "../../../lib/inputTypes"; 3 | 4 | export const parseData = (data: any[], colors: (Color | string)[]) => 5 | data.map((dataPoint: any, idx: number) => { 6 | const baseColor = idx < colors.length ? colors[idx] : BaseColors.Gray; 7 | return { 8 | ...dataPoint, 9 | // explicitly adding color key if not present for tooltip coloring 10 | color: baseColor, 11 | className: getColorClassNames(baseColor ?? BaseColors.Gray, colorPalette.background) 12 | .fillColor, 13 | fill: "", 14 | }; 15 | }); 16 | 17 | const calculateDefaultLabel = (data: any[], category: string) => 18 | sumNumericArray(data.map((dataPoint) => dataPoint[category])); 19 | 20 | export const parseLabelInput = ( 21 | labelInput: string | undefined, 22 | valueFormatter: ValueFormatter, 23 | data: any[], 24 | category: string, 25 | ) => (labelInput ? labelInput : valueFormatter(calculateDefaultLabel(data, category))); 26 | -------------------------------------------------------------------------------- /src/components/chart-elements/FunnelChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FunnelChart } from "./FunnelChart"; 2 | export type { FunnelChartProps } from "./FunnelChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/LineChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as LineChart } from "./LineChart"; 2 | export type { LineChartProps } from "./LineChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/ScatterChart/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as ScatterChart } from "./ScatterChart"; 2 | export type { ScatterChartProps } from "./ScatterChart"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/BaseAnimationTimingProps.tsx: -------------------------------------------------------------------------------- 1 | interface BaseAnimationTimingProps { 2 | animationDuration?: number; 3 | showAnimation?: boolean; 4 | } 5 | 6 | export default BaseAnimationTimingProps; 7 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/BaseChartProps.tsx: -------------------------------------------------------------------------------- 1 | import { Color, ValueFormatter, IntervalType } from "../../../lib"; 2 | import type BaseAnimationTimingProps from "./BaseAnimationTimingProps"; 3 | import { CustomTooltipProps } from "./CustomTooltipProps"; 4 | 5 | type FixedProps = { 6 | eventType: "dot" | "category" | "bar" | "slice" | "bubble"; 7 | categoryClicked: string; 8 | }; 9 | 10 | type BaseEventProps = FixedProps & { 11 | [key: string]: number | string; 12 | }; 13 | 14 | export type EventProps = BaseEventProps | null | undefined; 15 | 16 | interface BaseChartProps extends BaseAnimationTimingProps, React.HTMLAttributes { 17 | data: any[]; 18 | categories: string[]; 19 | index: string; 20 | colors?: (Color | string)[]; 21 | valueFormatter?: ValueFormatter; 22 | startEndOnly?: boolean; 23 | showXAxis?: boolean; 24 | showYAxis?: boolean; 25 | yAxisWidth?: number; 26 | intervalType?: IntervalType; 27 | showTooltip?: boolean; 28 | showLegend?: boolean; 29 | showGridLines?: boolean; 30 | autoMinValue?: boolean; 31 | minValue?: number; 32 | maxValue?: number; 33 | allowDecimals?: boolean; 34 | noDataText?: string; 35 | onValueChange?: (value: EventProps) => void; 36 | enableLegendSlider?: boolean; 37 | padding?: { left?: number; right?: number }; 38 | customTooltip?: React.ComponentType; 39 | rotateLabelX?: { 40 | angle: number; 41 | verticalShift?: number; 42 | xAxisHeight?: number; 43 | }; 44 | tickGap?: number; 45 | xAxisLabel?: string; 46 | yAxisLabel?: string; 47 | } 48 | 49 | export default BaseChartProps; 50 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/ChartLegend.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | 3 | import { useOnWindowResize } from "hooks"; 4 | 5 | import { Legend } from "components/text-elements/Legend"; 6 | import { Color } from "../../../lib"; 7 | 8 | const ChartLegend = ( 9 | { payload }: any, 10 | categoryColors: Map, 11 | setLegendHeight: React.Dispatch>, 12 | activeLegend: string | undefined, 13 | onClick?: (category: string, color: Color | string) => void, 14 | enableLegendSlider?: boolean, 15 | ) => { 16 | const legendRef = useRef(null); 17 | 18 | useOnWindowResize(() => { 19 | const calculateHeight = (height: number | undefined) => 20 | height 21 | ? Number(height) + 20 // 20px extra padding 22 | : 60; // default height 23 | setLegendHeight(calculateHeight(legendRef.current?.clientHeight)); 24 | }); 25 | 26 | const filteredPayload = payload.filter((item: any) => item.type !== "none"); 27 | 28 | return ( 29 |
30 | entry.value)} 32 | colors={filteredPayload.map((entry: any) => categoryColors.get(entry.value))} 33 | onClickLegendItem={onClick} 34 | activeLegend={activeLegend} 35 | enableLegendSlider={enableLegendSlider} 36 | /> 37 |
38 | ); 39 | }; 40 | 41 | export default ChartLegend; 42 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/CustomTooltipProps.tsx: -------------------------------------------------------------------------------- 1 | import { NameType, Payload } from "recharts/types/component/DefaultTooltipContent"; 2 | 3 | export type CustomTooltipProps = { 4 | payload: Payload[] | undefined; 5 | active: boolean | undefined; 6 | label: NameType | undefined; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/NoData.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | interface NoDataProps { 5 | noDataText?: string; 6 | className?: string; 7 | } 8 | const NoData = ({ className, noDataText = "No data" }: NoDataProps) => { 9 | return ( 10 |
21 |

29 | {noDataText} 30 |

31 |
32 | ); 33 | }; 34 | 35 | export default NoData; 36 | -------------------------------------------------------------------------------- /src/components/chart-elements/common/index.ts: -------------------------------------------------------------------------------- 1 | export type { EventProps } from "./BaseChartProps"; 2 | export type { CustomTooltipProps } from "./CustomTooltipProps"; 3 | -------------------------------------------------------------------------------- /src/components/chart-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./AreaChart"; 2 | export * from "./BarChart"; 3 | export { EventProps } from "./common/BaseChartProps"; 4 | export { CustomTooltipProps } from "./common/CustomTooltipProps"; 5 | export * from "./DonutChart"; 6 | export * from "./LineChart"; 7 | export * from "./ScatterChart"; 8 | export * from "./FunnelChart"; 9 | -------------------------------------------------------------------------------- /src/components/icon-elements/Badge/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Badge } from "./Badge"; 2 | export type { BadgeProps } from "./Badge"; 3 | -------------------------------------------------------------------------------- /src/components/icon-elements/Badge/styles.ts: -------------------------------------------------------------------------------- 1 | export type BadgeProportionTypes = { 2 | paddingX: string; 3 | paddingY: string; 4 | fontSize: string; 5 | }; 6 | 7 | export const badgeProportions: { [char: string]: BadgeProportionTypes } = { 8 | xs: { 9 | paddingX: "px-2", 10 | paddingY: "py-0.5", 11 | fontSize: "text-xs", 12 | }, 13 | sm: { 14 | paddingX: "px-2.5", 15 | paddingY: "py-0.5", 16 | fontSize: "text-sm", 17 | }, 18 | md: { 19 | paddingX: "px-3", 20 | paddingY: "py-0.5", 21 | fontSize: "text-md", 22 | }, 23 | lg: { 24 | paddingX: "px-3.5", 25 | paddingY: "py-0.5", 26 | fontSize: "text-lg", 27 | }, 28 | xl: { 29 | paddingX: "px-4", 30 | paddingY: "py-1", 31 | fontSize: "text-xl", 32 | }, 33 | }; 34 | 35 | export const iconSizes: { 36 | [size: string]: { 37 | height: string; 38 | width: string; 39 | }; 40 | } = { 41 | xs: { 42 | height: "h-4", 43 | width: "w-4", 44 | }, 45 | sm: { 46 | height: "h-4", 47 | width: "w-4", 48 | }, 49 | md: { 50 | height: "h-4", 51 | width: "w-4", 52 | }, 53 | lg: { 54 | height: "h-5", 55 | width: "w-5", 56 | }, 57 | xl: { 58 | height: "h-6", 59 | width: "w-6", 60 | }, 61 | }; 62 | -------------------------------------------------------------------------------- /src/components/icon-elements/BadgeDelta/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BadgeDelta } from "./BadgeDelta"; 2 | export type { BadgeDeltaProps } from "./BadgeDelta"; 3 | -------------------------------------------------------------------------------- /src/components/icon-elements/Icon/Icon.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | 4 | import Tooltip, { useTooltip } from "components/util-elements/Tooltip/Tooltip"; 5 | import { makeClassName, mergeRefs, Sizes, tremorTwMerge, Color, IconVariant, Size } from "lib"; 6 | import { getIconColors, iconSizes, shape, wrapperProportions } from "./styles"; 7 | 8 | const makeIconClassName = makeClassName("Icon"); 9 | 10 | export const IconVariants: { [key: string]: IconVariant } = { 11 | Simple: "simple", 12 | Light: "light", 13 | Shadow: "shadow", 14 | Solid: "solid", 15 | Outlined: "outlined", 16 | }; 17 | 18 | export interface IconProps extends React.HTMLAttributes { 19 | icon: React.ElementType; 20 | variant?: IconVariant; 21 | tooltip?: string; 22 | size?: Size; 23 | color?: Color; 24 | } 25 | 26 | const Icon = React.forwardRef((props, ref) => { 27 | const { 28 | icon, 29 | variant = IconVariants.Simple, 30 | tooltip, 31 | size = Sizes.SM, 32 | color, 33 | className, 34 | ...other 35 | } = props; 36 | const Icon = icon; 37 | const iconColorStyles = getIconColors(variant, color); 38 | 39 | const { tooltipProps, getReferenceProps } = useTooltip(); 40 | 41 | return ( 42 | 62 | 63 | 71 | 72 | ); 73 | }); 74 | 75 | Icon.displayName = "Icon"; 76 | 77 | export default Icon; 78 | -------------------------------------------------------------------------------- /src/components/icon-elements/Icon/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Icon } from "./Icon"; 2 | export type { IconProps } from "./Icon"; 3 | -------------------------------------------------------------------------------- /src/components/icon-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Badge"; 2 | export * from "./BadgeDelta"; 3 | export * from "./Icon"; 4 | -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./chart-elements"; 2 | export * from "./icon-elements"; 3 | export * from "./input-elements"; 4 | export * from "./layout-elements"; 5 | export * from "./list-elements"; 6 | export * from "./spark-elements"; 7 | export * from "./text-elements"; 8 | export * from "./vis-elements"; 9 | -------------------------------------------------------------------------------- /src/components/input-elements/Button/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Button } from "./Button"; 2 | export type { ButtonProps } from "./Button"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/Calendar/NavButton.tsx: -------------------------------------------------------------------------------- 1 | import { Icon as IconComponent } from "components/icon-elements"; 2 | import { tremorTwMerge } from "lib"; 3 | import React from "react"; 4 | 5 | interface NavButtonProps extends React.HTMLAttributes { 6 | onClick: () => void; 7 | icon: React.ElementType; 8 | } 9 | 10 | export const NavButton = ({ onClick, icon, ...other }: NavButtonProps) => { 11 | const Icon = icon; 12 | return ( 13 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /src/components/input-elements/Calendar/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Calendar } from "./Calendar"; 2 | -------------------------------------------------------------------------------- /src/components/input-elements/DatePicker/datePickerUtils.tsx: -------------------------------------------------------------------------------- 1 | import { makeClassName } from "lib"; 2 | 3 | export const makeDatePickerClassName = makeClassName("DatePicker"); 4 | -------------------------------------------------------------------------------- /src/components/input-elements/DatePicker/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DatePicker } from "./DatePicker"; 2 | export type { DatePickerProps, DatePickerValue } from "./DatePicker"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/DateRangePicker/DateRangePickerItem.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | 4 | import { SelectItem } from "../Select"; 5 | 6 | export interface DateRangePickerItemProps extends React.HTMLAttributes { 7 | value: string; 8 | from: Date; 9 | to?: Date; 10 | } 11 | 12 | const DateRangePickerItem = React.forwardRef( 13 | (props, ref) => { 14 | const { value, className, children, ...other } = props; 15 | 16 | return ( 17 | 18 | {children ?? value} 19 | 20 | ); 21 | }, 22 | ); 23 | 24 | DateRangePickerItem.displayName = "DateRangePickerItem"; 25 | 26 | export default DateRangePickerItem; 27 | -------------------------------------------------------------------------------- /src/components/input-elements/DateRangePicker/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DateRangePicker } from "./DateRangePicker"; 2 | export type { DateRangePickerProps, DateRangePickerValue } from "./DateRangePicker"; 3 | export { default as DateRangePickerItem } from "./DateRangePickerItem"; 4 | export type { DateRangePickerItemProps } from "./DateRangePickerItem"; 5 | -------------------------------------------------------------------------------- /src/components/input-elements/MultiSelect/index.ts: -------------------------------------------------------------------------------- 1 | export { default as MultiSelect } from "./MultiSelect"; 2 | export type { MultiSelectProps } from "./MultiSelect"; 3 | export { default as MultiSelectItem } from "./MultiSelectItem"; 4 | export type { MultiSelectItemProps } from "./MultiSelectItem"; 5 | -------------------------------------------------------------------------------- /src/components/input-elements/NumberInput/index.ts: -------------------------------------------------------------------------------- 1 | export { default as NumberInput } from "./NumberInput"; 2 | export type { NumberInputProps } from "./NumberInput"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/SearchSelect/SearchSelectItem.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | 4 | import { makeClassName, tremorTwMerge } from "lib"; 5 | 6 | import { ComboboxOption } from "@headlessui/react"; 7 | 8 | const makeSearchSelectItemClassName = makeClassName("SearchSelectItem"); 9 | 10 | export interface SearchSelectItemProps extends React.HTMLAttributes { 11 | value: string; 12 | icon?: React.ElementType; 13 | } 14 | 15 | const SearchSelectItem = React.forwardRef((props, ref) => { 16 | const { value, icon, className, children, ...other } = props; 17 | const Icon = icon; 18 | 19 | return ( 20 | 36 | {Icon && ( 37 | 48 | )} 49 | {children ?? value} 50 | 51 | ); 52 | }); 53 | 54 | SearchSelectItem.displayName = "SearchSelectItem"; 55 | 56 | export default SearchSelectItem; 57 | -------------------------------------------------------------------------------- /src/components/input-elements/SearchSelect/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SearchSelect } from "./SearchSelect"; 2 | export type { SearchSelectProps } from "./SearchSelect"; 3 | export { default as SearchSelectItem } from "./SearchSelectItem"; 4 | export type { SearchSelectItemProps } from "./SearchSelectItem"; 5 | -------------------------------------------------------------------------------- /src/components/input-elements/Select/SelectItem.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { ListboxOption } from "@headlessui/react"; 4 | import { makeClassName, tremorTwMerge } from "lib"; 5 | 6 | const makeSelectItemClassName = makeClassName("SelectItem"); 7 | 8 | export interface SelectItemProps extends React.HTMLAttributes { 9 | value: string; 10 | icon?: React.ElementType; 11 | } 12 | 13 | const SelectItem = React.forwardRef((props, ref) => { 14 | const { value, icon, className, children, ...other } = props; 15 | 16 | const Icon = icon; 17 | 18 | return ( 19 | 35 | {Icon && ( 36 | 47 | )} 48 | {children ?? value} 49 | 50 | ); 51 | }); 52 | 53 | SelectItem.displayName = "SelectItem"; 54 | 55 | export default SelectItem; 56 | -------------------------------------------------------------------------------- /src/components/input-elements/Select/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Select } from "./Select"; 2 | export type { SelectProps } from "./Select"; 3 | export { default as SelectItem } from "./SelectItem"; 4 | export type { SelectItemProps } from "./SelectItem"; 5 | -------------------------------------------------------------------------------- /src/components/input-elements/Switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Switch } from "./Switch"; 2 | export type { SwitchProps } from "./Switch"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/Tabs/TabGroup.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Tab } from "@headlessui/react"; 3 | import { makeClassName, tremorTwMerge } from "lib"; 4 | import React from "react"; 5 | 6 | const makeTabGroupClassName = makeClassName("TabGroup"); 7 | 8 | export interface TabGroupProps extends React.HTMLAttributes { 9 | defaultIndex?: number; 10 | index?: number; 11 | onIndexChange?: (index: number) => void; 12 | children: React.ReactElement[] | React.ReactElement; 13 | } 14 | 15 | const TabGroup = React.forwardRef((props, ref) => { 16 | const { defaultIndex, index, onIndexChange, children, className, ...other } = props; 17 | return ( 18 | 27 | {children} 28 | 29 | ); 30 | }); 31 | 32 | TabGroup.displayName = "TabGroup"; 33 | 34 | export default TabGroup; 35 | -------------------------------------------------------------------------------- /src/components/input-elements/Tabs/TabList.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { createContext } from "react"; 3 | 4 | import { BaseColorContext } from "contexts"; 5 | 6 | import { Tab } from "@headlessui/react"; 7 | import { makeClassName, tremorTwMerge, Color } from "lib"; 8 | 9 | const makeTabListClassName = makeClassName("TabList"); 10 | 11 | export type TabVariant = "line" | "solid"; 12 | 13 | export const TabVariantContext = createContext("line"); 14 | 15 | const variantStyles: { [key in TabVariant]: string } = { 16 | line: tremorTwMerge( 17 | // common 18 | "flex border-b space-x-4", 19 | // light 20 | "border-tremor-border", 21 | // dark 22 | "dark:border-dark-tremor-border", 23 | ), 24 | solid: tremorTwMerge( 25 | // common 26 | "inline-flex p-0.5 rounded-tremor-default space-x-1.5", 27 | // light 28 | "bg-tremor-background-subtle", 29 | // dark 30 | "dark:bg-dark-tremor-background-subtle", 31 | ), 32 | }; 33 | 34 | export interface TabListProps extends React.HTMLAttributes { 35 | color?: Color; 36 | variant?: TabVariant; 37 | children: React.ReactElement[] | React.ReactElement; 38 | } 39 | 40 | const TabList = React.forwardRef((props, ref) => { 41 | const { color, variant = "line", children, className, ...other } = props; 42 | 43 | return ( 44 | 54 | 55 | {children} 56 | 57 | 58 | ); 59 | }); 60 | 61 | TabList.displayName = "TabList"; 62 | 63 | export default TabList; 64 | -------------------------------------------------------------------------------- /src/components/input-elements/Tabs/TabPanel.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { IndexContext, SelectedValueContext } from "contexts"; 3 | import { makeClassName, tremorTwMerge } from "lib"; 4 | import React, { useContext } from "react"; 5 | 6 | const makeTabPanelClassName = makeClassName("TabPanel"); 7 | 8 | const TabPanel = React.forwardRef>( 9 | (props, ref) => { 10 | const { children, className, ...other } = props; 11 | 12 | const { selectedValue: selectedIndex } = useContext(SelectedValueContext); 13 | const index = useContext(IndexContext); 14 | 15 | const isSelected = selectedIndex === index; 16 | 17 | return ( 18 | // Not using Tab.Panel because of https://github.com/tailwindlabs/headlessui/discussions/2366. 19 |
30 | {children} 31 |
32 | ); 33 | }, 34 | ); 35 | 36 | TabPanel.displayName = "TabPanel"; 37 | 38 | export default TabPanel; 39 | -------------------------------------------------------------------------------- /src/components/input-elements/Tabs/TabPanels.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Tab } from "@headlessui/react"; 3 | import { IndexContext, SelectedValueContext } from "contexts"; 4 | import { makeClassName, tremorTwMerge } from "lib"; 5 | import React from "react"; 6 | 7 | const makeTabPanelsClassName = makeClassName("TabPanels"); 8 | 9 | const TabPanels = React.forwardRef>( 10 | (props, ref) => { 11 | const { children, className, ...other } = props; 12 | 13 | return ( 14 | 20 | {({ selectedIndex }) => ( 21 | 22 | {React.Children.map(children, (child, index) => ( 23 | {child} 24 | ))} 25 | 26 | )} 27 | 28 | ); 29 | }, 30 | ); 31 | 32 | TabPanels.displayName = "TabPanels"; 33 | 34 | export default TabPanels; 35 | -------------------------------------------------------------------------------- /src/components/input-elements/Tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tab } from "./Tab"; 2 | export type { TabProps } from "./Tab"; 3 | export { default as TabGroup } from "./TabGroup"; 4 | export type { TabGroupProps } from "./TabGroup"; 5 | export { default as TabList } from "./TabList"; 6 | export type { TabListProps } from "./TabList"; 7 | export { default as TabPanel } from "./TabPanel"; 8 | export { default as TabPanels } from "./TabPanels"; 9 | -------------------------------------------------------------------------------- /src/components/input-elements/TextInput/TextInput.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { makeClassName } from "lib"; 4 | import BaseInput, { BaseInputProps } from "../BaseInput"; 5 | 6 | export type TextInputProps = Omit & { 7 | defaultValue?: string; 8 | value?: string; 9 | onValueChange?: (value: string) => void; 10 | icon?: React.ElementType | React.JSXElementConstructor; 11 | error?: boolean; 12 | errorMessage?: string; 13 | disabled?: boolean; 14 | }; 15 | 16 | const makeTextInputClassName = makeClassName("TextInput"); 17 | 18 | const TextInput = React.forwardRef((props, ref) => { 19 | const { type = "text", ...other } = props; 20 | return ; 21 | }); 22 | 23 | TextInput.displayName = "TextInput"; 24 | 25 | export default TextInput; 26 | -------------------------------------------------------------------------------- /src/components/input-elements/TextInput/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TextInput } from "./TextInput"; 2 | export type { TextInputProps } from "./TextInput"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/Textarea/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Textarea } from "./Textarea"; 2 | export type { TextareaProps } from "./Textarea"; 3 | -------------------------------------------------------------------------------- /src/components/input-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Button"; 2 | export * from "./DatePicker"; 3 | export * from "./DateRangePicker"; 4 | export * from "./MultiSelect"; 5 | export * from "./NumberInput"; 6 | export * from "./SearchSelect"; 7 | export * from "./Select"; 8 | export * from "./Switch"; 9 | export * from "./Tabs"; 10 | export * from "./Textarea"; 11 | export * from "./TextInput"; 12 | -------------------------------------------------------------------------------- /src/components/input-elements/selectUtils.ts: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | export interface SelectItemProps { 5 | value: string; 6 | children?: React.ReactNode; 7 | } 8 | 9 | export const getNodeText = (node: React.ReactElement): string | React.ReactElement | undefined => { 10 | if (["string", "number"].includes(typeof node)) return node; 11 | if (node instanceof Array) return node.map(getNodeText).join(""); 12 | if (typeof node === "object" && node) return getNodeText(node.props.children); 13 | }; 14 | 15 | export function constructValueToNameMapping(children: React.ReactElement[] | React.ReactElement) { 16 | const valueToNameMapping = new Map(); 17 | React.Children.map(children, (child: React.ReactElement) => { 18 | valueToNameMapping.set(child.props.value, (getNodeText(child) ?? child.props.value) as string); 19 | }); 20 | return valueToNameMapping; 21 | } 22 | 23 | export function getFilteredOptions( 24 | searchQuery: string, 25 | children: React.ReactElement[], 26 | ): React.ReactElement[] { 27 | return React.Children.map(children, (child) => { 28 | const optionText = (getNodeText(child) ?? child.props.value) as string; 29 | if (optionText.toLowerCase().includes(searchQuery.toLowerCase())) return child; 30 | }); 31 | } 32 | 33 | export const getSelectButtonColors = ( 34 | hasSelection: boolean, 35 | isDisabled: boolean, 36 | hasError = false, 37 | ) => { 38 | return tremorTwMerge( 39 | isDisabled 40 | ? "bg-tremor-background-subtle dark:bg-dark-tremor-background-subtle" 41 | : "bg-tremor-background dark:bg-dark-tremor-background", 42 | !isDisabled && "hover:bg-tremor-background-muted dark:hover:bg-dark-tremor-background-muted", 43 | hasSelection 44 | ? "text-tremor-content-emphasis dark:text-dark-tremor-content-emphasis" 45 | : "text-tremor-content dark:text-dark-tremor-content", 46 | isDisabled && "text-tremor-content-subtle dark:text-dark-tremor-content-subtle", 47 | hasError && 48 | "text-red-500 placeholder:text-red-500 dark:text-red-500 dark:placeholder:text-red-500", 49 | hasError 50 | ? "border-red-500 dark:border-red-500" 51 | : "border-tremor-border dark:border-dark-tremor-border", 52 | ); 53 | }; 54 | 55 | export function hasValue(value: T | null | undefined) { 56 | return value !== null && value !== undefined && value !== ""; 57 | } 58 | -------------------------------------------------------------------------------- /src/components/layout-elements/Accordion/Accordion.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Disclosure } from "@headlessui/react"; 3 | import { RootStylesContext } from "contexts"; 4 | import { makeClassName, tremorTwMerge } from "lib"; 5 | import React, { createContext, useContext } from "react"; 6 | 7 | const makeAccordionClassName = makeClassName("Accordion"); 8 | 9 | interface OpenContextValue { 10 | isOpen: boolean; 11 | } 12 | export const OpenContext = createContext({ 13 | isOpen: false, 14 | }); 15 | 16 | export interface AccordionProps extends React.HTMLAttributes { 17 | defaultOpen?: boolean; 18 | } 19 | 20 | const Accordion = React.forwardRef((props, ref) => { 21 | const { defaultOpen = false, children, className, ...other } = props; 22 | 23 | const rootStyles = 24 | useContext(RootStylesContext) ?? tremorTwMerge("rounded-tremor-default border"); 25 | return ( 26 | 43 | {({ open }) => ( 44 | {children} 45 | )} 46 | 47 | ); 48 | }); 49 | 50 | Accordion.displayName = "Accordion"; 51 | 52 | export default Accordion; 53 | -------------------------------------------------------------------------------- /src/components/layout-elements/Accordion/AccordionBody.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { Disclosure } from "@headlessui/react"; 4 | import { makeClassName, tremorTwMerge } from "lib"; 5 | 6 | const makeAccordionBodyClassName = makeClassName("AccordionBody"); 7 | 8 | const AccordionBody = React.forwardRef>( 9 | (props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | 26 | {children} 27 | 28 | ); 29 | }, 30 | ); 31 | 32 | AccordionBody.displayName = "AccordionBody"; 33 | 34 | export default AccordionBody; 35 | -------------------------------------------------------------------------------- /src/components/layout-elements/Accordion/AccordionHeader.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useContext } from "react"; 3 | 4 | import { Disclosure } from "@headlessui/react"; 5 | import { ArrowUpHeadIcon } from "assets"; 6 | import { OpenContext } from "components/layout-elements/Accordion/Accordion"; 7 | import { makeClassName, tremorTwMerge } from "lib"; 8 | 9 | const makeAccordionHeaderClassName = makeClassName("AccordionHeader"); 10 | 11 | const AccordionHeader = React.forwardRef< 12 | HTMLButtonElement, 13 | React.ButtonHTMLAttributes 14 | >((props, ref) => { 15 | const { children, className, ...other } = props; 16 | 17 | const { isOpen } = useContext(OpenContext); 18 | 19 | return ( 20 | 34 |
40 | {children} 41 |
42 |
43 | 55 |
56 |
57 | ); 58 | }); 59 | 60 | AccordionHeader.displayName = "AccordionHeader"; 61 | 62 | export default AccordionHeader; 63 | -------------------------------------------------------------------------------- /src/components/layout-elements/Accordion/AccordionList.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | 5 | import { RootStylesContext } from "contexts"; 6 | import { makeClassName, tremorTwMerge } from "lib"; 7 | 8 | const makeAccordionListClassName = makeClassName("AccordionList"); 9 | 10 | export interface AccordionListProps extends React.HTMLAttributes { 11 | children: React.ReactElement[] | React.ReactElement; 12 | } 13 | 14 | const AccordionList = React.forwardRef((props, ref) => { 15 | const { children, className, ...other } = props; 16 | const numChildren = React.Children.count(children); 17 | 18 | return ( 19 |
33 | {React.Children.map(children, (child, idx) => { 34 | if (idx === 0) { 35 | return ( 36 | 37 | {React.cloneElement(child)} 38 | 39 | ); 40 | } 41 | if (idx === numChildren - 1) { 42 | return ( 43 | 46 | {React.cloneElement(child)} 47 | 48 | ); 49 | } 50 | return ( 51 | 52 | {React.cloneElement(child)} 53 | 54 | ); 55 | })} 56 |
57 | ); 58 | }); 59 | 60 | AccordionList.displayName = "AccordionList"; 61 | 62 | export default AccordionList; 63 | -------------------------------------------------------------------------------- /src/components/layout-elements/Accordion/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Accordion } from "./Accordion"; 2 | export type { AccordionProps } from "./Accordion"; 3 | export { default as AccordionBody } from "./AccordionBody"; 4 | export { default as AccordionHeader } from "./AccordionHeader"; 5 | export { default as AccordionList } from "./AccordionList"; 6 | export type { AccordionListProps } from "./AccordionList"; 7 | -------------------------------------------------------------------------------- /src/components/layout-elements/Card/Card.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | getColorClassNames, 4 | makeClassName, 5 | tremorTwMerge, 6 | Color, 7 | HorizontalPosition, 8 | VerticalPosition, 9 | } from "lib"; 10 | import { HorizontalPositions, VerticalPositions } from "lib/constants"; 11 | import { colorPalette } from "lib/theme"; 12 | 13 | const makeCardClassName = makeClassName("Card"); 14 | 15 | const parseDecorationAlignment = (decorationAlignment: string) => { 16 | if (!decorationAlignment) return ""; 17 | switch (decorationAlignment) { 18 | case HorizontalPositions.Left: 19 | return "border-l-4"; 20 | case VerticalPositions.Top: 21 | return "border-t-4"; 22 | case HorizontalPositions.Right: 23 | return "border-r-4"; 24 | case VerticalPositions.Bottom: 25 | return "border-b-4"; 26 | default: 27 | return ""; 28 | } 29 | }; 30 | 31 | export interface CardProps extends React.HTMLAttributes { 32 | decoration?: HorizontalPosition | VerticalPosition | ""; 33 | decorationColor?: Color; 34 | } 35 | 36 | const Card = React.forwardRef((props, ref) => { 37 | const { decoration = "", decorationColor, children, className, ...other } = props; 38 | return ( 39 |
58 | {children} 59 |
60 | ); 61 | }); 62 | 63 | Card.displayName = "Card"; 64 | 65 | export default Card; 66 | -------------------------------------------------------------------------------- /src/components/layout-elements/Card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from "./Card"; 2 | export type { CardProps } from "./Card"; 3 | -------------------------------------------------------------------------------- /src/components/layout-elements/Dialog/Dialog.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Dialog as HeadlessUiDialog, DialogBackdrop, Transition } from "@headlessui/react"; 3 | import { makeClassName, tremorTwMerge } from "lib"; 4 | 5 | const makeDisplayClassName = makeClassName("dialog"); 6 | 7 | type Without = { [P in Exclude]?: never }; 8 | type XOR = T | U extends object ? (Without & U) | (Without & T) : T | U; 9 | 10 | export type DialogProps = React.HTMLAttributes & { 11 | open: boolean; 12 | onClose: (val: boolean) => void; 13 | role?: "dialog" | "alertdialog"; 14 | } & XOR<{ unmount?: boolean }, { static?: boolean }>; 15 | 16 | const Dialog = React.forwardRef((props, ref) => { 17 | const { children, className, ...other } = props; 18 | return ( 19 | 20 | 25 | 29 |
30 |
{children}
31 |
32 |
33 |
34 | ); 35 | }); 36 | 37 | Dialog.displayName = "Dialog"; 38 | 39 | export default Dialog; 40 | -------------------------------------------------------------------------------- /src/components/layout-elements/Dialog/DialogPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { DialogPanel as HeadlessuiDialogPanel, TransitionChild } from "@headlessui/react"; 3 | import { makeClassName, tremorTwMerge } from "lib"; 4 | import { RootStylesContext } from "contexts"; 5 | 6 | const makeDisplayClassName = makeClassName("dialog"); 7 | 8 | export type DialogPanelProps = React.HTMLAttributes; 9 | 10 | const DialogPanel = React.forwardRef((props, ref) => { 11 | const { children, className, ...other } = props; 12 | const rootStyles = 13 | React.useContext(RootStylesContext) ?? tremorTwMerge("rounded-tremor-default p-6"); 14 | 15 | return ( 16 | 24 | 39 | {children} 40 | 41 | 42 | ); 43 | }); 44 | 45 | DialogPanel.displayName = "DialogPanel"; 46 | 47 | export default DialogPanel; 48 | -------------------------------------------------------------------------------- /src/components/layout-elements/Dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Dialog, type DialogProps } from "./Dialog"; 2 | export { default as DialogPanel, type DialogPanelProps } from "./DialogPanel"; 3 | -------------------------------------------------------------------------------- /src/components/layout-elements/Divider/Divider.tsx: -------------------------------------------------------------------------------- 1 | import { makeClassName, tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | const makeDividerClassName = makeClassName("Divider"); 5 | 6 | const Divider = React.forwardRef>( 7 | (props, ref) => { 8 | const { className, children, ...other } = props; 9 | return ( 10 |
24 | {children ? ( 25 | <> 26 |
31 |
{children}
32 |
37 | 38 | ) : ( 39 |
42 | )} 43 |
44 | ); 45 | }, 46 | ); 47 | 48 | Divider.displayName = "Divider"; 49 | 50 | export default Divider; 51 | -------------------------------------------------------------------------------- /src/components/layout-elements/Divider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Divider } from "./Divider"; 2 | -------------------------------------------------------------------------------- /src/components/layout-elements/Flex/Flex.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { makeClassName } from "lib"; 5 | import { AlignItems, FlexDirection, JustifyContent } from "../../../lib"; 6 | 7 | const makeFlexClassName = makeClassName("Flex"); 8 | 9 | const justifyContentClassNames: { [key in JustifyContent]: string } = { 10 | start: "justify-start", 11 | end: "justify-end", 12 | center: "justify-center", 13 | between: "justify-between", 14 | around: "justify-around", 15 | evenly: "justify-evenly", 16 | }; 17 | 18 | const alignItemsClassNames: { [key in AlignItems]: string } = { 19 | start: "items-start", 20 | end: "items-end", 21 | center: "items-center", 22 | baseline: "items-baseline", 23 | stretch: "items-stretch", 24 | }; 25 | 26 | const flexDirectionClassNames: { [key in FlexDirection]: string } = { 27 | row: "flex-row", 28 | col: "flex-col", 29 | "row-reverse": "flex-row-reverse", 30 | "col-reverse": "flex-col-reverse", 31 | }; 32 | 33 | export interface FlexProps extends React.HTMLAttributes { 34 | flexDirection?: FlexDirection; 35 | justifyContent?: JustifyContent; 36 | alignItems?: AlignItems; 37 | children: React.ReactNode; 38 | } 39 | 40 | const Flex = React.forwardRef((props, ref) => { 41 | const { 42 | flexDirection = "row", 43 | justifyContent = "between", 44 | alignItems = "center", 45 | children, 46 | className, 47 | ...other 48 | } = props; 49 | 50 | return ( 51 |
63 | {children} 64 |
65 | ); 66 | }); 67 | 68 | Flex.displayName = "Flex"; 69 | 70 | export default Flex; 71 | -------------------------------------------------------------------------------- /src/components/layout-elements/Flex/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Flex } from "./Flex"; 2 | export type { FlexProps } from "./Flex"; 3 | -------------------------------------------------------------------------------- /src/components/layout-elements/Grid/Col.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { makeClassName } from "lib"; 5 | import { colSpan, colSpanLg, colSpanMd, colSpanSm, GridClassesMapping } from "./styles"; 6 | 7 | const makeColClassName = makeClassName("Col"); 8 | 9 | export interface ColProps extends React.HTMLAttributes { 10 | numColSpan?: number; 11 | numColSpanSm?: number; 12 | numColSpanMd?: number; 13 | numColSpanLg?: number; 14 | } 15 | 16 | const Col = React.forwardRef((props, ref) => { 17 | const { 18 | numColSpan = 1, 19 | numColSpanSm, 20 | numColSpanMd, 21 | numColSpanLg, 22 | children, 23 | className, 24 | ...other 25 | } = props; 26 | const getColSpan = ( 27 | numColSpan: number | undefined, 28 | colSpanMapping: GridClassesMapping, 29 | ): string => { 30 | if (!numColSpan) return ""; 31 | if (!Object.keys(colSpanMapping).includes(String(numColSpan))) return ""; 32 | return colSpanMapping[numColSpan]; 33 | }; 34 | 35 | const getColSpanClassNames = () => { 36 | const spanBase = getColSpan(numColSpan, colSpan); 37 | const spanSm = getColSpan(numColSpanSm, colSpanSm); 38 | const spanMd = getColSpan(numColSpanMd, colSpanMd); 39 | const spanLg = getColSpan(numColSpanLg, colSpanLg); 40 | 41 | return tremorTwMerge(spanBase, spanSm, spanMd, spanLg); 42 | }; 43 | 44 | return ( 45 |
50 | {children} 51 |
52 | ); 53 | }); 54 | 55 | Col.displayName = "Col"; 56 | 57 | export default Col; 58 | -------------------------------------------------------------------------------- /src/components/layout-elements/Grid/Grid.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { makeClassName } from "lib"; 5 | import { GridClassesMapping, gridCols, gridColsLg, gridColsMd, gridColsSm } from "./styles"; 6 | 7 | const makeGridClassName = makeClassName("Grid"); 8 | 9 | const getGridCols = (numCols: number | undefined, gridColsMapping: GridClassesMapping): string => { 10 | if (!numCols) return ""; 11 | if (!Object.keys(gridColsMapping).includes(String(numCols))) return ""; 12 | return gridColsMapping[numCols]; 13 | }; 14 | 15 | export interface GridProps extends React.HTMLAttributes { 16 | numItems?: number; 17 | numItemsSm?: number; 18 | numItemsMd?: number; 19 | numItemsLg?: number; 20 | children: React.ReactNode; 21 | } 22 | 23 | const Grid = React.forwardRef((props, ref) => { 24 | const { numItems = 1, numItemsSm, numItemsMd, numItemsLg, children, className, ...other } = props; 25 | 26 | const colsBase = getGridCols(numItems, gridCols); 27 | const colsSm = getGridCols(numItemsSm, gridColsSm); 28 | const colsMd = getGridCols(numItemsMd, gridColsMd); 29 | const colsLg = getGridCols(numItemsLg, gridColsLg); 30 | 31 | const colClassNames = tremorTwMerge(colsBase, colsSm, colsMd, colsLg); 32 | 33 | return ( 34 |
39 | {children} 40 |
41 | ); 42 | }); 43 | 44 | Grid.displayName = "Grid"; 45 | 46 | export default Grid; 47 | -------------------------------------------------------------------------------- /src/components/layout-elements/Grid/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Col } from "./Col"; 2 | export type { ColProps } from "./Col"; 3 | export { default as Grid } from "./Grid"; 4 | export type { GridProps } from "./Grid"; 5 | -------------------------------------------------------------------------------- /src/components/layout-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Accordion"; 2 | export * from "./Card"; 3 | export * from "./Divider"; 4 | export * from "./Flex"; 5 | export * from "./Grid"; 6 | export * from "./Dialog"; 7 | -------------------------------------------------------------------------------- /src/components/list-elements/List/List.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { makeClassName } from "lib"; 5 | 6 | const makeListClassName = makeClassName("List"); 7 | 8 | const List = React.forwardRef>( 9 | (props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 |
    26 | {children} 27 |
28 | ); 29 | }, 30 | ); 31 | 32 | List.displayName = "List"; 33 | 34 | export default List; 35 | -------------------------------------------------------------------------------- /src/components/list-elements/List/ListItem.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeListItemClassName = makeClassName("ListItem"); 5 | 6 | const ListItem = React.forwardRef>( 7 | (props, ref) => { 8 | const { children, className, ...other } = props; 9 | return ( 10 | <> 11 |
  • 21 | {children} 22 |
  • 23 | 24 | ); 25 | }, 26 | ); 27 | 28 | ListItem.displayName = "ListItem"; 29 | 30 | export default ListItem; 31 | -------------------------------------------------------------------------------- /src/components/list-elements/List/index.ts: -------------------------------------------------------------------------------- 1 | export { default as List } from "./List"; 2 | export { default as ListItem } from "./ListItem"; 3 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/Table.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableClassName = makeClassName("Table"); 5 | 6 | const Table = React.forwardRef>( 7 | (props, ref) => { 8 | const { children, className, ...other } = props; 9 | 10 | return ( 11 |
    12 | 25 | {children} 26 |
    27 |
    28 | ); 29 | }, 30 | ); 31 | 32 | Table.displayName = "Table"; 33 | 34 | export default Table; 35 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableBody.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableBodyClassName = makeClassName("TableBody"); 5 | 6 | const TableBody = React.forwardRef< 7 | HTMLTableSectionElement, 8 | React.HTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | <> 13 | 27 | {children} 28 | 29 | 30 | ); 31 | }); 32 | 33 | TableBody.displayName = "TableBody"; 34 | 35 | export default TableBody; 36 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableCell.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableCellClassName = makeClassName("TableCell"); 5 | 6 | const TableCell = React.forwardRef< 7 | HTMLTableCellElement, 8 | React.TdHTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | <> 13 | 22 | {children} 23 | 24 | 25 | ); 26 | }); 27 | 28 | TableCell.displayName = "TableCell"; 29 | 30 | export default TableCell; 31 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableFoot.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableFootClassName = makeClassName("TableFoot"); 5 | 6 | const TableFoot = React.forwardRef< 7 | HTMLTableSectionElement, 8 | React.HTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | 26 | {children} 27 | 28 | ); 29 | }); 30 | 31 | TableFoot.displayName = "TableFoot"; 32 | 33 | export default TableFoot; 34 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableFooterCell.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableFooterCellClassName = makeClassName("TableFooterCell"); 5 | 6 | const TableFooterCell = React.forwardRef< 7 | HTMLTableCellElement, 8 | React.HTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | <> 13 | 27 | {children} 28 | 29 | 30 | ); 31 | }); 32 | 33 | TableFooterCell.displayName = "TableFooterCell"; 34 | 35 | export default TableFooterCell; 36 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableHead.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableHeadClassName = makeClassName("TableHead"); 5 | 6 | const TableHead = React.forwardRef< 7 | HTMLTableSectionElement, 8 | React.HTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | <> 13 | 27 | {children} 28 | 29 | 30 | ); 31 | }); 32 | 33 | TableHead.displayName = "TableHead"; 34 | 35 | export default TableHead; 36 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableHeaderCell.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeTableHeaderCellClassName = makeClassName("TableHeaderCell"); 5 | 6 | const TableHeaderCell = React.forwardRef< 7 | HTMLTableCellElement, 8 | React.ThHTMLAttributes 9 | >((props, ref) => { 10 | const { children, className, ...other } = props; 11 | return ( 12 | <> 13 | 27 | {children} 28 | 29 | 30 | ); 31 | }); 32 | 33 | TableHeaderCell.displayName = "TableHeaderCell"; 34 | 35 | export default TableHeaderCell; 36 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/TableRow.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { makeClassName, tremorTwMerge } from "lib"; 3 | 4 | const makeRowClassName = makeClassName("TableRow"); 5 | 6 | const TableRow = React.forwardRef>( 7 | (props, ref) => { 8 | const { children, className, ...other } = props; 9 | return ( 10 | <> 11 | 12 | {children} 13 | 14 | 15 | ); 16 | }, 17 | ); 18 | 19 | TableRow.displayName = "TableRow"; 20 | 21 | export default TableRow; 22 | -------------------------------------------------------------------------------- /src/components/list-elements/Table/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Table } from "./Table"; 2 | export { default as TableBody } from "./TableBody"; 3 | export { default as TableCell } from "./TableCell"; 4 | export { default as TableFoot } from "./TableFoot"; 5 | export { default as TableFooterCell } from "./TableFooterCell"; 6 | export { default as TableHead } from "./TableHead"; 7 | export { default as TableHeaderCell } from "./TableHeaderCell"; 8 | export { default as TableRow } from "./TableRow"; 9 | -------------------------------------------------------------------------------- /src/components/list-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./List"; 2 | export * from "./Table"; 3 | -------------------------------------------------------------------------------- /src/components/spark-elements/SparkAreaChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SparkAreaChart } from "./SparkAreaChart"; 2 | export type { SparkAreaChartProps } from "./SparkAreaChart"; 3 | -------------------------------------------------------------------------------- /src/components/spark-elements/SparkBarChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SparkBarChart } from "./SparkBarChart"; 2 | export type { SparkBarChartProps } from "./SparkBarChart"; 3 | -------------------------------------------------------------------------------- /src/components/spark-elements/SparkLineChart/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SparkLineChart } from "./SparkLineChart"; 2 | export type { SparkLineChartProps } from "./SparkLineChart"; 3 | -------------------------------------------------------------------------------- /src/components/spark-elements/common/BaseSparkChartProps.tsx: -------------------------------------------------------------------------------- 1 | import BaseAnimationTimingProps from "components/chart-elements/common/BaseAnimationTimingProps"; 2 | import { Color } from "../../../lib"; 3 | 4 | type FixedProps = { 5 | eventType: "dot" | "category" | "bar" | "slice" | "bubble"; 6 | categoryClicked: string; 7 | }; 8 | 9 | type BaseEventProps = FixedProps & { 10 | [key: string]: number | string; 11 | }; 12 | 13 | export type EventProps = BaseEventProps | null | undefined; 14 | 15 | interface BaseSparkChartProps 16 | extends BaseAnimationTimingProps, 17 | React.HTMLAttributes { 18 | data: any[]; 19 | categories: string[]; 20 | index: string; 21 | colors?: (Color | string)[]; 22 | noDataText?: string; 23 | autoMinValue?: boolean; 24 | minValue?: number; 25 | maxValue?: number; 26 | } 27 | 28 | export default BaseSparkChartProps; 29 | -------------------------------------------------------------------------------- /src/components/spark-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./SparkBarChart"; 2 | export * from "./SparkLineChart"; 3 | export * from "./SparkAreaChart"; 4 | -------------------------------------------------------------------------------- /src/components/text-elements/Bold/Bold.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | const Bold = React.forwardRef>((props, ref) => { 5 | const { children, className, ...other } = props; 6 | return ( 7 | 8 | {children} 9 | 10 | ); 11 | }); 12 | 13 | Bold.displayName = "Bold"; 14 | 15 | export default Bold; 16 | -------------------------------------------------------------------------------- /src/components/text-elements/Bold/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Bold } from "./Bold"; 2 | -------------------------------------------------------------------------------- /src/components/text-elements/Callout/Callout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { getColorClassNames, makeClassName, tremorTwMerge, Color } from "lib"; 3 | import { colorPalette } from "lib/theme"; 4 | 5 | const makeCalloutClassName = makeClassName("Callout"); 6 | 7 | export interface CalloutProps extends React.HTMLAttributes { 8 | title: string; 9 | icon?: React.ElementType; 10 | color?: Color; 11 | } 12 | 13 | const Callout = React.forwardRef((props, ref) => { 14 | const { title, icon, color, className, children, ...other } = props; 15 | const Icon = icon; 16 | return ( 17 |
    39 |
    40 | {Icon ? ( 41 | 44 | ) : null} 45 |

    {title}

    46 |
    47 |

    54 | {children} 55 |

    56 |
    57 | ); 58 | }); 59 | 60 | Callout.displayName = "Callout"; 61 | 62 | export default Callout; 63 | -------------------------------------------------------------------------------- /src/components/text-elements/Callout/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Callout } from "./Callout"; 2 | export type { CalloutProps } from "./Callout"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/Italic/Italic.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | const Italic = React.forwardRef>((props, ref) => { 5 | const { children, className, ...other } = props; 6 | return ( 7 | 8 | {children} 9 | 10 | ); 11 | }); 12 | 13 | Italic.displayName = "Italic"; 14 | 15 | export default Italic; 16 | -------------------------------------------------------------------------------- /src/components/text-elements/Italic/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Italic } from "./Italic"; 2 | -------------------------------------------------------------------------------- /src/components/text-elements/Legend/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Legend } from "./Legend"; 2 | export type { LegendProps } from "./Legend"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/Metric/Metric.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { getColorClassNames } from "lib"; 5 | import { colorPalette } from "lib/theme"; 6 | import { Color } from "../../../lib"; 7 | 8 | export interface MetricProps extends React.HTMLAttributes { 9 | color?: Color; 10 | } 11 | 12 | const Metric = React.forwardRef((props, ref) => { 13 | const { color, children, className, ...other } = props; 14 | return ( 15 |

    26 | {children} 27 |

    28 | ); 29 | }); 30 | 31 | Metric.displayName = "Metric"; 32 | 33 | export default Metric; 34 | -------------------------------------------------------------------------------- /src/components/text-elements/Metric/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Metric } from "./Metric"; 2 | export type { MetricProps } from "./Metric"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/Subtitle/Subtitle.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { getColorClassNames } from "lib"; 5 | import { colorPalette } from "lib/theme"; 6 | import { Color } from "../../../lib"; 7 | 8 | export interface SubtitleProps extends React.HTMLAttributes { 9 | color?: Color; 10 | } 11 | 12 | const Subtitle = React.forwardRef((props, ref) => { 13 | const { color, children, className, ...other } = props; 14 | return ( 15 |

    25 | {children} 26 |

    27 | ); 28 | }); 29 | 30 | Subtitle.displayName = "Subtitle"; 31 | 32 | export default Subtitle; 33 | -------------------------------------------------------------------------------- /src/components/text-elements/Subtitle/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Subtitle } from "./Subtitle"; 2 | export type { SubtitleProps } from "./Subtitle"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/Text/Text.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { getColorClassNames } from "lib"; 5 | import { colorPalette } from "lib/theme"; 6 | import { Color } from "../../../lib/inputTypes"; 7 | 8 | export interface TextProps extends React.HTMLAttributes { 9 | color?: Color; 10 | } 11 | 12 | const Text = React.forwardRef((props, ref) => { 13 | const { color, className, children } = props; 14 | return ( 15 |

    31 | {children} 32 |

    33 | ); 34 | }); 35 | 36 | Text.displayName = "Text"; 37 | 38 | export default Text; 39 | -------------------------------------------------------------------------------- /src/components/text-elements/Text/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Text } from "./Text"; 2 | export type { TextProps } from "./Text"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/Title/Title.tsx: -------------------------------------------------------------------------------- 1 | import { tremorTwMerge } from "lib"; 2 | import React from "react"; 3 | 4 | import { getColorClassNames } from "lib"; 5 | import { colorPalette } from "lib/theme"; 6 | import { Color } from "../../../lib"; 7 | 8 | export interface TitleProps extends React.HTMLAttributes { 9 | color?: Color; 10 | } 11 | 12 | const Title = React.forwardRef((props, ref) => { 13 | const { color, children, className, ...other } = props; 14 | return ( 15 |

    27 | {children} 28 |

    29 | ); 30 | }); 31 | 32 | Title.displayName = "Title"; 33 | 34 | export default Title; 35 | -------------------------------------------------------------------------------- /src/components/text-elements/Title/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Title } from "./Title"; 2 | export type { TitleProps } from "./Title"; 3 | -------------------------------------------------------------------------------- /src/components/text-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Bold"; 2 | export * from "./Callout"; 3 | export * from "./Italic"; 4 | export * from "./Legend"; 5 | export * from "./Metric"; 6 | export * from "./Subtitle"; 7 | export * from "./Text"; 8 | export * from "./Title"; 9 | -------------------------------------------------------------------------------- /src/components/util-elements/Tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tooltip } from "./Tooltip"; 2 | export type { TooltipProps } from "./Tooltip"; 3 | -------------------------------------------------------------------------------- /src/components/util-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Tooltip"; 2 | -------------------------------------------------------------------------------- /src/components/vis-elements/BarList/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BarList } from "./BarList"; 2 | export type { BarListProps } from "./BarList"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/CategoryBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CategoryBar } from "./CategoryBar"; 2 | export type { CategoryBarProps } from "./CategoryBar"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/DeltaBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DeltaBar } from "./DeltaBar"; 2 | export type { DeltaBarProps } from "./DeltaBar"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/DeltaBar/styles.ts: -------------------------------------------------------------------------------- 1 | import { BaseColors, DeltaTypes, getColorClassNames } from "lib"; 2 | import { colorPalette } from "lib/theme"; 3 | 4 | export type ColorTypes = { 5 | bgColor: string; 6 | }; 7 | 8 | export const colors: { [key: string]: ColorTypes } = { 9 | [DeltaTypes.Increase]: { 10 | bgColor: getColorClassNames(BaseColors.Emerald, colorPalette.background).bgColor, 11 | }, 12 | [DeltaTypes.ModerateIncrease]: { 13 | bgColor: getColorClassNames(BaseColors.Emerald, colorPalette.background).bgColor, 14 | }, 15 | [DeltaTypes.Decrease]: { 16 | bgColor: getColorClassNames(BaseColors.Rose, colorPalette.background).bgColor, 17 | }, 18 | [DeltaTypes.ModerateDecrease]: { 19 | bgColor: getColorClassNames(BaseColors.Rose, colorPalette.background).bgColor, 20 | }, 21 | [DeltaTypes.Unchanged]: { 22 | bgColor: getColorClassNames(BaseColors.Orange, colorPalette.background).bgColor, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/vis-elements/MarkerBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default as MarkerBar } from "./MarkerBar"; 2 | export type { MarkerBarProps } from "./MarkerBar"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/ProgressBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ProgressBar } from "./ProgressBar"; 2 | export type { ProgressBarProps } from "./ProgressBar"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/ProgressCircle/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ProgressCircle } from "./ProgressCircle"; 2 | export type { ProgressCircleProps } from "./ProgressCircle"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/Tracker/Tracker.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { tremorTwMerge } from "lib"; 3 | import React from "react"; 4 | 5 | import Tooltip, { useTooltip } from "components/util-elements/Tooltip/Tooltip"; 6 | import { colorPalette, getColorClassNames, makeClassName, mergeRefs } from "lib"; 7 | import { Color } from "../../../lib/inputTypes"; 8 | 9 | export const makeTrackerClassName = makeClassName("Tracker"); 10 | 11 | export interface TrackerBlockProps { 12 | key?: string | number; 13 | color?: Color | string; 14 | tooltip?: string; 15 | } 16 | 17 | const TrackerBlock = React.forwardRef((props, ref) => { 18 | const { color, tooltip, ...other } = props; 19 | 20 | const { tooltipProps, getReferenceProps } = useTooltip(); 21 | 22 | return ( 23 |
    33 | 34 |
    35 | ); 36 | }); 37 | 38 | TrackerBlock.displayName = "TrackerBlock"; 39 | 40 | export interface TrackerProps extends React.HTMLAttributes { 41 | data: TrackerBlockProps[]; 42 | } 43 | 44 | const Tracker = React.forwardRef((props, ref) => { 45 | const { data = [], className, ...other } = props; 46 | return ( 47 |
    56 | {data.map((item, idx) => ( 57 | 58 | ))} 59 |
    60 | ); 61 | }); 62 | 63 | Tracker.displayName = "Tracker"; 64 | 65 | export default Tracker; 66 | -------------------------------------------------------------------------------- /src/components/vis-elements/Tracker/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tracker } from "./Tracker"; 2 | export type { TrackerProps } from "./Tracker"; 3 | -------------------------------------------------------------------------------- /src/components/vis-elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./BarList"; 2 | export * from "./CategoryBar"; 3 | export * from "./DeltaBar"; 4 | export * from "./MarkerBar"; 5 | export * from "./ProgressBar"; 6 | export * from "./ProgressCircle"; 7 | export * from "./Tracker"; 8 | -------------------------------------------------------------------------------- /src/contexts/BaseColorContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | import { BaseColors } from "lib"; 4 | import { Color } from "../lib/inputTypes"; 5 | 6 | const BaseColorContext = createContext(BaseColors.Blue); 7 | 8 | export default BaseColorContext; 9 | -------------------------------------------------------------------------------- /src/contexts/IndexContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const IndexContext = createContext(0); 4 | 5 | export default IndexContext; 6 | -------------------------------------------------------------------------------- /src/contexts/RootStylesContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const RootStylesContext = createContext(undefined); 4 | 5 | export default RootStylesContext; 6 | -------------------------------------------------------------------------------- /src/contexts/SelectedValueContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export interface SelectedValueContextValue { 4 | selectedValue: any; 5 | handleValueChange?: (value: any) => void; 6 | } 7 | 8 | const SelectedValueContext = createContext({ 9 | selectedValue: undefined, 10 | handleValueChange: undefined, 11 | }); 12 | 13 | export default SelectedValueContext; 14 | -------------------------------------------------------------------------------- /src/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BaseColorContext } from "./BaseColorContext"; 2 | export { default as IndexContext } from "./IndexContext"; 3 | export { default as RootStylesContext } from "./RootStylesContext"; 4 | export { default as SelectedValueContext } from "./SelectedValueContext"; 5 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useInternalState } from "./useInternalState"; 2 | export { default as useOnWindowResize } from "./useOnWindowResize"; 3 | -------------------------------------------------------------------------------- /src/hooks/useInternalState.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | const useInternalState = (defaultValueProp: T, valueProp: T) => { 4 | const isControlled = valueProp !== undefined; 5 | const [valueState, setValueState] = useState(defaultValueProp); 6 | 7 | const value = isControlled ? valueProp : valueState; 8 | const setValue = (nextValue: T) => { 9 | if (isControlled) { 10 | return; 11 | } 12 | setValueState(nextValue); 13 | }; 14 | 15 | return [value, setValue] as [T, React.Dispatch>]; 16 | }; 17 | 18 | export default useInternalState; 19 | -------------------------------------------------------------------------------- /src/hooks/useOnWindowResize.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const useOnWindowResize = (handler: { (): void }) => { 4 | React.useEffect(() => { 5 | const handleResize = () => { 6 | handler(); 7 | }; 8 | handleResize(); 9 | window.addEventListener("resize", handleResize); 10 | 11 | return () => window.removeEventListener("resize", handleResize); 12 | }, [handler]); 13 | }; 14 | 15 | export default useOnWindowResize; 16 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components"; 2 | export * from "./lib/inputTypes"; 3 | -------------------------------------------------------------------------------- /src/lib/constants.ts: -------------------------------------------------------------------------------- 1 | import { Color, DeltaType, HorizontalPosition, Size, VerticalPosition } from "./inputTypes"; 2 | 3 | export const DeltaTypes: { [key: string]: DeltaType } = { 4 | Increase: "increase", 5 | ModerateIncrease: "moderateIncrease", 6 | Decrease: "decrease", 7 | ModerateDecrease: "moderateDecrease", 8 | Unchanged: "unchanged", 9 | }; 10 | 11 | export const BaseColors: { [key: string]: Color } = { 12 | Slate: "slate", 13 | Gray: "gray", 14 | Zinc: "zinc", 15 | Neutral: "neutral", 16 | Stone: "stone", 17 | Red: "red", 18 | Orange: "orange", 19 | Amber: "amber", 20 | Yellow: "yellow", 21 | Lime: "lime", 22 | Green: "green", 23 | Emerald: "emerald", 24 | Teal: "teal", 25 | Cyan: "cyan", 26 | Sky: "sky", 27 | Blue: "blue", 28 | Indigo: "indigo", 29 | Violet: "violet", 30 | Purple: "purple", 31 | Fuchsia: "fuchsia", 32 | Pink: "pink", 33 | Rose: "rose", 34 | }; 35 | 36 | export const Sizes: { [key: string]: Size } = { 37 | XS: "xs", 38 | SM: "sm", 39 | MD: "md", 40 | LG: "lg", 41 | XL: "xl", 42 | }; 43 | 44 | export const HorizontalPositions: { [key: string]: HorizontalPosition } = { 45 | Left: "left", 46 | Right: "right", 47 | }; 48 | 49 | export const VerticalPositions: { [key: string]: VerticalPosition } = { 50 | Top: "top", 51 | Bottom: "bottom", 52 | }; 53 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./constants"; 2 | export * from "./inputTypes"; 3 | export * from "./theme"; 4 | export * from "./tremorTwMerge"; 5 | export * from "./utils"; 6 | -------------------------------------------------------------------------------- /src/lib/inputTypes.ts: -------------------------------------------------------------------------------- 1 | export type ValueFormatter = { 2 | (value: number): string; 3 | }; 4 | 5 | export type CurveType = "linear" | "natural" | "monotone" | "step"; 6 | 7 | export type Interval = "preserveStartEnd" | "equidistantPreserveStart"; 8 | 9 | export type IntervalType = "preserveStartEnd" | Interval; 10 | 11 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 12 | const iconVariantValues = ["simple", "light", "shadow", "solid", "outlined"] as const; 13 | 14 | export type IconVariant = (typeof iconVariantValues)[number]; 15 | 16 | export type HorizontalPosition = "left" | "right"; 17 | 18 | export type VerticalPosition = "top" | "bottom"; 19 | 20 | export type ButtonVariant = "primary" | "secondary" | "light"; 21 | 22 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 23 | const deltaTypeValues = [ 24 | "increase", 25 | "moderateIncrease", 26 | "decrease", 27 | "moderateDecrease", 28 | "unchanged", 29 | ] as const; 30 | 31 | export type DeltaType = (typeof deltaTypeValues)[number]; 32 | 33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 34 | const sizeValues = ["xs", "sm", "md", "lg", "xl"] as const; 35 | 36 | export type Size = (typeof sizeValues)[number]; 37 | 38 | const colorValues = [ 39 | "slate", 40 | "gray", 41 | "zinc", 42 | "neutral", 43 | "stone", 44 | "red", 45 | "orange", 46 | "amber", 47 | "yellow", 48 | "lime", 49 | "green", 50 | "emerald", 51 | "teal", 52 | "cyan", 53 | "sky", 54 | "blue", 55 | "indigo", 56 | "violet", 57 | "purple", 58 | "fuchsia", 59 | "pink", 60 | "rose", 61 | ] as const; 62 | 63 | export type Color = (typeof colorValues)[number]; 64 | export type CustomColor = Color | string; 65 | export const getIsBaseColor = (color: Color | string) => colorValues.includes(color as Color); 66 | 67 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 68 | const justifyContentValues = ["start", "end", "center", "between", "around", "evenly"] as const; 69 | export type JustifyContent = (typeof justifyContentValues)[number]; 70 | 71 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 72 | const alignItemsValues = ["start", "end", "center", "baseline", "stretch"] as const; 73 | export type AlignItems = (typeof alignItemsValues)[number]; 74 | 75 | export type FlexDirection = "row" | "col" | "row-reverse" | "col-reverse"; 76 | 77 | export type FunnelVariantType = "base" | "center"; 78 | -------------------------------------------------------------------------------- /src/lib/theme.ts: -------------------------------------------------------------------------------- 1 | import { BaseColors } from "./constants"; 2 | import { Color } from "./inputTypes"; 3 | 4 | export const DEFAULT_COLOR: Color = "gray"; 5 | export const WHITE = "white"; 6 | export const TRANSPARENT = "transparent"; 7 | 8 | export const colorPalette = { 9 | canvasBackground: 50, 10 | lightBackground: 100, 11 | background: 500, 12 | darkBackground: 600, 13 | darkestBackground: 800, 14 | lightBorder: 200, 15 | border: 500, 16 | darkBorder: 700, 17 | lightRing: 200, 18 | ring: 300, 19 | iconRing: 500, 20 | lightText: 400, 21 | text: 500, 22 | iconText: 600, 23 | darkText: 700, 24 | darkestText: 900, 25 | icon: 500, 26 | }; 27 | 28 | export const themeColorRange: Color[] = [ 29 | BaseColors.Blue, 30 | BaseColors.Cyan, 31 | BaseColors.Sky, 32 | BaseColors.Indigo, 33 | BaseColors.Violet, 34 | BaseColors.Purple, 35 | BaseColors.Fuchsia, 36 | BaseColors.Slate, 37 | BaseColors.Gray, 38 | BaseColors.Zinc, 39 | BaseColors.Neutral, 40 | BaseColors.Stone, 41 | BaseColors.Red, 42 | BaseColors.Orange, 43 | BaseColors.Amber, 44 | BaseColors.Yellow, 45 | BaseColors.Lime, 46 | BaseColors.Green, 47 | BaseColors.Emerald, 48 | BaseColors.Teal, 49 | BaseColors.Pink, 50 | BaseColors.Rose, 51 | ]; 52 | -------------------------------------------------------------------------------- /src/lib/tremorTwMerge.ts: -------------------------------------------------------------------------------- 1 | import { extendTailwindMerge } from "tailwind-merge"; 2 | 3 | export const tremorTwMerge = extendTailwindMerge({ 4 | extend: { 5 | classGroups: { 6 | shadow: [ 7 | { 8 | shadow: [ 9 | { 10 | tremor: ["input", "card", "dropdown"], 11 | "dark-tremor": ["input", "card", "dropdown"], 12 | }, 13 | ], 14 | }, 15 | ], 16 | rounded: [ 17 | { 18 | rounded: [ 19 | { 20 | tremor: ["small", "default", "full"], 21 | "dark-tremor": ["small", "default", "full"], 22 | }, 23 | ], 24 | }, 25 | ], 26 | "font-size": [ 27 | { 28 | text: [ 29 | { 30 | tremor: ["default", "title", "metric"], 31 | "dark-tremor": ["default", "title", "metric"], 32 | }, 33 | ], 34 | }, 35 | ], 36 | }, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /src/stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /src/stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /src/stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /src/stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /src/stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /src/stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /src/stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /src/stories/chart-elements/helpers/testDataScatterChart.tsx: -------------------------------------------------------------------------------- 1 | export const simpleScatterChartData = [ 2 | { 3 | location: "Location A", 4 | x: 100, 5 | y: 200, 6 | z: 200, 7 | }, 8 | { 9 | location: "Location A", 10 | x: 120, 11 | y: 100, 12 | z: 260, 13 | }, 14 | { 15 | location: "Location A", 16 | x: 170, 17 | y: 300, 18 | z: 400, 19 | }, 20 | { 21 | location: "Location B", 22 | x: 140, 23 | y: 250, 24 | z: 280, 25 | }, 26 | { 27 | location: "Location B", 28 | x: 150, 29 | y: 400, 30 | z: 500, 31 | }, 32 | { 33 | location: "Location B", 34 | x: 110, 35 | y: 280, 36 | z: 200, 37 | }, 38 | { 39 | location: "Location C", 40 | x: 200, 41 | y: 260, 42 | z: 240, 43 | }, 44 | { 45 | location: "Location C", 46 | x: 220, 47 | y: 290, 48 | z: 120, 49 | }, 50 | { 51 | location: "Location D", 52 | x: 0, 53 | y: 190, 54 | z: 250, 55 | }, 56 | { 57 | location: "Location D", 58 | x: 70, 59 | y: 0, 60 | z: 950, 61 | }, 62 | ]; 63 | 64 | export const simpleScatterChartData2 = [ 65 | { 66 | country: "Afghanistan", 67 | lifeExp: 27.7, 68 | gdpPercap: 1156, 69 | population: 7480464, 70 | continent: "Asia", 71 | happinessLev: 4.5, 72 | }, 73 | { 74 | country: "Albania", 75 | lifeExp: 46.5, 76 | gdpPercap: 1736, 77 | population: 1366747, 78 | continent: "Europe", 79 | happinessLev: 5.5, 80 | }, 81 | { 82 | country: "France", 83 | lifeExp: 86.5, 84 | gdpPercap: 5636, 85 | population: 7000000, 86 | continent: "Europe", 87 | happinessLev: 8.5, 88 | }, 89 | { 90 | country: "South Africa", 91 | lifeExp: 75.5, 92 | gdpPercap: 3694, 93 | population: 4100000, 94 | continent: "Africa", 95 | happinessLev: 6.5, 96 | }, 97 | ]; 98 | -------------------------------------------------------------------------------- /src/stories/chart-elements/helpers/utils.ts: -------------------------------------------------------------------------------- 1 | export const valueFormatter = (number: number) => { 2 | return Intl.NumberFormat("us").format(number).toString() + " $"; 3 | }; 4 | -------------------------------------------------------------------------------- /src/stories/icon-elements/Badge.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | import { BaseColors, Sizes as InputSizes } from "lib/constants"; 6 | 7 | import { ArrowUpIcon } from "assets"; 8 | import { Badge, Grid } from "components"; 9 | 10 | const meta: Meta = { 11 | title: "UI/Icon/Badge", 12 | component: Badge, 13 | args: { 14 | children: "Live", 15 | tooltip: "Tooltip", 16 | icon: ArrowUpIcon, 17 | }, 18 | }; 19 | 20 | export default meta; 21 | type Story = StoryObj; 22 | 23 | const BadgeTemplateColors: Story = { 24 | render: ({ ...args }) => { 25 | return ( 26 | 27 | 28 | {Object.values(BaseColors).map((color) => ( 29 | 30 | ))} 31 | 32 | ); 33 | }, 34 | }; 35 | 36 | const BadgeTemplateSizes: Story = { 37 | render: ({ ...args }) => { 38 | return ( 39 | 40 | {Object.values(InputSizes).map((size) => ( 41 | 42 | ))} 43 | 44 | ); 45 | }, 46 | }; 47 | 48 | export const Default: Story = { 49 | args: {}, 50 | }; 51 | 52 | export const Sizes: Story = { 53 | ...BadgeTemplateSizes, 54 | }; 55 | 56 | export const Colors: Story = { 57 | ...BadgeTemplateColors, 58 | }; 59 | 60 | export const NoIcon: Story = { 61 | args: { 62 | icon: undefined, 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /src/stories/icon-elements/BadgeDelta.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | import { DeltaTypes as InputDeltaTypes, Sizes as InputSizes } from "lib/constants"; 6 | 7 | import { BadgeDelta, Grid } from "components"; 8 | 9 | const meta: Meta = { 10 | title: "UI/Icon/BadgeDelta", 11 | component: BadgeDelta, 12 | args: { 13 | children: "12.5%", 14 | tooltip: "Tooltip", 15 | }, 16 | }; 17 | 18 | export default meta; 19 | type Story = StoryObj; 20 | 21 | const BadgeDeltaTemplateSizes: Story = { 22 | render: ({ ...args }) => { 23 | return ( 24 | 25 | {Object.values(InputSizes).map((size) => ( 26 | <> 27 | 28 | 29 | ))} 30 | 31 | ); 32 | }, 33 | }; 34 | 35 | const BadgeDeltaTemplateTypes: Story = { 36 | render: ({ ...args }) => { 37 | return ( 38 | 39 | 40 | {Object.values(InputDeltaTypes).map((deltaType) => ( 41 | 42 | ))} 43 | 44 | ); 45 | }, 46 | }; 47 | 48 | export const Default: Story = { 49 | args: {}, 50 | }; 51 | 52 | export const Sizes: Story = { 53 | ...BadgeDeltaTemplateSizes, 54 | }; 55 | 56 | export const Types: Story = { 57 | ...BadgeDeltaTemplateTypes, 58 | }; 59 | -------------------------------------------------------------------------------- /src/stories/input-elements/MultiSelect.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import { MultiSelect } from "components"; 4 | import { 5 | SimpleMultiSelect, 6 | SimpleMultiSelectControlled, 7 | SimpleMultiSelectForm, 8 | SimpleMultiSelectWithStaticAndDynamicChildren, 9 | } from "./helpers/SimpleMultiSelect"; 10 | 11 | import { CalendarIcon } from "assets"; 12 | 13 | const meta: Meta = { 14 | title: "UI/Input/MultiSelect", 15 | component: MultiSelect, 16 | }; 17 | 18 | export default meta; 19 | type Story = StoryObj; 20 | 21 | export const UncontrolledDefault: Story = { 22 | render: SimpleMultiSelect, 23 | args: {}, 24 | }; 25 | 26 | export const UncontrolledDefaultWithStaticAndDynamicChildren: Story = { 27 | render: SimpleMultiSelectWithStaticAndDynamicChildren, 28 | args: {}, 29 | }; 30 | 31 | export const UncontrolledDefaultValues: Story = { 32 | render: SimpleMultiSelect, 33 | args: { defaultValue: ["5", "1"] }, 34 | }; 35 | 36 | export const UncontrolledIcon: Story = { 37 | render: SimpleMultiSelect, 38 | args: { icon: CalendarIcon, defaultValue: ["5", "1"] }, 39 | }; 40 | 41 | export const UncontrolledDisabled: Story = { 42 | render: SimpleMultiSelect, 43 | args: { icon: CalendarIcon, defaultValue: ["5", "1"], disabled: true }, 44 | }; 45 | 46 | export const Controlled: Story = { 47 | render: SimpleMultiSelectControlled, 48 | args: {}, 49 | }; 50 | 51 | export const Error: Story = { 52 | render: SimpleMultiSelect, 53 | args: { 54 | error: true, 55 | errorMessage: "Error message", 56 | }, 57 | }; 58 | 59 | export const Form: Story = { 60 | render: SimpleMultiSelectForm, 61 | args: { 62 | required: true, 63 | }, 64 | }; 65 | 66 | export const WithCustomMinWidth: Story = { 67 | render: SimpleMultiSelect, 68 | args: { 69 | className: "min-w-min w-[95px]", 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /src/stories/input-elements/NumberInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import { CalendarIcon } from "assets"; 4 | import { NumberInput } from "components"; 5 | import { SimpleNumberInput, SimpleNumberInputControlled } from "./helpers/SimpleNumberInput"; 6 | 7 | const meta: Meta = { 8 | title: "UI/Input/NumberInput", 9 | component: NumberInput, 10 | }; 11 | 12 | export default meta; 13 | type Story = StoryObj; 14 | 15 | export const Default: Story = { 16 | args: {}, 17 | }; 18 | 19 | export const DefaultSet: Story = { 20 | render: SimpleNumberInput, 21 | args: {}, 22 | }; 23 | 24 | export const Icon: Story = { 25 | render: SimpleNumberInput, 26 | args: { 27 | icon: CalendarIcon, 28 | }, 29 | }; 30 | 31 | export const NoPlaceholder: Story = { 32 | render: SimpleNumberInput, 33 | args: { 34 | placeholder: "", 35 | }, 36 | }; 37 | 38 | export const DefaultValue: Story = { 39 | render: SimpleNumberInput, 40 | args: { 41 | value: 123, 42 | }, 43 | }; 44 | 45 | export const StepProp: Story = { 46 | render: SimpleNumberInput, 47 | args: { 48 | step: ".1", 49 | }, 50 | }; 51 | 52 | export const StepPropNumber: Story = { 53 | render: SimpleNumberInput, 54 | args: { 55 | step: 0.1, 56 | }, 57 | }; 58 | 59 | export const MinMaxProp: Story = { 60 | render: SimpleNumberInput, 61 | args: { 62 | min: "2", 63 | max: "10", 64 | }, 65 | }; 66 | 67 | export const Error: Story = { 68 | render: SimpleNumberInput, 69 | args: { 70 | value: 123, 71 | error: true, 72 | }, 73 | }; 74 | 75 | export const ErrorMessage: Story = { 76 | render: SimpleNumberInput, 77 | args: { 78 | value: 123, 79 | error: true, 80 | errorMessage: "Something is wrong", 81 | }, 82 | }; 83 | 84 | export const Disabled: Story = { 85 | render: SimpleNumberInput, 86 | args: { 87 | value: 123, 88 | disabled: true, 89 | }, 90 | }; 91 | 92 | export const DisabledAndError: Story = { 93 | render: SimpleNumberInput, 94 | args: { 95 | value: 123, 96 | error: true, 97 | disabled: true, 98 | }, 99 | }; 100 | 101 | export const ControlledWithOnChange: Story = { 102 | render: SimpleNumberInputControlled, 103 | args: {}, 104 | }; 105 | -------------------------------------------------------------------------------- /src/stories/input-elements/SearchSelect.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import { SearchSelect } from "components"; 4 | import { 5 | SimpleSearchSelect, 6 | SimpleSearchSelectControlled, 7 | SimpleSearchSelectWithStaticAndDynamicChildren, 8 | SimpleSearchSelectForm, 9 | SimpleSearchSelectServerSideRendering, 10 | } from "./helpers/SimpleSearchSelect"; 11 | 12 | import { CalendarIcon } from "assets"; 13 | 14 | const meta: Meta = { 15 | title: "UI/Input/SearchSelect", 16 | component: SearchSelect, 17 | }; 18 | 19 | export default meta; 20 | type Story = StoryObj; 21 | 22 | export const UncontrolledDefault: Story = { 23 | render: SimpleSearchSelect, 24 | args: {}, 25 | }; 26 | 27 | export const UncontrolledDefaultWithStaticAndDynamicChildren: Story = { 28 | render: SimpleSearchSelectWithStaticAndDynamicChildren, 29 | args: {}, 30 | }; 31 | 32 | export const UncontrolledOnValueChange: Story = { 33 | render: SimpleSearchSelect, 34 | args: { onValueChange: (v: string) => alert(v) }, 35 | }; 36 | 37 | export const UncontrolledEnableClear: Story = { 38 | render: SimpleSearchSelect, 39 | args: { onValueChange: (v: string) => alert(v), enableClear: true }, 40 | }; 41 | 42 | export const UncontrolledDefaultValue: Story = { 43 | render: SimpleSearchSelect, 44 | args: { 45 | defaultValue: "5", 46 | }, 47 | }; 48 | 49 | export const Icon: Story = { 50 | render: SimpleSearchSelect, 51 | args: { 52 | defaultValue: "5", 53 | icon: CalendarIcon, 54 | }, 55 | }; 56 | 57 | export const Error: Story = { 58 | render: SimpleSearchSelect, 59 | args: { 60 | error: true, 61 | errorMessage: "Error message", 62 | }, 63 | }; 64 | 65 | export const Disabled: Story = { 66 | render: SimpleSearchSelect, 67 | args: { 68 | onValueChange: (v: string) => alert(v), 69 | disabled: true, 70 | }, 71 | }; 72 | 73 | export const Controlled: Story = { 74 | render: SimpleSearchSelectControlled, 75 | args: {}, 76 | }; 77 | 78 | export const Form: Story = { 79 | render: SimpleSearchSelectForm, 80 | args: { 81 | required: true, 82 | }, 83 | }; 84 | 85 | export const ServerSideRendering: Story = { 86 | render: SimpleSearchSelectServerSideRendering, 87 | args: { 88 | required: true, 89 | }, 90 | }; 91 | 92 | export const WithCustomMinWidth: Story = { 93 | render: SimpleSearchSelect, 94 | args: { 95 | className: "min-w-min w-[95px]", 96 | }, 97 | }; 98 | -------------------------------------------------------------------------------- /src/stories/input-elements/Select.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import { Select } from "components"; 4 | import { 5 | SimpleSelect, 6 | SimpleSelectControlled, 7 | SimpleSelectForm, 8 | SimpleSelectWithStaticAndDynamicChildren, 9 | } from "./helpers/SimpleSelect"; 10 | 11 | import { CalendarIcon } from "assets"; 12 | 13 | const meta: Meta = { 14 | title: "UI/Input/Select", 15 | component: Select, 16 | }; 17 | 18 | export default meta; 19 | type Story = StoryObj; 20 | 21 | export const UncontrolledDefault: Story = { 22 | render: SimpleSelect, 23 | args: {}, 24 | }; 25 | 26 | export const UncontrolledDefaultWithStaticAndDynamicChildren: Story = { 27 | render: SimpleSelectWithStaticAndDynamicChildren, 28 | args: {}, 29 | }; 30 | 31 | export const UncontrolledOnValueChange: Story = { 32 | render: SimpleSelect, 33 | args: { onValueChange: (v: string) => alert(v) }, 34 | }; 35 | 36 | export const UncontrolledEnableClear: Story = { 37 | render: SimpleSelect, 38 | args: { onValueChange: (v: string) => alert(v), enableClear: true }, 39 | }; 40 | 41 | export const UncontrolledDefaultValue: Story = { 42 | render: SimpleSelect, 43 | args: { 44 | defaultValue: "5", 45 | }, 46 | }; 47 | 48 | export const Icon: Story = { 49 | render: SimpleSelect, 50 | args: { 51 | defaultValue: "5", 52 | icon: CalendarIcon, 53 | }, 54 | }; 55 | 56 | export const UncontrolledDisabled: Story = { 57 | render: SimpleSelect, 58 | args: { 59 | icon: CalendarIcon, 60 | disabled: true, 61 | }, 62 | }; 63 | 64 | export const Controlled: Story = { 65 | render: SimpleSelectControlled, 66 | }; 67 | 68 | export const Error: Story = { 69 | render: SimpleSelect, 70 | args: { 71 | error: true, 72 | errorMessage: "Error message", 73 | }, 74 | }; 75 | 76 | export const Form: Story = { 77 | render: SimpleSelectForm, 78 | args: { 79 | required: true, 80 | }, 81 | }; 82 | 83 | export const WithCustomMinWidth: Story = { 84 | render: SimpleSelect, 85 | args: { 86 | className: "min-w-min w-[95px]", 87 | }, 88 | }; 89 | -------------------------------------------------------------------------------- /src/stories/input-elements/Switch.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | import { Switch } from "components"; 3 | import { SimpleSwitch, SimpleIdSwitch } from "./helpers/SimpleSwitch"; 4 | 5 | const meta: Meta = { 6 | title: "UI/Input/Switch", 7 | component: Switch, 8 | }; 9 | 10 | export default meta; 11 | type Story = StoryObj; 12 | 13 | export const Uncontrolled: Story = { 14 | args: {}, 15 | }; 16 | 17 | export const DefaultChecked: Story = { 18 | args: { 19 | defaultChecked: true, 20 | }, 21 | }; 22 | 23 | export const Disabled: Story = { 24 | args: { 25 | disabled: true, 26 | }, 27 | }; 28 | 29 | export const CustomColor: Story = { 30 | args: { 31 | color: "emerald", 32 | }, 33 | }; 34 | 35 | export const Tooltip: Story = { 36 | args: { 37 | tooltip: "Action disabled", 38 | }, 39 | }; 40 | 41 | export const TooltipDisabled: Story = { 42 | args: { 43 | tooltip: "Action disabled", 44 | disabled: true, 45 | }, 46 | }; 47 | 48 | export const Controlled: Story = { 49 | render: SimpleSwitch, 50 | }; 51 | 52 | export const Required: Story = { 53 | render: SimpleSwitch, 54 | args: { 55 | required: true, 56 | }, 57 | }; 58 | 59 | export const Error: Story = { 60 | args: { 61 | error: true, 62 | errorMessage: "Something is wrong", 63 | }, 64 | }; 65 | 66 | export const Id: Story = { 67 | render: SimpleIdSwitch, 68 | args: { 69 | required: true, 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /src/stories/input-elements/TextArea.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | import { Button, Textarea } from "components"; 3 | import React from "react"; 4 | 5 | const meta: Meta = { 6 | title: "UI/Input/Textarea", 7 | component: Textarea, 8 | }; 9 | 10 | export default meta; 11 | type Story = StoryObj; 12 | 13 | function Controlled({ ...args }) { 14 | const [value, setValue] = React.useState("Default Value"); 15 | return ( 16 |
    17 |