docs: migrate UI docs (#13245)

* docs: create a new UI docs project (#13233)

* docs: create a new UI docs project

* fix installation errors

* docs: migrate UI docs content to new project (#13241)

* Fix content

* added examples for some components

* finish adding examples

* lint fix

* fix build errors

* delete empty files

* path fixes + refactor

* fix build error
This commit is contained in:
Shahed Nasser
2025-08-20 11:42:25 +03:00
committed by GitHub
parent 5b7a041246
commit d1a1135328
748 changed files with 13079 additions and 7319 deletions

View File

@@ -260,7 +260,7 @@ jobs:
- name: Get Directories to Scan
if: ${{ steps.pr-files.outputs.files_lt_threshold == 'true' }}
working-directory: www/vale
run: ./get-files.sh ui/src/content/docs
run: ./get-files.sh ui/app
id: directories
- name: Vale Linter

3
www/.gitignore vendored
View File

@@ -8,4 +8,5 @@ node_modules
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.env.local
.env.local
ui-old

View File

@@ -50,7 +50,6 @@ const withMDX = createMDX({
},
ui: {
projectPath: path.resolve("..", "ui"),
contentPath: "src/content/docs",
},
"user-guide": {
projectPath: path.resolve("..", "user-guide"),

View File

@@ -98,11 +98,11 @@ The API reference's content is split into two types:
### Medusa UI Documentation
The content of the Medusa UI documentation are located under the `www/apps/ui/src/content/docs` directory. They are MDX files.
The content of the Medusa UI documentation are located under the `www/apps/ui/app` directory. They are MDX files.
The UI documentation also shows code examples, which are under the `www/apps/ui/src/examples` directory.
The UI documentation also shows code examples, which are under the `www/apps/ui/specs/examples` directory.
The UI component props are generated from the source code and placed into the `www/apps/ui/src/specs` directory. To contribute to these props and their comments, check the comments in the source code under the `packages/design-system/ui` directory.
The UI component props are generated from the source code and placed into the `www/apps/ui/specs/components` directory. To contribute to these props and their comments, check the comments in the source code under the `packages/design-system/ui` directory.
---
@@ -195,7 +195,7 @@ cd www/vale
# to lint content for the API reference
./run-vale.sh api-reference/markdown error
# to lint content for the Medusa UI documentation
./run-vale.sh ui/src/content/docs error
./run-vale.sh ui/app error
# to lint content for the user guide
./run-vale.sh user-guide/app error
```

View File

@@ -109,7 +109,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/api-routes/parse-body/page.mdx": "2025-04-17T08:29:10.145Z",
"app/learn/fundamentals/admin/routing/page.mdx": "2025-07-25T07:35:18.038Z",
"app/learn/resources/contribution-guidelines/admin-translations/page.mdx": "2025-02-11T16:57:46.726Z",
"app/learn/resources/contribution-guidelines/docs/page.mdx": "2025-05-26T15:55:02.974Z",
"app/learn/resources/contribution-guidelines/docs/page.mdx": "2025-08-20T06:41:30.822Z",
"app/learn/resources/usage/page.mdx": "2025-02-26T13:35:34.824Z",
"app/learn/configurations/medusa-config/page.mdx": "2025-07-14T09:28:54.302Z",
"app/learn/configurations/ts-aliases/page.mdx": "2025-07-23T15:32:18.008Z",

View File

@@ -31,7 +31,6 @@ const withMDX = mdx({
},
ui: {
projectPath: path.resolve("..", "ui"),
contentPath: "src/content/docs",
},
"user-guide": {
projectPath: path.resolve("..", "user-guide"),

File diff suppressed because it is too large Load Diff

View File

@@ -265,7 +265,7 @@ async function main() {
},
},
{
dir: path.join(process.cwd(), "..", "ui", "src", "content", "docs"),
dir: path.join(process.cwd(), "..", "ui", "app"),
options: {
parserOptions: {
ComponentExample: {
@@ -273,12 +273,18 @@ async function main() {
process.cwd(),
"..",
"ui",
"src",
"specs",
"examples"
),
},
ComponentReference: {
specsPath: path.join(process.cwd(), "..", "ui", "src", "specs"),
specsPath: path.join(
process.cwd(),
"..",
"ui",
"specs",
"components"
),
},
},
},

View File

@@ -30,7 +30,6 @@ const withMDX = mdx({
},
ui: {
projectPath: path.resolve("..", "ui"),
contentPath: "src/content/docs",
},
resources: {
projectPath: path.resolve("..", "resources"),

View File

@@ -740,7 +740,7 @@ export const paymentInfoMap: Record<
For every payment method you want to customize its display, add an entry in the `paymentInfoMap` object. The key should match the [type enum in Stripe's Payment Element](https://docs.stripe.com/api/payment_methods/object#payment_method_object-type), and the value is an object with the following properties:
- `title`: The title to display for the payment method.
- `icon`: A JSX element representing the icon for the payment method. You can use icons from [Medusa UI](!ui!/icons) or custom icons.
- `icon`: A JSX element representing the icon for the payment method. You can use icons from [Medusa UI](!ui!/icons/overview) or custom icons.
### Test it out

View File

@@ -33,7 +33,6 @@ const withMDX = mdx({
},
ui: {
projectPath: path.resolve("..", "ui"),
contentPath: "src/content/docs",
},
"user-guide": {
projectPath: path.resolve("..", "user-guide"),

View File

@@ -150,7 +150,7 @@ export default [
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-require-imports": "off",
},
},
]

View File

@@ -1,11 +1,19 @@
NEXT_PUBLIC_DOCS_URL=
NEXT_PUBLIC_BASE_URL=
NEXT_PUBLIC_BASE_PATH=/ui
NEXT_PUBLIC_SEGMENT_API_KEY=
NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME=
NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME=
NEXT_PUBLIC_ALGOLIA_API_KEY=
NEXT_PUBLIC_ALGOLIA_APP_ID=
NEXT_PUBLIC_SEGMENT_API_KEY=
NEXT_PUBLIC_ENV=
NEXT_PUBLIC_BASE_URL=
NEXT_PUBLIC_BASE_PATH=
NEXT_PUBLIC_DOCS_URL=
NEXT_PUBLIC_RESOURCES_URL=
NEXT_PUBLIC_UI_URL=
NEXT_PUBLIC_API_URL=
NEXT_PUBLIC_USER_GUIDE_URL=
ALGOLIA_WRITE_API_KEY=
ANALYZE_BUNDLE=
CLOUDINARY_CLOUD_NAME=
NEXT_PUBLIC_GA_ID=
NEXT_PUBLIC_INTEGRATION_ID=
NEXT_PUBLIC_REO_DEV_CLIENT_ID=

View File

@@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
@@ -33,6 +34,3 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
# contentlayer
.contentlayer

View File

@@ -1 +0,0 @@
nmMode: hardlinks-local

View File

@@ -0,0 +1,39 @@
---
generate_toc: true
---
import { Colors } from "@/components/Colors"
export const metadata = {
title: `Medusa UI Colors`,
}
# {metadata.title}
In this guide, you'll learn about the color classes available in Medusa UI and how to use them.
## Overview
Medusa UI provides Tailwind CSS classes for colors from the Medusa design system. These classes can be used to style components and elements consistently across your Medusa and standalone applications.
To view the colors in the list below in dark mode, switch the documentation's theme from the menu in the top right.
To copy a color's Tailwind CSS class from the list below, click on it.
### How to Use the Medusa UI Colors
You can use the color classes in your Medusa Admin customizations or standalone projects that have the `@medusajs/ui` package installed.
You can apply the color classes as CSS classes to any element.
For example, to set the background color of the document's body:
```tsx
<body className="bg-medusa-bg-base">
...
</body>
```
---
<Colors />

View File

@@ -1,15 +1,22 @@
---
title: "Alert"
description: "A component for displaying important messages."
component: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Alert`,
}
# {metadata.title}
A component for displaying important messages.
In this guide, you'll learn how to use the Alert component.
<ComponentExample name="alert-demo" />
## Usage
---
## Usage
```tsx
import { Alert } from "@medusajs/ui"
```
@@ -18,16 +25,16 @@ import { Alert } from "@medusajs/ui"
<Alert>Here's a message</Alert>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Alert" />
## Examples
---
## Examples
### Success Alert
<ComponentExample name="alert-success" />
@@ -40,6 +47,7 @@ import { Alert } from "@medusajs/ui"
<ComponentExample name="alert-error" />
### Dismissable Alert
### Dismissible Alert
<ComponentExample name="alert-dismissable" hideFeedback />
<ComponentExample name="alert-dismissable" />

View File

@@ -0,0 +1,59 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Avatar`,
}
# {metadata.title}
A component for displaying user avatars with a fallback option.
In this guide, you'll learn how to use the Avatar component.
<ComponentExample name="avatar-demo" />
## Usage
```tsx
import { Avatar } from "@medusajs/ui"
```
```tsx
<Avatar
src="https://avatars.githubusercontent.com/u/10656202?v=4"
fallback="M"
/>
```
---
## API Reference
<ComponentReference mainComponent="Avatar" />
---
## Examples
### Avatar Variants
<ComponentExample name="avatar-variants" />
### Avatar Sizes
<ComponentExample name="avatar-sizes" />
### Avatar Fallback Only
<ComponentExample name="avatar-fallback" />
### Avatar Custom Styling
<ComponentExample name="avatar-custom-style" />
### Avatar Accessibility
You can add the `aria-label` prop to the Avatar component for better accessibility.
<ComponentExample name="avatar-accessible" hideFeedback />

View File

@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Badge`,
}
# {metadata.title}
A component for displaying labels or indicators in a badge style.
In this guide, you'll learn how to use the Badge component.
<ComponentExample name="badge-demo" />
## Usage
```tsx
import { Badge } from "@medusajs/ui"
```
```tsx
<Badge>Badge</Badge>
```
---
## API Reference
<ComponentReference mainComponent="Badge" />
---
## Examples
### Badge Colors
<ComponentExample name="badge-all-colors" />
### Badge Sizes
<ComponentExample name="badge-all-sizes" />
### Badge Rounded Variants
<ComponentExample name="badge-all-rounded" hideFeedback />

View File

@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Button`,
}
# {metadata.title}
A component for rendering buttons using Medusa's design system.
In this guide, you'll learn how to use the Button component.
<ComponentExample name="button-demo" />
---
## Usage
```tsx
import { Button } from "@medusajs/ui"
```
```tsx
<Button>Button</Button>
```
---
## API Reference
<ComponentReference mainComponent="Button" />
---
## Examples
### Button Variants
<ComponentExample name="button-all-variants" />
### Button Sizes
<ComponentExample name="button-all-sizes" />
### Button Loading State
<ComponentExample name="button-loading" />
### Button with Icon
<ComponentExample name="button-with-icon" />
### Button as Link
<ComponentExample name="button-as-link" hideFeedback />

View File

@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Calendar`,
}
# {metadata.title}
A component for displaying a calendar interface with date selection capability.
In this guide, you'll learn how to use the Calendar component.
<ComponentExample name="calendar-demo" />
## Usage
```tsx
import { Calendar } from "@medusajs/ui"
```
```tsx
<Calendar />
```
---
## API Reference
<ComponentReference mainComponent="Calendar" />
---
## Examples
### Controlled
<ComponentExample name="calendar-controlled" />
### Min/Max Dates
<ComponentExample name="calendar-min-max" />
### Unavailable Dates
<ComponentExample name="calendar-unavailable" hideFeedback />

View File

@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Checkbox`,
}
# {metadata.title}
A component for rendering checkbox inputs using Medusa's design system.
In this guide, you'll learn how to use the Checkbox component.
<ComponentExample name="checkbox-demo" />
## Usage
```tsx
import { Checkbox } from "@medusajs/ui"
```
```tsx
<Checkbox />
```
---
## API Reference
<ComponentReference mainComponent="Checkbox" />
---
## Examples
### Checkbox All States
<ComponentExample name="checkbox-all-states" />
### Controlled Checkbox
<ComponentExample name="checkbox-controlled" hideFeedback />

View File

@@ -1,15 +1,24 @@
---
title: "Code Block"
description: "Allows you to render highlighted code snippets"
component: true
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Code Block`,
}
# {metadata.title}
A component for displaying code snippets with syntax highlighting and copy functionality.
In this guide, you'll learn how to use the Code Block component.
<ComponentExample name="code-block-demo" />
## Usage
---
```tsx
import { CodeBlock } from "@medusajs/ui"
```
@@ -29,11 +38,10 @@ import { CodeBlock } from "@medusajs/ui"
</CodeBlock>
```
---
## API Reference
---
<ComponentReference mainComponent="CodeBlock" componentsToShow={[
"CodeBlock",
"CodeBlock.Header",
@@ -41,11 +49,11 @@ import { CodeBlock } from "@medusajs/ui"
"CodeBlock.Body"
]} />
## Usage Outside Medusa Admin
---
If you're using the `CodeBlock` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `CodeBlock.Header` component uses a [Tooltip](/components/tooltip#usage-outside-medusa-admin):
## Usage Outside Medusa Admin
If you're using the `CodeBlock` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `CodeBlock.Header` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
@@ -64,11 +72,11 @@ If you're using the `CodeBlock` component in a project other than the Medusa Adm
</TooltipProvider>
```
## Examples
---
### Single snippet
## Examples
### Single Snippet
If you want to only show a code sample for one language or API, you can choose to hide the snippet labels:
@@ -76,7 +84,7 @@ If you want to only show a code sample for one language or API, you can choose t
### No Header
You could also choose to omit the header entirely:
You can also omit the header entirely:
<ComponentExample name="code-block-no-header" />
@@ -86,4 +94,4 @@ You could also choose to omit the header entirely:
### No Copy Button
<ComponentExample name="code-block-no-copy" />
<ComponentExample name="code-block-no-copy" hideFeedback />

View File

@@ -1,15 +1,24 @@
---
title: "Command Bar"
description: "Display a command bar with a list of commands"
component: true
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Command Bar`,
}
# {metadata.title}
A component that displays a command bar with a list of commands to perform on a bulk selection of items.
In this guide, you'll learn how to use the Command Bar component.
<ComponentExample name="command-bar-demo" />
## Usage
---
```tsx
import { CommandBar } from "@medusajs/ui"
```
@@ -34,14 +43,15 @@ import { CommandBar } from "@medusajs/ui"
</CommandBar>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="CommandBar" componentsToShow={[
"CommandBar",
"CommandBar.Bar",
"CommandBar.Value",
"CommandBar.Seperator",
"CommandBar.Command"
]} />
]} hideFeedback />

View File

@@ -1,15 +1,20 @@
---
title: "Command"
description: "Renders an unhighlighted code block, useful for one-liners or API Routes"
component: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Command`,
}
# {metadata.title}
A component that renders an unhighlighted code block, useful for one-liners or API routes.
In this guide, you'll learn how to use the Command component.
<ComponentExample name="command-demo" />
## Usage
---
```tsx
import { Command } from "@medusajs/ui"
```
@@ -20,17 +25,17 @@ import { Command } from "@medusajs/ui"
</Command>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Command" />
## Usage Outside Medusa Admin
---
If you're using the `Command` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `Command.Copy` component uses a [Tooltip](/components/tooltip#usage-outside-medusa-admin):
## Usage Outside Medusa Admin
If you're using the `Command` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `Command.Copy` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
@@ -42,4 +47,4 @@ If you're using the `Command` component in a project other than the Medusa Admin
/>
</Command>
</TooltipProvider>
```
```

View File

@@ -0,0 +1,38 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Container`,
}
# {metadata.title}
A component that wraps content in a card-like container. The container is useful to create sections in the Medusa Admin dashboard.
In this guide, you'll learn how to use the Container component.
<ComponentExample name="container-demo" />
## Usage
```tsx
import { Container } from "@medusajs/ui"
```
```tsx
<Container>Container</Container>
```
---
## API Reference
<ComponentReference mainComponent="Container" />
---
## Examples
### In a Layout
<ComponentExample name="container-layout" hideFeedback />

View File

@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Copy`,
}
# {metadata.title}
A component that wraps content in a button with copy functionality. It is useful for quickly copying text to the clipboard, such as code snippets or configuration commands.
In this guide, you'll learn how to use the Copy component.
<ComponentExample name="copy-demo" />
## Usage
```tsx
import { Copy } from "@medusajs/ui"
```
```tsx
<Copy content="yarn add @medusajs/ui" />
```
---
## API Reference
<ComponentReference mainComponent="Copy" />
---
## Usage Outside Medusa Admin
If you're using the `Copy` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `Copy` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
<Copy content="yarn add @medusajs/ui" />
</TooltipProvider>
```
---
## Examples
### Copy with Custom Display
<ComponentExample name="copy-custom-display" />
### Copy Display As Child
Using the `asChild` prop, you can render the `<Copy/>` as its child. This is useful if you want to render a custom button, to prevent rendering a button inside a button.
<ComponentExample name="copy-as-child" hideFeedback />

View File

@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Currency Input`,
}
# {metadata.title}
A component for rendering form inputs for money amounts, showing the currency in the input.
In this guide, you'll learn how to use the Currency Input component.
<ComponentExample name="currency-input-demo" />
## Usage
```tsx
import { CurrencyInput } from "@medusajs/ui"
```
```tsx
<CurrencyInput symbol="$" code="usd" />
```
---
## API Reference
<ComponentReference mainComponent="CurrencyInput" />
---
## Examples
### Controlled Currency Input
<ComponentExample name="currency-input-controlled" />
### Disabled Currency Input
<ComponentExample name="currency-input-disabled" />
### Currency Input with Error State
<ComponentExample name="currency-input-error" />
### Currency Input Sizes
#### Base
<ComponentExample name="currency-input-base" />
#### Small
<ComponentExample name="currency-input-small" hideFeedback />

View File

@@ -1,26 +1,33 @@
---
title: "DataTable"
description: "A Table component with advanced functionalities like pagination, filtering, and more."
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
import { Feedback } from "@/components/Feedback"
export const metadata = {
title: `Data Table`,
}
# {metadata.title}
A component to display a table of data with advanced functionalities like pagination, filtering, and more.
In this guide, you'll learn how to use the DataTable component.
The `DataTable` component is useful if you're displaying large data with functionalities like pagination, filtering, sorting, and searching. It's also the recommended table component to use when creating customizations in the Medusa Admin.
<Note>
This component is available after Medusa UI v4.0.4 (or Medusa v2.4.0). It is built on top of the [Table](/components/table) component. If you want a table with more control over its styling and functionality, use that component instead.
This component is available after Medusa UI v4.0.4 (or Medusa v2.4.0). It is built on top of the [Table](../table/page.mdx) component. If you want a table with more control over its styling and functionality, use that component instead.
</Note>
## Simple Example
---
<ComponentExample name="data-table-demo" disableCenterAlignPreview />
## Usage
---
You import the `DataTable` component from `@medusajs/ui`.
```tsx
@@ -29,7 +36,7 @@ import {
} from "@medusajs/ui"
```
### Columns Preparation
### Data Table Columns Preparation
Before using the `DataTable` component, you need to prepare its columns using the `createDataTableColumnHelper` utility:
@@ -61,14 +68,14 @@ const columns = [
]
```
The `createDataTableColumnHelper` utility is a function that returns a helper used to generates column configurations for the `DataTable` component.
The `createDataTableColumnHelper` utility is a function that returns a helper used to generate column configurations for the `DataTable` component.
For each column in the table, use the `accessor` method of the column helper to specify configurations for a specific column. The `accessor` method accepts the column's key in the table's data as the first parameter, and an object with the following properties as the second parameter:
- `header`: The table header text for the column.
- `enableSorting`: (optional) A boolean that indicates whether data in the table can be sorted by this column. More on sorting in [this section](#configure-sorting-in-datatable).
### Create Table Instance
### Create Data Table Instance
The `DataTable` component expects a table instance created using the `useDataTable` hook. Import that hook from `@medusajs/ui`:
@@ -126,10 +133,10 @@ In the `DataTable` component, you pass the following child components:
Refer to the examples later on this page to learn how to add pagination, filtering, and other functionalities using the `DataTable` component.
## API Reference
---
## API Reference
<ComponentReference mainComponent="DataTable" componentsToShow={[
"DataTable",
"DataTable.Table",
@@ -140,16 +147,16 @@ Refer to the examples later on this page to learn how to add pagination, filteri
"DataTable.SortingMenu",
]} />
## Example with Data Fetching
---
## Example with Data Fetching
Refer to [this Admin Components guide](https://docs.medusajs.com/resources/admin-components/components/data-table) for an example on using the `DataTable` component with data fetching from the Medusa application.
## Handle Row Click
---
## Handle Row Click
<ComponentExample name="data-table-row-click" disableCenterAlignPreview />
In many cases, you want to perform an action when a row is clicked. Most commonly, you may want to open the details page of the row when it's clicked.
@@ -175,15 +182,15 @@ const table = useDataTable({
The value of `onRowClick` is a function that accepts two parameters:
- `event`: An instance of the [MouseClickEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) object.
- `event`: An instance of the [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) object.
- `row`: The data of the row that was clicked.
In the above example, you use a `navigate` function, retrieved through the `useNavigate` hook from `react-router-dom`, to navigate to the details page of the row that was clicked.
## Configure Cell Rendering
---
## Configure Cell Rendering
<ComponentExample name="data-table-custom-cell" disableCenterAlignPreview />
The `accessor` method of the `createDataTableColumnHelper` utility accepts a `cell` property that you can use to customize the rendering of the cell content.
@@ -226,10 +233,10 @@ const columns = [
The `cell` property's value is a function that returns a string or a React node to be rendered in the cell. The function receives as a parameter an object having a `getValue` property to get the raw value of the cell.
## Configure Search in DataTable
---
## Configure Search in DataTable
<ComponentExample name="data-table-search" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `search` property that you can use to enable and configure the search functionality in the `DataTable` component:
@@ -294,10 +301,10 @@ return (
This will show a search input at the top of the table, in the data table's toolbar.
## Configure Pagination in DataTable
---
## Configure Pagination in DataTable
<ComponentExample name="data-table-pagination" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `pagination` property that you can use to enable and configure the pagination functionality in the `DataTable` component.
@@ -390,10 +397,10 @@ return (
This will show the pagination controls at the end of the table.
## Configure Filters in DataTable
---
## Configure Filters in DataTable
<ComponentExample name="data-table-filters" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `filters` property that you can use to enable and configure the filtering functionality in the `DataTable` component.
@@ -553,7 +560,7 @@ return (
This will show a filter menu at the top of the table, in the data table's toolbar.
### Filtering Date Values
### Filtering Date Values in DataTable
<ComponentExample name="data-table-filters-date" disableCenterAlignPreview />
@@ -645,7 +652,7 @@ const shownProducts = useMemo(() => {
}, [filtering])
```
### Initial Filter Values
### Initial Filter Values in DataTable
<ComponentExample name="data-table-filters-initial" disableCenterAlignPreview />
@@ -659,10 +666,10 @@ const [filtering, setFiltering] = useState<DataTableFilteringState>({
The user can still change the filter values, but the initial values will be applied when the table is first rendered.
## Configure Sorting in DataTable
---
## Configure Sorting in DataTable
<ComponentExample name="data-table-sorting" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `sorting` property that you can use to enable and configure the sorting functionality in the `DataTable` component.
@@ -785,7 +792,7 @@ return (
This will show a sorting menu at the top of the table, in the data table's toolbar.
### Initial Sort Values
### Initial Sort Values in DataTable
<ComponentExample name="data-table-sorting-initial" disableCenterAlignPreview />
@@ -800,10 +807,10 @@ const [sorting, setSorting] = useState<DataTableSortingState | null>({
The user can still change the sort values, but the initial values will be applied when the table is first rendered.
## Perform Bulk Actions on DataTable Rows
---
## Perform Bulk Actions on DataTable Rows
<ComponentExample name="data-table-commands" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `commands` object property that you can use to add custom actions to the `DataTable` component.
@@ -913,4 +920,4 @@ return (
)
```
This will show a command bar when the user has selected at least one row in the table.
This will show a command bar when the user has selected at least one row in the table.

View File

@@ -1,15 +1,20 @@
---
title: "Date Picker"
description: "A date picker component with range and presets."
component: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Date Picker`,
}
# {metadata.title}
A component for rendering date picker inputs with range and presets.
In this guide, you'll learn how to use the Date Picker component.
<ComponentExample name="date-picker-demo" />
## Usage
---
```tsx
import { DatePicker } from "@medusajs/ui"
```
@@ -18,16 +23,16 @@ import { DatePicker } from "@medusajs/ui"
<DatePicker />
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="DatePicker" />
## Examples
---
## Examples
### Controlled Date Picker
Manage and store the value of the date picker in a state variable for controlled behavior. This is also useful for form integration.
@@ -40,7 +45,7 @@ Enable time selection with different granularity levels for precise scheduling.
<ComponentExample name="date-picker-with-time" />
### Min/Max Values
### Date Picker Min/Max Values
Restrict date selection to a specific range by setting minimum and maximum values.
@@ -48,7 +53,7 @@ In the example below, you can only select dates within the next 30 days. Dates o
<ComponentExample name="date-picker-min-max" />
### Disabled Dates
### Date Picker Disabled Dates
Disable specific dates like weekends and holidays to prevent selection of unavailable dates.
@@ -56,14 +61,14 @@ The example below disables weekends and holidays like Christmas.
<ComponentExample name="date-picker-business-hours" />
### Granularity Options
### Date Picker Granularity Options
Different levels of time precision from date-only to second-precision selection.
<ComponentExample name="date-picker-granularity" />
### Form Integration
### Date Picker Form Integration
The following example shows how to use the date picker in a form, with simulated form submission.
<ComponentExample name="date-picker-form" />
<ComponentExample name="date-picker-form" hideFeedback />

View File

@@ -1,15 +1,24 @@
---
title: "Drawer"
description: "A triggerable drawer that overlaps whatever page it's on."
component: true
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Drawer`,
}
# {metadata.title}
A component for rendering a sliding panel that overlays the main content.
In this guide, you'll learn how to use the Drawer component.
<ComponentExample name="drawer-demo" />
## Usage
---
```tsx
import { Drawer } from "@medusajs/ui"
```
@@ -27,10 +36,10 @@ import { Drawer } from "@medusajs/ui"
</Drawer>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Drawer" componentsToShow={[
"Drawer",
"Drawer.Trigger",
@@ -39,4 +48,14 @@ import { Drawer } from "@medusajs/ui"
"Drawer.Title",
"Drawer.Body",
"Drawer.Footer"
]} />
]} />
---
## Examples
### Drawer with Form
This example shows a simple form inside a Drawer, demonstrating how to use form elements and handle submission.
<ComponentExample name="drawer-form" hideFeedback />

View File

@@ -0,0 +1,79 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
import { getOsShortcut, Kbd } from "docs-ui"
export const osShortcut = getOsShortcut()
export const metadata = {
title: `Dropdown Menu`,
}
# {metadata.title}
A component for rendering dropdown menus that display a set of actions or options to users.
In this guide, you'll learn how to use the Dropdown Menu component.
<ComponentExample name="dropdown-menu-demo" />
## Usage
```tsx
import { DropdownMenu } from "@medusajs/ui"
```
```tsx
<DropdownMenu>
<DropdownMenu.Trigger>Trigger</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item>Edit</DropdownMenu.Item>
<DropdownMenu.Item>Add</DropdownMenu.Item>
<DropdownMenu.Item>Delete</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
```
---
## API Reference
<ComponentReference mainComponent="DropdownMenu" componentsToShow={[
"DropdownMenu",
"DropdownMenu.Trigger",
"DropdownMenu.Content",
"DropdownMenu.Item",
"DropdownMenu.Shortcut",
"DropdownMenu.Hint",
"DropdownMenu.RadioGroup",
"DropdownMenu.RadioItem"
]} />
---
## Examples
### Sorting
This example shows how to display collection sorting choices using a Dropdown Menu.
<ComponentExample name="dropdown-menu-sorting" />
### Dropdown with Submenu
<ComponentExample name="dropdown-menu-submenu" />
### Disabled Items and Using Icons
<ComponentExample name="dropdown-menu-disabled-icons" />
### Keyboard Shortcuts (with handling)
This example shows how to visually display keyboard shortcuts in the menu and handle them in your application logic.
You can use the <Kbd>{osShortcut}E</Kbd> and <Kbd>{osShortcut}D</Kbd> shortcuts to trigger the actions of the dropdown items.
<ComponentExample name="dropdown-menu-shortcuts" hideFeedback />

View File

@@ -0,0 +1,66 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Focus Modal`,
}
# {metadata.title}
A component for rendering a modal dialog shown over the main content.
In this guide, you'll learn how to use the Focus Modal component.
<ComponentExample name="focus-modal-demo" />
## Usage
```tsx
import { FocusModal } from "@medusajs/ui"
```
```tsx
<FocusModal>
<FocusModal.Trigger>Trigger</FocusModal.Trigger>
<FocusModal.Content>
<FocusModal.Header>Title</FocusModal.Header>
<FocusModal.Body>Content</FocusModal.Body>
</FocusModal.Content>
</FocusModal>
```
---
## API Reference
<ComponentReference mainComponent="FocusModal" componentsToShow={[
"FocusModal",
"FocusModal.Trigger",
"FocusModal.Content",
"FocusModal.Header",
"FocusModal.Body",
"FocusModal.Footer"
]} />
---
## Examples
### Control Focus Modal Open State
<ComponentExample name="focus-modal-controlled" />
### Using Form in Focus Modal
<ComponentExample name="focus-modal-form" />
### Nested Focus Modals
A focus modal can open another focus modal. These focus modals will be stacked on top of each other. You can nest as many focus modals as you want.
<ComponentExample name="focus-modal-nested" hideFeedback />

View File

@@ -0,0 +1,30 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Heading`,
}
# {metadata.title}
A component used for page titles and other headers.
In this guide, you'll learn how to use the Heading component.
<ComponentExample name="heading-demo" />
## Usage
```tsx
import { Heading } from "@medusajs/ui"
```
```tsx
<Heading>A Title</Heading>
```
---
## API Reference
<ComponentReference mainComponent="Heading" hideFeedback />

View File

@@ -0,0 +1,45 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Icon Badge`,
}
# {metadata.title}
A component that displays an icon in a badge.
In this guide, you'll learn how to use the Icon Badge component.
<ComponentExample name="icon-badge-demo" />
## Usage
```tsx
import { IconBadge } from "@medusajs/ui"
import { BuildingTax } from "@medusajs/icons"
```
```tsx
<IconBadge>
<BuildingTax />
</IconBadge>
```
---
## API Reference
<ComponentReference mainComponent="IconBadge" />
---
## Examples
### Colors
<ComponentExample name="icon-badge-all-colors" />
### Sizes
<ComponentExample name="icon-badge-all-sizes" hideFeedback />

View File

@@ -0,0 +1,55 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Icon Button`,
}
# {metadata.title}
A component that displays an icon in a button.
In this guide, you'll learn how to use the Icon Button component.
<ComponentExample name="icon-button-demo" />
## Usage
```tsx
import { IconButton } from "@medusajs/ui"
import { Plus } from "@medusajs/icons"
```
```tsx
<IconButton>
<Plus />
</IconButton>
```
---
## API Reference
<ComponentReference mainComponent="IconButton" />
---
## Examples
### Icon Button Variants
<ComponentExample name="icon-button-all-variants" />
### Icon Button Sizes
<ComponentExample name="icon-button-all-sizes" />
### Icon Button Loading State
<ComponentExample name="icon-button-loading" />
### Disabled Icon Button
<ComponentExample name="icon-button-disabled" hideFeedback />

View File

@@ -1,15 +1,20 @@
---
title: "Inline Tip"
description: "A component for displaying a note or tip inline."
component: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Inline Tip`,
}
# {metadata.title}
A component for displaying a note or tip inline.
In this guide, you'll learn how to use the Inline Tip component.
<ComponentExample name="inline-tip-demo" />
## Usage
---
```tsx
import { InlineTip } from "@medusajs/ui"
```
@@ -22,16 +27,16 @@ import { InlineTip } from "@medusajs/ui"
</InlineTip>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="InlineTip" />
## Examples
---
## Examples
### Success Inline Tip
<ComponentExample name="inline-tip-success" />
@@ -42,4 +47,4 @@ import { InlineTip } from "@medusajs/ui"
### Error Inline Tip
<ComponentExample name="inline-tip-error" />
<ComponentExample name="inline-tip-error" hideFeedback />

View File

@@ -1,15 +1,20 @@
---
title: "Input"
description: "Renders a form input field"
component: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Input`,
}
# {metadata.title}
A component that renders a form input field using Medusa's design system.
In this guide, you'll learn how to use the Input component.
<ComponentExample name="input-demo" />
## Usage
---
```tsx
import { Input } from "@medusajs/ui"
```
@@ -18,16 +23,16 @@ import { Input } from "@medusajs/ui"
<Input placeholder="Placeholder" id="input-id" />
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Input" />
## Examples
---
## Examples
### Password
<ComponentExample name="input-password" />
@@ -40,12 +45,16 @@ import { Input } from "@medusajs/ui"
<ComponentExample name="input-disabled" />
### Small
### Small Size
<ComponentExample name="input-small" />
### Error state
### Controlled
<ComponentExample name="input-controlled" />
### Error State
You can leverage the native `aria-invalid` property to show an error state on your input:
<ComponentExample name="input-error" />
<ComponentExample name="input-error" hideFeedback />

View File

@@ -0,0 +1,30 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Kbd`,
}
# {metadata.title}
A component that renders a badge-styled keyboard (`kbd`) element.
In this guide, you'll learn how to use the Kbd component.
<ComponentExample name="kbd-demo" />
## Usage
```tsx
import { Kbd } from "@medusajs/ui"
```
```tsx
<Kbd>Ctrl + Shift + A</Kbd>
```
---
## API Reference
<ComponentReference mainComponent="Kbd" hideFeedback />

View File

@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Label`,
}
# {metadata.title}
A component that renders an accessible label associated with input fields.
In this guide, you'll learn how to use the Label component.
<ComponentExample name="label-demo" />
## Usage
```tsx
import { Label } from "@medusajs/ui"
```
```tsx
<Label>Label</Label>
```
---
## API Reference
<ComponentReference mainComponent="Label" />
---
## Examples
### Label Sizes
<ComponentExample name="label-all-sizes" />
### Label with Form Inputs
<ComponentExample name="label-with-inputs" hideFeedback />

View File

@@ -0,0 +1,78 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Progress Accordion`,
}
# {metadata.title}
A component that renders a set of expandable content, specifically designed for implementing multi-step tasks.
In this guide, you'll learn how to use the Progress Accordion component.
<ComponentExample name="progress-accordion-demo" />
## Usage
```tsx
import { ProgressAccordion } from "@medusajs/ui"
```
```tsx
<ProgressAccordion type="single">
<ProgressAccordion.Item value="general">
<ProgressAccordion.Header>
General
</ProgressAccordion.Header>
<ProgressAccordion.Content>
{/* Content */}
</ProgressAccordion.Content>
</ProgressAccordion.Item>
<ProgressAccordion.Item value="shipping">
<ProgressAccordion.Header>
Shipping
</ProgressAccordion.Header>
<ProgressAccordion.Content>
{/* Content */}
</ProgressAccordion.Content>
</ProgressAccordion.Item>
</ProgressAccordion>
```
---
## API Reference
<ComponentReference mainComponent="ProgressAccordion" componentsToShow={[
"ProgressAccordion",
"ProgressAccordion.Header"
]} />
---
## Examples
### Only One Accordion Open
<ComponentExample name="progress-accordion-single" />
### Allow Multiple Accordions to Open
<ComponentExample name="progress-accordion-multiple" />
### Set Status Indicator
<ComponentExample name="progress-accordion-status" />
### Controlled Accordion Open State
<ComponentExample name="progress-accordion-controlled" />
### Disabled Accordion Item
<ComponentExample name="progress-accordion-disabled" hideFeedback />

View File

@@ -0,0 +1,74 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Progress Tabs`,
}
# {metadata.title}
A component that renders tabbed content, specifically designed for implementing multi-step tasks.
In this guide, you'll learn how to use the Progress Tabs component.
<ComponentExample name="progress-tabs-demo" />
## Usage
```tsx
import { ProgressTabs } from "@medusajs/ui"
```
```tsx
<ProgressTabs defaultValue="general">
<ProgressTabs.List>
<ProgressTabs.Trigger value="general">
General
</ProgressTabs.Trigger>
<ProgressTabs.Trigger value="shipping">
Shipping
</ProgressTabs.Trigger>
<ProgressTabs.Trigger value="payment">
Payment
</ProgressTabs.Trigger>
</ProgressTabs.List>
<ProgressTabs.Content value="general">
{/* Content */}
</ProgressTabs.Content>
<ProgressTabs.Content value="shipping">
{/* Content */}
</ProgressTabs.Content>
<ProgressTabs.Content value="payment">
{/* Content */}
</ProgressTabs.Content>
</ProgressTabs>
```
---
## API Reference
<ComponentReference mainComponent="ProgressTabs" componentsToShow={[
"ProgressTabs",
"ProgressTabs.Trigger",
]} />
---
## Examples
### Set Status Indicator
<ComponentExample name="progress-tabs-status" />
### Controlled Active Tab
<ComponentExample name="progress-tabs-controlled" />
### Disabled Tab
<ComponentExample name="progress-tabs-disabled" hideFeedback />

View File

@@ -0,0 +1,66 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Prompt`,
}
# {metadata.title}
A component that displays a dialog prompting the user for their approval. It's useful when confirming destructive actions.
<Note>
This component is useful if you want to control the prompt's content, format, and design. For a simpler approach that follows Medusa's prompt format, refer to the [usePrompt hook](../../hooks/use-prompt/page.mdx).
</Note>
In this guide, you'll learn how to use the Prompt component.
<ComponentExample name="prompt-demo" />
## Usage
```tsx
import { Prompt } from "@medusajs/ui"
```
```tsx
<Prompt>
<Prompt.Trigger>Trigger</Prompt.Trigger>
<Prompt.Content>
<Prompt.Header>
<Prompt.Title>Title</Prompt.Title>
<Prompt.Description>Description</Prompt.Description>
</Prompt.Header>
<Prompt.Footer>
<Prompt.Cancel>Cancel</Prompt.Cancel>
<Prompt.Action>Delete</Prompt.Action>
</Prompt.Footer>
</Prompt.Content>
</Prompt>
```
---
## API Reference
<ComponentReference mainComponent="Prompt" componentsToShow={[
"Prompt",
"Prompt.Header",
"Prompt.Footer"
]} />
---
## Examples
### Confirmation Prompt Variant
The `confirmation` variant is useful when confirming an operation that isn't destructive, such as deleting an item.
<ComponentExample name="prompt-confirmation" hideFeedback />

View File

@@ -0,0 +1,60 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Radio Group`,
}
# {metadata.title}
A component that renders a group of radio buttons using Medusa's design system.
In this guide, you'll learn how to use the Radio Group component.
<ComponentExample name="radio-group-demo" />
## Usage
```tsx
import { RadioGroup } from "@medusajs/ui"
```
```tsx
<RadioGroup>
<RadioGroup.Item value="1" id="radio_1" />
<RadioGroup.Item value="2" id="radio_2" />
<RadioGroup.Item value="3" id="radio_3" />
</RadioGroup>
```
---
## API Reference
<ComponentReference mainComponent="RadioGroup" />
---
## Examples
### Radio Group with Descriptions
<ComponentExample name="radio-group-descriptions" />
### Controlled Radio Group
<ComponentExample name="radio-group-controlled" />
### Radio Group with a Disabled Item
<ComponentExample name="radio-group-disabled" />
---
## Radio Choice Box
The `RadioGroup.ChoiceBox` component allows you to show a group of radio buttons, each in a box with a label and description.
<ComponentExample name="radio-group-choicebox" hideFeedback />
{/* TODO add API reference */}

View File

@@ -1,15 +1,24 @@
---
title: "Select"
description: "Displays a list of options for the user to pick from—triggered by a button."
component: true
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Select`,
}
# {metadata.title}
A component that displays a select form input using Medusa's design system.
In this guide, you'll learn how to use the Select component.
<ComponentExample name="select-demo" />
## Usage
---
```tsx
import { Select } from "@medusajs/ui"
```
@@ -29,10 +38,10 @@ import { Select } from "@medusajs/ui"
</Select>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Select" componentsToShow={[
"Select",
"Select.Trigger",
@@ -43,26 +52,26 @@ import { Select } from "@medusajs/ui"
"Select.Content"
]} />
## Examples
---
### Small
## Examples
### Small Select
<ComponentExample name="select-small" />
### Item-Aligned Position
### Select Item-Aligned Position
<ComponentExample name="select-item-aligned" />
### Disabled
### Disabled Select
<ComponentExample name="select-disabled" />
### Grouped Items
### Select with Grouped Items
<ComponentExample name="select-grouped-items" />
### Controlled
### Controlled Select
<ComponentExample name="select-controlled" />
<ComponentExample name="select-controlled" hideFeedback />

View File

@@ -0,0 +1,38 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Status Badge`,
}
# {metadata.title}
A component that displays the status of an item in a badge style. It's useful to indicate states like "Active", "Published", or "Draft".
In this guide, you'll learn how to use the Status Badge component.
<ComponentExample name="status-badge-demo" />
## Usage
```tsx
import { StatusBadge } from "@medusajs/ui"
```
```tsx
<StatusBadge color="green">Active</StatusBadge>
```
---
## API Reference
<ComponentReference mainComponent="StatusBadge" />
---
## Examples
### Status Badge Colors
<ComponentExample name="status-badge-all-colors" hideFeedback />

View File

@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Switch`,
}
# {metadata.title}
A component for toggling between two states, typically on and off. It's essentially a checkbox in the form of a switch.
In this guide, you'll learn how to use the Switch component.
<ComponentExample name="switch-demo" />
## Usage
```tsx
import { Switch } from "@medusajs/ui"
```
```tsx
<Switch />
```
---
## API Reference
<ComponentReference mainComponent="Switch" />
---
## Examples
### Switch Sizes
<ComponentExample name="switch-all-sizes" />
### Controlled Switch
<ComponentExample name="switch-controlled" hideFeedback />
### Disabled Switch
<ComponentExample name="switch-disabled" />

View File

@@ -1,11 +1,23 @@
---
title: "Table"
description: "A Table component for displaying data."
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Table`,
}
# {metadata.title}
A component that displays data in a structured table format.
In this guide, you'll learn how to use the Table component.
<Note>
If you're looking to add a table in your Medusa Admin Extensions with features like pagination and filters, refer to the [DataTable](/components/data-table) component instead.
If you're looking to add a table to your Medusa Admin customizations with advanced features like filters, search, sorting, and bulk actions, refer to the [DataTable](../data-table/page.mdx) component instead.
</Note>
@@ -13,8 +25,6 @@ If you're looking to add a table in your Medusa Admin Extensions with features l
## Usage
---
```tsx
import { Table } from "@medusajs/ui"
```
@@ -38,19 +48,19 @@ import { Table } from "@medusajs/ui"
</Table>
```
## API Reference
---
## API Reference
<ComponentReference mainComponent="Table" componentsToShow={[
"Table",
"Table.Pagination"
]} />
## Examples
---
## Examples
### Table with Pagination
<ComponentExample name="table-pagination" />
<ComponentExample name="table-pagination" hideFeedback />

View File

@@ -0,0 +1,61 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Tabs`,
}
# {metadata.title}
A component that displays tabbed content.
In this guide, you'll learn how to use the Tabs component.
<ComponentExample name="tabs-demo" />
## Usage
```tsx
import { Tabs } from "@medusajs/ui"
```
```tsx
<Tabs>
<Tabs.List>
<Tabs.Trigger value="1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="1">Panel 1</Tabs.Content>
<Tabs.Content value="2">Panel 2</Tabs.Content>
<Tabs.Content value="3">Panel 3</Tabs.Content>
</Tabs>
```
---
## API Reference
<ComponentReference mainComponent="Tabs" />
---
## Examples
### Controlled Tabs
<ComponentExample name="tabs-controlled" />
### Tabs with a Disabled Tab
<ComponentExample name="tabs-disabled" />
### Tabs with Icons
<ComponentExample name="tabs-icons" />
### Vertical Tabs
The `orientation` prop doesn't change the layout of the tabs, but it allows you to navigate between the tabs using the up and down arrow keys. You'll need to manually style the tabs vertically.
<ComponentExample name="tabs-vertical" hideFeedback />

View File

@@ -0,0 +1,50 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Text`,
}
# {metadata.title}
A component that displays text using the typography styles from Medusa's design system.
In this guide, you'll learn how to use the Text component.
<ComponentExample name="text-demo" />
## Usage
```tsx
import { Text } from "@medusajs/ui"
```
```tsx
<Text>Text</Text>
```
---
## API Reference
<ComponentReference mainComponent="Text" />
---
## Examples
### Text Sizes
<ComponentExample name="text-sizes" />
### Text Weights
<ComponentExample name="text-weights" />
### Text Fonts
<ComponentExample name="text-fonts" />
### Text Leading
<ComponentExample name="text-leading" hideFeedback />

View File

@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Textarea`,
}
# {metadata.title}
A component that displays a textarea field using Medusa's design system.
In this guide, you'll learn how to use the Textarea component.
<ComponentExample name="textarea-demo" />
## Usage
```tsx
import { Textarea } from "@medusajs/ui"
```
```tsx
<Textarea />
```
---
## API Reference
<ComponentReference mainComponent="Textarea" />
---
## Examples
### Controlled Textarea
<ComponentExample name="textarea-controlled" />
### Disabled Textarea
<ComponentExample name="textarea-disabled" hideFeedback />

View File

@@ -0,0 +1,119 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Toaster and Toast Messages`,
}
# {metadata.title}
A component and utility for displaying brief messages to users, typically used for notifications or alerts. Toast messages appear momentarily on top of the application UI.
You can display multiple toast messages at once, and they will be stacked neatly.
In this guide, you'll learn how to use the Toaster component.
<ComponentExample name="toaster-demo" />
## Usage
First, import the `toast` utility and `Toaster` component from `@medusajs/ui`:
```tsx
import { Toaster, toast } from "@medusajs/ui"
```
Then, add the `Toaster` component somewhere in your tree hierarchy. For example, in your main application layout:
```tsx highlights={[["6"]]}
export default function AppLayout({ children }) {
return (
<html>
<body>
{children}
<Toaster />
</body>
</html>
)
}
```
Finally, use the `toast` utility in your components to display a toast message:
```tsx highlights={[["5", "info", "Display an informational message"]]}
export default function MyComponent() {
return (
<Button
onClick={() =>
toast.info("Toast title", {
description: "Toast body",
})
}
>
Trigger
</Button>
)
}
```
---
## API Reference
### Toast Utility Functions
The `toast` utility has the following functions to display different variants of toast messages:
- `info`: Display a toast message with an informational style.
- `error`: Display a toast message with an error style.
- `success`: Display a toast message with a success style.
- `warning`: Display a toast message with a warning style.
- `loading`: Display a toast message with a loading style.
Each of these functions accept two parameters:
1. A string indicating the title of the toast.
2. An object of [Toast component props](#toast-props).
### Toast Props
<ComponentReference mainComponent="Toast" />
### Toaster Props
<ComponentReference mainComponent="Toaster" />
---
## Examples
### Toast Variants
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-all-variants" />
### Dismissable Toast
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-dismiss" />
### Toast with Action
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-with-action" hideFeedback />

View File

@@ -0,0 +1,59 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Tooltip`,
}
# {metadata.title}
A component that displays a pop-up with additional information when hovering over or focusing on an element.
In this guide, you'll learn how to use the Tooltip component.
<ComponentExample name="tooltip-demo" />
## Usage
```tsx
import { Tooltip } from "@medusajs/ui"
```
```tsx
<Tooltip content="Tooltip content">Trigger</Tooltip>
```
---
## API Reference
<ComponentReference mainComponent="Tooltip" />
---
## Usage Outside Medusa Admin with TooltipProvider
If you're using the `Tooltip` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree:
```tsx
<TooltipProvider>
<Tooltip content="Tooltip content">Trigger</Tooltip>
</TooltipProvider>
```
### TooltipProvider Reference
<ComponentReference mainComponent="TooltipProvider" />
---
## Examples
### Changing Tooltip Side
<ComponentExample name="tooltip-sides" />
### Set Tooltip Max Width
<ComponentExample name="tooltip-maxwidth" />

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -3,32 +3,38 @@
@tailwind utilities;
@layer base {
html {
@apply antialiased;
text-rendering: optimizeLegibility;
}
.html {
@apply text-medusa-fg-base;
body {
@apply overflow-x-hidden;
}
*::selection {
@apply bg-medusa-bg-highlight;
}
pre *::selection {
@apply !bg-medusa-contrast-bg-highlight;
*:not(.code-block-elm) {
scrollbar-color: var(--docs-border-base) var(--docs-bg-base);
}
* {
scrollbar-color: var(--docs-border-base) var(--docs-bg-base);
.code-block-elm {
scrollbar-color: var(--docs-contrast-border-base) transparent;
}
aside * {
scrollbar-color: var(--docs-border-base) var(--docs-bg-subtle);
}
body {
@apply text-ui-fg-base;
body[data-modal="opened"] {
@apply !overflow-hidden;
}
.text-wrap {
text-wrap: wrap;
}
/* Hack to hide navbar / toc when some components like prompt are opened. */
@@ -36,14 +42,6 @@
body[data-scroll-locked] .z-10 {
z-index: 0 !important;
}
body[data-modal="opened"] {
@apply !overflow-hidden text-ui-fg-base;
}
.text-wrap {
text-wrap: wrap;
}
}
.grecaptcha-badge {

View File

@@ -0,0 +1,59 @@
import { HookValues } from "@/components/HookValues"
import { ComponentReference } from "@/components/ComponentReference"
import { ComponentExample } from "@/components/ComponentExample"
export const metadata = {
title: `usePrompt`,
}
# {metadata.title}
This hook returns a function that prompts the user to confirm an action.
In this guide, you'll learn how to use the `usePrompt` hook.
<ComponentExample name="use-prompt-demo" />
## Usage
```tsx
import { usePrompt } from "@medusajs/ui"
```
```tsx
const dialog = usePrompt()
const actionFunction = async () => {
const confirmed = await dialog({
title: "Are you sure?",
description: "Please confirm this action",
})
}
```
---
## API Reference
### usePrompt Return Value
<HookValues hook="usePromptReturn" />
### Returned Dialog Parameters
The dialog function returned by `usePrompt` accepts an object having the following properties:
<ComponentReference mainComponent="RenderPrompt" />
### Dialog Return Value
The dialog function returns a Promise that resolves to a boolean indicating whether the user confirmed the action.
---
## Examples
### Prompt with Verification Text
<ComponentExample name="use-prompt-verification" hideFeedback />

View File

@@ -0,0 +1,38 @@
import { HookValues } from "@/components/HookValues"
import { ComponentExample } from "@/components/ComponentExample"
export const metadata = {
title: `useToggleState`,
}
# {metadata.title}
This hook tracks a boolean value and toggles between its two states.
This guide explains how to use the `useToggleState` hook.
For example, you can use this hook to display a checkbox or a [Switch](../../components/switch/page.mdx) that toggles a [Focus Modal](../../components/focus-modal/page.mdx).
<ComponentExample name="use-toggle-state-demo" hideFeedback />
## Usage
```tsx
import { useToggleState } from "@medusajs/ui"
```
```tsx
const [state, open, close, toggle] = useToggleState()
```
---
## API Reference
### useToggleState Parameters
<HookValues hook="useToggleStateProps" />
### useToggleState Return Value
<HookValues hook="useToggleStateReturn" hideFeedback />

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1,80 @@
import { IconSearch } from "@/components/IconSearch"
import { ComponentExample } from "@/components/ComponentExample"
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `Icons`,
}
# {metadata.title}
In this guide, you'll learn how to install and use Medusa UI icons.
The Medusa UI icons package is a collection of React icon components from Medusa's design system. You can use these icons either in your Medusa Admin customizations, or in your standalone React projects.
## Installation
The Medusa UI icons package is available by default in your Medusa application, so you can use them in your Medusa Admin customizations without any additional installation steps.
### Installation in Standalone Projects
<Prerequisites
items={[
{
text: "React 16.8+ installed in your project.",
link: "https://react.dev/",
}
]}
/>
To install the Medusa UI icons package in your React-based project, run the following command:
```bash npm2yarn
npm install @medusajs/icons
```
---
## Usage
You can import and use the icons in your React components:
```tsx
import { Sun } from "@medusajs/icons"
export default function Component() {
return (
<Sun />
)
}
```
---
## Icons List
Below is a list of all the icons available in the Medusa UI design system. Click on any icon to copy its component name.
<IconSearch />
---
## Icon Props
Icons accept all props that an `svg` element accepts.
### Icon Color
By default, outline icons' stroke color and solid icon's fill color are set to `currentColor`.
You can set a different color by passing the `color` prop.
<ComponentExample name="icon-color" />
You can also use a CSS class by passing the `className` prop.
<ComponentExample name="icon-color-classes" />
### Icon Size
All icon's width and height are `20px` and it's not possible to change them.

View File

@@ -0,0 +1,50 @@
export const metadata = {
title: `Install Medusa UI for Medusa Admin Customizations`,
}
# {metadata.title}
In this guide, you'll learn how to use Medusa UI for building Medusa Admin customizations.
## Use Medusa UI in Medusa Admin
The `@medusajs/ui` and `@medusajs/icons` packages are already installed as dependencies of the `@medusajs/admin-sdk` package in your Medusa project. They're installed by default in your Medusa plugins as well.
So, you can import the packages and use them in your Medusa Admin customizations without any additional installation steps.
For example, to use the UI and icon packages in a UI route:
```tsx title="src/admin/routes/custom/page.tsx"
import { defineRouteConfig } from "@medusajs/admin-sdk"
import { ChatBubbleLeftRight } from "@medusajs/icons"
import { Container, Heading } from "@medusajs/ui"
const CustomPage = () => {
return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading level="h2">This is my custom route</Heading>
</div>
</Container>
)
}
export const config = defineRouteConfig({
label: "Custom Route",
icon: ChatBubbleLeftRight,
})
export default CustomPage
```
In this example, you use the [Container](../../components/container/page.mdx) and [Heading](../../components/heading/page.mdx) components in the UI route. You also use the `ChatBubbleLeftRight` icon from the [Icons package](../../icons/overview/page.mdx) for the UI route's sidebar item.
---
## Related Resources
If you're building Medusa Admin customizations, check out the following documentation guides:
- [Admin Widgets](!docs!/learn/fundamentals/admin/widgets): Insert custom components into existing Medusa Admin pages.
- [Admin UI Routes](!docs!/learn/fundamentals/admin/ui-routes): Add new pages to the Medusa Admin.
- [Admin Components & Layouts](!resources!/admin-components): Use Medusa UI to implement common Medusa Admin components and layouts for a consistent design in your customizations.

View File

@@ -1,23 +1,31 @@
---
title: "Medusa UI Installation in Standalone Projects"
description: "Learn how to install and use Medusa UI in a standalone project."
---
import Feedback from "@/components/Feedback"
import { Note } from "docs-ui"
Medusa UI is a React UI library that, while intended for usage within Medusa projects, can also be used in any React project.
export const metadata = {
title: `Install Medusa UI in Standalone Projects`,
}
# {metadata.title}
In this guide, you'll learn how to install and use Medusa UI in a standalone project.
Medusa UI is a React UI library that, while intended for use within Medusa projects, can also be used in any React project.
<Note>
The icons package is installed independently from Medusa UI. Learn how to install it in the [Icons](../icons/overview.mdx) guide.
The icons package is installed independently from Medusa UI. Learn how to install it in the [Icons](../../icons/overview/page.mdx) guide.
</Note>
---
## Medusa UI Compatibility
To use Medusa UI in your standalone project, you must have:
- React 18+ installed. Most React-based frameworks and libraries, such as Next.js and Vite, are compatible with this requirement.
- [Tailwind CSS](https://v3.tailwindcss.com/) installed. The components in Medusa UI are styled using Tailwind CSS, so you will need to install it in your project as well.
- Medusa UI was built with Tailwind CSS v3, but it may generally support v4 as well.
- [Tailwind CSS](https://v3.tailwindcss.com/) installed. The components in Medusa UI are styled using Tailwind CSS, so you'll need to install it in your project as well.
- Medusa UI was built with Tailwind CSS v3, but it may also support v4.
---
@@ -25,17 +33,21 @@ To use Medusa UI in your standalone project, you must have:
In your standalone project, install the Medusa UI package with the following command:
<PackageInstall packageName="@medusajs/ui" />
```bash npm2yarn
npm install @medusajs/ui
```
---
## Step 2: Install UI Presets
Medusa UI customizes Tailwind CSS classes to implement its design system. So, you must also install the Medusa UI preset package.
Medusa UI customizes Tailwind CSS classes to implement its design system, so you must also install the Medusa UI preset package.
To install the Medusa UI preset, run the following command:
<PackageInstall packageName="@medusajs/ui-preset" devDependency />
```bash npm2yarn
npm install @medusajs/ui-preset --save-dev
```
---
@@ -50,7 +62,7 @@ In Tailwind CSS v3, which is the recommended version to use with Medusa UI, you
1. Add the Medusa UI preset to the `presets` array.
2. Ensure that the `content` field includes the path to the Medusa UI package.
```js title="tailwind.config.js"
```js title="tailwind.config.js" highlights={[["5"]]}
module.exports = {
presets: [require("@medusajs/ui-preset")],
content: [
@@ -63,7 +75,12 @@ module.exports = {
If your project is in a monorepo, you'll need to resolve the path to the `@medusajs/ui` package from the monorepo root:
```tsx title="tailwind.config.js"
export const monorepoHighlights = [
["3", "uiPath", "Resolve the UI package path from `node_modules`."],
["13"]
]
```tsx title="tailwind.config.js" highlights={monorepoHighlights}
const path = require("path")
const uiPath = path.resolve(
@@ -87,7 +104,7 @@ module.exports = {
Medusa UI isn't officially compatible with Tailwind CSS v4 yet, so use it with caution.
In your CSS file that imports Tailwind CSS, add the following `@config` and `@source` directives:
In your CSS file that imports Tailwind CSS, add the following `@import`, `@config`, and `@source` directives:
```css
@import "tailwindcss";
@@ -95,7 +112,7 @@ In your CSS file that imports Tailwind CSS, add the following `@config` and `@so
@config "@medusajs/ui-preset";
```
This will explicitly include the Medusa UI preset and its components in your Tailwind CSS build, and will apply the preset styles to your project.
This will explicitly include the Medusa UI preset and its components in your Tailwind CSS build and apply the preset styles to your project.
---
@@ -121,9 +138,9 @@ Refer to the documentation of each component to learn about its props and usage.
## Update UI Packages in Standalone Projects
Medusa's design-system packages, including `@medusajs/ui` and `@medusajs/ui-preset`, are versioned independently from other `@medusajs/*` packages. However, they're still released as part of Medusa's releases.
Medusa's design system packages, including `@medusajs/ui` and `@medusajs/ui-preset`, are versioned independently from other `@medusajs/*` packages. However, they're still released as part of Medusa's releases.
So, to find latest updates and breaking changes to any of these packages, refer to the [release notes in the Medusa GitHub repository](https://github.com/medusajs/medusa/releases).
So, to find the latest updates and breaking changes to any of these packages, refer to the [release notes in the Medusa GitHub repository](https://github.com/medusajs/medusa/releases).
To update these packages in your standalone project, update their version in your `package.json` file and re-install dependencies. For example:

View File

@@ -1,19 +1,22 @@
import type { Metadata } from "next"
import { Providers } from "@/providers"
import { siteConfig } from "@/config/site"
import "../styles/globals.css"
import { BareboneLayout, InjectedMDXData, TightLayout } from "docs-ui"
import { Inter, Roboto_Mono } from "next/font/google"
import Providers from "@/providers"
import "./globals.css"
import { BareboneLayout, TightLayout } from "docs-ui"
import { config } from "@/config"
import clsx from "clsx"
import Footer from "@/components/Footer"
const ogImage =
"https://res.cloudinary.com/dza7lstvk/image/upload/v1732200992/Medusa%20Resources/opengraph-image_daq6nx.jpg"
export const metadata: Metadata = {
title: siteConfig.name,
description: siteConfig.description,
title: {
template: `%s - ${config.titleSuffix}`,
default: config.titleSuffix || "",
},
description:
"Learn about Medusa UI, A React package with primitives for building Medusa applications.",
metadataBase: new URL(
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
),
@@ -39,13 +42,13 @@ export const metadata: Metadata = {
},
}
const inter = Inter({
export const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
weight: ["400", "500"],
})
const robotoMono = Roboto_Mono({
export const robotoMono = Roboto_Mono({
subsets: ["latin"],
variable: "--font-roboto-mono",
})
@@ -60,18 +63,8 @@ export default function RootLayout({
htmlClassName={clsx(inter.variable, robotoMono.variable)}
gaId={process.env.NEXT_PUBLIC_GA_ID}
>
<TightLayout ProvidersComponent={Providers}>
<TightLayout ProvidersComponent={Providers} footerComponent={<Footer />}>
{children}
{/*
Since we use contentlayer in this project, we can't use a Recma plugin.
This is a workaround until we move from contentlayer.
*/}
<InjectedMDXData
frontmatter={{
generate_toc: true,
}}
toc={[]}
/>
</TightLayout>
</BareboneLayout>
)

View File

@@ -7,7 +7,7 @@ import path from "path"
import { addUrlToRelativeLink } from "remark-rehype-plugins"
import type { Plugin } from "unified"
import * as Icons from "@medusajs/icons"
import * as HookValues from "@/registries/hook-values"
import * as HookValues from "@/specs/hook-values"
import { colors as allColors } from "@/config/colors"
type Params = {
@@ -18,12 +18,10 @@ export async function GET(req: NextRequest, { params }: Params) {
const { slug = ["/"] } = await params
// keep this so that Vercel keeps the files in deployment
const basePath = path.join(process.cwd(), "src", "content", "docs")
const examplesPath = path.join(process.cwd(), "src", "examples")
const specsPath = path.join(process.cwd(), "src", "specs")
const fileName = slug.length === 1 ? "index" : slug.pop() || "index"
const filePath = path.join(basePath, ...slug, `${fileName}.mdx`)
const basePath = path.join(process.cwd(), "app")
const componentSpecsPath = path.join(process.cwd(), "specs", "components")
const examplesPath = path.join(process.cwd(), "specs", "examples")
const filePath = path.join(basePath, ...slug, "page.mdx")
if (!existsSync(filePath)) {
return notFound()
@@ -31,7 +29,7 @@ export async function GET(req: NextRequest, { params }: Params) {
const cleanMdContent = await getCleanMd_(
filePath,
{ examplesPath, specsPath },
{ examplesPath, specsPath: componentSpecsPath },
{
after: [
[addUrlToRelativeLink, { url: process.env.NEXT_PUBLIC_BASE_URL }],

View File

@@ -1,3 +1,7 @@
---
hide_content_menu: true
---
import { CardList, H1 } from "docs-ui"
import {
BookOpen,

44
www/apps/ui/app/page.mdx Normal file
View File

@@ -0,0 +1,44 @@
import { FigmaCard } from "@/components/FigmaCard"
export const metadata = {
title: `Medusa UI Documentation`,
}
# {metadata.title}
Welcome to Medusa UI, a React implementation of the Medusa design system.
Medusa UI is a collection of components, hooks, utility functions, icons, and [Tailwind CSS](https://tailwindcss.com/) classes that can be used to build
a consistent user interface across the Medusa Admin and client applications.
<FigmaCard />
---
## Packages
Medusa UI is split into multiple packages. Each package is published to npm
and can be installed separately.
- `@medusajs/ui` - React components, hooks, and utility functions used
in Medusa UI.
- `@medusajs/ui-preset` - Tailwind CSS preset containing all the classes
used in Medusa UI.
- `@medusajs/icons` - Icons used in Medusa UI.
Learn how to install and use these packages either for [Medusa Admin](./installation/medusa-admin-extension/page.mdx) customizations or a [standalone project](./installation/standalone-project/page.mdx).
---
## How Medusa UI is Built
At its core, Medusa UI is a styled and slightly opinionated implementation of [Radix Primitives](https://www.radix-ui.com/primitives).
Our team has also referenced the fantastic [shadcn/ui](https://ui.shadcn.com/) for inspiration in certain implementations.
Our team strongly believes in keeping the components simple and
composable, much like Medusa's foundation. This allows you to build whatever you need.
Our team has tried to avoid overloading
the component API and, instead, has leveraged the native HTML API, which gets implemented
and respected accordingly, and passed to the underlying elements.

View File

@@ -1,14 +1,13 @@
import { retrieveMdxPages } from "build-scripts"
import type { MetadataRoute } from "next"
import path from "path"
import { siteConfig } from "../config/site"
import { basePathUrl } from "../lib/base-path-url"
import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
export default function sitemap(): MetadataRoute.Sitemap {
return retrieveMdxPages({
basePath: path.resolve("src", "content", "docs"),
testFileName: false,
basePath: path.resolve("app"),
}).map((filePath) => ({
url: `${siteConfig.baseUrl}${basePathUrl(filePath)}`,
url: `${config.baseUrl}${basePathUrl(filePath)}`,
}))
}

View File

@@ -0,0 +1,92 @@
export const metadata = {
title: `clx`,
}
# {metadata.title}
`clx` is a utility function that adds class names to your components, with support for conditional classes and merging Tailwind CSS classes.
In this guide, you'll learn how to use the `clx` utility function.
## Usage
The `clx` function is built using [clsx](https://www.npmjs.com/package/clsx) and [tw-merge](https://www.npmjs.com/package/tw-merge). It is intended to be used with [Tailwind CSS](https://tailwindcss.com/) to efficiently add classes to your components.
`clx` is useful for:
- Conditionally apply classes based on props or state. For example, you can apply the `hidden` class if a component's `open` state variable is `false`.
- Merge multiple strings into a single class name string. For example, you can apply class names to the component, and allow passing additional class names as props.
- Override conflicting Tailwind CSS classes. For example, if you specify a `p-2` class name on your component, and you pass a `p-4` class name as a prop, the `p-4` class will take precedence.
- The last class name specified will take precedence over any previous class names.
For example:
```tsx
import { clx } from "@medusajs/ui"
type BoxProps = {
className?: string
children: React.ReactNode
mt: "sm" | "md" | "lg"
}
const Box = ({ className, children, mt }: BoxProps) => {
return (
<div
className={clx(
"flex items-center justify-center",
{
"mt-4": mt === "sm",
"mt-8": mt === "md",
"mt-12": mt === "lg",
},
className
)}
>
{children}
</div>
)
}
```
In the above example, you use `clx` to:
- Apply a base style.
- Apply a margin top that depends on the `mt` prop.
- Add class names passed as a prop.
`clx` ensures that Tailwind CSS classes are merged without style conflicts.
---
## API Reference
### clx Parameters
`clx` accepts any number of arguments, each of them can be of the following types:
- `string`: A string of class names to apply.
```tsx
clx("flex items-center justify-between")
```
- `Record<string, boolean>`: An object whose keys are the class names to apply, and the values are booleans indicating whether to apply the class names.
```tsx
clx({
"flex items-center justify-between": isFlex,
})
```
- `Array`: An array of strings or objects to apply.
```tsx
clx([
"flex items-center justify-between",
{
"hidden": isHidden,
},
])

View File

@@ -1,9 +1,10 @@
"use client"
import React from "react"
import { CopyButton, useColorMode } from "docs-ui"
import { colors as allColors } from "../config/colors"
import { CopyButton, H2, Hr, MarkdownContent, useColorMode } from "docs-ui"
import { colors as allColors } from "@/config/colors"
import { clx } from "@medusajs/ui"
import slugify from "slugify"
type Color = {
name: string
@@ -11,21 +12,10 @@ type Color = {
}
type ColorsTable = {
backgrounds: Color[]
foregrounds: Color[]
borders: Color[]
buttons: Color[]
code: Color[]
tags: Color[]
}
const PREFIXES: { [k: string]: keyof ColorsTable } = {
"--bg": "backgrounds",
"--fg": "foregrounds",
"--border": "borders",
"--button": "buttons",
"--code": "code",
"--tag": "tags",
[k: string]: {
description?: string
colors: Color[]
}
}
interface ColorBlockProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -99,7 +89,7 @@ const cssVarToTailwindClass = (name: string) => {
return name.replace("-", "border-ui")
}
if (name.startsWith("--tag") || name.startsWith("--code")) {
if (name.startsWith("--tag")) {
if (name.includes("bg")) {
return name.replace("-", "bg-ui")
}
@@ -111,49 +101,78 @@ const cssVarToTailwindClass = (name: string) => {
}
}
if (name.startsWith("--contrast") || name.startsWith("--alpha")) {
return name.replace("-", "bg-ui")
}
return name
}
const transformPrefixToTitle = (prefix: string) => {
switch (prefix) {
case "bg":
return "Background"
case "fg":
return "Foreground"
default:
return prefix.charAt(0).toUpperCase() + prefix.slice(1)
}
}
const getDescriptionOfSection = (title: string) => {
switch (title) {
case "Alpha":
case "Contrast":
return "These colors can be used for foreground (using `text-` prefix), background (using `bg-` prefix), and border (using `border-` prefix) elements."
default:
return ""
}
}
const Colors = () => {
const { colorMode } = useColorMode()
const colors: ColorsTable = {
backgrounds: [],
foregrounds: [],
borders: [],
buttons: [],
code: [],
tags: [],
}
const colors: ColorsTable = {}
for (const [tag, value] of Object.entries(allColors[colorMode])) {
const prefix = tag.match(/(--[a-zA-Z]+)/gi)
if (prefix && Object.keys(PREFIXES).includes(prefix[0])) {
if (!tag.includes("gradient")) {
colors[PREFIXES[prefix[0]]].push({
name: tag,
code: value as string,
})
const prefixMatch = tag.match(/(--[a-zA-Z]+)/gi)
if (!prefixMatch) {
return
}
const prefix = transformPrefixToTitle(prefixMatch[0].replace("--", ""))
if (!colors[prefix]) {
colors[prefix] = {
description: getDescriptionOfSection(prefix),
colors: [],
}
}
colors[prefix].colors.push({
name: tag,
code: value as string,
})
}
for (const [, section] of Object.entries(colors)) {
section.sort((a, b) => {
const sortedSections = Object.entries(colors).sort((a, b) => {
return a[0].localeCompare(b[0])
})
for (const [, sectionData] of sortedSections) {
sectionData.colors.sort((a, b) => {
return a.name < b.name ? -1 : 1
})
}
return (
<div>
{Object.entries(colors).map(([section, colors]) => (
{sortedSections.map(([section, sectionData], index) => (
<div className="mb-16" key={`colours-section-${section}`}>
<h2 className="h2-docs mb-4 mt-10 text-medusa-fg-base">
{section.charAt(0).toUpperCase() + section.slice(1)}
</h2>
<hr className="mb-4" />
<H2 id={slugify(section)}>{section}</H2>
{sectionData.description && (
<MarkdownContent>{sectionData.description}</MarkdownContent>
)}
<div className="xs:grid-cols-2 mb-8 grid grid-cols-1 gap-4 gap-y-10 sm:grid-cols-3 ">
{colors.map((colour) => (
{sectionData.colors.map((colour) => (
<CopyButton
text={cssVarToTailwindClass(colour.name)}
key={`colours-section-${section}-${colour.name}`}
@@ -162,6 +181,7 @@ const Colors = () => {
</CopyButton>
))}
</div>
{index !== sortedSections.length - 1 && <Hr />}
</div>
))}
</div>

View File

@@ -5,18 +5,20 @@ import { Tabs, clx } from "@medusajs/ui"
import { CodeBlock } from "docs-ui"
import * as React from "react"
import { Feedback } from "@/components/feedback"
import { ExampleRegistry } from "@/registries/example-registry"
import Feedback from "@/components/Feedback"
import { ExampleRegistry } from "@/specs/examples.mjs"
interface ComponentExampleProps extends React.HTMLAttributes<HTMLDivElement> {
name: string
disableCenterAlignPreview?: boolean
hideFeedback?: boolean
}
export function ComponentExample({
children,
name,
disableCenterAlignPreview = false,
hideFeedback = false,
...props
}: ComponentExampleProps) {
const Preview = React.useMemo(() => {
@@ -30,7 +32,9 @@ export function ComponentExample({
}, [name])
const CodeElement = children as React.ReactElement
const Code = (CodeElement.props as Record<string, string>).code
const Code = JSON.parse(
(CodeElement.props as Record<string, string>).codeLinesJSON
).join("\n")
return (
<div className="relative my-4 flex flex-col space-y-2" {...props}>
@@ -70,10 +74,13 @@ export function ComponentExample({
</Tabs.Content>
</div>
</Tabs>
<Feedback
title={`example ${name}`}
question="Was this example helpful?"
/>
{!hideFeedback && (
<Feedback
title={`example ${name}`}
question="Was this example helpful?"
showDottedSeparator={false}
/>
)}
</div>
)
}

View File

@@ -1,23 +1,25 @@
import { Documentation } from "react-docgen"
import { Suspense } from "react"
import { Spinner } from "@medusajs/icons"
import { PropTable } from "./props-table"
import { PropTable } from "../PropsTable"
import { Container } from "@medusajs/ui"
import { Feedback } from "./feedback"
import Feedback from "../Feedback"
import { H3, MarkdownContent } from "docs-ui"
import { components } from "./mdx-components"
import MDXComponents from "../MDXComponents"
import slugify from "slugify"
type ComponentReferenceProps = {
mainComponent: string
componentsToShow?: string[]
specsSrc?: string
hideFeedback?: boolean
}
const ComponentReference = ({
mainComponent,
componentsToShow = [mainComponent],
specsSrc,
hideFeedback = false,
}: ComponentReferenceProps) => {
if (!specsSrc) {
return <></>
@@ -53,7 +55,7 @@ const ComponentReference = ({
<H3 id={componentSlug}>{componentName}</H3>
)}
{componentSpec.description && (
<MarkdownContent components={components}>
<MarkdownContent components={MDXComponents}>
{componentSpec.description}
</MarkdownContent>
)}
@@ -70,10 +72,13 @@ const ComponentReference = ({
<PropTable props={componentSpec.props!} />
</Suspense>
</Container>
<Feedback
title={`props of ${component}`}
question="Was this helpful?"
/>
{!hideFeedback && (
<Feedback
title={`props of ${component}`}
question="Was this helpful?"
showDottedSeparator={false}
/>
)}
</>
)}
</>

View File

@@ -0,0 +1,37 @@
"use client"
import { EditButton as UiEditButton } from "docs-ui"
import { usePathname } from "next/navigation"
import { useCallback, useEffect, useState } from "react"
const EditButton = () => {
const pathname = usePathname()
const [editDate, setEditDate] = useState<string | undefined>()
const loadEditDate = useCallback(async () => {
const generatedEditDates = (await import("../../generated/edit-dates.mjs"))
.generatedEditDates
setEditDate(
(generatedEditDates as Record<string, string>)[
`app${pathname.replace(/\/$/, "")}/page.mdx`
]
)
}, [pathname])
useEffect(() => {
void loadEditDate()
}, [loadEditDate])
if (!editDate) {
return <></>
}
return (
<UiEditButton
filePath={`/www/apps/ui/app${pathname.replace(/\/$/, "")}/page.mdx`}
editDate={editDate}
/>
)
}
export default EditButton

View File

@@ -0,0 +1,28 @@
"use client"
import {
Feedback as UiFeedback,
FeedbackProps as UiFeedbackProps,
} from "docs-ui"
import { usePathname } from "next/navigation"
import { basePathUrl } from "../../utils/base-path-url"
import { useMemo } from "react"
type FeedbackProps = Omit<UiFeedbackProps, "event" | "pathName">
const Feedback = (props: FeedbackProps) => {
const pathname = usePathname()
const feedbackPathname = useMemo(() => basePathUrl(pathname), [pathname])
return (
<UiFeedback
event="survey"
pathName={feedbackPathname}
question="Was this guide helpful?"
{...props}
/>
)
}
export default Feedback

View File

@@ -1,6 +1,6 @@
import React from "react"
import { Card } from "docs-ui"
import { basePathUrl } from "../lib/base-path-url"
import { basePathUrl } from "@/utils/base-path-url"
export const FigmaCard = () => {
return (

View File

@@ -0,0 +1,17 @@
"use client"
import { Footer as UiFooter } from "docs-ui"
import Feedback from "../Feedback"
import EditButton from "../EditButton"
const Footer = () => {
return (
<UiFooter
showPagination={true}
feedbackComponent={<Feedback className="my-2" />}
editComponent={<EditButton />}
/>
)
}
export default Footer

View File

@@ -1,30 +1,52 @@
import { InformationCircleSolid } from "@medusajs/icons"
import { HookData, HookDataMap } from "@/types/hooks"
import { EnumType, FunctionType, ObjectType } from "@/types/props"
import {
HookData,
HookDataMap,
EnumType,
FunctionType,
ObjectType,
} from "@/types/ui"
import { InlineCode, Table, Tooltip } from "docs-ui"
const HookTable = ({ props }: { props: HookDataMap }) => {
interface HookTableProps {
props: HookDataMap
isReturn?: boolean
}
const HookTable = ({ props, isReturn = false }: HookTableProps) => {
return (
<Table className="!mb-0">
<Table.Header className="border-t-0">
<Table.Row>
<Table.HeaderCell>Value</Table.HeaderCell>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
<Table.HeaderCell className="!text-right">
{isReturn ? "Description" : "Default"}
</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body className="border-b-0 [&_tr:last-child]:border-b-0">
{/* eslint-disable-next-line react/prop-types */}
{props.map((propData, index) => (
<Row key={index} {...propData} />
<Row key={index} {...propData} isReturn={isReturn} />
))}
</Table.Body>
</Table>
)
}
const Row = ({ value, type, description }: HookData) => {
interface RowProps extends HookData {
isReturn?: boolean
}
const Row = ({
value,
type,
description,
default: defaultValue,
isReturn = false,
}: RowProps) => {
const isEnum = (t: unknown): t is EnumType => {
return (t as EnumType).type !== undefined && (t as EnumType).type === "enum"
}
@@ -48,7 +70,14 @@ const Row = ({ value, type, description }: HookData) => {
return (
<Table.Row className="code-body">
<Table.Cell>
<InlineCode>{value}</InlineCode>
<div className="flex items-center gap-x-1">
<InlineCode>{value}</InlineCode>
{!isReturn && description && (
<Tooltip content={description} className="max-w-[350px] text-left">
<InformationCircleSolid className="text-medusa-fg-subtle" />
</Tooltip>
)}
</div>
</Table.Cell>
<Table.Cell>
{!isComplexType && type.toString()}
@@ -87,7 +116,19 @@ const Row = ({ value, type, description }: HookData) => {
</Tooltip>
)}
</Table.Cell>
<Table.Cell>{description}</Table.Cell>
<Table.Cell className="!text-right">
{isReturn ? (
description ? (
<span>{description}</span>
) : (
<span className="text-medusa-fg-muted"> - </span>
)
) : defaultValue !== undefined && defaultValue !== null ? (
<InlineCode>{defaultValue.toString()}</InlineCode>
) : (
<span className="text-medusa-fg-muted"> - </span>
)}
</Table.Cell>
</Table.Row>
)
}

View File

@@ -2,14 +2,15 @@ import { Spinner } from "@medusajs/icons"
import { Container } from "@medusajs/ui"
import * as React from "react"
import { HookRegistry } from "@/registries/hook-registry"
import { Feedback } from "./feedback"
import { HookRegistry } from "@/specs/hooks"
import Feedback from "../Feedback"
type HookValuesProps = {
hook: string
hideFeedback?: boolean
}
const HookValues = ({ hook }: HookValuesProps) => {
const HookValues = ({ hook, hideFeedback = false }: HookValuesProps) => {
const Props = React.useMemo(() => {
const Table = HookRegistry[hook]?.table
@@ -40,7 +41,9 @@ const HookValues = ({ hook }: HookValuesProps) => {
{Props}
</React.Suspense>
</Container>
<Feedback title={`props of ${hook}`} />
{!hideFeedback && (
<Feedback title={`props of ${hook}`} showDottedSeparator={false} />
)}
</>
)
}

View File

@@ -0,0 +1,16 @@
import type { MDXComponents as MDXComponentsType } from "mdx/types"
import {
Link,
MDXComponents as UiMdxComponents,
InlineThemeImage,
InlineIcon,
} from "docs-ui"
const MDXComponents: MDXComponentsType = {
...UiMdxComponents,
a: Link,
InlineThemeImage,
InlineIcon,
}
export default MDXComponents

View File

@@ -2,7 +2,7 @@
import { InformationCircleSolid } from "@medusajs/icons"
import { PropData, PropDataMap, PropSpecType } from "@/types/props"
import { PropData, PropDataMap, PropSpecType } from "@/types/ui"
import { useCallback, useMemo } from "react"
import { InlineCode, MarkdownContent, Table, Tooltip } from "docs-ui"
@@ -46,7 +46,7 @@ const Row = ({
}: RowProps) => {
const normalizeRaw = (str: string): string => {
return str
.replace("\\|", "|")
.replaceAll("\\|", "|")
.replaceAll("&#60;", "<")
.replaceAll("&#62;", ">")
}

View File

@@ -180,7 +180,7 @@ export const colors = {
"--bg-overlay": "rgba(24, 24, 27, 0.4)",
"--fg-disabled": "rgba(161, 161, 170, 1)",
"--fg-muted": "rgba(113, 113, 122, 1)",
"--alpha-400": "rgba(24, 24, 27, 0.24)",
"--alpha-250": "rgba(24, 24, 27, 0.1)",
"--alpha-400": "rgba(24, 24, 27, 0.24)",
},
}

View File

@@ -0,0 +1,30 @@
import { DocsConfig, Sidebar } from "types"
import { generatedSidebars } from "@/generated/sidebar.mjs"
import { globalConfig } from "docs-ui"
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
export const config: DocsConfig = {
...globalConfig,
titleSuffix: "Medusa UI",
baseUrl,
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
sidebars: generatedSidebars as Sidebar.Sidebar[],
project: {
title: "UI",
key: "ui",
},
logo: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo.png`,
breadcrumbOptions: {
startItems: [
{
title: "Documentation",
link: baseUrl,
},
],
},
version: {
...globalConfig.version,
hide: true,
},
}

View File

@@ -1,57 +0,0 @@
import "dotenv/config"
import { defineDocumentType, makeSource } from "contentlayer/source-files"
import rehypeSlug from "rehype-slug"
import { uiRehypePlugin } from "../../packages/remark-rehype-plugins/src"
import { ExampleRegistry } from "./src/registries/example-registry"
import rehypeMdxCodeProps from "rehype-mdx-code-props"
export const Doc = defineDocumentType(() => ({
name: "Doc",
filePathPattern: `docs/**/*.mdx`,
contentType: "mdx",
fields: {
title: { type: "string", required: true },
description: { type: "string", required: true },
component: { type: "boolean", required: false, default: false },
},
computedFields: {
slug: {
type: "string",
resolve: (doc) => `/ui/${doc._raw.flattenedPath}`,
},
slugAsParams: {
type: "string",
resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"),
},
},
}))
export default makeSource({
contentDirPath: "./src/content",
documentTypes: [Doc],
mdx: {
rehypePlugins: [
[
uiRehypePlugin,
{
exampleRegistry: ExampleRegistry,
},
],
[rehypeSlug],
[
// @ts-expect-error issue with type compatibility
rehypeMdxCodeProps,
{
tagName: "code",
},
],
],
mdxOptions: (options) => {
return {
...options,
development: process.env.NODE_ENV === "development",
}
},
},
})

View File

@@ -23,12 +23,12 @@ export default [
"**/eslint-config-docs",
"**/.eslintrc.js",
"**/dist",
"src/examples",
"**/next.config.js",
"**/spec",
"**/node_modules",
"**/public",
"**/.eslintrc.js"
"**/.eslintrc.js",
"generated",
],
},
...compat.extends(
@@ -36,7 +36,7 @@ export default [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:@next/next/recommended",
"plugin:@next/next/recommended"
),
{
languageOptions: {

View File

@@ -0,0 +1,48 @@
export const generatedEditDates = {
"app/page.mdx": "2025-08-18T11:47:21.886Z",
"app/colors/overview/page.mdx": "2025-08-18T11:40:32.013Z",
"app/components/alert/page.mdx": "2025-08-18T11:37:35.544Z",
"app/components/avatar/page.mdx": "2025-08-18T11:37:36.799Z",
"app/components/badge/page.mdx": "2025-08-18T11:37:36.164Z",
"app/components/button/page.mdx": "2025-08-18T11:37:35.546Z",
"app/components/calendar/page.mdx": "2025-08-18T11:37:38.037Z",
"app/components/checkbox/page.mdx": "2025-08-18T11:37:37.354Z",
"app/components/code-block/page.mdx": "2025-08-18T11:37:38.418Z",
"app/components/command-bar/page.mdx": "2025-08-18T11:37:36.642Z",
"app/components/command/page.mdx": "2025-08-18T11:37:36.401Z",
"app/components/container/page.mdx": "2025-08-18T11:37:37.043Z",
"app/components/copy/page.mdx": "2025-08-18T11:37:36.720Z",
"app/components/currency-input/page.mdx": "2025-08-18T11:37:37.429Z",
"app/components/data-table/page.mdx": "2025-08-18T11:37:36.243Z",
"app/components/date-picker/page.mdx": "2025-08-18T11:37:36.882Z",
"app/components/drawer/page.mdx": "2025-08-18T11:37:37.962Z",
"app/components/dropdown-menu/page.mdx": "2025-08-18T11:37:37.884Z",
"app/components/focus-modal/page.mdx": "2025-08-18T11:37:37.504Z",
"app/components/heading/page.mdx": "2025-08-18T11:37:38.265Z",
"app/components/icon-badge/page.mdx": "2025-08-18T11:37:36.089Z",
"app/components/icon-button/page.mdx": "2025-08-18T11:37:37.123Z",
"app/components/inline-tip/page.mdx": "2025-08-18T11:37:36.565Z",
"app/components/input/page.mdx": "2025-08-18T11:37:38.342Z",
"app/components/kbd/page.mdx": "2025-08-18T11:37:35.852Z",
"app/components/label/page.mdx": "2025-08-18T11:37:37.218Z",
"app/components/progress-accordion/page.mdx": "2025-08-18T11:37:35.931Z",
"app/components/progress-tabs/page.mdx": "2025-08-18T11:37:37.808Z",
"app/components/prompt/page.mdx": "2025-08-18T11:37:38.113Z",
"app/components/radio-group/page.mdx": "2025-08-18T11:37:36.321Z",
"app/components/select/page.mdx": "2025-08-18T11:37:36.964Z",
"app/components/status-badge/page.mdx": "2025-08-18T11:37:37.579Z",
"app/components/switch/page.mdx": "2025-08-18T11:37:37.277Z",
"app/components/table/page.mdx": "2025-08-18T11:37:37.655Z",
"app/components/tabs/page.mdx": "2025-08-18T11:37:38.190Z",
"app/components/text/page.mdx": "2025-08-18T11:37:36.492Z",
"app/components/textarea/page.mdx": "2025-08-18T11:37:37.731Z",
"app/components/toast/page.mdx": "2025-08-18T11:37:36.010Z",
"app/components/tooltip/page.mdx": "2025-08-18T11:37:35.772Z",
"app/hooks/use-prompt/page.mdx": "2025-08-18T11:37:35.558Z",
"app/hooks/use-toggle-state/page.mdx": "2025-08-18T11:37:35.558Z",
"app/icons/overview/page.mdx": "2025-08-18T11:37:35.553Z",
"app/installation/medusa-admin-extension/page.mdx": "2025-08-18T12:34:16.683Z",
"app/installation/page.mdx": "2025-08-18T11:37:35.544Z",
"app/installation/standalone-project/page.mdx": "2025-08-18T12:40:30.780Z",
"app/utils/clx/page.mdx": "2025-08-18T11:37:35.561Z"
}

View File

@@ -0,0 +1,410 @@
export const generatedSidebars = [
{
"sidebar_id": "ui",
"title": "Medusa UI",
"items": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Introduction",
"path": "/",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Installation",
"initialOpen": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Medusa Admin Extension",
"path": "/installation/medusa-admin-extension",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Standalone Project",
"path": "/installation/standalone-project",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Icons",
"path": "/icons/overview",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Colors",
"path": "/colors/overview",
"children": []
},
{
"type": "separator"
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Components",
"initialOpen": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Alert",
"path": "/components/alert",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Avatar",
"path": "/components/avatar",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Badge",
"path": "/components/badge",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Button",
"path": "/components/button",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Calendar",
"path": "/components/calendar",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Checkbox",
"path": "/components/checkbox",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Code Block",
"path": "/components/code-block",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Command",
"path": "/components/command",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Command Bar",
"path": "/components/command-bar",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Container",
"path": "/components/container",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Copy",
"path": "/components/copy",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Currency Input",
"path": "/components/currency-input",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Data Table",
"path": "/components/data-table",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Date Picker",
"path": "/components/date-picker",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Drawer",
"path": "/components/drawer",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Dropdown Menu",
"path": "/components/dropdown-menu",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Focus Modal",
"path": "/components/focus-modal",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Heading",
"path": "/components/heading",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Icon Badge",
"path": "/components/icon-badge",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Icon Button",
"path": "/components/icon-button",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Inline Tip",
"path": "/components/inline-tip",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Input",
"path": "/components/input",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Kbd",
"path": "/components/kbd",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Label",
"path": "/components/label",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Progress Accordion",
"path": "/components/progress-accordion",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Progress Tabs",
"path": "/components/progress-tabs",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Prompt",
"path": "/components/prompt",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Radio Group",
"path": "/components/radio-group",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Select",
"path": "/components/select",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Status Badge",
"path": "/components/status-badge",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Switch",
"path": "/components/switch",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Table",
"path": "/components/table",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Tabs",
"path": "/components/tabs",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Text",
"path": "/components/text",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Textarea",
"path": "/components/textarea",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Toast",
"path": "/components/toast",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "Tooltip",
"path": "/components/tooltip",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Hooks",
"initialOpen": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "usePrompt",
"path": "/hooks/use-prompt",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "useToggleState",
"path": "/hooks/use-toggle-state",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "category",
"title": "Utils",
"initialOpen": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"title": "clx",
"path": "/utils/clx",
"children": []
}
]
}
]
}
]

View File

@@ -0,0 +1,17 @@
import type { MDXComponents } from "mdx/types"
import CustomMDXComponents from "./components/MDXComponents"
// This file allows you to provide custom React components
// to be used in MDX files. You can import and use any
// React component you want, including components from
// other libraries.
// This file is required to use MDX in `app` directory.
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
// Allows customizing built-in components, e.g. to add styling.
// h1: ({ children }) => <h1 style={{ fontSize: "100px" }}>{children}</h1>,
...components,
...CustomMDXComponents,
}
}

View File

@@ -1,16 +0,0 @@
const { withContentlayer } = require("next-contentlayer")
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: process.env.NEXT_PUBLIC_BASE_PATH || "/ui",
reactStrictMode: true,
outputFileTracingIncludes: {
"/md\\-content/\\[\\[\\.\\.\\.slug\\]\\]": [
"./src/content/docs/**/*.mdx",
"./specs/**/*",
"./examples/**/*"
],
},
}
module.exports = withContentlayer(nextConfig)

150
www/apps/ui/next.config.mjs Normal file
View File

@@ -0,0 +1,150 @@
import mdx from "@next/mdx"
import path from "path"
import rehypeMdxCodeProps from "rehype-mdx-code-props"
import rehypeSlug from "rehype-slug"
import remarkDirective from "remark-directive"
import remarkFrontmatter from "remark-frontmatter"
import {
brokenLinkCheckerPlugin,
localLinksRehypePlugin,
cloudinaryImgRehypePlugin,
resolveAdmonitionsPlugin,
crossProjectLinksPlugin,
prerequisitesLinkFixerPlugin,
remarkAttachFrontmatterDataPlugin,
recmaInjectMdxDataPlugin,
uiRehypePlugin,
} from "remark-rehype-plugins"
import bundleAnalyzer from "@next/bundle-analyzer"
import withExtractedTableOfContents from "@stefanprobst/rehype-extract-toc"
import { ExampleRegistry } from "./specs/examples.mjs"
const withMDX = mdx({
extension: /\.mdx?$/,
options: {
rehypePlugins: [
[
brokenLinkCheckerPlugin,
{
crossProjects: {
docs: {
projectPath: path.resolve("..", "book"),
},
cloud: {
projectPath: path.resolve("..", "cloud"),
},
resources: {
projectPath: path.resolve("..", "resources"),
hasGeneratedSlugs: true,
},
api: {
projectPath: path.resolve("..", "api-reference"),
skipSlugValidation: true,
},
"user-guide": {
projectPath: path.resolve("..", "user-guide"),
},
},
},
],
[
crossProjectLinksPlugin,
{
baseUrl: process.env.NEXT_PUBLIC_BASE_URL,
projectUrls: {
docs: {
url: process.env.NEXT_PUBLIC_DOCS_URL,
path: "",
},
resources: {
url: process.env.NEXT_PUBLIC_RESOURCES_URL,
},
cloud: {
url: process.env.NEXT_PUBLIC_CLOUD_URL,
},
api: {
url: process.env.NEXT_PUBLIC_API_URL,
},
"user-guide": {
url: process.env.NEXT_PUBLIC_USER_GUIDE_URL,
},
},
useBaseUrl:
process.env.NODE_ENV === "production" ||
process.env.VERCEL_ENV === "production",
},
],
[localLinksRehypePlugin],
[
rehypeMdxCodeProps,
{
tagName: "code",
},
],
[rehypeSlug],
[
cloudinaryImgRehypePlugin,
{
cloudinaryConfig: {
cloudName: process.env.CLOUDINARY_CLOUD_NAME || "",
flags: ["fl_lossy", "f_auto"],
resize: {
action: "pad",
aspectRatio: "16:9",
},
roundCorners: 16,
},
},
],
[
prerequisitesLinkFixerPlugin,
{
checkLinksType: "value",
},
],
[withExtractedTableOfContents],
[
uiRehypePlugin,
{
exampleRegistry: ExampleRegistry,
},
],
],
remarkPlugins: [
[remarkFrontmatter],
[remarkDirective],
[resolveAdmonitionsPlugin],
[remarkAttachFrontmatterDataPlugin],
],
recmaPlugins: [[recmaInjectMdxDataPlugin]],
jsx: true,
},
})
/** @type {import('next').NextConfig} */
const nextConfig = {
// Configure `pageExtensions` to include MDX files
pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
transpilePackages: ["docs-ui"],
basePath: process.env.NEXT_PUBLIC_BASE_PATH || "/ui",
outputFileTracingIncludes: {
"/md\\-content/\\[\\[\\.\\.\\.slug\\]\\]": [
"./app/**/*.mdx",
"./specs/**/*",
"./examples/**/*",
],
},
outputFileTracingExcludes: {
"*": ["node_modules/@medusajs/icons"],
},
experimental: {
optimizePackageImports: ["@medusajs/icons", "@medusajs/ui"],
},
}
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === "true",
})
export default withMDX(withBundleAnalyzer(nextConfig))

View File

@@ -4,56 +4,51 @@
"private": true,
"scripts": {
"dev": "next dev",
"dev:monorepo": "yarn dev -p 3002",
"contentlayer:build": "contentlayer build",
"build": "yarn copy-colors && yarn contentlayer:build && next build",
"dev:monorepo": "yarn prep && yarn dev -p 3005",
"build": "yarn prep && next build",
"build:dev": "NODE_ENV=test yarn build",
"start": "next start",
"start:monorepo": "yarn start -p 3002",
"start:monorepo": "yarn start -p 3005",
"lint": "next lint --fix",
"copy-colors": "ts-node ./scripts/copy-colors.ts",
"lint:content": "eslint --no-config-lookup -c .content.eslintrc.mjs src/content/docs --fix"
"lint:content": "eslint --no-config-lookup -c .content.eslintrc.mjs app/**/*.mdx --fix",
"prep": "node ./scripts/prepare.mjs"
},
"dependencies": {
"@faker-js/faker": "^8.0.2",
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
"@medusajs/icons": "2.9.0",
"@medusajs/ui": "4.0.19",
"@medusajs/ui-preset": "2.9.0",
"autoprefixer": "10.4.14",
"build-scripts": "*",
"clsx": "^2.0.0",
"contentlayer": "^0.3.4",
"date-fns": "^3.3.1",
"@next/mdx": "15.3.5",
"@stefanprobst/rehype-extract-toc": "^3.0.0",
"clsx": "^2.1.0",
"docs-ui": "*",
"docs-utils": "*",
"mdast-util-toc": "^7.0.0",
"next": "15.3.5",
"next-contentlayer": "^0.3.4",
"next-themes": "^0.2.1",
"postcss": "8.4.27",
"react": "rc",
"react-dom": "rc",
"rehype-mdx-code-props": "^3.0.1",
"rehype-mdx-code-props": "^2.0.0",
"rehype-slug": "^6.0.0",
"remark": "^14.0.3",
"slugify": "^1.6.6",
"tailwind": "*",
"tailwindcss": "3.3.3",
"typescript": "5.1.6",
"unist-builder": "3.0.0",
"unist-util-visit": "4.1.2"
"remark-directive": "^3.0.0",
"remark-frontmatter": "^5.0.0",
"remark-rehype-plugins": "*",
"slugify": "^1.6.6"
},
"devDependencies": {
"@types/node": "20.4.9",
"@types/mdx": "^2.0.13",
"@types/node": "^20",
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react@rc",
"autoprefixer": "^10.0.1",
"build-scripts": "*",
"eslint": "^9.13.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react-hooks": "^5.0.0",
"react-docgen": "^7.1.0",
"remark-rehype-plugins": "*",
"ts-node": "^10.9.1",
"types": "*"
"postcss": "^8",
"tailwind": "*",
"tailwindcss": "^3.3.0",
"tsconfig": "*",
"types": "*",
"typescript": "^5"
},
"engines": {
"node": ">=20"

View File

@@ -0,0 +1,72 @@
"use client"
import {
AiAssistantProvider,
AnalyticsProvider,
ColorModeProvider,
HooksLoader,
LearningPathProvider,
MobileProvider,
ModalProvider,
NotificationProvider,
PaginationProvider,
ScrollControllerProvider,
SiteConfigProvider,
} from "docs-ui"
import SidebarProvider from "./sidebar"
import SearchProvider from "./search"
import { config } from "../config"
import { MainNavProvider } from "./main-nav"
import { TooltipProvider } from "@medusajs/ui"
type ProvidersProps = {
children?: React.ReactNode
}
const Providers = ({ children }: ProvidersProps) => {
return (
<AnalyticsProvider
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
>
<SiteConfigProvider config={config}>
<MobileProvider>
<ColorModeProvider>
<ModalProvider>
<LearningPathProvider>
<NotificationProvider>
<ScrollControllerProvider scrollableSelector="#main">
<SidebarProvider>
<PaginationProvider>
<MainNavProvider>
<SearchProvider>
<AiAssistantProvider
integrationId={
process.env.NEXT_PUBLIC_INTEGRATION_ID || "temp"
}
>
<HooksLoader
options={{
pageScrollManager: true,
currentLearningPath: false,
}}
>
<TooltipProvider>{children}</TooltipProvider>
</HooksLoader>
</AiAssistantProvider>
</SearchProvider>
</MainNavProvider>
</PaginationProvider>
</SidebarProvider>
</ScrollControllerProvider>
</NotificationProvider>
</LearningPathProvider>
</ModalProvider>
</ColorModeProvider>
</MobileProvider>
</SiteConfigProvider>
</AnalyticsProvider>
)
}
export default Providers

View File

@@ -5,7 +5,7 @@ import {
MainNavProvider as UiMainNavProvider,
} from "docs-ui"
import { useMemo } from "react"
import { siteConfig } from "../config/site"
import { config } from "../config"
type MainNavProviderProps = {
children?: React.ReactNode
@@ -15,7 +15,7 @@ export const MainNavProvider = ({ children }: MainNavProviderProps) => {
const navigationDropdownItems = useMemo(
() =>
getNavDropdownItems({
basePath: siteConfig.baseUrl,
basePath: config.baseUrl,
}),
[]
)

View File

@@ -1,7 +1,7 @@
"use client"
import { SearchProvider as UiSearchProvider } from "docs-ui"
import { absoluteUrl } from "../lib/absolute-url"
import { config } from "../config"
type SearchProviderProps = {
children: React.ReactNode
@@ -32,10 +32,10 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
suggestions: [
{
title: "Search Suggestions",
items: ["Install in Admin Extension", "Icons", "Colors"],
items: ["Install UI in Admin", "UI Icons", "UI Colors"],
},
],
checkInternalPattern: new RegExp(`^${absoluteUrl()}/ui`),
checkInternalPattern: new RegExp(`^${config.baseUrl}/ui`),
}}
>
{children}

View File

@@ -1,8 +1,9 @@
"use client"
import {
SidebarProvider as UiSidebarProvider,
useScrollController,
} from "docs-ui"
import { sidebars } from "@/config/sidebar"
import { config } from "@/config"
type SidebarProviderProps = {
children?: React.ReactNode
@@ -13,8 +14,8 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
return (
<UiSidebarProvider
sidebars={sidebars}
scrollableElement={scrollableElement}
sidebars={config.sidebars}
>
{children}
</UiSidebarProvider>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More