From 8f4a18da25aebbbcd80c1de28f78ec33746c3487 Mon Sep 17 00:00:00 2001 From: Din Date: Wed, 3 Apr 2024 15:33:51 +0700 Subject: [PATCH] example --- apps/web/components/example.tsx | 97 ++++++++ apps/web/examples/accordion-demo.tsx | 29 +++ apps/web/package.json | 3 +- apps/web/pages/ui/accordion.mdx | 25 +- apps/web/tsconfig.json | 9 +- apps/web/vocs.config.ts | 10 + packages/react-ui/package.json | 17 +- packages/react-ui/ui/accordion.tsx | 52 +++++ packages/react-ui/ui/button.tsx | 14 -- packages/react-ui/utils.ts | 6 + pnpm-lock.yaml | 329 ++++++++++++++++++++++----- 11 files changed, 515 insertions(+), 76 deletions(-) create mode 100644 apps/web/components/example.tsx create mode 100644 apps/web/examples/accordion-demo.tsx create mode 100644 packages/react-ui/ui/accordion.tsx delete mode 100644 packages/react-ui/ui/button.tsx create mode 100644 packages/react-ui/utils.ts diff --git a/apps/web/components/example.tsx b/apps/web/components/example.tsx new file mode 100644 index 0000000..beb6c48 --- /dev/null +++ b/apps/web/components/example.tsx @@ -0,0 +1,97 @@ +import { Suspense, lazy } from 'react' +import { codeToHtml } from 'shiki' +import githubDarkDimmed from 'shiki/themes/github-dark-dimmed.mjs' + +const exampleComponents = import.meta.glob('../examples/**/*.tsx') as { + [key: string]: () => Promise<{ + default: React.ComponentType + }> +} + +const exampleCodes = import.meta.glob('../examples/**/*.tsx', { + query: '?raw', + import: 'default', +}) as { + [key: string]: () => Promise +} + +export function Example({ path }: { path: string }) { + const fullPath = `../examples/${path}.tsx` + + return ( +
+ + +
+ ) +} + +function ExamplePreview(props: { fullPath: string }) { + const loadComponent = exampleComponents[props.fullPath] + + if (!loadComponent) { + throw new Error(`Component does not exists on [${props.fullPath}]`) + } + + const Component = lazy(loadComponent) + + return ( + // TODO + + + + ) +} + +function ExampleCode(props: { fullPath: string }) { + const loadCode = exampleCodes[props.fullPath] + + if (!loadCode) { + throw new Error(`Component does not exists on [${props.fullPath}]`) + } + + const Code = lazy(async () => { + const code = await loadCode() + const html = await codeToHtml(code, { + lang: 'tsx', + theme: 'github-light', + themes: { + light: 'github-light', + dark: githubDarkDimmed, + // dim: 'github-dimmed', + }, + transformers: [ + { + pre: (el) => { + el.properties.class += ' vocs_Pre' + return el + }, + code: (el) => { + el.properties.class += ' vocs_Code' + return el + }, + span: (el) => { + el.properties.class += ' vocs_Span' + return el + }, + }, + ], + }) + return { + default: () => { + return ( +
+
+
+ ) + }, + } + }) + + return ( + // TODO + + + + ) +} diff --git a/apps/web/examples/accordion-demo.tsx b/apps/web/examples/accordion-demo.tsx new file mode 100644 index 0000000..4736004 --- /dev/null +++ b/apps/web/examples/accordion-demo.tsx @@ -0,0 +1,29 @@ +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@dinui/react/accordion' + +export default function AccordionDemo() { + return ( + + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + + Is it styled? + + Yes. It comes with default styles that matches the other components' aesthetic. + + + + Is it animated? + + Yes. It's animated by default, but you can disable it if you prefer. + + + + ) +} diff --git a/apps/web/package.json b/apps/web/package.json index d0b5217..e432796 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -18,6 +18,7 @@ "autoprefixer": "^10.4.19", "postcss": "^8.4.38", "tailwindcss": "^3.4.3", - "typescript": "^5.4.3" + "typescript": "^5.4.3", + "vite": "^5.2.7" } } diff --git a/apps/web/pages/ui/accordion.mdx b/apps/web/pages/ui/accordion.mdx index 2b2d9c4..d9abadc 100644 --- a/apps/web/pages/ui/accordion.mdx +++ b/apps/web/pages/ui/accordion.mdx @@ -1,5 +1,28 @@ --- title: Accordion +description: A vertically stacked set of interactive headings that each reveal a section of content. --- -# Accordion +import { Example } from '@web/components/example' + + + +## Usage + +```tsx +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@dinui/react/accordion' +``` + +```tsx + + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + +``` diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index d9c3ab4..c7f1384 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": [], + "types": ["vite/client"], "module": "ESNext", "skipLibCheck": true, @@ -14,6 +14,11 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", + "paths": { + "@web/*": ["./*"], + "@dinui/react/utils": ["../../packages/react-ui/utils"], + "@dinui/react/*": ["../../packages/react-ui/ui/*"] + }, /* Linting */ "strict": true, @@ -21,5 +26,5 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "exclude": ["**/*.js", "**/*.cjs", "**/*.mjs"] + "exclude": ["**/*.js", "**/*.cjs", "**/*.mjs", "vocs.config.ts"] } diff --git a/apps/web/vocs.config.ts b/apps/web/vocs.config.ts index 7a171f3..5a57ae1 100644 --- a/apps/web/vocs.config.ts +++ b/apps/web/vocs.config.ts @@ -1,7 +1,17 @@ +import { resolve } from 'path' import { defineConfig } from 'vocs' export default defineConfig({ rootDir: '.', + vite: { + resolve: { + alias: { + '@web': resolve(__dirname, './'), + '@dinui/react/utils': resolve(__dirname, '../../packages/react-ui/utils'), + '@dinui/react': resolve(__dirname, '../../packages/react-ui/ui'), + }, + }, + }, title: 'DinUI', sidebar: [ { diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 389180a..ec19f5f 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -17,10 +17,13 @@ }, "license": "MIT", "exports": { - "./button": { - "default": "./build/ui/button.jsx", - "import": "./build/ui/button.jsx", - "types": "./build/ui/button.d.ts" + "./accordion": { + "types": "./build/ui/accordion.d.ts", + "default": "./build/ui/accordion.jsx" + }, + "./utils": { + "types": "./build/utils.d.ts", + "default": "./build/utils.jsx" } }, "scripts": { @@ -32,6 +35,10 @@ "typescript": "^5.4.2" }, "dependencies": { - "react": "^18.2.0" + "@radix-ui/react-accordion": "^1.1.2", + "clsx": "^2.1.0", + "react": "^18.2.0", + "tailwind-merge": "^2.2.2", + "tailwind-variants": "^0.2.1" } } diff --git a/packages/react-ui/ui/accordion.tsx b/packages/react-ui/ui/accordion.tsx new file mode 100644 index 0000000..32fcf14 --- /dev/null +++ b/packages/react-ui/ui/accordion.tsx @@ -0,0 +1,52 @@ +'use client' + +import { cx } from '../utils' +import * as AccordionPrimitive from '@radix-ui/react-accordion' +import { ChevronDownIcon } from '@radix-ui/react-icons' +import * as React from 'react' + +const Accordion = AccordionPrimitive.Root + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AccordionItem.displayName = 'AccordionItem' + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180', + className, + )} + {...props} + > + {children} + + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/packages/react-ui/ui/button.tsx b/packages/react-ui/ui/button.tsx deleted file mode 100644 index 32872e4..0000000 --- a/packages/react-ui/ui/button.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type * as React from 'react' - -type ButtonProps = React.ComponentPropsWithRef<'button'> - -export function Button(props: ButtonProps) { - return ( -