Skip to content

Commit

Permalink
Add storybook for playground library (#3412)
Browse files Browse the repository at this point in the history
Don't include it anwhere but this will help showcasing all the
components available in the playground.


![image](https://github.com/microsoft/typespec/assets/1031227/8a7e130f-2e3f-4149-9f33-ed8991950ea2)
  • Loading branch information
timotheeguerin committed May 24, 2024
1 parent 9a10990 commit 42e72b8
Show file tree
Hide file tree
Showing 41 changed files with 2,473 additions and 455 deletions.
8 changes: 8 additions & 0 deletions .chronus/changes/playground-storybook-2024-4-22-18-10-6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/playground"
---

Add storybook for playground library
12 changes: 12 additions & 0 deletions packages/playground/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
stories: ["../stories/**/*.stories.@(ts|tsx)"],
framework: "@storybook/react-vite",
typescript: {
reactDocgen: false,
},
addons: ["@storybook/addon-actions"],
};

export default config;
16 changes: 16 additions & 0 deletions packages/playground/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
import type { Preview } from "@storybook/react";

const preview: Preview = {
decorators: [
(Story, { parameters }) => {
return (
<FluentProvider theme={webLightTheme}>
<Story />
</FluentProvider>
);
},
],
};

export default preview;
8 changes: 8 additions & 0 deletions packages/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
"clean": "rimraf ./dist ./dist-dev ./temp ./typespecContents.json",
"build": "vite build",
"watch": "vite build --watch",
"storybook": "sb dev",
"build: storybook": "sb build",
"copy-css": "copyfiles -u 1 src/**/*.module.css dist/src",
"preview": "npm run build && vite preview",
"start": "vite",
Expand Down Expand Up @@ -91,6 +93,12 @@
"devDependencies": {
"@babel/core": "^7.24.5",
"@playwright/test": "^1.44.0",
"@storybook/addon-actions": "^8.1.2",
"@storybook/cli": "^8.1.2",
"@storybook/react": "^8.1.2",
"@storybook/react-vite": "^8.1.2",
"@storybook/test": "^8.1.2",
"@storybook/types": "^8.1.2",
"@types/debounce": "~1.2.4",
"@types/node": "~18.11.19",
"@types/react": "~18.3.2",
Expand Down
89 changes: 56 additions & 33 deletions packages/playground/src/browser-host.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,52 @@
import { createSourceFile, getSourceFileKindFromExt, resolvePath } from "@typespec/compiler";
import { LibraryImportOptions, importLibrary, importTypeSpecCompiler } from "./core.js";
import { BrowserHost, PlaygroundTspLibrary } from "./types.js";
import { importLibrary, importTypeSpecCompiler, type LibraryImportOptions } from "./core.js";
import type { BrowserHost, PlaygroundTspLibrary } from "./types.js";

export function resolveVirtualPath(path: string, ...paths: string[]) {
return resolvePath("/test", path, ...paths);
}

/**
* Create the browser host from the list of libraries.
* @param libsToLoad List of libraries to load. Those must be set in the webpage importmap.
* @param importOptions Import configuration.
* @returns
* @internal
*/
export async function createBrowserHost(
libsToLoad: readonly string[],
importOptions: LibraryImportOptions = {}
): Promise<BrowserHost> {
export interface BrowserHostCreateOptions {
readonly compiler: typeof import("@typespec/compiler");
readonly libraries: Record<string, PlaygroundTspLibrary & { _TypeSpecLibrary_: any }>;
}

/**
* @internal
*/
export function createBrowserHostInternal(options: BrowserHostCreateOptions): BrowserHost {
const virtualFs = new Map<string, string>();
const jsImports = new Map<string, Promise<any>>();

const libraries: Record<string, PlaygroundTspLibrary> = {};
for (const libName of libsToLoad) {
const { _TypeSpecLibrary_, $lib, $linter } = (await importLibrary(
libName,
importOptions
)) as any;
libraries[libName] = {
name: libName,
isEmitter: $lib?.emitter,
definition: $lib,
packageJson: JSON.parse(_TypeSpecLibrary_.typespecSourceFiles["package.json"]),
linter: $linter,
};
const libraries = options.libraries;
for (const [libName, { _TypeSpecLibrary_ }] of Object.entries(libraries)) {
for (const [key, value] of Object.entries<any>(_TypeSpecLibrary_.typespecSourceFiles)) {
virtualFs.set(`/test/node_modules/${libName}/${key}`, value);
}
for (const [key, value] of Object.entries<any>(_TypeSpecLibrary_.jsSourceFiles)) {
addJsImport(`/test/node_modules/${libName}/${key}`, value);
}
virtualFs.set(
`/test/package.json`,
JSON.stringify({
name: "playground-pkg",
dependencies: Object.fromEntries(
Object.values(libraries).map((x) => [x.name, x.packageJson.version])
),
})
);
}

virtualFs.set(
`/test/package.json`,
JSON.stringify({
name: "playground-pkg",
dependencies: Object.fromEntries(
Object.values(libraries).map((x) => [x.name, x.packageJson.version])
),
})
);

function addJsImport(path: string, value: any) {
virtualFs.set(path, "");
jsImports.set(path, value);
}
return {
compiler: await importTypeSpecCompiler(importOptions),
compiler: options.compiler,
libraries,
async readUrl(url: string) {
const contents = virtualFs.get(url);
Expand Down Expand Up @@ -177,3 +169,34 @@ export async function createBrowserHost(
},
};
}

/**
* Create the browser host from the list of libraries.
* @param libsToLoad List of libraries to load. Those must be set in the webpage importmap.
* @param importOptions Import configuration.
* @returns
*/
export async function createBrowserHost(
libsToLoad: readonly string[],
importOptions: LibraryImportOptions = {}
): Promise<BrowserHost> {
const libraries: Record<string, PlaygroundTspLibrary & { _TypeSpecLibrary_: any }> = {};
for (const libName of libsToLoad) {
const { _TypeSpecLibrary_, $lib, $linter } = (await importLibrary(
libName,
importOptions
)) as any;
libraries[libName] = {
name: libName,
isEmitter: $lib?.emitter,
definition: $lib,
packageJson: JSON.parse(_TypeSpecLibrary_.typespecSourceFiles["package.json"]),
linter: $linter,
_TypeSpecLibrary_,
};
}
return createBrowserHostInternal({
compiler: await importTypeSpecCompiler(importOptions),
libraries,
});
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Link, Toolbar, ToolbarButton, Tooltip } from "@fluentui/react-components";
import { Broom16Filled, Bug16Regular, Save16Regular } from "@fluentui/react-icons";
import { CompilerOptions } from "@typespec/compiler";
import { FunctionComponent, useMemo } from "react";
import type { CompilerOptions } from "@typespec/compiler";
import { useMemo, type FunctionComponent } from "react";
import { EmitterDropdown } from "../react/emitter-dropdown.js";
import { SamplesDropdown } from "../react/samples-dropdown.js";
import { CompilerSettingsDialogButton } from "../react/settings/compiler-settings-dialog-button.js";
import { BrowserHost, PlaygroundSample } from "../types.js";
import type { BrowserHost, PlaygroundSample } from "../types.js";
import style from "./editor-command-bar.module.css";

export interface EditorCommandBarProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/src/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* THIS FILE IS MEANT TO BE STUBBED using the manifest plugin.
*/
import { PlaygroundConfig } from "../src/vite/types.js";
import type { PlaygroundConfig } from "../src/vite/types.js";

const config: PlaygroundConfig = {} as any;
export default config;
2 changes: 1 addition & 1 deletion packages/playground/src/react/context/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export {
PlaygroundContext,
PlaygroundContextProvider,
usePlaygroundContext,
type PlaygroundContext,
} from "./playground-context.js";
4 changes: 2 additions & 2 deletions packages/playground/src/react/context/playground-context.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createContext, useContext } from "react";
import { BrowserHost } from "../../types.js";
import type { BrowserHost } from "../../types.js";

export interface PlaygroundContext {
host: BrowserHost;
readonly host: BrowserHost;
}

const PlaygroundContext = createContext<PlaygroundContext | undefined>(undefined);
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/src/react/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { editor, IDisposable, Uri } from "monaco-editor";
import { FunctionComponent, useEffect, useMemo, useRef } from "react";
import { Uri, editor, type IDisposable } from "monaco-editor";
import { useEffect, useMemo, useRef, type FunctionComponent } from "react";

export interface EditorProps {
model: editor.IModel;
Expand Down
6 changes: 3 additions & 3 deletions packages/playground/src/react/file-output/file-output.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Select, SelectOnChangeData } from "@fluentui/react-components";
import { FunctionComponent, useCallback, useMemo, useState } from "react";
import { FileOutputViewer } from "../types.js";
import { Select, type SelectOnChangeData } from "@fluentui/react-components";
import { useCallback, useMemo, useState, type FunctionComponent } from "react";
import type { FileOutputViewer } from "../types.js";
import style from "./file-output.module.css";

export interface FileOutputProps {
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/src/react/footer/footer-version-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import {
PopoverSurface,
PopoverTrigger,
Select,
SelectOnChangeData,
Table,
TableBody,
TableCell,
TableHeader,
TableHeaderCell,
TableRow,
Title3,
type SelectOnChangeData,
} from "@fluentui/react-components";
import { ChangeEvent, FunctionComponent, memo, useCallback } from "react";
import { memo, useCallback, type ChangeEvent, type FunctionComponent } from "react";
import { usePlaygroundContext } from "../context/playground-context.js";
import { FooterItem } from "./footer-item.js";
import style from "./footer-version-item.module.css";
Expand Down
6 changes: 3 additions & 3 deletions packages/playground/src/react/footer/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { FooterItem, type FooterItemProps } from "./footer-item.js";
export {
FooterVersionItem,
FooterVersionItemProps,
VersionSelectorProps,
VersionSelectorVersion,
type FooterVersionItemProps,
type VersionSelectorProps,
type VersionSelectorVersion,
} from "./footer-version-item.js";
export { Footer, type FooterProps } from "./footer.js";
10 changes: 5 additions & 5 deletions packages/playground/src/react/output-tabs/output-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {
SelectTabData,
SelectTabEvent,
SelectTabEventHandler,
Tab,
TabList,
TabProps,
mergeClasses,
type SelectTabData,
type SelectTabEvent,
type SelectTabEventHandler,
type TabProps,
} from "@fluentui/react-components";
import { FunctionComponent, ReactElement, useCallback } from "react";
import { useCallback, type FunctionComponent, type ReactElement } from "react";
import style from "./output-tabs.module.css";

export interface OutputTab {
Expand Down
14 changes: 9 additions & 5 deletions packages/playground/src/react/output-view/output-view.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { tokens } from "@fluentui/react-components";
import type { Program } from "@typespec/compiler";
import { ColorPalette, ColorProvider, TypeSpecProgramViewer } from "@typespec/html-program-viewer";
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from "react";
import {
ColorProvider,
TypeSpecProgramViewer,
type ColorPalette,
} from "@typespec/html-program-viewer";
import { useCallback, useEffect, useMemo, useState, type FunctionComponent } from "react";
import { FileOutput } from "../file-output/file-output.js";
import { OutputTab, OutputTabs } from "../output-tabs/output-tabs.js";
import { PlaygroundEditorsOptions } from "../playground.js";
import { CompilationState, CompileResult, FileOutputViewer, ViewerProps } from "../types.js";
import { OutputTabs, type OutputTab } from "../output-tabs/output-tabs.js";
import type { PlaygroundEditorsOptions } from "../playground.js";
import type { CompilationState, CompileResult, FileOutputViewer, ViewerProps } from "../types.js";
import { OutputEditor } from "../typespec-editor.js";
import style from "./output-view.module.css";

Expand Down
12 changes: 6 additions & 6 deletions packages/playground/src/react/playground.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { CompilerOptions, Diagnostic } from "@typespec/compiler";
import type { CompilerOptions, Diagnostic } from "@typespec/compiler";
import debounce from "debounce";
import { KeyCode, KeyMod, MarkerSeverity, Uri, editor } from "monaco-editor";
import {
FunctionComponent,
ReactNode,
useCallback,
useEffect,
useMemo,
useRef,
useState,
type FunctionComponent,
type ReactNode,
} from "react";
import { CompletionItemTag } from "vscode-languageserver";
import { EditorCommandBar } from "../editor-command-bar/editor-command-bar.js";
import { getMonacoRange } from "../services.js";
import { BrowserHost, PlaygroundSample } from "../types.js";
import type { BrowserHost, PlaygroundSample } from "../types.js";
import { PlaygroundContextProvider } from "./context/playground-context.js";
import { DefaultFooter } from "./default-footer.js";
import { OnMountData, useMonacoModel } from "./editor.js";
import { useMonacoModel, type OnMountData } from "./editor.js";
import { useControllableValue } from "./hooks.js";
import { OutputView } from "./output-view/output-view.js";
import style from "./playground.module.css";
import { ProblemPane } from "./problem-pane/index.js";
import Pane from "./split-pane/pane.js";
import { SplitPane } from "./split-pane/split-pane.js";
import { CompilationState, FileOutputViewer } from "./types.js";
import type { CompilationState, FileOutputViewer } from "./types.js";
import { TypeSpecEditor } from "./typespec-editor.js";

export interface PlaygroundProps {
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/src/react/problem-pane/header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mergeClasses } from "@fluentui/react-components";
import { ChevronDown16Regular, ErrorCircle16Filled, Warning16Filled } from "@fluentui/react-icons";
import { MouseEventHandler, ReactNode, memo } from "react";
import { CompilationState } from "../types.js";
import { memo, type MouseEventHandler, type ReactNode } from "react";
import type { CompilationState } from "../types.js";
import style from "./header.module.css";

export interface ProblemPaneHeaderProps {
Expand Down
6 changes: 3 additions & 3 deletions packages/playground/src/react/problem-pane/problem-pane.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Diagnostic } from "@typespec/compiler";
import { FunctionComponent, MouseEventHandler } from "react";
import type { Diagnostic } from "@typespec/compiler";
import type { FunctionComponent, MouseEventHandler } from "react";
import { DiagnosticList } from "../diagnostic-list/diagnostic-list.js";
import { CompilationState } from "../types.js";
import type { CompilationState } from "../types.js";
import { ProblemPaneHeader } from "./header.js";
import style from "./problem-pane.module.css";

Expand Down
4 changes: 2 additions & 2 deletions packages/playground/src/react/samples-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Select } from "@fluentui/react-components";
import { FunctionComponent, useCallback } from "react";
import { PlaygroundSample } from "../types.js";
import { useCallback, type FunctionComponent } from "react";
import type { PlaygroundSample } from "../types.js";

export interface SamplesDropdownProps {
samples: Record<string, PlaygroundSample>;
Expand Down
8 changes: 4 additions & 4 deletions packages/playground/src/react/settings/compiler-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Divider } from "@fluentui/react-components";
import { CompilerOptions, LinterRuleSet } from "@typespec/compiler";
import { FunctionComponent, useCallback } from "react";
import { BrowserHost } from "../../types.js";
import { EmitterOptions } from "../types.js";
import type { CompilerOptions, LinterRuleSet } from "@typespec/compiler";
import { useCallback, type FunctionComponent } from "react";
import type { BrowserHost } from "../../types.js";
import type { EmitterOptions } from "../types.js";
import { EmitterOptionsForm } from "./emitter-options-form.js";
import { LinterForm } from "./linter-form.js";

Expand Down
Loading

0 comments on commit 42e72b8

Please sign in to comment.