diff --git a/common/changes/@typespec/html-program-viewer/feature-themable-html-program-viewer_2023-11-09-20-22.json b/common/changes/@typespec/html-program-viewer/feature-themable-html-program-viewer_2023-11-09-20-22.json new file mode 100644 index 0000000000..076b3e344f --- /dev/null +++ b/common/changes/@typespec/html-program-viewer/feature-themable-html-program-viewer_2023-11-09-20-22.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/html-program-viewer", + "comment": "Add ability to change colors of the program viewer using css variables. A `ColorProvider` component is also provided for convenience.", + "type": "none" + } + ], + "packageName": "@typespec/html-program-viewer" +} diff --git a/common/changes/@typespec/playground/feature-themable-html-program-viewer_2023-11-09-20-22.json b/common/changes/@typespec/playground/feature-themable-html-program-viewer_2023-11-09-20-22.json new file mode 100644 index 0000000000..3007c546a8 --- /dev/null +++ b/common/changes/@typespec/playground/feature-themable-html-program-viewer_2023-11-09-20-22.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/playground", + "comment": "Configure the program viewer to respect the color theme", + "type": "none" + } + ], + "packageName": "@typespec/playground" +} \ No newline at end of file diff --git a/packages/html-program-viewer/src/color-provider.tsx b/packages/html-program-viewer/src/color-provider.tsx new file mode 100644 index 0000000000..8cc881cd8f --- /dev/null +++ b/packages/html-program-viewer/src/color-provider.tsx @@ -0,0 +1,19 @@ +import { FunctionComponent, ReactNode, useMemo } from "react"; +import { ColorPalette, ColorVariable, ColorsVariables } from "./constants.js"; + +export interface ColorProviderProps { + colors: Partial; + children?: ReactNode; +} + +export const ColorProvider: FunctionComponent = ({ children, colors }) => { + const cssVariables = useMemo(() => { + const colorArray: [ColorVariable, string][] = Object.entries(colors) as any; + return Object.fromEntries( + colorArray.map(([key, value]) => { + return [ColorsVariables[key], value]; + }) + ); + }, [colors]); + return
{children}
; +}; diff --git a/packages/html-program-viewer/src/common.tsx b/packages/html-program-viewer/src/common.tsx index a3f86fa4f2..b0c5cc8f6d 100644 --- a/packages/html-program-viewer/src/common.tsx +++ b/packages/html-program-viewer/src/common.tsx @@ -1,46 +1,8 @@ -import { css } from "@emotion/react"; -import { FunctionComponent, PropsWithChildren, ReactElement } from "react"; +import { FunctionComponent, ReactElement } from "react"; import { Colors } from "./constants.js"; -export interface ItemProps { - title: string; - id?: string; - hide?: boolean; -} - -const ItemStyles = css({ - border: "1px solid #c5c5c5", -}); - -const ItemTitleStyles = css({ - border: "1px solid #c5c5c5", - backgroundColor: "#dedede", - padding: "2px 5px", -}); - -const ItemContentStyles = css({ - padding: "1rem", -}); - -export const Item: FunctionComponent> = ({ - id, - title, - hide, - children, -}) => { - if (hide) { - return
; - } - return ( -
-
{title}
-
{children}
-
- ); -}; - export const Literal: FunctionComponent<{ children: any }> = ({ children }) => ( -
{children}
+
{children}
); export const KeyValueSection: FunctionComponent<{ children: ReactElement | ReactElement[] }> = ({ diff --git a/packages/html-program-viewer/src/constants.ts b/packages/html-program-viewer/src/constants.ts index 220c9e5bda..d2c9d87f85 100644 --- a/packages/html-program-viewer/src/constants.ts +++ b/packages/html-program-viewer/src/constants.ts @@ -1,4 +1,28 @@ -export const Colors = { - typeKind: "#7a3e9d", +const variablePrefix = `--tsp-tgv`; +export const ColorsVariables = { + background: `${variablePrefix}-background`, + dataKey: `${variablePrefix}-data-key`, + indentationGuide: `${variablePrefix}-indentation-guide`, + literal: `${variablePrefix}-literal`, + property: `${variablePrefix}-property`, + ref: `${variablePrefix}-ref`, + typeKind: `${variablePrefix}-type-kind`, + typeName: `${variablePrefix}-type-name`, +} as const; + +export type ColorVariable = keyof typeof ColorsVariables; +export type ColorPalette = Record; +export const DefaultColors: ColorPalette = { + background: "#f3f3f3", + dataKey: "#333333", indentationGuide: "#777", + literal: "#5da713", + property: "#9c5d27", + ref: "#268bd2", + typeKind: "#7a3e9d", + typeName: "#333333", }; + +export const Colors: typeof ColorsVariables = Object.fromEntries( + Object.entries(ColorsVariables).map(([k, v]) => [k, `var(${v}, ${(DefaultColors as any)[k]})`]) +) as any; diff --git a/packages/html-program-viewer/src/index.ts b/packages/html-program-viewer/src/index.ts index 1789ee445b..dd9bb34234 100644 --- a/packages/html-program-viewer/src/index.ts +++ b/packages/html-program-viewer/src/index.ts @@ -1,2 +1,4 @@ +export { ColorProvider, ColorProviderProps } from "./color-provider.js"; +export type { ColorPalette } from "./constants.js"; export * from "./emitter.js"; export { TypeSpecProgramViewer } from "./ui.js"; diff --git a/packages/html-program-viewer/src/type-ui-base.tsx b/packages/html-program-viewer/src/type-ui-base.tsx index 2ec0b8ac90..7b54fed8f6 100644 --- a/packages/html-program-viewer/src/type-ui-base.tsx +++ b/packages/html-program-viewer/src/type-ui-base.tsx @@ -24,7 +24,7 @@ export interface TypeUIBaseProps { const TypeNameStyles = css({ display: "inline", - color: "#333333", + color: Colors.typeName, }); export const TypeUIBase: FunctionComponent = (props) => { @@ -32,7 +32,7 @@ export const TypeUIBase: FunctionComponent = (props) => { const properties = props.properties.map((prop) => { return (
  • - + {prop.name} : {prop.value} diff --git a/packages/html-program-viewer/src/ui.tsx b/packages/html-program-viewer/src/ui.tsx index 40097b138c..e1fcf10490 100644 --- a/packages/html-program-viewer/src/ui.tsx +++ b/packages/html-program-viewer/src/ui.tsx @@ -18,6 +18,7 @@ import { import React, { FunctionComponent, ReactElement, useContext } from "react"; import ReactDOMServer from "react-dom/server"; import { KeyValueSection, Literal } from "./common.js"; +import { Colors } from "./constants.js"; import { inspect } from "./inspect.js"; import { TypeUIBase, TypeUIBaseProperty } from "./type-ui-base.js"; import { getIdForType, isNamedUnion } from "./utils.js"; @@ -39,7 +40,7 @@ export interface TypeSpecProgramViewerProps { const ProgramViewerStyles = css({ fontFamily: "monospace", - backgroundColor: "#f3f3f3", + backgroundColor: Colors.background, li: { margin: 0, listStyle: "none", @@ -347,7 +348,7 @@ const NamedTypeRef: FunctionComponent<{ type: NamedType }> = ({ type }) => { return ( = ({ type }) => { {entries.map(([k, v], i) => (
    -
    {k.toString()}:
    {" "} +
    {k.toString()}:
    {" "}
    {inspect(v)}
    ))} diff --git a/packages/playground/src/react/output-view.tsx b/packages/playground/src/react/output-view.tsx index 144b21a224..76955dd503 100644 --- a/packages/playground/src/react/output-view.tsx +++ b/packages/playground/src/react/output-view.tsx @@ -1,7 +1,7 @@ import { css } from "@emotion/react"; import { tokens } from "@fluentui/react-components"; import { Diagnostic, Program } from "@typespec/compiler"; -import { TypeSpecProgramViewer } from "@typespec/html-program-viewer"; +import { ColorPalette, ColorProvider, TypeSpecProgramViewer } from "@typespec/html-program-viewer"; import { FunctionComponent, useCallback, useEffect, useMemo, useState } from "react"; import { ErrorTab, InternalCompilerError } from "./error-tab.js"; import { FileOutput } from "./file-output.js"; @@ -159,7 +159,7 @@ const OutputContent: FunctionComponent = ({ overflow: "scroll", }} > - {program && } + {program && } ); } @@ -185,3 +185,25 @@ const ErrorTabCountStyles = css({ padding: "0 5px", borderRadius: "20px", }); + +interface TypeGraphViewerProps { + program: Program; +} +const TypeGraphViewer = ({ program }: TypeGraphViewerProps) => { + return ( + + + + ); +}; + +const TypeGraphColors: ColorPalette = { + background: tokens.colorNeutralBackground1, + typeKind: tokens.colorPaletteBerryForeground2, + typeName: tokens.colorNeutralForeground2, + dataKey: tokens.colorNeutralForeground2, + ref: tokens.colorBrandForeground1, + literal: tokens.colorPaletteLightGreenForeground2, + indentationGuide: tokens.colorNeutralForeground4, + property: tokens.colorPaletteMarigoldForeground2, +};