diff --git a/www/apps/api-reference/components/Tags/Operation/DescriptionSection/index.tsx b/www/apps/api-reference/components/Tags/Operation/DescriptionSection/index.tsx index 6dd71eda2d..d800958979 100644 --- a/www/apps/api-reference/components/Tags/Operation/DescriptionSection/index.tsx +++ b/www/apps/api-reference/components/Tags/Operation/DescriptionSection/index.tsx @@ -67,6 +67,14 @@ const TagsOperationDescriptionSection = ({ workflow={operation["x-workflow"]} /> )} + {operation.externalDocs && ( + <> + Related guide:{" "} + + {operation.externalDocs.description || "Read More"} + + + )} - {operation.externalDocs && ( - <> - Related guide:{" "} - - {operation.externalDocs.description || "Read More"} - - - )} {operation.security && ( { - let typeDescription: React.ReactNode = <> - switch (true) { - case schema.type === "object": - typeDescription = ( - <> - {schema.type} {schema.title ? `(${schema.title})` : ""} - {schema.nullable ? ` or null` : ""} - - ) - break - case schema.type === "array": - typeDescription = ( - <> - {schema.type === "array" && formatArrayDescription(schema.items)} - {schema.nullable ? ` or null` : ""} - - ) - break - case schema.anyOf !== undefined: - case schema.allOf !== undefined: - typeDescription = ( - <> - {formatUnionDescription(schema.allOf)} - {schema.nullable ? ` or null` : ""} - - ) - break - case schema.oneOf !== undefined: - typeDescription = ( - <> - {schema.oneOf?.map((item, index) => ( - - {index !== 0 && <> or } - {item.type !== "array" && <>{item.title || item.type}} - {item.type === "array" && ( - <>array{item.items.type ? ` of ${item.items.type}s` : ""} - )} - - ))} - {schema.nullable ? ` or null` : ""} - - ) - break - default: - typeDescription = ( - <> - {!schema.type ? "any" : schema.type} - {schema.nullable ? ` or null` : ""} - {schema.format ? ` <${schema.format}>` : ""} - - ) - } return ( -
- {typeDescription} +
{schema.default !== undefined && ( - <> -
- - Default:{" "} - - {JSON.stringify(schema.default)} - - - + + Default:{" "} + + {JSON.stringify(schema.default)} + + )} {schema.enum && ( - <> -
- - Enum:{" "} - {schema.enum.map((value, index) => ( - - {index !== 0 && <>, } - {JSON.stringify(value)} - - ))} - - + + Enum:{" "} + {schema.enum.map((value, index) => ( + + {index !== 0 && <>, } + {JSON.stringify(value)} + + ))} + )} {schema.example !== undefined && ( - <> -
- - Example:{" "} - - {JSON.stringify(schema.example)} - - - + + Example:{" "} + + {JSON.stringify(schema.example)} + + )} {schema.description && ( <> -
*]:!mb-0")} @@ -120,33 +57,15 @@ const TagOperationParametersDescription = ({ )} {schema.externalDocs && ( - <> + Related guide:{" "} {schema.externalDocs.description || "Read More"} - + )}
) } export default TagOperationParametersDescription - -function formatArrayDescription(schema?: SchemaObject) { - if (!schema) { - return "Array" - } - - const type = - schema.type === "object" - ? `objects ${schema.title ? `(${schema.title})` : ""}` - : `${schema.type || "object"}s` - - return `Array of ${type}` -} - -function formatUnionDescription(arr?: SchemaObject[]) { - const types = [...new Set(arr?.map((type) => type.type || "object"))] - return <>{types.join(" or ")} -} diff --git a/www/apps/api-reference/components/Tags/Operation/Parameters/Name/index.tsx b/www/apps/api-reference/components/Tags/Operation/Parameters/Name/index.tsx index 465b5e8c31..c42e065301 100644 --- a/www/apps/api-reference/components/Tags/Operation/Parameters/Name/index.tsx +++ b/www/apps/api-reference/components/Tags/Operation/Parameters/Name/index.tsx @@ -1,5 +1,6 @@ import type { SchemaObject } from "@/types/openapi" import { Badge, ExpandableNotice, FeatureFlagNotice } from "docs-ui" +import { Fragment } from "react" export type TagOperationParametersNameProps = { name: string @@ -12,39 +13,101 @@ const TagOperationParametersName = ({ isRequired, schema, }: TagOperationParametersNameProps) => { + let typeDescription: React.ReactNode = <> + switch (true) { + case schema.type === "object": + typeDescription = ( + <> + {schema.type} {schema.title ? `(${schema.title})` : ""} + {schema.nullable ? ` or null` : ""} + + ) + break + case schema.type === "array": + typeDescription = ( + <> + {schema.type === "array" && formatArrayDescription(schema.items)} + {schema.nullable ? ` or null` : ""} + + ) + break + case schema.anyOf !== undefined: + case schema.allOf !== undefined: + typeDescription = ( + <> + {formatUnionDescription(schema.allOf)} + {schema.nullable ? ` or null` : ""} + + ) + break + case schema.oneOf !== undefined: + typeDescription = ( + <> + {schema.oneOf?.map((item, index) => ( + + {index !== 0 && <> or } + {item.type !== "array" && <>{item.title || item.type}} + {item.type === "array" && ( + <>array{item.items.type ? ` of ${item.items.type}s` : ""} + )} + + ))} + {schema.nullable ? ` or null` : ""} + + ) + break + default: + typeDescription = ( + <> + {!schema.type ? "any" : schema.type} + {schema.nullable ? ` or null` : ""} + {schema.format ? ` <${schema.format}>` : ""} + + ) + } + return ( - + {name} + + {typeDescription} + {schema.deprecated && ( deprecated )} {schema["x-expandable"] && ( - <> -
- - + )} {schema["x-featureFlag"] && ( - <> -
- - + )} - {isRequired && ( - <> -
- - required - - + {!isRequired && ( + + optional + )}
) } export default TagOperationParametersName + +function formatArrayDescription(schema?: SchemaObject) { + if (!schema) { + return "Array" + } + + const type = + schema.type === "object" + ? `objects ${schema.title ? `(${schema.title})` : ""}` + : `${schema.type || "object"}s` + + return `Array of ${type}` +} + +function formatUnionDescription(arr?: SchemaObject[]) { + const types = [...new Set(arr?.map((type) => type.type || "object"))] + return <>{types.join(" or ")} +} diff --git a/www/apps/api-reference/components/Tags/Operation/Parameters/Types/Default/index.tsx b/www/apps/api-reference/components/Tags/Operation/Parameters/Types/Default/index.tsx index 6102282e4b..96b443e0d4 100644 --- a/www/apps/api-reference/components/Tags/Operation/Parameters/Types/Default/index.tsx +++ b/www/apps/api-reference/components/Tags/Operation/Parameters/Types/Default/index.tsx @@ -21,7 +21,7 @@ const TagOperationParametersDefault = ({ return (
{sortedProperties.map((property, index) => ( - + <> + {index !== 0 &&
} + + ))} ) diff --git a/www/apps/api-reference/components/Tags/Section/Schema/index.tsx b/www/apps/api-reference/components/Tags/Section/Schema/index.tsx index 0801d54630..c542fe2db9 100644 --- a/www/apps/api-reference/components/Tags/Section/Schema/index.tsx +++ b/www/apps/api-reference/components/Tags/Section/Schema/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from "react" +import { useEffect, useMemo, useRef, useState } from "react" import { SchemaObject } from "../../../../types/openapi" import TagOperationParameters from "../../Operation/Parameters" import { @@ -16,6 +16,8 @@ import useSchemaExample from "../../../../hooks/use-schema-example" import { InView } from "react-intersection-observer" import checkElementInViewport from "../../../../utils/check-element-in-viewport" import { singular } from "pluralize" +import useResizeObserver from "@react-hook/resize-observer" +import clsx from "clsx" export type TagSectionSchemaProps = { schema: SchemaObject @@ -23,6 +25,8 @@ export type TagSectionSchemaProps = { } const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => { + const paramsRef = useRef(null) + const [maxCodeHeight, setMaxCodeHeight] = useState(0) const { addItems, setActivePath, activePath } = useSidebar() const tagSlugName = useMemo(() => getSectionId([tagName]), [tagName]) const formattedName = useMemo( @@ -39,6 +43,9 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => { skipNonRequired: false, }, }) + useResizeObserver(paramsRef, () => { + setMaxCodeHeight(paramsRef.current?.clientHeight || 0) + }) const { scrollableElement, scrollToElement } = useScrollController() const root = useMemo(() => { @@ -106,7 +113,7 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => { > +

{formattedName} Object

Fields @@ -121,6 +128,11 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => { source={examples[0].content} lang="json" title={`The ${formattedName} Object`} + className={clsx(maxCodeHeight && "overflow-auto")} + style={{ + // remove padding + extra space + maxHeight: maxCodeHeight ? maxCodeHeight - 212 : "unset", + }} /> )} diff --git a/www/apps/api-reference/components/Tags/Section/index.tsx b/www/apps/api-reference/components/Tags/Section/index.tsx index 42527c0860..2c318afc62 100644 --- a/www/apps/api-reference/components/Tags/Section/index.tsx +++ b/www/apps/api-reference/components/Tags/Section/index.tsx @@ -74,7 +74,7 @@ const TagSection = ({ tag }: TagSectionProps) => { return isElmWindow(scrollableElement) ? document.body : scrollableElement }, [scrollableElement]) const { ref } = useInView({ - threshold: 0.5, + threshold: 0.8, rootMargin: `112px 0px 112px 0px`, root, onChange: (inView) => { diff --git a/www/apps/api-reference/package.json b/www/apps/api-reference/package.json index 1d6b2d3c92..40cbd473f3 100644 --- a/www/apps/api-reference/package.json +++ b/www/apps/api-reference/package.json @@ -18,6 +18,7 @@ "@medusajs/icons": "preview", "@medusajs/ui": "^3.0.0", "@next/mdx": "14.2.14", + "@react-hook/resize-observer": "^2.0.2", "@readme/openapi-parser": "^2.5.0", "@types/mapbox__rehype-prism": "^0.8.0", "@types/mdx": "^2.0.5", diff --git a/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx index 7544ac1685..7deb8bc8fe 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx @@ -15,7 +15,7 @@ export type CodeBlockActionsProps = { inInnerCode?: boolean isCollapsed: boolean canShowApiTesting?: boolean - onApiTesting: React.Dispatch> + onApiTesting?: React.Dispatch> noReport?: boolean noCopy?: boolean } @@ -91,7 +91,7 @@ export const CodeBlockActions = ({ inHeader && "p-[4.5px]", "cursor-pointer" )} - onClick={() => onApiTesting(true)} + onClick={() => onApiTesting?.(true)} > diff --git a/www/packages/docs-ui/src/components/CodeBlock/Header/Wrapper/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Header/Wrapper/index.tsx new file mode 100644 index 0000000000..5f7b1d9549 --- /dev/null +++ b/www/packages/docs-ui/src/components/CodeBlock/Header/Wrapper/index.tsx @@ -0,0 +1,46 @@ +import clsx from "clsx" +import React, { useMemo } from "react" +import { useColorMode } from "../../../../providers" +import { CodeBlockStyle } from "../../../.." + +type CodeBlockHeaderWrapperProps = { + blockStyle?: CodeBlockStyle + children: React.ReactNode +} + +export const CodeBlockHeaderWrapper = React.forwardRef< + HTMLDivElement, + CodeBlockHeaderWrapperProps +>(function CodeBlockHeaderWrapper({ children, blockStyle = "loud" }, ref) { + const { colorMode } = useColorMode() + + const bgColor = useMemo( + () => + clsx( + blockStyle === "loud" && "bg-medusa-contrast-bg-base", + blockStyle === "subtle" && [ + colorMode === "light" && "bg-medusa-bg-component", + colorMode === "dark" && "bg-medusa-code-bg-header", + ] + ), + [blockStyle, colorMode] + ) + + return ( +
+ {children} +
+ ) +}) diff --git a/www/packages/docs-ui/src/components/CodeBlock/Header/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Header/index.tsx index 19fa820836..b6be62c9d8 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/Header/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/Header/index.tsx @@ -6,6 +6,7 @@ import { CodeBlockStyle } from ".." import { useColorMode } from "@/providers" import { Badge, BadgeVariant } from "@/components" import { CodeBlockActions, CodeBlockActionsProps } from "../Actions" +import { CodeBlockHeaderWrapper } from "./Wrapper" export type CodeBlockHeaderMeta = { badgeLabel?: string @@ -27,17 +28,6 @@ export const CodeBlockHeader = ({ }: CodeBlockHeaderProps) => { const { colorMode } = useColorMode() - const bgColor = useMemo( - () => - clsx( - blockStyle === "loud" && "bg-medusa-contrast-bg-base", - blockStyle === "subtle" && [ - colorMode === "light" && "bg-medusa-bg-component", - colorMode === "dark" && "bg-medusa-code-bg-header", - ] - ), - [blockStyle, colorMode] - ) const titleColor = useMemo( () => clsx( @@ -51,18 +41,7 @@ export const CodeBlockHeader = ({ ) return ( -
+
{badgeLabel && ( @@ -76,6 +55,6 @@ export const CodeBlockHeader = ({ )}
-
+ ) } diff --git a/www/packages/docs-ui/src/components/CodeBlock/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/index.tsx index 541215447e..7f3392efef 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/index.tsx @@ -51,6 +51,7 @@ export type CodeBlockProps = { collapsed?: boolean blockStyle?: CodeBlockStyle children?: React.ReactNode + style?: React.HTMLAttributes["style"] } & CodeBlockMetaFields & Omit @@ -71,6 +72,7 @@ export const CodeBlock = ({ collapsibleLines, expandButtonLabel, isTerminal, + style, ...rest }: CodeBlockProps) => { if (!source && typeof children === "string") { @@ -92,10 +94,14 @@ export const CodeBlock = ({ : isTerminal }, [isTerminal, lang]) const codeTitle = useMemo(() => { - if (title || hasTabs) { + if (title) { return title } + if (hasTabs) { + return "" + } + if (isTerminalCode) { return "Terminal" } @@ -329,6 +335,7 @@ export const CodeBlock = ({ !hasInnerCodeBlock && "rounded-docs_DEFAULT", className )} + style={style} > { + if (!selectedTab) { + return + } + + return { + source: selectedTab?.codeProps.source, + blockStyle, + noReport: selectedTab?.codeProps.noReport, + noCopy: selectedTab?.codeProps.noCopy, + inInnerCode: true, + showGradientBg: false, + inHeader: true, + isCollapsed: false, + } + }, [selectedTab]) + return (
-
+ )} -
+ {actionsProps && } + {selectedTab?.codeBlock}
) diff --git a/www/yarn.lock b/www/yarn.lock index 836b0527fe..8d62faaf16 100644 --- a/www/yarn.lock +++ b/www/yarn.lock @@ -3197,6 +3197,18 @@ __metadata: languageName: node linkType: hard +"@react-hook/resize-observer@npm:^2.0.2": + version: 2.0.2 + resolution: "@react-hook/resize-observer@npm:2.0.2" + dependencies: + "@react-hook/latest": ^1.0.2 + "@react-hook/passive-layout-effect": ^1.2.0 + peerDependencies: + react: ">=18" + checksum: a88f088bd5b87fea80daca391bdea9823dc38651bd112f0c607b057d9c8381f37395cf5a01a79ba7ab24369c4b48acf912cfef0244e6610d72ea3074415e9c32 + languageName: node + linkType: hard + "@react-stately/datepicker@npm:^3.5.0, @react-stately/datepicker@npm:^3.9.2": version: 3.9.2 resolution: "@react-stately/datepicker@npm:3.9.2" @@ -5553,6 +5565,7 @@ __metadata: "@medusajs/ui": ^3.0.0 "@next/bundle-analyzer": ^14.2.14 "@next/mdx": 14.2.14 + "@react-hook/resize-observer": ^2.0.2 "@readme/openapi-parser": ^2.5.0 "@types/jsdom": ^21.1.1 "@types/mapbox__rehype-prism": ^0.8.0