diff --git a/.changeset/config.json b/.changeset/config.json index a91a85d..5eb625e 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,12 +1,11 @@ { - "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json", + "$schema": "https://unpkg.com/@changesets/config@3/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [], "linked": [], "access": "public", + "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": [ - "@repo/docs" - ] -} \ No newline at end of file + "ignore": ["storybook", "docs"] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8944503 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - run: pnpm lint + + typecheck: + name: Typecheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - run: pnpm turbo typecheck + + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - run: pnpm test + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, typecheck, test] + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - run: pnpm build diff --git a/.github/workflows/publish-datum-ui.yml b/.github/workflows/publish-datum-ui.yml index a1946b1..1928135 100644 --- a/.github/workflows/publish-datum-ui.yml +++ b/.github/workflows/publish-datum-ui.yml @@ -13,8 +13,8 @@ jobs: publish-datum-ui: uses: datum-cloud/actions/.github/workflows/publish-npm-package.yaml@main permissions: - contents: write # needed to push the version bump commit and tag - id-token: write # needed for npm trusted publishing (OIDC) + contents: write + id-token: write with: package-name: "@datum-cloud/datum-ui" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c8bbb4..3333c7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,38 +5,34 @@ on: branches: - main -concurrency: ${{ github.workflow }}-${{ github.ref }} +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: release: name: Release runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: - - name: Checkout Repo - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Setup Node.js 24.x - uses: actions/setup-node@v4 + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 with: node-version: 24 cache: pnpm - - name: Install Dependencies - run: | - corepack enable - pnpm install --frozen-lockfile + - run: pnpm install --frozen-lockfile - name: Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 with: - # This expects you to have a script called release which does a build for your packages and calls changeset publish publish: pnpm release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Send a Slack notification if a publish happens - if: steps.changesets.outputs.published == 'true' - # You can do something when a publish happens. - run: my-slack-bot send-notification --message "A new version of ${GITHUB_REPOSITORY} was published!" diff --git a/.gitignore b/.gitignore index 69b9263..56175bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,13 @@ -.DS_Store -node_modules -.turbo -*.log -.next -dist -dist-ssr -*.local -.env -.cache -server/dist -public/dist +node_modules/ +dist/ storybook-static/ +.next/ +.turbo/ +coverage/ +*.tsbuildinfo +.env* +.source/ + +.claude/ +CLAUDE.MD +/docs/ \ No newline at end of file diff --git a/.npmrc b/.npmrc index 15e41aa..3e775ef 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1 @@ -auto-install-peers = true -public-hoist-pattern[]=*storybook* -engine-strict = true +auto-install-peers=true diff --git a/.nvmrc b/.nvmrc index 18c92ea..92f279e 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v24 \ No newline at end of file +v22 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 61a83af..1d3f801 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,60 @@ { + // TypeScript — use workspace version (not VS Code's bundled one) + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true, + + // ESLint — flat config support + "eslint.useFlatConfig": true, "eslint.workingDirectories": [ - { - "mode": "auto" - } + { "pattern": "apps/*" }, + { "pattern": "packages/*" } ], - "typescript.tsdk": "node_modules/typescript/lib", - "css.lint.unknownAtRules": "ignore", - "scss.lint.unknownAtRules": "ignore", - "less.lint.unknownAtRules": "ignore" + + // Formatting — let ESLint handle it, disable built-in formatters + "editor.formatOnSave": true, + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + + // Tailwind CSS v4 + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ], + "tailwindCSS.includeLanguages": { + "typescript": "javascript", + "typescriptreact": "javascript" + }, + + // File associations + "files.associations": { + "*.css": "tailwindcss" + }, + + // Search and file exclusions + "search.exclude": { + "**/node_modules": true, + "**/dist": true, + "**/.next": true, + "**/.turbo": true, + "**/storybook-static": true, + "**/coverage": true, + "**/.source": true + }, + "files.exclude": { + "**/.turbo": true + }, + + // Editor defaults for the project + "editor.tabSize": 2, + "editor.insertSpaces": true, + + // File nesting for cleaner explorer + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.patterns": { + "package.json": "pnpm-lock.yaml, pnpm-workspace.yaml, .nvmrc, turbo.json, .gitignore, .npmrc", + "tsconfig.json": "tsconfig.*.json", + "eslint.config.*": ".eslintignore" + } } diff --git a/README.md b/README.md index a97345a..57b3e8c 100644 --- a/README.md +++ b/README.md @@ -1,208 +1,100 @@ -# Turborepo Design System Starter +

+ -This is a community-maintained example. If you experience a problem, please submit a pull request with a fix. GitHub Issues will be closed. +

Datum UI

-This guide explains how to use a React design system starter powered by: +

+ Datum Cloud Design System & Component Library +

+

-- 🏎 [Turborepo](https://turborepo.dev) — High-performance build system for Monorepos -- 🚀 [React](https://reactjs.org/) — JavaScript library for user interfaces -- 🛠 [Tsup](https://github.com/egoist/tsup) — TypeScript bundler powered by esbuild -- 📖 [Storybook](https://storybook.js.org/) — UI component environment powered by Vite +--- -As well as a few others tools preconfigured: +## About -- [TypeScript](https://www.typescriptlang.org/) for static type checking -- [ESLint](https://eslint.org/) for code linting -- [Prettier](https://prettier.io) for code formatting -- [Changesets](https://github.com/changesets/changesets) for managing versioning and changelogs -- [GitHub Actions](https://github.com/changesets/action) for fully automated package publishing +Datum UI is Datum Cloud's design system and React component library. It provides themed, composable components built on [shadcn/ui](https://ui.shadcn.com) and [Radix UI](https://www.radix-ui.com) with a Figma-driven design token pipeline. -## Using this example +### Key Features -Run the following command: +- **50+ Components** — Buttons, forms, data tables, dialogs, navigation, and more +- **Compound Form System** — Built on Conform.js and Zod with validation, field arrays, and multi-step support +- **Design Token Pipeline** — Figma tokens → purpose tokens → theme classes +- **Dark Mode** — Built-in theme provider with system preference detection +- **TypeScript** — Fully typed with exported types for all components -```sh -npx create-turbo@latest -e design-system -``` - -### Useful Commands - -- `pnpm build` - Build all packages, including the Storybook site -- `pnpm dev` - Run all packages locally and preview with Storybook -- `pnpm lint` - Lint all packages -- `pnpm changeset` - Generate a changeset -- `pnpm clean` - Clean up all `node_modules` and `dist` folders (runs each package's clean script) - -## Turborepo - -[Turborepo](https://turborepo.dev) is a high-performance build system for JavaScript and TypeScript codebases. It was designed after the workflows used by massive software engineering organizations to ship code at scale. Turborepo abstracts the complex configuration needed for monorepos and provides fast, incremental builds with zero-configuration remote caching. - -Using Turborepo simplifies managing your design system monorepo, as you can have a single lint, build, test, and release process for all packages. [Learn more](https://vercel.com/blog/monorepos-are-changing-how-teams-build-software) about how monorepos improve your development workflow. - -## Apps & Packages - -This Turborepo includes the following packages and applications: - -- `apps/docs`: Component documentation site with Storybook -- `packages/ui`: Core React components -- `packages/typescript-config`: Shared `tsconfig.json`s used throughout the Turborepo -- `packages/eslint-config`: ESLint preset - -Each package and app is 100% [TypeScript](https://www.typescriptlang.org/). Workspaces enables us to "hoist" dependencies that are shared between packages to the root `package.json`. This means smaller `node_modules` folders and a better local dev experience. To install a dependency for the entire monorepo, use the `-w` workspaces flag with `pnpm add`. - -This example sets up your `.gitignore` to exclude all generated files, other folders like `node_modules` used to store your dependencies. - -### Compilation +### Built With -To make the ui library code work across all browsers, we need to compile the raw TypeScript and React code to plain JavaScript. We can accomplish this with `tsup`, which uses `esbuild` to greatly improve performance. +- **React 19** — Latest React with server component support +- **Tailwind CSS v4** — Utility-first CSS framework +- **Radix UI** — Accessible, unstyled primitives +- **shadcn/ui** — Component foundation layer +- **Conform.js + Zod** — Form state management and schema validation -Running `pnpm build` from the root of the Turborepo will run the `build` command defined in each package's `package.json` file. Turborepo runs each `build` in parallel and caches & hashes the output to speed up future builds. +--- -For `@acme/ui`, the `build` command is equivalent to the following: +## Monorepo Structure -```bash -tsup src/*.tsx --format esm,cjs --dts --external react ``` - -`tsup` compiles all of the components in the design system individually, into both ES Modules and CommonJS formats as well as their TypeScript types. The `package.json` for `@acme/ui` then instructs the consumer to select the correct format: - -```json:ui/package.json -{ - "name": "@acme/ui", - "version": "0.0.0", - "sideEffects": false, - "exports":{ - "./button": { - "types": "./src/button.tsx", - "import": "./dist/button.mjs", - "require": "./dist/button.js" - } - } -} +packages/ + datum-ui/ # Component library (@datum-cloud/datum-ui) + shadcn/ # shadcn/ui primitives (@repo/shadcn) + config/ # Shared config (TypeScript, Tailwind) +apps/ + docs/ # Fumadocs documentation site + storybook/ # Storybook component explorer ``` -Run `pnpm build` to confirm compilation is working correctly. You should see a folder `ui/dist` which contains the compiled output. - -```bash -ui -└── dist - ├── button.d.ts <-- Types - ├── button.js <-- CommonJS version - ├── button.mjs <-- ES Modules version - └── button.d.mts <-- ES Modules version with Types -``` +--- -## Components +## Quick Start -Each file inside of `ui/src` is a component inside our design system. For example: - -```tsx:ui/src/Button.tsx -import * as React from 'react'; - -export interface ButtonProps { - children: React.ReactNode; -} - -export function Button(props: ButtonProps) { - return ; -} +```bash +# Install dependencies +pnpm install -Button.displayName = 'Button'; -``` +# Start Storybook +pnpm --filter storybook dev -When adding a new file, ensure that its specifier is defined in `package.json` file: - -```json:ui/package.json -{ - "name": "@acme/ui", - "version": "0.0.0", - "sideEffects": false, - "exports":{ - "./button": { - "types": "./src/button.tsx", - "import": "./dist/button.mjs", - "require": "./dist/button.js" - } - // Add new component exports here - } -} +# Start documentation site +pnpm --filter docs dev ``` -## Storybook - -Storybook provides us with an interactive UI playground for our components. This allows us to preview our components in the browser and instantly see changes when developing locally. This example preconfigures Storybook to: - -- Use Vite to bundle stories instantly (in milliseconds) -- Automatically find any stories inside the `stories/` folder -- Support using module path aliases like `@acme/ui` for imports -- Write MDX for component documentation pages - -For example, here's the included Story for our `Button` component: +> **Note:** Apps auto-build `@datum-cloud/datum-ui` before starting via a `predev` script. -```js:apps/docs/stories/button.stories.mdx -import { Button } from '@acme/ui/button'; -import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks'; +--- - +## Usage -# Button +Install the package: -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisl eget consectetur tempor, nisl nunc egestas nisi, euismod aliquam nisl nunc euismod. - -## Props - - - -## Examples - - - - - - +```bash +npm install @datum-cloud/datum-ui ``` -This example includes a few helpful Storybook scripts: - -- `pnpm dev`: Starts Storybook in dev mode with hot reloading at `localhost:6006` -- `pnpm build`: Builds the Storybook UI and generates the static HTML files -- `pnpm preview-storybook`: Starts a local server to view the generated Storybook UI +Wrap your app with `DatumProvider` and start using components: -## Versioning & Publishing Packages +```tsx +import { DatumProvider, Button, Input } from "@datum-cloud/datum-ui"; -This example uses [Changesets](https://github.com/changesets/changesets) to manage versions, create changelogs, and publish to npm. It's preconfigured so you can start publishing packages immediately. - -You'll need to create an `NPM_TOKEN` and `GITHUB_TOKEN` and add it to your GitHub repository settings to enable access to npm. It's also worth installing the [Changesets bot](https://github.com/apps/changeset-bot) on your repository. - -### Generating the Changelog - -To generate your changelog, run `pnpm changeset` locally: - -1. **Which packages would you like to include?** – This shows which packages and changed and which have remained the same. By default, no packages are included. Press `space` to select the packages you want to include in the `changeset`. -1. **Which packages should have a major bump?** – Press `space` to select the packages you want to bump versions for. -1. If doing the first major version, confirm you want to release. -1. Write a summary for the changes. -1. Confirm the changeset looks as expected. -1. A new Markdown file will be created in the `changeset` folder with the summary and a list of the packages included. - -### Releasing - -When you push your code to GitHub, the [GitHub Action](https://github.com/changesets/action) will run the `release` script defined in the root `package.json`: - -```bash -turbo run build --filter=docs^... && changeset publish +function App() { + return ( + + + + + ); +} ``` -Turborepo runs the `build` script for all publishable packages (excluding docs) and publishes the packages to npm. By default, this example includes `acme` as the npm organization. To change this, do the following: +--- -- Rename folders in `packages/*` to replace `acme` with your desired scope -- Search and replace `acme` with your desired scope -- Re-run `pnpm install` +## Documentation -To publish packages to a private npm organization scope, **remove** the following from each of the `package.json`'s - -```diff -- "publishConfig": { -- "access": "public" -- }, -``` +- **[Documentation Site](apps/docs/)** — Component docs, guides, and live previews +- **[Storybook](apps/storybook/)** — Interactive component explorer diff --git a/apps/docs/.eslintrc.cjs b/apps/docs/.eslintrc.cjs deleted file mode 100644 index a38cd22..0000000 --- a/apps/docs/.eslintrc.cjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -module.exports = { - extends: ["@repo/eslint-config/storybook.js"], -}; diff --git a/apps/docs/.storybook/main.js b/apps/docs/.storybook/main.js deleted file mode 100644 index 5b157eb..0000000 --- a/apps/docs/.storybook/main.js +++ /dev/null @@ -1,37 +0,0 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import tailwindcss from "@tailwindcss/vite"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -const config = { - stories: ["../stories/*.stories.tsx", "../stories/**/*.stories.tsx"], - framework: { - name: "@storybook/react-vite", - options: {}, - }, - - async viteFinal(config) { - config.plugins = [...(config.plugins || []), tailwindcss()]; - return { - ...config, - resolve: { - ...config.resolve, - alias: [ - ...(Array.isArray(config.resolve?.alias) ? config.resolve.alias : []), - { - find: /^@datum-cloud\/datum-ui$/, - replacement: path.resolve(__dirname, "../../../packages/datum-ui/src/index.ts"), - }, - ], - }, - define: { "process.env": {} }, - }; - }, - - docs: { - autodocs: true, - }, -}; - -export default config; diff --git a/apps/docs/.storybook/preview.tsx b/apps/docs/.storybook/preview.tsx deleted file mode 100644 index ed9432a..0000000 --- a/apps/docs/.storybook/preview.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { Preview } from "@storybook/react"; -import { useEffect } from "react"; -import "../stories/styles.css"; - -const preview: Preview = { - decorators: [ - (Story) => { - useEffect(() => { - document.documentElement.classList.add("theme-alpha"); - return () => { - document.documentElement.classList.remove("theme-alpha"); - }; - }, []); - return ; - }, - ], - parameters: { - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - }, -}; - -export default preview; diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..beb4a4c --- /dev/null +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,45 @@ +import { DocsBody, DocsPage } from 'fumadocs-ui/page' +import { notFound } from 'next/navigation' + +import { source } from '@/lib/source' +import { getMDXComponents } from '@/mdx-components' + +interface PageProps { + params: Promise<{ slug?: string[] }> +} + +export default async function Page({ params }: PageProps) { + const { slug } = await params + const page = source.getPage(slug) + + if (!page) { + notFound() + } + + const MDX = page.data.body + + return ( + + + + + + ) +} + +export function generateStaticParams(): { slug: string[] }[] { + return source.generateParams() +} + +export async function generateMetadata({ params }: PageProps) { + const { slug } = await params + const page = source.getPage(slug) + if (!page) { + notFound() + } + + return { + title: page.data.title, + description: page.data.description, + } +} diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx new file mode 100644 index 0000000..ab9a42f --- /dev/null +++ b/apps/docs/app/docs/layout.tsx @@ -0,0 +1,13 @@ +import type { ReactNode } from 'react' + +import { DocsLayout } from 'fumadocs-ui/layouts/docs' + +import { source } from '@/lib/source' + +export default function Layout({ children }: { children: ReactNode }) { + return ( + + {children} + + ) +} diff --git a/apps/docs/app/globals.css b/apps/docs/app/globals.css new file mode 100644 index 0000000..a7b7c34 --- /dev/null +++ b/apps/docs/app/globals.css @@ -0,0 +1 @@ +@import 'fumadocs-ui/style.css'; diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx new file mode 100644 index 0000000..f439395 --- /dev/null +++ b/apps/docs/app/layout.tsx @@ -0,0 +1,23 @@ +import type { ReactNode } from 'react' + +import { RootProvider } from 'fumadocs-ui/provider/next' + +import { Providers } from '@/components/providers' +import './globals.css' + +export default function RootLayout({ children }: { children: ReactNode }) { + return ( + + + + {children} + + + + ) +} + +export const metadata = { + title: 'datum-ui', + description: 'Datum Cloud Design System Documentation', +} diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx new file mode 100644 index 0000000..23d8049 --- /dev/null +++ b/apps/docs/app/page.tsx @@ -0,0 +1,18 @@ +import Link from 'next/link' + +export default function HomePage() { + return ( +
+

datum-ui

+

+ Datum Cloud Design System +

+ + View Documentation + +
+ ) +} diff --git a/apps/docs/components/component-preview.tsx b/apps/docs/components/component-preview.tsx new file mode 100644 index 0000000..5eb204d --- /dev/null +++ b/apps/docs/components/component-preview.tsx @@ -0,0 +1,28 @@ +'use client' + +import type { ReactNode } from 'react' + +interface ComponentPreviewProps { + /** Accessible label for the preview area */ + name: string + /** The live component(s) to render */ + children: ReactNode + /** Additional CSS class for the preview container */ + className?: string +} + +/** + * Renders live datum-ui components in a bordered preview container. + * Used in MDX docs to show interactive component examples. + */ +export function ComponentPreview({ name, children, className }: ComponentPreviewProps) { + return ( +
+ {children} +
+ ) +} diff --git a/apps/docs/components/providers.tsx b/apps/docs/components/providers.tsx new file mode 100644 index 0000000..3829ea9 --- /dev/null +++ b/apps/docs/components/providers.tsx @@ -0,0 +1,9 @@ +'use client' + +import type { ReactNode } from 'react' + +import { DatumProvider } from '@datum-cloud/datum-ui' + +export function Providers({ children }: { children: ReactNode }) { + return {children} +} diff --git a/apps/docs/components/ui.tsx b/apps/docs/components/ui.tsx new file mode 100644 index 0000000..b38b86b --- /dev/null +++ b/apps/docs/components/ui.tsx @@ -0,0 +1,10 @@ +'use client' + +/** + * Client-side re-export of datum-ui components. + * + * datum-ui's bundle includes React hooks at the top level, which makes it + * incompatible with Next.js server components. MDX files must import from + * this wrapper instead of '@datum-cloud/datum-ui' directly. + */ +export * from '@datum-cloud/datum-ui' diff --git a/apps/docs/content/docs/components/base/alert.mdx b/apps/docs/content/docs/components/base/alert.mdx new file mode 100644 index 0000000..34950bd --- /dev/null +++ b/apps/docs/content/docs/components/base/alert.mdx @@ -0,0 +1,110 @@ +--- +title: Alert +description: Display contextual feedback messages with semantic variants and optional dismiss functionality. +--- + +import { Alert, AlertTitle, AlertDescription } from '@/components/ui' + +## Overview + +The Alert component displays short, important messages to the user. It supports seven semantic variants for different contexts (default, secondary, outline, destructive, success, info, warning) and an optional close button for dismissible alerts. + +## Usage + + + + Heads up! + You can add components to your app using the CLI. + + + +```tsx +import { Alert, AlertTitle, AlertDescription } from '@datum-cloud/datum-ui' + + + Heads up! + You can add components to your app using the CLI. + +``` + +## Examples + +### Variants + + +
+ + Default + This is a default alert. + + + Secondary + This is a secondary alert. + + + Outline + This is an outline alert. + + + Destructive + Your session has expired. Please log in again. + + + Success + Your changes have been saved successfully. + + + Info + A new software update is available. + + + Warning + Your account is approaching its storage limit. + +
+
+ +```tsx +... +... +... +... +``` + +### Closable + +Set `closable` to show a dismiss button. Provide `onClose` for custom handling, or omit it to auto-hide the alert. + + + + Dismissible + Click the close button to dismiss this alert. + + + +```tsx + console.log('closed')}> + Dismissible + Click the close button to dismiss this alert. + +``` + +## Props + +### Alert + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `variant` | `'default' \| 'secondary' \| 'outline' \| 'destructive' \| 'success' \| 'info' \| 'warning'` | `'default'` | Semantic color variant | +| `closable` | `boolean` | `false` | Show a close button | +| `onClose` | `() => void` | -- | Callback on dismiss; if omitted the alert auto-hides | +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Alert content (typically AlertTitle + AlertDescription) | + +### AlertTitle + +Renders a bold heading line inside the alert. Accepts all `div` HTML attributes. + +### AlertDescription + +Renders muted body text inside the alert. Accepts all `div` HTML attributes. diff --git a/apps/docs/content/docs/components/base/badge.mdx b/apps/docs/content/docs/components/base/badge.mdx new file mode 100644 index 0000000..d606b1d --- /dev/null +++ b/apps/docs/content/docs/components/base/badge.mdx @@ -0,0 +1,230 @@ +--- +title: Badge +description: A flexible badge component for displaying labels, status indicators, and tags with multiple type and theme variants. +--- + +import { Badge } from '@/components/ui' + +## Overview + +Badge is a lightweight inline element used to display short labels, status indicators, categories, or tags. It supports nine semantic types and three visual themes, making it adaptable for a wide range of use cases such as status flags, counters, and categorization labels. + +## Usage + + + Badge + + +```tsx +import { Badge } from '@datum-cloud/datum-ui' + +Badge +``` + +## Examples + +### Types + +The `type` prop controls the semantic color of the badge. Each type maps to a distinct color defined by design tokens. + + +
+ Primary + Secondary + Tertiary + Quaternary + Info + Warning + Danger + Success + Muted +
+
+ +```tsx +Primary +Secondary +Tertiary +Quaternary +Info +Warning +Danger +Success +Muted +``` + +### Themes + +The `theme` prop controls the visual style of the badge. Choose between a filled background, a bordered outline, or a subtle tinted appearance. + + +
+ Solid + Outline + Light +
+
+ +```tsx +Solid +Outline +Light +``` + +### Type and Theme Combinations + +Every type can be combined with every theme. Here is a grid showing all combinations. + + +
+
+ Primary Solid + Primary Outline + Primary Light +
+
+ Secondary Solid + Secondary Outline + Secondary Light +
+
+ Success Solid + Success Outline + Success Light +
+
+ Danger Solid + Danger Outline + Danger Light +
+
+ Warning Solid + Warning Outline + Warning Light +
+
+
+ +```tsx +Primary Solid +Primary Outline +Primary Light + +Secondary Solid +Secondary Outline +Secondary Light + +Success Solid +Success Outline +Success Light + +Danger Solid +Danger Outline +Danger Light + +Warning Solid +Warning Outline +Warning Light +``` + +### Status Indicators + +Badges work well as status indicators in lists, tables, or cards. + + +
+ Active + Pending + Failed + In Progress + Archived +
+
+ +```tsx +Active +Pending +Failed +In Progress +Archived +``` + +### With Icons + +Since Badge renders as a `div` with `inline-flex`, you can include icons alongside text by adding a `gap` class. + + +
+ + + Verified + + + + Rejected + + + + Caution + +
+
+ +```tsx +import { CheckCircle, XCircle, AlertTriangle } from 'lucide-react' + + + + Verified + + + + Rejected + + + + Caution + +``` + +### Custom Styling + +Pass additional Tailwind classes via the `className` prop to customize padding, borders, shadows, or any other styling. + + +
+ Larger Padding + Thicker Border + With Shadow +
+
+ +```tsx +Larger Padding +Thicker Border +With Shadow +``` + +## Props + +### Badge + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `type` | `'primary' \| 'secondary' \| 'tertiary' \| 'quaternary' \| 'info' \| 'warning' \| 'danger' \| 'success' \| 'muted'` | `'muted'` | Semantic color type of the badge | +| `theme` | `'solid' \| 'outline' \| 'light'` | `'solid'` | Visual style theme of the badge | +| `className` | `string` | - | Additional CSS classes to apply | +| `children` | `React.ReactNode` | - | Badge content | +| `...props` | `React.HTMLAttributes` | - | All standard HTML div attributes | + +### badgeVariants + +The `badgeVariants` utility is also exported for use cases where you need badge styling without the Badge component wrapper. + +```tsx +import { badgeVariants } from '@datum-cloud/datum-ui' + +
+ Custom Element +
+``` diff --git a/apps/docs/content/docs/components/base/breadcrumb.mdx b/apps/docs/content/docs/components/base/breadcrumb.mdx new file mode 100644 index 0000000..94d96c7 --- /dev/null +++ b/apps/docs/content/docs/components/base/breadcrumb.mdx @@ -0,0 +1,89 @@ +--- +title: Breadcrumb +description: A navigational trail showing the user's current location within a hierarchy. +--- + +## Overview + +Breadcrumb renders a horizontal list of links representing the user's current path within the application hierarchy. It follows the WAI-ARIA breadcrumb pattern with `nav[aria-label="breadcrumb"]` and `aria-current="page"` on the current page. Built on Radix UI's Slot for polymorphic link rendering. + +## Usage + +```tsx +import { + Breadcrumb, BreadcrumbList, BreadcrumbItem, + BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator +} from '@datum-cloud/datum-ui' + + + + + Home + + + + Projects + + + + Settings + + + +``` + +## Examples + +### With Framework Links + +Use `asChild` on `BreadcrumbLink` to render your framework's link component instead of a plain ``: + +```tsx +import { Link } from '@remix-run/react' + + + Projects + +``` + +### With Ellipsis + +For deep hierarchies, collapse middle items with `BreadcrumbEllipsis`: + +```tsx +import { BreadcrumbEllipsis } from '@datum-cloud/datum-ui' + + + + + Home + + + + + + + + Services + + + + API Gateway + + + +``` + +## Props + +### Sub-components + +| Component | Description | +|-----------|-------------| +| `Breadcrumb` | Root `nav` element with `aria-label="breadcrumb"` | +| `BreadcrumbList` | Ordered list (`ol`) container | +| `BreadcrumbItem` | List item (`li`) wrapper | +| `BreadcrumbLink` | Clickable link; supports `asChild` for custom link components | +| `BreadcrumbPage` | Current page indicator (non-interactive, `aria-current="page"`) | +| `BreadcrumbSeparator` | Chevron separator between items (customizable via `children`) | +| `BreadcrumbEllipsis` | Collapsed indicator for deep hierarchies | diff --git a/apps/docs/content/docs/components/base/button-group.mdx b/apps/docs/content/docs/components/base/button-group.mdx new file mode 100644 index 0000000..22c8665 --- /dev/null +++ b/apps/docs/content/docs/components/base/button-group.mdx @@ -0,0 +1,14 @@ +--- +title: Button Group +description: Group related buttons together with consistent spacing and styling. +--- + +# Button Group + +Re-exported from shadcn/ui. Groups related buttons together. + +## Usage + +```tsx +import { ButtonGroup } from '@datum-cloud/datum-ui' +``` diff --git a/apps/docs/content/docs/components/base/button.mdx b/apps/docs/content/docs/components/base/button.mdx new file mode 100644 index 0000000..5a437b3 --- /dev/null +++ b/apps/docs/content/docs/components/base/button.mdx @@ -0,0 +1,126 @@ +--- +title: Button +description: Trigger actions and events with configurable types, themes, sizes, and states. +--- + +import { Button } from '@/components/ui' + +## Overview + +The Button component supports multiple visual types (primary, secondary, tertiary, quaternary, danger, warning, success) combined with themes (solid, outline, light, borderless, link) for flexible styling. It includes loading states, icon support, and full-width layout. + +## Usage + + + + + +```tsx +import { Button } from '@datum-cloud/datum-ui' + + +``` + +## Examples + +### Types + + +
+ + + + + + + +
+
+ +```tsx + + + + + + + +``` + +### Themes + + +
+ + + + + +
+
+ +```tsx + + + + + +``` + +### Sizes + + +
+ + + + +
+
+ +```tsx + + + + +``` + +### Loading State + + +
+ + +
+
+ +```tsx + +``` + +### Full Width + + +
+ +
+
+ +```tsx + +``` + +## Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `type` | `'primary' \| 'secondary' \| 'tertiary' \| 'quaternary' \| 'warning' \| 'danger' \| 'success'` | `'primary'` | Color type | +| `theme` | `'solid' \| 'light' \| 'outline' \| 'borderless' \| 'link'` | `'solid'` | Visual theme | +| `size` | `'xs' \| 'small' \| 'default' \| 'large' \| 'icon' \| 'link'` | `'default'` | Button size | +| `block` | `boolean` | `false` | Full width | +| `loading` | `boolean` | `false` | Show loading spinner | +| `icon` | `ReactNode` | -- | Icon element | +| `iconPosition` | `'left' \| 'right'` | `'left'` | Icon placement | +| `loadingIcon` | `ReactNode` | -- | Custom loading spinner | +| `disabled` | `boolean` | `false` | Disabled state | +| `htmlType` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type | diff --git a/apps/docs/content/docs/components/base/calendar.mdx b/apps/docs/content/docs/components/base/calendar.mdx new file mode 100644 index 0000000..5efd0e4 --- /dev/null +++ b/apps/docs/content/docs/components/base/calendar.mdx @@ -0,0 +1,61 @@ +--- +title: Calendar +description: A date picker calendar built on react-day-picker with Datum styling. +--- + +import { Calendar } from '@/components/ui' + +## Overview + +The `Calendar` component renders an interactive month calendar. It supports single-date selection, date ranges, outside-day display, and multiple months. Built on `react-day-picker` v4 with Datum design tokens applied to navigation, day cells, and range highlighting. + +## Usage + + + + + +```tsx +import { Calendar } from '@datum-cloud/datum-ui' + + +``` + +## Examples + +### Single Date Selection + +```tsx +const [date, setDate] = useState(new Date()) + + +``` + +### Multi-Month + +```tsx + +``` + +## Props + +The `Calendar` component accepts all `react-day-picker` `DayPicker` props plus the following. + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `mode` | `'single' \| 'multiple' \| 'range'` | -- | Selection mode | +| `selected` | `Date \| Date[] \| DateRange` | -- | Controlled selected date(s) | +| `onSelect` | `(date) => void` | -- | Callback when selection changes | +| `showOutsideDays` | `boolean` | `true` | Show days from adjacent months | +| `numberOfMonths` | `number` | `1` | Number of months to display | +| `captionLayout` | `'label' \| 'dropdown'` | `'label'` | Month/year caption style | +| `buttonVariant` | `'ghost' \| 'outline' \| ...` | `'ghost'` | Navigation button variant | +| `className` | `string` | -- | Additional CSS classes | +| `classNames` | `object` | -- | Override individual element classes | diff --git a/apps/docs/content/docs/components/base/card.mdx b/apps/docs/content/docs/components/base/card.mdx new file mode 100644 index 0000000..a5ae8de --- /dev/null +++ b/apps/docs/content/docs/components/base/card.mdx @@ -0,0 +1,202 @@ +--- +title: Card +description: A container component for grouping related content with optional header, footer, and description sections. +--- + +import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui' + +## Overview + +The Card component provides a styled container for grouping related content. It extends the shadcn Card with Datum-specific styling and includes sub-components for structured layouts: `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, and `CardFooter`. + +## Usage + + + + + Card Title + Card description providing additional context. + + +

+ This is the main content area of the card. +

+
+
+
+ +```tsx +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@datum-cloud/datum-ui' + + + + Card Title + Card description providing additional context. + + +

This is the main content area of the card.

+
+
+``` + +## Examples + +### Simple Card + +A card with content only, without header or footer. + + + + +

+ A simple card with only content, no header or footer. +

+
+
+
+ +```tsx + + +

A simple card with only content, no header or footer.

+
+
+``` + +### With Footer Actions + +Use `CardFooter` to place actions at the bottom of the card. + + + + + Project Settings + Manage your project configuration and preferences. + + +

+ Review and update project settings below. Changes will be applied immediately after saving. +

+
+ + + + +
+
+ +```tsx +import { Button, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@datum-cloud/datum-ui' + + + + Project Settings + Manage your project configuration and preferences. + + +

Review and update project settings below.

+
+ + + + +
+``` + +### Full Example + +A complete card showcasing all sub-components together. + + + + + Notifications + Configure how you receive notifications. + + +
+
+ Email notifications + Enabled +
+
+ Push notifications + Disabled +
+
+
+ + + +
+
+ +```tsx + + + Notifications + Configure how you receive notifications. + + +
+
+ Email notifications + Enabled +
+
+ Push notifications + Disabled +
+
+
+ + + +
+``` + +## Props + +### Card + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Card content, typically sub-components | + +All standard `div` HTML attributes are also supported. + +### CardHeader + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Typically contains `CardTitle` and `CardDescription` | + +### CardTitle + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Title text | + +### CardDescription + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Description text | + +### CardContent + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Main card body content | + +### CardFooter + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `children` | `ReactNode` | -- | Footer content, typically actions | diff --git a/apps/docs/content/docs/components/base/chart.mdx b/apps/docs/content/docs/components/base/chart.mdx new file mode 100644 index 0000000..3e0698d --- /dev/null +++ b/apps/docs/content/docs/components/base/chart.mdx @@ -0,0 +1,14 @@ +--- +title: Chart +description: Data visualization components built on Recharts. +--- + +# Chart + +Re-exported from shadcn/ui. Provides chart components built on Recharts. + +## Usage + +```tsx +import { ChartContainer, ChartTooltip, ChartLegend } from '@datum-cloud/datum-ui' +``` diff --git a/apps/docs/content/docs/components/base/checkbox.mdx b/apps/docs/content/docs/components/base/checkbox.mdx new file mode 100644 index 0000000..7edfae3 --- /dev/null +++ b/apps/docs/content/docs/components/base/checkbox.mdx @@ -0,0 +1,75 @@ +--- +title: Checkbox +description: A toggleable checkbox control built on Radix UI Checkbox. +--- + +import { Checkbox, Label } from '@/components/ui' + +## Overview + +The `Checkbox` component renders an accessible checkbox input. It supports checked, unchecked, and indeterminate states, and is styled with Datum design tokens. + +## Usage + + + + + +```tsx +import { Checkbox } from '@datum-cloud/datum-ui' + + +``` + +## Examples + +### Checked by Default + + + + + +```tsx + +``` + +### With Label + + +
+ + +
+
+ +```tsx +
+ + +
+``` + +### Disabled + + + + + +```tsx + +``` + +## Props + +The `Checkbox` component accepts all props from Radix UI's `Checkbox.Root`. + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `checked` | `boolean \| 'indeterminate'` | -- | Controlled checked state | +| `defaultChecked` | `boolean` | `false` | Default checked state | +| `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | -- | Callback when state changes | +| `disabled` | `boolean` | `false` | Disables the checkbox | +| `required` | `boolean` | `false` | Marks as required in a form | +| `name` | `string` | -- | Name for form submission | +| `value` | `string` | -- | Value for form submission | +| `className` | `string` | -- | Additional CSS classes | diff --git a/apps/docs/content/docs/components/base/collapsible.mdx b/apps/docs/content/docs/components/base/collapsible.mdx new file mode 100644 index 0000000..240e711 --- /dev/null +++ b/apps/docs/content/docs/components/base/collapsible.mdx @@ -0,0 +1,71 @@ +--- +title: Collapsible +description: A component that toggles the visibility of its content with expand/collapse behavior. +--- + +## Overview + +Collapsible is a thin wrapper around Radix UI's Collapsible primitive. It lets users expand and collapse a section of content, useful for FAQs, advanced settings panels, or any progressive-disclosure pattern. + +## Usage + +```tsx +import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@datum-cloud/datum-ui' +import { Button } from '@datum-cloud/datum-ui' +import { ChevronsUpDown } from 'lucide-react' + + + + + + +
+ Advanced configuration options go here. +
+
+
+``` + +## Examples + +### Controlled + +Use `open` and `onOpenChange` for controlled state: + +```tsx +const [isOpen, setIsOpen] = useState(false) + + + + + + +

+ Detailed information revealed on demand. +

+
+
+``` + +## Props + +### Collapsible + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `open` | `boolean` | -- | Controlled open state | +| `onOpenChange` | `(open: boolean) => void` | -- | Callback when state changes | +| `defaultOpen` | `boolean` | `false` | Uncontrolled initial state | +| `disabled` | `boolean` | `false` | Prevent toggling | + +### Sub-components + +| Component | Description | +|-----------|-------------| +| `CollapsibleTrigger` | The element that toggles the content | +| `CollapsibleContent` | The section that expands and collapses | diff --git a/apps/docs/content/docs/components/base/command.mdx b/apps/docs/content/docs/components/base/command.mdx new file mode 100644 index 0000000..9aa060f --- /dev/null +++ b/apps/docs/content/docs/components/base/command.mdx @@ -0,0 +1,118 @@ +--- +title: Command +description: A searchable command palette for quick navigation and action execution. +--- + +## Overview + +Command provides a searchable, keyboard-navigable list of actions, inspired by the command palettes in VS Code and Linear. It is built on [cmdk](https://cmdk.paco.me/) and can be used inline or inside a dialog overlay (`CommandDialog`). Items are automatically filtered as the user types. + +## Usage + +```tsx +import { + Command, CommandInput, CommandList, + CommandEmpty, CommandGroup, CommandItem +} from '@datum-cloud/datum-ui' + + + + + No results found. + + Create Project + Deploy Service + View Logs + + + +``` + +## Examples + +### Command Dialog + +Wrap the command palette in a `CommandDialog` for a modal overlay, typically bound to a keyboard shortcut like `Ctrl+K`: + +```tsx +import { CommandDialog, CommandInput, CommandList, CommandGroup, CommandItem } from '@datum-cloud/datum-ui' + +function CommandMenu() { + const [open, setOpen] = useState(false) + + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { + e.preventDefault() + setOpen((prev) => !prev) + } + } + document.addEventListener('keydown', onKeyDown) + return () => document.removeEventListener('keydown', onKeyDown) + }, []) + + return ( + + + + + Dashboard + Projects + Settings + + + Create Project + Invite Member + + + + ) +} +``` + +### With Icons and Shortcuts + +```tsx +import { Settings, Plus, Users } from 'lucide-react' + + + + Settings + Ctrl+, + + + + New Project + Ctrl+N + +``` + +## Props + +### Command + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes | +| `filter` | `(value: string, search: string) => number` | -- | Custom filter function | + +### CommandDialog + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `open` | `boolean` | -- | Controlled open state | +| `onOpenChange` | `(open: boolean) => void` | -- | Callback when open state changes | +| `title` | `string` | `'Command Palette'` | Accessible dialog title (visually hidden) | +| `description` | `string` | `'Search for a command to run...'` | Accessible dialog description (visually hidden) | + +### Sub-components + +| Component | Description | +|-----------|-------------| +| `CommandInput` | Search input with a built-in search icon | +| `CommandList` | Scrollable container for command items (max 300px height) | +| `CommandEmpty` | Shown when no items match the search query | +| `CommandGroup` | Groups items under a heading | +| `CommandItem` | A single selectable command | +| `CommandSeparator` | Visual divider between groups | +| `CommandShortcut` | Right-aligned keyboard shortcut label | diff --git a/apps/docs/content/docs/components/base/dialog.mdx b/apps/docs/content/docs/components/base/dialog.mdx new file mode 100644 index 0000000..30400ff --- /dev/null +++ b/apps/docs/content/docs/components/base/dialog.mdx @@ -0,0 +1,114 @@ +--- +title: Dialog +description: A modal overlay for confirmations, forms, and focused user interactions. +--- + +import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose, Button, Input, Label } from '@/components/ui' + +## Overview + +The Dialog component renders a centered modal panel with a semi-transparent backdrop. It composes Radix UI's Dialog primitive with Datum styling -- blur overlay, rounded content panel, and built-in close button. Use it for confirmations, short forms, or any interaction that requires focused attention. + +## Usage + +```tsx +import { + Dialog, DialogTrigger, DialogContent, + DialogHeader, DialogFooter, DialogTitle, + DialogDescription, DialogClose, Button +} from '@datum-cloud/datum-ui' + + + + + + + + Invite Team Member + They will receive an email invitation. + + + + + + + + + +``` + +## Examples + +### With Form + +Add form fields between the header and footer for data-entry dialogs: + +```tsx + + + + + + + Create API Key + Generate a new API key. + +
+ + +
+ + + + + + +
+
+``` + +### Destructive Confirmation + +```tsx + + + + + + + Delete Project + This action cannot be undone. + + + + + + + + + +``` + +## Props + +### Dialog + +Root component. Controls open/close state. + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `open` | `boolean` | -- | Controlled open state | +| `onOpenChange` | `(open: boolean) => void` | -- | Called when open state changes | +| `defaultOpen` | `boolean` | `false` | Uncontrolled initial open state | + +### DialogContent + +The modal panel. Renders inside a portal with an overlay and a built-in close button. + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `className` | `string` | -- | Additional CSS classes for the panel | + +### Sub-components + +`DialogTrigger`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, and `DialogClose` are compositional wrappers -- see the examples above for usage patterns. diff --git a/apps/docs/content/docs/components/base/hover-card.mdx b/apps/docs/content/docs/components/base/hover-card.mdx new file mode 100644 index 0000000..5e8231b --- /dev/null +++ b/apps/docs/content/docs/components/base/hover-card.mdx @@ -0,0 +1,66 @@ +--- +title: HoverCard +description: A floating preview card that appears on hover over a trigger element. +--- + +## Overview + +HoverCard shows a floating preview card when the user hovers over a trigger element. It is useful for displaying supplementary information (user profiles, resource summaries, link previews) without requiring a click. Built on Radix UI's HoverCard primitive. + +## Usage + +```tsx +import { HoverCard, HoverCardTrigger, HoverCardContent } from '@datum-cloud/datum-ui' + + + +
@sarah + + +
+

Sarah Lin

+

+ Platform engineer. Joined March 2024. +

+
+
+ +``` + +## Examples + +### Resource Preview + +```tsx + + + us-east-1-prod + + +
+

Production Cluster

+

Region: us-east-1

+

Replicas: 3 / 3 healthy

+

Last deployed: 2 hours ago

+
+
+
+``` + +## Props + +### HoverCardContent + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Horizontal alignment relative to trigger | +| `sideOffset` | `number` | `4` | Distance from the trigger in pixels | +| `className` | `string` | -- | Additional CSS classes | + +### Sub-components + +| Component | Description | +|-----------|-------------| +| `HoverCard` | Root -- manages hover state with open/close delay | +| `HoverCardTrigger` | The element that activates the card on hover | +| `HoverCardContent` | The floating preview panel | diff --git a/apps/docs/content/docs/components/base/input-group.mdx b/apps/docs/content/docs/components/base/input-group.mdx new file mode 100644 index 0000000..5ff9a4d --- /dev/null +++ b/apps/docs/content/docs/components/base/input-group.mdx @@ -0,0 +1,14 @@ +--- +title: Input Group +description: Group input elements with labels, addons, and icons. +--- + +# Input Group + +Re-exported from shadcn/ui. Groups input elements with labels and addons. + +## Usage + +```tsx +import { InputGroup } from '@datum-cloud/datum-ui' +``` diff --git a/apps/docs/content/docs/components/base/input.mdx b/apps/docs/content/docs/components/base/input.mdx new file mode 100644 index 0000000..50a8175 --- /dev/null +++ b/apps/docs/content/docs/components/base/input.mdx @@ -0,0 +1,120 @@ +--- +title: Input +description: A styled text input field for capturing user input with built-in focus and error states. +--- + +import { Input } from '@/components/ui' + +## Overview + +The `Input` component wraps a standard HTML `` element with Datum design tokens for consistent styling across your application. It supports all native input types, provides visual feedback for focus and invalid states, and integrates with the Datum theming system. + +## Usage + +```tsx +import { Input } from '@datum-cloud/datum-ui' + + +``` + +## Examples + +### Default + +A basic text input with placeholder text. + +```tsx + +``` + +### Email Input + +Use the `type` prop to render different input types. + +```tsx + +``` + +### Password Input + +```tsx + +``` + +### Number Input + +```tsx + +``` + +### Disabled + +Set the `disabled` prop to prevent interaction. The input renders with reduced opacity and a not-allowed cursor. + +```tsx + +``` + +### Read-Only + +Use `readOnly` to display a value that cannot be edited. + +```tsx + +``` + +### Invalid State + +Add `aria-invalid` to trigger the destructive border style, typically used with form validation. + +```tsx + +``` + +### With Custom Class + +Pass a `className` prop to extend or override the default styles. + +```tsx + +``` + +### File Input + +The component supports file inputs with styled file button text. + +```tsx + +``` + +## Props + +The `Input` component accepts all standard HTML `` attributes via `React.ComponentProps<'input'>`. + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `type` | `string` | `'text'` | The HTML input type (`text`, `email`, `password`, `number`, `file`, etc.) | +| `placeholder` | `string` | — | Placeholder text displayed when the input is empty | +| `disabled` | `boolean` | `false` | Disables the input, preventing interaction | +| `readOnly` | `boolean` | `false` | Makes the input read-only | +| `value` | `string \| number` | — | The controlled value of the input | +| `defaultValue` | `string \| number` | — | The uncontrolled default value | +| `onChange` | `(e: ChangeEvent) => void` | — | Callback fired when the input value changes | +| `className` | `string` | — | Additional CSS classes to merge with default styles | +| `ref` | `RefObject` | — | Ref forwarded to the underlying `` element | +| `aria-invalid` | `boolean \| string` | — | Marks the input as invalid, applying a destructive border style | + +## Styling + +The Input component uses the following Datum design tokens: + +| Token | Purpose | +|-------|---------| +| `--input-background` | Input background color (applied at 50% opacity) | +| `--input-foreground` | Text color | +| `--input-border` | Default border color | +| `--input-placeholder` | Placeholder text color | +| `--input-focus-border` | Border color on focus | +| `--input-focus-shadow` | Shadow applied on focus | + +Override these tokens in your theme to customize input appearance globally. See [Theming](/docs/theming) for details. diff --git a/apps/docs/content/docs/components/base/label.mdx b/apps/docs/content/docs/components/base/label.mdx new file mode 100644 index 0000000..32390ac --- /dev/null +++ b/apps/docs/content/docs/components/base/label.mdx @@ -0,0 +1,52 @@ +--- +title: Label +description: An accessible text label for form controls, built on Radix UI Label. +--- + +import { Label, Input } from '@/components/ui' + +## Overview + +The `Label` component renders an accessible `