From 37455f88f332187204f8be7ef5dd63ff132b7f3d Mon Sep 17 00:00:00 2001 From: Makenna Smutz <32865577+KenzoBenzo@users.noreply.github.com> Date: Tue, 7 May 2024 18:25:46 -0400 Subject: [PATCH] fix: `Tag` component primitive + documentation; + fixes usage bugs (#818) Co-authored-by: Andrew Jiang --- .../api-page/endpoints/EndpointContent.tsx | 6 +- .../endpoints/ErrorCodeSnippetExample.tsx | 2 +- .../PlaygroundEndpointSelector.tsx | 2 +- .../PlaygroundEndpointSelectorContent.tsx | 8 +- packages/ui/app/src/commons/HttpMethodTag.tsx | 81 ++++++++----- packages/ui/app/src/commons/withStream.tsx | 26 ----- packages/ui/app/src/commons/withWss.tsx | 29 ----- .../ui/app/src/components/FernTag.stories.tsx | 108 ++++++++++++++++++ packages/ui/app/src/components/FernTag.tsx | 79 ++++++++++--- .../ui/app/src/sidebar/SidebarApiSection.tsx | 16 ++- .../ui/app/src/util/shared-component-types.ts | 2 + 11 files changed, 239 insertions(+), 120 deletions(-) delete mode 100644 packages/ui/app/src/commons/withStream.tsx delete mode 100644 packages/ui/app/src/commons/withWss.tsx create mode 100644 packages/ui/app/src/components/FernTag.stories.tsx create mode 100644 packages/ui/app/src/util/shared-component-types.ts diff --git a/packages/ui/app/src/api-page/endpoints/EndpointContent.tsx b/packages/ui/app/src/api-page/endpoints/EndpointContent.tsx index 4cfe0592d0..fd1bf8f827 100644 --- a/packages/ui/app/src/api-page/endpoints/EndpointContent.tsx +++ b/packages/ui/app/src/api-page/endpoints/EndpointContent.tsx @@ -5,7 +5,7 @@ import dynamic from "next/dynamic"; import { useRouter } from "next/router"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useInView } from "react-intersection-observer"; -import { withStream } from "../../commons/withStream"; +import { withStream } from "../../commons/HttpMethodTag"; import { useDocsContext } from "../../contexts/docs-context/useDocsContext"; import { useLayoutBreakpoint } from "../../contexts/layout-breakpoint/useLayoutBreakpoint"; import { useViewportSize } from "../../hooks/useViewportSize"; @@ -225,9 +225,9 @@ export const EndpointContent: React.FC = ({
{endpoint.responseBody?.shape.type === "stream" ? ( - withStream(

{endpoint.title}

) + withStream(

{endpoint.title}

, "lg") ) : ( -

{endpoint.title}

+

{endpoint.title}

)} {endpoint.availability != null && ( diff --git a/packages/ui/app/src/api-page/endpoints/ErrorCodeSnippetExample.tsx b/packages/ui/app/src/api-page/endpoints/ErrorCodeSnippetExample.tsx index 5c15050949..c0cbfa4ad7 100644 --- a/packages/ui/app/src/api-page/endpoints/ErrorCodeSnippetExample.tsx +++ b/packages/ui/app/src/api-page/endpoints/ErrorCodeSnippetExample.tsx @@ -41,7 +41,7 @@ export function ErrorCodeSnippetExample({ - {resolvedError.statusCode} + {resolvedError.statusCode} {options.length === 0 ? ( {resolvedError.name} ) : ( diff --git a/packages/ui/app/src/api-playground/PlaygroundEndpointSelector.tsx b/packages/ui/app/src/api-playground/PlaygroundEndpointSelector.tsx index 81a69a77cb..95877703fb 100644 --- a/packages/ui/app/src/api-playground/PlaygroundEndpointSelector.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundEndpointSelector.tsx @@ -4,7 +4,7 @@ import { ChevronDownIcon, SlashIcon } from "@radix-ui/react-icons"; import { TooltipProvider } from "@radix-ui/react-tooltip"; import cn from "clsx"; import { FC, Fragment, useCallback, useRef } from "react"; -import { withStream } from "../commons/withStream"; +import { withStream } from "../commons/HttpMethodTag"; import { FernButton } from "../components/FernButton"; import { usePlaygroundContext } from "./PlaygroundContext"; import { ApiGroup, PlaygroundEndpointSelectorContent } from "./PlaygroundEndpointSelectorContent"; diff --git a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx index 999b86448e..8fbb524b12 100644 --- a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx @@ -6,9 +6,7 @@ import cn from "clsx"; import { noop } from "lodash-es"; import dynamic from "next/dynamic"; import { Fragment, ReactElement, forwardRef, useImperativeHandle, useRef, useState } from "react"; -import { HttpMethodTag } from "../commons/HttpMethodTag"; -import { withStream } from "../commons/withStream"; -import { Chip } from "../components/Chip"; +import { HttpMethodTag, withStream } from "../commons/HttpMethodTag"; import { FernButton } from "../components/FernButton"; import { FernInput } from "../components/FernInput"; import { FernScrollArea } from "../components/FernScrollArea"; @@ -154,7 +152,7 @@ export const PlaygroundEndpointSelectorContent = forwardRef} + rightIcon={} /> @@ -177,7 +175,7 @@ export const PlaygroundEndpointSelectorContent = forwardRef} + rightIcon={} /> diff --git a/packages/ui/app/src/commons/HttpMethodTag.tsx b/packages/ui/app/src/commons/HttpMethodTag.tsx index 1eec2173a1..098e3cdd0a 100644 --- a/packages/ui/app/src/commons/HttpMethodTag.tsx +++ b/packages/ui/app/src/commons/HttpMethodTag.tsx @@ -1,44 +1,63 @@ import { FdrAPI } from "@fern-api/fdr-sdk"; -import cn from "clsx"; -import { memo } from "react"; +import clsx from "clsx"; +import { ReactNode, memo } from "react"; +import { FernTag, FernTagColorScheme, FernTagProps } from "../components/FernTag"; +import { FernTooltip } from "../components/FernTooltip"; + export declare namespace HttpMethodTag { - export interface Props { - method: FdrAPI.api.v1.read.HttpMethod; - small?: boolean; - className?: string; + export interface Props extends FernTagProps { + method: FdrAPI.api.v1.read.HttpMethod | "STREAM" | "WSS"; active?: boolean; } } -const UnmemoizedHttpMethodTag: React.FC = ({ method, small = false, className, active }) => { +const METHOD_COLOR_SCHEMES: Record = { + GET: "green", + DELETE: "red", + POST: "blue", + STREAM: "accent", + WSS: "accent", + PUT: "amber", + PATCH: "amber", +}; + +const UnmemoizedHttpMethodTag: React.FC = ({ + method, + active, + size = "sm", + className, + ...rest +}) => { return ( - {method === FdrAPI.api.v1.read.HttpMethod.Delete ? "DEL" : method} - + ); }; +export function withStream(text: ReactNode, size: "sm" | "lg" = "sm"): ReactNode { + return ( + + {text} + + + ); +} +export function withWss(text: ReactNode, size: "sm" | "lg" = "sm"): ReactNode { + return ( + + {text} + + + + + ); +} + export const HttpMethodTag = memo(UnmemoizedHttpMethodTag); diff --git a/packages/ui/app/src/commons/withStream.tsx b/packages/ui/app/src/commons/withStream.tsx deleted file mode 100644 index 4033e3271e..0000000000 --- a/packages/ui/app/src/commons/withStream.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import cn from "clsx"; -import { ReactElement, ReactNode } from "react"; - -export function StreamTag({ small = false, active = false }: { small?: boolean; active?: boolean }): ReactElement { - return ( - - {"STREAM"} - - ); -} - -export function withStream(text: ReactNode, small?: boolean): ReactNode { - return ( - - {text} - - - ); -} diff --git a/packages/ui/app/src/commons/withWss.tsx b/packages/ui/app/src/commons/withWss.tsx deleted file mode 100644 index 2f38f47002..0000000000 --- a/packages/ui/app/src/commons/withWss.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import cn from "clsx"; -import { ReactElement, ReactNode } from "react"; -import { FernTooltip } from "../components/FernTooltip"; - -export function WssTag({ small = false, active = false }: { small?: boolean; active?: boolean }): ReactElement { - return ( - - - {"WSS"} - - - ); -} - -export function withWss(text: ReactNode, small?: boolean): ReactNode { - return ( - - {text} - - - ); -} diff --git a/packages/ui/app/src/components/FernTag.stories.tsx b/packages/ui/app/src/components/FernTag.stories.tsx new file mode 100644 index 0000000000..ee4176fb3e --- /dev/null +++ b/packages/ui/app/src/components/FernTag.stories.tsx @@ -0,0 +1,108 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { FernTag, FernTagColorSchemes, FernTagSizes } from "./FernTag"; + +const methods = ["test", "get", "post", "put", "patch", "delete", "stream", "wss"]; + +const meta: Meta = { + title: "General/FernTag", + component: FernTag, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + args: { + children: "Test", + size: "lg", + variant: "subtle", + colorScheme: "gray", + }, + argTypes: { + size: { + options: ["sm", "lg"], + control: { type: "select" }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; + +export const ColorSchemes: Story = { + argTypes: { + colorScheme: { + control: false, + }, + }, + render: (args) => { + const colorSchemes = Object.values(FernTagColorSchemes); + return ( +
+ {colorSchemes.map((colorScheme, i) => ( + + ))} +
+ ); + }, +}; + +export const Sizes: Story = { + argTypes: { + size: { + control: false, + }, + }, + render: (args) => { + const sizes = Object.values(FernTagSizes); + return ( +
+ {sizes.map((size, i) => ( + + ))} +
+ ); + }, +}; + +export const Solid: Story = { + args: { + variant: "solid", + }, +}; + +export const ClassNameOverrides: Story = { + args: { + size: "sm", + className: "w-11 uppercase", + }, + render: (args) => { + return ( +
+ {methods.map((method) => ( + + {method === "DELETE" ? "DEL" : method} + + ))} +
+ ); + }, +}; diff --git a/packages/ui/app/src/components/FernTag.tsx b/packages/ui/app/src/components/FernTag.tsx index 9010d4d3c3..1416d69d09 100644 --- a/packages/ui/app/src/components/FernTag.tsx +++ b/packages/ui/app/src/components/FernTag.tsx @@ -1,28 +1,77 @@ -import cn from "clsx"; -import { PropsWithChildren, ReactElement } from "react"; +import { clsx } from "clsx"; +import { FC, PropsWithChildren } from "react"; +import { ColorScheme, Size } from "../util/shared-component-types"; -interface FernTagProps extends PropsWithChildren { +export type FernTagSize = Extract; +export const FernTagSizes: { [key: string]: FernTagSize } = { + Small: "sm", + Large: "lg", +}; + +export type FernTagColorScheme = ColorScheme; +export const FernTagColorSchemes: { [key: string]: FernTagColorScheme } = { + Gray: "gray", + Green: "green", + Blue: "blue", + Amber: "amber", + Red: "red", + Accent: "accent", +}; + +export interface FernTagProps extends PropsWithChildren { + size?: FernTagSize; + variant?: "subtle" | "solid"; + colorScheme?: FernTagColorScheme; className?: string; - intent?: "none" | "success" | "warning" | "danger" | "accent"; } -export function FernTag({ children, className, intent = "none" }: FernTagProps): ReactElement { +/** + * The `FernTag` component is used for items that need to be labeled, categorized, or organized using keywords that describe them. + */ +export const FernTag: FC = ({ + children, + size = "lg", + variant = "subtle", + colorScheme = "gray", + className, +}) => { return ( - {children} - +
); -} +}; diff --git a/packages/ui/app/src/sidebar/SidebarApiSection.tsx b/packages/ui/app/src/sidebar/SidebarApiSection.tsx index b854464776..67ce20a311 100644 --- a/packages/ui/app/src/sidebar/SidebarApiSection.tsx +++ b/packages/ui/app/src/sidebar/SidebarApiSection.tsx @@ -7,8 +7,6 @@ import { isEqual, last, sortBy } from "lodash-es"; import { ReactElement, ReactNode, memo, useCallback, useMemo } from "react"; import { areApiArtifactsNonEmpty } from "../api-page/artifacts/areApiArtifactsNonEmpty"; import { HttpMethodTag } from "../commons/HttpMethodTag"; -import { StreamTag } from "../commons/withStream"; -import { WssTag } from "../commons/withWss"; import { FernErrorTag } from "../components/FernErrorBoundary"; import { API_ARTIFACTS_TITLE } from "../config"; import { useNavigationContext } from "../contexts/navigation-context"; @@ -208,11 +206,11 @@ function SidebarApiSlugLink({ item, registerScrolledToPathListener, depth, api } const selected = isEqual(item.slug, selectedSlug); const httpMethodTags: Record = { - GET: , - POST: , - PUT: , - PATCH: , - DELETE: , + GET: , + POST: , + PUT: , + PATCH: , + DELETE: , }; return ( + ) : ( httpMethodTags[item.method] ) ) : item.apiType === "websocket" ? ( - + ) : null ) : null } diff --git a/packages/ui/app/src/util/shared-component-types.ts b/packages/ui/app/src/util/shared-component-types.ts new file mode 100644 index 0000000000..8ea67e0405 --- /dev/null +++ b/packages/ui/app/src/util/shared-component-types.ts @@ -0,0 +1,2 @@ +export type ColorScheme = "accent" | "gray" | "blue" | "green" | "amber" | "red"; +export type Size = "xs" | "sm" | "md" | "lg" | "xl";