docs: make code blocks collapsible (#7606)
* added collapsible code feature * fixed side shadow * fix build errors * change design * make code blocks collapsible
This commit is contained in:
@@ -72,7 +72,7 @@ For example:
|
||||
|
||||
export const highlights = [["18", "parseCorsOrigins", "A utility function that parses the CORS configurations in `medusa-config.js`"]]
|
||||
|
||||
```ts title="src/api/middlewares.ts" highlights={highlights}
|
||||
```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
ConfigModule,
|
||||
MiddlewaresConfig,
|
||||
|
||||
@@ -57,7 +57,7 @@ You can access the logged-in customer’s ID in all API routes starting with `/s
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/api/store/customers/me/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]}
|
||||
```ts title="src/api/store/customers/me/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
@@ -90,7 +90,7 @@ You can access the logged-in admin user’s ID in all API Routes starting with `
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]}
|
||||
```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
@@ -125,12 +125,11 @@ To protect custom API Routes that don’t start with `/store/customers/me` or `/
|
||||
For example:
|
||||
|
||||
export const highlights = [
|
||||
["11", "authenticate", "Only authenticated admin users can access routes starting with `/custom/admin`"],
|
||||
["17", "authenticate", "Only authenticated customers can access routes starting with `/custom/customers`"]
|
||||
["8", "authenticate", "Only authenticated admin users can access routes starting with `/custom/admin`"],
|
||||
["14", "authenticate", "Only authenticated customers can access routes starting with `/custom/customers`"]
|
||||
]
|
||||
|
||||
```ts title="src/api/middlewares.ts" highlights={highlights}
|
||||
// TODO update import
|
||||
import { MiddlewaresConfig, authenticate } from "@medusajs/medusa"
|
||||
|
||||
export const config: MiddlewaresConfig = {
|
||||
|
||||
@@ -35,7 +35,7 @@ For building relationships between data models in different modules, refer to th
|
||||
|
||||
The following example showcase a data model with common definitions:
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
Entity,
|
||||
Enum,
|
||||
|
||||
@@ -20,7 +20,7 @@ When retrieving or listing records of that data model, records having their `del
|
||||
|
||||
To create a soft-deletable model, first, add the following filter decorator to the data model class:
|
||||
|
||||
```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["7"]]}
|
||||
```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["7"]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
// other imports...
|
||||
import { Entity, Filter } from "@mikro-orm/core"
|
||||
import { DALUtils } from "@medusajs/utils"
|
||||
|
||||
@@ -20,10 +20,10 @@ export const highlights = [
|
||||
["9", '"data" in data ? data.data.id : data.id', "The payload data is either in `data.data` or directly in `data`."]
|
||||
]
|
||||
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights}
|
||||
import {
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
SubscriberArgs,
|
||||
type SubscriberConfig,
|
||||
SubscriberConfig,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
export default async function productCreateHandler({
|
||||
|
||||
@@ -48,7 +48,7 @@ When the loader function is created outside a module, it receives the Medusa con
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/loaders/hello-world.ts"
|
||||
```ts title="src/loaders/hello-world.ts" collapsibleLines="1-5" expandButtonLabel="Show Imports"
|
||||
import { MedusaContainer } from "@medusajs/medusa"
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
|
||||
@@ -40,7 +40,7 @@ The Medusa application resolves these relationships while maintaining isolation
|
||||
|
||||
Consider you’re creating a data model that adds custom fields associated with a product:
|
||||
|
||||
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]}
|
||||
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]} collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import { BaseEntity } from "@medusajs/utils"
|
||||
import {
|
||||
Entity,
|
||||
@@ -83,7 +83,7 @@ export const relationshipsHighlight = [
|
||||
["42", "foreignKey", "The name of the field in your data models referencing the other module’s model."],
|
||||
]
|
||||
|
||||
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight}
|
||||
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight} collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
// other imports...
|
||||
import { MyCustom } from "./models/custom-product-data"
|
||||
import { CustomProductData } from "./models/custom-product-data"
|
||||
|
||||
@@ -12,28 +12,27 @@ The remote link is a class with utility methods to manage links defined by the l
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
ModuleRegistrationName,
|
||||
RemoteLink,
|
||||
} from "@medusajs/modules-sdk"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
ContainerRegistrationKeys,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
RemoteLink,
|
||||
} from "@medusajs/modules-sdk"
|
||||
|
||||
export async function POST(
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
): Promise<void> {
|
||||
const remoteLink: RemoteLink = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_LINK
|
||||
)
|
||||
|
||||
// ...
|
||||
const remoteLink: RemoteLink = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_LINK
|
||||
)
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export const exampleHighlights = [
|
||||
["27", "remoteQuery", "Run the query using the remote query."]
|
||||
]
|
||||
|
||||
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query"
|
||||
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-12" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
@@ -210,7 +210,7 @@ The remote query function alternatively accepts a string with GraphQL syntax as
|
||||
|
||||
### Basic GraphQL usage
|
||||
|
||||
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query"
|
||||
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
|
||||
@@ -146,7 +146,7 @@ export const typeArgsHighlights = [
|
||||
["27", "AllModelsDTO", "The expected input/output type of the generated methods of every data model."],
|
||||
]
|
||||
|
||||
```ts title="src/modules/hello/service.ts" highlights={typeArgsHighlights}
|
||||
```ts title="src/modules/hello/service.ts" highlights={typeArgsHighlights} collapsibleLines="1-22" expandButtonLabel="Show More"
|
||||
import { ModulesSdkUtils } from "@medusajs/utils"
|
||||
import { MyCustom } from "./models/my-custom"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const highlights = [
|
||||
["14", "throwOnError", "Specify that errors occuring during the workflow's execution should be returned, not thrown."],
|
||||
]
|
||||
|
||||
```ts title="src/api/store/workflows/route.ts" highlights={highlights}
|
||||
```ts title="src/api/store/workflows/route.ts" highlights={highlights} collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
|
||||
@@ -46,7 +46,7 @@ export const updateProductHighlights = [
|
||||
["39", "", "Revert the product’s data using the `previousProductData` passed from the step to the compensation function."]
|
||||
]
|
||||
|
||||
```ts title="src/workflows/update-product-erp/steps/update-product.ts" highlights={updateProductHighlights}
|
||||
```ts title="src/workflows/update-product-erp/steps/update-product.ts" highlights={updateProductHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
@@ -145,7 +145,7 @@ export const updateErpHighlights = [
|
||||
["37", "updateProductErpData", "Revert the product's data in the ERP system to its previous state using the `previousErpData`."]
|
||||
]
|
||||
|
||||
```ts title="src/workflows/update-product-erp/steps/update-erp.ts" highlights={updateErpHighlights}
|
||||
```ts title="src/workflows/update-product-erp/steps/update-erp.ts" highlights={updateErpHighlights} collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
@@ -208,7 +208,7 @@ With the steps ready, you'll create the workflow that runs these steps to update
|
||||
|
||||
Change the content of `src/workflows/update-product-erp/index.ts` to the following:
|
||||
|
||||
```ts title="src/workflows/update-product-erp/index.ts"
|
||||
```ts title="src/workflows/update-product-erp/index.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import { createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { UpdateProductDTO, ProductDTO } from "@medusajs/types"
|
||||
import updateProduct from "./steps/update-product"
|
||||
|
||||
@@ -12,7 +12,7 @@ Errors can occur in a workflow. To avoid data inconsistency, define a function t
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["16"], ["17"], ["18"]]}
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["16"], ["17"], ["18"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
// other imports...
|
||||
import {
|
||||
createStep,
|
||||
@@ -52,7 +52,7 @@ const step2 = createStep(
|
||||
|
||||
2. Use the steps in a workflow. For example:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts"
|
||||
```ts title="src/workflows/hello-world.ts" collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
// other imports...
|
||||
createWorkflow,
|
||||
@@ -81,7 +81,7 @@ export default myWorkflow
|
||||
|
||||
3. Execute the workflow from a resource, such as an API route:
|
||||
|
||||
```ts title="src/api/store/workflow/route.ts"
|
||||
```ts title="src/api/store/workflow/route.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
|
||||
@@ -22,7 +22,7 @@ A workflow is considered long-running if at least one step has its `async` confi
|
||||
|
||||
For example, consider the following workflow and steps:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["13"]]}
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["13"]]} collapsibleLines="1-10" expandButtonLabel="Show More"
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
@@ -88,7 +88,7 @@ export const highlights = [
|
||||
["24", "subscribe", "Subscribe to status changes of the workflow execution."],
|
||||
]
|
||||
|
||||
```ts title="src/api/store/workflows/route.ts" highlights={highlights}
|
||||
```ts title="src/api/store/workflows/route.ts" highlights={highlights} collapsibleLines="1-11" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
|
||||
@@ -19,7 +19,7 @@ export const highlights = [
|
||||
["23", "parallelize", "Run the steps passed as parameters in parallel."],
|
||||
]
|
||||
|
||||
```ts highlights={highlights}
|
||||
```ts highlights={highlights} collapsibleLines="1-12" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
createWorkflow,
|
||||
parallelize,
|
||||
|
||||
@@ -12,7 +12,7 @@ By default, when an error occurs in a step, the step and the workflow fail, and
|
||||
|
||||
You can configure the step to retry on failure. The `createStep` function can accept a configuration object instead of the step’s name as a first parameter:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["10"]]}
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["10"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
|
||||
@@ -20,7 +20,7 @@ Timeout doesn't stop the execution of a running step. The timeout only affects t
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["22"]]}
|
||||
```ts title="src/workflows/hello-world.ts" highlights={[["22"]]} collapsibleLines="1-16" expandButtonLabel="Show More"
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Services`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn what services are and how to create a service.
|
||||
|
||||
## What is a Service?
|
||||
|
||||
A service is a class that holds methods related to a business logic or commerce functionality. For example, the `ProductService` holds methods to retrieve and manage products.
|
||||
|
||||
---
|
||||
|
||||
## How to Create a Service
|
||||
|
||||
Services are created in a TypeScript or JavaScript file under the `src/services` directory of your Medusa application.
|
||||
|
||||
For example, to create a `HelloWorld` service, create the file `src/services/hello-world.ts` with the following content:
|
||||
|
||||
```ts title="src/services/hello-world.ts"
|
||||
class HelloWorld {
|
||||
// TODO add methods
|
||||
}
|
||||
|
||||
export default HelloWorld
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
A service's file name must be the kebab-case name of the service without the word `Service`.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## When to Use
|
||||
|
||||
<Note title="Use services when" type="success">
|
||||
|
||||
- You're implementing custom commerce functionality to be reused across the Medusa application.
|
||||
- You're integrating a third-party service, such as an ERP system.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Resolve Resources
|
||||
|
||||
In a service's constructor, you can resolve other services or resources of your Medusa application using the Medusa container.
|
||||
|
||||
For example, you can resolve the `IProductModuleService` to use it in your methods:
|
||||
|
||||
```ts title="src/services/hello-world.ts" highlights={[["10"]]}
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
|
||||
type InjectedDependencies = {
|
||||
productModuleService: IProductModuleService
|
||||
}
|
||||
|
||||
class HelloWorldService {
|
||||
protected productModuleService: IProductModuleService
|
||||
|
||||
constructor({ productModuleService }: InjectedDependencies) {
|
||||
this.productModuleService = productModuleService
|
||||
}
|
||||
|
||||
async getMessage(): Promise<string> {
|
||||
const [, count] =
|
||||
await this.productModuleService.listAndCount()
|
||||
|
||||
return `You have ${count} products`
|
||||
}
|
||||
}
|
||||
|
||||
export default HelloWorldService
|
||||
```
|
||||
@@ -20,7 +20,7 @@ export const highlights = [
|
||||
["21", "data", "The data to pass to the template defined in the third-party service."]
|
||||
]
|
||||
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights}
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
SubscriberArgs,
|
||||
SubscriberConfig,
|
||||
|
||||
@@ -146,7 +146,7 @@ export const highlights = [
|
||||
["21", "data", "The data to pass to the template defined in SendGrid."]
|
||||
]
|
||||
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights}
|
||||
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import type {
|
||||
SubscriberArgs,
|
||||
SubscriberConfig,
|
||||
|
||||
@@ -119,7 +119,7 @@ In this guide, you’ll find common examples of how you can use the API Key Modu
|
||||
<CodeTabs groupId="app-type">
|
||||
<CodeTab label="Medusa API Router" value="medusa">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse
|
||||
@@ -257,7 +257,7 @@ In this guide, you’ll find common examples of how you can use the API Key Modu
|
||||
<CodeTabs groupId="app-type">
|
||||
<CodeTab label="Medusa API Router" value="medusa">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse
|
||||
|
||||
@@ -19,7 +19,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
|
||||
<CodeTabs groupId="app-type">
|
||||
<CodeTab label="Medusa API Router" value="medusa">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import {
|
||||
IAuthModuleService,
|
||||
@@ -122,7 +122,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
|
||||
<CodeTabs groupId="app-type">
|
||||
<CodeTab label="Medusa API Router" value="medusa">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import {
|
||||
IAuthModuleService,
|
||||
@@ -171,7 +171,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
|
||||
</CodeTab>
|
||||
<CodeTab label="Next.js App Router" value="nextjs">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
|
||||
@@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Module’s documentation](../../promo
|
||||
|
||||
</Note>
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
ComputeActionAdjustmentLine,
|
||||
ComputeActionItemLine,
|
||||
@@ -101,7 +101,7 @@ The `computeActions` method accepts the existing adjustments of line items and s
|
||||
|
||||
Then, use the returned `addItemAdjustment` and `addShippingMethodAdjustment` actions to set the cart’s line item and the shipping method’s adjustments.
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
AddItemAdjustmentAction,
|
||||
AddShippingMethodAdjustment,
|
||||
|
||||
@@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Module’s documentation](../../promo
|
||||
|
||||
</Note>
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
ComputeActionAdjustmentLine,
|
||||
ComputeActionItemLine,
|
||||
@@ -103,7 +103,7 @@ The `computeActions` method accepts the existing adjustments of line items and s
|
||||
|
||||
Then, use the returned `addItemAdjustment` and `addShippingMethodAdjustment` actions to set the order’s line items and the shipping method’s adjustments.
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
AddItemAdjustmentAction,
|
||||
AddShippingMethodAdjustment,
|
||||
|
||||
@@ -323,7 +323,7 @@ In this document, you’ll find common examples of how you can use the Pricing M
|
||||
<CodeTabs groupId="app-type">
|
||||
<CodeTab value="medusa" label="Medusa API Router">
|
||||
|
||||
```ts
|
||||
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import {
|
||||
IPricingModuleService,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Table, LegacyCodeTabs } from "docs-ui"
|
||||
import { Table, CodeTabs, CodeTab } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Medusa JS Client`,
|
||||
@@ -267,13 +267,11 @@ Once the user or customer is authenticated successfully, the Medusa client autom
|
||||
|
||||
For example:
|
||||
|
||||
<LegacyCodeTabs tabs={[
|
||||
{
|
||||
label: "Admin User",
|
||||
value: "user",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import Medusa from "@medusajs/medusa-js"
|
||||
<CodeTabs group="client-authentication-type">
|
||||
<CodeTab label="Admin User" value="user">
|
||||
|
||||
```ts
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
const medusa = new Medusa({
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
maxRetries: 3,
|
||||
@@ -282,15 +280,14 @@ For example:
|
||||
email: "user@example.com",
|
||||
password: "supersecret",
|
||||
})
|
||||
// send authenticated requests now`
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Customer",
|
||||
value: "customer",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import Medusa from "@medusajs/medusa-js"
|
||||
// send authenticated requests now
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="Customer" value="customer">
|
||||
|
||||
```ts
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
const medusa = new Medusa({
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
maxRetries: 3,
|
||||
@@ -299,10 +296,11 @@ For example:
|
||||
email: "user@example.com",
|
||||
password: "supersecret",
|
||||
})
|
||||
// send authenticated requests now`
|
||||
}
|
||||
}
|
||||
]} group="client-authentication-type" />
|
||||
// send authenticated requests now
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
### Cookie Session ID
|
||||
|
||||
@@ -314,13 +312,11 @@ Once the user or customer is authenticated successfully, the Medusa client sets
|
||||
|
||||
For example:
|
||||
|
||||
<LegacyCodeTabs tabs={[
|
||||
{
|
||||
label: "Admin User",
|
||||
value: "user",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import Medusa from "@medusajs/medusa-js"
|
||||
<CodeTabs group="client-authentication-type">
|
||||
<CodeTab label="Admin User" value="user">
|
||||
|
||||
```ts
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
const medusa = new Medusa({
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
maxRetries: 3,
|
||||
@@ -329,15 +325,14 @@ For example:
|
||||
email: "user@example.com",
|
||||
password: "supersecret",
|
||||
})
|
||||
// send authenticated requests now`
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Customer",
|
||||
value: "customer",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import Medusa from "@medusajs/medusa-js"
|
||||
// send authenticated requests now
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="Customer" value="customer">
|
||||
|
||||
```ts
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
const medusa = new Medusa({
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
maxRetries: 3,
|
||||
@@ -346,10 +341,11 @@ For example:
|
||||
email: "user@example.com",
|
||||
password: "user@example.com",
|
||||
})
|
||||
// send authenticated requests now`
|
||||
}
|
||||
}
|
||||
]} group="client-authentication-type" />
|
||||
// send authenticated requests now
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
### API Key
|
||||
|
||||
@@ -357,13 +353,11 @@ You can authenticate admin users with a personal API Token.
|
||||
|
||||
If a user doesn't have a personal API token, create one with the [admin.users.update](/references/js-client/AdminUsersResource#update) method or the [Update User API route](https://docs.medusajs.com/api/admin#users_postusersuser):
|
||||
|
||||
<LegacyCodeTabs tabs={[
|
||||
{
|
||||
label: "JS Client",
|
||||
value: "js-client",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import Medusa from "@medusajs/medusa-js"
|
||||
<CodeTabs group="client-type">
|
||||
<CodeTab label="JS Client" value="js-client">
|
||||
|
||||
```ts
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
const medusa = new Medusa({
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
maxRetries: 3,
|
||||
@@ -374,23 +368,23 @@ If a user doesn't have a personal API token, create one with the [admin.users.up
|
||||
})
|
||||
.then(({ user }) => {
|
||||
console.log(user.api_token)
|
||||
})`
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "cURL",
|
||||
value: "curl",
|
||||
code: {
|
||||
lang: "bash",
|
||||
source: `curl -L -X POST '<BACKEND_URL>/admin/users/<USER_ID>' \\
|
||||
})
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="cURL" value="curl">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/users/<USER_ID>' \\
|
||||
-H 'Cookie: connect.sid={sid}' \\
|
||||
-H 'Content-Type: application/json' \\
|
||||
--data-raw '{
|
||||
"api_token": "{api_token}"
|
||||
}'`
|
||||
}
|
||||
}
|
||||
]} group="client-type" />
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
Then, initialize the Medusa client passing it the `apiKey` option:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Table, LegacyCodeTabs } from "docs-ui"
|
||||
import { Table, CodeTabs, CodeTab } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Medusa React`,
|
||||
@@ -216,13 +216,11 @@ There are two ways to authenticate an admin user:
|
||||
|
||||
For example:
|
||||
|
||||
<LegacyCodeTabs tabs={[
|
||||
{
|
||||
value: "useadminlogin",
|
||||
label: "useAdminLogin hook",
|
||||
code: {
|
||||
lang: "ts",
|
||||
source: `import React from "react"
|
||||
<CodeTabs group="admin-auth">
|
||||
<CodeTab label="useAdminLogin hook" value="useadminlogin">
|
||||
|
||||
```ts
|
||||
import React from "react"
|
||||
import { useAdminLogin } from "medusa-react"
|
||||
|
||||
const Login = () => {
|
||||
@@ -244,15 +242,14 @@ For example:
|
||||
// ...
|
||||
}
|
||||
|
||||
export default Login`
|
||||
}
|
||||
},
|
||||
{
|
||||
value: "apikey",
|
||||
label: "apikey Option",
|
||||
code: {
|
||||
lang: "tsx",
|
||||
source: `import { MedusaProvider } from "medusa-react"
|
||||
export default Login
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="apikey Option" value="apikey">
|
||||
|
||||
```tsx
|
||||
import { MedusaProvider } from "medusa-react"
|
||||
import Storefront from "./Storefront"
|
||||
import { QueryClient } from "@tanstack/react-query"
|
||||
import React from "react"
|
||||
@@ -271,10 +268,11 @@ For example:
|
||||
)
|
||||
}
|
||||
|
||||
export default App`
|
||||
}
|
||||
}
|
||||
]} group="admin-auth" />
|
||||
export default App
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
### Customer Authentication
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LegacyCodeTabs } from "docs-ui"
|
||||
import { CodeTabs, CodeTab } from "docs-ui"
|
||||
|
||||
If you install the Medusa CLI tool with Yarn, then try to use the CLI tool but get the error:
|
||||
|
||||
@@ -8,28 +8,23 @@ command not found: medusa
|
||||
|
||||
You have to add Yarn’s install location to the PATH variable:
|
||||
|
||||
<LegacyCodeTabs
|
||||
tabs={[
|
||||
{
|
||||
label: "MacOS / Linux",
|
||||
value: "unix",
|
||||
code: {
|
||||
lang: "bash",
|
||||
source: `export PATH="$(yarn global bin):$PATH"`
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Windows",
|
||||
value: "windows",
|
||||
code: {
|
||||
lang: "bash",
|
||||
source: `# MAKE SURE TO INCLUDE %path%
|
||||
<CodeTabs group="operating-systems">
|
||||
<CodeTab label="MacOS / Linux" value="unix">
|
||||
|
||||
```plain
|
||||
export PATH="$(yarn global bin):$PATH
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="Windows" value="windows">
|
||||
|
||||
```bash
|
||||
# MAKE SURE TO INCLUDE %path%
|
||||
setx path "%path%;c:\\users\\YOURUSERNAME\\appdata\\local\\yarnbin"
|
||||
# YOURUSERNAME is your account username`
|
||||
}
|
||||
}
|
||||
]}
|
||||
group="operating-systems"
|
||||
/>
|
||||
# YOURUSERNAME is your account username
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
|
||||
You can learn more in [Yarn’s documentation](https://classic.yarnpkg.com/en/docs/cli/global#adding-the-install-location-to-your-path).
|
||||
@@ -1,26 +1,24 @@
|
||||
import { LegacyCodeTabs } from "docs-ui"
|
||||
import { CodeTabs, CodeTab } from "docs-ui"
|
||||
|
||||
This error can occur while installing any of Medusa's projects (for example, Next.js Starter Template). There is no specific cause to this error.
|
||||
|
||||
One way to resolve it is by removing the `node_modules` directory in the project and re-installing the dependencies:
|
||||
|
||||
<LegacyCodeTabs tabs={[
|
||||
{
|
||||
label: "MacOS / Linux",
|
||||
value: "unix",
|
||||
code: {
|
||||
lang: "bash",
|
||||
source: `rm -rf node_modules
|
||||
yarn install`
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Windows",
|
||||
value: "windows",
|
||||
code: {
|
||||
lang: "bash",
|
||||
source: `rd /s /q node_modules
|
||||
yarn install`
|
||||
}
|
||||
}
|
||||
]} group="operating-systems" />
|
||||
<CodeTabs group="operating-systems">
|
||||
<CodeTab label="MacOS / Linux" value="unix">
|
||||
|
||||
```bash
|
||||
rm -rf node_modules
|
||||
yarn install
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
<CodeTab label="Windows" value="windows">
|
||||
|
||||
```bash
|
||||
rd /s /q node_modules
|
||||
yarn install
|
||||
```
|
||||
|
||||
</CodeTab>
|
||||
</CodeTabs>
|
||||
@@ -227,6 +227,10 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx",
|
||||
"pathname": "/architectural-modules/workflow-engine/redis"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx",
|
||||
"pathname": "/commerce-modules/api-key/concepts"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/api-key/events/_events-table/page.mdx",
|
||||
"pathname": "/commerce-modules/api-key/events/_events-table"
|
||||
@@ -247,10 +251,6 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx",
|
||||
"pathname": "/commerce-modules/api-key/relations-to-other-modules"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/api-key/tokens/page.mdx",
|
||||
"pathname": "/commerce-modules/api-key/tokens"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx",
|
||||
"pathname": "/commerce-modules/auth/auth-flows"
|
||||
@@ -331,6 +331,10 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/currency/page.mdx",
|
||||
"pathname": "/commerce-modules/currency"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/currency/relations-to-other-modules/page.mdx",
|
||||
"pathname": "/commerce-modules/currency/relations-to-other-modules"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/customer/customer-accounts/page.mdx",
|
||||
"pathname": "/commerce-modules/customer/customer-accounts"
|
||||
@@ -687,6 +691,10 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/store/page.mdx",
|
||||
"pathname": "/commerce-modules/store"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/store/relations-to-other-modules/page.mdx",
|
||||
"pathname": "/commerce-modules/store/relations-to-other-modules"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/tax/events/_events-table/page.mdx",
|
||||
"pathname": "/commerce-modules/tax/events/_events-table"
|
||||
@@ -743,10 +751,6 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/commerce-modules/user/user-creation-flows/page.mdx",
|
||||
"pathname": "/commerce-modules/user/user-creation-flows"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/configurations/_medusa-admin/page.mdx",
|
||||
"pathname": "/configurations/_medusa-admin"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/contribution-guidelines/_admin-translations/page.mdx",
|
||||
"pathname": "/contribution-guidelines/_admin-translations"
|
||||
@@ -931,14 +935,6 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/_transaction-promise-all/page.mdx",
|
||||
"pathname": "/troubleshooting/_transaction-promise-all"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/admin-sign-in/page.mdx",
|
||||
"pathname": "/troubleshooting/admin-sign-in"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/admin-webpack-build-error/page.mdx",
|
||||
"pathname": "/troubleshooting/admin-webpack-build-error"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/troubleshooting/cors-errors/page.mdx",
|
||||
"pathname": "/troubleshooting/cors-errors"
|
||||
|
||||
@@ -37,8 +37,8 @@ export const generatedSidebar = [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/commerce-modules/api-key/tokens",
|
||||
"title": "Tokens",
|
||||
"path": "/commerce-modules/api-key/concepts",
|
||||
"title": "API Key Concepts",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
@@ -863,6 +863,20 @@ export const generatedSidebar = [
|
||||
"title": "Examples",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Concepts",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/commerce-modules/currency/relations-to-other-modules",
|
||||
"title": "Relation to Modules",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
@@ -5068,6 +5082,20 @@ export const generatedSidebar = [
|
||||
"title": "Examples",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Concepts",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/commerce-modules/store/relations-to-other-modules",
|
||||
"title": "Relation to Modules",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
@@ -5236,7 +5264,7 @@ export const generatedSidebar = [
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/commerce-modules/tax/tax-calculation-with-provider",
|
||||
"title": "Tax Calculation",
|
||||
"title": "Tax Calculation and Providers",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
@@ -5246,13 +5274,6 @@ export const generatedSidebar = [
|
||||
"isPathHref": true,
|
||||
"title": "References",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/references/tax/provider",
|
||||
"title": "Tax Provider Reference",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
@@ -7144,28 +7165,6 @@ export const generatedSidebar = [
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Medusa Admin",
|
||||
"hasTitleStyling": true,
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/troubleshooting/admin-sign-in",
|
||||
"title": "Signing In",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/troubleshooting/admin-custom-hooks-error",
|
||||
"title": "Custom Hooks Error",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import {
|
||||
SearchProvider as UiSearchProvider,
|
||||
AiAssistantCommandIcon,
|
||||
AiAssistantIcon,
|
||||
AiAssistantProvider,
|
||||
searchFiltersV1,
|
||||
} from "docs-ui"
|
||||
@@ -48,7 +48,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
commands={[
|
||||
{
|
||||
name: "ai-assistant",
|
||||
icon: <AiAssistantCommandIcon />,
|
||||
icon: <AiAssistantIcon />,
|
||||
component: (
|
||||
<AiAssistantProvider
|
||||
apiUrl={process.env.NEXT_PUBLIC_AI_ASSISTANT_URL || "temp"}
|
||||
@@ -61,8 +61,9 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
),
|
||||
title: "AI Assistant",
|
||||
badge: {
|
||||
variant: "purple",
|
||||
variant: "blue",
|
||||
children: "Beta",
|
||||
badgeType: "shaded",
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -12,6 +12,9 @@ export type CodeBlockActionsProps = {
|
||||
source: string
|
||||
isSingleLine?: boolean
|
||||
inHeader: boolean
|
||||
showGradientBg?: boolean
|
||||
inInnerCode?: boolean
|
||||
isCollapsed: boolean
|
||||
canShowApiTesting?: boolean
|
||||
blockStyle: CodeBlockStyle
|
||||
onApiTesting: React.Dispatch<React.SetStateAction<boolean>>
|
||||
@@ -22,6 +25,9 @@ export type CodeBlockActionsProps = {
|
||||
export const CodeBlockActions = ({
|
||||
source,
|
||||
inHeader,
|
||||
showGradientBg = true,
|
||||
inInnerCode = false,
|
||||
isCollapsed,
|
||||
isSingleLine = false,
|
||||
canShowApiTesting = false,
|
||||
blockStyle,
|
||||
@@ -45,65 +51,87 @@ export const CodeBlockActions = ({
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"absolute hidden md:flex md:justify-end",
|
||||
"xs:rounded xs:absolute xs:right-0 xs:top-0 xs:w-[calc(10%+24px)] xs:h-full xs:bg-transparent",
|
||||
!inHeader && [
|
||||
"md:right-docs_0.5",
|
||||
isSingleLine && "md:top-docs_0.25",
|
||||
!isSingleLine && "md:top-docs_0.5",
|
||||
],
|
||||
inHeader && "md:right-docs_1 md:top-docs_0.5"
|
||||
"absolute hidden md:block",
|
||||
"xs:rounded xs:absolute xs:right-0 xs:top-0 xs:w-[calc(17%+10px)] xs:h-full"
|
||||
)}
|
||||
>
|
||||
{canShowApiTesting && (
|
||||
<Tooltip
|
||||
text="Test API"
|
||||
tooltipClassName="font-base"
|
||||
className={clsx(
|
||||
"h-fit",
|
||||
!inHeader && "p-[6px]",
|
||||
inHeader && "px-[6px] pb-[6px]"
|
||||
)}
|
||||
>
|
||||
<PlaySolid
|
||||
className={clsx("cursor-pointer", iconColor)}
|
||||
onClick={() => onApiTesting(true)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!noReport && (
|
||||
<Tooltip
|
||||
text="Report Issue"
|
||||
tooltipClassName="font-base"
|
||||
className={clsx(
|
||||
"h-fit",
|
||||
!inHeader && "p-[6px]",
|
||||
inHeader && "px-[6px] pb-[6px]"
|
||||
)}
|
||||
>
|
||||
<Link
|
||||
href={`${GITHUB_ISSUES_PREFIX}&title=${encodeURIComponent(
|
||||
`Docs(Code Issue): `
|
||||
)}`}
|
||||
target="_blank"
|
||||
<div
|
||||
className={clsx(
|
||||
!inHeader &&
|
||||
showGradientBg && [
|
||||
inInnerCode &&
|
||||
"xs:bg-subtle-code-fade-right-to-left dark:xs:bg-subtle-code-fade-right-to-left-dark",
|
||||
!inInnerCode &&
|
||||
"xs:bg-base-code-fade-right-to-left dark:xs:bg-base-code-fade-right-to-left-dark",
|
||||
],
|
||||
(inHeader || !showGradientBg) && "xs:bg-transparent",
|
||||
"z-[9] w-full h-full absolute top-0 left-0"
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={clsx(
|
||||
"md:flex md:justify-end z-[11] relative",
|
||||
!inHeader && [
|
||||
"md:pr-docs_0.5",
|
||||
isCollapsed && "md:pt-docs_2.5",
|
||||
!isCollapsed && [
|
||||
isSingleLine && "md:pt-docs_0.25",
|
||||
!isSingleLine && "md:pt-docs_0.5",
|
||||
],
|
||||
],
|
||||
inHeader && "md:pr-docs_1 md:pt-docs_0.5"
|
||||
)}
|
||||
>
|
||||
{canShowApiTesting && (
|
||||
<Tooltip
|
||||
text="Test API"
|
||||
tooltipClassName="font-base"
|
||||
className={clsx(
|
||||
"bg-transparent border-none cursor-pointer rounded",
|
||||
"[&:not(:first-child)]:ml-docs_0.5",
|
||||
"inline-flex justify-center items-center invisible xs:visible"
|
||||
"h-fit",
|
||||
!inHeader && "p-[6px]",
|
||||
inHeader && "px-[6px] pb-[6px]"
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<ExclamationCircle className={clsx(iconColor)} />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!noCopy && (
|
||||
<CodeBlockCopyAction
|
||||
source={source}
|
||||
inHeader={inHeader}
|
||||
iconColor={iconColor}
|
||||
/>
|
||||
)}
|
||||
<PlaySolid
|
||||
className={clsx("cursor-pointer", iconColor)}
|
||||
onClick={() => onApiTesting(true)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!noReport && (
|
||||
<Tooltip
|
||||
text="Report Issue"
|
||||
tooltipClassName="font-base"
|
||||
className={clsx(
|
||||
"h-fit",
|
||||
!inHeader && "p-[6px]",
|
||||
inHeader && "px-[6px] pb-[6px]"
|
||||
)}
|
||||
>
|
||||
<Link
|
||||
href={`${GITHUB_ISSUES_PREFIX}&title=${encodeURIComponent(
|
||||
`Docs(Code Issue): `
|
||||
)}`}
|
||||
target="_blank"
|
||||
className={clsx(
|
||||
"bg-transparent border-none cursor-pointer rounded",
|
||||
"[&:not(:first-child)]:ml-docs_0.5",
|
||||
"inline-flex justify-center items-center invisible xs:visible"
|
||||
)}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<ExclamationCircle className={clsx(iconColor)} />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!noCopy && (
|
||||
<CodeBlockCopyAction
|
||||
source={source}
|
||||
inHeader={inHeader}
|
||||
iconColor={iconColor}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
"use client"
|
||||
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { CollapsibleReturn } from "../../../../hooks"
|
||||
import { Button } from "@medusajs/ui"
|
||||
|
||||
export type CodeBlockCollapsibleButtonProps = {
|
||||
type: "start" | "end"
|
||||
expandButtonLabel?: string
|
||||
className?: string
|
||||
} & Omit<CollapsibleReturn, "getCollapsibleElms">
|
||||
|
||||
export const CodeBlockCollapsibleButton = ({
|
||||
type,
|
||||
expandButtonLabel = "Show more",
|
||||
collapsed,
|
||||
setCollapsed,
|
||||
className,
|
||||
}: CodeBlockCollapsibleButtonProps) => {
|
||||
if (!collapsed) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{type === "start" && (
|
||||
<Button
|
||||
className={clsx(
|
||||
"font-base w-full p-docs_0.5 !shadow-none z-10",
|
||||
"bg-medusa-contrast-button hover:bg-medusa-contrast-button-hover",
|
||||
"txt-compact-xsmall text-medusa-contrast-fg-secondary",
|
||||
type === "start" && "rounded-t-docs_DEFAULT rounded-b-none",
|
||||
className
|
||||
)}
|
||||
onClick={() => setCollapsed(false)}
|
||||
>
|
||||
{expandButtonLabel}
|
||||
</Button>
|
||||
)}
|
||||
{type === "end" && (
|
||||
<Button
|
||||
className={clsx(
|
||||
"font-base w-full p-docs_0.5 !shadow-none z-10",
|
||||
"bg-medusa-contrast-button hover:bg-medusa-contrast-button-hover",
|
||||
"txt-compact-xsmall text-medusa-contrast-fg-secondary",
|
||||
"rounded-t-none rounded-b-docs_DEFAULT",
|
||||
className
|
||||
)}
|
||||
onClick={() => setCollapsed(false)}
|
||||
>
|
||||
{expandButtonLabel}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { CollapsibleReturn } from "../../../../hooks"
|
||||
|
||||
export type CodeBlockCollapsibleFadeProps = {
|
||||
type: "start" | "end"
|
||||
hasHeader?: boolean
|
||||
} & Pick<CollapsibleReturn, "collapsed">
|
||||
|
||||
export const CodeBlockCollapsibleFade = ({
|
||||
type,
|
||||
hasHeader = false,
|
||||
collapsed,
|
||||
}: CodeBlockCollapsibleFadeProps) => {
|
||||
if (!collapsed) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
"absolute flex flex-col z-10",
|
||||
hasHeader && "left-[6px] w-[calc(100%-12px)]",
|
||||
!hasHeader && "w-full left-0",
|
||||
type === "start" && [
|
||||
hasHeader && "top-[44px]",
|
||||
!hasHeader && "top-[36px]",
|
||||
],
|
||||
type === "end" && [
|
||||
hasHeader && "bottom-[44px]",
|
||||
!hasHeader && "bottom-[36px]",
|
||||
]
|
||||
)}
|
||||
>
|
||||
{type === "end" && (
|
||||
<span
|
||||
className={clsx(
|
||||
"w-full h-[56px]",
|
||||
"bg-code-fade-bottom-to-top dark:bg-code-fade-bottom-to-top-dark"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{type === "start" && (
|
||||
<span
|
||||
className={clsx(
|
||||
"w-full h-[56px]",
|
||||
"bg-code-fade-top-to-bottom dark:bg-code-fade-top-to-bottom-dark"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
"use client"
|
||||
|
||||
import React, { useMemo } from "react"
|
||||
import { CollapsibleReturn } from "../../../../hooks"
|
||||
|
||||
export type CodeBlockCollapsibleLinesProps = {
|
||||
children: React.ReactNode
|
||||
type: "start" | "end"
|
||||
} & Omit<CollapsibleReturn, "setCollapsed">
|
||||
|
||||
export const CodeBlockCollapsibleLines = ({
|
||||
children,
|
||||
type,
|
||||
collapsed,
|
||||
getCollapsibleElms,
|
||||
}: CodeBlockCollapsibleLinesProps) => {
|
||||
const shownChildren: React.ReactNode = useMemo(() => {
|
||||
const isStart = type === "start"
|
||||
return (
|
||||
<>
|
||||
{collapsed && Array.isArray(children)
|
||||
? children.slice(isStart ? -2 : 0, isStart ? undefined : 2)
|
||||
: children}
|
||||
</>
|
||||
)
|
||||
}, [children, collapsed])
|
||||
|
||||
return getCollapsibleElms(shownChildren)
|
||||
}
|
||||
@@ -22,6 +22,7 @@ type CodeBlockLineProps = {
|
||||
lineNumber: number
|
||||
showLineNumber: boolean
|
||||
lineNumberColorClassName: string
|
||||
lineNumberBgClassName: string
|
||||
noLineNumbers?: boolean
|
||||
} & Pick<RenderProps, "getLineProps" | "getTokenProps">
|
||||
|
||||
@@ -33,6 +34,7 @@ export const CodeBlockLine = ({
|
||||
getTokenProps,
|
||||
showLineNumber,
|
||||
lineNumberColorClassName,
|
||||
lineNumberBgClassName,
|
||||
}: CodeBlockLineProps) => {
|
||||
const lineProps = getLineProps({ line, key: lineNumber })
|
||||
|
||||
@@ -241,7 +243,8 @@ export const CodeBlockLine = ({
|
||||
className={clsx(
|
||||
"mr-docs_1 table-cell select-none",
|
||||
"sticky left-0 w-[1%] px-docs_1 text-right",
|
||||
lineNumberColorClassName
|
||||
lineNumberColorClassName,
|
||||
lineNumberBgClassName
|
||||
)}
|
||||
>
|
||||
{lineNumber + 1}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
"use client"
|
||||
|
||||
import React, { useMemo, useState } from "react"
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react"
|
||||
import clsx from "clsx"
|
||||
import { HighlightProps, Highlight, themes } from "prism-react-renderer"
|
||||
import { Highlight, HighlightProps, themes, Token } from "prism-react-renderer"
|
||||
import { ApiRunner } from "@/components"
|
||||
import { useColorMode } from "@/providers"
|
||||
import { CodeBlockHeader, CodeBlockHeaderMeta } from "./Header"
|
||||
import { CodeBlockLine } from "./Line"
|
||||
import { ApiAuthType, ApiDataOptions, ApiMethod } from "types"
|
||||
import { CSSTransition } from "react-transition-group"
|
||||
import { useCollapsibleCodeLines } from "../.."
|
||||
import { HighlightProps as CollapsibleHighlightProps } from "@/hooks"
|
||||
import { CodeBlockActions, CodeBlockActionsProps } from "./Actions"
|
||||
import { CodeBlockCollapsibleButton } from "./Collapsible/Button"
|
||||
import { CodeBlockCollapsibleFade } from "./Collapsible/Fade"
|
||||
|
||||
export type Highlight = {
|
||||
line: number
|
||||
@@ -32,6 +36,8 @@ export type CodeBlockMetaFields = {
|
||||
noCopy?: boolean
|
||||
noReport?: boolean
|
||||
noLineNumbers?: boolean
|
||||
collapsibleLines?: string
|
||||
expandButtonLabel?: string
|
||||
} & CodeBlockHeaderMeta
|
||||
|
||||
export type CodeBlockStyle = "loud" | "subtle"
|
||||
@@ -60,6 +66,8 @@ export const CodeBlock = ({
|
||||
noReport = false,
|
||||
noLineNumbers = false,
|
||||
children,
|
||||
collapsibleLines,
|
||||
expandButtonLabel,
|
||||
...rest
|
||||
}: CodeBlockProps) => {
|
||||
if (!source && typeof children === "string") {
|
||||
@@ -68,6 +76,9 @@ export const CodeBlock = ({
|
||||
|
||||
const { colorMode } = useColorMode()
|
||||
const [showTesting, setShowTesting] = useState(false)
|
||||
const codeContainerRef = useRef<HTMLDivElement>(null)
|
||||
const codeRef = useRef<HTMLElement>(null)
|
||||
const [scrollable, setScrollable] = useState(false)
|
||||
const hasInnerCodeBlock = useMemo(
|
||||
() => hasTabs || title.length > 0,
|
||||
[hasTabs, title]
|
||||
@@ -107,7 +118,7 @@ export const CodeBlock = ({
|
||||
const borderColor = useMemo(
|
||||
() =>
|
||||
clsx(
|
||||
blockStyle === "loud" && "border-transparent",
|
||||
blockStyle === "loud" && "border-0",
|
||||
blockStyle === "subtle" && [
|
||||
colorMode === "light" && "border-medusa-border-base",
|
||||
colorMode === "dark" && "border-medusa-code-border",
|
||||
@@ -158,10 +169,6 @@ export const CodeBlock = ({
|
||||
return lowerLang === "json" ? "plain" : lowerLang
|
||||
}, [lang])
|
||||
|
||||
if (!source.length) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const transformedHighlights: Highlight[] = highlights
|
||||
.filter((highlight) => highlight.length !== 0)
|
||||
.map((highlight) => ({
|
||||
@@ -170,13 +177,79 @@ export const CodeBlock = ({
|
||||
tooltipText: highlight.length >= 3 ? highlight[2] : undefined,
|
||||
}))
|
||||
|
||||
const actionsProps: Omit<CodeBlockActionsProps, "inHeader"> = {
|
||||
source,
|
||||
canShowApiTesting,
|
||||
onApiTesting: setShowTesting,
|
||||
blockStyle,
|
||||
noReport,
|
||||
noCopy,
|
||||
const getLines = (
|
||||
tokens: Token[][],
|
||||
highlightProps: CollapsibleHighlightProps,
|
||||
lineNumberOffset = 0
|
||||
) =>
|
||||
tokens.map((line, i) => {
|
||||
const offsettedLineNumber = i + lineNumberOffset
|
||||
const highlightedLines = transformedHighlights.filter(
|
||||
(highlight) => highlight.line - 1 === offsettedLineNumber
|
||||
)
|
||||
|
||||
return (
|
||||
<CodeBlockLine
|
||||
line={line}
|
||||
lineNumber={offsettedLineNumber}
|
||||
highlights={highlightedLines}
|
||||
showLineNumber={!noLineNumbers && tokens.length > 1}
|
||||
key={offsettedLineNumber}
|
||||
lineNumberColorClassName={lineNumbersColor}
|
||||
lineNumberBgClassName={innerBgColor}
|
||||
{...highlightProps}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
const {
|
||||
getCollapsedLinesElm,
|
||||
getNonCollapsedLinesElm,
|
||||
type: collapsibleType,
|
||||
...collapsibleResult
|
||||
} = useCollapsibleCodeLines({
|
||||
collapsibleLinesStr: collapsibleLines,
|
||||
getLines,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!codeContainerRef.current || !codeRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
setScrollable(
|
||||
codeContainerRef.current.scrollWidth < codeRef.current.clientWidth
|
||||
)
|
||||
}, [codeContainerRef.current, codeRef.current])
|
||||
|
||||
const actionsProps: Omit<CodeBlockActionsProps, "inHeader"> = useMemo(
|
||||
() => ({
|
||||
source,
|
||||
canShowApiTesting,
|
||||
onApiTesting: setShowTesting,
|
||||
blockStyle,
|
||||
noReport,
|
||||
noCopy,
|
||||
isCollapsed: collapsibleType !== undefined && collapsibleResult.collapsed,
|
||||
inInnerCode: hasInnerCodeBlock,
|
||||
showGradientBg: scrollable,
|
||||
}),
|
||||
[
|
||||
source,
|
||||
canShowApiTesting,
|
||||
setShowTesting,
|
||||
blockStyle,
|
||||
noReport,
|
||||
noCopy,
|
||||
collapsibleType,
|
||||
collapsibleResult,
|
||||
hasInnerCodeBlock,
|
||||
scrollable,
|
||||
]
|
||||
)
|
||||
|
||||
if (!source.length) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -233,12 +306,30 @@ export const CodeBlock = ({
|
||||
tokens,
|
||||
...rest
|
||||
}) => (
|
||||
<div className={clsx(innerBorderClasses, innerBgColor)}>
|
||||
<div
|
||||
className={clsx(innerBorderClasses, innerBgColor, "relative")}
|
||||
ref={codeContainerRef}
|
||||
>
|
||||
{collapsibleType === "start" && (
|
||||
<>
|
||||
<CodeBlockCollapsibleButton
|
||||
type={collapsibleType}
|
||||
expandButtonLabel={expandButtonLabel}
|
||||
className={innerBorderClasses}
|
||||
{...collapsibleResult}
|
||||
/>
|
||||
<CodeBlockCollapsibleFade
|
||||
type={collapsibleType}
|
||||
collapsed={collapsibleResult.collapsed}
|
||||
hasHeader={hasInnerCodeBlock}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<pre
|
||||
style={{ ...style, fontStretch: "100%" }}
|
||||
className={clsx(
|
||||
"relative !my-0 break-words bg-transparent !outline-none",
|
||||
"overflow-auto break-words p-0",
|
||||
"overflow-auto break-words p-0 pr-docs_0.25",
|
||||
"rounded-docs_DEFAULT",
|
||||
!hasInnerCodeBlock &&
|
||||
tokens.length <= 1 &&
|
||||
@@ -253,24 +344,22 @@ export const CodeBlock = ({
|
||||
tokens.length > 1 && "py-docs_0.75",
|
||||
tokens.length <= 1 && "!py-[6px] px-docs_0.5"
|
||||
)}
|
||||
ref={codeRef}
|
||||
>
|
||||
{tokens.map((line, i) => {
|
||||
const highlightedLines = transformedHighlights.filter(
|
||||
(highlight) => highlight.line - 1 === i
|
||||
)
|
||||
|
||||
return (
|
||||
<CodeBlockLine
|
||||
line={line}
|
||||
lineNumber={i}
|
||||
highlights={highlightedLines}
|
||||
showLineNumber={!noLineNumbers && tokens.length > 1}
|
||||
key={i}
|
||||
lineNumberColorClassName={lineNumbersColor}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
{collapsibleType === "start" &&
|
||||
getCollapsedLinesElm({
|
||||
tokens,
|
||||
highlightProps: rest,
|
||||
})}
|
||||
{getNonCollapsedLinesElm({
|
||||
tokens,
|
||||
highlightProps: rest,
|
||||
})}
|
||||
{collapsibleType === "end" &&
|
||||
getCollapsedLinesElm({
|
||||
tokens,
|
||||
highlightProps: rest,
|
||||
})}
|
||||
</code>
|
||||
</pre>
|
||||
{!title && (
|
||||
@@ -280,6 +369,21 @@ export const CodeBlock = ({
|
||||
isSingleLine={tokens.length <= 1}
|
||||
/>
|
||||
)}
|
||||
{collapsibleType === "end" && (
|
||||
<>
|
||||
<CodeBlockCollapsibleFade
|
||||
type={collapsibleType}
|
||||
collapsed={collapsibleResult.collapsed}
|
||||
hasHeader={hasInnerCodeBlock}
|
||||
/>
|
||||
<CodeBlockCollapsibleButton
|
||||
type={collapsibleType}
|
||||
expandButtonLabel={expandButtonLabel}
|
||||
className={innerBorderClasses}
|
||||
{...collapsibleResult}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Highlight>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import React, { Suspense, cloneElement, useRef, useState } from "react"
|
||||
import { Loading } from "@/components"
|
||||
import clsx from "clsx"
|
||||
import { CSSTransition } from "react-transition-group"
|
||||
import { DetailsSummary } from "./Summary"
|
||||
import { useCollapsible } from "../../hooks"
|
||||
|
||||
export type DetailsProps = {
|
||||
openInitial?: boolean
|
||||
@@ -22,7 +22,11 @@ export const Details = ({
|
||||
...props
|
||||
}: DetailsProps) => {
|
||||
const [open, setOpen] = useState(openInitial)
|
||||
const [showContent, setShowContent] = useState(openInitial)
|
||||
const { getCollapsibleElms, setCollapsed } = useCollapsible({
|
||||
initialValue: !openInitial,
|
||||
heightAnimation,
|
||||
onClose: () => setOpen(false),
|
||||
})
|
||||
const ref = useRef<HTMLDetailsElement>(null)
|
||||
|
||||
const handleToggle = (e: React.MouseEvent<HTMLElement>) => {
|
||||
@@ -36,10 +40,10 @@ export const Details = ({
|
||||
return
|
||||
}
|
||||
if (open) {
|
||||
setShowContent(false)
|
||||
setCollapsed(true)
|
||||
} else {
|
||||
setOpen(true)
|
||||
setShowContent(true)
|
||||
setCollapsed(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,56 +81,11 @@ export const Details = ({
|
||||
open,
|
||||
onClick: handleToggle,
|
||||
})}
|
||||
<CSSTransition
|
||||
unmountOnExit
|
||||
in={showContent}
|
||||
timeout={150}
|
||||
onEnter={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.classList.add("transition-[height]")
|
||||
node.style.height = `0px`
|
||||
} else {
|
||||
node.classList.add(
|
||||
"!mb-docs_2",
|
||||
"!mt-0",
|
||||
"translate-y-docs_1",
|
||||
"transition-transform"
|
||||
)
|
||||
}
|
||||
}}
|
||||
onEntering={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `${node.scrollHeight}px`
|
||||
}
|
||||
}}
|
||||
onEntered={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `auto`
|
||||
}
|
||||
}}
|
||||
onExit={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `${node.scrollHeight}px`
|
||||
} else {
|
||||
node.classList.add("transition-transform", "!-translate-y-docs_1")
|
||||
setTimeout(() => {
|
||||
setOpen(false)
|
||||
}, 100)
|
||||
}
|
||||
}}
|
||||
onExiting={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `0px`
|
||||
setTimeout(() => {
|
||||
setOpen(false)
|
||||
}, 100)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{getCollapsibleElms(
|
||||
<Suspense fallback={<Loading className="!mb-docs_2 !mt-0" />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
</CSSTransition>
|
||||
)}
|
||||
</details>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from "./use-collapsible"
|
||||
export * from "./use-collapsible-code-lines"
|
||||
export * from "./use-copy"
|
||||
export * from "./use-current-learning-path"
|
||||
export * from "./use-is-browser"
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
LineInputProps,
|
||||
LineOutputProps,
|
||||
Token,
|
||||
TokenInputProps,
|
||||
TokenOutputProps,
|
||||
} from "prism-react-renderer"
|
||||
import React, { useCallback, useMemo } from "react"
|
||||
import { CodeBlockCollapsibleLines } from "../../components/CodeBlock/Collapsible/Lines"
|
||||
import { useCollapsible } from "../use-collapsible"
|
||||
|
||||
export type HighlightProps = {
|
||||
getLineProps: (input: LineInputProps) => LineOutputProps
|
||||
getTokenProps: (input: TokenInputProps) => TokenOutputProps
|
||||
}
|
||||
|
||||
export type CollapsibleCodeLines = {
|
||||
collapsibleLinesStr?: string
|
||||
getLines: (
|
||||
token: Token[][],
|
||||
highlightProps: HighlightProps,
|
||||
lineNumberOffset?: number
|
||||
) => React.ReactNode
|
||||
}
|
||||
|
||||
export type CollapsedCodeLinesPosition = "start" | "end"
|
||||
|
||||
export const useCollapsibleCodeLines = ({
|
||||
collapsibleLinesStr,
|
||||
getLines,
|
||||
}: CollapsibleCodeLines) => {
|
||||
const collapsedRange:
|
||||
| {
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
| undefined = useMemo(() => {
|
||||
if (!collapsibleLinesStr) {
|
||||
return
|
||||
}
|
||||
|
||||
const splitCollapsedLines = collapsibleLinesStr
|
||||
.split("-")
|
||||
.map((lineNumber) => parseInt(lineNumber))
|
||||
|
||||
if (
|
||||
splitCollapsedLines.length !== 2 ||
|
||||
(splitCollapsedLines[0] !== 1 && splitCollapsedLines[1] < 2)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
start: splitCollapsedLines[0],
|
||||
end: splitCollapsedLines[1],
|
||||
}
|
||||
}, [collapsibleLinesStr])
|
||||
|
||||
const type: CollapsedCodeLinesPosition | undefined = useMemo(() => {
|
||||
if (!collapsedRange) {
|
||||
return undefined
|
||||
}
|
||||
return collapsedRange.start === 1 ? "start" : "end"
|
||||
}, [collapsedRange])
|
||||
|
||||
const collapsibleHookResult = useCollapsible({
|
||||
unmountOnExit: false,
|
||||
translateEnabled: false,
|
||||
heightAnimation: true,
|
||||
})
|
||||
|
||||
const getCollapsedLinesElm = useCallback(
|
||||
({
|
||||
tokens,
|
||||
highlightProps,
|
||||
}: {
|
||||
tokens: Token[][]
|
||||
highlightProps: HighlightProps
|
||||
}) => {
|
||||
if (!collapsedRange || !type) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const startIndex =
|
||||
type === "start" ? collapsedRange.start - 1 : collapsedRange.start
|
||||
|
||||
const lines = tokens.slice(
|
||||
startIndex,
|
||||
Math.min(collapsedRange.end, tokens.length)
|
||||
)
|
||||
|
||||
return (
|
||||
<CodeBlockCollapsibleLines {...collapsibleHookResult} type={type}>
|
||||
{getLines(lines, highlightProps, startIndex)}
|
||||
</CodeBlockCollapsibleLines>
|
||||
)
|
||||
},
|
||||
[collapsedRange, collapsibleHookResult]
|
||||
)
|
||||
|
||||
const getNonCollapsedLinesElm = useCallback(
|
||||
({
|
||||
tokens,
|
||||
highlightProps,
|
||||
}: {
|
||||
tokens: Token[][]
|
||||
highlightProps: HighlightProps
|
||||
}) => {
|
||||
if (!collapsedRange) {
|
||||
return getLines(tokens, highlightProps)
|
||||
}
|
||||
|
||||
const isCollapseBeginning = collapsedRange.start === 1
|
||||
const lines = tokens.slice(
|
||||
isCollapseBeginning ? collapsedRange.end : 0,
|
||||
isCollapseBeginning ? undefined : collapsedRange.start
|
||||
)
|
||||
|
||||
return getLines(
|
||||
lines,
|
||||
highlightProps,
|
||||
isCollapseBeginning ? collapsedRange.end : 0
|
||||
)
|
||||
},
|
||||
[collapsedRange, collapsibleHookResult]
|
||||
)
|
||||
|
||||
return {
|
||||
getCollapsedLinesElm,
|
||||
getNonCollapsedLinesElm,
|
||||
type,
|
||||
...collapsibleHookResult,
|
||||
}
|
||||
}
|
||||
85
www/packages/docs-ui/src/hooks/use-collapsible/index.tsx
Normal file
85
www/packages/docs-ui/src/hooks/use-collapsible/index.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
"use client"
|
||||
|
||||
import React, { useState } from "react"
|
||||
import { CSSTransition } from "react-transition-group"
|
||||
|
||||
export type CollapsibleProps = {
|
||||
initialValue?: boolean
|
||||
heightAnimation?: boolean
|
||||
translateEnabled?: boolean
|
||||
onClose?: () => void
|
||||
unmountOnExit?: boolean
|
||||
}
|
||||
|
||||
export type CollapsibleReturn = {
|
||||
getCollapsibleElms: (children: React.ReactNode) => React.JSX.Element
|
||||
collapsed: boolean
|
||||
setCollapsed: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
export const useCollapsible = ({
|
||||
initialValue = true,
|
||||
heightAnimation = false,
|
||||
translateEnabled = true,
|
||||
onClose,
|
||||
unmountOnExit = true,
|
||||
}: CollapsibleProps): CollapsibleReturn => {
|
||||
const [collapsed, setCollapsed] = useState(initialValue)
|
||||
|
||||
const getCollapsibleElms = (children: React.ReactNode) => (
|
||||
<CSSTransition
|
||||
unmountOnExit={unmountOnExit}
|
||||
in={!collapsed}
|
||||
timeout={150}
|
||||
onEnter={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.classList.add("transition-[height]")
|
||||
node.style.height = `0px`
|
||||
} else {
|
||||
node.classList.add("!mb-docs_2", "!mt-0")
|
||||
if (translateEnabled) {
|
||||
node.classList.add("translate-y-docs_1", "transition-transform")
|
||||
}
|
||||
}
|
||||
}}
|
||||
onEntering={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `${node.scrollHeight}px`
|
||||
}
|
||||
}}
|
||||
onEntered={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `auto`
|
||||
}
|
||||
}}
|
||||
onExit={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `${node.scrollHeight}px`
|
||||
} else {
|
||||
if (translateEnabled) {
|
||||
node.classList.add("transition-transform", "!-translate-y-docs_1")
|
||||
}
|
||||
setTimeout(() => {
|
||||
onClose?.()
|
||||
}, 100)
|
||||
}
|
||||
}}
|
||||
onExiting={(node: HTMLElement) => {
|
||||
if (heightAnimation) {
|
||||
node.style.height = `0px`
|
||||
setTimeout(() => {
|
||||
onClose?.()
|
||||
}, 100)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</CSSTransition>
|
||||
)
|
||||
|
||||
return {
|
||||
getCollapsibleElms,
|
||||
collapsed,
|
||||
setCollapsed,
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,11 @@ module.exports = {
|
||||
top: "var(--docs-contrast-border-top)",
|
||||
bot: "var(--docs-contrast-border-bot)",
|
||||
},
|
||||
// not in UI but necessary for show more button
|
||||
button: {
|
||||
DEFAULT: "#3D3D3F",
|
||||
hover: "#505052",
|
||||
},
|
||||
},
|
||||
},
|
||||
/* docs defaults */
|
||||
@@ -257,7 +262,13 @@ module.exports = {
|
||||
},
|
||||
backgroundImage: {
|
||||
"code-fade-top-to-bottom": `linear-gradient(180deg, #27272A 0%, rgba(39, 39, 42, 0.00) 100%)`,
|
||||
"code-fade-bottom-to-top": `linear-gradient(180deg, #27272A 0%, rgba(39, 39, 42, 0.00) 100%)`,
|
||||
"code-fade-bottom-to-top": `linear-gradient(180deg, rgba(39, 39, 42, 0.00) 0%, #27272A 100%)`,
|
||||
"base-code-fade-right-to-left": `linear-gradient(90deg, #18181b7d, #18181B)`,
|
||||
"subtle-code-fade-right-to-left": `linear-gradient(90deg, #27272aa3, #27272A)`,
|
||||
"code-fade-top-to-bottom-dark": `linear-gradient(180deg, #2F2F32 0%, rgba(47, 47, 50, 0.00) 100%)`,
|
||||
"code-fade-bottom-to-top-dark": `linear-gradient(180deg, rgba(47, 47, 50, 0.00) 0%, #2F2F32 100%)`,
|
||||
"base-code-fade-right-to-left-dark": `linear-gradient(90deg, #27272aa3, #27272A)`,
|
||||
"subtle-code-fade-right-to-left-dark": `linear-gradient(90deg, #30303380, #303033)`,
|
||||
},
|
||||
screens: {
|
||||
xs: "576px",
|
||||
|
||||
@@ -196,7 +196,7 @@ const dark = {
|
||||
"--docs-contrast-bg-base": "rgba(39, 39, 42, 1)",
|
||||
"--docs-contrast-bg-base-pressed": "rgba(113, 113, 122, 1)",
|
||||
"--docs-contrast-bg-base-hover": "rgba(82, 82, 91, 1)",
|
||||
"--docs-contrast-bg-subtle": "rgba(255, 255, 255, 0.04)",
|
||||
"--docs-contrast-bg-subtle": "rgba(47, 47, 50, 1)",
|
||||
"--docs-contrast-bg-highlight": "rgba(82, 82, 91, 1)",
|
||||
"--docs-contrast-bg-alpha": "rgba(63, 63, 70, 0.9)",
|
||||
"--docs-contrast-fg-primary": "rgba(250, 250, 250, 1)",
|
||||
|
||||
Reference in New Issue
Block a user