diff --git a/packages/components/tabs/.eslintrc.js b/packages/components/tabs/.eslintrc.js new file mode 100644 index 000000000..6f452d4d0 --- /dev/null +++ b/packages/components/tabs/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: ['custom/react'], +} diff --git a/packages/components/tabs/package.json b/packages/components/tabs/package.json new file mode 100644 index 000000000..55063b9d6 --- /dev/null +++ b/packages/components/tabs/package.json @@ -0,0 +1,43 @@ +{ + "name": "@consolelabs/tabs", + "version": "0.0.1", + "sideEffects": false, + "main": "src/index.ts", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "license": "MIT", + "scripts": { + "build": "tsup src --dts", + "build:fast": "tsup src", + "dev": "pnpm build:fast -- --watch", + "lint": "eslint src/", + "clean": "rimraf dist .turbo", + "typecheck": "tsc --noEmit", + "prepack": "clean-package", + "postpack": "clean-package restore" + }, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@consolelabs/icons": "workspace:*", + "@consolelabs/theme": "workspace:*", + "clean-package": "^2.2.0", + "eslint-config-custom": "workspace:*", + "prettier": "^3.0.3", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tsconfig": "workspace:*" + }, + "dependencies": { + "@radix-ui/react-tabs": "^1.0.4", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0" + }, + "clean-package": "../../../clean-package.config.json" +} diff --git a/packages/components/tabs/src/index.ts b/packages/components/tabs/src/index.ts new file mode 100644 index 000000000..3fb765f1b --- /dev/null +++ b/packages/components/tabs/src/index.ts @@ -0,0 +1 @@ +export * from './tabs' diff --git a/packages/components/tabs/src/tabs.tsx b/packages/components/tabs/src/tabs.tsx new file mode 100644 index 000000000..ef4a1adfe --- /dev/null +++ b/packages/components/tabs/src/tabs.tsx @@ -0,0 +1,28 @@ +import * as RadixTabs from '@radix-ui/react-tabs' +import React from 'react' +import { tabs, TabTriggerProps } from '@consolelabs/theme' + +const Tabs = RadixTabs.Root +const TabList = RadixTabs.List +const TabContent = RadixTabs.Content + +const TabTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & TabTriggerProps +>(({ className, variant, disabled, ...props }, ref) => { + const { tabTriggerVariants, tabTriggerWrapperClassName } = tabs + + return ( +
+ +
+ ) +}) +TabTrigger.displayName = RadixTabs.Trigger.displayName + +export { Tabs, TabList, TabContent, TabTrigger } diff --git a/packages/components/tabs/stories/tabs.stories.tsx b/packages/components/tabs/stories/tabs.stories.tsx new file mode 100644 index 000000000..815cf3f6f --- /dev/null +++ b/packages/components/tabs/stories/tabs.stories.tsx @@ -0,0 +1,79 @@ +import { Tabs, TabList, TabTrigger, TabContent } from '../src/tabs' +import { IconCoding, IconSetting, IconUser } from '@consolelabs/icons' + +export default { + title: 'ui/Tabs', +} + +export function Default() { + return ( +
+
+ + + + + Account + + + + Documents + + + + Settings + + + +
+ +
+ + Make changes to your account. + + + Access and update your documents. + + + Edit your profile or update contact information. + +
+ +
+ +
+ + + + Account + + + Documents + + + Settings + + + +
+ +
+ + Make changes to your account. + + + Access and update your documents. + + + Edit your profile or update contact information. + +
+ +
+
+ ) +} + +Default.story = { + name: 'default', +} diff --git a/packages/components/tabs/tsconfig.json b/packages/components/tabs/tsconfig.json new file mode 100644 index 000000000..871cb5775 --- /dev/null +++ b/packages/components/tabs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "tsconfig/react-library.json", + "include": ["src", "index.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/components/tabs/tsup.config.ts b/packages/components/tabs/tsup.config.ts new file mode 100644 index 000000000..c8289764e --- /dev/null +++ b/packages/components/tabs/tsup.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'tsup' + +export default defineConfig(() => ({ + clean: true, + target: 'es2019', + format: ['cjs', 'esm'], +})) diff --git a/packages/theme/src/components/index.ts b/packages/theme/src/components/index.ts index 4f9177373..628ab797c 100644 --- a/packages/theme/src/components/index.ts +++ b/packages/theme/src/components/index.ts @@ -9,3 +9,4 @@ export * from './input-field' export * from './list' export * from './toggle-button' export * from './select' +export * from './tabs' diff --git a/packages/theme/src/components/tabs.ts b/packages/theme/src/components/tabs.ts new file mode 100644 index 000000000..968567389 --- /dev/null +++ b/packages/theme/src/components/tabs.ts @@ -0,0 +1,53 @@ +import { VariantProps, cva } from 'class-variance-authority' + +const tabTriggerVariants = cva( + [ + 'flex flex-1 items-center justify-center gap-x-1 text-sm font-medium px-1 py-1', + ], + { + variants: { + variant: { + solid: '', + link: '', + }, + disabled: { + true: '', + false: '', + }, + }, + compoundVariants: [ + { + disabled: true, + className: 'text-neutral-400 cursor-not-allowed', + }, + { + disabled: false, + variant: 'solid', + className: + 'rounded text-neutral-600 hover:text-neutral-500 hover:bg-neutral-150 data-[state=active]:text-neutral-800 data-[state=active]:hover:text-neutral-500', + }, + { + disabled: false, + variant: 'link', + className: + 'text-neutral-600 hover:text-neutral-700 data-[state=active]:text-neutral-800 data-[state=active]:hover:text-neutral-700', + }, + ], + defaultVariants: { + variant: 'link', + disabled: false, + }, + }, +) + +const tabTriggerWrapperClassName = + 'inline-flex flex-1 px-2 border-r border-r-neutral-200 last:border-none sm:border-none' + +const tabs = { + tabTriggerVariants, + tabTriggerWrapperClassName, +} + +export type TabTriggerProps = VariantProps + +export { tabs } diff --git a/packages/ui/package.json b/packages/ui/package.json index a65d1b398..9fe95d2f6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -59,12 +59,13 @@ "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", + "@tanstack/react-table": "^8.10.7", "@uidotdev/usehooks": "^2.4.0", "browser-string-hexer": "^1.0.0", "bs58": "^5.0.0", - "@tanstack/react-table": "^8.10.7", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "vaul": "^0.7.2", diff --git a/packages/ui/src/tabs/index.ts b/packages/ui/src/tabs/index.ts new file mode 100644 index 000000000..246dcbc29 --- /dev/null +++ b/packages/ui/src/tabs/index.ts @@ -0,0 +1,2 @@ +export * from './tabs' +export * from './trigger' diff --git a/packages/ui/src/tabs/tabs.stories.tsx b/packages/ui/src/tabs/tabs.stories.tsx new file mode 100644 index 000000000..3430417c0 --- /dev/null +++ b/packages/ui/src/tabs/tabs.stories.tsx @@ -0,0 +1,39 @@ +import { Tabs, TabList, TabTrigger, TabContent } from '.' + +export default { + title: 'ui/Tabs', +} + +export function Default() { + return ( +
+ + + Account + + Documents + + + Settings + + + +
+ +
+ Make changes to your account. + + Access and update your documents. + + + Edit your profile or update contact information. + +
+ +
+ ) +} + +Default.story = { + name: 'default', +} diff --git a/packages/ui/src/tabs/tabs.tsx b/packages/ui/src/tabs/tabs.tsx new file mode 100644 index 000000000..1c140b3da --- /dev/null +++ b/packages/ui/src/tabs/tabs.tsx @@ -0,0 +1,7 @@ +import * as RadixTabs from '@radix-ui/react-tabs' + +const Tabs = RadixTabs.Root +const TabList = RadixTabs.List +const TabContent = RadixTabs.Content + +export { Tabs, TabList, TabContent } diff --git a/packages/ui/src/tabs/trigger.tsx b/packages/ui/src/tabs/trigger.tsx new file mode 100644 index 000000000..fbeb98d86 --- /dev/null +++ b/packages/ui/src/tabs/trigger.tsx @@ -0,0 +1,64 @@ +import * as RadixTabs from '@radix-ui/react-tabs' +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' +import * as React from 'react' + +const tabTrigger = cva( + [ + 'flex flex-1 items-center justify-center gap-x-1 text-sm font-medium px-1 py-0.5', + ], + { + variants: { + variant: { + solid: '', + link: '', + }, + disabled: { + true: '', + false: '', + }, + }, + compoundVariants: [ + { + disabled: true, + className: 'text-neutral-400 cursor-not-allowed', + }, + { + disabled: false, + variant: 'solid', + className: + 'rounded text-neutral-600 hover:text-neutral-500 hover:bg-neutral-150 data-[state=active]:text-neutral-800', + }, + { + disabled: false, + variant: 'link', + className: + 'text-neutral-600 hover:text-neutral-700 data-[state=active]:text-neutral-800', + }, + ], + defaultVariants: { + variant: 'link', + disabled: false, + }, + }, +) + +type Props = React.ComponentPropsWithoutRef & + VariantProps + +const TabTrigger = React.forwardRef< + React.ElementRef, + Props +>(({ className, variant, disabled, ...props }, ref) => ( +
+ +
+)) +TabTrigger.displayName = RadixTabs.Trigger.displayName + +export { TabTrigger } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8f737d6d..8b396f752 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -951,6 +951,43 @@ importers: specifier: workspace:* version: link:../../tsconfig + packages/components/tabs: + dependencies: + '@radix-ui/react-tabs': + specifier: ^1.0.4 + version: 1.0.4(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.0.0 + version: 2.0.0 + devDependencies: + '@consolelabs/icons': + specifier: workspace:* + version: link:../../icons + '@consolelabs/theme': + specifier: workspace:* + version: link:../../theme + clean-package: + specifier: ^2.2.0 + version: 2.2.0 + eslint-config-custom: + specifier: workspace:* + version: link:../../eslint-config-custom + prettier: + specifier: ^3.0.3 + version: 3.0.3 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + tsconfig: + specifier: workspace:* + version: link:../../tsconfig + packages/components/toggle-button: dependencies: '@radix-ui/react-toggle-group': @@ -1302,6 +1339,9 @@ importers: '@radix-ui/react-switch': specifier: ^1.0.3 version: 1.0.3(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-tabs': + specifier: ^1.0.4 + version: 1.0.4(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-toggle-group': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) @@ -5748,6 +5788,33 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-tabs@1.0.4(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.28)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.28)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.28)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.4)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.28)(react@18.2.0) + '@types/react': 18.2.28 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.28)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} peerDependencies: