├── .changeset └── config.json ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── prepare-commit-msg ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── apps └── docs │ ├── .eslintrc.json │ ├── .storybook │ ├── main.ts │ └── preview.ts │ ├── package.json │ ├── postcss.config.cjs │ ├── src │ ├── components │ │ ├── DataTableRowAction.tsx │ │ └── ThemeColor.tsx │ ├── data │ │ ├── data.tsx │ │ ├── schema.ts │ │ └── tasks.json │ ├── stories │ │ ├── components │ │ │ ├── accordion.stories.tsx │ │ │ ├── alert-dialog.stories.tsx │ │ │ ├── avatar.stories.tsx │ │ │ ├── badge.stories.tsx │ │ │ ├── button.stories.tsx │ │ │ ├── card.stories.tsx │ │ │ ├── checkbox.stories.tsx │ │ │ ├── data-table.stories.tsx │ │ │ ├── dialog.stories.tsx │ │ │ ├── dropdown-menu.stories.tsx │ │ │ ├── form.stories.tsx │ │ │ ├── heading.stories.tsx │ │ │ ├── radio-group.stories.tsx │ │ │ ├── select.stories.tsx │ │ │ ├── separator.stories.tsx │ │ │ ├── skeleton.stories.tsx │ │ │ ├── slider.stories.tsx │ │ │ ├── switch.stories.tsx │ │ │ ├── table.stories.tsx │ │ │ ├── text.stories.tsx │ │ │ ├── textarea.stories.tsx │ │ │ ├── textfield.stories.tsx │ │ │ └── toast.stories.tsx │ │ └── docs │ │ │ └── colors.stories.mdx │ ├── styles │ │ └── globals.css │ └── utils │ │ └── colors.ts │ ├── tailwind.config.js │ └── tsconfig.json ├── commitlint.config.cjs ├── package.json ├── packages ├── styles │ ├── .eslintrc.json │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ │ ├── cn.spec.ts │ │ ├── cn.ts │ │ ├── config.spec.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── theme.css │ ├── tsconfig.json │ └── tsup.config.ts ├── tsconfig │ ├── base.json │ ├── package.json │ └── react.json └── ui │ ├── .eslintrc.json │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ ├── accordion.tsx │ ├── alert-dialog.tsx │ ├── alert.tsx │ ├── avatar.tsx │ ├── badge.tsx │ ├── button.tsx │ ├── card.tsx │ ├── checkbox.tsx │ ├── data-table.tsx │ ├── dialog.tsx │ ├── dropdown-menu.tsx │ ├── form.tsx │ ├── heading.tsx │ ├── label.tsx │ ├── radio-group.tsx │ ├── select.tsx │ ├── separator.tsx │ ├── skeleton.tsx │ ├── slider.tsx │ ├── switch.tsx │ ├── table.tsx │ ├── text.tsx │ ├── textarea.tsx │ ├── textfield.tsx │ └── toast.tsx │ ├── tailwind.config.js │ ├── tsconfig.json │ └── tsup.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "fellipeutaka/ui" 7 | } 8 | ], 9 | "commit": false, 10 | "linked": [], 11 | "access": "public", 12 | "baseBranch": "main", 13 | "updateInternalDependencies": "patch", 14 | "ignore": ["@fellipeutaka/docs"] 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: ${{ github.workflow }}-${{ github.ref }} 9 | 10 | permissions: 11 | contents: write 12 | issues: write 13 | pull-requests: write 14 | 15 | jobs: 16 | release: 17 | name: Release 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | node-version: [lts/*] 22 | env: 23 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 24 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 25 | steps: 26 | - name: Checkout Repo 27 | uses: actions/checkout@v4 28 | 29 | - uses: pnpm/action-setup@v2 30 | with: 31 | version: 8.9.0 32 | 33 | - name: Use Node.js ${{ matrix.node-version }} 34 | uses: actions/setup-node@v3 35 | with: 36 | node-version: ${{ matrix.node-version }} 37 | cache: "pnpm" 38 | 39 | - name: Install dependencies 40 | run: pnpm install --frozen-lockfile --ignore-scripts 41 | 42 | - name: Publish to npm 43 | id: changesets 44 | uses: changesets/action@v1 45 | with: 46 | publish: pnpm release 47 | version: pnpm version-packages 48 | commit: "chore: new release" 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .turbo 4 | *.log 5 | .next 6 | dist 7 | dist-ssr 8 | *.local 9 | .env 10 | .cache 11 | server/dist 12 | public/dist 13 | storybook-static/ 14 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit ${1} 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm lint-staged 5 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | exec < /dev/tty && npx cz --hook || true 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ], 7 | "cSpell.words": [ 8 | "clsx", 9 | "commitlint", 10 | "deepmerge", 11 | "fastify", 12 | "hookform", 13 | "lucide", 14 | "shadcn", 15 | "sonner", 16 | "tanstack", 17 | "treeshake", 18 | "tsup" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Fellipe Utaka 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 | # fellipeutaka/ui 2 | 3 | ## Installation 4 | 5 | ```bash 6 | pnpm i @fellipeutaka/ui @fellipeutaka/styles lucide-react 7 | ``` 8 | 9 | 10 | ## Initial configuration 11 | Extend the Design System theme on `tailwind.config.js`. 12 | 13 | ```js 14 | import { defineTailwindConfig } from "@fellipeutaka/styles"; 15 | 16 | export default defineTailwindConfig({ 17 | content: ["./src/{app,screens,components}/**/*.{ts,tsx}"], 18 | }); 19 | ``` 20 | 21 | Or in CJS 22 | 23 | ```cjs 24 | const { defineTailwindConfig } = require("@fellipeutaka/styles"); 25 | 26 | module.exports = defineTailwindConfig({ 27 | content: ["./src/{app,screens,components}/**/*.{ts,tsx}"], 28 | }); 29 | ``` 30 | 31 | Import `theme.css` file at your `globals.css`. 32 | 33 | ```css 34 | /* default theme */ 35 | @import "@fellipeutaka/styles/theme.css"; 36 | 37 | @tailwind base; 38 | @tailwind components; 39 | @tailwind utilities; 40 | ``` 41 | 42 | Great! Everything is ready to use it. 43 | 44 | ```jsx 45 | import { Button } from "@fellipeutaka/ui/button"; 46 | 47 | export function App() { 48 | return ; 49 | } 50 | ``` 51 | 52 | 53 | ## Customization 54 | 55 | 56 | Customizing is as simple as changing CSS variables values. 57 | 58 | ```css 59 | @tailwind base; 60 | @tailwind components; 61 | @tailwind utilities; 62 | 63 | @layer theme { 64 | :root { 65 | --background: 0 0% 100%; 66 | --foreground: 222.2 47.4% 11.2%; 67 | 68 | --muted: 210 40% 96.1%; 69 | --muted-foreground: 215.4 16.3% 46.9%; 70 | 71 | --popover: 0 0% 100%; 72 | --popover-foreground: 222.2 47.4% 11.2%; 73 | 74 | --border: 214.3 31.8% 91.4%; 75 | --input: 214.3 31.8% 91.4%; 76 | 77 | --card: 0 0% 100%; 78 | --card-foreground: 222.2 47.4% 11.2%; 79 | 80 | --primary: 222.2 47.4% 11.2%; 81 | --primary-foreground: 210 40% 98%; 82 | 83 | --secondary: 210 40% 96.1%; 84 | --secondary-foreground: 222.2 47.4% 11.2%; 85 | 86 | --accent: 210 40% 96.1%; 87 | --accent-foreground: 222.2 47.4% 11.2%; 88 | 89 | --destructive: 0 100% 50%; 90 | --destructive-foreground: 210 40% 98%; 91 | 92 | --ring: 215 20.2% 65.1%; 93 | 94 | --radius: 0.5rem; 95 | } 96 | 97 | .dark:root { 98 | --background: 224 71% 4%; 99 | --foreground: 213 31% 91%; 100 | 101 | --muted: 223 47% 11%; 102 | --muted-foreground: 215.4 16.3% 56.9%; 103 | 104 | --accent: 216 34% 17%; 105 | --accent-foreground: 210 40% 98%; 106 | 107 | --popover: 224 71% 4%; 108 | --popover-foreground: 215 20.2% 65.1%; 109 | 110 | --border: 216 34% 17%; 111 | --input: 216 34% 17%; 112 | 113 | --card: 224 71% 4%; 114 | --card-foreground: 213 31% 91%; 115 | 116 | --primary: 210 40% 98%; 117 | --primary-foreground: 222.2 47.4% 1.2%; 118 | 119 | --secondary: 222.2 47.4% 11.2%; 120 | --secondary-foreground: 210 40% 98%; 121 | 122 | --destructive: 0 63% 31%; 123 | --destructive-foreground: 210 40% 98%; 124 | 125 | --ring: 216 34% 17%; 126 | 127 | --radius: 0.5rem; 128 | } 129 | 130 | body { 131 | @apply bg-background text-foreground antialiased; 132 | font-feature-settings: 133 | "rlig" 1, 134 | "calt" 1; 135 | } 136 | 137 | ::-webkit-scrollbar { 138 | @apply h-1.5 w-1.5; 139 | } 140 | 141 | ::-webkit-scrollbar-thumb { 142 | @apply bg-foreground/40 rounded-lg transition-colors; 143 | } 144 | 145 | ::-webkit-scdrollbar-thumb:hover, 146 | ::-webkit-scrollbar-thumb:active { 147 | @apply bg-foreground/60; 148 | } 149 | 150 | :autofill { 151 | background: none; 152 | } 153 | 154 | ::-webkit-color-swatch-wrapper { 155 | padding: 0; 156 | } 157 | 158 | ::-webkit-color-swatch { 159 | border: 0; 160 | border-radius: 0; 161 | } 162 | 163 | ::-moz-color-swatch, 164 | ::-moz-focus-inner { 165 | border: 0; 166 | } 167 | 168 | ::-moz-focus-inner { 169 | padding: 0; 170 | } 171 | } 172 | ``` 173 | -------------------------------------------------------------------------------- /apps/docs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@fellipeutaka/eslint-config/react", 4 | "@fellipeutaka/eslint-config/tailwind", 5 | "plugin:storybook/recommended" 6 | ], 7 | "overrides": [ 8 | { 9 | "files": ["src/stories/components/*.stories.{tsx,mdx}"], 10 | "rules": { 11 | "import/no-default-export": "off" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /apps/docs/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import { dirname, join } from "node:path"; 2 | import type { StorybookConfig } from "@storybook/react-vite"; 3 | import { mergeConfig } from "vite"; 4 | 5 | const config: StorybookConfig = { 6 | stories: ["../src/stories/**/*.stories.{tsx,mdx}"], 7 | addons: [ 8 | getAbsolutePath("@storybook/addon-links"), 9 | getAbsolutePath("@storybook/addon-essentials"), 10 | getAbsolutePath("@storybook/addon-interactions"), 11 | getAbsolutePath("@storybook/addon-a11y"), 12 | getAbsolutePath("@storybook/addon-themes"), 13 | ], 14 | framework: { 15 | name: getAbsolutePath("@storybook/react-vite"), 16 | options: { 17 | strictMode: true, 18 | }, 19 | }, 20 | docs: { 21 | autodocs: true, 22 | }, 23 | async viteFinal(config) { 24 | return mergeConfig(config, { 25 | resolve: { 26 | alias: { 27 | "~": join(__dirname, "..", "src"), 28 | }, 29 | }, 30 | }); 31 | }, 32 | }; 33 | 34 | export default config; 35 | 36 | function getAbsolutePath(value: TValue) { 37 | return dirname(require.resolve(join(value, "package.json"))) as TValue; 38 | } 39 | -------------------------------------------------------------------------------- /apps/docs/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from "@storybook/react"; 2 | import { withThemeByClassName } from "@storybook/addon-themes"; 3 | 4 | import "~/styles/globals.css"; 5 | 6 | const preview: Preview = { 7 | parameters: { 8 | actions: { argTypesRegex: "^on[A-Z].*" }, 9 | controls: { 10 | matchers: { 11 | color: /(background|color)$/i, 12 | date: /Date$/, 13 | }, 14 | }, 15 | }, 16 | decorators: [ 17 | withThemeByClassName({ 18 | defaultTheme: "light", 19 | themes: { 20 | light: "", 21 | dark: "dark", 22 | }, 23 | }), 24 | ], 25 | }; 26 | 27 | export default preview; 28 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fellipeutaka/docs", 3 | "private": true, 4 | "scripts": { 5 | "dev": "storybook dev -p 6006 --no-open", 6 | "build": "storybook build -o dist", 7 | "start": "serve dist", 8 | "preview-storybook": "serve dist", 9 | "clean": "rimraf .turbo dist node_modules", 10 | "lint": "eslint src --fix --max-warnings 0" 11 | }, 12 | "dependencies": { 13 | "@fellipeutaka/ui": "workspace:*", 14 | "lucide-react": "latest", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "zod": "^3.22.4" 18 | }, 19 | "devDependencies": { 20 | "@fellipeutaka/styles": "workspace:*", 21 | "@fellipeutaka/tsconfig": "workspace:*", 22 | "@storybook/addon-a11y": "^7.5.1", 23 | "@storybook/addon-actions": "^7.5.1", 24 | "@storybook/addon-docs": "^7.5.1", 25 | "@storybook/addon-essentials": "^7.5.1", 26 | "@storybook/addon-interactions": "^7.5.1", 27 | "@storybook/addon-links": "^7.5.1", 28 | "@storybook/addon-themes": "^7.5.1", 29 | "@storybook/blocks": "^7.5.1", 30 | "@storybook/react": "^7.5.1", 31 | "@storybook/react-vite": "^7.5.1", 32 | "@types/react": "^18.2.32", 33 | "@types/react-dom": "^18.2.14", 34 | "@vitejs/plugin-react": "^4.1.0", 35 | "autoprefixer": "^10.4.16", 36 | "eslint-plugin-storybook": "^0.6.15", 37 | "postcss": "^8.4.31", 38 | "serve": "^14.2.1", 39 | "storybook": "^7.5.1", 40 | "tailwindcss": "^3.3.5", 41 | "vite": "^4.5.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /apps/docs/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /apps/docs/src/components/DataTableRowAction.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@fellipeutaka/ui/button"; 4 | import type { Row } from "@fellipeutaka/ui/data-table"; 5 | import { DropdownMenu } from "@fellipeutaka/ui/dropdown-menu"; 6 | import { MoreHorizontalIcon } from "lucide-react"; 7 | 8 | import { labels } from "~/data/data"; 9 | import { taskSchema } from "~/data/schema"; 10 | 11 | type DataTableRowActionsProps = { 12 | row: Row; 13 | }; 14 | 15 | export function DataTableRowActions({ 16 | row, 17 | }: DataTableRowActionsProps) { 18 | const task = taskSchema.parse(row.original); 19 | 20 | return ( 21 | 22 | 23 | 30 | 31 | 32 | Edit 33 | Make a copy 34 | Favorite 35 | 36 | 37 | Labels 38 | 39 | 40 | {labels.map((label) => ( 41 | 42 | {label.label} 43 | 44 | ))} 45 | 46 | 47 | 48 | 49 | 50 | Delete 51 | ⌘⌫ 52 | 53 | 54 | 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /apps/docs/src/components/ThemeColor.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@fellipeutaka/styles"; 2 | 3 | import { hslToColors } from "~/utils/colors"; 4 | 5 | type ThemeColorProps = React.ComponentPropsWithoutRef<"div"> & { 6 | variable: string; 7 | }; 8 | 9 | function getCSSColor(color: string) { 10 | return getComputedStyle(document.documentElement).getPropertyValue( 11 | `--${color}`, 12 | ); 13 | } 14 | 15 | export function ThemeColor({ variable, className, ...props }: ThemeColorProps) { 16 | const cssVariableValue = getCSSColor(variable); 17 | 18 | if (!cssVariableValue) { 19 | throw new Error(`Variable ${variable} not found`); 20 | } 21 | 22 | const color = hslToColors(cssVariableValue); 23 | 24 | return ( 25 |
26 |

{variable}

27 |

{color.hsl}

28 |

{color.hex}

29 |

{color.rgb}

30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /apps/docs/src/data/data.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ArrowDownIcon, 3 | ArrowRightIcon, 4 | ArrowUpIcon, 5 | BanIcon, 6 | CheckCircleIcon, 7 | CircleIcon, 8 | HelpCircleIcon, 9 | TimerIcon, 10 | } from "lucide-react"; 11 | 12 | export const labels = [ 13 | { 14 | value: "bug", 15 | label: "Bug", 16 | }, 17 | { 18 | value: "feature", 19 | label: "Feature", 20 | }, 21 | { 22 | value: "documentation", 23 | label: "Documentation", 24 | }, 25 | ]; 26 | 27 | export const statuses = [ 28 | { 29 | value: "backlog", 30 | label: "Backlog", 31 | icon: HelpCircleIcon, 32 | }, 33 | { 34 | value: "todo", 35 | label: "Todo", 36 | icon: CircleIcon, 37 | }, 38 | { 39 | value: "in progress", 40 | label: "In Progress", 41 | icon: TimerIcon, 42 | }, 43 | { 44 | value: "done", 45 | label: "Done", 46 | icon: CheckCircleIcon, 47 | }, 48 | { 49 | value: "canceled", 50 | label: "Canceled", 51 | icon: BanIcon, 52 | }, 53 | ]; 54 | 55 | export const priorities = [ 56 | { 57 | label: "Low", 58 | value: "low", 59 | icon: ArrowDownIcon, 60 | }, 61 | { 62 | label: "Medium", 63 | value: "medium", 64 | icon: ArrowRightIcon, 65 | }, 66 | { 67 | label: "High", 68 | value: "high", 69 | icon: ArrowUpIcon, 70 | }, 71 | ]; 72 | -------------------------------------------------------------------------------- /apps/docs/src/data/schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const taskSchema = z.object({ 4 | id: z.string(), 5 | title: z.string(), 6 | status: z.string(), 7 | label: z.string(), 8 | priority: z.string(), 9 | }); 10 | 11 | export type Task = z.output; 12 | -------------------------------------------------------------------------------- /apps/docs/src/data/tasks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "TASK-8782", 4 | "title": "You can't compress the program without quantifying the open-source SSD pixel!", 5 | "status": "in progress", 6 | "label": "documentation", 7 | "priority": "medium" 8 | }, 9 | { 10 | "id": "TASK-7878", 11 | "title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!", 12 | "status": "backlog", 13 | "label": "documentation", 14 | "priority": "medium" 15 | }, 16 | { 17 | "id": "TASK-7839", 18 | "title": "We need to bypass the neural TCP card!", 19 | "status": "todo", 20 | "label": "bug", 21 | "priority": "high" 22 | }, 23 | { 24 | "id": "TASK-5562", 25 | "title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!", 26 | "status": "backlog", 27 | "label": "feature", 28 | "priority": "medium" 29 | }, 30 | { 31 | "id": "TASK-8686", 32 | "title": "I'll parse the wireless SSL protocol, that should driver the API panel!", 33 | "status": "canceled", 34 | "label": "feature", 35 | "priority": "medium" 36 | }, 37 | { 38 | "id": "TASK-1280", 39 | "title": "Use the digital TLS panel, then you can transmit the haptic system!", 40 | "status": "done", 41 | "label": "bug", 42 | "priority": "high" 43 | }, 44 | { 45 | "id": "TASK-7262", 46 | "title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!", 47 | "status": "done", 48 | "label": "feature", 49 | "priority": "high" 50 | }, 51 | { 52 | "id": "TASK-1138", 53 | "title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!", 54 | "status": "in progress", 55 | "label": "feature", 56 | "priority": "medium" 57 | }, 58 | { 59 | "id": "TASK-7184", 60 | "title": "We need to program the back-end THX pixel!", 61 | "status": "todo", 62 | "label": "feature", 63 | "priority": "low" 64 | }, 65 | { 66 | "id": "TASK-5160", 67 | "title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!", 68 | "status": "in progress", 69 | "label": "documentation", 70 | "priority": "high" 71 | }, 72 | { 73 | "id": "TASK-5618", 74 | "title": "Generating the driver won't do anything, we need to index the online SSL application!", 75 | "status": "done", 76 | "label": "documentation", 77 | "priority": "medium" 78 | }, 79 | { 80 | "id": "TASK-6699", 81 | "title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!", 82 | "status": "backlog", 83 | "label": "documentation", 84 | "priority": "medium" 85 | }, 86 | { 87 | "id": "TASK-2858", 88 | "title": "We need to override the online UDP bus!", 89 | "status": "backlog", 90 | "label": "bug", 91 | "priority": "medium" 92 | }, 93 | { 94 | "id": "TASK-9864", 95 | "title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!", 96 | "status": "done", 97 | "label": "bug", 98 | "priority": "high" 99 | }, 100 | { 101 | "id": "TASK-8404", 102 | "title": "We need to generate the virtual HEX alarm!", 103 | "status": "in progress", 104 | "label": "bug", 105 | "priority": "low" 106 | }, 107 | { 108 | "id": "TASK-5365", 109 | "title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!", 110 | "status": "in progress", 111 | "label": "documentation", 112 | "priority": "low" 113 | }, 114 | { 115 | "id": "TASK-1780", 116 | "title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!", 117 | "status": "todo", 118 | "label": "documentation", 119 | "priority": "high" 120 | }, 121 | { 122 | "id": "TASK-6938", 123 | "title": "Use the redundant SCSI application, then you can hack the optical alarm!", 124 | "status": "todo", 125 | "label": "documentation", 126 | "priority": "high" 127 | }, 128 | { 129 | "id": "TASK-9885", 130 | "title": "We need to compress the auxiliary VGA driver!", 131 | "status": "backlog", 132 | "label": "bug", 133 | "priority": "high" 134 | }, 135 | { 136 | "id": "TASK-3216", 137 | "title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!", 138 | "status": "backlog", 139 | "label": "documentation", 140 | "priority": "medium" 141 | }, 142 | { 143 | "id": "TASK-9285", 144 | "title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!", 145 | "status": "todo", 146 | "label": "bug", 147 | "priority": "high" 148 | }, 149 | { 150 | "id": "TASK-1024", 151 | "title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!", 152 | "status": "in progress", 153 | "label": "documentation", 154 | "priority": "low" 155 | }, 156 | { 157 | "id": "TASK-7068", 158 | "title": "You can't generate the capacitor without indexing the wireless HEX pixel!", 159 | "status": "canceled", 160 | "label": "bug", 161 | "priority": "low" 162 | }, 163 | { 164 | "id": "TASK-6502", 165 | "title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!", 166 | "status": "todo", 167 | "label": "bug", 168 | "priority": "high" 169 | }, 170 | { 171 | "id": "TASK-5326", 172 | "title": "We need to hack the redundant UTF8 transmitter!", 173 | "status": "todo", 174 | "label": "bug", 175 | "priority": "low" 176 | }, 177 | { 178 | "id": "TASK-6274", 179 | "title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!", 180 | "status": "canceled", 181 | "label": "documentation", 182 | "priority": "low" 183 | }, 184 | { 185 | "id": "TASK-1571", 186 | "title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!", 187 | "status": "in progress", 188 | "label": "feature", 189 | "priority": "medium" 190 | }, 191 | { 192 | "id": "TASK-9518", 193 | "title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!", 194 | "status": "canceled", 195 | "label": "documentation", 196 | "priority": "medium" 197 | }, 198 | { 199 | "id": "TASK-5581", 200 | "title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!", 201 | "status": "backlog", 202 | "label": "documentation", 203 | "priority": "high" 204 | }, 205 | { 206 | "id": "TASK-2197", 207 | "title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!", 208 | "status": "todo", 209 | "label": "documentation", 210 | "priority": "low" 211 | }, 212 | { 213 | "id": "TASK-8484", 214 | "title": "We need to parse the solid state UDP firewall!", 215 | "status": "in progress", 216 | "label": "bug", 217 | "priority": "low" 218 | }, 219 | { 220 | "id": "TASK-9892", 221 | "title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!", 222 | "status": "done", 223 | "label": "documentation", 224 | "priority": "high" 225 | }, 226 | { 227 | "id": "TASK-9616", 228 | "title": "We need to synthesize the cross-platform ASCII pixel!", 229 | "status": "in progress", 230 | "label": "feature", 231 | "priority": "medium" 232 | }, 233 | { 234 | "id": "TASK-9744", 235 | "title": "Use the back-end IP card, then you can input the solid state hard drive!", 236 | "status": "done", 237 | "label": "documentation", 238 | "priority": "low" 239 | }, 240 | { 241 | "id": "TASK-1376", 242 | "title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!", 243 | "status": "backlog", 244 | "label": "documentation", 245 | "priority": "low" 246 | }, 247 | { 248 | "id": "TASK-7382", 249 | "title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!", 250 | "status": "todo", 251 | "label": "feature", 252 | "priority": "low" 253 | }, 254 | { 255 | "id": "TASK-2290", 256 | "title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!", 257 | "status": "canceled", 258 | "label": "documentation", 259 | "priority": "high" 260 | }, 261 | { 262 | "id": "TASK-1533", 263 | "title": "You can't input the firewall without overriding the wireless TCP firewall!", 264 | "status": "done", 265 | "label": "bug", 266 | "priority": "high" 267 | }, 268 | { 269 | "id": "TASK-4920", 270 | "title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!", 271 | "status": "in progress", 272 | "label": "bug", 273 | "priority": "high" 274 | }, 275 | { 276 | "id": "TASK-5168", 277 | "title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!", 278 | "status": "in progress", 279 | "label": "feature", 280 | "priority": "low" 281 | }, 282 | { 283 | "id": "TASK-7103", 284 | "title": "We need to parse the multi-byte EXE bandwidth!", 285 | "status": "canceled", 286 | "label": "feature", 287 | "priority": "low" 288 | }, 289 | { 290 | "id": "TASK-4314", 291 | "title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!", 292 | "status": "in progress", 293 | "label": "bug", 294 | "priority": "high" 295 | }, 296 | { 297 | "id": "TASK-3415", 298 | "title": "Use the cross-platform XML application, then you can quantify the solid state feed!", 299 | "status": "todo", 300 | "label": "feature", 301 | "priority": "high" 302 | }, 303 | { 304 | "id": "TASK-8339", 305 | "title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!", 306 | "status": "in progress", 307 | "label": "feature", 308 | "priority": "low" 309 | }, 310 | { 311 | "id": "TASK-6995", 312 | "title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!", 313 | "status": "todo", 314 | "label": "feature", 315 | "priority": "high" 316 | }, 317 | { 318 | "id": "TASK-8053", 319 | "title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!", 320 | "status": "todo", 321 | "label": "feature", 322 | "priority": "medium" 323 | }, 324 | { 325 | "id": "TASK-4336", 326 | "title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!", 327 | "status": "todo", 328 | "label": "documentation", 329 | "priority": "low" 330 | }, 331 | { 332 | "id": "TASK-8790", 333 | "title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!", 334 | "status": "done", 335 | "label": "bug", 336 | "priority": "medium" 337 | }, 338 | { 339 | "id": "TASK-8980", 340 | "title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!", 341 | "status": "canceled", 342 | "label": "bug", 343 | "priority": "low" 344 | }, 345 | { 346 | "id": "TASK-7342", 347 | "title": "Use the neural CLI card, then you can parse the online port!", 348 | "status": "backlog", 349 | "label": "documentation", 350 | "priority": "low" 351 | }, 352 | { 353 | "id": "TASK-5608", 354 | "title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!", 355 | "status": "canceled", 356 | "label": "documentation", 357 | "priority": "low" 358 | }, 359 | { 360 | "id": "TASK-1606", 361 | "title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!", 362 | "status": "done", 363 | "label": "feature", 364 | "priority": "medium" 365 | }, 366 | { 367 | "id": "TASK-7872", 368 | "title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!", 369 | "status": "canceled", 370 | "label": "feature", 371 | "priority": "medium" 372 | }, 373 | { 374 | "id": "TASK-4167", 375 | "title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!", 376 | "status": "canceled", 377 | "label": "bug", 378 | "priority": "medium" 379 | }, 380 | { 381 | "id": "TASK-9581", 382 | "title": "You can't index the port without hacking the cross-platform XSS monitor!", 383 | "status": "backlog", 384 | "label": "documentation", 385 | "priority": "low" 386 | }, 387 | { 388 | "id": "TASK-8806", 389 | "title": "We need to bypass the back-end SSL panel!", 390 | "status": "done", 391 | "label": "bug", 392 | "priority": "medium" 393 | }, 394 | { 395 | "id": "TASK-6542", 396 | "title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!", 397 | "status": "done", 398 | "label": "feature", 399 | "priority": "low" 400 | }, 401 | { 402 | "id": "TASK-6806", 403 | "title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!", 404 | "status": "canceled", 405 | "label": "documentation", 406 | "priority": "low" 407 | }, 408 | { 409 | "id": "TASK-9549", 410 | "title": "You can't bypass the bus without connecting the neural JBOD bus!", 411 | "status": "todo", 412 | "label": "feature", 413 | "priority": "high" 414 | }, 415 | { 416 | "id": "TASK-1075", 417 | "title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!", 418 | "status": "done", 419 | "label": "feature", 420 | "priority": "medium" 421 | }, 422 | { 423 | "id": "TASK-1427", 424 | "title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!", 425 | "status": "done", 426 | "label": "documentation", 427 | "priority": "high" 428 | }, 429 | { 430 | "id": "TASK-1907", 431 | "title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!", 432 | "status": "todo", 433 | "label": "documentation", 434 | "priority": "high" 435 | }, 436 | { 437 | "id": "TASK-4309", 438 | "title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!", 439 | "status": "backlog", 440 | "label": "bug", 441 | "priority": "medium" 442 | }, 443 | { 444 | "id": "TASK-3973", 445 | "title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!", 446 | "status": "todo", 447 | "label": "feature", 448 | "priority": "medium" 449 | }, 450 | { 451 | "id": "TASK-7962", 452 | "title": "Use the wireless RAM program, then you can hack the cross-platform feed!", 453 | "status": "canceled", 454 | "label": "bug", 455 | "priority": "low" 456 | }, 457 | { 458 | "id": "TASK-3360", 459 | "title": "You can't quantify the program without synthesizing the neural OCR interface!", 460 | "status": "done", 461 | "label": "feature", 462 | "priority": "medium" 463 | }, 464 | { 465 | "id": "TASK-9887", 466 | "title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!", 467 | "status": "backlog", 468 | "label": "bug", 469 | "priority": "medium" 470 | }, 471 | { 472 | "id": "TASK-3649", 473 | "title": "I'll input the virtual USB system, that should circuit the DNS monitor!", 474 | "status": "in progress", 475 | "label": "feature", 476 | "priority": "medium" 477 | }, 478 | { 479 | "id": "TASK-3586", 480 | "title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!", 481 | "status": "in progress", 482 | "label": "bug", 483 | "priority": "low" 484 | }, 485 | { 486 | "id": "TASK-5150", 487 | "title": "I'll hack the wireless XSS port, that should transmitter the IP interface!", 488 | "status": "canceled", 489 | "label": "feature", 490 | "priority": "medium" 491 | }, 492 | { 493 | "id": "TASK-3652", 494 | "title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!", 495 | "status": "backlog", 496 | "label": "feature", 497 | "priority": "low" 498 | }, 499 | { 500 | "id": "TASK-6884", 501 | "title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!", 502 | "status": "canceled", 503 | "label": "feature", 504 | "priority": "high" 505 | }, 506 | { 507 | "id": "TASK-1591", 508 | "title": "We need to connect the mobile XSS driver!", 509 | "status": "in progress", 510 | "label": "feature", 511 | "priority": "high" 512 | }, 513 | { 514 | "id": "TASK-3802", 515 | "title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!", 516 | "status": "in progress", 517 | "label": "feature", 518 | "priority": "low" 519 | }, 520 | { 521 | "id": "TASK-7253", 522 | "title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!", 523 | "status": "backlog", 524 | "label": "bug", 525 | "priority": "high" 526 | }, 527 | { 528 | "id": "TASK-9739", 529 | "title": "We need to hack the multi-byte HDD bus!", 530 | "status": "done", 531 | "label": "documentation", 532 | "priority": "medium" 533 | }, 534 | { 535 | "id": "TASK-4424", 536 | "title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!", 537 | "status": "in progress", 538 | "label": "documentation", 539 | "priority": "medium" 540 | }, 541 | { 542 | "id": "TASK-3922", 543 | "title": "You can't back up the capacitor without generating the wireless PCI program!", 544 | "status": "backlog", 545 | "label": "bug", 546 | "priority": "low" 547 | }, 548 | { 549 | "id": "TASK-4921", 550 | "title": "I'll index the open-source IP feed, that should system the GB application!", 551 | "status": "canceled", 552 | "label": "bug", 553 | "priority": "low" 554 | }, 555 | { 556 | "id": "TASK-5814", 557 | "title": "We need to calculate the 1080p AGP feed!", 558 | "status": "backlog", 559 | "label": "bug", 560 | "priority": "high" 561 | }, 562 | { 563 | "id": "TASK-2645", 564 | "title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!", 565 | "status": "todo", 566 | "label": "documentation", 567 | "priority": "medium" 568 | }, 569 | { 570 | "id": "TASK-4535", 571 | "title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!", 572 | "status": "in progress", 573 | "label": "feature", 574 | "priority": "low" 575 | }, 576 | { 577 | "id": "TASK-4463", 578 | "title": "We need to copy the solid state AGP monitor!", 579 | "status": "done", 580 | "label": "documentation", 581 | "priority": "low" 582 | }, 583 | { 584 | "id": "TASK-9745", 585 | "title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!", 586 | "status": "canceled", 587 | "label": "feature", 588 | "priority": "high" 589 | }, 590 | { 591 | "id": "TASK-2080", 592 | "title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!", 593 | "status": "todo", 594 | "label": "bug", 595 | "priority": "medium" 596 | }, 597 | { 598 | "id": "TASK-3838", 599 | "title": "I'll bypass the online TCP application, that should panel the AGP system!", 600 | "status": "backlog", 601 | "label": "bug", 602 | "priority": "high" 603 | }, 604 | { 605 | "id": "TASK-1340", 606 | "title": "We need to navigate the virtual PNG circuit!", 607 | "status": "todo", 608 | "label": "bug", 609 | "priority": "medium" 610 | }, 611 | { 612 | "id": "TASK-6665", 613 | "title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!", 614 | "status": "canceled", 615 | "label": "feature", 616 | "priority": "low" 617 | }, 618 | { 619 | "id": "TASK-7585", 620 | "title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!", 621 | "status": "backlog", 622 | "label": "feature", 623 | "priority": "low" 624 | }, 625 | { 626 | "id": "TASK-6319", 627 | "title": "We need to copy the multi-byte SCSI program!", 628 | "status": "backlog", 629 | "label": "bug", 630 | "priority": "high" 631 | }, 632 | { 633 | "id": "TASK-4369", 634 | "title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!", 635 | "status": "backlog", 636 | "label": "bug", 637 | "priority": "high" 638 | }, 639 | { 640 | "id": "TASK-9035", 641 | "title": "We need to override the solid state PNG array!", 642 | "status": "canceled", 643 | "label": "documentation", 644 | "priority": "low" 645 | }, 646 | { 647 | "id": "TASK-3970", 648 | "title": "You can't index the transmitter without quantifying the haptic ASCII card!", 649 | "status": "todo", 650 | "label": "documentation", 651 | "priority": "medium" 652 | }, 653 | { 654 | "id": "TASK-4473", 655 | "title": "You can't bypass the protocol without overriding the neural RSS program!", 656 | "status": "todo", 657 | "label": "documentation", 658 | "priority": "low" 659 | }, 660 | { 661 | "id": "TASK-4136", 662 | "title": "You can't hack the hard drive without hacking the primary JSON program!", 663 | "status": "canceled", 664 | "label": "bug", 665 | "priority": "medium" 666 | }, 667 | { 668 | "id": "TASK-3939", 669 | "title": "Use the back-end SQL firewall, then you can connect the neural hard drive!", 670 | "status": "done", 671 | "label": "feature", 672 | "priority": "low" 673 | }, 674 | { 675 | "id": "TASK-2007", 676 | "title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!", 677 | "status": "backlog", 678 | "label": "bug", 679 | "priority": "high" 680 | }, 681 | { 682 | "id": "TASK-7516", 683 | "title": "Use the primary SQL program, then you can generate the auxiliary transmitter!", 684 | "status": "done", 685 | "label": "documentation", 686 | "priority": "medium" 687 | }, 688 | { 689 | "id": "TASK-6906", 690 | "title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!", 691 | "status": "done", 692 | "label": "feature", 693 | "priority": "high" 694 | }, 695 | { 696 | "id": "TASK-5207", 697 | "title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!", 698 | "status": "in progress", 699 | "label": "bug", 700 | "priority": "low" 701 | } 702 | ] 703 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/accordion.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Accordion } from "@fellipeutaka/ui/accordion"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | type AlertDialogProps = React.ComponentPropsWithoutRef; 5 | 6 | const meta: Meta = { 7 | title: "Components/Accordion", 8 | component: Accordion, 9 | args: { 10 | type: "single", 11 | collapsible: false, 12 | }, 13 | argTypes: { 14 | type: { 15 | control: { 16 | type: "inline-radio", 17 | }, 18 | options: ["single", "multiple"], 19 | description: "The type of accordion.", 20 | table: { 21 | type: { summary: "string" }, 22 | defaultValue: { summary: "single" }, 23 | }, 24 | }, 25 | collapsible: { 26 | description: "Whether or not the accordion can be collapsed.", 27 | defaultValue: false, 28 | table: { 29 | type: { summary: "boolean" }, 30 | defaultValue: { summary: false }, 31 | }, 32 | }, 33 | }, 34 | render(props) { 35 | return ( 36 | 37 | 38 | Is it accessible? 39 | 40 | Yes. It adheres to the WAI-ARIA design pattern. 41 | 42 | 43 | 44 | Is it styled? 45 | 46 | Yes. It comes with default styles that matches the other 47 | components' aesthetic. 48 | 49 | 50 | 51 | Is it animated? 52 | 53 | Yes. It's animated by default, but you can disable it if you 54 | prefer. 55 | 56 | 57 | 58 | ); 59 | }, 60 | }; 61 | 62 | export default meta; 63 | 64 | type Story = StoryObj; 65 | 66 | export const Default: Story = {}; 67 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/alert-dialog.stories.tsx: -------------------------------------------------------------------------------- 1 | import { AlertDialog } from "@fellipeutaka/ui/alert-dialog"; 2 | import { Button } from "@fellipeutaka/ui/button"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type AlertDialogProps = React.ComponentPropsWithoutRef; 6 | 7 | const meta: Meta = { 8 | title: "Components/Alert Dialog", 9 | component: AlertDialog, 10 | render(props) { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | Are you absolutely sure? 19 | 20 | This action cannot be undone. This will permanently delete your 21 | account and remove your data from our servers. 22 | 23 | 24 | 25 | Cancel 26 | 27 | Continue 28 | 29 | 30 | 31 | 32 | ); 33 | }, 34 | }; 35 | 36 | export default meta; 37 | 38 | type Story = StoryObj; 39 | 40 | export const Default: Story = {}; 41 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/avatar.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Avatar, type AvatarProps } from "@fellipeutaka/ui/avatar"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Components/Avatar", 6 | component: Avatar, 7 | render(props) { 8 | return ( 9 | 10 | 11 | FU 12 | 13 | ); 14 | }, 15 | }; 16 | 17 | export default meta; 18 | 19 | type Story = StoryObj; 20 | 21 | export const Default: Story = {}; 22 | 23 | export const Group: Story = { 24 | render(props) { 25 | const users = [ 26 | { 27 | username: "zKriguer", 28 | fallback: "KR", 29 | }, 30 | { 31 | username: "MatheusLukas", 32 | fallback: "ML", 33 | }, 34 | { 35 | username: "Kyori-kyo", 36 | fallback: "KK", 37 | }, 38 | { 39 | username: "Nick-Gabe", 40 | fallback: "NG", 41 | }, 42 | { 43 | username: "fellipeutaka", 44 | fallback: "FU", 45 | }, 46 | ]; 47 | 48 | return ( 49 |
50 | {users.map((user) => ( 51 | 52 | 53 | {user.fallback} 54 | 55 | ))} 56 |
57 | ); 58 | }, 59 | }; 60 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/badge.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Badge, type BadgeProps } from "@fellipeutaka/ui/badge"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | type BadgeVariant = Required; 5 | 6 | const meta: Meta = { 7 | title: "Components/Badge", 8 | component: Badge, 9 | argTypes: { 10 | variant: { 11 | control: { type: "select" }, 12 | options: [ 13 | "default", 14 | "secondary", 15 | "outline", 16 | "destructive", 17 | ] satisfies BadgeVariant[], 18 | description: "The variant of the badge.", 19 | table: { 20 | type: { summary: "string" }, 21 | defaultValue: { summary: "default" }, 22 | }, 23 | }, 24 | }, 25 | }; 26 | 27 | export default meta; 28 | 29 | type Story = StoryObj; 30 | 31 | export const Default: Story = { 32 | args: { 33 | children: "Badge", 34 | variant: "default", 35 | }, 36 | }; 37 | 38 | export const Secondary: Story = { 39 | args: { 40 | children: "Secondary", 41 | variant: "secondary", 42 | }, 43 | }; 44 | 45 | export const Outline: Story = { 46 | args: { 47 | children: "Outline", 48 | variant: "outline", 49 | }, 50 | }; 51 | 52 | export const Destructive: Story = { 53 | args: { 54 | children: "Destructive", 55 | variant: "destructive", 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/button.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Button, type ButtonProps } from "@fellipeutaka/ui/button"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | import { Plus } from "lucide-react"; 4 | 5 | type ButtonVariant = Required; 6 | 7 | type ButtonSize = Required; 8 | 9 | const meta: Meta = { 10 | title: "Components/Button", 11 | component: Button, 12 | args: { 13 | children: "Hello", 14 | disabled: false, 15 | size: "default", 16 | }, 17 | argTypes: { 18 | onClick: { 19 | action: "onClick", 20 | table: { 21 | disable: true, 22 | }, 23 | }, 24 | onFocus: { 25 | action: "onFocus", 26 | table: { 27 | disable: true, 28 | }, 29 | }, 30 | onMouseOver: { 31 | action: "onMouseOver", 32 | table: { 33 | disable: true, 34 | }, 35 | }, 36 | type: { 37 | control: { type: "inline-radio" }, 38 | options: ["button", "submit", "reset"], 39 | description: "The type of the button.", 40 | table: { 41 | type: { summary: "string" }, 42 | defaultValue: { summary: "button" }, 43 | }, 44 | }, 45 | variant: { 46 | control: { type: "select" }, 47 | options: [ 48 | "default", 49 | "destructive", 50 | "ghost", 51 | "link", 52 | "outline", 53 | "secondary", 54 | ] satisfies ButtonVariant[], 55 | description: "The variant of the button.", 56 | table: { 57 | type: { summary: "string" }, 58 | defaultValue: { summary: "default" }, 59 | }, 60 | }, 61 | size: { 62 | control: { type: "select" }, 63 | options: ["default", "icon", "lg", "sm"] satisfies ButtonSize[], 64 | description: "The size of the button.", 65 | table: { 66 | type: { summary: "string" }, 67 | defaultValue: { summary: "default" }, 68 | }, 69 | }, 70 | disabled: { 71 | description: "Whether the button is disabled.", 72 | table: { 73 | type: { summary: "boolean" }, 74 | defaultValue: { summary: false }, 75 | }, 76 | }, 77 | }, 78 | }; 79 | 80 | export default meta; 81 | 82 | type Story = StoryObj; 83 | 84 | export const Primary: Story = { 85 | args: { 86 | variant: "default", 87 | }, 88 | }; 89 | 90 | export const Secondary: Story = { 91 | args: { 92 | variant: "secondary", 93 | }, 94 | }; 95 | 96 | export const Outline: Story = { 97 | args: { 98 | variant: "outline", 99 | }, 100 | }; 101 | 102 | export const Link: Story = { 103 | args: { 104 | variant: "link", 105 | }, 106 | }; 107 | 108 | export const Ghost: Story = { 109 | args: { 110 | variant: "ghost", 111 | }, 112 | }; 113 | 114 | export const Destructive: Story = { 115 | args: { 116 | variant: "destructive", 117 | }, 118 | }; 119 | 120 | export const Icon: Story = { 121 | render(props) { 122 | return ( 123 | 126 | ); 127 | }, 128 | args: { 129 | variant: "default", 130 | size: "icon", 131 | "aria-label": "Add", 132 | }, 133 | argTypes: { 134 | children: { 135 | control: { type: "none" }, 136 | }, 137 | }, 138 | }; 139 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/card.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@fellipeutaka/ui/button"; 2 | import { Card, type CardProps } from "@fellipeutaka/ui/card"; 3 | import { Label } from "@fellipeutaka/ui/label"; 4 | import { Select } from "@fellipeutaka/ui/select"; 5 | import { TextField } from "@fellipeutaka/ui/textfield"; 6 | import type { Meta, StoryObj } from "@storybook/react"; 7 | 8 | const meta: Meta = { 9 | title: "Components/Card", 10 | component: Card, 11 | render(props) { 12 | return ( 13 | 14 | 15 | Create project 16 | 17 | Deploy your new project in one-click. 18 | 19 | 20 | 21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 | 38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 |
47 | ); 48 | }, 49 | }; 50 | 51 | export default meta; 52 | 53 | type Story = StoryObj; 54 | 55 | export const Default: Story = {}; 56 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/checkbox.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Checkbox, type CheckboxProps } from "@fellipeutaka/ui/checkbox"; 2 | import { Label } from "@fellipeutaka/ui/label"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Checkbox", 7 | component: Checkbox, 8 | args: { 9 | disabled: false, 10 | }, 11 | }; 12 | 13 | export default meta; 14 | 15 | type Story = StoryObj; 16 | 17 | export const Default: Story = {}; 18 | 19 | export const WithLabel: Story = { 20 | render(props) { 21 | return ( 22 |
23 | 24 | 25 |
26 | ); 27 | }, 28 | }; 29 | 30 | export const Disabled: Story = { 31 | args: { 32 | disabled: true, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/data-table.stories.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import { useState } from "react"; 3 | 4 | import { Badge } from "@fellipeutaka/ui/badge"; 5 | import { Checkbox } from "@fellipeutaka/ui/checkbox"; 6 | import { 7 | DataTable, 8 | flexRender, 9 | useReactTable, 10 | type ColumnFiltersState, 11 | type SortingState, 12 | type VisibilityState, 13 | getCoreRowModel, 14 | getFilteredRowModel, 15 | getPaginationRowModel, 16 | getSortedRowModel, 17 | getFacetedRowModel, 18 | getFacetedUniqueValues, 19 | type ColumnDef, 20 | } from "@fellipeutaka/ui/data-table"; 21 | import type { Meta, StoryObj } from "@storybook/react"; 22 | 23 | import { DataTableRowActions } from "~/components/DataTableRowAction"; 24 | import { labels, priorities, statuses } from "~/data/data"; 25 | import type { Task } from "~/data/schema"; 26 | import data from "~/data/tasks.json"; 27 | 28 | type DataTableProps = React.ComponentPropsWithoutRef; 29 | 30 | const meta: Meta = { 31 | title: "Components/Data Table", 32 | component: DataTable, 33 | render(props) { 34 | const columns: ColumnDef[] = [ 35 | { 36 | id: "select", 37 | header: ({ table }) => ( 38 | 41 | table.toggleAllPageRowsSelected(!!value) 42 | } 43 | aria-label="Select all" 44 | className="translate-y-[2px]" 45 | /> 46 | ), 47 | cell: ({ row }) => ( 48 | row.toggleSelected(!!value)} 51 | aria-label="Select row" 52 | className="translate-y-[2px]" 53 | /> 54 | ), 55 | enableSorting: false, 56 | enableHiding: false, 57 | }, 58 | { 59 | accessorKey: "id", 60 | header: ({ column }) => ( 61 | 62 | ), 63 | cell: ({ row }) =>
{row.getValue("id")}
, 64 | enableSorting: false, 65 | enableHiding: false, 66 | }, 67 | { 68 | accessorKey: "title", 69 | header: ({ column }) => ( 70 | 71 | ), 72 | cell: ({ row }) => { 73 | const label = labels.find( 74 | (label) => label.value === row.original.label, 75 | ); 76 | 77 | return ( 78 |
79 | {label && {label.label}} 80 | 81 | {row.getValue("title")} 82 | 83 |
84 | ); 85 | }, 86 | }, 87 | { 88 | accessorKey: "status", 89 | header: ({ column }) => ( 90 | 91 | ), 92 | cell: ({ row }) => { 93 | const status = statuses.find( 94 | (status) => status.value === row.getValue("status"), 95 | ); 96 | 97 | if (!status) { 98 | return null; 99 | } 100 | 101 | return ( 102 |
103 | {status.icon && ( 104 | 105 | )} 106 | {status.label} 107 |
108 | ); 109 | }, 110 | filterFn: (row, id, value) => { 111 | return value.includes(row.getValue(id)); 112 | }, 113 | }, 114 | { 115 | accessorKey: "priority", 116 | header: ({ column }) => ( 117 | 118 | ), 119 | cell: ({ row }) => { 120 | const priority = priorities.find( 121 | (priority) => priority.value === row.getValue("priority"), 122 | ); 123 | 124 | if (!priority) { 125 | return null; 126 | } 127 | 128 | return ( 129 |
130 | {priority.icon && ( 131 | 132 | )} 133 | {priority.label} 134 |
135 | ); 136 | }, 137 | filterFn: (row, id, value) => { 138 | return value.includes(row.getValue(id)); 139 | }, 140 | }, 141 | { 142 | id: "actions", 143 | cell: ({ row }) => , 144 | }, 145 | ]; 146 | 147 | const [rowSelection, setRowSelection] = useState({}); 148 | const [columnVisibility, setColumnVisibility] = useState( 149 | {}, 150 | ); 151 | const [columnFilters, setColumnFilters] = useState([]); 152 | const [sorting, setSorting] = useState([]); 153 | 154 | const table = useReactTable({ 155 | data, 156 | columns, 157 | state: { 158 | sorting, 159 | columnVisibility, 160 | rowSelection, 161 | columnFilters, 162 | }, 163 | enableRowSelection: true, 164 | onRowSelectionChange: setRowSelection, 165 | onSortingChange: setSorting, 166 | onColumnFiltersChange: setColumnFilters, 167 | onColumnVisibilityChange: setColumnVisibility, 168 | getCoreRowModel: getCoreRowModel(), 169 | getFilteredRowModel: getFilteredRowModel(), 170 | getPaginationRowModel: getPaginationRowModel(), 171 | getSortedRowModel: getSortedRowModel(), 172 | getFacetedRowModel: getFacetedRowModel(), 173 | getFacetedUniqueValues: getFacetedUniqueValues(), 174 | }); 175 | 176 | return ( 177 |
178 |
179 | 180 | 181 | {table.getHeaderGroups().map((headerGroup) => ( 182 | 183 | {headerGroup.headers.map((header) => ( 184 | 185 | {header.isPlaceholder 186 | ? null 187 | : flexRender( 188 | header.column.columnDef.header, 189 | header.getContext(), 190 | )} 191 | 192 | ))} 193 | 194 | ))} 195 | 196 | 197 | {table.getRowModel().rows?.length ? ( 198 | table.getRowModel().rows.map((row) => ( 199 | 203 | {row.getVisibleCells().map((cell) => ( 204 | 205 | {flexRender( 206 | cell.column.columnDef.cell, 207 | cell.getContext(), 208 | )} 209 | 210 | ))} 211 | 212 | )) 213 | ) : ( 214 | 215 | 219 | No results. 220 | 221 | 222 | )} 223 | 224 | 225 |
226 | 227 |
228 | ); 229 | }, 230 | }; 231 | 232 | export default meta; 233 | 234 | type Story = StoryObj; 235 | 236 | export const Default: Story = {}; 237 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/dialog.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@fellipeutaka/ui/button"; 2 | import { Dialog } from "@fellipeutaka/ui/dialog"; 3 | import { Label } from "@fellipeutaka/ui/label"; 4 | import { TextField } from "@fellipeutaka/ui/textfield"; 5 | import type { Meta, StoryObj } from "@storybook/react"; 6 | 7 | type DialogProps = React.ComponentPropsWithoutRef; 8 | 9 | const meta: Meta = { 10 | title: "Components/Dialog", 11 | component: Dialog, 12 | render(props) { 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | 20 | Edit profile 21 | 22 | Make changes to your profile here. Click save when you're done. 23 | 24 | 25 |
26 |
27 | 30 | 31 | 32 | 33 |
34 |
35 | 38 | 39 | 40 | 41 |
42 |
43 | 44 | 45 | 46 |
47 |
48 | ); 49 | }, 50 | }; 51 | 52 | export default meta; 53 | 54 | type Story = StoryObj; 55 | 56 | export const Default: Story = {}; 57 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/dropdown-menu.stories.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | import { Button } from "@fellipeutaka/ui/button"; 4 | import { DropdownMenu } from "@fellipeutaka/ui/dropdown-menu"; 5 | import type { Meta, StoryObj } from "@storybook/react"; 6 | import { 7 | User, 8 | CreditCard, 9 | Settings, 10 | Keyboard, 11 | Users, 12 | UserPlus, 13 | Mail, 14 | MessageSquare, 15 | PlusCircle, 16 | Plus, 17 | Github, 18 | LifeBuoy, 19 | Cloud, 20 | LogOut, 21 | } from "lucide-react"; 22 | 23 | type DropdownMenuProps = React.ComponentPropsWithoutRef; 24 | 25 | const meta: Meta = { 26 | title: "Components/Dropdown Menu", 27 | component: DropdownMenu, 28 | parameters: { 29 | layout: "centered", 30 | }, 31 | render(props) { 32 | return ( 33 | 34 | 35 | 36 | 37 | 38 | My Account 39 | 40 | 41 | 42 | 43 | Profile 44 | ⇧⌘P 45 | 46 | 47 | 48 | Billing 49 | ⌘B 50 | 51 | 52 | 53 | Settings 54 | ⌘S 55 | 56 | 57 | 58 | Keyboard shortcuts 59 | ⌘K 60 | 61 | 62 | 63 | 64 | 65 | 66 | Team 67 | 68 | 69 | 70 | 71 | Invite users 72 | 73 | 74 | 75 | 76 | 77 | Email 78 | 79 | 80 | 81 | Message 82 | 83 | 84 | 85 | 86 | More... 87 | 88 | 89 | 90 | 91 | 92 | 93 | New Team 94 | ⌘+T 95 | 96 | 97 | 98 | 99 | 100 | GitHub 101 | 102 | 103 | 104 | Support 105 | 106 | 107 | 108 | API 109 | 110 | 111 | 112 | 113 | Log out 114 | ⇧⌘Q 115 | 116 | 117 | 118 | ); 119 | }, 120 | }; 121 | 122 | export default meta; 123 | 124 | type Story = StoryObj; 125 | 126 | export const Default: Story = {}; 127 | 128 | export const Checkboxes: Story = { 129 | render(props) { 130 | // eslint-disable-next-line react-hooks/rules-of-hooks 131 | const [checked, setChecked] = useState({ 132 | statusBar: true, 133 | activityBar: false, 134 | panel: true, 135 | }); 136 | 137 | return ( 138 | 139 | 140 | 141 | 142 | 143 | Appearance 144 | 145 | 148 | setChecked((prev) => ({ 149 | ...prev, 150 | statusBar: event, 151 | })) 152 | } 153 | > 154 | Status Bar 155 | 156 | 159 | setChecked((prev) => ({ 160 | ...prev, 161 | activityBar: event, 162 | })) 163 | } 164 | disabled 165 | > 166 | Activity Bar 167 | 168 | 171 | setChecked((prev) => ({ 172 | ...prev, 173 | panel: event, 174 | })) 175 | } 176 | > 177 | Panel 178 | 179 | 180 | 181 | ); 182 | }, 183 | }; 184 | 185 | export const RadioGroup: Story = { 186 | render(props) { 187 | // eslint-disable-next-line react-hooks/rules-of-hooks 188 | const [position, setPosition] = useState("bottom"); 189 | 190 | return ( 191 | 192 | 193 | 194 | 195 | 196 | Panel Position 197 | 198 | 199 | Top 200 | 201 | Bottom 202 | 203 | Right 204 | 205 | 206 | 207 | ); 208 | }, 209 | }; 210 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/form.stories.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | 3 | import { Button } from "@fellipeutaka/ui/button"; 4 | import { Form, useForm } from "@fellipeutaka/ui/form"; 5 | import { TextField } from "@fellipeutaka/ui/textfield"; 6 | import { Toaster, toast } from "@fellipeutaka/ui/toast"; 7 | import type { Meta, StoryObj } from "@storybook/react"; 8 | import { z } from "zod"; 9 | 10 | type FormProps = React.ComponentPropsWithoutRef; 11 | 12 | const FormSchema = z.object({ 13 | username: z.string().min(2, "Username must be at least 2 characters."), 14 | }); 15 | 16 | const meta: Meta = { 17 | title: "Components/Form", 18 | decorators: [ 19 | (Story) => ( 20 | <> 21 | 22 | 23 | 24 | ), 25 | ], 26 | component: Form, 27 | render(props) { 28 | const form = useForm({ 29 | schema: FormSchema, 30 | defaultValues: { 31 | username: "", 32 | }, 33 | }); 34 | 35 | const handleSubmit = form.handleSubmit((data) => { 36 | toast("You submitted the following values:", { 37 | description: ( 38 |
39 |             {JSON.stringify(data, null, 2)}
40 |           
41 | ), 42 | }); 43 | }); 44 | 45 | return ( 46 |
47 | 48 | ( 52 | 53 | Username 54 | 55 | 56 | 57 | 58 | 59 | )} 60 | /> 61 | 62 | 63 | 64 | ); 65 | }, 66 | }; 67 | 68 | export default meta; 69 | 70 | type Story = StoryObj; 71 | 72 | export const Default: Story = {}; 73 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/heading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Heading, type HeadingProps } from "@fellipeutaka/ui/heading"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | type HeadingVariant = Required; 5 | type HeadingElement = Required; 6 | 7 | const meta: Meta = { 8 | title: "Components/Heading", 9 | component: Heading, 10 | args: { 11 | children: "Heading", 12 | variant: "h1", 13 | as: "h1", 14 | }, 15 | argTypes: { 16 | variant: { 17 | control: { type: "select" }, 18 | options: ["h1", "h2", "h3", "h4", "h5", "h6"] satisfies HeadingVariant[], 19 | description: "The variant of the component.", 20 | }, 21 | as: { 22 | control: { type: "select" }, 23 | options: ["h1", "h2", "h3", "h4", "h5", "h6"] satisfies HeadingElement[], 24 | description: "The HTML element to use for the component.", 25 | table: { 26 | type: "string", 27 | }, 28 | }, 29 | asChild: { 30 | table: { 31 | disable: true, 32 | }, 33 | }, 34 | }, 35 | }; 36 | 37 | export default meta; 38 | 39 | type Story = StoryObj; 40 | 41 | export const Default: Story = {}; 42 | 43 | export const H1: Story = { 44 | name: "h1", 45 | args: { 46 | variant: "h1", 47 | children: "Taxing Laughter: The Joke Tax Chronicles", 48 | }, 49 | }; 50 | 51 | export const H2: Story = { 52 | name: "h2", 53 | args: { 54 | variant: "h2", 55 | children: "The People of the Kingdom", 56 | }, 57 | }; 58 | 59 | export const H3: Story = { 60 | name: "h3", 61 | args: { 62 | variant: "h3", 63 | children: "The Joke Tax", 64 | }, 65 | }; 66 | 67 | export const H4: Story = { 68 | name: "h4", 69 | args: { 70 | variant: "h4", 71 | children: "People stopped telling jokes", 72 | }, 73 | }; 74 | 75 | export const H5: Story = { 76 | name: "h5", 77 | args: { 78 | variant: "h5", 79 | children: "The Joke Tax Chronicles", 80 | }, 81 | }; 82 | 83 | export const H6: Story = { 84 | name: "h6", 85 | args: { 86 | variant: "h6", 87 | children: "The Joke Tax Chronicles", 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/radio-group.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@fellipeutaka/ui/label"; 2 | import { RadioGroup, type RadioGroupProps } from "@fellipeutaka/ui/radio-group"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Radio Group", 7 | component: RadioGroup, 8 | render(props) { 9 | return ( 10 | 11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 |
20 | 21 | 22 |
23 |
24 | ); 25 | }, 26 | args: { 27 | disabled: false, 28 | }, 29 | }; 30 | 31 | export default meta; 32 | 33 | type Story = StoryObj; 34 | 35 | export const Default: Story = {}; 36 | 37 | export const Disabled: Story = { 38 | args: { 39 | disabled: true, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/select.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@fellipeutaka/ui/label"; 2 | import { Select, type SelectProps } from "@fellipeutaka/ui/select"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Select", 7 | component: Select, 8 | args: { 9 | disabled: false, 10 | }, 11 | render(props) { 12 | return ( 13 | 26 | ); 27 | }, 28 | }; 29 | 30 | export default meta; 31 | 32 | type Story = StoryObj; 33 | 34 | export const Default: Story = {}; 35 | 36 | export const WithLabel: Story = { 37 | render(props) { 38 | return ( 39 |
40 | 41 | 58 |
59 | ); 60 | }, 61 | }; 62 | 63 | export const Disabled: Story = { 64 | args: { 65 | disabled: true, 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/separator.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Separator, type SeparatorProps } from "@fellipeutaka/ui/separator"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Components/Separator", 6 | component: Separator, 7 | render(_props) { 8 | return ( 9 | <> 10 |
11 |

Radix Primitives

12 |

13 | An open-source UI component library. 14 |

15 |
16 | 17 |
18 |
Blog
19 | 20 |
Docs
21 | 22 |
Source
23 |
24 | 25 | ); 26 | }, 27 | argTypes: { 28 | orientation: { 29 | description: "The orientation of the separator.", 30 | table: { 31 | type: { summary: "string" }, 32 | }, 33 | control: { 34 | disable: true, 35 | }, 36 | }, 37 | decorative: { 38 | description: "Whether the separator is purely decorative.", 39 | table: { 40 | type: { summary: "boolean" }, 41 | defaultValue: { summary: true }, 42 | }, 43 | control: { 44 | disable: true, 45 | }, 46 | }, 47 | }, 48 | }; 49 | 50 | export default meta; 51 | 52 | type Story = StoryObj; 53 | 54 | export const Default: Story = {}; 55 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/skeleton.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton, type SkeletonProps } from "@fellipeutaka/ui/skeleton"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Components/Skeleton", 6 | component: Skeleton, 7 | render(_props) { 8 | return ( 9 |
10 | 11 |
12 | 13 | 14 |
15 |
16 | ); 17 | }, 18 | }; 19 | 20 | export default meta; 21 | 22 | type Story = StoryObj; 23 | 24 | export const Default: Story = {}; 25 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/slider.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Slider, type SliderProps } from "@fellipeutaka/ui/slider"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Components/Slider", 6 | component: Slider, 7 | args: { 8 | step: 1, 9 | max: 100, 10 | defaultValue: [0], 11 | }, 12 | }; 13 | 14 | export default meta; 15 | 16 | type Story = StoryObj; 17 | 18 | export const Default: Story = {}; 19 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/switch.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@fellipeutaka/ui/label"; 2 | import { Switch, type SwitchProps } from "@fellipeutaka/ui/switch"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Switch", 7 | component: Switch, 8 | args: { 9 | disabled: false, 10 | }, 11 | }; 12 | 13 | export default meta; 14 | 15 | type Story = StoryObj; 16 | 17 | export const Default: Story = {}; 18 | 19 | export const WithLabel: Story = { 20 | render(props) { 21 | return ( 22 |
23 | 24 | 25 |
26 | ); 27 | }, 28 | }; 29 | 30 | export const Disabled: Story = { 31 | args: { 32 | disabled: true, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/table.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Table, type TableProps } from "@fellipeutaka/ui/table"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | const meta: Meta = { 5 | title: "Components/Table", 6 | component: Table, 7 | render(props) { 8 | const invoices = [ 9 | { 10 | invoice: "INV001", 11 | paymentStatus: "Paid", 12 | totalAmount: "$250.00", 13 | paymentMethod: "Credit Card", 14 | }, 15 | { 16 | invoice: "INV002", 17 | paymentStatus: "Pending", 18 | totalAmount: "$150.00", 19 | paymentMethod: "PayPal", 20 | }, 21 | { 22 | invoice: "INV003", 23 | paymentStatus: "Unpaid", 24 | totalAmount: "$350.00", 25 | paymentMethod: "Bank Transfer", 26 | }, 27 | { 28 | invoice: "INV004", 29 | paymentStatus: "Paid", 30 | totalAmount: "$450.00", 31 | paymentMethod: "Credit Card", 32 | }, 33 | { 34 | invoice: "INV005", 35 | paymentStatus: "Paid", 36 | totalAmount: "$550.00", 37 | paymentMethod: "PayPal", 38 | }, 39 | { 40 | invoice: "INV006", 41 | paymentStatus: "Pending", 42 | totalAmount: "$200.00", 43 | paymentMethod: "Bank Transfer", 44 | }, 45 | { 46 | invoice: "INV007", 47 | paymentStatus: "Unpaid", 48 | totalAmount: "$300.00", 49 | paymentMethod: "Credit Card", 50 | }, 51 | ]; 52 | 53 | return ( 54 | 55 | A list of your recent invoices. 56 | 57 | 58 | Invoice 59 | Status 60 | Method 61 | Amount 62 | 63 | 64 | 65 | {invoices.map((invoice) => ( 66 | 67 | {invoice.invoice} 68 | {invoice.paymentStatus} 69 | {invoice.paymentMethod} 70 | 71 | {invoice.totalAmount} 72 | 73 | 74 | ))} 75 | 76 |
77 | ); 78 | }, 79 | }; 80 | 81 | export default meta; 82 | 83 | type Story = StoryObj; 84 | 85 | export const Default: Story = {}; 86 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/text.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Text, type TextProps } from "@fellipeutaka/ui/text"; 2 | import type { Meta, StoryObj } from "@storybook/react"; 3 | 4 | type TextVariant = Required; 5 | type TextElement = Required; 6 | 7 | const meta: Meta = { 8 | title: "Components/Text", 9 | component: Text, 10 | args: { 11 | children: "Text", 12 | variant: "p", 13 | as: "p", 14 | }, 15 | argTypes: { 16 | variant: { 17 | control: { type: "select" }, 18 | options: ["blockquote", "label", "p"] satisfies TextVariant[], 19 | }, 20 | as: { 21 | control: { type: "select" }, 22 | options: ["span", "label", "p"] satisfies TextElement[], 23 | description: "The HTML element to use for the component.", 24 | table: { 25 | type: "string", 26 | }, 27 | }, 28 | asChild: { 29 | table: { 30 | disable: true, 31 | }, 32 | }, 33 | }, 34 | }; 35 | 36 | export default meta; 37 | 38 | type Story = StoryObj; 39 | 40 | export const Default: Story = {}; 41 | -------------------------------------------------------------------------------- /apps/docs/src/stories/components/textarea.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@fellipeutaka/ui/label"; 2 | import { Textarea, type TextareaProps } from "@fellipeutaka/ui/textarea"; 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Textarea", 7 | component: Textarea, 8 | args: { 9 | disabled: false, 10 | placeholder: "Type your message here.", 11 | }, 12 | }; 13 | 14 | export default meta; 15 | 16 | type Story = StoryObj; 17 | 18 | export const Default: Story = {}; 19 | 20 | export const WithLabel: Story = { 21 | render(props) { 22 | return ( 23 |
24 | 25 |