From 767b6f4820ff4b9bfbb4802171f48ef69eeceaf3 Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Thu, 4 Sep 2025 17:18:50 +0530 Subject: [PATCH 1/9] feat: docs beta setup + layout --- apps/www-beta/.eslintrc.json | 3 + apps/www-beta/.gitignore | 44 + apps/www-beta/README.md | 36 + apps/www-beta/next.config.ts | 43 + apps/www-beta/package.json | 34 + apps/www-beta/public/assets/logo.png | Bin 0 -> 7885 bytes apps/www-beta/public/assets/logo.svg | 20 + apps/www-beta/source.config.ts | 5 + apps/www-beta/src/app/(home)/page.module.css | 46 + apps/www-beta/src/app/(home)/page.tsx | 24 + apps/www-beta/src/app/layout.tsx | 36 + apps/www-beta/src/assets/github.tsx | 22 + apps/www-beta/src/components/kbd/index.ts | 1 + .../src/components/kbd/kbd.module.css | 11 + apps/www-beta/src/components/kbd/kbd.tsx | 51 + apps/www-beta/src/components/logo/index.ts | 1 + .../src/components/logo/logo.module.css | 17 + apps/www-beta/src/components/logo/logo.tsx | 25 + apps/www-beta/src/components/navbar/index.ts | 1 + .../src/components/navbar/navbar.module.css | 51 + .../www-beta/src/components/navbar/navbar.tsx | 78 + apps/www-beta/src/components/theme.tsx | 78 + .../content/docs/components/amount/demo.ts | 161 ++ .../content/docs/components/amount/index.mdx | 70 + .../content/docs/components/amount/props.ts | 68 + .../docs/components/announcement-bar/demo.ts | 23 + .../components/announcement-bar/index.mdx | 26 + .../docs/components/announcement-bar/props.ts | 24 + .../content/docs/components/avatar/demo.ts | 138 ++ .../content/docs/components/avatar/index.mdx | 68 + .../content/docs/components/avatar/props.ts | 65 + .../src/content/docs/components/badge/demo.ts | 83 + .../content/docs/components/badge/index.mdx | 50 + .../content/docs/components/badge/props.ts | 31 + .../docs/components/breadcrumb/demo.ts | 135 ++ .../docs/components/breadcrumb/index.mdx | 81 + .../docs/components/breadcrumb/props.ts | 70 + .../content/docs/components/button/demo.ts | 125 ++ .../content/docs/components/button/index.mdx | 63 + .../content/docs/components/button/props.ts | 49 + .../content/docs/components/calendar/demo.ts | 102 + .../docs/components/calendar/index.mdx | 77 + .../content/docs/components/calendar/props.ts | 117 ++ .../content/docs/components/callout/demo.ts | 105 + .../content/docs/components/callout/index.mdx | 72 + .../content/docs/components/callout/props.ts | 53 + .../content/docs/components/checkbox/demo.ts | 48 + .../docs/components/checkbox/index.mdx | 31 + .../content/docs/components/checkbox/props.ts | 21 + .../src/content/docs/components/chip/demo.ts | 110 + .../content/docs/components/chip/index.mdx | 70 + .../src/content/docs/components/chip/props.ts | 48 + .../docs/components/color-picker/demo.ts | 83 + .../docs/components/color-picker/index.mdx | 59 + .../docs/components/color-picker/props.ts | 42 + .../content/docs/components/command/demo.ts | 50 + .../content/docs/components/command/index.mdx | 19 + .../content/docs/components/command/props.ts | 0 .../content/docs/components/container/demo.ts | 105 + .../docs/components/container/index.mdx | 40 + .../docs/components/container/props.ts | 26 + .../docs/components/copy-button/demo.ts | 50 + .../docs/components/copy-button/index.mdx | 36 + .../docs/components/copy-button/props.ts | 18 + .../content/docs/components/datatable/demo.ts | 6 + .../docs/components/datatable/index.mdx | 191 ++ .../docs/components/datatable/props.ts | 74 + .../content/docs/components/dialog/demo.ts | 142 ++ .../content/docs/components/dialog/index.mdx | 86 + .../content/docs/components/dialog/props.ts | 88 + .../content/docs/components/dropdown/demo.ts | 447 ++++ .../docs/components/dropdown/index.mdx | 117 ++ .../content/docs/components/dropdown/props.ts | 134 ++ .../docs/components/empty-state/demo.ts | 66 + .../docs/components/empty-state/index.mdx | 18 + .../docs/components/empty-state/props.ts | 39 + .../src/content/docs/components/flex/demo.ts | 60 + .../content/docs/components/flex/index.mdx | 24 + .../src/content/docs/components/flex/props.ts | 19 + .../docs/components/fliter-chip/demo.ts | 150 ++ .../docs/components/fliter-chip/index.mdx | 48 + .../docs/components/fliter-chip/props.ts | 38 + .../src/content/docs/components/grid/demo.ts | 66 + .../content/docs/components/grid/index.mdx | 30 + .../src/content/docs/components/grid/props.ts | 156 ++ .../content/docs/components/headline/demo.ts | 52 + .../docs/components/headline/index.mdx | 28 + .../content/docs/components/headline/props.ts | 28 + .../docs/components/icon-button/demo.ts | 45 + .../docs/components/icon-button/index.mdx | 56 + .../docs/components/icon-button/props.ts | 19 + .../src/content/docs/components/image/demo.ts | 109 + .../content/docs/components/image/index.mdx | 78 + .../content/docs/components/image/props.ts | 31 + .../content/docs/components/indicator/demo.ts | 59 + .../docs/components/indicator/index.mdx | 59 + .../docs/components/indicator/props.ts | 19 + .../docs/components/input-field/demo.ts | 140 ++ .../docs/components/input-field/index.mdx | 92 + .../docs/components/input-field/props.ts | 46 + .../src/content/docs/components/label/demo.ts | 45 + .../content/docs/components/label/index.mdx | 42 + .../content/docs/components/label/props.ts | 22 + .../src/content/docs/components/link/demo.ts | 86 + .../content/docs/components/link/index.mdx | 63 + .../src/content/docs/components/link/props.ts | 13 + .../src/content/docs/components/list/demo.ts | 36 + .../content/docs/components/list/index.mdx | 50 + .../src/content/docs/components/list/props.ts | 48 + .../content/docs/components/popover/demo.ts | 132 ++ .../content/docs/components/popover/index.mdx | 51 + .../content/docs/components/popover/props.ts | 44 + .../src/content/docs/components/radio/demo.ts | 95 + .../content/docs/components/radio/index.mdx | 44 + .../content/docs/components/radio/props.ts | 42 + .../content/docs/components/search/demo.ts | 40 + .../content/docs/components/search/index.mdx | 60 + .../content/docs/components/search/props.ts | 28 + .../content/docs/components/select/demo.ts | 228 +++ .../content/docs/components/select/index.mdx | 116 ++ .../content/docs/components/select/props.ts | 99 + .../content/docs/components/separator/demo.ts | 56 + .../docs/components/separator/index.mdx | 47 + .../docs/components/separator/props.ts | 19 + .../src/content/docs/components/sheet/demo.ts | 90 + .../content/docs/components/sheet/index.mdx | 50 + .../content/docs/components/sheet/props.ts | 24 + .../content/docs/components/sidebar/demo.ts | 152 ++ .../content/docs/components/sidebar/index.mdx | 71 + .../content/docs/components/sidebar/props.ts | 78 + .../content/docs/components/sidepanel/demo.ts | 63 + .../docs/components/sidepanel/index.mdx | 32 + .../docs/components/sidepanel/props.ts | 39 + .../content/docs/components/skeleton/demo.ts | 105 + .../docs/components/skeleton/index.mdx | 95 + .../content/docs/components/skeleton/props.ts | 75 + .../content/docs/components/slider/demo.ts | 75 + .../content/docs/components/slider/index.mdx | 66 + .../content/docs/components/slider/props.ts | 40 + .../content/docs/components/spinner/demo.ts | 59 + .../content/docs/components/spinner/index.mdx | 39 + .../content/docs/components/spinner/props.ts | 16 + .../content/docs/components/switch/demo.ts | 64 + .../content/docs/components/switch/index.mdx | 48 + .../content/docs/components/switch/props.ts | 25 + .../src/content/docs/components/table/demo.ts | 104 + .../content/docs/components/table/index.mdx | 58 + .../content/docs/components/table/props.ts | 39 + .../src/content/docs/components/tabs/demo.ts | 79 + .../content/docs/components/tabs/index.mdx | 52 + .../src/content/docs/components/tabs/props.ts | 40 + .../src/content/docs/components/text/demo.ts | 151 ++ .../content/docs/components/text/index.mdx | 59 + .../src/content/docs/components/text/props.ts | 66 + .../content/docs/components/textarea/demo.ts | 82 + .../docs/components/textarea/index.mdx | 50 + .../content/docs/components/textarea/props.ts | 43 + .../src/content/docs/components/toast/demo.ts | 15 + .../content/docs/components/toast/index.mdx | 42 + .../content/docs/components/toast/props.ts | 96 + .../content/docs/components/tooltip/demo.ts | 147 ++ .../content/docs/components/tooltip/index.mdx | 62 + .../content/docs/components/tooltip/props.ts | 95 + .../src/content/docs/getting-started.mdx | 48 + apps/www-beta/src/content/docs/index.mdx | 8 + apps/www-beta/src/content/docs/meta.json | 9 + apps/www-beta/src/lib/source.ts | 7 + apps/www-beta/src/lib/utils.ts | 33 + apps/www-beta/src/styles.css | 16 + apps/www-beta/tsconfig.json | 31 + .../components/command/command.module.css | 9 +- pnpm-lock.yaml | 1799 ++++++++++++++++- 172 files changed, 12201 insertions(+), 50 deletions(-) create mode 100644 apps/www-beta/.eslintrc.json create mode 100644 apps/www-beta/.gitignore create mode 100644 apps/www-beta/README.md create mode 100644 apps/www-beta/next.config.ts create mode 100644 apps/www-beta/package.json create mode 100644 apps/www-beta/public/assets/logo.png create mode 100644 apps/www-beta/public/assets/logo.svg create mode 100644 apps/www-beta/source.config.ts create mode 100644 apps/www-beta/src/app/(home)/page.module.css create mode 100644 apps/www-beta/src/app/(home)/page.tsx create mode 100644 apps/www-beta/src/app/layout.tsx create mode 100644 apps/www-beta/src/assets/github.tsx create mode 100644 apps/www-beta/src/components/kbd/index.ts create mode 100644 apps/www-beta/src/components/kbd/kbd.module.css create mode 100644 apps/www-beta/src/components/kbd/kbd.tsx create mode 100644 apps/www-beta/src/components/logo/index.ts create mode 100644 apps/www-beta/src/components/logo/logo.module.css create mode 100644 apps/www-beta/src/components/logo/logo.tsx create mode 100644 apps/www-beta/src/components/navbar/index.ts create mode 100644 apps/www-beta/src/components/navbar/navbar.module.css create mode 100644 apps/www-beta/src/components/navbar/navbar.tsx create mode 100644 apps/www-beta/src/components/theme.tsx create mode 100644 apps/www-beta/src/content/docs/components/amount/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/amount/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/amount/props.ts create mode 100644 apps/www-beta/src/content/docs/components/announcement-bar/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/announcement-bar/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/announcement-bar/props.ts create mode 100644 apps/www-beta/src/content/docs/components/avatar/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/avatar/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/avatar/props.ts create mode 100644 apps/www-beta/src/content/docs/components/badge/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/badge/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/badge/props.ts create mode 100644 apps/www-beta/src/content/docs/components/breadcrumb/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/breadcrumb/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/breadcrumb/props.ts create mode 100644 apps/www-beta/src/content/docs/components/button/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/button/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/button/props.ts create mode 100644 apps/www-beta/src/content/docs/components/calendar/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/calendar/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/calendar/props.ts create mode 100644 apps/www-beta/src/content/docs/components/callout/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/callout/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/callout/props.ts create mode 100644 apps/www-beta/src/content/docs/components/checkbox/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/checkbox/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/checkbox/props.ts create mode 100644 apps/www-beta/src/content/docs/components/chip/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/chip/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/chip/props.ts create mode 100644 apps/www-beta/src/content/docs/components/color-picker/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/color-picker/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/color-picker/props.ts create mode 100644 apps/www-beta/src/content/docs/components/command/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/command/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/command/props.ts create mode 100644 apps/www-beta/src/content/docs/components/container/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/container/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/container/props.ts create mode 100644 apps/www-beta/src/content/docs/components/copy-button/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/copy-button/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/copy-button/props.ts create mode 100644 apps/www-beta/src/content/docs/components/datatable/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/datatable/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/datatable/props.ts create mode 100644 apps/www-beta/src/content/docs/components/dialog/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/dialog/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/dialog/props.ts create mode 100644 apps/www-beta/src/content/docs/components/dropdown/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/dropdown/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/dropdown/props.ts create mode 100644 apps/www-beta/src/content/docs/components/empty-state/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/empty-state/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/empty-state/props.ts create mode 100644 apps/www-beta/src/content/docs/components/flex/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/flex/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/flex/props.ts create mode 100644 apps/www-beta/src/content/docs/components/fliter-chip/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/fliter-chip/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/fliter-chip/props.ts create mode 100644 apps/www-beta/src/content/docs/components/grid/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/grid/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/grid/props.ts create mode 100644 apps/www-beta/src/content/docs/components/headline/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/headline/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/headline/props.ts create mode 100644 apps/www-beta/src/content/docs/components/icon-button/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/icon-button/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/icon-button/props.ts create mode 100644 apps/www-beta/src/content/docs/components/image/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/image/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/image/props.ts create mode 100644 apps/www-beta/src/content/docs/components/indicator/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/indicator/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/indicator/props.ts create mode 100644 apps/www-beta/src/content/docs/components/input-field/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/input-field/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/input-field/props.ts create mode 100644 apps/www-beta/src/content/docs/components/label/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/label/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/label/props.ts create mode 100644 apps/www-beta/src/content/docs/components/link/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/link/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/link/props.ts create mode 100644 apps/www-beta/src/content/docs/components/list/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/list/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/list/props.ts create mode 100644 apps/www-beta/src/content/docs/components/popover/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/popover/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/popover/props.ts create mode 100644 apps/www-beta/src/content/docs/components/radio/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/radio/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/radio/props.ts create mode 100644 apps/www-beta/src/content/docs/components/search/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/search/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/search/props.ts create mode 100644 apps/www-beta/src/content/docs/components/select/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/select/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/select/props.ts create mode 100644 apps/www-beta/src/content/docs/components/separator/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/separator/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/separator/props.ts create mode 100644 apps/www-beta/src/content/docs/components/sheet/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/sheet/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/sheet/props.ts create mode 100644 apps/www-beta/src/content/docs/components/sidebar/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/sidebar/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/sidebar/props.ts create mode 100644 apps/www-beta/src/content/docs/components/sidepanel/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/sidepanel/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/sidepanel/props.ts create mode 100644 apps/www-beta/src/content/docs/components/skeleton/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/skeleton/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/skeleton/props.ts create mode 100644 apps/www-beta/src/content/docs/components/slider/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/slider/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/slider/props.ts create mode 100644 apps/www-beta/src/content/docs/components/spinner/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/spinner/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/spinner/props.ts create mode 100644 apps/www-beta/src/content/docs/components/switch/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/switch/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/switch/props.ts create mode 100644 apps/www-beta/src/content/docs/components/table/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/table/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/table/props.ts create mode 100644 apps/www-beta/src/content/docs/components/tabs/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/tabs/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/tabs/props.ts create mode 100644 apps/www-beta/src/content/docs/components/text/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/text/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/text/props.ts create mode 100644 apps/www-beta/src/content/docs/components/textarea/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/textarea/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/textarea/props.ts create mode 100644 apps/www-beta/src/content/docs/components/toast/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/toast/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/toast/props.ts create mode 100644 apps/www-beta/src/content/docs/components/tooltip/demo.ts create mode 100644 apps/www-beta/src/content/docs/components/tooltip/index.mdx create mode 100644 apps/www-beta/src/content/docs/components/tooltip/props.ts create mode 100644 apps/www-beta/src/content/docs/getting-started.mdx create mode 100644 apps/www-beta/src/content/docs/index.mdx create mode 100644 apps/www-beta/src/content/docs/meta.json create mode 100644 apps/www-beta/src/lib/source.ts create mode 100644 apps/www-beta/src/lib/utils.ts create mode 100644 apps/www-beta/src/styles.css create mode 100644 apps/www-beta/tsconfig.json diff --git a/apps/www-beta/.eslintrc.json b/apps/www-beta/.eslintrc.json new file mode 100644 index 000000000..372241854 --- /dev/null +++ b/apps/www-beta/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/core-web-vitals", "next/typescript"] +} diff --git a/apps/www-beta/.gitignore b/apps/www-beta/.gitignore new file mode 100644 index 000000000..c09047d52 --- /dev/null +++ b/apps/www-beta/.gitignore @@ -0,0 +1,44 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# fumadocs source +.source diff --git a/apps/www-beta/README.md b/apps/www-beta/README.md new file mode 100644 index 000000000..e215bc4cc --- /dev/null +++ b/apps/www-beta/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/apps/www-beta/next.config.ts b/apps/www-beta/next.config.ts new file mode 100644 index 000000000..7576474e3 --- /dev/null +++ b/apps/www-beta/next.config.ts @@ -0,0 +1,43 @@ +import { createMDX } from 'fumadocs-mdx/next'; +import type { NextConfig } from 'next'; + +const nextConfig: NextConfig = { + reactStrictMode: true, + typescript: { + // !! WARN !! + // Dangerously allow production builds to successfully complete even if + // your project has type errors. + // !! WARN !! + ignoreBuildErrors: true + }, + eslint: { + // Warning: This allows production builds to successfully complete even if + // your project has ESLint errors. + ignoreDuringBuilds: true + }, + experimental: { + optimizePackageImports: ['shiki'] + }, + async rewrites() { + return [ + { + source: '/docs/:path*.mdx', + destination: '/llms.mdx/:path*' + }, + { + source: '/docs/:path*.md', + destination: '/llms.mdx/:path*' + } + ]; + } +}; + +const withMDX = createMDX(); +const mdxConfig = withMDX(nextConfig); + +if (mdxConfig.experimental?.turbo) { + mdxConfig.turbopack = mdxConfig.experimental.turbo; + delete mdxConfig.experimental.turbo; +} + +export default mdxConfig; diff --git a/apps/www-beta/package.json b/apps/www-beta/package.json new file mode 100644 index 000000000..915412d0b --- /dev/null +++ b/apps/www-beta/package.json @@ -0,0 +1,34 @@ +{ + "name": "www-beta", + "version": "0.1.0", + "private": true, + "scripts": { + "prebuild": "cd ../.. && npm run build:apsara", + "dev": "next dev --turbopack", + "build": "next build --turbopack", + "start": "next start", + "postinstall": "fumadocs-mdx" + }, + "dependencies": { + "@raystack/apsara": "workspace:*", + "class-variance-authority": "^0.7.1", + "fumadocs-core": "^15.7.7", + "fumadocs-mdx": "^11.8.2", + "fumadocs-ui": "^15.7.8", + "lucide-react": "^0.477.0", + "next": "15.5.2", + "next-themes": "^0.4.4", + "react": "19.1.0", + "react-dom": "19.1.0" + }, + "devDependencies": { + "@types/mdx": "^2.0.13", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5.7.3" + }, + "engines": { + "node": ">=22" + } +} diff --git a/apps/www-beta/public/assets/logo.png b/apps/www-beta/public/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..61cad6a697b8027bc137145470b0014be5a372f0 GIT binary patch literal 7885 zcmV;;9x~yHP)@~0drDELIAGL9O(c600d`2O+f$vv5yP*SNB$5?3&02*mSj#ffjQP_;?InicqjIo^ zMP-01O*7Zb#Iw=`6i}#m2SvdUW<=yAxc}#SW-bnwJ7=G}=iYnvKJ)vm_4SU!%$ak~ z*}uDg=lA>V-#!L{4OIB@nw9%7QxTg7aZS&Xl&96ck5Cbe7G^&)Z(P%QXp@`4W3MFfpRGqI{$ZS~> z!~ly2jcX#BW;VWhNETUxT!QyzN}-L20k(}4nr66Ev)U6h!df&LWGw`tOr(6>?W@6; z5(Ucmsz&?!5E9Bn3SxAH8skt1LL1;S-E3bqaLWK}GsZNM_dG0=kd&`QklC)-s)o3z zLMw2#OG9S6awyY$tp(w*n<=whe1_;jXm^O=*=2~cA%@s45W}Ihfa}w&U0meiK1yX1nWsb+|48_gQk@xf@N^l zW38qu14-02RYTlTYe+$6z4oXKWHyWyne{}fc?>v)P)-_vPT(6 zTZ}ft=RH?$xX4af{an})_A=Yooe+e!aYgfM9fZh8utijCNpL0tjC8X4-K85Vaz`9n zRxS9oDG|>LQv-Q$7D@{{dNXNn#aj>HN^M?d*E2CMhwJJ3B!bF z8iHUK=c36odkSTw+y*$?*DMHvos4XLEnC@IISr77)l%Cj*iOpVo4!_|43sMfLmzuJ z1T7spbUWxUhLVk z2mAN$M?*sc-gx5;?A*B%J9g~An{U2}ZQHg5uZIpDf)I&eXbR4hlyVrL2g&v2g$6_; z8$5V01`Qg7K7IP2Z{NN+{q)n(vu98A=+Ohm9d{hs!oGd`0wbihZ{Lm=UU&f;Hf+H9 z_3N>2-MZj=N+}3OQI9g@2+LuB8Hn*6hO^kXapN$0^k|G2F(NRwii!%HaKZ^FC!8r8 z8yityUyqe5SE9DI7SBBM40i9{4dF0W)s33a?w1w$2B-S>@2{p!o2DLp^ilQJTW={_ z@!eRpaN$CA{q@%?e=hqR0b zZ+-yCse4i+HNdgQs0`e?z-j zJokB?r*69GCbfCp`>M~@z@R;*Z|1T$8yT&YHl8s*e|FF+Ys;)>3OTNh5N zYm?>*SM94wA+~yzm|*WF~AtnbH!o0VtQnXk1NA zjS}o&>C&Z1iI7&I#CULg_T!Ca-J)O@yeA1T!h&bPLfaB@mHR|Eitp;c&+%dS@Zk{b zf}P)n4I75XAAdaP?&c_+eeL&EixS|$;n|N5`|`|ZKfFf_j=40p(1uyCkQtCOUm6a= zneX0v@5MFOTm!*w1`HU0Q%*T0=+buJzyUZ&$!5U}-1;O6#Dp(%PO^;19heqkZr0&s zebFPLX#mPa&6qJmjL$(>7{Tf!m&RI-(kLPs0LnG7?oi6h+=chf;o8v}6p0i7<(e4M zmcnZH;XQOXJ&}TjC>wN6gJZDO`(1b4h4aok4}#n99?qLLug!a8#Ka8U59p$xp05RP zjGJ%18Plgv4|W<7+^1i^emHpWAXcnc5$puz5WRdo;A>xNKcF+fiEu3OK5En`%%49$ zNIeM2fFGn6U33waEn9}on>WKDv?&SQ?noIp)RLR~=GE2JVdTh>5RwOXak})mQ=j@2gk<6eV}kt-moHxqhw#v}<#m0&e++v_(mp`i z#K3_Aal;KaKu9)xw&%Tej8-4x!VEA4N1*F@#~pVBn_UXYrg!h&!M#5A*kj=kt!5Hh zGr$xadiJ~W$}2Hp!UPD(hueDdeqVn1`WYLi>Vi2d7M#0*A;uspU&Uq!44T!$M%i%j(su z;dvf}_Q&(jKacU_$D_W!9*)3tL~YA&qjC0O8$Cc!KEpn3bxig>#2aJy};V#A}oO$M%E_FIcA!ng( zt^qn>e4PE#=`;j^Fgfo~Uhs%Vyj%mk3J!3=1s4QG*MdNX3>gv>YdgXblbn+?;C0ts z=UOF%P(qjso;Gb-kfe8jBPO|)21wu3dILQ7+;cH;qO+|@g%ZIr(YJ43IDm&1&w(us zFa-y=_~MJD=2JKdHuhys&=FGEFPt*KjvYG&l`n#j57vj$9d&?I_KTJVI0Tk+_St9S zl1nauAmn4rm@&a>2?scAYb_1X`scsPF1rjTopcfeAs^kkb#o;;e%RJJwD?9@_BLw^ z4*B>(Onm&~ABO|b);xZZjoUJ;xCjKE?tc2y*KLc`^Nsk^qAP9xP4{Zkw@GKf&cUTN(Kruj} zP&j5BNJYSU7nB!LO3;Kt;g;5}xS&=W;QQY9J_v#de0;H-3U)TK+5nRrfZ4NW57w+% z6Kp!ky$*`~iQUl9fPek#Ux5d4;e{6#wUL!l3Y#`l`6u5fqOlBJne0T@8$8D&U zt@`%2zpawUfBy3yb;s$y~5ZMUi3y?Y18_a76~#EBEtjvYIcP0X1y$J%k-tPCtaLG``weNQC~e^yfc z`}aTUy>{!?O+E9>GpemDS+XQJR_^i7Jo8NT`s=T&ws7FU0d@QBx97cA6DCYhHZgbZ zT&u^nuLkQgl`Jbt694<(|8VWK*9JTLq1B(+x^*i| z*|~EkuD|~JyvA3I$`4PxNu?U&#>{Z z2^{$B7|tD|N^$&WpM4fz{Nfjb8N4;v6v?KpWR7&ow%SKl3l=O;uH(CIK~SV)$Bv=z z^}O@WQ<+Rg6^bA241yy5fNS;G{s)bL8_)R+u)*dNWGLBH{6w`HJ9cd7 z`{T^TTqoVsLSbI7XV0FY$LGxZ*kg~WLgD%F+E-Rqh8~~kl=}L5Wh3AJ{`ajL&-n~6 zWAh0znd%~qjg9K6tFF?%KR;?|&K9sm9B ze}7Sv`^APIY&MSR7Rp#}fVbRoi*k)ahYm$@-Nug}9|TYeg~@a#y~B>pfDZ#Re1C1%yo z02kPNk{|lehl2V;7ht6Ej5E#%eLoC}ELyZknefLy{!tt8^gK_kU%y@z3Jq%J%$eHz zLAQD5&YjA3=z5PDHOjj2oTJ6o8z3wCw{G34Y=`GKXwab0_d?h0hd=zG(d@xoqAude z0_?y4{qM?zyYIeRJF^ZOHY`Z1xBxwXfddCxH=c7;O#`g5`6Rj2g{uc_=IyuNR>Ox6 z*S?o8ed$X^vpHw9Q%*T0^w^vkfBy5ID-(Y8t6!;3ojQdczgMqb>bd8hQ?5X7L>EZ1 zKvgurw9O~UV8atnJfUobDTJ?m?Q7ciF?#f9qlo18?b`#lFYMTyxft;?VdKV)+Cl-k z%}+h`lyV7r47$=k3pA4kIMMQxR6qXlkCm;k+JcoVVdqcRl=YN_!kLu;4_(Cb3t#wx z(R10$FTbpY3>l)m{;WnaDHMp4`|i8Xx^bLGw7p~{6n2})>)zFee%gCtKa|r_o`4h+wgf#=Rz?+WfByj+kDeaH)&_qDO0AX zZQHgf*Wd@nhd=yb>&9^&9qz|ubv-Bp048~@Qo)EPd$@$1bC)h%)Q^7jBcq7t(@#Gg z{C?Q+8DRL^-~Ogdxbx0CwZ`{>4}8Fh=yN{!p`i;}S)c~A!0KukhVM<6>J*#(`}eC$ zF1bW|&YWRPTsOL_y6`#E4WiFV9lTiJEeskpKd9Oj7?_N+S*#}%)qoyF&aa~33HmZjo&;v zqWRBE+fVrFtFKmZ6D8t#@x>RbS6_Wq6$(=njCks<18ZYVjGJu`d2V6H=FIrugAXd# ziLwgC0#%^})~6y^U&$FLF8=)IKWkmLv(G-;xC|^x#M3mF$luW!AH{s8>+rqmYH=-5 zkb=nKS$v|0#ns<&P*+zM$#vuNl?mVd?sp@to-k=CL3FDp=r+^CaG}Oi$HIjRtsJ{~ z6r>sm^1X5qqD6KGUX`o*xLTA|Rb<%fdK z9pm4(DaF$kcJ0~~$6W807gFSop1a6t`oUXg>x*#=CC|vl; zmJZMuH%qEaBA#@cbp_VUB`#mSTqOn83_DQ&shVx=D69{}P|UBD8m?I2vLW37PNh;t zl_;$7oH})?_PtJ@KHVtd$tFqXpMQSnvFX+(q2*&s9C1Gtasn_}tS?EU7>p=&g$7-| zlTJD*^gQ@n`26$Ft3t_^f$0*(rV&rN&HP{pJ2q!lZm?oGO!PR@PkG*m^7%5ee7e}YiQbu&1UA!n`hlv zZAC#JnAWiVIglDTa%4$zg3RHur9;@?W>Dl8zxahRA80VUV7=JMyn@m zh94#z6Sj@hR#c4;(w3ZLsF*WbwrrUyCNI78QsDOK{_fYm{&i)-v(G*o!X#SrL;oqIfM9Dev=N7AKwqDF!i$1zk5rGj#))f77I;1iOuKX4AbV zu2L|GcyhJ6E~3h%Q8hI+Dv2;ZY}@z@kp~Sm7M!G33^#AyyjiuCsNKLgJDN1nW$({1 zW5#IT3xgsiuwRbO_}D}@t}3EZ!`-ADn*Bnb|FTp8v7cxp6(c1PrHL*pMd+dy3X2AA zyzxeD8CW`#D1cY#DEE#3Yo%n zW4fRS3$RW1Kls59exNmO_GB@sM4{V!?X}lxuhAzy@rlG5A7?+^{j*FdM8x{K(5yIn zm^2Jx8CaB^g&uk25oH3K??!2&%iv6*FzOej=L!48B%#2%HF)oB8;>E%pa7gmM^Mbk z722UcK6tWk*?6qX1F>;y&TX zy5fo}A{z<|cB3S#xj2?3V}(NFV?UL!W79bAzyE$^!jdIRBCVd_>i49=d(G{(Z5)ds zN})iUaYH#9a1% z7?1*>ToJ?hx88bdt2gdXfBKW^-o1P1G1&fa#flZm1h$6Pt)Ad+JtqBPn9iV^t-A)F z{p@FhlC&hl?b&P_dl7Wh>i4MB08p-o3GIA=4K~s3)2C19@3K)#u?HC&d9oSM(^IejrRm}1%5E{p4v3d3Xq33vIu~3NnA3- z4rT12sry+*Jeis(6h=Hb^FZ@qFnjiFqe21ZHgz*Ajk8=WI^u-I5RO&6WL1qKkOH7w z6Q32L?0-NPwNN-)PM$njdk&@xU)fS(@ZiB(<6~4e>1^1rLA&j@#Y&+_)BsRP5-UYa z*2Xc!f6FbmXpcW(!UUt$6H&GeW3Y+Qz$CSl$Oo^VuDyoE%Akm(0jQ*it|4nRO^C93 zf=zrkZQ7&?g~rY5e%;K?**D2Go+RorF^iQ(5pgaU)0*hInbvr+!bDep$Y&MPZNuiy zof~OsR8snQwg&IboH=t`X)%~j8I*u30Lo>xrHL;4#W0r_cKpi9O5-NFY$>5T|0Ffh z4TC**7(KRi97RwXCBXSvkd1pxn&`4Ljiqj3$7Z6OHJ+xqMBUOTR`ERf%V1YOjauds}5i;V*MY+1);~ozt zxx}ZRemYnk5q4~L$WCe#UBXB-TO~Ty(J z=b&W7GpQ{lSXk|FZD(s*gc$MQ-UTz(h!G=z4vMhteMW>^I_6p8xDT3=-$7h%D^I0aO>g~BsM%US-8v9>bgFjOgAK{i7wL% zEEs16QNjW(xeDFqFAkjQBU-4~`-Ms4r~wkLp5W?*uw&9K`{_@As*(b)4X+WagTlJF zB|z1%ki@&9Oun-vx~`U#&7h(*kG=1{`w|iHZ`TK;O{3P;>mXTd@s7O?rSOpE7U=4+-fZQ%o_Pv3BiRVWUW8k}V@Pinr ztgM7TL!zAc(ONV%HsaM+U&X3bt58>07Z{%y+!56KIvXXV)CNdAG#Q}>;Rt-U4n2GJ z#QEo+4?k}hsBhoC!S{Of=n<%`v!x%I#f}|2;747tWy==4_~MJ$v}qI8uV0UK>(=4* z*Iy52X5lF6eT`{;Eg9u7K*AYtH3ThwbP?UVcSo;Yy@FR7p&z^njM7hgpi`$#=-Ra_ z{Ja}Fbm$QL4h?AU-n}?*-~e{*+7--hJ9qAcA8kcLLqlL>e5L%PIfO_I^R)&ELV_|P zS5&f~OD-KzK31V=#!W#G?B)M_-H9?$P6H&hzAAlYh{`4_+ewtW5+*87Ldw>J;=%H=vR1ex1u5VbwN+&+tWGKn%4Fcy zO&7(l3?!geG(3nAilU2aPdx}lM}jjVoj69ywpV+5gg(8rJQU@MW5T)TJ)08oh2TNT z*M#?|hb5IQ?G15BMdEVC3>Wrh;MSlKwOtuVp4b{ZUkl*Y01}x?W<5)h*)ZA4KxREB zsDfJqOQcs7WY%*E4^7RVTpDDeqg4Zmb~{ZP;+DFo48+|`6lsVdx*#VL>OwU53{eF! zL|YB73i6!SF7P0RD26A*jt6l~#qb0xNJ9*<9I9!))?#=%nqrHy-6BX-Qz!rr zGAp)KH4rybC<1J4umEC=QN-DfwVEjiLJ3Ggj8TlPNVvKn*A`M}DgYmi_SXQY)>mEg zYb^vL!~lzjhbAMWK@LIk46@$W5;V1TXNPI&E?oq~080l052sn~wea0IVg00000NkvXXu0mjf3z|SU literal 0 HcmV?d00001 diff --git a/apps/www-beta/public/assets/logo.svg b/apps/www-beta/public/assets/logo.svg new file mode 100644 index 000000000..a678b0b18 --- /dev/null +++ b/apps/www-beta/public/assets/logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/apps/www-beta/source.config.ts b/apps/www-beta/source.config.ts new file mode 100644 index 000000000..1f35ae2ab --- /dev/null +++ b/apps/www-beta/source.config.ts @@ -0,0 +1,5 @@ +import { defineDocs } from 'fumadocs-mdx/config'; + +export const docs = defineDocs({ + dir: 'content/docs' +}); diff --git a/apps/www-beta/src/app/(home)/page.module.css b/apps/www-beta/src/app/(home)/page.module.css new file mode 100644 index 000000000..eb2d8f257 --- /dev/null +++ b/apps/www-beta/src/app/(home)/page.module.css @@ -0,0 +1,46 @@ +.main { + flex: 1; + display: flex; + flex-direction: column; + text-align: center; + justify-content: center; + align-items: center; + gap: 48px; + width: 100%; + height: 100vh; +} +.links { + display: flex; + gap: 20px; + align-items: center; + max-width: 500px; + width: 100%; +} +.card h3, +.card p { + text-align: start; +} +.card { + flex: 1; +} +.info { + display: flex; + flex-direction: column; + align-items: flex-start; + max-width: 500px; + text-align: start; + gap: 20px; +} +.info h1 { + font-size: 36px; + font-weight: 500; + line-height: 48px; + max-width: 400px; + margin-bottom: 0; +} +.info h3 { + font-size: 20px; + font-weight: 400; + line-height: 28px; + color: hsl(var(--fd-muted-foreground) / 1); +} diff --git a/apps/www-beta/src/app/(home)/page.tsx b/apps/www-beta/src/app/(home)/page.tsx new file mode 100644 index 000000000..c4cc58d48 --- /dev/null +++ b/apps/www-beta/src/app/(home)/page.tsx @@ -0,0 +1,24 @@ +import Logo from '@/components/logo'; +import styles from './page.module.css'; + +export const metadata = { + title: 'Apsara' +}; + +export default function HomePage() { + return ( +
+
+ +

+ The design system
+ for the next big thing +

+

+ Apsara is an elegant and beautiful re-usable React component library + built using Radix UI. +

+
+
+ ); +} diff --git a/apps/www-beta/src/app/layout.tsx b/apps/www-beta/src/app/layout.tsx new file mode 100644 index 000000000..55e270ef8 --- /dev/null +++ b/apps/www-beta/src/app/layout.tsx @@ -0,0 +1,36 @@ +import Navbar from '@/components/navbar'; +import '@/styles.css'; +import '@raystack/apsara/normalize.css'; +import '@raystack/apsara/style.css'; +import { ThemeProvider } from '@raystack/apsara'; +import { NextProvider } from 'fumadocs-core/framework/next'; +import { Inter } from 'next/font/google'; +import type { ReactNode } from 'react'; + +const inter = Inter({ + subsets: ['latin'] +}); + +export default function Layout({ children }: { children: ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ); +} diff --git a/apps/www-beta/src/assets/github.tsx b/apps/www-beta/src/assets/github.tsx new file mode 100644 index 000000000..bd5dd9696 --- /dev/null +++ b/apps/www-beta/src/assets/github.tsx @@ -0,0 +1,22 @@ +import { FC, SVGProps } from 'react'; + +export const GitHubIcon: FC> = ({ + width = 24, + height = 24, + ...props +}) => { + return ( + + + + ); +}; + +export default GitHubIcon; diff --git a/apps/www-beta/src/components/kbd/index.ts b/apps/www-beta/src/components/kbd/index.ts new file mode 100644 index 000000000..fbbeae156 --- /dev/null +++ b/apps/www-beta/src/components/kbd/index.ts @@ -0,0 +1 @@ +export { Kbd } from './kbd'; diff --git a/apps/www-beta/src/components/kbd/kbd.module.css b/apps/www-beta/src/components/kbd/kbd.module.css new file mode 100644 index 000000000..767cde464 --- /dev/null +++ b/apps/www-beta/src/components/kbd/kbd.module.css @@ -0,0 +1,11 @@ +.container { + display: flex; + align-items: center; + gap: var(--rs-space-2); +} + +.kbd { + padding: var(--rs-space-1); + border-radius: var(--rs-radius-1); + background: var(--rs-color-background-neutral-primary); +} diff --git a/apps/www-beta/src/components/kbd/kbd.tsx b/apps/www-beta/src/components/kbd/kbd.tsx new file mode 100644 index 000000000..92086c568 --- /dev/null +++ b/apps/www-beta/src/components/kbd/kbd.tsx @@ -0,0 +1,51 @@ +import { Text } from '@raystack/apsara'; +import { cx } from 'class-variance-authority'; +import { HTMLAttributes } from 'react'; +import styles from './kbd.module.css'; + +interface KBDProps extends HTMLAttributes { + children: string | number; + mode?: 'single' | 'combination'; +} + +export const Kbd = ({ + children, + mode = 'single', + className, + ...props +}: KBDProps) => { + const content = String(children); + + if (mode === 'combination') { + const keys = content.split(' '); + return ( + + {keys.map((key, index) => ( + + {key} + + ))} + + ); + } + + return ( + + {content} + + ); +}; diff --git a/apps/www-beta/src/components/logo/index.ts b/apps/www-beta/src/components/logo/index.ts new file mode 100644 index 000000000..f0d8afd94 --- /dev/null +++ b/apps/www-beta/src/components/logo/index.ts @@ -0,0 +1 @@ +export { default } from './logo'; diff --git a/apps/www-beta/src/components/logo/logo.module.css b/apps/www-beta/src/components/logo/logo.module.css new file mode 100644 index 000000000..0be1f751f --- /dev/null +++ b/apps/www-beta/src/components/logo/logo.module.css @@ -0,0 +1,17 @@ +.container { + display: flex; + gap: 8px; + justify-content: center; + align-items: center; + font-weight: 700; + font-size: var(--rs-font-size-t2); + font-style: normal; + font-weight: 700; + line-height: normal; + color: var(--rs-color-foreground-base-primary); +} +.container.large { + gap: 16px; + font-size: 2rem; + font-weight: bold; +} diff --git a/apps/www-beta/src/components/logo/logo.tsx b/apps/www-beta/src/components/logo/logo.tsx new file mode 100644 index 000000000..56d41cb24 --- /dev/null +++ b/apps/www-beta/src/components/logo/logo.tsx @@ -0,0 +1,25 @@ +import { cx } from 'class-variance-authority'; +import Image from 'next/image'; +import styles from './logo.module.css'; + +type Props = { + variant?: 'small' | 'large'; + wordmark?: boolean; + monogram?: boolean; +}; + +export default function Logo({ + variant = 'small', + wordmark = true, + monogram = true +}: Props) { + const size = variant === 'small' ? 24 : 48; + return ( +
+ {monogram && ( + + )} + {wordmark &&

Apsara

} +
+ ); +} diff --git a/apps/www-beta/src/components/navbar/index.ts b/apps/www-beta/src/components/navbar/index.ts new file mode 100644 index 000000000..b4a0bf9f0 --- /dev/null +++ b/apps/www-beta/src/components/navbar/index.ts @@ -0,0 +1 @@ +export { default } from './navbar'; diff --git a/apps/www-beta/src/components/navbar/navbar.module.css b/apps/www-beta/src/components/navbar/navbar.module.css new file mode 100644 index 000000000..77efbe54f --- /dev/null +++ b/apps/www-beta/src/components/navbar/navbar.module.css @@ -0,0 +1,51 @@ +.navbar { + display: flex; + gap: 36px; + align-items: center; + position: sticky; + top: 0; + z-index: 100; + padding: var(--rs-space-5) var(--rs-space-8); + border-bottom: 1px solid var(--rs-color-border-base-primary); + justify-content: space-between; + min-height: 48px; +} +.linksContainer { + display: flex; + gap: var(--rs-space-7); + align-items: center; +} +.links { + display: flex; + gap: var(--rs-space-8); + align-items: center; +} +.navbar a { + text-decoration: none; + transition: color 0.2s ease; +} +.search { + min-width: 312px; +} +.kbd { + margin-right: var(--rs-space-3); +} +.actionsContainer { + display: flex; + gap: var(--rs-space-6); + align-items: center; + max-height: 32px; +} +.actions { + display: flex; + gap: var(--rs-space-4); + align-items: center; +} +.item { + cursor: pointer; + color: var(--rs-color-foreground-base-secondary); +} +.item:hover, +.active { + color: var(--rs-color-foreground-base-primary); +} diff --git a/apps/www-beta/src/components/navbar/navbar.tsx b/apps/www-beta/src/components/navbar/navbar.tsx new file mode 100644 index 000000000..58344fbcf --- /dev/null +++ b/apps/www-beta/src/components/navbar/navbar.tsx @@ -0,0 +1,78 @@ +'use client'; + +import GitHubIcon from '@/assets/github'; +import { Search, Text, ThemeSwitcher } from '@raystack/apsara'; +import { cx } from 'class-variance-authority'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { Kbd } from '../kbd'; +import Logo from '../logo'; +import styles from './navbar.module.css'; + +const LINKS = [ + { + name: 'Documentation', + url: '/docs' + }, + { + name: 'Playground', + url: '/playground' + }, + { + name: 'Icons', + url: '/icons' + } +]; +export default function Navbar() { + const pathname = usePathname(); + + return ( +
+
+ + + +
+ {LINKS.map(link => ( + + + {link.name} + + + ))} +
+
+
+ + ⌘ K +
+ } + className={styles.search} + /> +
+ + + + {/* @ts-ignore */} + +
+ +
+ ); +} diff --git a/apps/www-beta/src/components/theme.tsx b/apps/www-beta/src/components/theme.tsx new file mode 100644 index 000000000..29122fae4 --- /dev/null +++ b/apps/www-beta/src/components/theme.tsx @@ -0,0 +1,78 @@ +'use client'; + +import { ThemeProvider as ApsaraThemeProvider } from '@raystack/apsara'; +import { useTheme as useNextTheme } from 'next-themes'; +import { + ReactNode, + createContext, + useCallback, + useContext, + useState +} from 'react'; + +type Theme = 'light' | 'dark'; + +export interface ThemeOptions { + /** Style variant of the theme, either 'modern' or 'traditional' */ + style?: 'modern' | 'traditional'; + /** Accent color for the theme */ + accentColor?: 'indigo' | 'orange' | 'mint'; + /** Gray color variant for the theme */ + grayColor?: 'gray' | 'mauve' | 'slate'; + /** Theme value for light or dark */ + theme?: Theme; +} + +interface ThemeContextType extends ThemeOptions { + setTheme: (options: ThemeOptions) => void; +} + +const ThemeContext = createContext(undefined); + +interface ThemeProviderProps { + children: ReactNode; +} + +export function ThemeProvider({ children }: ThemeProviderProps) { + const { resolvedTheme, setTheme } = useNextTheme(); + const theme = (resolvedTheme ?? 'light') as Theme; + + const [options, setOptions] = useState({ + style: 'modern', + accentColor: 'indigo', + grayColor: 'gray' + }); + + const updateOptions = useCallback( + (options: ThemeOptions) => { + if ('theme' in options && options.theme) setTheme(options.theme); + setOptions(_options => ({ ..._options, ...options })); + }, + [setTheme] + ); + + const key = `${options?.accentColor}-${options?.grayColor}-${options?.style}`; + return ( + + + {children} + + + ); +} + +export function useTheme() { + const context = useContext(ThemeContext); + if (context === undefined) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +} diff --git a/apps/www-beta/src/content/docs/components/amount/demo.ts b/apps/www-beta/src/content/docs/components/amount/demo.ts new file mode 100644 index 000000000..d23556c1b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/amount/demo.ts @@ -0,0 +1,161 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + console.log('props:', props); + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + value: { + type: 'number', + initialValue: 1299 + }, + currency: { + type: 'text', + defaultValue: 'USD' + }, + valueInMinorUnits: { + type: 'checkbox', + defaultValue: true + }, + locale: { + type: 'text', + defaultValue: 'en-US' + }, + hideDecimals: { + type: 'checkbox', + defaultValue: false + }, + currencyDisplay: { + type: 'select', + options: ['symbol', 'code', 'name'], + defaultValue: 'symbol' + }, + minimumFractionDigits: { + type: 'number', + defaultValue: undefined + }, + maximumFractionDigits: { + type: 'number', + defaultValue: undefined + }, + groupDigits: { + type: 'checkbox', + defaultValue: true + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + + + + + ` +}; + +export const currencyDemo = { + type: 'code', + code: ` + + + + + + + ` +}; + +export const valueInMinorUnitsDemo = { + type: 'code', + code: ` + + {/* $12.99 */} + {/* $12.99 */} + + ` +}; + +export const localeDemo = { + type: 'code', + code: ` + + {/* $12.99 */} + {/* 12,99 € */} + {/* ¥1,299 */} + + ` +}; + +export const hideDecimalsDemo = { + type: 'code', + code: ` + + {/* $12 */} + {/* $12 */} + + ` +}; + +export const currencyDisplayDemo = { + type: 'code', + code: ` + + {/* $12.99 */} + {/* USD 12.99 */} + {/* 12.99 US dollars */} + + ` +}; + +export const groupDigitsDemo = { + type: 'code', + code: ` + + {/* $1,234,567.89 */} + {/* $1234567.89 */} + + ` +}; + +export const withTextDemo = { + type: 'code', + code: ` + + + Total: + + + Discount: + + + Tax: + + + ` +}; + +export const largeNumbersDemo = { + type: 'code', + code: ` + + {/* For large numbers, use string to maintain precision */} + {/* $9,999,999,999,999.99 */} + {/* $10,000,100,091,636,935 */} + + {/* Numbers exceeding safe integer limit will show warning in console */} + {/* Will show warning */} + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/amount/index.mdx b/apps/www-beta/src/content/docs/components/amount/index.mdx new file mode 100644 index 000000000..525ca4575 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/amount/index.mdx @@ -0,0 +1,70 @@ +--- +title: Amount +description: Component for displaying monetary values +tag: new +--- + +import { + playground, + basicDemo, + currencyDemo, + valueInMinorUnitsDemo, + localeDemo, + hideDecimalsDemo, + currencyDisplayDemo, + groupDigitsDemo, + withTextDemo, + largeNumbersDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Amount } from '@raystack/apsara' +``` + +## Amount Props + + + +## Examples + +### Basic + + + +### Currency Variants + + + +### valueInMinorUnits + + + +### locale + + + +### hideDecimals + + + +### currencyDisplay + + + +### groupDigits + + + +### Large Numbers + +For numbers larger than JavaScript's safe integer limit (2^53 - 1), pass the value as a string to maintain precision. + + + +### With Text + + diff --git a/apps/www-beta/src/content/docs/components/amount/props.ts b/apps/www-beta/src/content/docs/components/amount/props.ts new file mode 100644 index 000000000..c6a7fb9e6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/amount/props.ts @@ -0,0 +1,68 @@ +export interface AmountProps { + /** + * The monetary value to display + * For large numbers (> 2^53), pass the value as string to maintain precision + * @default 0 + * @example + * valueInMinorUnits=true: 1299 => "$12.99" + * valueInMinorUnits=false: 12.99 => "$12.99" + * Large numbers: "999999999999999" => "$9,999,999,999,999.99" + */ + value: number | string; + + /** + * ISO 4217 currency code + * @default 'USD' + */ + currency?: string; + + /** + * Whether the value is in minor units (cents, paise, etc.) + * If true, the value will be converted based on the currency's decimal places + * If false, the value will be used as is + * @default true + * @example + * USD: 1299 => $12.99 (2 decimals) + * JPY: 1299 => ¥1,299 (0 decimals) + * BHD: 1299 => BHD 1.299 (3 decimals) + */ + valueInMinorUnits?: boolean; + + /** + * BCP 47 language tag + * @default 'en-US' + * @example 'en-US', 'de-DE', 'ja-JP' + */ + locale?: string; + + /** + * Truncates decimal places + * @default false + */ + hideDecimals?: boolean; + + /** + * Currency display format + * @default 'symbol' + * @example 'symbol' - $12.99, 'code' - USD 12.99, 'name' - 12.99 US Dollars + */ + currencyDisplay?: 'symbol' | 'code' | 'name'; + + /** + * Number of minimum fraction digits + * @default undefined (uses currency's default) + */ + minimumFractionDigits?: number; + + /** + * Number of maximum fraction digits + * @default undefined (uses currency's default) + */ + maximumFractionDigits?: number; + + /** + * Group digits (e.g., thousand separators) + * @default true + */ + groupDigits?: boolean; +} diff --git a/apps/www-beta/src/content/docs/components/announcement-bar/demo.ts b/apps/www-beta/src/content/docs/components/announcement-bar/demo.ts new file mode 100644 index 000000000..eb445d4ba --- /dev/null +++ b/apps/www-beta/src/content/docs/components/announcement-bar/demo.ts @@ -0,0 +1,23 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: ['normal', 'error', 'gradient'], + defaultValue: 'normal' + }, + text: { type: 'text', initialValue: 'We have introduced a new feature' }, + leadingIcon: { type: 'icon', defaultValue: '' }, + actionLabel: { type: 'text', initialValue: 'Read More' }, + actionIcon: { type: 'icon', defaultValue: '' } + }, + getCode +}; diff --git a/apps/www-beta/src/content/docs/components/announcement-bar/index.mdx b/apps/www-beta/src/content/docs/components/announcement-bar/index.mdx new file mode 100644 index 000000000..af1b7f607 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/announcement-bar/index.mdx @@ -0,0 +1,26 @@ +--- +title: Announcement Bar +description: AnnouncementBar component to display message +--- + +import { + playground, + variantsDemo, + sizesDemo, + colorsDemo, + disabledDemo, + loadingDemo, + iconsDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { AnnouncementBar } from '@raystack/apsara' +``` + +## Announcement Bar Props + + diff --git a/apps/www-beta/src/content/docs/components/announcement-bar/props.ts b/apps/www-beta/src/content/docs/components/announcement-bar/props.ts new file mode 100644 index 000000000..a93406069 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/announcement-bar/props.ts @@ -0,0 +1,24 @@ +export interface AnnouncementBarProps { + /** + * Visual style variant + * @defaultValue "normal" + */ + variant?: 'normal' | 'error' | 'gradient'; + + /** + * Text content for the component + */ + text: string; + + /** Icon element to display before the text */ + leadingIcon?: React.ReactNode; + + /** Text of the onClick action. It will be display after the text. */ + actionLabel?: string; + + /** Icon of the onClick action.*/ + actionIcon?: React.ReactNode; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/avatar/demo.ts b/apps/www-beta/src/content/docs/components/avatar/demo.ts new file mode 100644 index 000000000..9ed5723b0 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/avatar/demo.ts @@ -0,0 +1,138 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: ['solid', 'soft'], + defaultValue: 'soft' + }, + radius: { + type: 'select', + options: ['small', 'full'], + defaultValue: 'small' + }, + color: { + type: 'select', + options: [ + 'indigo', + 'orange', + 'mint', + 'neutral', + 'sky', + 'lime', + 'grass', + 'cyan', + 'iris', + 'purple', + 'pink', + 'crimson', + 'gold' + ], + defaultValue: 'indigo' + }, + size: { type: 'number', defaultValue: 3, min: 1, max: 13 }, + src: { + type: 'text', + initialValue: + 'https://images.unsplash.com/photo-1511485977113-f34c92461ad9' + }, + fallback: { type: 'text', initialValue: 'RC' } + }, + getCode +}; + +export const variantDemo = { + type: 'code', + code: ` + + + + ` +}; + +export const sizesDemo = { + type: 'code', + code: ` + + + + + + + + + + + + + + + + + + ` +}; + +export const colorsDemo = { + type: 'code', + tabs: [ + { + name: 'Base', + code: ` + + + + + + ` + }, + { + name: 'Extended', + code: ` + + + + + + + + + + + ` + } + ] +}; + +export const radiusDemo = { + type: 'code', + code: ` + + + + ` +}; +export const imageDemo = { + type: 'code', + code: ` + + + + ` +}; + +export const generatedColorDemo = { + type: 'code', + code: ` + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/avatar/index.mdx b/apps/www-beta/src/content/docs/components/avatar/index.mdx new file mode 100644 index 000000000..bd50e308c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/avatar/index.mdx @@ -0,0 +1,68 @@ +--- +title: Avatar +description: An image element with a fallback for representing the user. +--- + +import { + playground, + sizesDemo, + variantDemo, + colorsDemo, + radiusDemo, + imageDemo, + generatedColorDemo +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Avatar, AvatarGroup, getAvatarColor } from '@raystack/apsara' +``` + +## Avatar Props + + + +## AvatarGroup Props + + + +## Examples + +### Variant + +Choose between soft and solid variants to control the visual weight and emphasis of the avatar in your interface. + + + +### Size + +The Avatar component supports 13 different sizes to accommodate various layout requirements and design needs. + + + +### Color + +Avatar comes with a range of predefined colors including both base and extended color options to match your design system. + + + +### Radius + +Choose between small and full border radius styles to match your design preferences. + + + +### With Image + +Avatar can display user images with graceful fallback to initials when images fail to load or aren't available. + + + +### With Generated Colors + +use `getAvatarColor` utility to generate colors based on a string. + + diff --git a/apps/www-beta/src/content/docs/components/avatar/props.ts b/apps/www-beta/src/content/docs/components/avatar/props.ts new file mode 100644 index 000000000..0180ca048 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/avatar/props.ts @@ -0,0 +1,65 @@ +export interface AvatarProps { + /** + * Specifies the size of the avatar (1-13) + * @defaultValue 3 + */ + size?: number; + + /** The URL of the image to display */ + src?: string; + + /** Alternative text description for the image */ + alt?: string; + + /** Content to display when image fails to load or while loading */ + fallback?: React.ReactNode; + + /** + * Visual style variant + * @defaultValue "soft" + */ + variant?: 'solid' | 'soft'; + + /** + * Border radius style + * @defaultValue "small" + */ + radius?: 'small' | 'full'; + + /** + * Color theme for the avatar + */ + color?: + | 'indigo' + | 'orange' + | 'mint' + | 'neutral' + | 'sky' + | 'lime' + | 'grass' + | 'cyan' + | 'iris' + | 'purple' + | 'pink' + | 'crimson' + | 'gold'; + + /** Boolean to merge props onto child element */ + asChild?: boolean; + + /** Additional CSS class names */ + className?: string; +} + +export interface AvatarGroupProps { + /** + * Array of Avatar components to display + */ + children: React.ReactNode; + + /** Maximum number of avatars to show before displaying a count */ + max?: number; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/badge/demo.ts b/apps/www-beta/src/content/docs/components/badge/demo.ts new file mode 100644 index 000000000..688105765 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/badge/demo.ts @@ -0,0 +1,83 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: [ + 'accent', + 'warning', + 'danger', + 'success', + 'neutral', + 'gradient' + ], + defaultValue: 'accent' + }, + size: { + type: 'select', + options: ['micro', 'small', 'regular'], + defaultValue: 'small' + }, + icon: { + type: 'icon' + }, + screenReaderText: { + type: 'text', + initialValue: 'Notification badge' + }, + children: { + type: 'text', + initialValue: 'New Badge' + } + }, + getCode +}; + +export const variantDemo = { + type: 'code', + code: ` + + Accent + Warning + Danger + Success + Neutral + Gradient + ` +}; + +export const sizesDemo = { + type: 'code', + code: ` + + Micro + Small + Regular + ` +}; + +export const iconDemo = { + type: 'code', + code: ` + + }>Badge + }>Badge + Badge + ` +}; + +export const screenReaderTextDemo = { + type: 'code', + code: ` + + Updates + ` +}; diff --git a/apps/www-beta/src/content/docs/components/badge/index.mdx b/apps/www-beta/src/content/docs/components/badge/index.mdx new file mode 100644 index 000000000..823370ae9 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/badge/index.mdx @@ -0,0 +1,50 @@ +--- +title: Badge +description: Badge component to display concise information. +--- + +import { + playground, + sizesDemo, + variantDemo, + iconDemo, + screenReaderTextDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Badge } from '@raystack/apsara' +``` + +## Badge Props + + + +## Examples + +### Variant + +Choose between different variants to convey different meanings or importance levels. Default variant is `accent`. + + + +### Size + +The Badge component supports three sizes to accommodate various layout requirements. Default size is `small`. + + + +### With Icon + +Badges can include an icon to provide additional visual context. By default there is no icon. + + + +### Accessibility + +The Badge component includes screen reader support through the `screenReaderText` prop, only be announced to screen readers. By default no text is passed to `screenReaderText` prop. + + diff --git a/apps/www-beta/src/content/docs/components/badge/props.ts b/apps/www-beta/src/content/docs/components/badge/props.ts new file mode 100644 index 000000000..16e893d85 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/badge/props.ts @@ -0,0 +1,31 @@ +export interface BadgeProps { + /** + * Visual style variant + * @defaultValue "accent" + */ + variant?: + | 'accent' + | 'warning' + | 'danger' + | 'success' + | 'neutral' + | 'gradient'; + + /** + * Size of the badge + * @defaultValue "small" + */ + size?: 'micro' | 'small' | 'regular'; + + /** Optional ReactNode to display an icon before the text */ + icon?: React.ReactNode; + + /** Additional text content only announced to screen readers */ + screenReaderText?: string; + + /** Text content of the badge */ + children?: React.ReactNode; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/breadcrumb/demo.ts b/apps/www-beta/src/content/docs/components/breadcrumb/demo.ts new file mode 100644 index 000000000..866a05108 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/breadcrumb/demo.ts @@ -0,0 +1,135 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ` + Home + + Products + + Shoes + `; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['small', 'medium'], + defaultValue: 'medium' + } + }, + getCode +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + Home + + Products + + Shoes + + + Home + + Products + + Shoes + + ` +}; + +export const separatorDemo = { + type: 'code', + code: ` + + + Home + | + Products + | + Shoes + + + Home + - + Products + - + Shoes + + ` +}; + +export const ellipsisDemo = { + type: 'code', + code: ` + + Home + + + + Shoes + ` +}; + +export const dropdownDemo = { + type: 'code', + code: ` + + Home + + Category + + {console.log('Option 1')}}, + { label: 'Option 2', onClick: () => {console.log('Option 2')}} + ]}>Subcategory + + Current Page + ` +}; +export const asDemo = { + type: 'code', + code: ` + + }>Home + + }>Playground + + Docs + ` +}; + +export const iconsDemo = { + type: 'code', + tabs: [ + { + name: 'Text with Icon', + code: ` + + H}>Home + + D}>Documents + + S}>Settings + ` + }, + { + name: 'Only Icon', + code: ` + + H}/> + + D}/> + + S}/> + ` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/breadcrumb/index.mdx b/apps/www-beta/src/content/docs/components/breadcrumb/index.mdx new file mode 100644 index 000000000..2e5f3a6d1 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/breadcrumb/index.mdx @@ -0,0 +1,81 @@ +--- +title: Breadcrumb +description: A navigation component for displaying a route trail. +tag: update +--- + +import { + playground, + sizeDemo, + separatorDemo, + iconsDemo, + ellipsisDemo, + dropdownDemo, + asDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Breadcrumb } from '@raystack/apsara' +``` + +## Breadcrumb Props + + + +### Breadcrumb.Item Props + + + +### Breadcrumb.Separator Props + + + +### Breadcrumb.Ellipsis Props + + + +## Examples + +### Size + +The Breadcrumb component supports different sizes to accommodate various design requirements. Specify the size using the `size` prop. + + + +### Separator + +Customize the separator between breadcrumb items using the `separator` prop. + + + +### Ellipsis + +Use the `Breadcrumb.Ellipsis` component to truncate the breadcrumb trail when you need to display a large number of items in a limited space. + + + +### Icons + +Breadcrumb items can include icons either alongside text or as standalone elements. + + + +### Dropdown + +Breadcrumb items can include dropdown menus for additional navigation options. Specify the dropdown items using the `dropdownItems` prop. + +**Note:** When `dropdownItems` is provided, the `as` and `href` props are ignored. + + + +### As + +Use the `as` prop to render the breadcrumb item as a custom component. By default, breadcrumb items are rendered as `a` tags. + +When a custom component is provided, the props are merged, with the custom component's props taking precedence over the breadcrumb item's props. + + diff --git a/apps/www-beta/src/content/docs/components/breadcrumb/props.ts b/apps/www-beta/src/content/docs/components/breadcrumb/props.ts new file mode 100644 index 000000000..02b7d4ed9 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/breadcrumb/props.ts @@ -0,0 +1,70 @@ +import { ReactElement, ReactEventHandler, ReactNode } from 'react'; + +export interface BreadcrumbItem { + /** Text to display for the item */ + label: string; + + /** URL for the item link */ + href?: string; + + /** Optional icon element to display */ + leadingIcon?: ReactNode; + + /** + * Whether the item is the current page + * @defaultValue false + */ + current?: boolean; + + /** + * Optional array of dropdown items + * + * When `dropdownItems` is provided, the `as` and `href` props are ignored. + */ + dropdownItems?: { + /** Text to display for the dropdown item */ + label: string; + /** Callback function when a dropdown item is clicked */ + onClick?: ReactEventHandler; + }[]; + + /** + * Custom element used to render the Item. + * + * All props are merged, with the custom component's props taking precedence over the breadcrumb item's props. + * + * @default "" + */ + as?: ReactElement; +} + +export interface BreadcrumbProps { + /** + * Size variant of the breadcrumb + * @defaultValue "medium" + */ + size?: 'small' | 'medium'; + + /** Custom CSS class names */ + className?: string; +} + +export interface BreadcrumbSeparatorProps { + /** + * Custom separator between items + * @defaultValue "/" + */ + children?: ReactNode; + /** Custom CSS class names */ + className?: string; +} + +export interface BreadcrumbEllipsisProps { + /** + * Custom ellipsis element + * @defaultValue + */ + children?: ReactNode; + /** Custom CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/button/demo.ts b/apps/www-beta/src/content/docs/components/button/demo.ts new file mode 100644 index 000000000..fe14d0ad1 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/button/demo.ts @@ -0,0 +1,125 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: ['solid', 'outline', 'ghost', 'text'], + defaultValue: 'solid' + }, + color: { + type: 'select', + options: ['accent', 'danger', 'neutral', 'success'], + defaultValue: 'accent' + }, + size: { + type: 'select', + options: ['small', 'normal'], + defaultValue: 'normal' + }, + leadingIcon: { type: 'icon' }, + trailingIcon: { type: 'icon' }, + disabled: { type: 'checkbox', defaultValue: false }, + loading: { type: 'checkbox', defaultValue: false }, + children: { type: 'text', initialValue: 'Click me' }, + loaderText: { type: 'text' } + }, + getCode +}; + +export const variantsDemo = { + type: 'code', + code: ` + + + + + ` +}; + +export const colorsDemo = { + type: 'code', + tabs: [ + { + name: 'Solid', + code: ` + + + + + + ` + }, + { + name: 'Outline', + code: ` + + + + + + ` + }, + { + name: 'Ghost', + code: ` + + + + + + ` + }, + { + name: 'Text', + code: ` + + + + + + ` + } + ] +}; + +export const sizesDemo = { + type: 'code', + code: ` + + + ` +}; +export const disabledDemo = { + type: 'code', + code: ` + + + + + ` +}; +export const loadingDemo = { + type: 'code', + code: ` + + + + ` +}; +export const iconsDemo = { + type: 'code', + code: ` + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/button/index.mdx b/apps/www-beta/src/content/docs/components/button/index.mdx new file mode 100644 index 000000000..b02b187b5 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/button/index.mdx @@ -0,0 +1,63 @@ +--- +title: Button +description: Triggers a click action usually performed by the user to trigger an event such as submitting a form or closing a dialog. +--- + +import { + playground, + variantsDemo, + sizesDemo, + colorsDemo, + disabledDemo, + loadingDemo, + iconsDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Button } from '@raystack/apsara' +``` + +## Button Props + + + +## Examples + +### Variant + +Variants allow you to customize the button's style, making it visually distinctive and suitable for different purposes. Default is `solid`. + + + +### Color + +Colors help convey the purpose and importance of actions. The color prop only affects solid and outline variants. Default is `accent`. + + +### Size + +The Button component offers two size options. Default size is `normal`. + + + +### Disabled + +The Button component provides a "disabled" state, which prevents the button from responding to any user actions. Default is `false`. + + + +### Loading + +The Button component offers inbuilt loading states. Loading state is used to signify an ongoing process after the user has clicked on the button. + + + +### With leading and trailing icons + +The button component accepts optional leading and/or trailing icons. + + diff --git a/apps/www-beta/src/content/docs/components/button/props.ts b/apps/www-beta/src/content/docs/components/button/props.ts new file mode 100644 index 000000000..6d6fabcad --- /dev/null +++ b/apps/www-beta/src/content/docs/components/button/props.ts @@ -0,0 +1,49 @@ +export type ButtonProps = { + /** + * Visual style variant + * @defaultValue "solid" + */ + variant?: 'solid' | 'outline' | 'ghost' | 'text'; + + /** + * Color theme + * @defaultValue "accent" + */ + color?: 'accent' | 'danger' | 'neutral' | 'success'; + + /** + * Size of the button + * @defaultValue "normal" + */ + size?: 'small' | 'normal'; + + /** + * Whether the button is disabled + * @defaultValue false + */ + disabled?: boolean; + + /** Shows a loading spinner inside the button */ + loading?: boolean; + + /** Optional text to display next to the loading spinner */ + loaderText?: React.ReactNode; + + /** Icon element to display before button text */ + leadingIcon?: React.ReactNode; + + /** Icon element to display after button text */ + trailingIcon?: React.ReactNode; + + /** Custom maximum width for the button */ + maxWidth?: string | number; + + /** Custom width for the button */ + width?: string | number; + + /** Boolean to merge props onto child element */ + asChild?: boolean; + + /** Additional CSS class names */ + className?: string; +}; diff --git a/apps/www-beta/src/content/docs/components/calendar/demo.ts b/apps/www-beta/src/content/docs/components/calendar/demo.ts new file mode 100644 index 000000000..c67dd59f5 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/calendar/demo.ts @@ -0,0 +1,102 @@ +'use client'; + +export const preview = { + type: 'code', + tabs: [ + { + name: 'Calendar', + code: `` + }, + { + name: 'Range Picker', + code: ` + ` + }, + { + name: 'Date Picker', + code: ` + + + ` + } + ] +}; + +export const calendarDemo = { + type: 'code', + tabs: [ + { + name: 'Basic', + code: `` + }, + { + name: 'With Loading', + code: `` + } + ] +}; +export const rangePickerDemo = { + type: 'code', + tabs: [ + { + name: 'Basic', + code: `` + }, + { + name: 'Without Calendar Icon', + code: `` + }, + { + name: 'Custom Trigger', + code: ` + console.log('Date range:', range)} + value={{ + from: new Date(2024, 0, 1), + to: new Date(2024, 0, 15) + }} + calendarProps={{ + mode: "range", + required: true, + selected: { + from: new Date(2024, 0, 1), + to: new Date(2024, 0, 15) + }, + fromMonth: new Date(2024, 0, 1), + toMonth: new Date(2024, 11, 31), + }} + > + {({ startDate, endDate }) => ( + + )} + ` + } + ] +}; +export const datePickerDemo = { + type: 'code', + tabs: [ + { + name: 'Basic', + code: `` + }, + { + name: 'Without Calendar Icon', + code: `` + }, + { + name: 'Custom Trigger', + code: ` + + {({ selectedDate }) => ( + + )} + ` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/calendar/index.mdx b/apps/www-beta/src/content/docs/components/calendar/index.mdx new file mode 100644 index 000000000..7a5e65d83 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/calendar/index.mdx @@ -0,0 +1,77 @@ +--- +title: Calendar +description: A calendar component for selecting dates and date ranges. +--- + +import { + preview, + datePickerDemo, + rangePickerDemo, + calendarDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Calendar, RangePicker, DatePicker } from '@raystack/apsara' +``` + +## Calendar Props + + + +## RangePicker Props + + + +## DatePicker Props + + + +## Examples + +### Calendar + +Choose between different variants to convey different meanings or importance levels. Default variant is `accent`. + + + +### Range Picker + +The Range Picker component allows selecting a date range with the following behaviors: + +1. When selecting two different dates: + - The UI will show the exact selected dates + - The callback will return the start and end date as selected + ```tsx + // Example: If user selects April 1st and April 10th, 2025 + // UI will show: April 1st, 2025 - April 10th, 2025 + // Callback will return: + { + "from": "2025-03-31T18:30:00.000Z", + "to": "2025-04-09T18:30:00.000Z" + } + ``` + +2. When clicking the same date twice: + - The UI will show the same date for both start and end + - The callback will return the start and end date as selected + ```tsx + // Example: If user clicks April 1st, 2025 twice + // UI will show: April 1st, 2025 - April 1st, 2025 + // Callback will return: + { + "from": "2025-03-31T18:30:00.000Z", + "to": "2025-03-31T18:30:00.000Z" + } + ``` + + + +### Date Picker + +Badges can include an icon to provide additional visual context. By default there is no icon. + + diff --git a/apps/www-beta/src/content/docs/components/calendar/props.ts b/apps/www-beta/src/content/docs/components/calendar/props.ts new file mode 100644 index 000000000..0c9f4d63b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/calendar/props.ts @@ -0,0 +1,117 @@ +import { InputFieldProps } from '../input-field/props'; + +export interface CalendarProps { + /** Number of months to display */ + numberOfMonths?: number; + + /** Layout for the month caption (e.g., "dropdown") */ + captionLayout?: string; + + /** Boolean to show loading state */ + loadingData?: boolean; + + /** Object containing date-specific information like icons and text */ + dateInfo?: Record; + + /** Boolean to show days from previous/next months */ + showOutsideDays?: boolean; + + /** Additional CSS class names */ + className?: string; + + /** + * IANA timezone name (e.g., "America/New_York"), "UTC", or UTC offset (e.g., "+02:00"). + * If not provided, uses the local timezone. + */ + timeZone?: string; +} + +export interface RangePickerProps { + /** + * Format for displaying the date. Supports various formats: + * - With slashes: "DD/MM/YYYY", "MM/DD/YYYY", "YYYY/MM/DD" + * - With dashes: "DD-MM-YYYY", "MM-DD-YYYY", "YYYY-MM-DD" + * - With dots: "DD.MM.YYYY", "MM.DD.YYYY", "YYYY.MM.DD" + * - With spaces: "DD MMM YYYY", "MMM DD YYYY", "YYYY MMM DD" + * - With full month: "DD MMMM YYYY", "MMMM DD YYYY", "YYYY MMMM DD" + * - For more supported formats, refer to https://day.js.org/docs/en/display/format + * @defaultValue "DD/MM/YYYY" + */ + dateFormat?: string; + + /** Callback function when date range is selected */ + onSelect?: (range: { from: Date; to: Date }) => void; + + /** Initial date range value */ + defaultValue?: { from: Date; to: Date }; + + /** Controlled date range value */ + value?: { from: Date; to: Date }; + + /** Props for customizing the calendar */ + calendarProps?: CalendarProps; + + /** Props for customizing the input fields */ + inputFieldsProps?: { + startDate?: InputFieldProps; + endDate?: InputFieldProps; + }; + + /** Render prop for custom trigger */ + children?: React.ReactNode; + + /** + * Boolean to show/hide calendar icon + * @defaultValue true + */ + showCalendarIcon?: boolean; + + /** Optional footer content for the calendar popover */ + footer?: React.ReactNode; + + /** + * IANA timezone name (e.g., "America/New_York"), "UTC", or UTC offset (e.g., "+02:00"). + * If not provided, uses the local timezone. + */ + timeZone?: string; +} + +export interface DatePickerProps { + /** + * Format for displaying the date. Supports various formats: + * - With slashes: "DD/MM/YYYY", "MM/DD/YYYY", "YYYY/MM/DD" + * - With dashes: "DD-MM-YYYY", "MM-DD-YYYY", "YYYY-MM-DD" + * - With dots: "DD.MM.YYYY", "MM.DD.YYYY", "YYYY.MM.DD" + * - With spaces: "DD MMM YYYY", "MMM DD YYYY", "YYYY MMM DD" + * - With full month: "DD MMMM YYYY", "MMMM DD YYYY", "YYYY MMMM DD" + * @defaultValue "DD/MM/YYYY" + */ + dateFormat?: string; + + /** Props for customizing the input field */ + inputFieldProps?: InputFieldProps; + + /** Initial date value */ + value?: Date; + + /** Callback function when date is selected */ + onSelect?: (date: Date) => void; + + /** Props for customizing the calendar */ + calendarProps?: CalendarProps; + + /** Render prop for custom trigger */ + children?: React.ReactNode; + + /** + * Boolean to show/hide calendar icon + * @defaultValue true + */ + showCalendarIcon?: boolean; + + /** + * IANA timezone name (e.g., "America/New_York"), "UTC", or UTC offset (e.g., "+02:00"). + * If not provided, uses the local timezone. + */ + timeZone?: string; +} diff --git a/apps/www-beta/src/content/docs/components/callout/demo.ts b/apps/www-beta/src/content/docs/components/callout/demo.ts new file mode 100644 index 000000000..dc330c6d1 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/callout/demo.ts @@ -0,0 +1,105 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return ` alert("Dismissed")}>${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + type: { + type: 'select', + options: [ + 'grey', + 'success', + 'alert', + 'gradient', + 'accent', + 'attention', + 'normal' + ], + defaultValue: 'grey', + initialValue: 'gradient' + }, + children: { + type: 'text', + initialValue: 'A short message' + }, + icon: { + type: 'icon' + }, + outline: { + type: 'checkbox', + defaultValue: false + }, + highContrast: { + type: 'checkbox', + defaultValue: false + }, + dismissible: { + type: 'checkbox', + defaultValue: false + }, + width: { + type: 'text' + } + }, + getCode +}; +export const typeDemo = { + type: 'code', + code: ` + + Default Callout + Success Callout + Alert Callout + Gradient Callout + Accent Callout + Attention Callout + Normal Callout + ` +}; + +export const outlineDemo = { + type: 'code', + code: ` + + Without Outline Callout + With Outline Callout + ` +}; + +export const highContrastDemo = { + type: 'code', + code: ` + + Normal Callout + High Contrast Callout + ` +}; + +export const dismissibleDemo = { + type: 'code', + code: ` + alert("Dismissed!")}> + Dismissible Callout + ` +}; + +export const actionDemo = { + type: 'code', + code: ` + Action}> + A short message to attract user's attention + ` +}; + +export const widthDemo = { + type: 'code', + code: `A short message to attract user's attention` +}; diff --git a/apps/www-beta/src/content/docs/components/callout/index.mdx b/apps/www-beta/src/content/docs/components/callout/index.mdx new file mode 100644 index 000000000..bc0d93cfc --- /dev/null +++ b/apps/www-beta/src/content/docs/components/callout/index.mdx @@ -0,0 +1,72 @@ +--- +title: Callout +description: A visual message component to attract user's attention. +--- + +import { + playground, + typeDemo, + outlineDemo, + highContrastDemo, + dismissibleDemo, + actionDemo, + widthDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Callout } from '@raystack/apsara' +``` + +## Callout Props + + + +## Examples + +### Type + +The Callout component offers different type options. You can customize the visual style using the `type` prop: + + + +### Outline + +The Callout component can be rendered with or without an outline border: + + + +### High Contrast + +The Callout component supports high contrast mode for better visibility: + + + +### Dismissible + +The Callout component can be made dismissible: + + + +### With Action + +The Callout component can include an action button: + + + +### Custom Width + +The Callout component supports custom width: + + + +## Accessibility + +The Callout component includes appropriate ARIA attributes for accessibility: + +- Uses semantic HTML elements for proper structure +- Dismiss button includes `aria-label` for screen readers +- Interactive elements are keyboard accessible diff --git a/apps/www-beta/src/content/docs/components/callout/props.ts b/apps/www-beta/src/content/docs/components/callout/props.ts new file mode 100644 index 000000000..d8b30fb1e --- /dev/null +++ b/apps/www-beta/src/content/docs/components/callout/props.ts @@ -0,0 +1,53 @@ +export interface CalloutProps { + /** + * Visual style variant + * @defaultValue "grey" + */ + type?: + | 'grey' + | 'success' + | 'alert' + | 'gradient' + | 'accent' + | 'attention' + | 'normal'; + + /** + * Whether to show an outline border + * @defaultValue false + */ + outline?: boolean; + + /** + * Whether to use high contrast colors + * @defaultValue false + */ + highContrast?: boolean; + + /** Optional action element to display on the right */ + action?: React.ReactNode; + + /** + * Whether to show a dismiss button + * @defaultValue false + */ + dismissible?: boolean; + + /** + * Custom leading icon + * @defaultValue InfoCircledIcon + */ + icon?: React.ReactNode; + + /** Callback function when dismiss button is clicked */ + onDismiss?: () => void; + + /** Text content of the callout */ + children?: React.ReactNode; + + /** Custom width for the callout */ + width?: string | number; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/checkbox/demo.ts b/apps/www-beta/src/content/docs/components/checkbox/demo.ts new file mode 100644 index 000000000..3cc2a5765 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/checkbox/demo.ts @@ -0,0 +1,48 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + if (props.checked === 'false') props.checked = false; + else if (props.checked === 'true') props.checked = true; + + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + checked: { + type: 'select', + options: ['true', 'false', 'indeterminate'], + initialValue: 'true' + }, + disabled: { + type: 'checkbox', + defaultValue: false + } + }, + getCode +}; + +export const statesExamples = { + type: 'code', + tabs: [ + { + name: 'Basic', + code: `` + }, + { + name: 'Checked', + code: `` + }, + { + name: 'Indeterminate', + code: `` + }, + { + name: 'Disabled', + code: `` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/checkbox/index.mdx b/apps/www-beta/src/content/docs/components/checkbox/index.mdx new file mode 100644 index 000000000..f6bad8e7f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/checkbox/index.mdx @@ -0,0 +1,31 @@ +--- +title: Checkbox +description: Checkbox is a user interface control that enables users to toggle between checked, unchecked, and indeterminate states +--- + +import { playground, statesExamples } from "./demo.ts"; + + + +## Usage + +```tsx +import { Checkbox } from "@raystack/apsara"; +``` + +## Checkbox Props + + + +## Examples + +### States + +The Checkbox component supports multiple states to represent different selection conditions: + +- Unchecked: Default state +- Checked: Selected state +- Indeterminate: Partial selection state +- Disabled: Disabled state + + diff --git a/apps/www-beta/src/content/docs/components/checkbox/props.ts b/apps/www-beta/src/content/docs/components/checkbox/props.ts new file mode 100644 index 000000000..1d2a70bc7 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/checkbox/props.ts @@ -0,0 +1,21 @@ +export interface CheckboxProps { + /** + * The controlled state of the checkbox + */ + checked?: boolean | 'indeterminate'; + + /** + * The default state when initially rendered + */ + defaultChecked?: boolean | 'indeterminate'; + + /** + * Event handler called when the state changes + */ + onCheckedChange?: (checked: boolean | 'indeterminate') => void; + + /** + * When true, prevents the user from interacting with the checkbox + */ + disabled?: boolean; +} diff --git a/apps/www-beta/src/content/docs/components/chip/demo.ts b/apps/www-beta/src/content/docs/components/chip/demo.ts new file mode 100644 index 000000000..618c22870 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/chip/demo.ts @@ -0,0 +1,110 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: ['outline', 'filled'], + defaultValue: 'outline' + }, + size: { + type: 'select', + options: ['small', 'large'], + defaultValue: 'small' + }, + color: { + type: 'select', + options: ['neutral', 'accent'], + defaultValue: 'neutral' + }, + isDismissible: { + type: 'checkbox', + defaultValue: false + }, + children: { + type: 'text', + initialValue: 'My Chip' + }, + leadingIcon: { type: 'icon' }, + trailingIcon: { type: 'icon' } + }, + getCode +}; + +export const variantsDemo = { + type: 'code', + code: ` + + Outline + Filled + ` +}; + +export const sizesDemo = { + type: 'code', + code: ` + + Small + Large + ` +}; + +export const colorDemo = { + type: 'code', + code: ` + + Outline + Filled + Outline + Filled + ` +}; + +export const dismissableDemo = { + type: 'code', + code: ` + + alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip + alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip + alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip + ` +}; + +export const iconsDemo = { + type: 'code', + tabs: [ + { + name: 'Leading Icon', + code: ` +
+ Add Item + Selected +
` + }, + { + name: 'Trailing Icon', + code: ` +
+ Next + Open +
` + }, + { + name: 'Both Icons', + code: ` +
+ Download + Edit Profile +
` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/chip/index.mdx b/apps/www-beta/src/content/docs/components/chip/index.mdx new file mode 100644 index 000000000..d24d3f1cd --- /dev/null +++ b/apps/www-beta/src/content/docs/components/chip/index.mdx @@ -0,0 +1,70 @@ +--- +title: Chip +description: A compact element for representing an input, attribute, or action. +--- + +import { + playground, + variantsDemo, + sizesDemo, + colorDemo, + dismissableDemo, + iconsDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Chip } from "@raystack/apsara"; +``` + +## Chip Props + + + +## Examples + +### Variant + +Choose between outline and filled variants to match your design needs. + + + +### Size + +The Chip component comes in two sizes: + +- `small`: Compact size with less padding +- `large`: More spacious with increased padding + + + +### Color + +Choose between neutral and accent styles to control the visual emphasis. + + + +### With Icons + +Chips can include leading and trailing icons to provide additional context or actions. + + + +### Dismissible + +Chips can be made dismissible by adding the isDismissible prop and an onDismiss handler. + + + +## Accessibility + +The Chip component has some accessibility features: + +- Uses semantic HTML elements +- Includes proper ARIA roles and labels +- Provides keyboard navigation support +- Makes decorative elements hidden from screen readers +- Ensures proper contrast ratios in all variants and states diff --git a/apps/www-beta/src/content/docs/components/chip/props.ts b/apps/www-beta/src/content/docs/components/chip/props.ts new file mode 100644 index 000000000..99396d0d7 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/chip/props.ts @@ -0,0 +1,48 @@ +export interface ChipProps { + /** + * Visual style variant + * @defaultValue "outline" + */ + variant?: 'outline' | 'filled'; + + /** + * Size of the chip + * @defaultValue "small" + */ + size?: 'small' | 'large'; + + /** + * Color style + * @defaultValue "neutral" + */ + color?: 'neutral' | 'accent'; + + /** ReactNode to display as an icon before the label */ + leadingIcon?: React.ReactNode; + + /** ReactNode to display as an icon after the label */ + trailingIcon?: React.ReactNode; + + /** + * Boolean to show a dismiss button (replaces trailingIcon) + */ + isDismissible?: boolean; + + /** Callback function when dismiss button is clicked */ + onDismiss?: () => void; + + /** Content to display inside the chip */ + children?: React.ReactNode; + + /** Additional CSS class names */ + className?: string; + + /** + * ARIA role for the chip + * @defaultValue "status" + */ + role?: string; + + /** Custom accessibility label for the chip */ + ariaLabel?: string; +} diff --git a/apps/www-beta/src/content/docs/components/color-picker/demo.ts b/apps/www-beta/src/content/docs/components/color-picker/demo.ts new file mode 100644 index 000000000..0ea1382d3 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/color-picker/demo.ts @@ -0,0 +1,83 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + + + + + +` +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + +` +}; + +export const popoverDemo = { + type: 'code', + previewCode: false, + code: ``, + codePreview: [ + { + label: 'index.tsx', + code: `function PopoverColorPicker() { + const [color, setColor] = useState('#DA2929'); + + return ( + + + + + + + ${title} + + + + + ${description} + + + + + + + + `; +}; + +export const playground = { + type: 'playground', + controls: { + title: { type: 'text', initialValue: 'A simple dialog example' }, + description: { + type: 'text', + initialValue: 'This is a basic dialog with title and description.' + } + }, + getCode +}; + +export const controlledDemo = { + type: 'code', + code: ` + function ControlledDialog() { + const [open, setOpen] = React.useState(false); + + return ( + + + + + + + Controlled State + + This dialog's state is controlled externally. + + + + + ); + }` +}; + +export const customDemo = { + type: 'code', + code: ` + + + + + + + Custom Styled Dialog + + This dialog has custom width and overlay styling. + + + + ` +}; + +export const onlyHeaderDemo = { + type: 'code', + code: ` + + + + + + + Title + + + + + This dialog has custom width and overlay styling. + + + + ` +}; + +export const onlyFooterDemo = { + type: 'code', + code: ` + + + + + + + Title + + This dialog has custom width and overlay styling. + + + + + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/dialog/index.mdx b/apps/www-beta/src/content/docs/components/dialog/index.mdx new file mode 100644 index 000000000..d878548fe --- /dev/null +++ b/apps/www-beta/src/content/docs/components/dialog/index.mdx @@ -0,0 +1,86 @@ +--- +title: Dialog +description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. +--- + +import { playground, closeDemo, customDemo, controlledDemo, onlyHeaderDemo, onlyFooterDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Dialog } from '@raystack/apsara' +``` + +## Dialog Props + + + +### Dialog.Content Props + + + + +### Dialog.Header Props + + + +### Dialog.Title Props + + + +### Dialog.Body Props + + + +### Dialog.Description Props + + + +### Dialog.Trigger Props + + + +### Dialog.CloseButton Props + + + + +### Dialog.Footer Props + + + +## Examples + +### Controlled Dialog + +Example of a controlled dialog with custom state management. + + + +### Custom Width and Overlay + +Example with custom width and overlay styling. + + + + +### With Header and Body + +Example with header and body. + + + +### With Body and Footer + +Example with header and body. + + + + +### Accessibility + +- Dialog has `role="dialog"` and `aria-modal="true"` +- Uses `aria-label` or `aria-labelledby` to identify the dialog +- Uses `aria-describedby` to provide additional context diff --git a/apps/www-beta/src/content/docs/components/dialog/props.ts b/apps/www-beta/src/content/docs/components/dialog/props.ts new file mode 100644 index 000000000..67a9ee7f2 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/dialog/props.ts @@ -0,0 +1,88 @@ +export interface DialogProps { + /** Controls the open state of the dialog */ + open?: boolean; + + /** Callback when open state changes */ + onOpenChange?: (open: boolean) => void; + + /** + * Whether the dialog is modal + * @default true + */ + modal?: boolean; +} + +export interface DialogContentProps { + /** Controls dialog width */ + width?: string | number; + + /** Enables backdrop blur effect */ + overlayBlur?: boolean; + + /** Custom class for overlay styling */ + overlayClassName?: string; + + /** Custom styles for overlay */ + overlayStyle?: React.CSSProperties; + + /** Additional CSS class names */ + className?: string; + + /** Position of the dialog */ + side?: 'top' | 'right' | 'bottom' | 'left'; + + /** Accessible label for the dialog */ + ariaLabel?: string; + + /** Detailed description for screen readers */ + ariaDescription?: string; +} + +export interface DialogHeaderProps { + /** Additional CSS class names */ + className?: string; + + children?: React.ReactNode; +} + +export interface DialogBodyProps { + /** Additional CSS class names */ + className?: string; + + children?: React.ReactNode; +} + +export interface DialogTitleProps { + /** Additional CSS class names */ + className?: string; + + children?: React.ReactNode; +} + +export interface DialogDescriptionProps { + /** Additional CSS class names for description */ + className?: string; +} + +export interface DialogTriggerProps { + /** Boolean to merge props onto child element */ + asChild?: boolean; + + /** Additional CSS class names */ + className?: string; +} + +export interface DialogCloseButtonProps { + /** Boolean to merge props onto child element */ + asChild?: boolean; + + /** Additional CSS class names */ + className?: string; +} + +export interface DialogFooterProps { + /** Additional CSS class names */ + className?: string; + + children?: React.ReactNode; +} diff --git a/apps/www-beta/src/content/docs/components/dropdown/demo.ts b/apps/www-beta/src/content/docs/components/dropdown/demo.ts new file mode 100644 index 000000000..1060fdfd6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/dropdown/demo.ts @@ -0,0 +1,447 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ` + + + + + + + Assign member... + Subscribe... + Rename... + + + Actions + + + Export + + + + All (.zip) + + CSV + + + All + 3 Months + 6 Months + + + + + PDF + + + All + 3 Months + 6 Months + + + + + Copy + + ⌘⇧D + + }> + Delete... + + + `; +}; + +export const playground = { + type: 'playground', + controls: { + autocomplete: { + type: 'checkbox', + defaultValue: false + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + + Profile + Settings + + Logout + + ` +}; +export const iconsDemo = { + type: 'code', + code: ` + + + + + + 📝}>Edit + 📋} trailingIcon={<>⌘C}>Copy + + 🗑️}>Delete + + ` +}; + +export const customDemo = { + type: 'code', + code: ` + + + + + + Actions + + New File + New Folder + + + Sort By + + Name + Date + + + ` +}; + +export const autocompleteDemo = { + type: 'code', + tabs: [ + { + name: 'Default Autocomplete', + code: ` + + + + + + + Heading + Assign member... + Subscribe... + Rename... + + + Actions + + Export + + All (.zip) + + CSV + + All + 3 Months + 6 Months + + + + PDF + + All + 3 Months + 6 Months + + + + + Copy + + ⌘⇧D + + }> + Delete... + + + ` + }, + { + name: 'Manual Autocomplete', + code: ` + function ManualDemo(){ + const items = [ + "Assign member...", + "Subscribe...", + "Rename...", + "Copy", + "Delete...", + ]; + + const [simpleSearchQuery, setSimpleSearchQuery] = React.useState(""); + return setSimpleSearchQuery(value)}> + + + + + {items + .filter(item => item.toLowerCase().includes(simpleSearchQuery)) + .map((item, index) => ( + {item} + ))} + + + }` + } + ] +}; + +export const linearDemo = { + type: 'code', + previewCode: false, + code: ``, + codePreview: [ + { + label: 'index.tsx', + code: `function LinearDropdownDemo() { + const [searchQuery, setSearchQuery] = useState(""); + + const renderDropdownMenu = (items: DropdownMenuItem[], query: string) => { + const filteredItems = filterDropdownMenuItems(items, query); + + if (searchQuery && filteredItems.length === 0) { + return
No results
; + } + + return filteredItems.map((item, index) => { + switch (item.type) { + case "group": + return ( + + {item.label} + {item.items && renderDropdownMenu(item.items, query)} + + ); + case "separator": + return ; + case "submenu": + return ( + + + {item.label} + + + {item.items && renderDropdownMenu(item.items, query)} + + + ); + case "item": + return ( + + {Array.isArray(item.label) + ? item.label.map((part, i) => ( + + {i > 0 && } + {part} + + )) + : item.label} + + ); + default: + return null; + } + }); + }; + + return ( + setSearchQuery(value)}> + + + + + {renderDropdownMenu(dropdownMenuData, searchQuery)} + + + ); +} +` + }, + { + label: 'utils.ts', + code: `function filterDropdownMenuItems( + items: DropdownMenuItem[], + query: string, + path: string[] = [], + isInsideSubmenu = false, +): DropdownMenuItem[] { + if (!query?.length) return items; + const normalizedQuery = query.trim().toLowerCase(); + const results: DropdownMenuItem[] = []; + + for (const item of items) { + if (item.type === "separator") continue; + + if (item.type === "item") { + const fullPath = isInsideSubmenu ? [...path, item.label] : [item.label]; + const flatLabel = fullPath.join(" ").toLowerCase(); + if (flatLabel.includes(normalizedQuery)) { + results.push({ + ...item, + label: fullPath, + } as DropdownMenuItem); + } + } + + if (item.type === "submenu") { + const nested = filterDropdownMenuItems( + item.items, + query, + [...path, item.label], + true, + ); + results.push(...nested); + } + + if (item.type === "group") { + const nested = filterDropdownMenuItems( + item.items, + query, + path, + isInsideSubmenu, + ); + results.push(...nested); + } + } + + return results.slice(0, 8); +}` + }, + { + label: 'data.ts', + code: `type DropdownMenuItem = + | { + type: "item"; + label: string | string[]; + disabled?: boolean; + trailingIcon?: ReactNode; + leadingIcon?: ReactNode; + } + | { type: "separator" } + | { type: "group"; label: string; items: DropdownMenuItem[] } + | { + type: "submenu"; + label: string; + items: DropdownMenuItem[]; + trailingIcon?: ReactNode; + leadingIcon?: ReactNode; + }; + +const dropdownMenuData: DropdownMenuItem[] = [ + { + type: "group", + label: "Heading", + items: [ + { type: "item", label: "Assign member..." }, + { type: "item", label: "Subscribe..." }, + { type: "item", label: "Rename..." }, + ], + }, + { type: "separator" }, + { + type: "group", + label: "Actions", + items: [ + { + type: "submenu", + label: "Export", + items: [ + { + type: "item", + label: "All (.zip)", + leadingIcon: , + }, + { + type: "submenu", + label: "CSV", + leadingIcon: , + items: [ + { + type: "item", + label: "All", + leadingIcon: , + }, + { + type: "item", + label: "3 Months", + leadingIcon: , + }, + { + type: "item", + label: "6 Months", + leadingIcon: , + }, + ], + }, + { + type: "submenu", + label: "PDF", + leadingIcon: , + items: [ + { + type: "item", + label: "All", + leadingIcon: , + }, + { + type: "item", + label: "3 Months", + leadingIcon: , + }, + { + type: "item", + label: "6 Months", + leadingIcon: , + }, + ], + }, + ], + }, + { type: "item", label: "Copy", disabled: true }, + { + type: "item", + label: "Delete...", + trailingIcon: ( + + ⌘⇧D + + ), + }, + ], + }, +];` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/dropdown/index.mdx b/apps/www-beta/src/content/docs/components/dropdown/index.mdx new file mode 100644 index 000000000..2e71f712c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/dropdown/index.mdx @@ -0,0 +1,117 @@ +--- +title: Dropdown Menu +description: Displays a menu to the user, such as a set of actions or functions, triggered by a button. +--- + +import { + playground, + iconsDemo, + customDemo, + basicDemo, + autocompleteDemo, + linearDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { DropdownMenu } from '@raystack/apsara' +``` + +## Dropdown Props + +The DropdownMenu component is composed of several parts, each with their own props. + +The root element is the parent component that holds the dropdown menu. Using the `autocomplete` prop, you can enable autocomplete functionality. Built on top of [Ariakit MenuProvider](https://ariakit.org/reference/menu-provider) + + + +### DropdownMenu.Trigger Props + +The button that triggers the dropdown menu. Built on top of [Ariakit MenuButton](https://ariakit.org/reference/menu-button) + +By default, the click event is not propagated. You can override this behavior by passing `stopPropagation={false}`. + + + +### DropdownMenu.TriggerItem Props + +`TriggerItem` is a helper component that renders a `DropdownMenu.Trigger` as a `DropdownMenu.MenuItem`. + +Accepts all `DropdownMenu.Item` props. The component is helpful to match styles for sub menu trigger. Use DropdownMenu.Trigger if you want more control. + +### DropdownMenu.Content Props + +The container that holds the dropdown menu items. Built on top of [Ariakit Menu](https://ariakit.org/reference/menu) + + + +### DropdownMenu.Item Props + +Individual clickable options within the dropdown menu. Built on top of [Ariakit MenuItem](https://ariakit.org/reference/menu-item). + +Renders as an [Ariakit ComboboxItem](https://ariakit.org/reference/combobox-item) when used in an autocomplete dropdown. By default, the item's `children` is used for matching and selection, which can be overriden by passing a `value` prop. + + + +### DropdownMenu.Group Props + +A way to group related menu items together. Built on top of [Ariakit MenuGroup](https://ariakit.org/reference/menu-group) + + + +### DropdownMenu.Label Props + +Renders a label in a menu group. This component should be wrapped with DropdownMenu.Group so the `aria-labelledby` is correctly set on the group element. Built on top of [Ariakit MenuGroupLabel](https://ariakit.org/reference/menu-group-label) + + + +### DropdownMenu.Separator Props + +Visual divider between menu items or groups. Built on top of [Ariakit MenuSeparator](https://ariakit.org/reference/menu-separator) + + + +### DropdownMenu.EmptyState Props + +Placeholder content when there are no menu items to display. + + + +## Examples + +### Basic Usage + +A simple dropdown menu with basic functionality. + + + +### With Icons + +You can add icons to the dropdown items. Supports both leading and trailing icons. + + + +### With Groups and Labels + +Organize related menu items into sections with descriptive headers. + + + +### Autocomplete + +To enable autocomplete, pass the `autocomplete` prop to the Dropdown root element. Each menu instance will manage its own autocomplete behavior. + +By default, only the top-level menu items are filtered. For more advanced control, set `autocompleteMode="manual"` and implement your own custom filtering logic. + + + +### Linear inspired Dropdown + +This is a Linear-inspired dropdown component that supports custom filtering and displays nested options. Users can search through all nested items using a single input field. + +To closely replicate Linear-style filtering, the filtering logic should include result ranking. Using a utility like [match-sorter](https://www.npmjs.com/package/match-sorter) can help achieve this by sorting filtered results based on relevance. + + diff --git a/apps/www-beta/src/content/docs/components/dropdown/props.ts b/apps/www-beta/src/content/docs/components/dropdown/props.ts new file mode 100644 index 000000000..e9135e35c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/dropdown/props.ts @@ -0,0 +1,134 @@ +export interface DropdownMenuRootProps { + /** Enables search functionality within the dropdown menu */ + autocomplete?: boolean; + + /** Controls the autocomplete behavior mode + * - "auto": Automatically filters items as user types + * - "manual": Requires explicit filtering through onSearch callback + * @default "auto" + */ + autocompleteMode?: 'auto' | 'manual'; + + /** Current search value for autocomplete */ + searchValue?: string; + + /** Initial search value for autocomplete */ + defaultSearchValue?: string; + + /** Callback fired when the search value changes */ + onSearch?: (value: string) => void; + + /** Placement of the dropdown relative to the trigger + * @default "bottom-start"" + */ + placement?: + | 'top' + | 'top-start' + | 'top-end' + | 'bottom' + | 'bottom-start' + | 'bottom-end' + | 'left' + | 'left-start' + | 'left-end' + | 'right' + | 'right-start' + | 'right-end'; + + /** Whether the dropdown should loop focus when navigating with keyboard + * @default true + */ + focusLoop?: boolean; + + /** Control the open state of the dropdown + * @default false + */ + open?: boolean; + + /** Callback fired when the dropdown is opened or closed */ + onOpenChange?: (open: boolean) => void; +} + +export interface DropdownMenuTriggerProps { + /** Boolean to merge props onto child element */ + asChild?: boolean; + + /** Whether the dropdown should stop propagation of the click event + * @default true + */ + stopPropagation?: boolean; +} + +export interface DropdownMenuContentProps { + /** Placeholder text for the autocomplete search input + * @default "Search..." + */ + searchPlaceholder?: string; + + /** + * The distance between the popover and the anchor element. + * @default 4 + */ + gutter?: number; + + /** + * The skidding of the popover along the anchor element. Can be set to negative values to make the popover shift to the opposite side. + * @default 0 + */ + shift?: number; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface DropdownMenuItemProps { + /** Icon element to display before item text */ + leadingIcon?: React.ReactNode; + + /** Icon element to display after item text */ + trailingIcon?: React.ReactNode; + + /** Whether the item is disabled */ + disabled?: boolean; + + /** Value of the item to be used for autocomplete */ + value?: string; + + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface DropdownMenuGroupProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface DropdownMenuLabelProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface DropdownMenuSeparatorProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface DropdownMenuEmptyStateProps { + /** React nodes to render in empty state */ + children?: React.ReactNode; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/empty-state/demo.ts b/apps/www-beta/src/content/docs/components/empty-state/demo.ts new file mode 100644 index 000000000..5f559e78f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/empty-state/demo.ts @@ -0,0 +1,66 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return `Primary Action} + secondaryAction={} + />`; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + initialValue: 'empty1', + options: ['empty1', 'empty2'] + }, + heading: { + type: 'text', + initialValue: 'No Data Available' + }, + subHeading: { + type: 'text', + initialValue: 'Try adjusting your filters.' + }, + icon: { + type: 'icon', + initialValue: '' + } + }, + getCode +}; + +export const variantsDemo = { + type: 'code', + code: ` + + } + heading="No notifications yet" + subHeading="When you have notifications, they will appear here" + primaryAction={ + + } + secondaryAction={ + + } + /> + } + heading="Organization" + subHeading="An organization in Aurora is a shared workspace where teams manage projects, AOIs, and image orders. It streamlines collaboration, analysis, and decision-making across industries." + primaryAction={ + + } + secondaryAction={ + + } + /> + ` +}; diff --git a/apps/www-beta/src/content/docs/components/empty-state/index.mdx b/apps/www-beta/src/content/docs/components/empty-state/index.mdx new file mode 100644 index 000000000..2c35cd827 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/empty-state/index.mdx @@ -0,0 +1,18 @@ +--- +title: Empty State +description: Displays an empty state +--- + +import { playground, variantsDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { EmptyState } from '@raystack/apsara' +``` + +## EmptyState Props + + diff --git a/apps/www-beta/src/content/docs/components/empty-state/props.ts b/apps/www-beta/src/content/docs/components/empty-state/props.ts new file mode 100644 index 000000000..60d6e169f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/empty-state/props.ts @@ -0,0 +1,39 @@ +export interface EmptyStateProps { + /** Icon to show in top of empty state */ + icon?: React.ReactNode; + + /** Primary heading message */ + heading?: string; + + /** Secondary heading message */ + subHeading?: string; + + /** Action to show in empty state like button or link */ + primaryAction?: React.ReactNode; + + /** Secondary action to show in empty state like button or link */ + secondaryAction?: React.ReactNode; + + /** Visual style variant of the empty state + * @default "empty1" + */ + variant?: 'empty1' | 'empty2'; + + /** Map of classNames for internal components */ + classNames?: { + /** Class for the container */ + container?: string; + + /** Class for the icon container */ + iconContainer?: string; + + /** Class for the icon */ + icon?: string; + + /** Class for the heading */ + heading?: string; + + /** Class for the subheading */ + subHeading?: string; + }; +} diff --git a/apps/www-beta/src/content/docs/components/flex/demo.ts b/apps/www-beta/src/content/docs/components/flex/demo.ts new file mode 100644 index 000000000..79c82de28 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/flex/demo.ts @@ -0,0 +1,60 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ` + + + + + `; +}; +export const playground = { + type: 'playground', + controls: { + gap: { + type: 'select', + options: ['extra-small', 'small', 'medium', 'large', 'extra-large'], + initialValue: 'small' + }, + wrap: { + type: 'select', + options: ['nowrap', 'wrap', 'wrap-reverse'], + initialValue: 'wrap' + }, + justify: { + type: 'select', + options: ['start', 'end', 'center', 'between'], + initialValue: 'center' + }, + align: { + type: 'select', + options: ['start', 'end', 'center', 'baseline', 'stretch'], + initialValue: 'center' + }, + direction: { + type: 'select', + options: ['row', 'rowReverse', 'column', 'columnReverse'], + initialValue: 'row' + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + + + + + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/flex/index.mdx b/apps/www-beta/src/content/docs/components/flex/index.mdx new file mode 100644 index 000000000..35bbbd750 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/flex/index.mdx @@ -0,0 +1,24 @@ +--- +title: Flex +description: Component for flexbox +--- + +import { playground, basicDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Flex } from "@raystack/apsara"; +``` + +## Flex Props + + + +## Examples + +### Basic Usage + + diff --git a/apps/www-beta/src/content/docs/components/flex/props.ts b/apps/www-beta/src/content/docs/components/flex/props.ts new file mode 100644 index 000000000..c95e29b9e --- /dev/null +++ b/apps/www-beta/src/content/docs/components/flex/props.ts @@ -0,0 +1,19 @@ +export interface FlexProps { + /** Sets the gutter space between row and columns */ + gap?: 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'; + + /** Sets whether flex items are forced onto one line or can wrap onto multiple lines */ + wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; + + /** Defines how the browser distributes space between and around content items along the main axis */ + justify?: 'start' | 'end' | 'center' | 'between'; + + /** Controls the alignment of items on the cross axis */ + align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'; + + /** Sets how flex items are placed in the flex container defining the main axis and the direction (normal or reversed) */ + direction?: 'row' | 'rowReverse' | 'column' | 'columnReverse'; + + /** Custom CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/fliter-chip/demo.ts b/apps/www-beta/src/content/docs/components/fliter-chip/demo.ts new file mode 100644 index 000000000..fe3fe5dac --- /dev/null +++ b/apps/www-beta/src/content/docs/components/fliter-chip/demo.ts @@ -0,0 +1,150 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { onRemove, ...rest } = props; + const onRemoveProp = onRemove ? `onRemove={() => alert("Removed")}` : ''; + + if (props.columnType === 'select') + return ` + `; + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + columnType: { + type: 'select', + options: ['select', 'date', 'string', 'number'], + defaultValue: 'string' + }, + variant: { + type: 'select', + options: ['default', 'text'], + defaultValue: 'default' + }, + label: { + type: 'text', + initialValue: 'Status' + }, + leadingIcon: { type: 'icon' }, + onRemove: { + type: 'checkbox', + defaultValue: false + } + }, + getCode +}; + +export const inputDemo = { + type: 'code', + tabs: [ + { + name: 'Select', + code: ` +} + columnType="select" + options={[ + { label: "Active", value: "active" }, + { label: "Inactive", value: "inactive" } + ]} +/>` + }, + { + name: 'Date', + code: ` +} + columnType="date" +/>` + }, + { + name: 'String', + code: ` +} + columnType="string" +/>` + }, + { + name: 'Number', + code: ` +} + columnType="number" +/>` + } + ] +}; + +export const iconDemo = { + type: 'code', + code: ` + } + columnType="select" + options={[ + { label: "Active", value: "active" }, + { label: "Inactive", value: "inactive" } + ]} +/>` +}; +export const actionDemo = { + type: 'code', + code: ` + } + columnType="select" + options={[ + { label: "Active", value: "active" }, + { label: "Inactive", value: "inactive" } + ]} + onRemove={() => alert('Removed')} +/>` +}; +export const operationsDemo = { + type: 'code', + code: ` + + } + columnType="select" + options={[ + { label: "Active", value: "active" }, + { label: "Inactive", value: "inactive" } + ]} + operations={[ + { label: "is", value: "is" }, + { label: "is not", value: "is not" } + ]} +/> +} + columnType="select" + options={[ + { label: "Active", value: "active" }, + { label: "Inactive", value: "inactive" } + ]} + operations={[ + { label: "is", value: "is" }, + ]} +/> +` +}; diff --git a/apps/www-beta/src/content/docs/components/fliter-chip/index.mdx b/apps/www-beta/src/content/docs/components/fliter-chip/index.mdx new file mode 100644 index 000000000..a84d3c36b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/fliter-chip/index.mdx @@ -0,0 +1,48 @@ +--- +title: FilterChip +description: A compact, interactive element for filtering data with various input types. +--- + +import { playground, inputDemo, iconDemo, actionDemo, operationsDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { FilterChip } from "@raystack/apsara"; +``` + +## FilterChip Props + + + +## Examples + +### Input Types + +FilterChip supports four different input types to handle various filtering needs. + + + +### With Leading Icon + +FilterChip can display an icon before the label to provide visual context. + + + +### With Remove Action + +FilterChip can include a remove action to allow users to dismiss the filter. + + + +### Custom Operations + +FilterChip supports custom filter operations through the `operations` prop. When specified, these operations override the default operations that are automatically selected based on the `columnType`. + +- When multiple operations are provided, they are rendered as a select dropdown +- When a single operation is provided, it is displayed as static text +- If no operations are specified, default operations are used based on the column type + + diff --git a/apps/www-beta/src/content/docs/components/fliter-chip/props.ts b/apps/www-beta/src/content/docs/components/fliter-chip/props.ts new file mode 100644 index 000000000..b0f9333a6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/fliter-chip/props.ts @@ -0,0 +1,38 @@ +export interface FilterChipProps { + /** Text label for the filter (required) */ + label: string; + + /** Current value of the filter */ + value?: string; + + /** Type of input for the filter + * @default "string" + */ + columnType?: 'select' | 'date' | 'string' | 'number'; + + /** Filterchip variant + * @default "default" + */ + variant?: 'default' | 'text'; + + /** Array of options for the select type input */ + options?: { label: string; value: string }[]; + + /** Optional array of operations for the type of filter oepration */ + operations?: { label: string; value: string }[]; + + /** Callback when the filter value changes */ + onValueChange?: (value: string) => void; + + /** Callback when the filter operation changes */ + onOperationChange?: (operation: string) => void; + + /** Icon element to display before the label */ + leadingIcon?: React.ReactNode; + + /** Callback to remove the filter chip */ + onRemove?: () => void; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/grid/demo.ts b/apps/www-beta/src/content/docs/components/grid/demo.ts new file mode 100644 index 000000000..c55bb8c99 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/grid/demo.ts @@ -0,0 +1,66 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ` + + + + + + + + + + `; +}; +export const playground = { + type: 'playground', + controls: { + gap: { + type: 'select', + options: ['extra-small', 'small', 'medium', 'large', 'extra-large'], + initialValue: 'small' + }, + rows: { + type: 'number', + min: 1, + max: 10, + initialValue: 4 + }, + columns: { + type: 'number', + min: 1, + max: 10, + initialValue: 2 + }, + justifyItems: { + type: 'select', + options: ['start', 'end', 'center', 'stretch'], + initialValue: 'center' + }, + alignItems: { + type: 'select', + options: ['start', 'end', 'center', 'stretch'], + initialValue: 'center' + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + 4 + 5 + 6 +` +}; diff --git a/apps/www-beta/src/content/docs/components/grid/index.mdx b/apps/www-beta/src/content/docs/components/grid/index.mdx new file mode 100644 index 000000000..b559329c6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/grid/index.mdx @@ -0,0 +1,30 @@ +--- +title: Grid +description: A flexible and powerful component for grid layout +--- + +import { playground, basicDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Grid } from "@raystack/apsara"; +``` + +## Grid Props + + + +### Grid.Item Props + +Grid.Item is a wrapper component that must be a direct child of Grid. Use it when you need to customize the positioning or styling of individual grid items. + + + +## Examples + +### Basic Usage + + diff --git a/apps/www-beta/src/content/docs/components/grid/props.ts b/apps/www-beta/src/content/docs/components/grid/props.ts new file mode 100644 index 000000000..a172dcd17 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/grid/props.ts @@ -0,0 +1,156 @@ +export interface GridProps { + /** + * Defines named grid areas using CSS Grid template areas syntax. + */ + templateAreas?: string | string[]; + + /** + * Controls how auto-placed items flow into the grid. + * - "row": Items flow by row + * - "column": Items flow by column + * - "dense": Attempts to fill in holes in the grid + */ + autoFlow?: 'row' | 'column' | 'dense' | 'row dense' | 'column dense'; + + /** + * Sets the size of auto-generated columns. + * Accepts any valid CSS size value. + */ + autoColumns?: string; + + /** + * Sets the size of auto-generated rows. + * Accepts any valid CSS size value. + */ + autoRows?: string; + + /** + * Defines the columns of the grid. Supports CSS Grid template columns syntax. + * + * If you pass a number, columns will be created using repeat(n, 1fr). + */ + columns?: string | number; + + /** + * Defines the rows of the grid. Supports CSS Grid template rows syntax. + * + * If you pass a number, rows will be created using repeat(n, 1fr). + */ + rows?: string | number; + + /** + * Sets the gap between grid items. + */ + gap?: 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'; + + /** + * Sets the gap between grid columns. + */ + columnGap?: 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'; + + /** + * Sets the gap between grid rows. + */ + rowGap?: 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'; + + /** + * Aligns grid items along the inline (row) axis. + */ + justifyItems?: 'start' | 'end' | 'center' | 'stretch'; + + /** + * Aligns grid items along the block (column) axis. + */ + alignItems?: 'start' | 'end' | 'center' | 'stretch'; + + /** + * Aligns the entire grid along the inline (row) axis. + */ + justifyContent?: + | 'start' + | 'end' + | 'center' + | 'stretch' + | 'space-around' + | 'space-between' + | 'space-evenly'; + + /** + * Aligns the entire grid along the block (column) axis. + */ + alignContent?: + | 'start' + | 'end' + | 'center' + | 'stretch' + | 'space-around' + | 'space-between' + | 'space-evenly'; + + /** + * Renders the grid as an inline element instead of a block element. + * + * @default false + */ + inline?: boolean; + + /** + * Merges the grid's props with its child component. + * Useful for composition with other components. + */ + asChild?: boolean; +} + +export interface GridItemProps { + /** + * Specifies the named grid area where the item should be placed. + * Must match a named area defined in the parent Grid's templateAreas. + */ + area?: string; + + /** + * Defines the starting column line where the item should be placed. + */ + colStart?: number | string; + + /** + * Defines the ending column line where the item should be placed. + */ + colEnd?: number | string; + + /** + * Defines the starting row line where the item should be placed. + */ + rowStart?: number | string; + + /** + * Defines the ending row line where the item should be placed. + */ + rowEnd?: number | string; + + /** + * Specifies how many columns the item should span. + */ + colSpan?: number | string; + + /** + * Specifies how many rows the item should span. + */ + rowSpan?: number | string; + + /** + * Aligns the item along the inline (row) axis within its grid area. + */ + justifySelf?: 'start' | 'end' | 'center' | 'stretch'; + + /** + * Aligns the item along the block (column) axis within its grid area. + */ + alignSelf?: 'start' | 'end' | 'center' | 'stretch'; + + /** + * Merges the grid item's props with its child component. + * Useful for composition with other components. + */ + asChild?: boolean; +} diff --git a/apps/www-beta/src/content/docs/components/headline/demo.ts b/apps/www-beta/src/content/docs/components/headline/demo.ts new file mode 100644 index 000000000..be24e1992 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/headline/demo.ts @@ -0,0 +1,52 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['t1', 't2', 't3', 't4'], + defaultValue: 't1' + }, + as: { + type: 'select', + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + defaultValue: 'h2' + }, + align: { + type: 'select', + options: ['left', 'center', 'right'], + defaultValue: 'left', + initialValue: 'center' + }, + truncate: { type: 'checkbox', defaultValue: false }, + children: { type: 'text', initialValue: 'This is a Headline' } + }, + getCode +}; + +export const alignDemo = { + type: 'code', + code: ` + + Left Aligned + Center Aligned + Right Aligned + ` +}; +export const truncateDemo = { + type: 'code', + code: ` + + + This is a very long headline that will be truncated with an ellipsis + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/headline/index.mdx b/apps/www-beta/src/content/docs/components/headline/index.mdx new file mode 100644 index 000000000..57081d98b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/headline/index.mdx @@ -0,0 +1,28 @@ +--- +title: Headline +description: A typographic component for displaying headings with different sizes and alignments. +--- + +import { playground, alignDemo, truncateDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Headline } from '@raystack/apsara' +``` + +## Headline Props + + + +## Examples + +### Alignment + + + +### Truncation + + diff --git a/apps/www-beta/src/content/docs/components/headline/props.ts b/apps/www-beta/src/content/docs/components/headline/props.ts new file mode 100644 index 000000000..0fdf6bbdb --- /dev/null +++ b/apps/www-beta/src/content/docs/components/headline/props.ts @@ -0,0 +1,28 @@ +export interface HeadlineProps { + /** + * Controls the size of the headline. + * @default "t1" + */ + size?: 't1' | 't2' | 't3' | 't4'; + + /** + * HTML heading element to render. + * @default "h2" + */ + as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + + /** + * Text alignment. + * @default "left" + */ + align?: 'left' | 'center' | 'right'; + + /** + * Enable text truncation with ellipsis. + * @default false + */ + truncate?: boolean; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/icon-button/demo.ts b/apps/www-beta/src/content/docs/components/icon-button/demo.ts new file mode 100644 index 000000000..a6c727712 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/icon-button/demo.ts @@ -0,0 +1,45 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: [1, 2, 3, 4], + defaultValue: 2, + initialValue: 4 + }, + disabled: { type: 'checkbox', defaultValue: false }, + children: { + type: 'icon', + initialValue: '' + } + }, + getCode +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + + + + ` +}; +export const stateDemo = { + type: 'code', + code: ` + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/icon-button/index.mdx b/apps/www-beta/src/content/docs/components/icon-button/index.mdx new file mode 100644 index 000000000..f9774803c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/icon-button/index.mdx @@ -0,0 +1,56 @@ +--- +title: IconButton +description: A button component designed specifically for icons with various sizes and states. +--- + +import { playground, stateDemo, sizeDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { IconButton } from "@raystack/apsara"; +``` + +## IconButton Props + + + +## Examples + +## Size + +The IconButton component offers different size options. You can customize the size using the `size` prop. The available size options are: + + + +### State + +The IconButton component has different states: default, hover, and disabled. + + + +## Styling + +The IconButton uses CSS variables for consistent styling across themes: + +- Background color uses `--rs-color-background-base-primary` +- Border color uses `--rs-color-border-base-primary` +- Text color uses `--rs-color-foreground-base-primary` +- Hover state uses `--rs-color-background-base-primary-hover` +- Disabled state uses reduced opacity and different background/border colors + +## Accessibility + +The IconButton component inherits all the accessibility features of the native HTML button element: + +- Keyboard navigation support +- Proper disabled state handling +- Can be focused and activated using keyboard +- Supports all standard button ARIA attributes + +For better accessibility, make sure to: + +- Provide meaningful aria-label when the button's purpose isn't clear from the icon alone +- Consider adding tooltips for icon-only buttons diff --git a/apps/www-beta/src/content/docs/components/icon-button/props.ts b/apps/www-beta/src/content/docs/components/icon-button/props.ts new file mode 100644 index 000000000..9605ecaf4 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/icon-button/props.ts @@ -0,0 +1,19 @@ +export interface IconButtonProps { + /** + * Size of the button. + * @default 2 + */ + size?: 1 | 2 | 3 | 4; + + /** + * Whether the button is disabled. + * @default false + */ + disabled?: boolean; + + /** Additional CSS class names. */ + className?: string; + + /** onClick function triggered when iconButton is clicked. */ + onClick?: (event: React.MouseEvent) => void; +} diff --git a/apps/www-beta/src/content/docs/components/image/demo.ts b/apps/www-beta/src/content/docs/components/image/demo.ts new file mode 100644 index 000000000..8dfe1bac6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/image/demo.ts @@ -0,0 +1,109 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + src: { + type: 'text', + initialValue: + 'https://images.unsplash.com/photo-1447690709975-318628b14c57' + }, + alt: { type: 'text', initialValue: 'Placeholder Image' }, + fit: { + type: 'select', + options: ['contain', 'cover', 'fill'], + defaultValue: 'cover' + }, + radius: { + type: 'select', + options: ['none', 'small', 'medium', 'full'], + defaultValue: 'none' + }, + width: { type: 'text', initialValue: '200px' }, + height: { type: 'text', initialValue: '200px' } + }, + getCode +}; + +export const fitDemo = { + type: 'code', + code: ` + + Nature landscape + Nature landscape + Nature landscape + ` +}; +export const radiusDemo = { + type: 'code', + code: ` + + Nature + Nature + Nature + Nature + ` +}; +export const fallbackDemo = { + type: 'code', + code: ` + + With fallback + ` +}; diff --git a/apps/www-beta/src/content/docs/components/image/index.mdx b/apps/www-beta/src/content/docs/components/image/index.mdx new file mode 100644 index 000000000..45fe12c24 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/image/index.mdx @@ -0,0 +1,78 @@ +--- +title: Image +description: A responsive image component with fallback support and various fitting options. +--- + +import { playground, radiusDemo, fitDemo, fallbackDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Image } from "@raystack/apsara"; +``` + +## Image Props + + + +## Examples + +### Object Fit + +Control how the image fills its container with different object-fit modes. + + + +### Border Radius + +Choose from different border radius styles to match your design. + + + +### Fallback + +Handle image loading failures gracefully with fallback images. + + + +## Styling + +The IconButton uses CSS variables for consistent styling across themes: + +- Background color uses `--rs-color-background-base-primary` +- Border color uses `--rs-color-border-base-primary` +- Text color uses `--rs-color-foreground-base-primary` +- Hover state uses `--rs-color-background-base-primary-hover` +- Disabled state uses reduced opacity and different background/border colors + +## Accessibility + +The IconButton component inherits all the accessibility features of the native HTML button element: + +- Keyboard navigation support +- Proper disabled state handling +- Can be focused and activated using keyboard +- Supports all standard button ARIA attributes + +For better accessibility, make sure to: + +- Provide meaningful aria-label when the button's purpose isn't clear from the icon alone +- Consider adding tooltips for icon-only buttons + +## Accessibility + +The Image component follows accessibility best practices: + +### ARIA Attributes + +- `role="img"`: Explicitly defines the image role for assistive technologies +- `aria-label`: Provides description matching alt text for screen readers +- `alt`: Required alternative text description for screen readers + +### Performance + +- `loading="lazy"`: Default lazy loading for better performance +- `decoding="async"`: Asynchronous image decoding to prevent blocking +- Fallback support for failed image loads diff --git a/apps/www-beta/src/content/docs/components/image/props.ts b/apps/www-beta/src/content/docs/components/image/props.ts new file mode 100644 index 000000000..27e2cbbeb --- /dev/null +++ b/apps/www-beta/src/content/docs/components/image/props.ts @@ -0,0 +1,31 @@ +export interface ImageProps { + /** The URL of the image to display */ + src: string; + + /** Alternative text description (required) */ + alt: string; + + /** + * Object-fit property + * @default cover + */ + fit?: 'contain' | 'cover' | 'fill'; + + /** + * Border radius style + * @deafult none + */ + radius?: 'none' | 'small' | 'medium' | 'full'; + + /** URL of fallback image to show on error */ + fallback?: string; + + /** Width of the image */ + width?: string | number; + + /** Height of the image */ + height?: string | number; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/indicator/demo.ts b/apps/www-beta/src/content/docs/components/indicator/demo.ts new file mode 100644 index 000000000..891fd446c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/indicator/demo.ts @@ -0,0 +1,59 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: ['accent', 'warning', 'danger', 'success', 'neutral'], + defaultValue: 'accent' + }, + label: { type: 'text', initialValue: '' }, + children: { + type: 'text', + initialValue: "" + } + }, + getCode +}; + +export const variantDemo = { + type: 'code', + code: ` + + + + + + + + + + + + + + + + + ` +}; +export const labelDemo = { + type: 'code', + code: ` + + + + + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/indicator/index.mdx b/apps/www-beta/src/content/docs/components/indicator/index.mdx new file mode 100644 index 000000000..1c9e4b83b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/indicator/index.mdx @@ -0,0 +1,59 @@ +--- +title: Indicator +description: A small dot indicator with small information that can be positioned on top of other components. +--- + +import { playground, labelDemo, variantDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Indicator } from "@raystack/apsara"; +``` + +## Indicator Props + + + +## Examples + +### Variant + +The Indicator component supports different variants to convey different states or meanings: + + + +### Label + +When no label is provided, the Indicator will show as a dot + + + +## Accessibility + +The Indicator component includes several accessibility features: + +- Uses `role="status"` to indicate its purpose to screen readers +- Provides appropriate `aria-label` based on the content: + - Uses custom `ariaLabel` prop if provided + - Falls back to the label text if available + - Uses a default "indicator" if neither is provided +- Hides decorative dot from screen readers when no label is present + +Example with custom aria label: + +```tsx + +
+ Content with custom aria label +
+
+``` diff --git a/apps/www-beta/src/content/docs/components/indicator/props.ts b/apps/www-beta/src/content/docs/components/indicator/props.ts new file mode 100644 index 000000000..c2cd153a6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/indicator/props.ts @@ -0,0 +1,19 @@ +export interface IndicatorProps { + /** + * Visual style variant + * @default "accent" + */ + variant?: 'accent' | 'warning' | 'danger' | 'success' | 'neutral'; + + /** Optional text label to display (if omitted, shows a dot) */ + label?: string; + + /** Optional custom description for screen readers */ + ariaLabel?: string; + + /** The content to show the indicator on */ + children: React.ReactNode; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/input-field/demo.ts b/apps/www-beta/src/content/docs/components/input-field/demo.ts new file mode 100644 index 000000000..097d7f67c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/input-field/demo.ts @@ -0,0 +1,140 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + label: { type: 'text', initialValue: 'Your Name' }, + helperText: { type: 'text', initialValue: 'Enter your full name' }, + error: { type: 'text', initialValue: '' }, + disabled: { type: 'boolean', initialValue: false }, + leadingIcon: { type: 'icon', initialValue: '' }, + trailingIcon: { type: 'icon', initialValue: '' }, + optional: { type: 'checkbox', defaultValue: false }, + prefix: { type: 'text', initialValue: '' }, + suffix: { type: 'text', initialValue: '' }, + size: { + type: 'select', + options: ['small', 'large'], + initialValue: 'large' + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + ` +}; +export const helperTextDemo = { + type: 'code', + code: ` + ` +}; +export const errorDemo = { + type: 'code', + code: ` + ` +}; +export const prefixDemo = { + type: 'code', + code: ` + ` +}; +export const iconDemo = { + type: 'code', + code: ` + } + trailingIcon={} +/>` +}; +export const optionalDemo = { + type: 'code', + code: ` + ` +}; +export const disabledDemo = { + type: 'code', + code: ` +` +}; +export const widthDemo = { + type: 'code', + code: ` +` +}; +export const sizeDemo = { + type: 'code', + code: ` + + + +` +}; +export const sizeChipDemo = { + type: 'code', + code: ` + + console.log("Remove A") }, + { label: "B", onRemove: () => console.log("Remove B") } + ]} + /> + console.log("Remove A") }, + { label: "B", onRemove: () => console.log("Remove B") } + ]} + /> +` +}; diff --git a/apps/www-beta/src/content/docs/components/input-field/index.mdx b/apps/www-beta/src/content/docs/components/input-field/index.mdx new file mode 100644 index 000000000..1c0a8476c --- /dev/null +++ b/apps/www-beta/src/content/docs/components/input-field/index.mdx @@ -0,0 +1,92 @@ +--- +title: Input Field +description: A text input component with support for labels, helper text, and various states. +--- + +import { + playground, + basicDemo, + helperTextDemo, + errorDemo, + prefixDemo, + iconDemo, + optionalDemo, + disabledDemo, + widthDemo, + sizeDemo, + sizeChipDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { InputField } from "@raystack/apsara"; +``` + +## InputField Props + + + +## Examples + +### Basic Input + +A basic input field with a label and placeholder. + + + +### With Helper Text + +Input field with additional helper text below. + + + +### With Error + +Input field displaying an error state with error message. + + + +### With Prefix/Suffix + +Input field with prefix and suffix text. + + + +### With Icons + +Input field with leading and trailing icons. + + + +### Optional Field + +Input field marked as optional. + + + +### Disabled State + +Input field in disabled state. + + + +### Custom Width + +Input field with custom width. + + + +### Size Variants + +InputField comes in two sizes: small (24px) and large (32px). + + + +### With Chips + +Input field that can display and manage chips/tags. + + diff --git a/apps/www-beta/src/content/docs/components/input-field/props.ts b/apps/www-beta/src/content/docs/components/input-field/props.ts new file mode 100644 index 000000000..0d0d2c961 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/input-field/props.ts @@ -0,0 +1,46 @@ +export interface InputFieldProps { + /** + * Size variant of the input field + * @default "large" + */ + size?: 'small' | 'large'; + + /** Text label above the input */ + label?: string; + + /** Helper text below the input */ + helperText?: string; + + /** Error message to display below the input */ + error?: string; + + /** Whether the input is disabled */ + disabled?: boolean; + + /** Icon element to display at the start of input */ + leadingIcon?: React.ReactNode; + + /** Icon element to display at the end of input */ + trailingIcon?: React.ReactNode; + + /** Shows "(Optional)" text next to label */ + optional?: boolean; + + /** Text or symbol to show before input value */ + prefix?: string; + + /** Text or symbol to show after input value */ + suffix?: string; + + /** Custom width for the input field */ + width?: string | number; + + /** + * Array of chip objects with label and onRemove function + * Each chip should have a `label` and an `onRemove` callback. + */ + chips?: { label: string; onRemove: () => void }[]; + + /** Additional CSS class names */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/label/demo.ts b/apps/www-beta/src/content/docs/components/label/demo.ts new file mode 100644 index 000000000..f7ae0bc6f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/label/demo.ts @@ -0,0 +1,45 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return `${children}`; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['small', 'medium', 'large'], + defaultValue: 'small' + }, + required: { type: 'checkbox', defaultValue: false }, + requiredIndicator: { type: 'text', defaultValue: '*' }, + children: { type: 'text', initialValue: 'Label' } + }, + getCode +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + + + ` +}; +export const requiredDemo = { + type: 'code', + code: ` + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/label/index.mdx b/apps/www-beta/src/content/docs/components/label/index.mdx new file mode 100644 index 000000000..6d5e2ca21 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/label/index.mdx @@ -0,0 +1,42 @@ +--- +title: Label +description: A text label component that provides names for form controls. +--- + +import { playground, requiredDemo, sizeDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Label } from '@raystack/apsara' +``` + +## Label Props + + + +## Examples + +### Size + +Labels have 3 different sizes. + + + +### Required + +Labels can indicate required fields with either a default asterisk or custom text. + + + +## Accessibility + +The Label component is designed with accessibility in mind: + +- Uses semantic HTML `
` elements with proper `role="link"` +- External links include `target="_blank"` and `rel="noopener noreferrer"` +- External links have aria-labels indicating they open in new tabs +- Download links include appropriate aria-labels +- Maintains color contrast ratios for all variants diff --git a/apps/www-beta/src/content/docs/components/link/props.ts b/apps/www-beta/src/content/docs/components/link/props.ts new file mode 100644 index 000000000..c26ef9779 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/link/props.ts @@ -0,0 +1,13 @@ +export interface LinkProps { + /** The URL that the link points to. (Required) */ + href: string; + + /** Whether the link should open in a new tab. */ + external?: boolean; + + /** Whether the link should be downloadable or a string for the filename. */ + download?: boolean | string; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/list/demo.ts b/apps/www-beta/src/content/docs/components/list/demo.ts new file mode 100644 index 000000000..d894c1431 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/list/demo.ts @@ -0,0 +1,36 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + User Information + + Status + Active + + + Type + Premium Account + + + Created + April 24, 2024 + + + ` +}; + +export const basicDemo = { + type: 'code', + code: ` + + User Information + + Status + Active + +; + ` +}; diff --git a/apps/www-beta/src/content/docs/components/list/index.mdx b/apps/www-beta/src/content/docs/components/list/index.mdx new file mode 100644 index 000000000..9ee098514 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/list/index.mdx @@ -0,0 +1,50 @@ +--- +title: List +description: A component for displaying information in a key-value pair list format. +--- + +import { basicDemo, preview } from "./demo.ts"; + + + +## Usage + +```tsx +import { List } from "@raystack/apsara"; +``` + +## List Props + +### List.Root Props + + + +### List.Header Props + + + +### List.Item Props + + + +### List.Label Props + + + +### List.Value Props + + + +## Examples + +### Basic Usage + + + +## Accessibility + +The List component implements proper ARIA attributes for accessibility: + +- List.Root has `role="list"` and `aria-label` +- List.Item has `role="listitem"` +- List.Header has `role="heading"` and `aria-level={3}` diff --git a/apps/www-beta/src/content/docs/components/list/props.ts b/apps/www-beta/src/content/docs/components/list/props.ts new file mode 100644 index 000000000..d87fa1d49 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/list/props.ts @@ -0,0 +1,48 @@ +export interface ListRootProps { + /** Maximum width of the list container. */ + maxWidth?: string | number; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ListHeaderProps { + /** Content to be displayed in the header. */ + children?: React.ReactNode; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ListItemProps { + /** + * Alignment of the item content. + * @default "start" + */ + align?: 'start' | 'center' | 'end'; + + /** Content to be displayed in the item. */ + children?: React.ReactNode; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ListLabelProps { + /** Minimum width of the label. */ + minWidth?: string; + + /** Content to be displayed in the label. */ + children?: React.ReactNode; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ListValueProps { + /** Content to be displayed in the value. */ + children?: React.ReactNode; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/popover/demo.ts b/apps/www-beta/src/content/docs/components/popover/demo.ts new file mode 100644 index 000000000..3ae740595 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/popover/demo.ts @@ -0,0 +1,132 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { children, ...rest } = props; + return ` + + + + + + ${children} + + `; +}; + +export const playground = { + type: 'playground', + controls: { + align: { + type: 'select', + options: ['start', 'center', 'end'], + defaultValue: 'center' + }, + alignOffset: { type: 'number', min: 0, defaultValue: 2 }, + side: { + type: 'select', + options: ['top', 'right', 'bottom', 'left'], + defaultValue: 'bottom' + }, + sideOffset: { type: 'number', min: 0, defaultValue: 2 }, + collisionPadding: { type: 'number', min: 0, defaultValue: 0 }, + children: { type: 'text', initialValue: 'This is the popover content.' } + }, + getCode +}; + +export const positionDemo = { + type: 'code', + tabs: [ + { + name: 'Top', + code: ` + + + + + + Content appears above the trigger + + ` + }, + { + name: 'Right', + code: ` + + + + + + Content appears to the right + + ` + }, + { + name: 'Bottom', + code: ` + + + + + + Content appears below the trigger + + ` + }, + { + name: 'Left', + code: ` + + + + + + Content appears to the left + + ` + } + ] +}; +export const alignDemo = { + type: 'code', + tabs: [ + { + name: 'Center', + code: ` + + + + + + Centered with the trigger + + ` + }, + { + name: 'Start', + code: ` + + + + + + Aligned to the start + + ` + }, + { + name: 'End', + code: ` + + + + + + Aligned to the end + + ` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/popover/index.mdx b/apps/www-beta/src/content/docs/components/popover/index.mdx new file mode 100644 index 000000000..e9fe303c2 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/popover/index.mdx @@ -0,0 +1,51 @@ +--- +title: Popover +description: Displays rich content in a portal, triggered by a button. +--- + +import { playground, alignDemo, positionDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Popover } from "@raystack/apsara"; +``` + +## Popover Props + +The Popover component consists of several parts, each with their own props: + +### Popover.Root Props + + + +### Popover.Content Props + + + +### Popover.Trigger Props + + + +## Examples + +### Positioning + +Control the position and alignment of your popover relative to its trigger. + + + +### Alignment + +Customize how the popover aligns with its trigger. + + + +## Accessibility + +The Callout component includes appropriate ARIA attributes for accessibility: + +- Uses semantic HTML elements for proper structure +- Dismiss button includes `aria-label` for screen readers diff --git a/apps/www-beta/src/content/docs/components/popover/props.ts b/apps/www-beta/src/content/docs/components/popover/props.ts new file mode 100644 index 000000000..646dd4d70 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/popover/props.ts @@ -0,0 +1,44 @@ +export interface PopoverRootProps { + /** Boolean to control the default open state. */ + defaultOpen?: boolean; + + /** Controlled open state. */ + open?: boolean; + + /** Callback when open state changes. */ + onOpenChange?: (open: boolean) => void; + + /** Boolean to enable modal behavior. */ + modal?: boolean; +} + +export interface PopoverContentProps { + /** + * Accessible label for the popover content. + * @default "Popover content" + */ + ariaLabel?: string; + + /** Preferred side of the trigger to render. */ + side?: 'top' | 'right' | 'bottom' | 'left'; + + /** Distance in pixels from the trigger. */ + sideOffset?: number; + + /** Alignment relative to trigger. */ + align?: 'start' | 'center' | 'end'; + + /** Offset in pixels from alignment edge. */ + alignOffset?: number; + + /** Boolean to prevent collision with viewport edges. */ + avoidCollisions?: boolean; + + /** Padding between content and viewport edges. */ + collisionPadding?: number; +} + +export interface PopoverTriggerProps { + /** Boolean to merge props onto child element. */ + asChild?: boolean; +} diff --git a/apps/www-beta/src/content/docs/components/radio/demo.ts b/apps/www-beta/src/content/docs/components/radio/demo.ts new file mode 100644 index 000000000..86d90e6eb --- /dev/null +++ b/apps/www-beta/src/content/docs/components/radio/demo.ts @@ -0,0 +1,95 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + + + + + + + + + + + + + + ` +}; + +export const stateDemo = { + type: 'code', + tabs: [ + { + name: 'Default', + code: ` + + + + + +` + }, + { + name: 'Disabled', + code: ` + + + + + +` + } + ] +}; + +export const labelDemo = { + type: 'code', + code: ` + + + + + + + + + + + + + + + + ` +}; + +export const formDemo = { + type: 'code', + code: ` +
{ + e.preventDefault(); + const formData = new FormData(e.target); + alert(JSON.stringify(Object.fromEntries(formData))); +}}> + + + + + + + + + + + + + + + +
` +}; diff --git a/apps/www-beta/src/content/docs/components/radio/index.mdx b/apps/www-beta/src/content/docs/components/radio/index.mdx new file mode 100644 index 000000000..256475977 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/radio/index.mdx @@ -0,0 +1,44 @@ +--- +title: Radio +description: A radio group component for selecting a single option from a list of options. +--- + +import { preview, stateDemo, labelDemo, formDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Radio } from "@raystack/apsara"; +``` + +## Radio Props + +### Radio.Root Props + + + +### Radio.Item Props + + + +## Examples + +### State + +Radio buttons support different states to indicate interactivity and selection. + + + +### With Labels + +Radio buttons should always be accompanied by labels for accessibility and usability. + + + +### Form Example + +Radio buttons can be used in forms with proper validation and submission handling. + + diff --git a/apps/www-beta/src/content/docs/components/radio/props.ts b/apps/www-beta/src/content/docs/components/radio/props.ts new file mode 100644 index 000000000..b2a311d64 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/radio/props.ts @@ -0,0 +1,42 @@ +export interface RadioRootProps { + /** The value of the radio item that should be checked by default. */ + defaultValue?: string; + + /** The controlled value of the radio item that is checked. */ + value?: string; + + /** Event handler called when the value changes. */ + onValueChange?: (value: string) => void; + + /** When true, prevents user interaction with the radio group. */ + disabled?: boolean; + + /** The name of the radio group when submitted as a form field. */ + name?: string; + + /** When true, indicates that a value must be selected before the form can be submitted. */ + required?: boolean; + + /** The orientation of the radio group. */ + orientation?: 'horizontal' | 'vertical'; + + /** The reading direction of the radio group. */ + dir?: 'ltr' | 'rtl'; + + /** A label for the radio group that is announced by screen readers. */ + ariaLabel?: string; +} + +export interface RadioItemProps { + /** The unique value of the radio item. */ + value: string; + + /** When true, prevents user interaction with this radio item. */ + disabled?: boolean; + + /** When true, indicates that this radio item must be checked. */ + required?: boolean; + + /** The unique identifier for the radio item. */ + id?: string; +} diff --git a/apps/www-beta/src/content/docs/components/search/demo.ts b/apps/www-beta/src/content/docs/components/search/demo.ts new file mode 100644 index 000000000..0e99b3dc6 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/search/demo.ts @@ -0,0 +1,40 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['small', 'large'], + defaultValue: 'large' + }, + placeholder: { type: 'text', initialValue: 'Search...' }, + disabled: { type: 'checkbox', defaultValue: false }, + showClearButton: { type: 'checkbox', defaultValue: false } + }, + getCode +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + + ` +}; + +export const clearDemo = { + type: 'code', + code: ` + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/search/index.mdx b/apps/www-beta/src/content/docs/components/search/index.mdx new file mode 100644 index 000000000..7ec469227 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/search/index.mdx @@ -0,0 +1,60 @@ +--- +title: Search +description: A search input component with built-in search icon and optional clear button. +--- + +import { playground, sizeDemo, clearDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Search } from "@raystack/apsara"; +``` + +## Search Props + + + +## Examples + +### Size + +The Search component comes in two sizes to fit different design contexts. + + + +### Clear Button + +The Search component can include a clear button that appears when there is input value. + + + +## Accessibility + +The Search component is built with accessibility in mind, following ARIA best practices: + +- Container has `role="search"` to identify it as a search landmark +- Input has `type="search"` for semantic HTML +- Search icon is marked as decorative with `aria-hidden="true"` +- Clear button has appropriate `aria-label` for screen readers +- Keyboard navigation support for the clear button +- Input inherits `aria-label` from placeholder text + +Example with accessibility features: + +```tsx + +``` + +The component supports keyboard navigation: + +- Tab to focus on the search input +- Tab again to focus on the clear button (when visible) +- Enter or Space to trigger the clear button diff --git a/apps/www-beta/src/content/docs/components/search/props.ts b/apps/www-beta/src/content/docs/components/search/props.ts new file mode 100644 index 000000000..3f6d212fe --- /dev/null +++ b/apps/www-beta/src/content/docs/components/search/props.ts @@ -0,0 +1,28 @@ +export interface SearchProps { + /** + * Size variant of the search input. + * @default large + */ + size?: 'small' | 'large'; + + /** Placeholder text for the input. */ + placeholder?: string; + + /** Whether the search input is disabled. */ + disabled?: boolean; + + /** Shows a clear button when the input has a value. */ + showClearButton?: boolean; + + /** The controlled value of the input. */ + value?: string; + + /** Callback when input value changes. */ + onChange?: (value: string) => void; + + /** Callback when clear button is clicked. */ + onClear?: () => void; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/select/demo.ts b/apps/www-beta/src/content/docs/components/select/demo.ts new file mode 100644 index 000000000..1dfb8387b --- /dev/null +++ b/apps/www-beta/src/content/docs/components/select/demo.ts @@ -0,0 +1,228 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + const { autocomplete, multiple, ...rest } = props; + return ` + + + + + + + Apple + Banana + Blueberry + Grapes + Pineapple + + + `; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['small', 'medium'], + defaultValue: 'medium' + }, + variant: { + type: 'select', + options: ['default', 'filter'], + defaultValue: 'default' + }, + autocomplete: { + type: 'checkbox', + defaultValue: false + }, + multiple: { + type: 'checkbox', + defaultValue: false + } + }, + getCode +}; + +export const iconDemo = { + type: 'code', + code: ` + ` +}; +export const basicDemo = { + type: 'code', + code: ` + ` +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + +` +}; + +export const variantDemo = { + type: 'code', + tabs: [ + { + name: 'Default', + code: ` + ` + }, + { + name: 'Filter', + code: ` + ` + } + ] +}; +export const separatorDemo = { + type: 'code', + code: ` + ` +}; +export const multipleDemo = { + type: 'code', + code: ` + ` +}; + +export const autocompleteDemo = { + type: 'code', + tabs: [ + { + name: 'Default Autocomplete', + code: ` + ` + }, + { + name: 'Manual Autocomplete', + code: ` + function ManualDemo(){ + const items = [ + "Apple", + "Banana", + "Grape", + "Orange", + "Pineapple", + ]; + + const [simpleSearchQuery, setSimpleSearchQuery] = React.useState(""); + return + }` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/select/index.mdx b/apps/www-beta/src/content/docs/components/select/index.mdx new file mode 100644 index 000000000..74dd0d2b3 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/select/index.mdx @@ -0,0 +1,116 @@ +--- +title: Select +description: Displays a list of options for the user to pick from—triggered by a button. +--- + +import { + playground, + sizeDemo, + basicDemo, + variantDemo, + separatorDemo, + iconDemo, + autocompleteDemo, + multipleDemo +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Select } from "@raystack/apsara"; +``` + +## Select Props + +The Select component is composed of several parts, each with their own props. + +The root element is the parent component that holds the select. Using the `autocomplete` prop, you can enable autocomplete functionality. Autcomplet is built using [Ariakit ComboboxProvider](https://ariakit.org/reference/combobox-provider) + + + +### Select.Trigger Props + +The button that triggers the Select. + + + +### Select.Content Props + +The container that holds the Select items. + + + +### Select.Item Props + +Individual clickable options within the Select. + + + +### Select.Group Props + +A way to group related Select items together. + + + +### Select.Label Props + +Renders a label in a Select group. This component can only be used inside Select.Group + + + +### Select.Separator Props + +Visual divider between Select items or groups. + + + +## Examples + +### Basic Select + + + +### Icon + +You can pass `leadingIcon` prop to Select.Item to include items + + + +### Size + + + +### Variant + + + +### With Separator + + + +### Multiple Selection + +To enable multiple selection, pass the `multiple` prop to the Select root element. + +When multiple selection is enabled, the value, onValueChange, and defaultValue will be an array of strings. + + + +### Autocomplete + +To enable autocomplete, pass the `autocomplete` prop to the Select root element. + +By default, only select items are filtered using a simple match. For more advanced control, set `autocompleteMode="manual"` and implement your own custom filtering logic. + + + +## Accessibility + +The Select component follows WAI-ARIA guidelines: + +- Trigger has role `combobox` +- Content has role `listbox` +- Items have role `option` +- ARIA labels and descriptions diff --git a/apps/www-beta/src/content/docs/components/select/props.ts b/apps/www-beta/src/content/docs/components/select/props.ts new file mode 100644 index 000000000..38f4ce661 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/select/props.ts @@ -0,0 +1,99 @@ +export interface SelectRootProps { + /** Enables multiple selection. + * When enabled, value, onValueChange, and defaultValue will be an array of strings. + * @default false + */ + multiple?: boolean; + + /** Enables search functionality within the select. + * @default false + */ + autocomplete?: boolean; + + /** Controls the autocomplete behavior mode + * - "auto": Automatically filters items as user types + * - "manual": Requires explicit filtering through onSearch callback + * @default "auto" + */ + autocompleteMode?: 'auto' | 'manual'; + + /** Current search value for autocomplete */ + searchValue?: string; + + /** Initial search value for autocomplete */ + defaultSearchValue?: string; + + /** Callback fired when the search value changes */ + onSearch?: (value: string) => void; +} + +export interface SelectTriggerProps { + /** Defines the size of the trigger. */ + size?: 'small' | 'medium'; + + /** Visual style variant. */ + variant?: 'default' | 'filter'; + + /** Props for the chevron icon. */ + iconProps?: Record; + + /** Accessible label. */ + ariaLabel?: string; + + /** ID of element describing the select. */ + ariaDescribedby?: string; + + /** Whether the select is required. */ + ariaRequired?: boolean; + + /** Whether the select has an invalid value. */ + ariaInvalid?: boolean; +} + +export interface SelectContentProps { + /** Placeholder text for the autocomplete search input + * @default "Search..." + */ + searchPlaceholder?: string; + + /** + * Position of the content + * @default "popper" + */ + position?: 'item-aligned' | 'popper'; + + /** Additional CSS class names. */ + className?: string; +} + +export interface SelectItemProps { + /** The value of the item. */ + value: string; + + /** Additional CSS class names. */ + className?: string; +} + +export interface SelectGroupProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface SelectLabelProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} + +export interface SelectSeparatorProps { + /** Additional CSS class names */ + className?: string; + + /** Boolean to merge props onto child element */ + asChild?: boolean; +} diff --git a/apps/www-beta/src/content/docs/components/separator/demo.ts b/apps/www-beta/src/content/docs/components/separator/demo.ts new file mode 100644 index 000000000..286f4dd3a --- /dev/null +++ b/apps/www-beta/src/content/docs/components/separator/demo.ts @@ -0,0 +1,56 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'select', + options: ['small', 'half', 'full'], + defaultValue: 'full' + }, + color: { + type: 'select', + options: ['primary', 'secondary', 'tertiary'], + defaultValue: 'primary' + }, + orientation: { + type: 'select', + options: ['horizontal', 'vertical'], + defaultValue: 'horizontal' + } + }, + getCode +}; +export const sizeDemo = { + type: 'code', + code: ` + + + + + ` +}; + +export const colorDemo = { + type: 'code', + code: ` + + + + + ` +}; +export const orientationDemo = { + type: 'code', + code: ` + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/separator/index.mdx b/apps/www-beta/src/content/docs/components/separator/index.mdx new file mode 100644 index 000000000..8ce5153fa --- /dev/null +++ b/apps/www-beta/src/content/docs/components/separator/index.mdx @@ -0,0 +1,47 @@ +--- +title: Separator +description: A visual divider that separates content with support for vertical and horizontal orientations. +--- + +import { playground, sizeDemo, colorDemo, orientationDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Separator } from '@raystack/apsara' +``` + +## Separator Props + + + +## Examples + +### Color + +The Separator component supports three colors. + + + +## Size + +The Separator component supports three sizes. + + + +## Orientation + +Separator can be rendered in both horizontal and vertical orientations. + + + +## Accessibility + +The Separator component follows accessibility best practices: + +- Uses `role="separator"` by default +- Is marked as `decorative` for visual separation +- Maintains proper color contrast +- Supports proper semantic structure in both orientations diff --git a/apps/www-beta/src/content/docs/components/separator/props.ts b/apps/www-beta/src/content/docs/components/separator/props.ts new file mode 100644 index 000000000..896b961c9 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/separator/props.ts @@ -0,0 +1,19 @@ +export interface SeparatorProps { + /** Defines the length of the separator. + * @default "full" + */ + size?: 'small' | 'half' | 'full'; + + /** Sets the color of the separator. + * @default "primary" + */ + color?: 'primary' | 'secondary' | 'tertiary'; + + /** Sets the direction of the separator. + * @default "horizontal" + */ + orientation?: 'horizontal' | 'vertical'; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/sheet/demo.ts b/apps/www-beta/src/content/docs/components/sheet/demo.ts new file mode 100644 index 000000000..a016a0e4e --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sheet/demo.ts @@ -0,0 +1,90 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ` + + + + + + Sheet + A simple sheet + + `; +}; + +export const playground = { + type: 'playground', + controls: { + side: { + type: 'select', + options: ['top', 'right', 'bottom', 'left'], + defaultValue: 'right' + }, + close: { + type: 'checkbox', + defaultValue: false + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + + Sheet Title + Sheet description goes here + Main content of the sheet + +` +}; + +export const positionDemo = { + type: 'code', + code: ` + + + + + + + Top Sheet + Slides in from the Top + + + + + + + + Right Sheet + Slides in from the Right + + + + + + + + Left Sheet + Slides in from the Left + + + + + + + + Bottom Sheet + Slides in from the Bottom + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/sheet/index.mdx b/apps/www-beta/src/content/docs/components/sheet/index.mdx new file mode 100644 index 000000000..bf49f0903 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sheet/index.mdx @@ -0,0 +1,50 @@ +--- +title: Sheet +description: Extends the Dialog component to display content that complements the main content of the screen. +--- + +import { playground, basicDemo, positionDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Sheet } from "@raystack/apsara"; +``` + +## Sheet Props + + + +### Sheet.Content Props + + + +### Sheet.Title Props + +- Inherits all HTML heading element props + +### Sheet.Description Props + +- Inherits all HTML paragraph element props + +## Examples + +### Basic + + + +### Positioning + +The Sheet can slide in from different sides of the screen. + + + +## Accessibility + +Sheet components are built with proper accessibility features following WAI-ARIA guidelines: + +- Uses semantic HTML elements for proper structure +- Dismiss button includes `aria-label` and `aria-description` for screen readers +- Interactive elements are keyboard accessible diff --git a/apps/www-beta/src/content/docs/components/sheet/props.ts b/apps/www-beta/src/content/docs/components/sheet/props.ts new file mode 100644 index 000000000..1233dc8ac --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sheet/props.ts @@ -0,0 +1,24 @@ +export interface SheetProps { + /** The content to be rendered inside the sheet. */ + children: React.ReactNode; + + /** Accessible label for the sheet trigger. */ + ariaLabel?: string; +} + +export interface SheetContentProps { + /** The direction from which the sheet appears. */ + side?: 'top' | 'right' | 'bottom' | 'left'; + + /** Whether to show the close button. */ + close?: boolean; + + /** Accessible label for the sheet content. */ + ariaLabel?: string; + + /** Accessible description for the sheet content. */ + ariaDescription?: string; + + /** The content to be rendered inside the sheet. */ + children: React.ReactNode; +} diff --git a/apps/www-beta/src/content/docs/components/sidebar/demo.ts b/apps/www-beta/src/content/docs/components/sidebar/demo.ts new file mode 100644 index 000000000..4f24794c3 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidebar/demo.ts @@ -0,0 +1,152 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + + + + + Apsara + + + + }> + } active> + Dashboard + + } disabled> + Settings + + + + }> + Help + + + + + }> + Help + + + ` +}; + +export const positionDemo = { + type: 'code', + tabs: [ + { + name: 'Left', + code: ` + + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + }, + { + name: 'Right', + code: ` + + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + } + ] +}; + +export const stateDemo = { + type: 'code', + tabs: [ + { + name: 'Expanded', + code: ` + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + }, + { + name: 'Collapsed', + code: ` + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + }, + { + name: 'Uncontrolled', + code: ` + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + }, + { + name: 'Uncontrolled (default open)', + code: ` + + + + + + Apsara + + + + } active>Dashboard + } disabled>Settings + + ` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/sidebar/index.mdx b/apps/www-beta/src/content/docs/components/sidebar/index.mdx new file mode 100644 index 000000000..6aa980170 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidebar/index.mdx @@ -0,0 +1,71 @@ +--- +title: Sidebar +description: A collapsible side navigation panel component. +--- + +import { preview, positionDemo, stateDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Sidebar } from "@raystack/apsara"; +``` + +## Sidebar Props + + + +### Sidebar.Header Props + +The header section is a container component that accepts all `div` props. It's commonly used to create a header with an icon and title. + +### Sidebar.Group Props + + + +### Sidebar.Item Props + +*Note: `leadingIcon` is optional and will show a fallback avatar only in collapsed state. You can pass `<>` to render truly nothing.* + + + +## Examples + +### Position + +The Sidebar can be positioned on either the left or right side of the screen. + + + +### State + +The Sidebar supports expanded and collapsed states with smooth transitions. + +The `data-collapse-hidden` attribute can be used to conditionally hide elements when the sidebar is collapsed. + + + +## Accessibility + +The Sidebar implements the following accessibility features: + +- Proper ARIA roles and attributes + + - `role="navigation"` for the main sidebar + - `role="banner"` for the header + - `role="menuitem"` for navigation items + - `aria-expanded` to indicate sidebar state + - `aria-current="page"` for active items + - `aria-disabled="true"` for disabled items + +- Keyboard navigation support + + - Enter/Space to toggle sidebar expansion + - Tab navigation through interactive elements + +- Screen reader support + - Meaningful labels for all interactive elements + - Hidden decorative elements + - Clear state indicators diff --git a/apps/www-beta/src/content/docs/components/sidebar/props.ts b/apps/www-beta/src/content/docs/components/sidebar/props.ts new file mode 100644 index 000000000..5d2678595 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidebar/props.ts @@ -0,0 +1,78 @@ +import { ReactElement, ReactNode } from 'react'; + +export interface SidebarRootProps { + /** Controls the expanded/collapsed state. */ + open?: boolean; + + /** Callback when expanded/collapsed state changes. */ + onOpenChange?: (open: boolean) => void; + + /** Default expanded/collapsed state.*/ + defaultOpen?: boolean; + + /** Disable the click to collapse/expand the Sidebar. + * @default undefined + */ + collapsible?: boolean; + + /** Position of the Sidebar. + * @default "left" + */ + position?: 'left' | 'right'; + + /** Hide tooltips on sidebar items when sidebar is collapsed. + * @default false + */ + hideCollapsedItemTooltip?: boolean; +} + +export interface SidebarGroupProps { + /** String for the group title. */ + label: string; + + /** Optional ReactNode for group icon. */ + leadingIcon?: ReactNode; + + /** ReactNode for the group content. */ + children?: ReactNode; +} + +export interface SidebarItemProps { + /** + * ReactNode for the item's icon. + * + * If not provided, the component will show a fallback avatar only in collapsed state. + */ + leadingIcon?: ReactNode; + + /** String for the link destination. */ + href?: string; + + /** Boolean to indicate current selection. */ + active?: boolean; + + /** Boolean to disable the item. */ + disabled?: boolean; + + /** ReactNode for the item's label. */ + children?: ReactNode; + + /** + * Custom element used to render the SidebarItem. + * + * All props are forwarded to the specified element. + * + * @default "
" + */ + as?: ReactElement; + + /** Optional class names for customizing parts of the item. */ + classNames?: { + /** Class name for the root element. */ + root?: string; + /** Class name for the leading icon container. */ + leadingIcon?: string; + /** Class name for the text element. */ + text?: string; + }; +} diff --git a/apps/www-beta/src/content/docs/components/sidepanel/demo.ts b/apps/www-beta/src/content/docs/components/sidepanel/demo.ts new file mode 100644 index 000000000..52b9b0279 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidepanel/demo.ts @@ -0,0 +1,63 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + } description="This is a description." actions={[]} /> + + + User Information + + Status + Active + + + Type + Premium Account + + + Created + April 24, 2024 + + + + + + User Information + + Status + Active + + + Type + Premium Account + + + Created + April 24, 2024 + + + + + ` +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + + User Information + + Status + Active + + + +; + ` +}; diff --git a/apps/www-beta/src/content/docs/components/sidepanel/index.mdx b/apps/www-beta/src/content/docs/components/sidepanel/index.mdx new file mode 100644 index 000000000..262b84f06 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidepanel/index.mdx @@ -0,0 +1,32 @@ +--- +title: Sidepanel +description: A flexible side panel component to place content on either side of the page. +--- + +import { basicDemo, preview } from "./demo.ts"; + + + +## Usage + +```tsx +import { SidePanel } from "@raystack/apsara"; +``` + +## SidePanel Props + +Customize the SidePanel appearance with these configuration options. + +The `SidePanel` component is composed of several parts, each with their own props + + + +### SidePanel.Header + + + +## Examples + +### Basic Usage + + diff --git a/apps/www-beta/src/content/docs/components/sidepanel/props.ts b/apps/www-beta/src/content/docs/components/sidepanel/props.ts new file mode 100644 index 000000000..3b3d58963 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/sidepanel/props.ts @@ -0,0 +1,39 @@ +export interface SidePanelProps { + /** + * The side to position the panel. + * @default "left" + */ + side?: 'left' | 'right'; + + /** + * Content to render inside the side panel. + */ + children: React.ReactNode; + + /** + * Additional CSS class names to apply. + */ + className?: string; +} + +export interface SidePanelHeaderProps { + /** + * The title text to display in the header. + */ + title: string; + + /** + * Optional description text below the title. + */ + description?: string; + + /** + * Optional icon element to display before the title. + */ + icon?: React.ReactNode; + + /** + * Array of action elements to display in the header. + */ + actions?: React.ReactNode[]; +} diff --git a/apps/www-beta/src/content/docs/components/skeleton/demo.ts b/apps/www-beta/src/content/docs/components/skeleton/demo.ts new file mode 100644 index 000000000..cb61f8514 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/skeleton/demo.ts @@ -0,0 +1,105 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + width: { + type: 'text', + initialValue: '200px' + }, + height: { + type: 'text', + initialValue: '15px' + }, + count: { + type: 'number', + initialValue: 3 + }, + enableAnimation: { + type: 'checkbox', + initialValue: true + }, + duration: { + type: 'number', + initialValue: 1.5 + }, + inline: { + type: 'checkbox', + initialValue: false + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` + + + ` +}; + +export const multipleDemo = { + type: 'code', + code: ` + + + ` +}; + +export const customStylesDemo = { + type: 'code', + code: ` + + + ` +}; + +export const animationDemo = { + type: 'code', + code: ` + + + + ` +}; + +export const cardDemo = { + type: 'code', + code: ` + + {/* Image placeholder */} + {/* Title placeholder */} + {/* Text lines placeholder */} + ` +}; + +export const providerDemo = { + type: 'code', + code: ` + + + + + + + + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/skeleton/index.mdx b/apps/www-beta/src/content/docs/components/skeleton/index.mdx new file mode 100644 index 000000000..8deb89b72 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/skeleton/index.mdx @@ -0,0 +1,95 @@ +--- +title: Skeleton +description: A placeholder loading state that mimics the layout of content while it's being loaded. +--- + +import { + playground, + basicDemo, + multipleDemo, + customStylesDemo, + animationDemo, + cardDemo, + providerDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Skeleton } from "@raystack/apsara"; +``` + +## Skeleton Props + + + +## Examples + +### Basic Usage + +A simple skeleton loader with fixed dimensions. + + + +### Multiple Lines + +Create multiple skeleton lines using the count prop. + + + +### Using Provider + +Group multiple skeletons and share common props using Skeleton.Provider. + + + +### Custom Styles + +Customize the appearance using baseColor and highlightColor. + + + +### Animation Control + +Control the animation duration or disable it entirely. + + + +### Complex Layout + +Create a card-like loading state by combining multiple skeletons. + + + +## Provider Pattern + +The Skeleton component supports a Provider pattern that allows you to share common props across multiple skeleton instances: + +```tsx + + {/* Inherits provider props */} + {/* Inherits provider props, overrides width */} + {/* Overrides specific props */} + +``` + +All props available on the Skeleton component can be passed to the Provider and will be inherited by child Skeleton components. Individual Skeleton components can override any provider props with their own values. + +## Accessibility + +The Skeleton component follows accessibility best practices: + +- Uses semantic HTML elements +- Provides appropriate ARIA attributes +- Maintains sufficient color contrast +- Animation can be disabled for users who prefer reduced motion +- Supports both block and inline layouts diff --git a/apps/www-beta/src/content/docs/components/skeleton/props.ts b/apps/www-beta/src/content/docs/components/skeleton/props.ts new file mode 100644 index 000000000..412955b17 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/skeleton/props.ts @@ -0,0 +1,75 @@ +export interface SkeletonProps { + /** + * Width of the skeleton + * @defaultValue "50px for inline, 100% otherwise" + */ + width?: string | number; + + /** + * Height of the skeleton + * @defaultValue "var(--rs-space-4)" + */ + height?: string | number; + + /** + * Base color of the skeleton + * @defaultValue "var(--rs-color-background-base-primary-hover)" + */ + baseColor?: string; + + /** + * Color of the shimmer effect + * @defaultValue "var(--rs-color-background-base-primary)" + */ + highlightColor?: string; + + /** + * Border radius of the skeleton + * @defaultValue "var(--rs-radius-2)" + */ + borderRadius?: string | number; + + /** + * Whether to display as inline-block + * @defaultValue false + */ + inline?: boolean; + + /** + * Duration of the animation in seconds + * @defaultValue 1.5 + */ + duration?: number; + + /** + * Whether to enable the shimmer animation + * @defaultValue true + */ + enableAnimation?: boolean; + + /** + * Number of skeleton elements to render + * @defaultValue 1 + */ + count?: number; + + /** + * Additional CSS class names for the skeleton element + */ + className?: string; + + /** + * Additional inline styles for the skeleton element + */ + style?: React.CSSProperties; + + /** + * Additional CSS class names for the container element (div for block and span for inline) + */ + containerClassName?: string; + + /** + * Additional inline styles for the container element (div for block and span for inline) + */ + containerStyle?: React.CSSProperties; +} diff --git a/apps/www-beta/src/content/docs/components/slider/demo.ts b/apps/www-beta/src/content/docs/components/slider/demo.ts new file mode 100644 index 000000000..c94858877 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/slider/demo.ts @@ -0,0 +1,75 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + defaultValue: { type: 'number', initialValue: 50 }, + min: { type: 'number', defaultValue: 0, min: 0, max: 99 }, + max: { type: 'number', defaultValue: 100, min: 1, max: 100 }, + step: { type: 'number', defaultValue: 1, min: 0, max: 100 }, + label: { type: 'text', initialValue: 'Slider Label' } + }, + getCode +}; + +export const variantDemo = { + type: 'code', + tabs: [ + { + name: 'Single', + code: `` + }, + { + name: 'Range', + code: `` + } + ] +}; +export const controlDemo = { + type: 'code', + tabs: [ + { + name: 'Single', + code: `function ControlledRangeSlider() { + const [value, setValue] = React.useState(50); + + return ( + + setValue(newValue as number)} + /> + Value {value} + + ); +}` + }, + { + name: 'Range', + code: `function ControlledRangeSlider() { + const [value, setValue] = React.useState([25, 75]); + + return ( + + setValue(newValue as [number, number])} + /> + Lower {value[0]} + Upper {value[1]} + + ); +}` + } + ] +}; diff --git a/apps/www-beta/src/content/docs/components/slider/index.mdx b/apps/www-beta/src/content/docs/components/slider/index.mdx new file mode 100644 index 000000000..842260ba9 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/slider/index.mdx @@ -0,0 +1,66 @@ +--- +title: Slider +description: A control that allows users to select a value or range from a given range. +--- + +import { playground, variantDemo, controlDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Slider } from '@raystack/apsara' +``` + +## Slider Props + + + +## Examples + +### Variant + + + +### Controlled Usage + +A controlled slider that maintains and updates its state through React's useState hook. + + + +## Accessibility + +The Slider component follows WAI-ARIA guidelines for the [Slider Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slider/). + +### ARIA Attributes + +The component handles the following ARIA attributes: + +- `aria-label`: Provides an accessible name for the slider +- `aria-valuetext`: Provides a human-readable text alternative for the current value +- `aria-valuemin`: Set automatically based on the `min` prop +- `aria-valuemax`: Set automatically based on the `max` prop +- `aria-valuenow`: Updated automatically as the value changes + +### Example with Custom ARIA Labels + +```tsx +
+ console.log(value)} + /> +
+``` + +### Screen Reader Considerations + +- Each thumb in a range slider has its own accessible label +- Values are announced as they change +- The component supports both mouse and keyboard interactions +- Labels are properly associated with their respective thumbs diff --git a/apps/www-beta/src/content/docs/components/slider/props.ts b/apps/www-beta/src/content/docs/components/slider/props.ts new file mode 100644 index 000000000..0d179b6e5 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/slider/props.ts @@ -0,0 +1,40 @@ +export interface SliderProps { + /** The type of slider. */ + variant?: 'single' | 'range'; + + /** Controlled value - number for single, [number, number] for range. */ + value?: number | [number, number]; + + /** Initial value - number for single, [number, number] for range. */ + defaultValue?: number | [number, number]; + + /** + * Minimum value. + * @default 0 + */ + min?: number; + + /** + * Maximum value. + * @default 100 + */ + max?: number; + + /** + * Step increment. + * @default 1 + */ + step?: number; + + /** + * Label text to display above thumb(s). + * For range slider, can be a string or [string, string] for individual thumb labels. + */ + label?: string | [string, string]; + + /** Callback when value changes. */ + onChange?: (value: number | [number, number]) => void; + + /** Additional CSS class name. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/spinner/demo.ts b/apps/www-beta/src/content/docs/components/spinner/demo.ts new file mode 100644 index 000000000..fd4207cca --- /dev/null +++ b/apps/www-beta/src/content/docs/components/spinner/demo.ts @@ -0,0 +1,59 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + size: { + type: 'number', + options: [1, 2, 3, 4, 5, 6], + defaultValue: 1, + initialValue: 4, + min: 1, + max: 6 + }, + color: { + type: 'select', + options: [ + 'default', + 'neutral', + 'accent', + 'danger', + 'success', + 'attention' + ], + defaultValue: 'default' + } + }, + getCode +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + + + + + + ` +}; +export const colorDemo = { + type: 'code', + code: ` + + + + + + + + ` +}; diff --git a/apps/www-beta/src/content/docs/components/spinner/index.mdx b/apps/www-beta/src/content/docs/components/spinner/index.mdx new file mode 100644 index 000000000..deeb57904 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/spinner/index.mdx @@ -0,0 +1,39 @@ +--- +title: Spinner +description: A visual indicator of a loading or processing state. +--- + +import { playground, sizeDemo, colorDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Spinner } from "@raystack/apsara"; +``` + +## Spinner Props + + + +## Examples + +### Size + +The Spinner component offers different size options. You can customize the size of the spinner using the `size` prop. The available size options are: + + + +### Color + +The Spinner component offers 6 color values. `default` prop sets the color to `currentColor` mainly helpful if we want to render the Spinner inside another component like Button. Spinner (with color="default") inherits the foreground color of button text. + + + +## Accessibility + +The Spinner component includes appropriate ARIA attributes for accessibility: + +- `role="status"`: Indicates that the element is a status indicator. +- `aria-hidden="true"`: Hides the spinner from screen readers, as it's a visual indicator only. diff --git a/apps/www-beta/src/content/docs/components/spinner/props.ts b/apps/www-beta/src/content/docs/components/spinner/props.ts new file mode 100644 index 000000000..026e0d236 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/spinner/props.ts @@ -0,0 +1,16 @@ +export interface SpinnerProps { + /** + * Size of the spinner. + * @default 1 + */ + size?: 1 | 2 | 3 | 4 | 5 | 6; + + /** + * Color variant of the spinner. + * @default "default" + * */ + color?: 'default' | 'neutral' | 'accent' | 'danger' | 'success' | 'attention'; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/switch/demo.ts b/apps/www-beta/src/content/docs/components/switch/demo.ts new file mode 100644 index 000000000..c1287319e --- /dev/null +++ b/apps/www-beta/src/content/docs/components/switch/demo.ts @@ -0,0 +1,64 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + defaultChecked: { + type: 'checkbox', + defaultValue: false + }, + disabled: { + type: 'checkbox', + defaultValue: false + }, + size: { + type: 'select', + options: ['large', 'small'], + defaultValue: 'large' + } + }, + getCode +}; + +export const stateDemo = { + type: 'code', + code: ` + + + + + + + ` +}; + +export const sizeDemo = { + type: 'code', + code: ` + + + + + + ` +}; + +export const controlDemo = { + type: 'code', + code: ` + function ControlledSwitch() { + const [checked, setChecked] = React.useState(false); + return ( + + ); +}` +}; diff --git a/apps/www-beta/src/content/docs/components/switch/index.mdx b/apps/www-beta/src/content/docs/components/switch/index.mdx new file mode 100644 index 000000000..a5f9254f5 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/switch/index.mdx @@ -0,0 +1,48 @@ +--- +title: Switch +description: A control that allows the user to toggle between checked and not checked. +--- + +import { playground, stateDemo, sizeDemo, controlDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Switch } from "@raystack/apsara"; +``` + +## Switch Props + + + +## Examples + +### State + +The Switch component supports various states to handle different interaction scenarios. + + + +### Size Variants + +The Switch component comes in two sizes: large (default) and small. + + + +### Controlled Usage + +Use the Switch component in a controlled manner to manage its state externally. + + + +## Accessibility + +The Switch component follows WAI-ARIA guidelines for toggle buttons: + +- Uses proper ARIA attributes (`aria-checked`, `aria-required`, `aria-label`) +- Supports keyboard navigation (Space and Enter to toggle) +- Includes proper labeling and description support +- Changes cursor to 'not-allowed' when disabled +- Associates labels with the switch using htmlFor diff --git a/apps/www-beta/src/content/docs/components/switch/props.ts b/apps/www-beta/src/content/docs/components/switch/props.ts new file mode 100644 index 000000000..c4cc9d2be --- /dev/null +++ b/apps/www-beta/src/content/docs/components/switch/props.ts @@ -0,0 +1,25 @@ +export interface SwitchProps { + /** The controlled checked state of the switch. */ + checked?: boolean; + + /** The default checked state when uncontrolled. */ + defaultChecked?: boolean; + + /** Event handler called when the checked state changes. */ + onCheckedChange?: (checked: boolean) => void; + + /** When true, prevents the user from interacting with the switch. */ + disabled?: boolean; + + /** When true, indicates that the user must check the switch. */ + required?: boolean; + + /** + * The size of the switch. + * @default "large" + */ + size?: 'large' | 'small'; + + /** A unique identifier for the switch. */ + id?: string; +} diff --git a/apps/www-beta/src/content/docs/components/table/demo.ts b/apps/www-beta/src/content/docs/components/table/demo.ts new file mode 100644 index 000000000..253ee31de --- /dev/null +++ b/apps/www-beta/src/content/docs/components/table/demo.ts @@ -0,0 +1,104 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + + Invoice + Status + Method + Amount + + + + + INV001 + Paid + $250.00 + Credit Card + + + INV002 + Pending + $150.00 + PayPal + + + INV003 + Unpaid + $350.00 + Bank Transfer + + Section 1 + + INV001 + Paid + $250.00 + Credit Card + + + INV002 + Pending + $150.00 + PayPal + + + INV003 + Unpaid + $350.00 + Bank Transfer + + Section 2 + + INV001 + Paid + $250.00 + Credit Card + + + INV002 + Pending + $150.00 + PayPal + + + INV003 + Unpaid + $350.00 + Bank Transfer + + +
` +}; + +export const basicDemo = { + type: 'code', + code: ` + + + + Invoice + Status + Method + Amount + + + + + INV001 + Paid + $250.00 + Credit Card + + + INV001 + Paid + $250.00 + Credit Card + + +
+` +}; diff --git a/apps/www-beta/src/content/docs/components/table/index.mdx b/apps/www-beta/src/content/docs/components/table/index.mdx new file mode 100644 index 000000000..1ddb379ee --- /dev/null +++ b/apps/www-beta/src/content/docs/components/table/index.mdx @@ -0,0 +1,58 @@ +--- +title: Table +description: A responsive table component to show structured data. +--- + +import { preview, basicDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Table } from "@raystack/apsara"; +``` + +## Table Props + +Customize the Table appearance with these configuration options. + +The `Table` component is composed of several parts, each with their own props + + + +### Table.Header Props + +Defines the table’s header row. + + + +### Table.Body Props + +Wraps the table rows inside the body section. + + + +### Table.Row Props + +Represents a single row in the table. + + + +### Table.Cell Props + +Represents a single cell in a row + + + +### Table.SectionHeader Props + +Represents a section heading, grouping different rows of the table. + + + +## Examples + +### Basic Usage + + diff --git a/apps/www-beta/src/content/docs/components/table/props.ts b/apps/www-beta/src/content/docs/components/table/props.ts new file mode 100644 index 000000000..d88173f4f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/table/props.ts @@ -0,0 +1,39 @@ +export interface TableProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TableHeaderProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TableBodyProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TableRowProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TableHeadProps {} + +export interface TableCellProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TableSectionHeaderProps { + /** Map of class names for internal components. */ + classNames?: { + /** CSS class for the row. */ + row?: string; + /** CSS class for the cell. */ + cell?: string; + }; + + /** Number of cells the row should span across. Ensures the section header spans all table columns. */ + colSpan?: number; +} diff --git a/apps/www-beta/src/content/docs/components/tabs/demo.ts b/apps/www-beta/src/content/docs/components/tabs/demo.ts new file mode 100644 index 000000000..77a6f5b3e --- /dev/null +++ b/apps/www-beta/src/content/docs/components/tabs/demo.ts @@ -0,0 +1,79 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + + + + }>Hoisting + Hosting + }>Editor + Billing + SEO + + + General settings content + + + Hosting configuration content + + + Editor preferences content + + + Billing information content + + + SEO settings content + + + ` +}; + +export const basicDemo = { + type: 'code', + code: ` +
+ + + Account + Password + Settings + + Account settings + Password settings + Other settings + +
` +}; + +export const iconsDemo = { + type: 'code', + code: ` +
+ + + Home + } /> + + Home + Info + +
` +}; + +export const disabledDemo = { + type: 'code', + code: ` +
+ + + Active + Disabled + + Active tab content + Disabled tab content + +
` +}; diff --git a/apps/www-beta/src/content/docs/components/tabs/index.mdx b/apps/www-beta/src/content/docs/components/tabs/index.mdx new file mode 100644 index 000000000..bb3ca13de --- /dev/null +++ b/apps/www-beta/src/content/docs/components/tabs/index.mdx @@ -0,0 +1,52 @@ +--- +title: Tabs +description: A set of layered sections of content that display one panel at a time. +--- + +import { preview, basicDemo, iconsDemo, disabledDemo } from "./demo.ts"; + + + +## Usage + +```tsx +import { Tabs } from "@raystack/apsara"; +``` + +## Tabs Props + + + +### Tabs.List Props + + + +### Tabs.Trigger Props + + + +### Tabs.Content Props + + + +## Examples + +### Basic Usage + + + +### With Icons + + + +### Disabled Tab + + + +## Accessibility + +Tabs follow the [WAI-ARIA Tabs Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/). They include the following accessibility features: + +- Keyboard navigation between tabs using arrow keys +- Proper ARIA roles, states, and properties +- Focus management for tab panels diff --git a/apps/www-beta/src/content/docs/components/tabs/props.ts b/apps/www-beta/src/content/docs/components/tabs/props.ts new file mode 100644 index 000000000..6c4f2c7b3 --- /dev/null +++ b/apps/www-beta/src/content/docs/components/tabs/props.ts @@ -0,0 +1,40 @@ +export interface TabsRootProps { + /** The initial active tab value. If not provided, no tab will be selected by default. */ + defaultValue?: string; + + /** The controlled active tab value. */ + value?: string; + + /** Callback function triggered when the active tab changes. */ + onValueChange?: (value: string) => void; + + /** Additional CSS class names. */ + className?: string; +} + +export interface TabsListProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface TabsTriggerProps { + /** Unique identifier for the tab. */ + value: string; + + /** Optional icon element to display. */ + icon?: React.ReactNode; + + /** Whether the tab is disabled. */ + disabled?: boolean; + + /** Additional CSS class names. */ + className?: string; +} + +export interface TabsContentProps { + /** Matching identifier for the tab. */ + value: string; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/text/demo.ts b/apps/www-beta/src/content/docs/components/text/demo.ts new file mode 100644 index 000000000..3f49caecd --- /dev/null +++ b/apps/www-beta/src/content/docs/components/text/demo.ts @@ -0,0 +1,151 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + variant: { + type: 'select', + options: [ + 'primary', + 'secondary', + 'tertiary', + 'emphasis', + 'accent', + 'attention', + 'danger', + 'success' + ], + defaultValue: 'primary' + }, + as: { + type: 'select', + options: ['span', 'p', 'div', 'label', 'a'], + defaultValue: 'span' + }, + size: { + type: 'select', + options: ['micro', 'mini', 'small', 'regular', 'large'], + defaultValue: 'regular' + }, + weight: { + type: 'select', + options: ['regular', 'medium'], + defaultValue: 'regular' + }, + transform: { + type: 'select', + options: [undefined, 'capitalize', 'uppercase', 'lowercase'] + }, + align: { + type: 'select', + options: [undefined, 'center', 'start', 'end', 'justify'] + }, + lineClamp: { + type: 'select', + options: [undefined, 1, 2, 3, 4, 5] + }, + underline: { + type: 'checkbox', + defaultValue: false + }, + strikeThrough: { + type: 'checkbox', + defaultValue: false + }, + italic: { + type: 'checkbox', + defaultValue: false + }, + + children: { + type: 'text', + initialValue: + 'Nulla dolor velit adipisicing duis excepteur esse in duis nostrud occaecat mollit incididunt deserunt sunt. Ut ut sunt laborum ex occaecat eu tempor labore enim adipisicing minim ad. Est in quis eu dolore occaecat excepteur fugiat dolore nisi aliqua fugiat enim ut cillum. Labore enim duis nostrud eu. Est ut eiusmod consequat irure quis deserunt ex. Enim laboris dolor magna pariatur. Dolor et ad sint voluptate sunt elit mollit officia ad enim sit consectetur enim.' + } + }, + getCode +}; + +export const variantDemo = { + type: 'code', + code: ` + + primary + secondary + tertiary +
+ emphasis +
+ accent + attention + danger + success +
` +}; +export const sizeDemo = { + type: 'code', + code: ` + + This is a text + This is a text + This is a text + This is a text + This is a text + ` +}; +export const weightDemo = { + type: 'code', + code: ` + + This is a text + This is a text + ` +}; +export const transformDemo = { + type: 'code', + code: ` + + This is a text + This is a text + This is a text + ` +}; +export const lineClampDemo = { + type: 'code', + code: ` + + Nulla dolor velit adipisicing duis excepteur esse in duis nostrud occaecat mollit incididunt deserunt sunt. Ut ut sunt laborum ex occaecat eu tempor labore enim adipisicing minim ad. Est in quis eu dolore occaecat excepteur fugiat dolore nisi aliqua fugiat enim ut cillum. Labore enim duis nostrud eu. Est ut eiusmod consequat irure quis deserunt ex. Enim laboris dolor magna pariatur. Dolor et ad sint voluptate sunt elit mollit officia ad enim sit consectetur enim. + Nulla dolor velit adipisicing duis excepteur esse in duis nostrud occaecat mollit incididunt deserunt sunt. Ut ut sunt laborum ex occaecat eu tempor labore enim adipisicing minim ad. Est in quis eu dolore occaecat excepteur fugiat dolore nisi aliqua fugiat enim ut cillum. Labore enim duis nostrud eu. Est ut eiusmod consequat irure quis deserunt ex. Enim laboris dolor magna pariatur. Dolor et ad sint voluptate sunt elit mollit officia ad enim sit consectetur enim. + ` +}; +export const alignDemo = { + type: 'code', + code: ` + + This is a text + This is a text + This is a text + This is a text + ` +}; +export const styleDemo = { + type: 'code', + code: ` + + This is a text + This is a text + This is a text + This is a text + ` +}; diff --git a/apps/www-beta/src/content/docs/components/text/index.mdx b/apps/www-beta/src/content/docs/components/text/index.mdx new file mode 100644 index 000000000..f5f00568f --- /dev/null +++ b/apps/www-beta/src/content/docs/components/text/index.mdx @@ -0,0 +1,59 @@ +--- +title: Text +description: Component for Text +--- + +import { + playground, + sizeDemo, + weightDemo, + variantDemo, + alignDemo, + styleDemo, + transformDemo, + lineClampDemo, +} from "./demo.ts"; + + + +## Usage + +```tsx +import { Text } from '@raystack/apsara' +``` + +## Text Props + +According to the element rendered using `as`, Text will extend over the default HTML Attributes + + + +## Examples + +### Variant + + + +### Size + + + +### Weight + + + +### Transform + + + +### Line Clamp + + + +### Align + + + +### Style + + diff --git a/apps/www-beta/src/content/docs/components/text/props.ts b/apps/www-beta/src/content/docs/components/text/props.ts new file mode 100644 index 000000000..b6ab559de --- /dev/null +++ b/apps/www-beta/src/content/docs/components/text/props.ts @@ -0,0 +1,66 @@ +export interface TextProps { + /** + * Text element to render as. + * @default "span" + */ + as?: 'span' | 'p' | 'div' | 'label' | 'a'; + + /** + * The visual style variant. + * @default "primary" + */ + variant?: + | 'primary' + | 'secondary' + | 'tertiary' + | 'emphasis' + | 'accent' + | 'attention' + | 'danger' + | 'success'; + + /** + * The text size. + * @default "regular" + */ + size?: 'micro' | 'mini' | 'small' | 'regular' | 'large'; + + /** + * The text weight. + * @default "regular" + */ + weight?: 'regular' | 'medium'; + + /** + * Text transform property + */ + transform?: 'capitalize' | 'uppercase' | 'lowercase'; + + /** + * Text align. + */ + align?: 'center' | 'start' | 'end' | 'justify'; + + /** + * Should clamp line. + */ + lineClamp?: 1 | 2 | 3 | 4 | 5; + + /** + * Show underlined text. + */ + underline?: boolean; + + /** + * Show strikethrough text. + */ + strikeThrough?: boolean; + + /** + * Show italic text. + */ + italic?: boolean; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/apps/www-beta/src/content/docs/components/textarea/demo.ts b/apps/www-beta/src/content/docs/components/textarea/demo.ts new file mode 100644 index 000000000..7eb14c2cf --- /dev/null +++ b/apps/www-beta/src/content/docs/components/textarea/demo.ts @@ -0,0 +1,82 @@ +'use client'; + +import { getPropsString } from '@/lib/utils'; + +export const getCode = (props: any) => { + return ``; +}; + +export const playground = { + type: 'playground', + controls: { + label: { + type: 'text', + initialValue: 'Textarea' + }, + isOptional: { + type: 'checkbox', + defaultValue: false + }, + helperText: { + type: 'text', + default: 'Helper text' + }, + error: { + type: 'checkbox', + defaultValue: false + }, + width: { + type: 'text', + defaultValue: '200px' + } + }, + getCode +}; + +export const basicDemo = { + type: 'code', + code: ` +