├── .changeset
├── README.md
├── bright-penguins-flow.md
├── config.json
├── fair-rabbits-report.md
├── five-otters-build.md
├── friendly-glasses-wait.md
├── gentle-lizards-remember.md
├── green-rings-destroy.md
├── healthy-stingrays-return.md
├── heavy-files-rush.md
├── itchy-socks-count.md
├── khaki-beers-pump.md
├── light-toys-compare.md
├── many-bugs-battle.md
├── moody-phones-retire.md
├── nasty-wolves-know.md
├── nervous-tools-build.md
├── plenty-jobs-heal.md
├── polite-cougars-happen.md
├── pre.json
├── silly-rats-attack.md
└── thirty-bees-cross.md
├── .eslintrc.js
├── .github
└── workflows
│ ├── main.yml
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── docs
├── .eslintrc.js
├── .gitignore
├── CHANGELOG.md
├── README.md
├── components
│ ├── authors.tsx
│ ├── blog-index.tsx
│ ├── component-link.tsx
│ └── demo-card.tsx
├── next.config.js
├── package.json
├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── _meta.json
│ ├── about.mdx
│ ├── api
│ │ └── hello.ts
│ ├── blog.mdx
│ ├── blog
│ │ ├── _meta.json
│ │ └── announcing-catalystui.mdx
│ ├── docs
│ │ ├── _meta.json
│ │ ├── accordion.mdx
│ │ ├── alert.mdx
│ │ ├── aspect-ratio.mdx
│ │ ├── avatar.mdx
│ │ ├── buttons.mdx
│ │ ├── checkbox.mdx
│ │ ├── collapsible.mdx
│ │ ├── copy-to-clipboard.mdx
│ │ ├── dialog.mdx
│ │ ├── dropdown.mdx
│ │ ├── getting-started.mdx
│ │ ├── hover-card.mdx
│ │ ├── index.mdx
│ │ ├── label.mdx
│ │ ├── nav.mdx
│ │ ├── popover.mdx
│ │ ├── progress.mdx
│ │ ├── radio-group.mdx
│ │ ├── scroll-area.mdx
│ │ ├── select.mdx
│ │ ├── separator.mdx
│ │ ├── slider.mdx
│ │ ├── switch.mdx
│ │ ├── tabs.mdx
│ │ ├── toast.mdx
│ │ ├── toggle-group.mdx
│ │ ├── toggle.mdx
│ │ ├── toolbar.mdx
│ │ └── tooltip.mdx
│ └── index.mdx
├── postcss.config.js
├── public
│ ├── assets
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── logo.png
│ │ ├── mstile-150x150.png
│ │ ├── safari-pinned-tab.svg
│ │ └── site.webmanifest
│ ├── favicon.ico
│ ├── next.svg
│ ├── thirteen.svg
│ └── vercel.svg
├── styles
│ └── globals.css
├── tailwind.config.js
├── theme.config.js
└── tsconfig.json
├── package.json
├── packages
├── eslint-config
│ ├── index.js
│ └── package.json
├── tsconfig
│ ├── README.md
│ ├── base.json
│ ├── nextjs.json
│ ├── package.json
│ └── ui.json
└── ui
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── index.tsx
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ ├── components
│ │ ├── accordion.tsx
│ │ ├── alert.tsx
│ │ ├── aspect-ratio.tsx
│ │ ├── avatar.tsx
│ │ ├── buttons
│ │ │ ├── button.tsx
│ │ │ ├── danger.tsx
│ │ │ ├── icon-button.tsx
│ │ │ ├── index.ts
│ │ │ ├── primary.tsx
│ │ │ ├── shared
│ │ │ │ └── button.tsx
│ │ │ └── types.ts
│ │ ├── checkbox.tsx
│ │ ├── collapsible.tsx
│ │ ├── copy-to-clipboard.tsx
│ │ ├── date-picker.tsx
│ │ ├── dialog.tsx
│ │ ├── dropdown.tsx
│ │ ├── hover-card.tsx
│ │ ├── label.tsx
│ │ ├── nav.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── radio-group.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── slider.tsx
│ │ ├── switch.tsx
│ │ ├── tabs.tsx
│ │ ├── toast.tsx
│ │ ├── toggle-group.tsx
│ │ ├── toggle.tsx
│ │ ├── toolbar.tsx
│ │ └── tooltip.tsx
│ └── internal
│ │ └── calendar.tsx
│ ├── styles
│ └── main.css
│ ├── tailwind.config.js
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── turbo.json
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4 | with multi-package repos, or single-package repos to help you version and publish your code. You can
5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/bright-penguins-flow.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': major
3 | ---
4 |
5 | Prerelease
6 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
3 | "changelog": "@changesets/cli/changelog",
4 | "commit": false,
5 | "fixed": [],
6 | "linked": [],
7 | "access": "restricted",
8 | "baseBranch": "main",
9 | "updateInternalDependencies": "patch",
10 | "ignore": []
11 | }
12 |
--------------------------------------------------------------------------------
/.changeset/fair-rabbits-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Add 4 new components - label, separator, slider, and toggle
6 |
--------------------------------------------------------------------------------
/.changeset/five-otters-build.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Improve colors, update styles, replace classnames with clsx, refactor some components
6 |
--------------------------------------------------------------------------------
/.changeset/friendly-glasses-wait.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Use theme variables everywhere and add a few radix primitives
6 |
--------------------------------------------------------------------------------
/.changeset/gentle-lizards-remember.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Add calendar and date picker components
6 |
--------------------------------------------------------------------------------
/.changeset/green-rings-destroy.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update readme and package details
6 |
--------------------------------------------------------------------------------
/.changeset/healthy-stingrays-return.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Fix default value not working in select
6 |
--------------------------------------------------------------------------------
/.changeset/heavy-files-rush.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update package homepage
6 |
--------------------------------------------------------------------------------
/.changeset/itchy-socks-count.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Fix select not opening in uncontrolled operation
6 |
--------------------------------------------------------------------------------
/.changeset/khaki-beers-pump.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update z-index of close button in dialog component
6 |
--------------------------------------------------------------------------------
/.changeset/light-toys-compare.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Push again
6 |
--------------------------------------------------------------------------------
/.changeset/many-bugs-battle.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update shortcut styles in dropdown component
6 |
--------------------------------------------------------------------------------
/.changeset/moody-phones-retire.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update date picker component
6 |
--------------------------------------------------------------------------------
/.changeset/nasty-wolves-know.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update select component styles and add size prop for avatar component
6 |
--------------------------------------------------------------------------------
/.changeset/nervous-tools-build.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Update scroll area
6 |
--------------------------------------------------------------------------------
/.changeset/plenty-jobs-heal.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Use theme variables everywhere and add a few radix primitives
6 |
--------------------------------------------------------------------------------
/.changeset/polite-cougars-happen.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Add value prop to select component for controlled operations
6 |
--------------------------------------------------------------------------------
/.changeset/pre.json:
--------------------------------------------------------------------------------
1 | {
2 | "mode": "pre",
3 | "tag": "alpha",
4 | "initialVersions": {
5 | "@catalystui/docs": "0.1.42",
6 | "@catalystui/eslint-config": "0.0.0",
7 | "@catalystui/tsconfig": "0.0.0",
8 | "@i4o/catalystui": "0.9.3"
9 | },
10 | "changesets": [
11 | "bright-penguins-flow",
12 | "fair-rabbits-report",
13 | "five-otters-build",
14 | "friendly-glasses-wait",
15 | "gentle-lizards-remember",
16 | "green-rings-destroy",
17 | "healthy-stingrays-return",
18 | "heavy-files-rush",
19 | "itchy-socks-count",
20 | "khaki-beers-pump",
21 | "light-toys-compare",
22 | "many-bugs-battle",
23 | "moody-phones-retire",
24 | "nasty-wolves-know",
25 | "nervous-tools-build",
26 | "plenty-jobs-heal",
27 | "polite-cougars-happen",
28 | "silly-rats-attack",
29 | "thirty-bees-cross"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/.changeset/silly-rats-attack.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Add change event handler prop to checkbox component
6 |
--------------------------------------------------------------------------------
/.changeset/thirty-bees-cross.md:
--------------------------------------------------------------------------------
1 | ---
2 | '@i4o/catalystui': patch
3 | ---
4 |
5 | Add few more components and update docs
6 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | // This tells ESLint to load the config from the package `eslint-config-custom`
4 | extends: ['@catalystui/eslint-config'],
5 | settings: {
6 | next: {
7 | rootDir: ['apps/*/'],
8 | },
9 | },
10 | }
11 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - '**'
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v3
12 | - uses: pnpm/action-setup@v2
13 | with:
14 | version: 7
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: 16.x
18 | cache: 'pnpm'
19 |
20 | - run: pnpm install --frozen-lockfile
21 | - run: pnpm run lint && pnpm run build
22 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 | on:
3 | push:
4 | branches:
5 | - 'main'
6 |
7 | concurrency: ${{ github.workflow }}-${{ github.ref }}
8 |
9 | jobs:
10 | build:
11 | name: Release
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | - uses: pnpm/action-setup@v2
16 | with:
17 | version: 7
18 | - uses: actions/setup-node@v3
19 | with:
20 | node-version: 16.x
21 | cache: 'pnpm'
22 |
23 | - run: pnpm install --frozen-lockfile
24 | - name: Create Release Pull Request or Publish
25 | id: changesets
26 | uses: changesets/action@v1
27 | with:
28 | publish: pnpm run release
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # next.js
12 | .next/
13 | out/
14 | build
15 |
16 | # build
17 | packages/ui/dist
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 | .idea
23 |
24 | # debug
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 | .pnpm-debug.log*
29 |
30 | # local env files
31 | .env.local
32 | .env.development.local
33 | .env.test.local
34 | .env.production.local
35 |
36 | # turbo
37 | .turbo
38 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | auto-install-peers=false
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | .changeset
4 | .github/
5 | .next/
6 | docs/.next
7 | packages/ui/dist
8 | pnpm-lock.yaml
9 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | bracketSpacing: true,
3 | endOfLine: 'lf',
4 | jsxBracketSameLine: false,
5 | jsxSingleQuote: true,
6 | semi: false,
7 | singleQuote: true,
8 | tabWidth: 4,
9 | trailingComma: 'es5',
10 | useTabs: true,
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ilango Rajagopal
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Catalyst UI
2 |
3 | Catalyst UI is a component library built on top of Radix UI Primitives styled with Tailwind CSS made to make prototyping faster.
4 |
5 | > **Note:** This project is NOT the Catalyst that Adam Wathan talked about in his keynote at Tailwind Connect 2023. This project is not affiliated with Tailwind Labs and Radix UI (and by extension WorkOS) in any way.
6 |
7 | ## Documentation
8 |
9 | For full documentation and a complete list of components, visit [catalyst-ui.com](https://catalyst-ui.com/)
10 |
11 | ## Installation
12 |
13 | ```bash
14 | pnpm add @i4o/catalystui
15 | ```
16 |
17 | ## Features
18 |
19 | - Built on top of Radix UI Primitives styled with Tailwind CSS
20 | - Goes beyond Radix UI Primitives to provide more components
21 | - Utility components and hooks
22 | - Built-in dark mode support
23 | - Customizable styles with Tailwind or CSS Variables
24 |
25 | ## Roadmap
26 |
27 | - [x] Have a base list of usable components
28 | - [x] Fix library styles being overridden by Nextra styles
29 | - [x] Make the API and styles more consistent
30 | - [x] Make docs light/dark mode work for the components
31 | - [ ] Implement all Radix UI Primitives
32 | - [ ] Fix accessibility issues
33 | - [ ] Better types and runtime type-checking with Zod
34 | - [ ] Add explanation for props in the docs
35 |
36 | ## Acknowledgements
37 |
38 | CatalystUI and its docs are powered by these incredible open-source projects:
39 |
40 | - [React](https://reactjs.org/)
41 | - [TypeScript](https://www.typescriptlang.org/)
42 | - [Next.js](https://nextjs.org/)
43 | - [Nextra](https://nextra.site/)
44 | - [Radix UI](https://www.radix-ui.com/)
45 | - [Tailwind CSS](https://tailwindcss.com/)
46 | - [tailwindcss-radix](https://github.com/ecklf/tailwindcss-radix)
47 | - [classnames](https://github.com/JedWatson/classnames)
48 | - [copy-to-clipboard](https://github.com/sudodoki/copy-to-clipboard)
49 |
50 | ## Star History
51 |
52 | [](https://star-history.com/#i4o-oss/catalystui&Date)
53 |
54 | ## License
55 |
56 | [MIT](https://choosealicense.com/licenses/mit/)
57 |
--------------------------------------------------------------------------------
/docs/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: '@catalystui/eslint-config',
3 | }
4 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22 |
23 | ## Learn More
24 |
25 | To learn more about Next.js, take a look at the following resources:
26 |
27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29 |
30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31 |
32 | ## Deploy on Vercel
33 |
34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35 |
36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
37 |
--------------------------------------------------------------------------------
/docs/components/authors.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react'
2 |
3 | export default function Authors({
4 | date,
5 | children,
6 | by = 'by',
7 | }: {
8 | date: Date
9 | children: ReactNode | ReactNode[]
10 | by: string
11 | }) {
12 | return (
13 |
14 | <>
15 | {date} {by} {children}
16 | >
17 |
18 | )
19 | }
20 |
21 | export function Author({ name, link }: { name: string; link: string }) {
22 | return (
23 |
24 |
31 | {name}
32 |
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/docs/components/blog-index.tsx:
--------------------------------------------------------------------------------
1 | import { getPagesUnderRoute } from 'nextra/context'
2 | import type { Page } from 'nextra'
3 | import Link from 'next/link'
4 |
5 | export default function BlogIndex({ more = 'Read more' }) {
6 | const pages: Page[] = getPagesUnderRoute('/blog')
7 | return pages.map((page, index) => {
8 | // @ts-ignore
9 | const frontMatter = page?.frontMatter
10 | return (
11 |
15 |
16 |
20 | {page.meta?.title || frontMatter?.title || page?.name}
21 |
22 |
23 |
24 | {frontMatter?.description}{' '}
25 | {more + ' →'}
26 |
27 | {frontMatter?.date ? (
28 |
29 | {frontMatter.date}
30 |
31 | ) : null}
32 |
33 | )
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/docs/components/component-link.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react'
2 | import Link from 'next/link'
3 |
4 | type ComponentLinkProps = {
5 | children: ReactNode
6 | className?: string
7 | href: string
8 | }
9 |
10 | export default function ComponentLink(props: ComponentLinkProps) {
11 | return (
12 |
13 |
16 | {props.children}
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/docs/components/demo-card.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react'
2 |
3 | type DemoCardProps = {
4 | children: ReactNode
5 | className?: string
6 | }
7 |
8 | export default function DemoCard(props: DemoCardProps) {
9 | return (
10 |
13 | {props.children}
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/docs/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | theme: 'nextra-theme-docs',
5 | themeConfig: './theme.config.js',
6 | }
7 |
8 | const withNextra = require('nextra')(nextConfig)
9 |
10 | module.exports = withNextra()
11 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@catalystui/docs",
3 | "version": "0.1.43-alpha.17",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@i4o/catalystui": "workspace:*",
13 | "@next/font": "13.3.0",
14 | "@radix-ui/react-icons": "^1.3.0",
15 | "next": "13.3.0",
16 | "nextra": "^2.4.0",
17 | "nextra-theme-docs": "^2.4.0",
18 | "react": "^18.2.0",
19 | "react-dom": "18.2.0",
20 | "typescript": "5.0.4"
21 | },
22 | "devDependencies": {
23 | "@types/node": "18.15.12",
24 | "@types/react": "^18.0.37",
25 | "@types/react-dom": "^18.0.11",
26 | "autoprefixer": "^10.4.14",
27 | "postcss": "^8.4.23",
28 | "tailwindcss": "^3.3.1"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/docs/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@i4o/catalystui/main.css'
2 | import '../styles/globals.css'
3 | import type { AppProps } from 'next/app'
4 |
5 | export default function App({ Component, pageProps }: AppProps) {
6 | return
7 | }
8 |
--------------------------------------------------------------------------------
/docs/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Head, Html, Main, NextScript } from 'next/document'
2 | import Script from 'next/script'
3 |
4 | export default function Document() {
5 | return (
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/docs/pages/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": {
3 | "title": "Home",
4 | "type": "page",
5 | "hidden": true,
6 | "display": "hidden",
7 | "theme": {
8 | "footer": false,
9 | "toc": false
10 | }
11 | },
12 | "docs": {
13 | "title": "Documentation",
14 | "type": "page",
15 | "theme": {
16 | "footer": false
17 | }
18 | },
19 | "about": {
20 | "title": "About",
21 | "type": "page",
22 | "theme": {
23 | "footer": false,
24 | "toc": false
25 | }
26 | },
27 | "blog": {
28 | "title": "Blog",
29 | "type": "page",
30 | "hidden": true,
31 | "display": "hidden",
32 | "theme": {
33 | "pagination": false,
34 | "sidebar": false
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/pages/about.mdx:
--------------------------------------------------------------------------------
1 | # About CatalystUI
2 |
3 | CatalystUI was created by [Ilango](https://i4o.dev/) in 2023. It was created to help me build prototypes faster and to help me learn new technologies. I hope you find it useful.
4 |
5 | ## Credits
6 |
7 | CatalystUI and its docs are powered by these incredible open source projects:
8 |
9 | - [React](https://reactjs.org/)
10 | - [TypeScript](https://www.typescriptlang.org/)
11 | - [Next.js](https://nextjs.org/)
12 | - [Nextra](https://nextra.site/)
13 | - [Radix UI](https://www.radix-ui.com/)
14 | - [Tailwind CSS](https://tailwindcss.com/)
15 | - [tailwindcss-radix](https://github.com/ecklf/tailwindcss-radix)
16 | - [classnames](https://github.com/JedWatson/classnames)
17 | - [copy-to-clipboard](https://github.com/sudodoki/copy-to-clipboard)
18 |
19 | ## License
20 |
21 | CatalystUI is licensed under the [MIT License](https://github.com/i4o-oss/catalystui/blob/main/LICENSE).
22 |
--------------------------------------------------------------------------------
/docs/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/docs/pages/blog.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Blog
3 | searchable: false
4 | ---
5 |
6 | Blog
7 |
8 | The latest updates and releases on CatalystUI
9 |
10 |
11 | import BlogIndex from '../components/blog-index'
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/pages/blog/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "announcing-catalystui": "Announcing CatalystUI"
3 | }
4 |
--------------------------------------------------------------------------------
/docs/pages/blog/announcing-catalystui.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | image:
3 | description: "I'm excited to announce CatalystUI, a component library built on top of Radix UI and TailwindCSS to make prototyping apps faster."
4 | date: January 18th, 2023
5 | ---
6 |
7 | import Authors, { Author } from '../../components/authors.tsx'
8 |
9 | # Introducing CatalystUI
10 |
11 |
12 |
13 |
14 |
15 | In the past few months, I've prototyped several toy projects to explore ideas, learn new things etc.
16 | Having a well thought out project starter is one of the crucial parts of being able to quickly build something and test out an idea. While I have a pretty solid
17 | project starter, one thing that always slowed my down is a collection of components that I can use in my prototypes.
18 |
19 | ### Why build a component library in 2023, when there are plenty of other choices?
20 |
21 | I've tried a few component libraries over the years but I found it hard to settle on one. Last year, I found out about Radix UI primitives. I instantly liked it.
22 | They were unstyled, had built-in accessibility and keyboard navigation, and a nice API. And they can be styled with whatever technology we want. I'm a huge fan of Tailwind,
23 | so naturally I chose that. Pretty soon, I had a collection of styled components that I can use for my prototypes, and I included them in my starter.
24 |
25 | But I ran into a problem. Making changes to these components meant that the components began to diverge across my projects and copy-pasting got tired very fast.
26 | So I decided to bite the bullet and build a component library. CatalystUI is the result of this work.
27 |
28 | ### Why Catalyst?
29 |
--------------------------------------------------------------------------------
/docs/pages/docs/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": "Introduction",
3 | "getting-started": "Get Started",
4 | "-- Components --": {
5 | "type": "separator",
6 | "title": "Components"
7 | },
8 | "accordion": "Accordion",
9 | "alert": "Alert",
10 | "aspect-ratio": "Aspect Ratio",
11 | "avatar": "Avatar",
12 | "buttons": "Buttons",
13 | "checkbox": "Checkbox",
14 | "collapsible": "Collapsible",
15 | "dialog": "Dialog",
16 | "dropdown": "Dropdown",
17 | "hover-card": "Hover Card",
18 | "label": "Label",
19 | "nav": "Navigation Menu",
20 | "popover": "Popover",
21 | "progress": "Progress",
22 | "radio-group": "Radio Group",
23 | "scroll-area": "Scroll Area",
24 | "select": "Select",
25 | "separator": "Separator",
26 | "slider": "Slider",
27 | "switch": "Switch",
28 | "tabs": "Tabs",
29 | "toast": "Toast",
30 | "toggle": "Toggle",
31 | "toggle-group": "Toggle Group",
32 | "toolbar": "Toolbar",
33 | "tooltip": "Tooltip",
34 | "-- Utils --": {
35 | "type": "separator",
36 | "title": "Utils"
37 | },
38 | "copy-to-clipboard": "Copy to Clipboard",
39 | "-- About --": {
40 | "type": "separator",
41 | "title": "More"
42 | },
43 | "about link": {
44 | "title": "About CatalystUI",
45 | "href": "/about"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/docs/pages/docs/accordion.mdx:
--------------------------------------------------------------------------------
1 | import { Accordion } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Accordion
5 |
6 |
7 |
32 |
33 |
34 | ### Example
35 |
36 | ```tsx
37 | import { Accordion } from '@i4o/catalystui'
38 |
39 | export default () => {
40 | return (
41 |
66 | )
67 | }
68 | ```
69 |
70 | ### Props
71 |
72 | | Name | Type | Default | Description |
73 | | :------------- | :-------------------------------------------------------------------------------- | :--------- | :-------------------------------------- |
74 | | `collapsible` | `boolean` | `true` | Whether the accordion can be collapsed. |
75 | | `defaultValue` | `string[]` | `[]` | The default value of the accordion. |
76 | | `items` | `Array<{ id: string, title: string \| ReactNode, content: string \| ReactNode }>` | `[]` | The items to display in the accordion. |
77 | | `type` | `'multiple' \| 'single'` | `'single'` | The type of accordion. |
78 |
--------------------------------------------------------------------------------
/docs/pages/docs/alert.mdx:
--------------------------------------------------------------------------------
1 | import { Alert, Button, DangerButton } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Alert
5 |
6 |
7 | Yes}
9 | cancel={No }
10 | title='Are you sure?'
11 | description='This action cannot be undone.'
12 | trigger={Delete Thing }
13 | />
14 |
15 |
16 | ### Example
17 |
18 | ```tsx
19 | import { Alert, Button, DangerButton } from '@i4o/catalystui'
20 |
21 | export default () => {
22 | return (
23 |
24 | Yes}
26 | cancel={No }
27 | title='Are you sure?'
28 | description='This action cannot be undone.'
29 | trigger={Delete Thing }
30 | />
31 |
32 | )
33 | }
34 | ```
35 |
36 | ### Props
37 |
38 | | Name | Type | Default | Description |
39 | | :---------- | :-------------------- | :------ | :---------------------------- |
40 | | action | `ReactNode` | | The action button. |
41 | | cancel | `ReactNode` | | The cancel button. |
42 | | description | `string \| ReactNode` | | The description of the alert. |
43 | | title | `string \| ReactNode` | | The title of the alert. |
44 | | trigger | `ReactNode` | | The trigger button. |
45 |
--------------------------------------------------------------------------------
/docs/pages/docs/aspect-ratio.mdx:
--------------------------------------------------------------------------------
1 | import { AspectRatio } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Aspect Ratio
5 |
6 |
7 |
12 |
13 |
14 | ### Example
15 |
16 | ```tsx
17 | import { Alert, Button, DangerButton } from '@i4o/catalystui'
18 |
19 | export default () => {
20 | return (
21 |
22 |
27 |
28 | )
29 | }
30 | ```
31 |
32 | ### Props
33 |
34 | | Name | Type | Default | Description |
35 | | :---- | :------- | :------ | :----------------------- |
36 | | alt | `string` | | Alt text of the image |
37 | | ratio | `number` | `1` | The desired aspect ratio |
38 | | src | `string` | | URL of the image |
39 |
--------------------------------------------------------------------------------
/docs/pages/docs/avatar.mdx:
--------------------------------------------------------------------------------
1 | import { Avatar } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Avatar
5 |
6 |
7 |
8 |
13 |
18 |
22 |
26 |
31 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ### Example
48 |
49 | ```tsx
50 | import { Avatar } from '@i4o/catalystui'
51 |
52 | export default () => {
53 | return (
54 | <>
55 |
60 |
65 |
70 |
71 |
72 | >
73 | )
74 | }
75 | ```
76 |
77 | ### Props
78 |
79 | | Name | Type | Default | Description |
80 | | :--------- | :---------------------- | :--------- | :-------------------------------------------------------------------------- |
81 | | `fallback` | `string \| ReactNode` | `''` | Fallback text to display if no image is provided or if image fails to load. |
82 | | `src` | `string` | `''` | Image source. |
83 | | `variant` | `'circle' \| 'rounded'` | `'circle'` | Avatar variant. |
84 |
--------------------------------------------------------------------------------
/docs/pages/docs/buttons.mdx:
--------------------------------------------------------------------------------
1 | import {
2 | Button,
3 | PrimaryButton,
4 | DangerButton,
5 | IconButton,
6 | } from '@i4o/catalystui'
7 | import { HomeIcon, PlayIcon, PauseIcon, StopIcon } from '@radix-ui/react-icons'
8 | import DemoCard from '../../components/demo-card'
9 | import '@i4o/catalystui/main.css'
10 |
11 | # Buttons
12 |
13 |
14 |
15 |
Button
16 |
Primary Button
17 |
Danger Button
18 |
} />
19 |
20 |
21 |
22 | ### Example
23 |
24 | ```tsx
25 | import {
26 | Button,
27 | PrimaryButton,
28 | DangerButton,
29 | IconButton,
30 | } from '@i4o/catalystui'
31 |
32 | export default () => {
33 | return (
34 |
35 |
Button
36 |
Primary Button
37 |
Danger Button
38 |
} />
39 |
40 | )
41 | }
42 | ```
43 |
44 | ### Props
45 |
46 | | Name | Type | Default | Description |
47 | | :---------- | :-------------------------- | :------ | :------------------------- |
48 | | ariaLabel | string | | `aria-label` of the button |
49 | | children | ReactNode | | Button content |
50 | | className | string | | Additional class name |
51 | | disabled | boolean | | Disabled state |
52 | | loading | boolean | | Loading state |
53 | | loadingText | string | | Loading text |
54 | | onClick | (event: MouseEvent) => void | | Click handler |
55 | | onMouseDown | (event: MouseEvent) => void | | Mouse down handler |
56 | | leftIcon | ReactNode | | Left icon |
57 | | rightIcon | ReactNode | | Right icon |
58 | | textSize | string | | Text size |
59 | | tooltip | string | | Tooltip text |
60 | | type | string | | Button type |
61 |
62 | ### IconButton Props
63 |
64 | Refer to [Default Button Props](#props). Icon Button also has the following props:
65 |
66 | | Name | Type | Default | Description |
67 | | :--- | :-------- | :------ | :---------- |
68 | | icon | ReactNode | | Icon |
69 |
70 | ## Variants
71 |
72 | ### Left/Right Icons
73 |
74 |
75 |
76 |
77 |
} padding='pl-3 pr-4 py-1'>
78 | Pause
79 |
80 |
} padding='pl-3 pr-4 py-1'>
81 | Play
82 |
83 |
} padding='pl-3 pr-4 py-1'>
84 | Stop
85 |
86 |
87 |
88 |
} padding='pl-4 pr-3 py-1'>
89 | Pause
90 |
91 |
} padding='pl-4 pr-3 py-1'>
92 | Play
93 |
94 |
} padding='pl-4 pr-3 py-1'>
95 | Stop
96 |
97 |
98 |
99 |
100 |
101 | ## States
102 |
103 | ### Loading
104 |
105 |
106 |
107 |
108 | Button
109 |
110 |
111 | Primary Button
112 |
113 |
114 | Danger Button
115 |
116 |
117 |
118 |
119 | ### Disabled
120 |
121 |
122 |
123 |
Button
124 |
Primary Button
125 |
Danger Button
126 |
127 |
128 |
--------------------------------------------------------------------------------
/docs/pages/docs/checkbox.mdx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Checkbox
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 | ### Example
20 |
21 | ```tsx
22 | import { Checkbox } from '@i4o/catalystui'
23 |
24 | export default () => {
25 | return (
26 | Checkbox}
29 | />
30 | )
31 | }
32 | ```
33 |
34 | ### Props
35 |
36 | | Name | Type | Default | Description |
37 | | :--------------- | :-------------------- | :------ | :---------------------------------------------------------------- |
38 | | `defaultChecked` | `boolean` | `false` | Whether the checkbox is checked by default |
39 | | `disabled` | `boolean` | `false` | Whether the checkbox is disabled |
40 | | `label` | `string \| ReactNode` | `''` | The label of the checkbox |
41 | | `name` | `string` | `''` | The label of the checkbox |
42 | | `required` | `boolean` | `false` | Whether the checkbox is required before the form can be submitted |
43 |
--------------------------------------------------------------------------------
/docs/pages/docs/collapsible.mdx:
--------------------------------------------------------------------------------
1 | import { Collapsible, IconButton } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 | import { RowSpacingIcon } from '@radix-ui/react-icons'
4 |
5 | # Collapsible
6 |
7 |
8 | ClickHouse/NoiSQL}
10 | items={[GyulyVGC/sniffnet , rvaiya/keyd ]}
11 | title='orhun starred 3 repositories'
12 | trigger={
13 | }
16 | />
17 | }
18 | />
19 |
20 |
21 | ### Example
22 |
23 | ```tsx
24 | import { Collapsible } from '@i4o/catalystui'
25 |
26 | export default () => {
27 | return (
28 |
29 | First Item}
31 | title='Are you sure?'
32 | trigger={ } />}
33 | />
34 |
35 | )
36 | }
37 | ```
38 |
39 | ### Props
40 |
41 | | Name | Type | Default | Description |
42 | | :------ | :-------------------- | :------ | :----------------------------------------------------------- |
43 | | first | `ReactNode` | | First element of the collapsible. It will always be visible. |
44 | | items | `ReactNode[]` | | List of elements in the collapsible. |
45 | | title | `string \| ReactNode` | | The title of the collapsible. |
46 | | trigger | `string \| ReactNode` | | The trigger button. |
47 |
--------------------------------------------------------------------------------
/docs/pages/docs/copy-to-clipboard.mdx:
--------------------------------------------------------------------------------
1 | import { CopyToClipboard } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Copy To Clipboard
5 |
6 |
7 |
8 |
9 |
10 | ### Example
11 |
12 | ```tsx
13 | import { CopyToClipboard } from '@i4o/catalystui'
14 |
15 | export default () => {
16 | return
17 | }
18 | ```
19 |
20 | ### Props
21 |
22 | | Name | Type | Default | Description |
23 | | :--- | :----- | :------ | :------------------------ |
24 | | text | string | | Text to copy to clipboard |
25 |
26 | // TODO: Show toast when copied
27 |
--------------------------------------------------------------------------------
/docs/pages/docs/dialog.mdx:
--------------------------------------------------------------------------------
1 | import { Button, Dialog, PrimaryButton } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Dialog
5 |
6 |
7 | Edit Profile}
9 | description={
10 |
11 | Change your profile information here. Click save when you are
12 | done.
13 |
14 | }
15 | trigger={Edit Profile }
16 | >
17 |
18 |
19 | Name
20 |
21 |
25 |
26 | Email
27 |
28 |
32 |
33 |
34 |
35 |
36 | ### Example
37 |
38 | ```tsx
39 | import { Button, Dialog, PrimaryButton } from '@i4o/catalystui'
40 |
41 | export default () => {
42 | return (
43 | OK}
45 | cancel={Cancel }
46 | title={Edit Profile
}
47 | description={
48 |
49 | Change your profile information here. Click save when you
50 | are done.
51 |
52 | }
53 | trigger={Edit Profile }
54 | >
55 |
56 |
57 | Name
58 |
59 |
63 |
64 | Email
65 |
66 |
70 |
71 |
72 | )
73 | }
74 | ```
75 |
76 | ### Props
77 |
78 | | Name | Type | Default | Description |
79 | | :----------- | :-------------------- | :------ | :------------------------------------------------------ |
80 | | title | `ReactNode \| string` | - | The title of the dialog. |
81 | | description | `ReactNode \| string` | - | The description of the dialog. |
82 | | trigger | ReactNode | - | The trigger element of the dialog. |
83 | | action | ReactNode | - | Action button in the dialog. |
84 | | cancel | ReactNode | - | Cancel button in the dialog. |
85 | | children | ReactNode | - | The content of the dialog. |
86 | | open | `boolean` | - | Open state of the dialog. |
87 | | onOpenChange | ReactNode | - | Function to call when open state of the dialog changes. |
88 |
--------------------------------------------------------------------------------
/docs/pages/docs/dropdown.mdx:
--------------------------------------------------------------------------------
1 | import { Dropdown, IconButton } from '@i4o/catalystui'
2 | import {
3 | ExitIcon,
4 | ExternalLinkIcon,
5 | FileIcon,
6 | GearIcon,
7 | HamburgerMenuIcon,
8 | InfoCircledIcon,
9 | } from '@radix-ui/react-icons'
10 | import DemoCard from '../../components/demo-card'
11 |
12 | # Dropdown
13 |
14 | export function DropdownMenu() {
15 | const dropdownItems = [
16 | {
17 | label: 'New',
18 | icon: ,
19 | submenu: [
20 | {
21 | label: 'File',
22 | icon: ,
23 | onClick: () => console.log('File'),
24 | shortcut: 'Ctrl + N',
25 | },
26 | {
27 | label: 'Folder',
28 | icon: ,
29 | onClick: () => console.log('Folder'),
30 | shortcut: 'Ctrl + Shift + N',
31 | },
32 | ],
33 | type: 'submenu',
34 | },
35 | {
36 | label: 'View Post',
37 | icon: ,
38 | onClick: () => console.log('View Post'),
39 | shortcut: 'Ctrl + V',
40 | },
41 | {
42 | type: 'separator',
43 | },
44 | {
45 | label: 'Settings',
46 | icon: ,
47 | onClick: () => console.log('Settings'),
48 | shortcut: 'Ctrl + ,',
49 | },
50 | {
51 | type: 'separator',
52 | },
53 | {
54 | label: 'About',
55 | icon: ,
56 | onClick: () => console.log('About'),
57 | },
58 | {
59 | label: 'Exit',
60 | icon: ,
61 | onClick: () => console.log('Logout'),
62 | shortcut: 'Ctrl + Q',
63 | },
64 | ]
65 |
66 | return (
67 |
68 | } />
73 | )}
74 | />
75 |
76 | )
77 |
78 | }
79 |
80 |
81 |
82 | ### Example
83 |
84 | ```tsx
85 | import { Dropdown, IconButton } from '@i4o/catalystui'
86 | import {
87 | ExitIcon,
88 | ExternalLinkIcon,
89 | FileIcon,
90 | GearIcon,
91 | HamburgerMenuIcon,
92 | InfoCircledIcon,
93 | } from '@radix-ui/react-icons'
94 |
95 | export default () => {
96 | const dropdownItems = [
97 | {
98 | label: 'New',
99 | icon: ,
100 | submenu: [
101 | {
102 | label: 'File',
103 | icon: ,
104 | onClick: () => console.log('File'),
105 | shortcut: 'Ctrl+N',
106 | },
107 | {
108 | label: 'Folder',
109 | icon: ,
110 | onClick: () => console.log('Folder'),
111 | shortcut: 'Ctrl+Shift+N',
112 | },
113 | ],
114 | type: 'submenu',
115 | },
116 | {
117 | label: 'View Post',
118 | icon: ,
119 | onClick: () => console.log('View Post'),
120 | shortcut: 'Ctrl+Shift+V',
121 | },
122 | {
123 | type: 'separator',
124 | },
125 | {
126 | label: 'Settings',
127 | icon: ,
128 | onClick: () => console.log('Settings'),
129 | shortcut: 'Ctrl+,',
130 | },
131 | {
132 | type: 'separator',
133 | },
134 | {
135 | label: 'About',
136 | icon: ,
137 | onClick: () => console.log('About'),
138 | },
139 | {
140 | label: 'Exit',
141 | icon: ,
142 | onClick: () => console.log('Logout'),
143 | shortcut: 'Ctrl+Q',
144 | },
145 | ]
146 |
147 | return (
148 | } />}
152 | />
153 | )
154 | }
155 | ```
156 |
157 | ### Props
158 |
159 | | Name | Type | Default | Description |
160 | | :------ | :--------------------------- | :------ | :----------------------------------------- |
161 | | align | 'start' \| 'center' \| 'end' | 'start' | The alignment of the dropdown menu. |
162 | | items | DropdownItem[] | [] | The items to display in the dropdown menu. |
163 | | trigger | ReactNode | null | The trigger element. |
164 |
165 | #### DropdownItem
166 |
167 | | Name | Type | Default | Description |
168 | | :------- | :--------------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------ |
169 | | type | 'submenu' \| 'separator' \| 'item' | 'item' | Type of the dropdown menu item. |
170 | | label | `string \| ReactNode` | `''` | Label to display for the item. |
171 | | icon | ReactNode | - | Icon to display for the item. |
172 | | submenu | DropdownItem[] | [] | The items to display as the submenu for the item. |
173 | | link | string | - | URL to open on click when type is `item`. |
174 | | onSelect | () => void | - | Function to call when type is `item`. |
175 | | shortcut | string | - | Keyboard shortcut to display when type is `item`. Calling the `onSelect` function is not handled. User has to handle it on their own. |
176 |
--------------------------------------------------------------------------------
/docs/pages/docs/getting-started.mdx:
--------------------------------------------------------------------------------
1 | # Get Started
2 |
3 | {Installation
}
4 |
5 | ```bash
6 | npm install @i4o/catalystui
7 | ```
8 |
9 | ```bash
10 | yarn add @i4o/catalystui
11 | ```
12 |
13 | ```bash
14 | pnpm add @i4o/catalystui
15 | ```
16 |
17 | {Example Usage
}
18 |
19 | ```tsx
20 | import { Button } from '@i4o/catalystui'
21 |
22 | export default function Home() {
23 | return (
24 |
25 | Click Me
26 |
27 | )
28 | }
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/pages/docs/hover-card.mdx:
--------------------------------------------------------------------------------
1 | import { IconButton, HoverCard } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 | import { MixIcon } from '@radix-ui/react-icons'
4 |
5 | # HoverCard
6 |
7 |
8 | } />}>
9 |
10 |
15 |
16 |
17 |
18 | Radix
19 |
20 |
21 | @radix_ui
22 |
23 |
24 |
25 | Components, icons, colors, and templates for building
26 | high-quality, accessible UI. Free and open-source.
27 |
28 |
29 |
30 |
31 | 0
32 |
33 |
34 | Following
35 |
36 |
37 |
38 |
39 | 2,900
40 |
41 |
42 | Followers
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | ### Example
52 |
53 | ```tsx
54 | import { HoverCard } from '@i4o/catalystui'
55 |
56 | export default () => {
57 | return (
58 |
59 |
60 |
61 |
66 |
67 |
68 |
69 | Radix
70 |
71 |
72 | @radix_ui
73 |
74 |
75 |
76 | Components, icons, colors, and templates for
77 | building high-quality, accessible UI. Free and
78 | open-source.
79 |
80 |
81 |
82 |
83 | 0
84 |
85 |
86 | Following
87 |
88 |
89 |
90 |
91 | 2,900
92 |
93 |
94 | Followers
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | )
103 | }
104 | ```
105 |
106 | ### Props
107 |
108 | | Name | Type | Default | Description |
109 | | :------- | :---------- | :------ | :-------------------------------------------- |
110 | | children | `ReactNode` | | React element to render inside the hover card |
111 | | trigger | `ReactNode` | | React element that triggers the hover card |
112 |
--------------------------------------------------------------------------------
/docs/pages/docs/index.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs'
2 |
3 | # Catalyst UI
4 |
5 | Catalyst UI is a component library built on top of Radix UI primitives and styled with Tailwind CSS.
6 |
7 |
8 | Catalyst UI is NOT affiliated with Tailwind Labs and Radix UI (and by
9 | extension, WorkOS) in any way. This is NOT the Catalyst that Adam Wathan
10 | talked about in his keynote at Tailwind Connect 2023. This is a passion
11 | project that I built for my own use and is NOT the upcoming UI kit from
12 | Tailwind Labs.
13 |
14 |
15 |
16 | Catalyst UI is in early stages of development. It's not ready for production
17 | use yet (although I use it in production since I need it) and APIs may
18 | change. Feel free to modify it and use in production at your own risk. If
19 | you have suggestions on how to improve it, please open an issue on GitHub.
20 |
21 |
22 |
23 | Catalyst UI is not exhaustive. It doesn't include all the Radix primitives
24 | yet. I'm working on supporting all of them. If you need a component that's
25 | not included, please open an issue on GitHub.
26 |
27 |
28 | Features
29 |
30 | - Built on top of Radix UI Primitives styled with Tailwind CSS
31 | - Goes beyond Radix UI Primitives to provide more components
32 | - Utility components and hooks
33 | - Built-in dark mode support
34 |
35 | Roadmap
36 |
37 | - [x] Have a base list of usable components
38 | - [x] Fix library styles being overridden by nextra styles
39 | - [x] Make the API and styles more consistent
40 | - [x] Make docs light/dark mode work for the components
41 | - [ ] Implement all Radix UI Primitives
42 | - [ ] Fix accessibility issues
43 | - [ ] Add explanation for props in the docs
44 |
--------------------------------------------------------------------------------
/docs/pages/docs/label.mdx:
--------------------------------------------------------------------------------
1 | import { Label } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Label
5 |
6 |
7 | <>
8 |
9 |
10 | >
11 |
12 |
13 | ### Example
14 |
15 | ```tsx
16 | import { Label } from '@i4o/catalystui'
17 |
18 | export default () => {
19 | return (
20 | <>
21 |
22 |
23 | >
24 | )
25 | }
26 | ```
27 |
28 | ### Props
29 |
30 | | Name | Type | Default | Description |
31 | | :------ | :------- | :------ | :--------------------------- |
32 | | label | `string` | `''` | Label Text |
33 | | htmlFor | `string` | `''` | ID of the associated element |
34 |
--------------------------------------------------------------------------------
/docs/pages/docs/nav.mdx:
--------------------------------------------------------------------------------
1 | import { Nav } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Navigation Menu
5 |
6 |
7 |
18 |
28 |
29 | },
30 | {
31 | id: 'contact',
32 | label: 'Contact',
33 | href: '/contact',
34 | },
35 | ]}
36 | type='row'
37 | />
38 |
39 |
40 |
41 | ### Example
42 |
43 | ```tsx
44 | import { Nav } from '@i4o/catalystui'
45 |
46 | export default () => (
47 |
59 |
69 |
70 | ),
71 | },
72 | {
73 | id: 'contact',
74 | label: 'Contact',
75 | href: '/contact',
76 | },
77 | ]}
78 | type='row'
79 | />
80 | )
81 | ```
82 |
83 | ### Props
84 |
85 | | Name | Type | Default | Description |
86 | | :---- | :-------------------------------------------------------------------------------- | :------ | :------------------------ |
87 | | items | `Array<{ id: string, label: string \| ReactNode, content: string \| ReactNode }>` | [] | Array of navigation items |
88 | | type | `row \| column` | 'row' | Type of navigation menu |
89 |
--------------------------------------------------------------------------------
/docs/pages/docs/popover.mdx:
--------------------------------------------------------------------------------
1 | import { Button, Popover } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Popover
5 |
6 |
7 | Click Me}
11 | >
12 | <>
13 |
14 |
15 | Name
16 |
17 |
21 |
22 | Email
23 |
24 |
28 |
29 | >
30 |
31 |
32 |
33 | ### Example
34 |
35 | ```tsx
36 | import { Button, Popover } from '@i4o/catalystui'
37 |
38 | export default () => {
39 | return (
40 | Click Me}
44 | placement='bottom'
45 | >
46 | <>
47 |
48 |
49 | Name
50 |
51 |
55 |
56 | Email
57 |
58 |
62 |
63 | >
64 |
65 | )
66 | }
67 | ```
68 |
69 | ### Props
70 |
71 | | Name | Type | Default | Description |
72 | | :--------- | :--------------------------------------- | :------- | :------------------------------------------------- |
73 | | align | `start \| center \| end` | `center` | Alignment of the popover in relation to the button |
74 | | close | boolean | true | Whether to show the close button on the popover |
75 | | children | ReactNode | | The content of the popover |
76 | | title | string | | The title of the popover |
77 | | trigger | ReactNode | | The element that triggers the popover |
78 | | side | `'top' \| 'right' \| 'bottom' \| 'left'` | 'bottom' | The placement of the popover. |
79 | | sideOffset | number | 0 | The offset of the popover from the trigger. |
80 |
--------------------------------------------------------------------------------
/docs/pages/docs/progress.mdx:
--------------------------------------------------------------------------------
1 | import { Progress } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Progress
5 |
6 |
7 |
8 |
9 |
10 | ### Example
11 |
12 | ```tsx
13 | import { Progress } from '@i4o/catalystui'
14 |
15 | export default () => {
16 | return (
17 |
18 |
19 |
20 | )
21 | }
22 | ```
23 |
24 | ### Props
25 |
26 | | Name | Type | Default | Description |
27 | | :------ | :------- | :------ | :--------------------- |
28 | | percent | `number` | | Percentage of progress |
29 |
--------------------------------------------------------------------------------
/docs/pages/docs/radio-group.mdx:
--------------------------------------------------------------------------------
1 | import { RadioGroup } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Radio Group
5 |
6 |
7 | Option 1, value: '1' },
12 | { label: Option 2
, value: '2' },
13 | { label: Option 3
, value: '3' },
14 | ]}
15 | />
16 |
17 |
18 | ### Example
19 |
20 | ```tsx
21 | import { RadioGroup } from '@i4o/catalystui'
22 |
23 | export default () => {
24 | return (
25 | Option 1,
31 | value: '1',
32 | },
33 | {
34 | label: Option 2
,
35 | value: '2',
36 | },
37 | {
38 | label: Option 3
,
39 | value: '3',
40 | },
41 | ]}
42 | />
43 | )
44 | }
45 | ```
46 |
47 | ### Props
48 |
49 | | Name | Type | Default | Description |
50 | | :------------- | :----------------------------------------------------------------- | :---------- | :--------------------------------------------------------------------------------- |
51 | | `defaultValue` | `string` | `''` | The default value of the radio group. |
52 | | `disabled` | `boolean` | `false` | Whether the radio group is disabled. |
53 | | `name` | `string` | `''` | The name of the radio group. |
54 | | `onChange` | `(value: string) => void` | `undefined` | The callback function that is triggered when the value of the radio group changes. |
55 | | `options` | `Array<{ id: string, label: string \| ReactNode, value: string }>` | `[]` | The options of the radio group. |
56 |
--------------------------------------------------------------------------------
/docs/pages/docs/scroll-area.mdx:
--------------------------------------------------------------------------------
1 | import { ScrollArea } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # ScrollArea
5 |
6 |
7 |
8 |
9 |
10 | v1.2.0-beta.50
11 |
12 |
13 | v1.2.0-beta.51
14 |
15 |
16 | v1.2.0-beta.52
17 |
18 |
19 | v1.2.0-beta.53
20 |
21 |
22 | v1.2.0-beta.54
23 |
24 |
25 | v1.2.0-beta.55
26 |
27 |
28 | v1.2.0-beta.56
29 |
30 |
31 | v1.2.0-beta.57
32 |
33 |
34 | v1.2.0-beta.58
35 |
36 |
37 | v1.2.0-beta.59
38 |
39 |
40 | v1.2.0-beta.60
41 |
42 |
43 | v1.2.0-beta.61
44 |
45 |
46 | v1.2.0-beta.62
47 |
48 |
49 |
50 |
51 |
52 | ### Example
53 |
54 | ```tsx
55 | import { ScrollArea } from '@i4o/catalystui'
56 |
57 | export default () => {
58 | return (
59 |
60 |
61 |
62 |
63 | v1.2.0-beta.50
64 |
65 |
66 | v1.2.0-beta.51
67 |
68 |
69 | v1.2.0-beta.52
70 |
71 |
72 | v1.2.0-beta.53
73 |
74 |
75 | v1.2.0-beta.54
76 |
77 |
78 | v1.2.0-beta.55
79 |
80 |
81 | v1.2.0-beta.56
82 |
83 |
84 | v1.2.0-beta.57
85 |
86 |
87 | v1.2.0-beta.58
88 |
89 |
90 | v1.2.0-beta.59
91 |
92 |
93 | v1.2.0-beta.60
94 |
95 |
96 | v1.2.0-beta.61
97 |
98 |
99 | v1.2.0-beta.62
100 |
101 |
102 |
103 |
104 | )
105 | }
106 | ```
107 |
108 | ### Props
109 |
110 | | Name | Type | Default | Description |
111 | | :-------- | :-------------------- | :------ | :----------------------------------------------- |
112 | | className | `string` | | Classname for the scroll area container. |
113 | | children | `ReactNode` | | React Element to display inside the scroll area. |
114 | | title | `string \| ReactNode` | | The title of the alert. |
115 | | trigger | `ReactNode` | | The trigger button. |
116 |
--------------------------------------------------------------------------------
/docs/pages/docs/select.mdx:
--------------------------------------------------------------------------------
1 | import { Select } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Select
5 |
6 |
7 | console.log(value)}
16 | />
17 |
18 |
19 | ### Example
20 |
21 | ```tsx
22 | import { Select } from '@i4o/catalystui'
23 |
24 | export default () => {
25 | return (
26 | console.log(value)}
35 | />
36 | )
37 | }
38 | ```
39 |
40 | ### Props
41 |
42 | | Name | Type | Default | Description |
43 | | :------------ | :----------------------------------------------------------- | :------ | :--------------------------------------------------------------------------------- |
44 | | defaultValue | `string` | `''` | Default selected value. Use for uncontrolled operation. |
45 | | items | `Array<{ label: string, value: string, disabled: boolean }>` | [] | Array of items to display in the select |
46 | | name | `string` | `''` | Name of the select component |
47 | | onValueChange | `(item: { label: string, value: string }) => void` | - | Callback when the value changes |
48 | | value | `string` | `''` | Currently selected value. Use for controlled operation along with `onValueChange`. |
49 |
--------------------------------------------------------------------------------
/docs/pages/docs/separator.mdx:
--------------------------------------------------------------------------------
1 | import { Separator } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Separator
5 |
6 |
7 |
8 |
Catalyst UI
9 |
10 | React component library built with Radix Primitives and Tailwind CSS
11 |
12 |
13 |
18 |
19 |
20 |
21 | ### Example
22 |
23 | ```tsx
24 | import { Separator } from '@i4o/catalystui'
25 |
26 | export default () => {
27 | return (
28 |
29 |
Catalyst UI
30 |
31 | React component library built with Radix Primitives and Tailwind
32 | CSS
33 |
34 |
35 |
40 |
41 | )
42 | }
43 | ```
44 |
45 | ### Props
46 |
47 | | Name | Type | Default | Description |
48 | | :---------- | :--------------------------- | :------------- | :------------------------------------------------------------ |
49 | | decorative | `boolean` | | If separator is purely decorative and has no semantic meaning |
50 | | orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | Orientation of the Separator |
51 |
--------------------------------------------------------------------------------
/docs/pages/docs/slider.mdx:
--------------------------------------------------------------------------------
1 | import { Slider } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Slider
5 |
6 |
7 |
15 |
16 |
17 | ### Example
18 |
19 | ```tsx
20 | import { Slider } from '@i4o/catalystui'
21 |
22 | export default () => {
23 | return (
24 |
32 | )
33 | }
34 | ```
35 |
36 | ### Props
37 |
38 | | Name | Type | Default | Description |
39 | | :------------ | :-------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------ |
40 | | ariaLabel | `string` | `''` | Aria Label for the Slider |
41 | | defaultValue | `number[]` | `-` | Default value(s) of the slider. Use for uncontrolled operations. |
42 | | value | `number[]` | `-` | Value(s) of the slider. Use for controlled operations (along with onValueChange). |
43 | | onValueChange | `(value: number[]) => void` | `-` | This function is called when the slider value changes. |
44 | | onValueCommit | `(value: number[]) => void` | `-` | This function is called when the slider value changes but only at the end of the interaction. Use when you only need the final value. |
45 | | name | `string` | `''` | Name of the slider component |
46 | | min | `number` | `0` | Minimum value of the slider |
47 | | max | `number` | `100` | Maximum value of the slider |
48 | | step | `number` | `1` | Stepping interval for the slider |
49 |
--------------------------------------------------------------------------------
/docs/pages/docs/switch.mdx:
--------------------------------------------------------------------------------
1 | import { Switch } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Switch
5 |
6 |
7 |
8 |
9 |
10 | ### Example
11 |
12 | ```tsx
13 | import { Switch } from '@i4o/catalystui'
14 |
15 | export default () => {
16 | return
17 | }
18 | ```
19 |
20 | ### Props
21 |
22 | | Name | Type | Default | Description |
23 | | :-------------- | :--------------------------- | :---------- | :------------------------------ |
24 | | defaultChecked | `boolean` | `false` | Default on or off |
25 | | icon | `ReactNode` | `undefined` | Icon to show inside the switch |
26 | | name | `string` | `''` | Name of the switch field |
27 | | onCheckedChange | `(checked: boolean) => void` | `undefined` | Callback when the value changes |
28 |
--------------------------------------------------------------------------------
/docs/pages/docs/tabs.mdx:
--------------------------------------------------------------------------------
1 | import { Tabs, TabsList, TabsContent } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Tabs
5 |
6 |
7 |
8 |
9 |
Tab 1 Content,
15 | },
16 | {
17 | id: '2',
18 | title: 'Tab 2',
19 | content: Tab 2 Content
,
20 | },
21 | {
22 | id: '3',
23 | title: 'Tab 3',
24 | content: Tab 3 Content
,
25 | },
26 | ]}
27 | />
28 |
29 |
Tab 1 Content,
35 | },
36 | {
37 | id: '2',
38 | title: 'Tab 2',
39 | content: Tab 2 Content
,
40 | },
41 | {
42 | id: '3',
43 | title: 'Tab 3',
44 | content: Tab 3 Content
,
45 | },
46 | ]}
47 | />
48 |
49 |
50 |
51 |
52 |
53 | ### Example
54 |
55 | ```tsx
56 | import { Tabs } from '@i4o/catalystui'
57 |
58 | export default () => {
59 | const tabs = [
60 | {
61 | id: '1',
62 | title: 'Tab 1',
63 | content: Tab 1 Content
,
64 | },
65 | {
66 | id: '2',
67 | title: 'Tab 2',
68 | content: Tab 2 Content
,
69 | },
70 | {
71 | id: '3',
72 | title: 'Tab 3',
73 | content: Tab 3 Content
,
74 | },
75 | ]
76 |
77 | return (
78 |
79 |
85 |
86 | )
87 | }
88 | ```
89 |
90 | ### Props
91 |
92 | | Name | Type | Default | Description |
93 | | :----------- | :-------------------------------------------------------------------------------- | :------ | :-------------------------------------- |
94 | | defaultValue | `string` | `''` | Id of the tab to be selected by default |
95 | | tabs | `Array<{ id: string, title: string \| ReactNode, content: string \| ReactNode }>` | [] | Array of tabs to render |
96 | | type | `row \| column` | `row` | Layout of the tabs list and content |
97 |
--------------------------------------------------------------------------------
/docs/pages/docs/toast.mdx:
--------------------------------------------------------------------------------
1 | import { Toast } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Toast
5 |
6 |
7 |
15 |
16 |
17 | ### Example
18 |
19 | ```tsx
20 | import { Toast } from '@i4o/catalystui'
21 |
22 | export default () => {
23 | return (
24 |
31 | )
32 | }
33 | ```
34 |
35 | ### Props
36 |
37 | | Name | Type | Default | Description |
38 | | :------------ | :-------------------- | :------ | :----------------------------------------------------------------- |
39 | | trigger | `ReactNode \| string` | `null` | The element that triggers the toast. |
40 | | title | `string` | `null` | The title of the toast. |
41 | | description | `string` | `null` | The description of the toast. |
42 | | duration | `number` | `5000` | The duration of the toast in milliseconds. |
43 | | action | `ReactNode` | `null` | The action button of the toast. |
44 | | actionAltText | `string` | `null` | Alt text for action button. |
45 | | dismiss | `boolean` | `true` | If toast should have a dismiss button. |
46 | | defaultOpen | `boolean` | `false` | Default open state of the toast. Use when a trigger is not needed. |
47 |
--------------------------------------------------------------------------------
/docs/pages/docs/toggle-group.mdx:
--------------------------------------------------------------------------------
1 | import { ToggleGroup } from '@i4o/catalystui'
2 | import {
3 | FontBoldIcon,
4 | FontItalicIcon,
5 | UnderlineIcon,
6 | TextAlignLeftIcon,
7 | TextAlignCenterIcon,
8 | TextAlignRightIcon,
9 | } from '@radix-ui/react-icons'
10 | import DemoCard from '../../components/demo-card'
11 |
12 | # Toggle Group
13 |
14 |
15 | ,
21 | },
22 | {
23 | value: 'italic',
24 | label: 'Font Italic',
25 | icon: ,
26 | },
27 | {
28 | value: 'underline',
29 | label: 'Underline',
30 | icon: ,
31 | },
32 | ]}
33 | orientation='vertical'
34 | type='multiple'
35 | />
36 | ,
42 | },
43 | {
44 | value: 'center',
45 | label: 'Center Align',
46 | icon: ,
47 | },
48 | {
49 | value: 'right',
50 | label: 'Right Align',
51 | icon: ,
52 | },
53 | ]}
54 | style='pills'
55 | type='single'
56 | />
57 |
58 |
59 | ### Example
60 |
61 | ```tsx
62 | import { ToggleGroup } from '@i4o/catalystui'
63 | import {
64 | FontBoldIcon,
65 | FontItalicIcon,
66 | UnderlineIcon,
67 | TextAlignLeftIcon,
68 | TextAlignCenterIcon,
69 | TextAlignRightIcon,
70 | } from '@radix-ui/react-icons'
71 |
72 | export default function ToggleGroupExample() {
73 | return (
74 |
75 | ,
81 | },
82 | {
83 | value: 'italic',
84 | label: 'Font Italic',
85 | icon: ,
86 | },
87 | {
88 | value: 'underline',
89 | label: 'Underline',
90 | icon: ,
91 | },
92 | ]}
93 | type='multiple'
94 | />
95 | ,
101 | },
102 | {
103 | value: 'center',
104 | label: 'Center Align',
105 | icon: ,
106 | },
107 | {
108 | value: 'right',
109 | label: 'Right Align',
110 | icon: ,
111 | },
112 | ]}
113 | type='single'
114 | />
115 |
116 | )
117 | }
118 | ```
119 |
120 | ### Props
121 |
122 | | Name | Type | Default | Description |
123 | | :---- | :---------------------------------------------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------- |
124 | | items | `Array<{ value: string, label: string, icon: ReactNode }>` | [] | Array of items to render |
125 | | type | 'single' \| 'multiple' | 'single' | Type of toggle group. Single allows only one button to be toggled in a group. Multiple allows multiple toggles in the group. |
126 |
127 | // TODO: Update docs
128 |
--------------------------------------------------------------------------------
/docs/pages/docs/toggle.mdx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import { Toggle } from '@i4o/catalystui'
3 | import DemoCard from '../../components/demo-card'
4 |
5 | # Toggle
6 |
7 | export function ToggleDemo() {
8 | const [pressed, setPressed] = useState(false)
9 |
10 | return (
11 |
12 |
13 | {pressed ? 'Starred' : 'Star'}
14 |
15 |
16 | )
17 |
18 | }
19 |
20 |
21 |
22 | ### Example
23 |
24 | ```tsx
25 | import { Toggle } from '@i4o/catalystui'
26 |
27 | export default () => {
28 | const [pressed, setPressed] = useState(false)
29 |
30 | return (
31 |
32 | {pressed ? 'Starred' : 'Star'}
33 |
34 | )
35 | }
36 | ```
37 |
38 | ### Props
39 |
40 | | Name | Type | Default | Description |
41 | | :-------------- | :--------------------------- | :------ | :------------------------------------------------------------------------------ |
42 | | ariaLabel | `string` | `''` | `aria-label` for the Toggle component |
43 | | defaultPressed | `boolean` | `false` | If the Toggle should be active by default. Use for uncontrolled operation. |
44 | | pressed | `boolean` | `-` | Pressed state of the Toggle. Use for controlled operation with onPressedChange. |
45 | | onPressedChange | `(pressed: boolean) => void` | `-` | Event handler called when the pressed state of the Toggle changes. |
46 |
--------------------------------------------------------------------------------
/docs/pages/docs/toolbar.mdx:
--------------------------------------------------------------------------------
1 | import { Toolbar } from '@i4o/catalystui'
2 | import {
3 | FontBoldIcon,
4 | FontItalicIcon,
5 | UnderlineIcon,
6 | TextAlignLeftIcon,
7 | TextAlignCenterIcon,
8 | TextAlignRightIcon,
9 | } from '@radix-ui/react-icons'
10 | import DemoCard from '../../components/demo-card.tsx'
11 |
12 | # Toolbar
13 |
14 |
15 | ,
23 | },
24 | {
25 | id: 'italic',
26 | icon: ,
27 | },
28 | {
29 | id: 'underline',
30 | icon: ,
31 | },
32 | ],
33 | groupType: 'multiple',
34 | },
35 | {
36 | type: 'separator',
37 | },
38 | {
39 | type: 'toggle-group',
40 | groupItems: [
41 | {
42 | id: 'left',
43 | icon: ,
44 | },
45 | {
46 | id: 'center',
47 | icon: ,
48 | },
49 | {
50 | id: 'right',
51 | icon: ,
52 | },
53 | ],
54 | groupType: 'single',
55 | },
56 | {
57 | type: 'separator',
58 | },
59 | {
60 | type: 'button',
61 | buttonText: 'Share',
62 | },
63 | {
64 | type: 'separator',
65 | },
66 | {
67 | type: 'link',
68 | link: '/',
69 | linkText: Edited 2 hours ago
,
70 | },
71 | ]}
72 | />
73 |
74 |
75 | ### Example
76 |
77 | ```tsx
78 | import { Toolbar } from '@i4o/catalystui'
79 | import {
80 | FontBoldIcon,
81 | FontItalicIcon,
82 | UnderlineIcon,
83 | TextAlignLeftIcon,
84 | TextAlignCenterIcon,
85 | TextAlignRightIcon,
86 | } from '@radix-ui/react-icons'
87 |
88 | export default () => {
89 | return (
90 | ,
99 | },
100 | {
101 | id: 'italic',
102 | icon: ,
103 | },
104 | {
105 | id: 'underline',
106 | icon: ,
107 | },
108 | ],
109 | groupType: 'multiple',
110 | },
111 | {
112 | type: 'separator',
113 | },
114 | {
115 | type: 'toggle-group',
116 | groupItems: [
117 | {
118 | id: 'left',
119 | icon: ,
120 | },
121 | {
122 | id: 'center',
123 | icon: ,
124 | },
125 | {
126 | id: 'right',
127 | icon: ,
128 | },
129 | ],
130 | groupType: 'single',
131 | },
132 | {
133 | type: 'separator',
134 | },
135 | {
136 | type: 'link',
137 | link: '/',
138 | linkText: 'Edited 2 hours ago',
139 | },
140 | {
141 | type: 'button',
142 | buttonText: 'Share',
143 | },
144 | ]}
145 | />
146 | )
147 | }
148 | ```
149 |
150 | ### Props
151 |
152 | | Name | Type | Default | Description |
153 | | :-------- | :---------- | :------ | :---------- |
154 | | className | string | | |
155 | | items | ToolbarItem | | |
156 |
157 | #### ToolbarItem
158 |
159 | | Name | Type | Default | Description |
160 | | :------------- | :-------------------------------------------- | :------ | :---------------------------------------------------------------------------- |
161 | | buttonOnSelect | `() => void` | | Function to execute when a button is clicked. Use when `type` is `button`. |
162 | | buttonText | `string` | | Text inside the button. Use when `type` is `button` |
163 | | groupType | `single \| multiple` | | If multiple toggles can be enabled at once. Use when `type` is `toggle-group` |
164 | | groupItems | `ToggleGroupItem[]` | | List of items in a toggle group. Use when `type` is `toggle-group` |
165 | | link | `string` | | URL of the link. Use when `type` is `link` |
166 | | linkText | `string` | | Text of the link. Use when `type` is `link` |
167 | | type | `toggle-group \| separator \| link \| button` | | Text of the link. Use when `type` is `link` |
168 |
--------------------------------------------------------------------------------
/docs/pages/docs/tooltip.mdx:
--------------------------------------------------------------------------------
1 | import { Button, Tooltip } from '@i4o/catalystui'
2 | import DemoCard from '../../components/demo-card'
3 |
4 | # Tooltip
5 |
6 |
7 |
8 | Hover me
9 |
10 |
11 |
12 | ### Example
13 |
14 | ```tsx
15 | import { Button, Tooltip } from '@i4o/catalystui'
16 |
17 | export default () => (
18 |
19 | Hover me
20 |
21 | )
22 | ```
23 |
24 | ### Props
25 |
26 | | Name | Type | Default | Description |
27 | | :------- | :------------------------------- | :------- | :------------------------------------------ |
28 | | content | `ReactNode \| string` | - | The content of the tooltip |
29 | | side | `top \| right \| bottom \| left` | 'top' | The placement of the tooltip |
30 | | align | `start \| center \| end` | 'center' | Alignment of the content inside the tooltip |
31 | | children | `ReactNode` | - | The element to be wrapped by the tooltip |
32 |
--------------------------------------------------------------------------------
/docs/pages/index.mdx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 | import { Button, CopyToClipboard } from '@i4o/catalystui'
3 | import Link from 'next/link'
4 |
5 |
17 |
18 | {
19 |
20 |
21 | Catalyst UI is a component library built on top of Radix UI Primitives,
22 | styled with Tailwind CSS to make prototyping faster.
23 |
24 |
25 | }
26 |
27 | {
28 |
29 |
30 | It also comes with more than just the styled Radix UI Primitives. It builds
31 | on top of them to provide you with more components and utilities to use in
32 | your apps.
33 |
34 | }
35 |
36 |
37 |
38 |
39 | Documentation
40 |
41 |
42 |
43 |
44 | npm install @i4o/catalystui
45 |
46 |
47 |
48 |
49 |
50 | Get Started
51 |
52 | {Example Usage
}
53 |
54 | ```tsx
55 | import { Button } from '@i4o/catalystui'
56 |
57 | export default function Home() {
58 | return (
59 |
60 | Click Me
61 |
62 | )
63 | }
64 | ```
65 |
66 | Features
67 |
68 | - Built on top of [Radix UI Primitives](https://www.radix-ui.com/) styled with [Tailwind CSS](https://tailwindcss.com/)
69 | - Additional utility components and hooks
70 | - Built-in dark mode support
71 | - Icons from [Radix UI Icons](https://icons.radix-ui.com/)
72 | - TypeScript support
73 |
74 | Roadmap
75 |
76 | - [x] Have a base list of usable components
77 | - [x] Fix library styles being overridden by nextra styles
78 | - [ ] Make the API and styles more consistent
79 | - [ ] Make docs light/dark mode work for the components
80 | - [ ] Implement all Radix UI Primitives
81 | - [ ] Fix accessibility issues
82 | - [ ] Add explanation for props in the docs
83 |
--------------------------------------------------------------------------------
/docs/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/docs/public/assets/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/public/assets/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/public/assets/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/public/assets/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/public/assets/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/public/assets/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/public/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/favicon.ico
--------------------------------------------------------------------------------
/docs/public/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/logo.png
--------------------------------------------------------------------------------
/docs/public/assets/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/assets/mstile-150x150.png
--------------------------------------------------------------------------------
/docs/public/assets/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.14, written by Peter Selinger 2001-2017
9 |
10 |
12 |
30 |
44 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/public/assets/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/i4o-oss/catalystui/581952069a769d8bb1542f07cb27ee4a3c4d012e/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | /* @layer base { */
6 | /* :root { */
7 | /* --brand: 104 221 253; */
8 | /* --brand-hover: 46 189 229; */
9 | /* --brand-states: 121 207 234; */
10 | /* } */
11 | /* } */
12 |
13 | body {
14 | @apply bg-[#010101] font-sans;
15 | }
16 |
17 | a {
18 | color: inherit;
19 | text-decoration: none;
20 | }
21 |
22 | article main p > a,
23 | article main ul > li > a {
24 | @apply !text-brand-500 !no-underline;
25 | }
26 |
27 | .contains-task-list {
28 | @apply mt-6 first:mt-0 ltr:ml-1 rtl:mr-1;
29 | }
30 |
31 | .contains-task-list .task-list-item {
32 | @apply my-2;
33 | }
34 |
35 | .contains-task-list input[type='checkbox'] {
36 | @apply !mr-2;
37 | }
38 |
39 | @media (prefers-color-scheme: dark) {
40 | html {
41 | color-scheme: dark;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/docs/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './theme.config.js',
5 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
6 | './components/**/*.{js,ts,jsx,tsx}',
7 | ],
8 | theme: {
9 | extend: {
10 | colors: {
11 | brand: {
12 | DEFAULT: '#2CB67D',
13 | 50: '#E6F9F1',
14 | 100: '#D2F4E6',
15 | 200: '#A5E9CD',
16 | 300: '#77DEB3',
17 | 400: '#46D298',
18 | 500: '#2CB67D',
19 | 600: '#239062',
20 | 700: '#1B6F4C',
21 | 800: '#124A33',
22 | 900: '#092519',
23 | },
24 | },
25 | fontFamily: {
26 | sans: ['Inter', 'sans-serif'],
27 | serif: ['Merriweather', 'serif'],
28 | },
29 | },
30 | },
31 | plugins: [],
32 | }
33 |
--------------------------------------------------------------------------------
/docs/theme.config.js:
--------------------------------------------------------------------------------
1 | import Image from 'next/image'
2 |
3 | const newItems = [
4 | 'Context Menu',
5 | 'Label',
6 | 'Menubar',
7 | 'Separator',
8 | 'Slider',
9 | 'Toggle',
10 | ]
11 |
12 | const theme = {
13 | logo: (
14 |
15 |
22 | Catalyst UI
23 |
24 | ),
25 | project: {
26 | link: 'https://github.com/i4o-oss/catalystui',
27 | newWindow: true,
28 | },
29 | head: ({ title }) => {
30 | return (
31 | <>
32 |
37 |
43 |
49 |
50 |
55 |
56 |
57 |
58 | {title
59 | ? `${title} - Catalyst UI`
60 | : 'Styled Radix UI components and utilities — Catalyst UI'}
61 |
62 | >
63 | )
64 | },
65 | gitTimestamp: null,
66 | sidebar: {
67 | titleComponent({ title }) {
68 | if (newItems.includes(title)) {
69 | return (
70 |
71 | {title}
72 |
73 | New
74 |
75 |
76 | )
77 | }
78 |
79 | return title
80 | },
81 | },
82 | // footer: {
83 | // component: (
84 | //
85 | //
86 | //
87 | //
98 | //
99 | //
100 | //
108 | //
109 | //
110 | // Built by{' '}
111 | //
117 | // i4o
118 | //
119 | // .
120 | //
121 | //
122 | //
135 | //
136 | //
137 | // ),
138 | // },
139 | }
140 | export default theme
141 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | },
18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "catalystui",
3 | "version": "0.1.0",
4 | "private": true,
5 | "workspaces": [
6 | "docs",
7 | "packages/*"
8 | ],
9 | "scripts": {
10 | "build": "turbo run build",
11 | "dev": "turbo run dev --parallel",
12 | "lint": "turbo run lint",
13 | "start": "turbo run start --scope=@catalystui/docs",
14 | "format": "prettier --write .",
15 | "release": "turbo run build --filter=@i4o/catalystui && changeset publish"
16 | },
17 | "devDependencies": {
18 | "@catalystui/eslint-config": "workspace:*",
19 | "@changesets/cli": "^2.26.1",
20 | "prettier": "latest",
21 | "turbo": "latest"
22 | },
23 | "engines": {
24 | "node": ">=18.0.0"
25 | },
26 | "packageManager": "pnpm@8.14.0"
27 | }
28 |
--------------------------------------------------------------------------------
/packages/eslint-config/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | plugins: ['@typescript-eslint'],
4 | env: {
5 | es6: true,
6 | node: true,
7 | browser: true,
8 | },
9 | parserOptions: {
10 | ecmaVersion: 'latest',
11 | sourceType: 'module',
12 | ecmaFeatures: {
13 | jsx: true,
14 | },
15 | },
16 | extends: ['next/core-web-vitals', 'turbo', 'prettier'],
17 | rules: {
18 | '@next/next/no-html-link-for-pages': 'off',
19 | 'react/prop-types': 'off',
20 | 'react/react-in-jsx-scope': 'off',
21 | 'react/display-name': 'off',
22 | '@typescript-eslint/ban-ts-comment': 'off',
23 | '@typescript-eslint/no-namespace': 'off',
24 | '@typescript-eslint/no-explicit-any': 'off',
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/packages/eslint-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@catalystui/eslint-config",
3 | "version": "0.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "eslint": "^7.23.0",
8 | "eslint-config-next": "13.0.0",
9 | "eslint-config-prettier": "^8.3.0",
10 | "eslint-plugin-react": "7.31.8",
11 | "eslint-config-turbo": "latest"
12 | },
13 | "devDependencies": {
14 | "@typescript-eslint/eslint-plugin": "^5.47.1",
15 | "@typescript-eslint/parser": "^5.47.1",
16 | "typescript": "^4.7.4"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/packages/tsconfig/README.md:
--------------------------------------------------------------------------------
1 | # `tsconfig`
2 |
3 | These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from.
4 |
--------------------------------------------------------------------------------
/packages/tsconfig/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "composite": false,
6 | "declaration": true,
7 | "declarationMap": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "inlineSources": false,
11 | "isolatedModules": true,
12 | "moduleResolution": "node",
13 | "noUnusedLocals": false,
14 | "noUnusedParameters": false,
15 | "preserveWatchOutput": true,
16 | "skipLibCheck": true,
17 | "strict": true
18 | },
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/tsconfig/nextjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Next.js",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "target": "es5",
7 | "lib": ["dom", "dom.iterable", "esnext"],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "noEmit": true,
13 | "incremental": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "resolveJsonModule": true,
17 | "isolatedModules": true,
18 | "jsx": "preserve"
19 | },
20 | "include": ["src", "next-env.d.ts"],
21 | "exclude": ["node_modules"]
22 | }
23 |
--------------------------------------------------------------------------------
/packages/tsconfig/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@catalystui/tsconfig",
3 | "version": "0.0.0",
4 | "private": true,
5 | "files": [
6 | "base.json",
7 | "nextjs.json",
8 | "ui.json"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/tsconfig/ui.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "UI",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "jsx": "react-jsx",
7 | "lib": ["DOM", "ES2019"],
8 | "module": "ESNext",
9 | "target": "es6",
10 | "esModuleInterop": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/ui/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @i4o-oss/catalystui
2 |
3 | ## 1.0.0-alpha.17
4 |
5 | ### Patch Changes
6 |
7 | - 55bdbd9: Update select component styles and add size prop for avatar component
8 |
9 | ## 1.0.0-alpha.16
10 |
11 | ### Patch Changes
12 |
13 | - e6fa1e0: Update date picker component
14 |
15 | ## 1.0.0-alpha.15
16 |
17 | ### Patch Changes
18 |
19 | - 065b99a: Add calendar and date picker components
20 |
21 | ## 1.0.0-alpha.14
22 |
23 | ### Patch Changes
24 |
25 | - 24b4499: Add value prop to select component for controlled operations
26 |
27 | ## 1.0.0-alpha.13
28 |
29 | ### Patch Changes
30 |
31 | - f5a6b1d: Improve colors, update styles, replace classnames with clsx, refactor some components
32 |
33 | ## 1.0.0-alpha.12
34 |
35 | ### Patch Changes
36 |
37 | - 09f5160: Add 4 new components - label, separator, slider, and toggle
38 |
39 | ## 1.0.0-alpha.11
40 |
41 | ### Patch Changes
42 |
43 | - d6189ff: Fix select not opening in uncontrolled operation
44 |
45 | ## 1.0.0-alpha.10
46 |
47 | ### Patch Changes
48 |
49 | - e098bd9: Update readme and package details
50 |
51 | ## 1.0.0-alpha.9
52 |
53 | ### Patch Changes
54 |
55 | - fe2ebbf: Update package homepage
56 |
57 | ## 1.0.0-alpha.8
58 |
59 | ### Patch Changes
60 |
61 | - 161e778: Update z-index of close button in dialog component
62 |
63 | ## 1.0.0-alpha.7
64 |
65 | ### Patch Changes
66 |
67 | - df9314a: Add change event handler prop to checkbox component
68 |
69 | ## 1.0.0-alpha.6
70 |
71 | ### Patch Changes
72 |
73 | - 23bfad9: Update shortcut styles in dropdown component
74 |
75 | ## 1.0.0-alpha.5
76 |
77 | ### Patch Changes
78 |
79 | - ae2a551: Fix default value not working in select
80 |
81 | ## 1.0.0-alpha.4
82 |
83 | ### Patch Changes
84 |
85 | - d759ad6: Update scroll area
86 |
87 | ## 1.0.0-alpha.3
88 |
89 | ### Patch Changes
90 |
91 | - 5530fd5: Add few more components and update docs
92 |
93 | ## 1.0.0-alpha.2
94 |
95 | ### Patch Changes
96 |
97 | - 99eff56: Use theme variables everywhere and add a few radix primitives
98 | - 875d6f8: Use theme variables everywhere and add a few radix primitives
99 |
100 | ## 1.0.0-alpha.1
101 |
102 | ### Patch Changes
103 |
104 | - b042150: Push again
105 |
106 | ## 1.0.0-alpha.0
107 |
108 | ### Major Changes
109 |
110 | - Prerelease
111 |
112 | ## 0.9.3
113 |
114 | ### Patch Changes
115 |
116 | - a67f196: Update dialog and select components
117 |
118 | ## 0.9.2
119 |
120 | ### Patch Changes
121 |
122 | - 59715eb: Update styles for dialog component
123 |
124 | ## 0.9.1
125 |
126 | ### Patch Changes
127 |
128 | - 15df07a: Update styles for dialog component
129 |
130 | ## 0.9.0
131 |
132 | ### Minor Changes
133 |
134 | - 92ddeef: Update button and dropdown components
135 |
136 | ## 0.8.0
137 |
138 | ### Minor Changes
139 |
140 | - b66cade: Split tab components and export them all
141 |
142 | ## 0.7.24
143 |
144 | ### Patch Changes
145 |
146 | - e6d7bcd: Update dialog component styles
147 |
148 | ## 0.7.23
149 |
150 | ### Patch Changes
151 |
152 | - 5abf743: Add aria-label prop to buttons
153 |
154 | ## 0.7.22
155 |
156 | ### Patch Changes
157 |
158 | - aaa928b: Add open link in new tab option to dropdown item
159 |
160 | ## 0.7.21
161 |
162 | ### Patch Changes
163 |
164 | - fe9a70a: Fix z-index of dropdown menu
165 |
166 | ## 0.7.20
167 |
168 | ### Patch Changes
169 |
170 | - e7bf713: Fix toggle-group styles in toolbar component
171 | - 5152a1a: Fix toggle-group styles in toolbar component
172 |
173 | ## 0.7.19
174 |
175 | ### Patch Changes
176 |
177 | - 76fb28f: Add prefix to tailwind classes to prevent collisions
178 |
179 | ## 0.7.18
180 |
181 | ### Patch Changes
182 |
183 | - 2e29543: Update toast styles
184 |
185 | ## 0.7.17
186 |
187 | ### Patch Changes
188 |
189 | - e0e453f: Update toast component
190 |
191 | ## 0.7.16
192 |
193 | ### Patch Changes
194 |
195 | - 26e6488: Update toast component
196 |
197 | ## 0.7.15
198 |
199 | ### Patch Changes
200 |
201 | - 5ffb099: Update toast component
202 |
203 | ## 0.7.14
204 |
205 | ### Patch Changes
206 |
207 | - 0cc2511: Update toast styles
208 |
209 | ## 0.7.13
210 |
211 | ### Patch Changes
212 |
213 | - cc6128c: Update toggle group styles
214 | - e9ada54: Fix type in toggle group
215 |
216 | ## 0.7.12
217 |
218 | ### Patch Changes
219 |
220 | - 1c3191a: Update tabs and toggle group styles
221 |
222 | ## 0.7.11
223 |
224 | ### Patch Changes
225 |
226 | - 814d449: Update tab styles
227 |
228 | ## 0.7.10
229 |
230 | ### Patch Changes
231 |
232 | - aeaeb83: Update tab styles
233 |
234 | ## 0.7.9
235 |
236 | ### Patch Changes
237 |
238 | - 6d9414c: Update tab styles
239 |
240 | ## 0.7.8
241 |
242 | ### Patch Changes
243 |
244 | - 088380d: Update dialog styles
245 |
246 | ## 0.7.7
247 |
248 | ### Patch Changes
249 |
250 | - 8aedae9: Update dialog styles
251 |
252 | ## 0.7.6
253 |
254 | ### Patch Changes
255 |
256 | - 18e6ec9: Update dialog styles
257 |
258 | ## 0.7.5
259 |
260 | ### Patch Changes
261 |
262 | - e4dacd2: Update alert and dialog components
263 |
264 | ## 0.7.4
265 |
266 | ### Patch Changes
267 |
268 | - 58b5690: Update dialog component
269 |
270 | ## 0.7.3
271 |
272 | ### Patch Changes
273 |
274 | - 782e6e5: Update props for dialog component
275 |
276 | ## 0.7.2
277 |
278 | ### Patch Changes
279 |
280 | - 065af3f: Update dropdown link behaviour
281 |
282 | ## 0.7.1
283 |
284 | ### Patch Changes
285 |
286 | - dc6fe75: Update toolbar component
287 |
288 | ## 0.7.0
289 |
290 | ### Minor Changes
291 |
292 | - 044bf7c: Rename package and update toolbar
293 |
294 | ## 0.6.1
295 |
296 | ### Patch Changes
297 |
298 | - bd0803e: Update components
299 |
300 | ## 0.6.0
301 |
302 | ### Minor Changes
303 |
304 | - c374db4: Add link prop to nav component which can accept link components from meta-frameworks like Remix
305 |
306 | ## 0.5.3
307 |
308 | ### Patch Changes
309 |
310 | - 3807436: Update styles for nav component
311 |
312 | ## 0.5.2
313 |
314 | ### Patch Changes
315 |
316 | - eead4c4: Fix peer dependencies
317 |
318 | ## 0.5.1
319 |
320 | ### Patch Changes
321 |
322 | - f7f3470: Fix issue with publishing
323 |
324 | ## 0.5.0
325 |
326 | ### Minor Changes
327 |
328 | - 003de96: Update components styles and props
329 |
330 | ## 0.4.0
331 |
332 | ### Minor Changes
333 |
334 | - 7ec079f: Add new props for select component
335 |
336 | ### Patch Changes
337 |
338 | - 24f10dd: Add github repo and website to package.json
339 |
340 | ## 0.3.0
341 |
342 | ### Minor Changes
343 |
344 | - c393da6: Add new functionality to some components
345 |
346 | - Add new props to checkbox component - disabled, name, required
347 | - Adjust props for accordion and toggle group
348 |
349 | ## 0.2.0
350 |
351 | ### Minor Changes
352 |
353 | - 2c7c6cf: Update toast component
354 |
355 | - Update toast styles
356 | - Update action props
357 | - Add a dismiss prop
358 | - Update how toast renders depending on whether both action and dismiss props are present or if only action is present.
359 |
360 | ## 0.1.2
361 |
362 | ### Patch Changes
363 |
364 | - 7b9f1ab: Add Readme
365 |
366 | ## 0.1.1
367 |
368 | ### Patch Changes
369 |
370 | - 84b9bcc: Fix issues with publish workflow
371 |
372 | ## 0.1.0
373 |
374 | ### Minor Changes
375 |
376 | - d8a06df: Add basic set of styled Radix primitives
377 |
--------------------------------------------------------------------------------
/packages/ui/README.md:
--------------------------------------------------------------------------------
1 | # Catalyst UI
2 |
3 | Catalyst UI is a component library built on top of Radix UI Primitives styled with Tailwind CSS made to make prototyping faster.
4 |
5 | ## Documentation
6 |
7 | For full documentation and a complete list of components, visit [catalyst-ui.com](https://catalyst-ui.com/)
8 |
9 | ## Installation
10 |
11 | ```bash
12 | npm install @i4o/catalystui
13 | ```
14 |
15 | ## Features
16 |
17 | - Built on top of Radix UI Primitives styled with Tailwind CSS
18 | - Goes beyond Radix UI Primitives to provide more components
19 | - Utility components and hooks
20 | - Built-in dark mode support
21 |
22 | ## Roadmap
23 |
24 | - [x] Have a base list of usable components
25 | - [x] Fix library styles being overridden by nextra styles
26 | - [ ] Make the API and styles more consistent
27 | - [ ] Make docs light/dark mode work for the components
28 | - [ ] Implement all Radix UI Primitives
29 | - [ ] Fix accessibility issues
30 | - [ ] Add explanation for props in the docs
31 |
32 | ## Acknowledgements
33 |
34 | CatalystUI and its docs are powered by these incredible open source projects:
35 |
36 | - [React](https://reactjs.org/)
37 | - [TypeScript](https://www.typescriptlang.org/)
38 | - [Next.js](https://nextjs.org/)
39 | - [Nextra](https://nextra.site/)
40 | - [Radix UI](https://www.radix-ui.com/)
41 | - [Tailwind CSS](https://tailwindcss.com/)
42 | - [tailwindcss-radix](https://github.com/ecklf/tailwindcss-radix)
43 | - [classnames](https://github.com/JedWatson/classnames)
44 | - [copy-to-clipboard](https://github.com/sudodoki/copy-to-clipboard)
45 |
46 | ## License
47 |
48 | [MIT](https://choosealicense.com/licenses/mit/)
49 |
--------------------------------------------------------------------------------
/packages/ui/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | export { default as Accordion } from './src/components/accordion'
4 | export { default as Alert } from './src/components/alert'
5 | export { default as AspectRatio } from './src/components/aspect-ratio'
6 | export { default as Avatar } from './src/components/avatar'
7 | export { default as Button } from './src/components/buttons/button'
8 | export { default as DangerButton } from './src/components/buttons/danger'
9 | export { default as IconButton } from './src/components/buttons/icon-button'
10 | export { default as PrimaryButton } from './src/components/buttons/primary'
11 | export { default as SharedButton } from './src/components/buttons/shared/button'
12 |
13 |
14 | export { default as Checkbox } from './src/components/checkbox'
15 | export { default as Collapsible } from './src/components/collapsible'
16 | export { default as CopyToClipboard } from './src/components/copy-to-clipboard'
17 | export { default as DatePicker } from './src/components/date-picker'
18 | export { default as Dialog } from './src/components/dialog'
19 | export { default as Dropdown } from './src/components/dropdown'
20 | export { default as HoverCard } from './src/components/hover-card'
21 | export { default as Label } from './src/components/label'
22 | export { default as Nav } from './src/components/nav'
23 | export { default as Popover } from './src/components/popover'
24 | export { default as Progress } from './src/components/progress'
25 | export { default as RadioGroup } from './src/components/radio-group'
26 | export { default as ScrollArea } from './src/components/scroll-area'
27 | export { default as Separator } from './src/components/separator'
28 | export { default as Select } from './src/components/select'
29 | export { default as Slider } from './src/components/slider'
30 | export { default as Switch } from './src/components/switch'
31 | export { Tabs, TabsList, TabsContent } from './src/components/tabs'
32 | export { default as Toast } from './src/components/toast'
33 | export { default as Toggle } from './src/components/toggle'
34 | export { default as ToggleGroup } from './src/components/toggle-group'
35 | export { default as Toolbar } from './src/components/toolbar'
36 | export { default as Tooltip } from './src/components/tooltip'
37 |
--------------------------------------------------------------------------------
/packages/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@i4o/catalystui",
3 | "version": "1.0.0-alpha.17",
4 | "files": [
5 | "dist"
6 | ],
7 | "main": "./dist/index.js",
8 | "module": "./dist/index.mjs",
9 | "style": "./dist/main.css",
10 | "exports": {
11 | ".": "./dist/index.js",
12 | "./main.css": "./dist/main.css"
13 | },
14 | "types": "./dist/index.d.ts",
15 | "license": "MIT",
16 | "scripts": {
17 | "build": "concurrently \"npm run build:css\" \"tsup index.tsx --format esm,cjs --dts --external react\"",
18 | "build:css": "tailwindcss -m -i ./styles/main.css -o ./dist/main.css",
19 | "dev": "concurrently \"npm run dev:css\" \"tsup index.tsx --format esm,cjs --watch --dts --external react\"",
20 | "dev:css": "tailwindcss -w -i ./styles/main.css -o ./dist/main.css",
21 | "lint": "eslint *.ts*"
22 | },
23 | "dependencies": {
24 | "@radix-ui/react-accordion": "1.1.2",
25 | "@radix-ui/react-alert-dialog": "1.0.4",
26 | "@radix-ui/react-aspect-ratio": "1.0.3",
27 | "@radix-ui/react-avatar": "1.0.3",
28 | "@radix-ui/react-checkbox": "1.0.4",
29 | "@radix-ui/react-collapsible": "^1.0.3",
30 | "@radix-ui/react-context-menu": "^2.1.4",
31 | "@radix-ui/react-dialog": "1.0.4",
32 | "@radix-ui/react-dropdown-menu": "2.0.5",
33 | "@radix-ui/react-hover-card": "^1.0.6",
34 | "@radix-ui/react-icons": "1.3.0",
35 | "@radix-ui/react-label": "2.0.2",
36 | "@radix-ui/react-menubar": "^1.0.3",
37 | "@radix-ui/react-navigation-menu": "1.1.3",
38 | "@radix-ui/react-popover": "1.0.6",
39 | "@radix-ui/react-progress": "^1.0.3",
40 | "@radix-ui/react-radio-group": "1.1.3",
41 | "@radix-ui/react-scroll-area": "^1.0.4",
42 | "@radix-ui/react-select": "1.2.2",
43 | "@radix-ui/react-separator": "^1.0.3",
44 | "@radix-ui/react-slider": "^1.1.2",
45 | "@radix-ui/react-switch": "1.0.3",
46 | "@radix-ui/react-tabs": "1.0.4",
47 | "@radix-ui/react-toast": "1.1.4",
48 | "@radix-ui/react-toggle": "1.0.3",
49 | "@radix-ui/react-toggle-group": "1.0.4",
50 | "@radix-ui/react-toolbar": "1.0.4",
51 | "@radix-ui/react-tooltip": "1.0.6",
52 | "clsx": "^2.0.0",
53 | "copy-to-clipboard": "^3.3.3",
54 | "date-fns": "^2.30.0",
55 | "react-day-picker": "^8.8.1",
56 | "tailwindcss-radix": "2.8.0"
57 | },
58 | "devDependencies": {
59 | "@catalystui/eslint-config": "workspace:*",
60 | "@catalystui/tsconfig": "workspace:*",
61 | "@types/react": "^18.2.15",
62 | "@types/react-dom": "^18.2.7",
63 | "autoprefixer": "^10.4.14",
64 | "concurrently": "^8.2.0",
65 | "eslint": "^8.44.0",
66 | "postcss": "^8.4.26",
67 | "react": "^18.2.0",
68 | "react-dom": "^18.2.0",
69 | "tailwindcss": "^3.3.3",
70 | "tsup": "^7.1.0",
71 | "typescript": "^5.1.6"
72 | },
73 | "peerDependencies": {
74 | "react": "^18.2.0",
75 | "react-dom": "^18.2.0"
76 | },
77 | "publishConfig": {
78 | "access": "public"
79 | },
80 | "homepage": "https://catalyst-ui.com",
81 | "repository": {
82 | "type": "git",
83 | "url": "git+https://github.com/i4o-oss/catalystui.git"
84 | },
85 | "bugs": {
86 | "url": "https://github.com/i4o-oss/catalystui/issues"
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/packages/ui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/packages/ui/src/components/accordion.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as AccordionPrimitive from '@radix-ui/react-accordion'
3 | import type {
4 | AccordionMultipleProps,
5 | AccordionSingleProps,
6 | } from '@radix-ui/react-accordion'
7 | import { ChevronDownIcon } from '@radix-ui/react-icons'
8 | import clsx from 'clsx'
9 |
10 | interface AccordionItemType {
11 | id: string
12 | title: string | ReactNode
13 | content: string | ReactNode
14 | }
15 |
16 | interface AccordionSingle extends AccordionSingleProps {
17 | collapsible?: boolean
18 | defaultValue?: string
19 | items: AccordionItemType[]
20 | type: 'single'
21 | }
22 |
23 | interface AccordionMultiple extends AccordionMultipleProps {
24 | collapsible?: boolean
25 | defaultValue?: string[]
26 | items: AccordionItemType[]
27 | type: 'multiple'
28 | }
29 |
30 | const Accordion: FC = ({
31 | collapsible = true,
32 | defaultValue,
33 | items,
34 | type = 'single',
35 | }) => {
36 | return (
37 | // @ts-ignore
38 |
48 | {items.map((item, index) => {
49 | return (
50 |
55 |
56 |
73 |
74 | {item.title}
75 |
76 |
82 |
83 |
93 |
94 | {item.content}
95 |
96 |
97 |
98 |
99 | )
100 | })}
101 |
102 | )
103 | }
104 |
105 | export default Accordion
106 |
--------------------------------------------------------------------------------
/packages/ui/src/components/alert.tsx:
--------------------------------------------------------------------------------
1 | import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
2 | import * as AlertPrimitive from '@radix-ui/react-alert-dialog'
3 | import clsx from 'clsx'
4 |
5 | type AlertProps = {
6 | title?: ReactNode | string
7 | description?: ReactNode | string
8 | cancel: ReactNode
9 | action: ReactNode
10 | trigger?: ReactNode
11 | open?: boolean
12 | onOpenChange?: Dispatch>
13 | }
14 |
15 | const Alert: FC = ({
16 | title = '',
17 | description = '',
18 | cancel,
19 | action,
20 | trigger = null,
21 | open,
22 | onOpenChange,
23 | }) => {
24 | return (
25 |
26 | {trigger ? (
27 |
28 | {trigger}
29 |
30 | ) : null}
31 |
32 |
36 |
45 | {title && (
46 |
47 | {title}
48 |
49 | )}
50 | {description && (
51 |
52 | {description}
53 |
54 | )}
55 |
56 |
{cancel}
57 |
{action}
58 |
59 |
60 |
61 |
62 | )
63 | }
64 |
65 | export default Alert
66 |
--------------------------------------------------------------------------------
/packages/ui/src/components/aspect-ratio.tsx:
--------------------------------------------------------------------------------
1 | import { FC, Fragment } from 'react'
2 | import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'
3 | import clsx from 'clsx'
4 |
5 | interface AspectRatioProps {
6 | alt: string
7 | ratio: number
8 | src: string
9 | }
10 |
11 | const AspectRatio: FC = ({ alt, ratio, src }) => {
12 | return (
13 |
14 |
18 |
24 |
30 |
31 |
32 |
33 | )
34 | }
35 |
36 | export default AspectRatio
37 |
--------------------------------------------------------------------------------
/packages/ui/src/components/avatar.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as AvatarPrimitive from '@radix-ui/react-avatar'
3 | import clsx from 'clsx'
4 |
5 | interface AvatarProps {
6 | alt?: string
7 | fallback?: ReactNode | string
8 | size: 'small' | 'base' | 'large'
9 | src?: string
10 | variant?: 'circle' | 'rounded'
11 | }
12 |
13 | const Avatar: FC = ({
14 | alt,
15 | fallback,
16 | size = 'base',
17 | src,
18 | variant,
19 | }) => {
20 | return (
21 |
33 |
45 |
56 |
57 | {fallback}
58 |
59 |
60 |
61 | )
62 | }
63 |
64 | export default Avatar
65 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import clsx from 'clsx'
3 | import type { ButtonProps } from './types'
4 | import Tooltip from '../tooltip'
5 |
6 | // TODO: Remove important ! modifier here when switching to Rescribe
7 | const Button = React.forwardRef(
8 | (
9 | {
10 | ariaLabel = '',
11 | children,
12 | className,
13 | disabled,
14 | leftIcon,
15 | loading,
16 | loadingText,
17 | onClick,
18 | onMouseDown,
19 | rightIcon,
20 | textSize = 'cui-text-sm',
21 | tooltip = '',
22 | type = 'button',
23 | ...props
24 | },
25 | ref
26 | ) => {
27 | const button = (
28 |
48 | {leftIcon}
49 | {loading && (
50 |
56 |
64 |
69 |
70 | )}
71 |
72 | {loading ? loadingText : children}
73 |
74 | {rightIcon}
75 |
76 | )
77 |
78 | if (tooltip) {
79 | return {button}
80 | }
81 |
82 | return button
83 | }
84 | )
85 |
86 | Button.displayName = 'Button'
87 | export default Button
88 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/danger.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import type { ButtonProps } from './types'
3 | import Tooltip from '../tooltip'
4 | import clsx from 'clsx'
5 |
6 | // TODO: Remove important ! modifier here when switching to Rescribe
7 | const DangerButton = React.forwardRef(
8 | (
9 | {
10 | ariaLabel = '',
11 | children,
12 | className,
13 | disabled,
14 | leftIcon,
15 | loading,
16 | loadingText,
17 | onClick,
18 | onMouseDown,
19 | rightIcon,
20 | shadow = '',
21 | textSize = 'cui-text-sm',
22 | tooltip = '',
23 | type = 'button',
24 | ...props
25 | },
26 | ref
27 | ) => {
28 | const button = (
29 |
49 | {leftIcon}
50 | {loading && (
51 |
57 |
65 |
70 |
71 | )}
72 |
73 | {loading ? loadingText : children}
74 |
75 | {rightIcon}
76 |
77 | )
78 |
79 | if (tooltip) {
80 | return {button}
81 | }
82 |
83 | return button
84 | }
85 | )
86 |
87 | export default DangerButton
88 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/icon-button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import type { ReactNode } from 'react'
3 | import type { ButtonProps } from './types'
4 | import Tooltip from '../tooltip'
5 | import clsx from 'clsx'
6 |
7 | interface IconButtonProps extends ButtonProps {
8 | icon: ReactNode
9 | }
10 |
11 | const IconButton = React.forwardRef(
12 | (
13 | {
14 | ariaLabel = '',
15 | bg = 'cui-bg-transparent',
16 | className,
17 | disabled,
18 | icon,
19 | onClick,
20 | onMouseDown,
21 | tooltip = '',
22 | type = 'button',
23 | ...props
24 | },
25 | ref
26 | ) => {
27 | const button = (
28 |
46 | {icon}
47 |
48 | )
49 |
50 | if (tooltip) {
51 | return {button}
52 | }
53 |
54 | return button
55 | }
56 | )
57 |
58 | export default IconButton
59 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Button } from './button'
2 | export { default as DangerButton } from './danger'
3 | export { default as PrimaryButton } from './primary'
4 | export { default as IconButton } from './icon-button'
5 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/primary.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import clsx from 'clsx'
3 | import type { ButtonProps } from './types'
4 | import Tooltip from '../tooltip'
5 |
6 | // TODO: Remove important ! modifier here when switching to Rescribe
7 | const PrimaryButton = React.forwardRef(
8 | (
9 | {
10 | ariaLabel = '',
11 | children,
12 | className,
13 | disabled,
14 | leftIcon,
15 | loading,
16 | loadingText,
17 | onClick,
18 | onMouseDown,
19 | rightIcon,
20 | textSize = 'cui-text-sm',
21 | tooltip = '',
22 | type = 'button',
23 | ...props
24 | },
25 | ref
26 | ) => {
27 | const button = (
28 |
48 | {leftIcon}
49 | {loading && (
50 |
56 |
64 |
69 |
70 | )}
71 |
72 | {loading ? loadingText : children}
73 |
74 | {rightIcon}
75 |
76 | )
77 |
78 | if (tooltip) {
79 | return {button}
80 | }
81 |
82 | return button
83 | }
84 | )
85 |
86 | export default PrimaryButton
87 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/shared/button.tsx:
--------------------------------------------------------------------------------
1 | import type { ButtonProps } from '../types'
2 | import clsx from 'clsx'
3 | import React from 'react'
4 |
5 | const Button = React.forwardRef(
6 | ({ children, ...props }, ref) => {
7 | return (
8 |
26 | {props.leftIcon}
27 | {props.loading && (
28 |
34 |
42 |
47 |
48 | )}
49 | {props.loading ? props.loadingText : children}
50 | {props.rightIcon}
51 |
52 | )
53 | }
54 | )
55 |
56 | Button.displayName = 'Button'
57 | export default Button
58 |
--------------------------------------------------------------------------------
/packages/ui/src/components/buttons/types.ts:
--------------------------------------------------------------------------------
1 | import type { MouseEventHandler, ReactNode } from 'react'
2 |
3 | export enum ButtonSize {
4 | LG,
5 | MD,
6 | sm,
7 | XS,
8 | }
9 |
10 | export interface ButtonProps {
11 | ariaLabel?: string
12 | bg?: string
13 | borderRadius?: string
14 | children?: ReactNode | string
15 | className?: string
16 | disabled?: boolean
17 | loading?: boolean
18 | loadingText?: string
19 | onClick?: MouseEventHandler
20 | onMouseDown?: MouseEventHandler
21 | padding?: string
22 | leftIcon?: ReactNode
23 | rightIcon?: ReactNode
24 | shadow?: string
25 | size?: ButtonSize
26 | textColor?: string
27 | textSize?: string
28 | tooltip?: string
29 | type?: 'button' | 'submit' | 'reset'
30 | }
31 |
--------------------------------------------------------------------------------
/packages/ui/src/components/checkbox.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
3 | import { CheckIcon } from '@radix-ui/react-icons'
4 | import * as LabelPrimitive from '@radix-ui/react-label'
5 | import clsx from 'clsx'
6 |
7 | const CheckboxRoot = CheckboxPrimitive.Root
8 | const CheckboxIndicator = CheckboxPrimitive.Indicator
9 | const Label = LabelPrimitive.Label
10 |
11 | interface Props {
12 | checked?: boolean
13 | defaultChecked?: boolean
14 | disabled?: boolean
15 | label: string | ReactNode
16 | name: string
17 | onCheckedChange?: (checked: boolean) => void
18 | required?: boolean
19 | }
20 |
21 | const Checkbox: FC = ({
22 | checked,
23 | defaultChecked = false,
24 | disabled = false,
25 | label,
26 | name,
27 | onCheckedChange,
28 | required = false,
29 | }) => {
30 | return (
31 |
32 |
47 |
48 |
58 |
59 |
60 |
61 |
65 | {label}
66 |
67 |
68 | )
69 | }
70 |
71 | export default Checkbox
72 |
--------------------------------------------------------------------------------
/packages/ui/src/components/collapsible.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import { useState } from 'react'
3 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'
4 | import { Cross2Icon, RowSpacingIcon } from '@radix-ui/react-icons'
5 | import clsx from 'clsx'
6 | import { IconButton } from './buttons'
7 |
8 | type CollapsedItem = ReactNode | string
9 |
10 | interface CollapsibeProps {
11 | first: ReactNode | string
12 | items?: CollapsedItem[]
13 | title: ReactNode | string
14 | trigger: ReactNode | string
15 | }
16 |
17 | const Collapsibe: FC = ({ first, items, title, trigger }) => {
18 | const [open, setOpen] = useState(false)
19 | return (
20 |
25 |
26 |
27 | {title}
28 |
29 |
30 | {typeof trigger !== 'string' ? (
31 | trigger
32 | ) : (
33 | : }
39 | />
40 | )}
41 |
42 |
43 |
44 |
45 | {first}
46 |
47 |
48 |
49 | {items?.map((item, index) => (
50 |
54 | {item}
55 |
56 | ))}
57 |
58 |
59 | )
60 | }
61 |
62 | export default Collapsibe
63 |
--------------------------------------------------------------------------------
/packages/ui/src/components/copy-to-clipboard.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from 'react'
2 | import copy from 'copy-to-clipboard'
3 | import { CopyIcon } from '@radix-ui/react-icons'
4 | import { IconButton } from './buttons'
5 | import Tooltip from './tooltip'
6 |
7 | interface Props {
8 | text: string
9 | }
10 |
11 | const CopyToClipboard: FC = ({ text }) => {
12 | return (
13 |
14 |
17 | copy(text, {
18 | format: 'text/plain',
19 | })
20 | }
21 | icon={ }
22 | type='button'
23 | />
24 |
25 | )
26 | }
27 |
28 | export default CopyToClipboard
29 |
--------------------------------------------------------------------------------
/packages/ui/src/components/date-picker.tsx:
--------------------------------------------------------------------------------
1 | import * as PopoverPrimitive from '@radix-ui/react-popover'
2 | import Calendar from '../internal/calendar'
3 | import { Dispatch, ReactNode, SetStateAction, useState } from 'react'
4 | import clsx from 'clsx'
5 |
6 | interface DatePickerProps {
7 | onDateChange?: Dispatch>
8 | trigger: ReactNode
9 | }
10 |
11 | export default function DatePicker({ onDateChange, trigger }: DatePickerProps) {
12 | const [date, setDate] = useState(new Date())
13 |
14 | const dateChangeHandler = (day: Date | undefined) => {
15 | onDateChange?.(day)
16 | setDate(day)
17 | }
18 |
19 | return (
20 |
21 |
22 |
23 | {trigger}
24 |
25 |
26 |
34 |
39 |
40 |
41 |
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/packages/ui/src/components/dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as DialogPrimitive from '@radix-ui/react-dialog'
2 | import { Cross1Icon } from '@radix-ui/react-icons'
3 | import clsx from 'clsx'
4 | import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
5 |
6 | interface Props {
7 | action?: ReactNode
8 | cancel?: ReactNode
9 | children: ReactNode
10 | description?: ReactNode | string
11 | trigger?: ReactNode
12 | title: ReactNode | string
13 | open?: boolean
14 | onOpenChange?: Dispatch>
15 | }
16 |
17 | const Dialog: FC = ({
18 | action,
19 | cancel,
20 | children,
21 | description,
22 | title,
23 | trigger = null,
24 | open,
25 | onOpenChange,
26 | }) => {
27 | return (
28 |
29 | {trigger ? (
30 |
31 | {trigger}
32 |
33 | ) : null}
34 |
35 |
39 |
48 | {title ? (
49 |
50 | {title}
51 |
52 | ) : null}
53 | {description ? (
54 |
55 | {description}
56 |
57 | ) : null}
58 |
59 | {children}
60 |
61 | {action || cancel ? (
62 |
63 | {cancel && (
64 |
65 | {cancel}
66 |
67 | )}
68 | {action && (
69 |
70 | {action}
71 |
72 | )}
73 |
74 | ) : null}
75 |
76 |
82 |
83 |
84 |
85 |
86 |
87 | )
88 | }
89 |
90 | export default Dialog
91 |
--------------------------------------------------------------------------------
/packages/ui/src/components/hover-card.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
3 | import clsx from 'clsx'
4 | import { Button } from './buttons'
5 |
6 | interface HoverCardProps {
7 | children: ReactNode
8 | defaultOpen?: boolean
9 | open?: boolean
10 | onOpenChange?: (open: boolean) => void
11 | trigger: ReactNode | string
12 | }
13 |
14 | const HoverCard: FC = ({
15 | children,
16 | defaultOpen,
17 | open,
18 | onOpenChange,
19 | trigger,
20 | }) => {
21 | return (
22 |
27 |
28 | {typeof trigger !== 'string' ? (
29 | trigger
30 | ) : (
31 | {trigger}
32 | )}
33 |
34 |
45 |
46 | {children}
47 |
48 |
49 | )
50 | }
51 |
52 | export default HoverCard
53 |
--------------------------------------------------------------------------------
/packages/ui/src/components/label.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from 'react'
2 | import * as LabelPrimitive from '@radix-ui/react-label'
3 |
4 | interface LabelProps {
5 | htmlFor: string
6 | label: string
7 | }
8 |
9 | const Label: FC = ({ htmlFor, label }) => {
10 | return (
11 |
15 | {label}
16 |
17 | )
18 | }
19 |
20 | export default Label
21 |
--------------------------------------------------------------------------------
/packages/ui/src/components/nav.tsx:
--------------------------------------------------------------------------------
1 | import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'
2 | import clsx from 'clsx'
3 | import type { FC, ReactNode } from 'react'
4 | import { useEffect, useState } from 'react'
5 |
6 | interface NavItem {
7 | content?: string | ReactNode
8 | href?: string
9 | label: string | ReactNode
10 | id: string
11 | }
12 |
13 | interface Props {
14 | items: NavItem[]
15 | type?: 'row' | 'column'
16 | Link?: React.ElementType
17 | }
18 |
19 | const Nav: FC = ({ items, type = 'row', Link }) => {
20 | const [pathname, setPathname] = useState('')
21 |
22 | useEffect(() => {
23 | setPathname(window?.location?.pathname)
24 | }, [])
25 |
26 | return (
27 |
28 |
35 | {items.map(({ content, href, label, id }) => {
36 | if (content) {
37 | return (
38 |
41 |
50 | {label}
51 |
52 |
62 | {content}
63 |
64 |
65 | )
66 | }
67 |
68 | return (
69 |
73 | {Link ? (
74 |
87 | {label}
88 |
89 | ) : (
90 |
103 | {label}
104 |
105 | )}
106 |
107 | )
108 | })}
109 |
110 |
119 |
120 |
121 |
122 |
123 |
132 |
142 |
143 |
144 | )
145 | }
146 |
147 | export default Nav
148 |
--------------------------------------------------------------------------------
/packages/ui/src/components/popover.tsx:
--------------------------------------------------------------------------------
1 | import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
2 | import * as PopoverPrimitive from '@radix-ui/react-popover'
3 | import clsx from 'clsx'
4 | import { Cross1Icon } from '@radix-ui/react-icons'
5 |
6 | interface PopoverProps {
7 | align?: 'start' | 'end' | 'center'
8 | close?: boolean
9 | children: string | ReactNode
10 | side?: 'top' | 'right' | 'bottom' | 'left'
11 | sideOffset?: number
12 | title?: string | ReactNode
13 | trigger: ReactNode
14 | open?: boolean
15 | onOpenChange?: Dispatch>
16 | }
17 |
18 | const Popover: FC = ({
19 | align = 'center',
20 | close = true,
21 | children,
22 | side = 'bottom',
23 | sideOffset = 0,
24 | title,
25 | trigger,
26 | open,
27 | onOpenChange,
28 | }) => {
29 | return (
30 |
31 |
32 | {trigger ? (
33 |
34 | {trigger}
35 |
36 | ) : null}
37 |
38 |
49 |
50 | {title ? (
51 |
52 | {title}
53 |
54 | ) : null}
55 | {children}
56 | {close && (
57 |
63 |
64 |
65 | )}
66 |
67 |
68 |
69 |
70 | )
71 | }
72 |
73 | export default Popover
74 |
--------------------------------------------------------------------------------
/packages/ui/src/components/progress.tsx:
--------------------------------------------------------------------------------
1 | import * as ProgressPrimitive from '@radix-ui/react-progress'
2 | import { FC } from 'react'
3 |
4 | interface ProgressProps {
5 | percent: number
6 | }
7 |
8 | const Progress: FC = ({ percent }) => {
9 | return (
10 |
14 |
18 |
19 | )
20 | }
21 |
22 | export default Progress
23 |
--------------------------------------------------------------------------------
/packages/ui/src/components/radio-group.tsx:
--------------------------------------------------------------------------------
1 | import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
2 | import type { FC, ReactNode } from 'react'
3 | import clsx from 'clsx'
4 |
5 | type RadioOption = {
6 | value: string
7 | id: string
8 | label: string | ReactNode
9 | }
10 |
11 | type RadioGroupProps = {
12 | className?: string
13 | defaultValue: string
14 | options: RadioOption[]
15 | name: string
16 | onChange?: (value: string) => void
17 | }
18 |
19 | // TODO: Clicking on label should select the radio
20 | const RadioGroup: FC = ({
21 | className,
22 | defaultValue,
23 | options,
24 | name,
25 | onChange,
26 | }) => {
27 | return (
28 |
34 | {options.map((option, index) => (
35 |
39 |
49 |
50 |
51 |
52 | {option.label}
53 |
54 |
55 | ))}
56 |
57 | )
58 | }
59 |
60 | export default RadioGroup
61 |
--------------------------------------------------------------------------------
/packages/ui/src/components/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
3 | import clsx from 'clsx'
4 |
5 | interface ScrollAreaProps {
6 | className?: string
7 | children: ReactNode
8 | title?: ReactNode | string
9 | }
10 |
11 | const ScrollArea: FC = ({ className, children, title }) => (
12 |
15 |
16 |
17 | {title ? (
18 |
19 | {title}
20 |
21 | ) : null}
22 |
{children}
23 |
24 |
25 |
32 |
39 |
40 |
41 | )
42 |
43 | export default ScrollArea
44 |
--------------------------------------------------------------------------------
/packages/ui/src/components/select.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | CheckIcon,
3 | ChevronDownIcon,
4 | ChevronUpIcon,
5 | } from '@radix-ui/react-icons'
6 | import * as SelectPrimitive from '@radix-ui/react-select'
7 | import clsx from 'clsx'
8 | import { Dispatch, SetStateAction, useState } from 'react'
9 | import type { FC, ReactNode } from 'react'
10 | import { Button } from './buttons'
11 |
12 | interface SelectItem {
13 | disabled?: boolean
14 | label: string | ReactNode
15 | value: string
16 | }
17 |
18 | // TODO: Add default label, onchange
19 | interface Props {
20 | defaultOpen?: boolean
21 | defaultValue?: string
22 | items: SelectItem[]
23 | name: string
24 | open?: boolean
25 | onOpenChange?: Dispatch>
26 | onValueChange?: (value: string) => void
27 | value?: string
28 | }
29 |
30 | const Select: FC = ({
31 | defaultOpen = false,
32 | defaultValue,
33 | items,
34 | name,
35 | open,
36 | onOpenChange,
37 | onValueChange,
38 | value,
39 | }) => {
40 | const defaultItem = items.find((item) =>
41 | defaultValue ? item.value === defaultValue : item.value === value
42 | )
43 | const [selected, setSelected] = useState(defaultItem || items[0])
44 |
45 | const handleSelect = (value: string) => {
46 | const item = items.find((item) => item.value === value)
47 | if (item) {
48 | setSelected(item)
49 | onValueChange?.(item.value)
50 | }
51 | }
52 |
53 | return (
54 |
63 |
64 |
65 |
66 |
67 | {selected.label}
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | {items.map((f, i) => (
83 |
94 |
95 | {f.label}
96 |
97 |
98 |
99 |
100 |
101 | ))}
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | )
111 | }
112 |
113 | export default Select
114 |
--------------------------------------------------------------------------------
/packages/ui/src/components/separator.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from 'react'
2 | import * as SeparatorPrimitive from '@radix-ui/react-separator'
3 | import clsx from 'clsx'
4 |
5 | interface SeparatorProps {
6 | decorative?: boolean
7 | orientation: 'horizontal' | 'vertical'
8 | }
9 |
10 | const Separator: FC = ({ decorative = true, orientation }) => {
11 | return (
12 |
21 | )
22 | }
23 |
24 | export default Separator
25 |
--------------------------------------------------------------------------------
/packages/ui/src/components/slider.tsx:
--------------------------------------------------------------------------------
1 | import type { FC } from 'react'
2 | import * as SliderPrimitive from '@radix-ui/react-slider'
3 | import clsx from 'clsx'
4 |
5 | interface SliderProps {
6 | ariaLabel: string
7 | defaultValue: number[]
8 | min?: number
9 | max: number
10 | name?: string
11 | onValueChange?: (value: number[]) => void
12 | onValueCommit?: (value: number[]) => void
13 | step: number
14 | value?: number[]
15 | }
16 |
17 | // TODO: update styles
18 | const Slider: FC = ({
19 | ariaLabel,
20 | defaultValue,
21 | min = 0,
22 | max,
23 | name,
24 | onValueChange,
25 | onValueCommit,
26 | step,
27 | value,
28 | }) => {
29 | return (
30 |
42 |
43 |
44 |
45 | {defaultValue && defaultValue.length > 0
46 | ? defaultValue.map((_, index) => (
47 |
54 | ))
55 | : value?.map((_, index) => (
56 |
63 | ))}
64 |
65 | )
66 | }
67 |
68 | export default Slider
69 |
--------------------------------------------------------------------------------
/packages/ui/src/components/switch.tsx:
--------------------------------------------------------------------------------
1 | import * as SwitchPrimitive from '@radix-ui/react-switch'
2 | import clsx from 'clsx'
3 | import type { FC, ReactNode } from 'react'
4 |
5 | const SwitchRoot = SwitchPrimitive.Root
6 | const SwitchThumb = SwitchPrimitive.Thumb
7 |
8 | interface Props {
9 | defaultChecked?: boolean
10 | icon?: ReactNode
11 | onCheckedChange?: (checked: boolean) => void
12 | name: string
13 | }
14 |
15 | const Switch: FC = ({ defaultChecked, icon, onCheckedChange, name }) => {
16 | return (
17 |
29 |
37 | {icon}
38 |
39 |
40 | )
41 | }
42 |
43 | export default Switch
44 |
--------------------------------------------------------------------------------
/packages/ui/src/components/tabs.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react'
2 | import * as TabsPrimitive from '@radix-ui/react-tabs'
3 | import clsx from 'clsx'
4 | import React from 'react'
5 |
6 | interface TabContent {
7 | content: string | ReactNode
8 | id: string
9 | title: string | ReactNode
10 | }
11 |
12 | // TODO: Add support for onchange, orientation, etc.
13 | // TODO: Update styles so they're consistent with the rest of the components
14 | interface TabsProps {
15 | defaultValue: string
16 | type: 'row' | 'column'
17 | }
18 |
19 | interface TabsData {
20 | tabs: TabContent[]
21 | type: 'row' | 'column'
22 | }
23 |
24 | const Tabs = TabsPrimitive.Root
25 |
26 | const TabsList = React.forwardRef(
27 | ({ className, ...props }, ref) => (
28 |
36 | {props.tabs.map(
37 | ({ title, id }: { title: string | ReactNode; id: string }) => (
38 |
54 |
55 | {title}
56 |
57 |
58 | )
59 | )}
60 |
61 | )
62 | )
63 | TabsList.displayName = TabsPrimitive.List.displayName
64 |
65 | const TabsContent = React.forwardRef(
66 | ({ className, ...props }, ref) => (
67 | <>
68 | {props.tabs.map(
69 | ({
70 | content,
71 | id,
72 | }: {
73 | content: string | ReactNode
74 | id: string
75 | }) => (
76 |
86 | {content}
87 |
88 | )
89 | )}
90 | >
91 | )
92 | )
93 | TabsContent.displayName = TabsPrimitive.Content.displayName
94 |
95 | export { Tabs, TabsContent, TabsList }
96 |
--------------------------------------------------------------------------------
/packages/ui/src/components/toast.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import { useEffect, useRef, useState } from 'react'
3 | import * as ToastPrimitive from '@radix-ui/react-toast'
4 | import clsx from 'clsx'
5 | import { Button } from './buttons'
6 |
7 | interface ToastProps {
8 | action: ReactNode | string
9 | actionAltText: string
10 | defaultOpen?: boolean
11 | description?: ReactNode | string
12 | dismiss?: ReactNode | string
13 | duration?: number
14 | open?: boolean
15 | onOpenChange?: (open: boolean) => void
16 | title?: ReactNode | string
17 | trigger?: ReactNode | string
18 | }
19 |
20 | // TODO: Fix description and action styles
21 | // TODO: Add support for triggering toast from a function call
22 | // TODO: Add examples for triggering the toast from a button click and from a function call
23 |
24 | const Toast: FC = ({
25 | action,
26 | actionAltText,
27 | defaultOpen = false,
28 | description,
29 | dismiss,
30 | duration = 3000,
31 | open,
32 | onOpenChange,
33 | title,
34 | trigger,
35 | }) => {
36 | const [isToastOpen, setIsToastOpen] = useState(
37 | defaultOpen || false
38 | )
39 | const timerRef = useRef(0)
40 |
41 | useEffect(() => {
42 | if (!trigger) {
43 | setIsToastOpen(false)
44 | onOpenChange?.(false)
45 | timerRef.current = window.setTimeout(() => {
46 | setIsToastOpen(true)
47 | onOpenChange?.(true)
48 | }, 100)
49 | }
50 |
51 | return () => clearTimeout(timerRef.current)
52 | }, [trigger, duration, open])
53 |
54 | return (
55 |
56 | {trigger && (
57 | {
59 | setIsToastOpen(false)
60 | onOpenChange?.(false)
61 | window.clearTimeout(timerRef.current)
62 | timerRef.current = window.setTimeout(() => {
63 | setIsToastOpen(true)
64 | onOpenChange?.(true)
65 | }, 100)
66 | }}
67 | >
68 | {trigger}
69 |
70 | )}
71 |
87 |
88 |
89 |
90 |
91 | {title}
92 |
93 |
94 | {description}
95 |
96 |
97 |
98 | {action && dismiss && (
99 |
100 |
108 |
113 | {action}
114 |
115 |
116 |
125 |
129 | {dismiss}
130 |
131 |
132 |
133 | )}
134 | {action && !dismiss && (
135 |
136 |
146 | {action}
147 |
148 |
149 | )}
150 |
151 |
152 |
153 |
154 | )
155 | }
156 |
157 | export default Toast
158 |
--------------------------------------------------------------------------------
/packages/ui/src/components/toggle-group.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactElement } from 'react'
2 | import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group'
3 | import clsx from 'clsx'
4 |
5 | interface ToggleItem {
6 | value: string
7 | label: string
8 | icon: ReactElement
9 | }
10 |
11 | interface ToggleGroupProps {
12 | defaultValue?: string | string[]
13 | items: ToggleItem[]
14 | onValueChange?: (value: string) => void
15 | orientation?: 'vertical' | 'horizontal'
16 | style?: 'stitched' | 'pills'
17 | type: 'single' | 'multiple'
18 | }
19 |
20 | const ToggleGroup: FC = ({
21 | defaultValue,
22 | items,
23 | onValueChange,
24 | orientation = 'horizontal',
25 | style = 'stitched',
26 | type,
27 | }) => {
28 | return (
29 | // @ts-ignore
30 |
49 | {items.map(({ value, label, icon }, i) => (
50 |
67 | {icon}
68 |
69 | ))}
70 |
71 | )
72 | }
73 |
74 | export default ToggleGroup
75 |
--------------------------------------------------------------------------------
/packages/ui/src/components/toggle.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as TogglePrimitive from '@radix-ui/react-toggle'
3 | import Button from './buttons/shared/button'
4 |
5 | interface ToggleProps {
6 | ariaLabel: string
7 | children: ReactNode
8 | defaultPressed?: boolean
9 | pressed?: boolean
10 | onPressedChange?: (pressed: boolean) => void
11 | }
12 |
13 | // TODO: update styles after changing shared button styles
14 | const Toggle: FC = ({
15 | ariaLabel,
16 | children,
17 | defaultPressed = false,
18 | pressed,
19 | onPressedChange,
20 | }) => (
21 |
27 | {children}
28 |
29 | )
30 |
31 | export default Toggle
32 |
--------------------------------------------------------------------------------
/packages/ui/src/components/toolbar.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as ToolbarPrimitive from '@radix-ui/react-toolbar'
3 | import clsx from 'clsx'
4 | import { PrimaryButton } from './buttons'
5 |
6 | interface ToggleGroupItem {
7 | id: string
8 | icon: ReactNode
9 | onSelect: () => void
10 | }
11 |
12 | interface ToolbarItem {
13 | buttonOnSelect?: () => void
14 | buttonText?: ReactNode | string
15 | groupItems?: ToggleGroupItem[]
16 | groupType?: 'single' | 'multiple'
17 | link?: string
18 | linkText?: ReactNode | string
19 | type: 'toggle-group' | 'separator' | 'link' | 'button'
20 | }
21 |
22 | interface ToolbarProps {
23 | className?: string
24 | items: ToolbarItem[]
25 | }
26 |
27 | const Toolbar: FC = ({ className, items }) => {
28 | return (
29 |
32 | {items.map(
33 | (
34 | {
35 | buttonOnSelect,
36 | buttonText,
37 | groupItems,
38 | groupType = 'multiple',
39 | link,
40 | linkText,
41 | type,
42 | },
43 | index
44 | ) => {
45 | if (type === 'link') {
46 | return (
47 |
57 | {linkText}
58 |
59 | )
60 | } else if (type === 'button') {
61 | return (
62 |
63 |
67 | {buttonText}
68 |
69 |
70 | )
71 | } else if (type === 'separator') {
72 | return (
73 |
77 | )
78 | } else {
79 | return (
80 |
85 | {groupItems?.map(
86 | ({ id, icon, onSelect }, index) => (
87 |
92 |
102 | {icon}
103 |
104 |
105 | )
106 | )}
107 |
108 | )
109 | }
110 | }
111 | )}
112 |
113 | )
114 | }
115 |
116 | export default Toolbar
117 |
--------------------------------------------------------------------------------
/packages/ui/src/components/tooltip.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react'
2 | import * as TooltipPrimitive from '@radix-ui/react-tooltip'
3 | import clsx from 'clsx'
4 |
5 | interface Props {
6 | align?: 'start' | 'center' | 'end'
7 | defaultOpen?: boolean
8 | content: string | ReactNode
9 | children: ReactNode
10 | open?: boolean
11 | onOpenChange?: (open: boolean) => void
12 | side?: 'top' | 'right' | 'bottom' | 'left'
13 | }
14 |
15 | const Tooltip: FC = ({
16 | align = 'center',
17 | defaultOpen,
18 | content,
19 | children,
20 | open,
21 | onOpenChange,
22 | side = 'top',
23 | }) => {
24 | return (
25 |
26 |
31 | {children}
32 |
33 |
47 |
48 |
49 | {content}
50 |
51 |
52 |
53 |
54 |
55 | )
56 | }
57 |
58 | export default Tooltip
59 |
--------------------------------------------------------------------------------
/packages/ui/src/internal/calendar.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentProps } from 'react'
2 | import { DayPicker } from 'react-day-picker'
3 | import clsx from 'clsx'
4 |
5 | import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons'
6 |
7 | export type CalendarProps = ComponentProps
8 |
9 | export default function Calendar({
10 | className,
11 | classNames,
12 | showOutsideDays = true,
13 | ...props
14 | }: CalendarProps) {
15 | return (
16 | (
56 |
57 | ),
58 | IconRight: ({ ...props }) => (
59 |
60 | ),
61 | }}
62 | {...props}
63 | />
64 | )
65 | }
66 | Calendar.displayName = 'Calendar'
67 |
68 | export { Calendar }
69 |
--------------------------------------------------------------------------------
/packages/ui/styles/main.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | /* color palette */
7 | --primary: 0 0% 99%;
8 | --primary-subtle: 0 0% 97.5%;
9 |
10 | --ui: 0 0% 94.6%;
11 | --ui-hover: 0 0% 92%;
12 | --ui-states: 0 0% 89.5%;
13 |
14 | --subtle: 0 0% 86.8%;
15 | --subtle-int: 0 0% 83%;
16 | --subtle-int-states: 0 0% 73.2%;
17 |
18 | --brand: 155 61% 44%;
19 | --brand-states: 156 63.1% 39.7%;
20 |
21 | --foreground: 0 0% 12.5%;
22 | --foreground-subtle: 0 0% 39.3%;
23 | --foreground-btn: 0 0% 100%;
24 |
25 | /* semantic colors */
26 | --danger: 358 75% 59%;
27 | --danger-states: 358 67.4% 54.6%;
28 |
29 | --success: 151 55% 41.5%;
30 | --success-states: 152 57.5% 37.6%;
31 |
32 | /* border radius and shadows */
33 | --ui-border-radius: 0.5rem;
34 |
35 | /* font families */
36 | --font-sans: 'Inter, sans-serif';
37 | --font-serif: 'Merriweather, serif';
38 | --font-mono: 'monospace';
39 |
40 | /* spacing - paddings and margins */
41 | --ui-p: 1rem;
42 | --ui-p-btn: 0.5rem 1rem;
43 | --ui-p-select: 1rem 0.5rem;
44 | --ui-p-icon-btn: 0.75rem;
45 | }
46 |
47 | .dark {
48 | /* color palette */
49 | --primary: 0 0% 9.5%;
50 | --primary-subtle: 0 0% 10.5%;
51 |
52 | --ui: 0 0% 15.8%;
53 | --ui-hover: 0 0% 18.9%;
54 | --ui-states: 0 0% 21.7%;
55 |
56 | --subtle: 0 0% 24.7%;
57 | --subtle-int: 0 0% 29.1%;
58 | --subtle-int-states: 0 0% 37.5%;
59 |
60 | /* brand colors will apply for both modes */
61 |
62 | --foreground: 0 0% 93.5%;
63 | --foreground-subtle: 0 0% 69.5%;
64 |
65 | /* semantic colors */
66 | --danger: 358 75% 59%;
67 | --danger-states: 359 84.8% 67.6%;
68 |
69 | --success: 151 55% 41.5%;
70 | --success-states: 151 55.2% 46.7%;
71 | }
72 |
--------------------------------------------------------------------------------
/packages/ui/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | const tailwindRadix = require('tailwindcss-radix')
3 |
4 | module.exports = {
5 | content: ['./src/**/*.{js,jsx,ts,tsx}'],
6 | darkMode: 'class',
7 | prefix: 'cui-',
8 | theme: {
9 | extend: {
10 | animation: {
11 | 'enter-from-right': 'enter-from-right 0.25s ease',
12 | 'enter-from-left': 'enter-from-left 0.25s ease',
13 | 'exit-to-right': 'exit-to-right 0.25s ease',
14 | 'exit-to-left': 'exit-to-left 0.25s ease',
15 | 'toast-hide': 'toast-hide 100ms ease-in forwards',
16 | 'toast-slide-in-right':
17 | 'toast-slide-in-right 150ms cubic-bezier(0.16, 1, 0.3, 1)',
18 | 'toast-slide-in-bottom':
19 | 'toast-slide-in-bottom 150ms cubic-bezier(0.16, 1, 0.3, 1)',
20 | 'toast-swipe-out-x':
21 | 'toast-swipe-out-x 100ms ease-out forwards',
22 | 'toast-swipe-out-y':
23 | 'toast-swipe-out-y 100ms ease-out forwards',
24 | },
25 | borderRadius: {
26 | DEFAULT: 'var(--ui-border-radius)',
27 | },
28 | colors: {
29 | primary: {
30 | DEFAULT: 'hsl(var(--primary) / )',
31 | subtle: 'hsl(var(--primary-subtle) / )',
32 | },
33 |
34 | ui: {
35 | DEFAULT: 'hsl(var(--ui) / )',
36 | hover: 'hsl(var(--ui-hover) / )',
37 | states: 'hsl(var(--ui-states) / )',
38 | },
39 |
40 | subtle: {
41 | DEFAULT: 'hsl(var(--subtle) / )',
42 | int: 'hsl(var(--subtle-int) / )',
43 | 'int-states':
44 | 'hsl(var(--subtle-int-states) / )',
45 | },
46 |
47 | brand: {
48 | DEFAULT: 'hsl(var(--brand) / )',
49 | states: 'hsl(var(--brand-states) / )',
50 | },
51 |
52 | foreground: {
53 | DEFAULT: 'hsl(var(--foreground) / )',
54 | subtle: 'hsl(var(--foreground-subtle) / )',
55 | btn: 'hsl(var(--foreground-btn) / )',
56 | },
57 |
58 | danger: {
59 | DEFAULT: 'hsl(var(--danger) / )',
60 | states: 'hsl(var(--danger-states) / )',
61 | },
62 |
63 | success: {
64 | DEFAULT: 'hsl(var(--success) / )',
65 | states: 'hsl(var(--success-states) / )',
66 | },
67 | },
68 | fontFamily: {
69 | mono: 'var(--font-mono)',
70 | sans: 'var(--font-sans)',
71 | serif: 'var(--font-serif)',
72 | },
73 | keyframes: {
74 | 'enter-from-right': {
75 | '0%': { transform: 'translateX(200px)', opacity: 0 },
76 | '100%': { transform: 'translateX(0)', opacity: 1 },
77 | },
78 | 'enter-from-left': {
79 | '0%': { transform: 'translateX(-200px)', opacity: 0 },
80 | '100%': { transform: 'translateX(0)', opacity: 1 },
81 | },
82 | 'exit-to-right': {
83 | '0%': { transform: 'translateX(0)', opacity: 1 },
84 | '100%': { transform: 'translateX(200px)', opacity: 0 },
85 | },
86 | 'exit-to-left': {
87 | '0%': { transform: 'translateX(0)', opacity: 1 },
88 | '100%': { transform: 'translateX(-200px)', opacity: 0 },
89 | },
90 | // toast
91 | 'toast-hide': {
92 | '0%': { opacity: 1 },
93 | '100%': { opacity: 0 },
94 | },
95 | 'toast-slide-in-right': {
96 | '0%': { transform: `translateX(calc(100% + 1rem))` },
97 | '100%': { transform: 'translateX(0)' },
98 | },
99 | 'toast-slide-in-bottom': {
100 | '0%': { transform: `translateY(calc(100% + 1rem))` },
101 | '100%': { transform: 'translateY(0)' },
102 | },
103 | 'toast-swipe-out-x': {
104 | '0%': {
105 | transform: 'translateX(var(--radix-toast-swipe-end-x))',
106 | },
107 | '100%': {
108 | transform: `translateX(calc(100% + 1rem))`,
109 | },
110 | },
111 | 'toast-swipe-out-y': {
112 | '0%': {
113 | transform: 'translateY(var(--radix-toast-swipe-end-y))',
114 | },
115 | '100%': {
116 | transform: `translateY(calc(100% + 1rem))`,
117 | },
118 | },
119 | },
120 | padding: {
121 | DEFAULT: 'var(--ui-p)',
122 | btn: 'var(--ui-p-btn)',
123 | select: 'var(--ui-p-select)',
124 | 'icon-btn': 'var(--ui-p-icon-btn)',
125 | },
126 | },
127 | },
128 | plugins: [tailwindRadix()],
129 | }
130 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@catalystui/tsconfig/ui.json",
3 | "include": ["."],
4 | "exclude": ["dist", "build", "node_modules"]
5 | }
6 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'docs'
3 | - 'packages/*'
4 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "pipeline": {
4 | "build": {
5 | "dependsOn": ["^build"],
6 | "outputs": ["dist/**", ".next/**"]
7 | },
8 | "lint": {
9 | "outputs": []
10 | },
11 | "dev": {
12 | "cache": false
13 | },
14 | "start": {
15 | "outputs": []
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------