docs: create docs workspace (#5174)

* docs: migrate ui docs to docs universe

* created yarn workspace

* added eslint and tsconfig configurations

* fix eslint configurations

* fixed eslint configurations

* shared tailwind configurations

* added shared ui package

* added more shared components

* migrating more components

* made details components shared

* move InlineCode component

* moved InputText

* moved Loading component

* Moved Modal component

* moved Select components

* Moved Tooltip component

* moved Search components

* moved ColorMode provider

* Moved Notification components and providers

* used icons package

* use UI colors in api-reference

* moved Navbar component

* used Navbar and Search in UI docs

* added Feedback to UI docs

* general enhancements

* fix color mode

* added copy colors file from ui-preset

* added features and enhancements to UI docs

* move Sidebar component and provider

* general fixes and preparations for deployment

* update docusaurus version

* adjusted versions

* fix output directory

* remove rootDirectory property

* fix yarn.lock

* moved code component

* added vale for all docs MD and MDX

* fix tests

* fix vale error

* fix deployment errors

* change ignore commands

* add output directory

* fix docs test

* general fixes

* content fixes

* fix announcement script

* added changeset

* fix vale checks

* added nofilter option

* fix vale error
This commit is contained in:
Shahed Nasser
2023-09-21 20:57:15 +03:00
committed by GitHub
parent 19c5d5ba36
commit fa7c94b4cc
3209 changed files with 32188 additions and 31018 deletions

View File

@@ -0,0 +1,171 @@
"use client"
import { Copy, clx } from "@medusajs/ui"
import React from "react"
import { useColorMode } from "docs-ui"
import { colors as allColors } from "../config/colors"
type Color = {
name: string
code: string
}
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",
}
interface ColorBlockProps extends React.HTMLAttributes<HTMLDivElement> {
colour: Color
}
const ColorBlock = ({ colour, className, ...props }: ColorBlockProps) => {
const [mounted, setMounted] = React.useState(false)
React.useEffect(() => setMounted(true), [])
if (!mounted) {
return (
<div className="flex w-fit flex-row items-center gap-x-2">
<div
className={
"border-medusa-border-base dark:border-medusa-border-base-dark h-[48px] w-[48px] rounded-lg border p-1"
}
>
<div
className={clx(
"bg-medusa-bg-component dark:bg-medusa-bg-component-dark h-full w-full animate-pulse rounded-[4px]",
className
)}
{...props}
/>
</div>
<div className="flex flex-col items-start">
<div className="bg-medusa-bg-component dark:bg-medusa-bg-component-dark h-[20px] w-[85px] animate-pulse rounded-sm" />
<div className="bg-medusa-bg-subtle dark:bg-medusa-bg-subtle-dark h-[20px] w-[120px] animate-pulse rounded-sm" />
</div>
</div>
)
}
return (
<div className="flex flex-row items-center gap-x-2">
<div
className={
"border-medusa-border-base dark:border-medusa-border-base-dark h-[48px] w-[48px] rounded-lg border p-1"
}
>
<div
className={clx("h-full w-full rounded-[4px]", className)}
style={{ background: colour.code }}
{...props}
/>
</div>
<div className="flex flex-col items-start">
<p className="txt-compact-xsmall-plus text-medusa-fg-base dark:text-medusa-fg-base-dark text-start">
{cssVarToTailwindClass(colour.name)}
</p>
<p className="txt-compact-xsmall text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark">
{colour.code}
</p>
</div>
</div>
)
}
const cssVarToTailwindClass = (name: string) => {
if (name.startsWith("--bg") || name.startsWith("--button")) {
return name.replace("-", "bg-ui")
}
if (name.startsWith("--fg")) {
return name.replace("-", "text-ui")
}
if (name.startsWith("--border")) {
return name.replace("-", "border-ui")
}
if (name.startsWith("--tag") || name.startsWith("--code")) {
if (name.includes("bg")) {
return name.replace("-", "bg-ui")
}
if (name.includes("border")) {
return name.replace("-", "border-ui")
}
if (name.includes("icon") || name.includes("text")) {
return name.replace("-", "text-ui")
}
}
return name
}
const Colors = () => {
const { colorMode } = useColorMode()
const colors: ColorsTable = {
backgrounds: [],
foregrounds: [],
borders: [],
buttons: [],
code: [],
tags: [],
}
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,
})
}
}
}
for (const [, section] of Object.entries(colors)) {
section.sort((a, b) => {
return a.name < b.name ? -1 : 1
})
}
return (
<div>
{Object.entries(colors).map(([section, colors]) => (
<div className="mb-16" key={`colours-section-${section}`}>
<h2 className="h2-docs mb-4 mt-10 text-medusa-fg-base dark:text-medusa-fg-base-dark">
{section.charAt(0).toUpperCase() + section.slice(1)}
</h2>
<hr className="mb-4" />
<div className="xs:grid-cols-2 mb-8 grid grid-cols-1 gap-4 gap-y-10 sm:grid-cols-3 ">
{colors.map((colour) => (
<Copy
content={cssVarToTailwindClass(colour.name)}
key={`colours-section-${section}-${colour.name}`}
>
<ColorBlock colour={colour} />
</Copy>
))}
</div>
</div>
))}
</div>
)
}
export { Colors }

View File

@@ -0,0 +1,72 @@
"use client"
import { Spinner } from "@medusajs/icons"
import * as React from "react"
import { ExampleRegistry } from "../registries/example-registry"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/tabs"
import { Feedback } from "./feedback"
import clsx from "clsx"
import { CodeBlock } from "docs-ui"
interface ComponentExampleProps extends React.HTMLAttributes<HTMLDivElement> {
name: string
}
export function ComponentExample({
children,
name,
...props
}: ComponentExampleProps) {
const Preview = React.useMemo(() => {
const Component = ExampleRegistry[name]?.component
if (!Component) {
return <p>Component {name} not found in registry</p>
}
return <Component />
}, [name])
const CodeElement = children as React.ReactElement
const Code = CodeElement.props.code
return (
<div className="relative my-4 flex flex-col space-y-2" {...props}>
<Tabs defaultValue="preview" className="relative mr-auto w-full">
<div className="flex flex-col items-center justify-between pb-3">
<TabsList className="">
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger value="code">Code</TabsTrigger>
</TabsList>
<TabsContent value="preview" className="relative">
<div
className={clsx(
"bg-docs-bg border-medusa-border-base flex max-h-[400px] min-h-[400px]",
"dark:bg-docs-bg-dark dark:border-medusa-border-base-dark",
"w-full items-center justify-center overflow-auto rounded-md border px-10 py-5"
)}
>
<React.Suspense
fallback={
<div className="text-medusa-fg-muted dark:text-medusa-fg-muted-dark flex items-center text-sm">
<Spinner className="animate-spin" />
</div>
}
>
{Preview}
</React.Suspense>
</div>
</TabsContent>
<TabsContent value="code" className="relative ">
<CodeBlock source={Code} lang="tsx" />
</TabsContent>
</div>
</Tabs>
<Feedback
title={`example ${name}`}
question="Was this example helpful?"
/>
</div>
)
}

View File

@@ -0,0 +1,48 @@
import { Spinner } from "@medusajs/icons"
import { Container } from "@medusajs/ui"
import * as React from "react"
import { PropRegistry } from "@/registries/prop-registry"
import { Feedback } from "./feedback"
type ComponentPropsProps = {
component: string
}
const ComponentProps = ({ component }: ComponentPropsProps) => {
const Props = React.useMemo(() => {
const Table = PropRegistry[component]?.table
if (!Table) {
return (
<div className="flex min-h-[200px] w-full items-center justify-center">
<p className="txt-compact-small">
No API reference found for{" "}
<span className="txt-compact-small-plus">{component}</span>
</p>
</div>
)
}
return <Table />
}, [component])
return (
<>
<Container className="mb-6 mt-8 overflow-hidden p-0">
<React.Suspense
fallback={
<div className="text-medusa-fg-muted dark:text-medusa-fg-muted-dark flex flex-1 items-center justify-center">
<Spinner className="animate-spin" />
</div>
}
>
{Props}
</React.Suspense>
</Container>
<Feedback title={`props of ${component}`} />
</>
)
}
export { ComponentProps }

View File

@@ -0,0 +1,34 @@
"use client"
import {
Feedback as UiFeedback,
FeedbackProps as UiFeedbackProps,
formatReportLink,
} from "docs-ui"
import { usePathname } from "next/navigation"
import { absoluteUrl } from "@/lib/absolute-url"
import clsx from "clsx"
export type FeedbackProps = {
title: string
} & Partial<UiFeedbackProps>
export const Feedback = ({ title, ...props }: FeedbackProps) => {
const pathname = usePathname()
return (
<UiFeedback
event="survey"
pathName={absoluteUrl(pathname)}
reportLink={formatReportLink("UI Docs", title)}
extraData={{
section: title,
}}
{...props}
className={clsx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
props.className
)}
/>
)
}

View File

@@ -0,0 +1,6 @@
import { BorderedIcon } from "docs-ui"
import { basePathUrl } from "@/lib/base-path-url"
export const FigmaIcon = () => {
return <BorderedIcon icon={basePathUrl("/images/figma.png")} />
}

View File

@@ -0,0 +1,94 @@
import { InformationCircleSolid } from "@medusajs/icons"
import { Table, Tooltip } from "@medusajs/ui"
import { HookData, HookDataMap } from "@/types/hooks"
import { EnumType, FunctionType, ObjectType } from "@/types/props"
const HookTable = ({ props }: { props: HookDataMap }) => {
return (
<Table>
<Table.Header className="border-t-0">
<Table.Row>
<Table.HeaderCell>Value</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>Description</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} />
))}
</Table.Body>
</Table>
)
}
const Row = ({ value, type, description }: HookData) => {
const isEnum = (t: unknown): t is EnumType => {
return (t as EnumType).type !== undefined && (t as EnumType).type === "enum"
}
const isObject = (t: unknown): t is ObjectType => {
return (
(t as ObjectType).type !== undefined &&
(t as ObjectType).type === "object"
)
}
const isFunction = (t: unknown): t is FunctionType => {
return (
(t as FunctionType).type !== undefined &&
(t as FunctionType).type === "function"
)
}
const isComplexType = isEnum(type) || isObject(type) || isFunction(type)
return (
<Table.Row className="code-body">
<Table.Cell>{value}</Table.Cell>
<Table.Cell>
{!isComplexType && type.toString()}
{isEnum(type) && (
<Tooltip
content={type.values.map((v) => `"${v}"`).join(" | ")}
className="font-mono"
>
<div className="flex items-center gap-x-1">
<span>enum</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
{isObject(type) && (
<Tooltip
content={<pre>{type.shape}</pre>}
className="font-mono"
maxWidth={500}
>
<div className="flex items-center gap-x-1">
<span>{type.name}</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
{isFunction(type) && (
<Tooltip
content={<pre>{type.signature}</pre>}
className="font-mono"
maxWidth={500}
>
<div className="flex items-center gap-x-1">
<span>function</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
</Table.Cell>
<Table.Cell>{description}</Table.Cell>
</Table.Row>
)
}
export { HookTable }

View File

@@ -0,0 +1,48 @@
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"
type HookValuesProps = {
hook: string
}
const HookValues = ({ hook }: HookValuesProps) => {
const Props = React.useMemo(() => {
const Table = HookRegistry[hook]?.table
if (!Table) {
return (
<div className="flex min-h-[200px] w-full items-center justify-center">
<p className="txt-compact-small">
No API reference found for{" "}
<span className="txt-compact-small-plus">{hook}</span>
</p>
</div>
)
}
return <Table />
}, [hook])
return (
<>
<Container className="mb-6 mt-8 overflow-hidden p-0">
<React.Suspense
fallback={
<div className="text-medusa-fg-muted dark:text-medusa-fg-muted-dark flex flex-1 items-center justify-center">
<Spinner className="animate-spin" />
</div>
}
>
{Props}
</React.Suspense>
</Container>
<Feedback title={`props of ${hook}`} />
</>
)
}
export { HookValues }

View File

@@ -0,0 +1,94 @@
"use client"
import * as Icons from "@medusajs/icons"
import { Container, Input, Text, Tooltip } from "@medusajs/ui"
import clsx from "clsx"
import * as React from "react"
const iconNames = Object.keys(Icons).filter((name) => name !== "default")
const IconSearch = React.memo(function IconSearch() {
const [query, setQuery] = React.useState<string | undefined>("")
return (
<div className="mt-8 flex flex-col gap-y-2">
<Input
type="search"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<Container>
<SearchResults query={query} />
</Container>
</div>
)
})
const SearchResults = ({ query = "" }: { query?: string }) => {
const cleanQuery = escapeStringRegexp(query.trim().replace(/\s/g, " "))
const results = iconNames.filter((name) =>
new RegExp(`\\b${cleanQuery}`, "gi").test(name)
)
if (results.length === 0) {
return (
<div
className={clsx(
"text-medusa-text-muted dark:text-medusa-text-muted-dark",
"flex min-h-[300px] items-center justify-center"
)}
>
<Text>
No results found for{" "}
<Text weight={"plus"} asChild>
<span>{query}</span>
</Text>
</Text>
</div>
)
}
return (
<div className="grid w-full grid-cols-4 gap-8 md:grid-cols-6 lg:grid-cols-8">
{results.map((name) => {
return (
<div
key={name}
className="flex h-full w-full items-center justify-center"
>
<Tooltip content={name}>
<div
className={clsx(
"border-medusa-border-base dark:border-medusa-border-base-dark",
"flex h-10 w-10 items-center justify-center rounded-lg border"
)}
>
<span className="sr-only">Icon named {name}</span>
<div
className={clsx(
"bg-medusa-bg-component text-medusa-fg-base",
"dark:bg-medusa-bg-component-dark dark:text-medusa-fg-base-dark",
"flex h-8 w-8 items-center justify-center rounded-[4px]"
)}
>
{React.createElement(Icons[name as keyof typeof Icons])}
</div>
</div>
</Tooltip>
</div>
)
})}
</div>
)
}
// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js
function escapeStringRegexp(string: unknown) {
if (typeof string !== "string") {
throw new TypeError("Expected a string")
}
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d")
}
export { IconSearch }

View File

@@ -0,0 +1,150 @@
"use client"
import { Text, clx } from "@medusajs/ui"
import { useMDXComponent } from "next-contentlayer/hooks"
import * as React from "react"
import { Colors } from "@/components/colors"
import { ComponentExample } from "@/components/component-example"
import { ComponentProps } from "@/components/component-props"
import { HookValues } from "@/components/hook-values"
import { IconSearch } from "@/components/icon-search"
import { PackageInstall } from "@/components/package-install"
import { Feedback } from "@/components/feedback"
import { FigmaIcon } from "@/components/figma-icon"
import clsx from "clsx"
import { NextLink, Card, BorderedIcon, CodeMdx, CodeBlock } from "docs-ui"
interface MdxProps {
code: string
}
const components = {
h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => {
return (
<h1
className={clx(
"h1-docs text-medusa-fg-base dark:text-medusa-fg-base-dark",
className
)}
{...props}
/>
)
},
h2: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => {
return (
<h2
className={clx(
"h2-docs mb-4 mt-16 text-medusa-fg-base dark:text-medusa-fg-base-dark",
className
)}
{...props}
/>
)
},
h3: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => {
return (
<h3
className={clx(
"h3-docs mb-2 mt-10 text-medusa-fg-base dark:text-medusa-fg-base-dark",
className
)}
{...props}
/>
)
},
p: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => {
return (
<Text
className={clx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark mb-docs_1.5",
className
)}
{...props}
/>
)
},
a: ({
className,
href,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) => {
const isInternal = href && href?.startsWith("/")
if (isInternal) {
return <NextLink className={className} href={href} {...props} />
}
return (
<a
className={clx(
"txt-medium text-medusa-fg-interactive hover:text-medusa-fg-interactive-hover",
"dark:text-medusa-fg-interactive-dark dark:hover:text-medusa-fg-interactive-hover-dark",
className
)}
href={href}
rel="noopener noreferrer"
target="_blank"
{...props}
/>
)
},
code: CodeMdx,
ul: ({
className,
children,
...props
}: React.HTMLAttributes<HTMLUListElement>) => {
return (
<ul
{...props}
className={clsx("list-disc px-docs_1 mb-docs_1.5", className)}
>
{children}
</ul>
)
},
li: ({
className,
children,
...props
}: React.HTMLAttributes<HTMLElement>) => {
return (
<li
className={clx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
className
)}
{...props}
>
<Text>{children}</Text>
</li>
)
},
hr: ({ className, ...props }: React.HTMLAttributes<HTMLHRElement>) => {
return <hr className={clx("mb-4", className)} {...props} />
},
HookValues,
ComponentProps,
CodeBlock,
ComponentExample,
PackageInstall,
IconSearch,
Feedback,
Colors,
Card,
BorderedIcon,
FigmaIcon,
}
const Mdx = ({ code }: MdxProps) => {
const Component = useMDXComponent(code)
return (
<div>
<Component components={components} />
</div>
)
}
export { Mdx }

View File

@@ -0,0 +1,26 @@
"use client"
import { docsConfig } from "@/config/docs"
import { Navbar as UiNavbar, useSidebar } from "docs-ui"
import { basePathUrl } from "@/lib/base-path-url"
const Navbar = () => {
const { mobileSidebarOpen, setMobileSidebarOpen } = useSidebar()
return (
<UiNavbar
logo={{
light: basePathUrl("/images/logo-icon.png"),
dark: basePathUrl("/images/logo-icon-dark.png"),
}}
items={docsConfig.mainNav}
mobileMenuButton={{
setMobileSidebarOpen,
mobileSidebarOpen,
}}
className="!z-[99]"
/>
)
}
export { Navbar }

View File

@@ -0,0 +1,35 @@
import { clx } from "@medusajs/ui"
import { CodeTabs } from "docs-ui"
type PackageInstallProps = {
packageName: string
devDependency?: boolean
version?: string
className?: string
}
const PackageInstall = ({
packageName,
devDependency = false,
version,
className,
}: PackageInstallProps) => {
const pkg = `${packageName}${version ? `@${version}` : ""}`
const yarn = `yarn add ${devDependency ? "-D " : ""}${pkg}`
const npm = `npm install ${pkg} ${devDependency ? "--save-dev" : "--save"}`
const pnpm = `pnpm add ${devDependency ? "-D " : ""}${pkg}`
return (
<CodeTabs
tabs={[
{ code: { lang: "bash", source: yarn }, label: "npm", value: "npm" },
{ code: { lang: "bash", source: npm }, label: "yarn", value: "yarn" },
{ code: { lang: "bash", source: pnpm }, label: "pnpm", value: "pnpm" },
]}
className={clx("my-4", className)}
/>
)
}
export { PackageInstall }

View File

@@ -0,0 +1,129 @@
"use client"
import { InformationCircleSolid } from "@medusajs/icons"
import { Table, Tooltip } from "@medusajs/ui"
import {
EnumType,
FunctionType,
ObjectType,
PropData,
PropDataMap,
} from "@/types/props"
type PropTableProps = {
props: PropDataMap
}
const PropTable = ({ props }: PropTableProps) => {
return (
<Table>
<Table.Header className="border-t-0">
<Table.Row>
<Table.HeaderCell>Prop</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell className="text-right">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} />
))}
</Table.Body>
</Table>
)
}
const Row = ({ prop, type, defaultValue }: PropData) => {
const isEnum = (t: unknown): t is EnumType => {
return (t as EnumType).type !== undefined && (t as EnumType).type === "enum"
}
const isObject = (t: unknown): t is ObjectType => {
return (
(t as ObjectType).type !== undefined &&
(t as ObjectType).type === "object"
)
}
const isFunction = (t: unknown): t is FunctionType => {
return (
(t as FunctionType).type !== undefined &&
(t as FunctionType).type === "function"
)
}
const defaultValueRenderer = (
v: string | number | boolean | null | undefined
) => {
if (v === undefined) {
return "-"
}
if (typeof v === "boolean") {
return v ? "true" : "false"
}
if (v === null) {
return "null"
}
if (typeof v === "string") {
return `"${v}"`
}
return v
}
const isComplexType = isEnum(type) || isObject(type) || isFunction(type)
return (
<Table.Row className="code-body">
<Table.Cell>{prop}</Table.Cell>
<Table.Cell>
{!isComplexType && type.toString()}
{isEnum(type) && (
<Tooltip
content={type.values.map((v) => `"${v}"`).join(" | ")}
className="font-mono"
>
<div className="flex items-center gap-x-1">
<span>enum</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
{isObject(type) && (
<Tooltip
content={<pre>{type.shape}</pre>}
className="font-mono"
maxWidth={500}
>
<div className="flex items-center gap-x-1">
<span>{type.name}</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
{isFunction(type) && (
<Tooltip
content={<pre>{type.signature}</pre>}
className="font-mono"
maxWidth={500}
>
<div className="flex items-center gap-x-1">
<span>function</span>
<InformationCircleSolid className="text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark" />
</div>
</Tooltip>
)}
</Table.Cell>
<Table.Cell className="text-right">
{defaultValueRenderer(defaultValue)}
</Table.Cell>
</Table.Row>
)
}
export { PropTable }

View File

@@ -0,0 +1,57 @@
"use client"
import { clx } from "@medusajs/ui"
import * as Primitives from "@radix-ui/react-scroll-area"
import clsx from "clsx"
type ScrollbarProps = React.ComponentProps<typeof Primitives.Scrollbar>
const Scrollbar = (props: ScrollbarProps) => {
return (
<Primitives.Scrollbar
className={clsx(
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark flex touch-none select-none p-0.5 transition-colors ease-out",
"data-[orientation=horizontal]:h-2.5 data-[orientation=vertical]:w-2.5 data-[orientation=horizontal]:flex-col"
)}
{...props}
/>
)
}
type ThumbProps = React.ComponentProps<typeof Primitives.Thumb>
const Thumb = ({ className, ...props }: ThumbProps) => {
return (
<Primitives.Thumb
className={clx(
"bg-medusa-bg-component dark:bg-medusa-bg-component-dark relative flex-1 rounded-[10px] before:absolute before:left-1/2 before:top-1/2 before:h-full",
"before:min-h-[44px] before:w-full before:min-w-[44px] before:-translate-x-1/2 before:-translate-y-1/2 before:content-['']",
className
)}
{...props}
/>
)
}
type ScrollAreaProps = React.ComponentProps<typeof Primitives.Root>
const ScrollArea = ({ children, className }: ScrollAreaProps) => {
return (
<Primitives.Root
className={clx("h-full w-full overflow-hidden", className)}
>
<Primitives.Viewport className="h-full w-full">
{children}
</Primitives.Viewport>
<Scrollbar orientation="vertical">
<Thumb />
</Scrollbar>
<Scrollbar orientation="horizontal">
<Thumb />
</Scrollbar>
<Primitives.Corner />
</Primitives.Root>
)
}
export { ScrollArea }

View File

@@ -0,0 +1,59 @@
"use client"
import { clx } from "@medusajs/ui"
import * as Primitives from "@radix-ui/react-tabs"
import * as React from "react"
const Tabs = Primitives.Root
const TabsList = React.forwardRef<
React.ElementRef<typeof Primitives.List>,
React.ComponentPropsWithoutRef<typeof Primitives.List>
// eslint-disable-next-line react/prop-types
>(({ className, ...props }, ref) => (
<Primitives.List
ref={ref}
className={clx(
"inline-flex h-10 w-full items-end justify-start rounded-none bg-transparent p-0",
className
)}
{...props}
/>
))
TabsList.displayName = "TabsList"
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof Primitives.Trigger>,
React.ComponentPropsWithoutRef<typeof Primitives.Trigger>
// eslint-disable-next-line react/prop-types
>(({ className, ...props }, ref) => (
<Primitives.Trigger
ref={ref}
className={clx(
"text-medusa-fg-subtle txt-compact-small-plus rounded-full px-3 py-1.5 transition-all",
"data-[state=active]:shadow-card-rest dark:data-[state=active]:shadow-card-rest-dark data-[state=active]:text-medusa-fg-base",
"dark:text-medusa-fg-subtle-dark dark:data-[state=active]:text-medusa-fg-base-dark",
className
)}
{...props}
/>
))
TabsTrigger.displayName = "TabsTrigger"
const TabsContent = React.forwardRef<
React.ElementRef<typeof Primitives.Content>,
React.ComponentPropsWithoutRef<typeof Primitives.Content>
// eslint-disable-next-line react/prop-types
>(({ className, ...props }, ref) => (
<Primitives.Content
ref={ref}
className={clx(
"w-full rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 data-[state=active]:mt-4",
className
)}
{...props}
/>
))
TabsContent.displayName = "TabsContent"
export { Tabs, TabsContent, TabsList, TabsTrigger }