diff --git a/vuu-ui/package-lock.json b/vuu-ui/package-lock.json index 7e2004311..d4c10225d 100644 --- a/vuu-ui/package-lock.json +++ b/vuu-ui/package-lock.json @@ -1397,9 +1397,10 @@ } }, "node_modules/@mdx-js/rollup": { - "version": "3.0.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-3.0.1.tgz", + "integrity": "sha512-j0II91OCm4ld+l5QVgXXMQGxVVcAWIQJakYWi1dv5pefDHASJyCYER2TsdH7Alf958GoFSM7ugukWyvDq/UY4A==", "dev": true, - "license": "MIT", "dependencies": { "@mdx-js/mdx": "^3.0.0", "@rollup/pluginutils": "^5.0.0", @@ -10454,6 +10455,39 @@ "version": "1.14.1", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "dev": true, @@ -11903,10 +11937,11 @@ "react-router-dom": "^6.2.1" }, "devDependencies": { - "@mdx-js/esbuild": "^3.0.1", - "@mdx-js/rollup": "3.0.0", + "@mdx-js/esbuild": "3.1.0", + "@mdx-js/rollup": "3.0.1", "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3" + "@rollup/plugin-node-resolve": "^15.2.3", + "tsx": "^4.19.1" } }, "showcase/node_modules/@salt-ds/theme": { diff --git a/vuu-ui/package.json b/vuu-ui/package.json index 01abb7dcd..ee774ee3b 100644 --- a/vuu-ui/package.json +++ b/vuu-ui/package.json @@ -40,7 +40,7 @@ "type-defs": "node ./scripts/build-all-type-defs.mjs", "showcase": "cd showcase && npm run showcase", "showcase:preview": "serve ./showcase/dist -p 4173", - "showcase:build": "npm run build:worker && cd showcase && node scripts/build.mjs", + "showcase:build": "npm run build:worker && cd showcase && tsx scripts/build.ts", "test:cypress": "npm run build:worker && cypress run --component --browser chrome --headless", "test:cypress:local": "cypress open --component --browser chrome", "test:vite": "npm run build:worker && vitest run", diff --git a/vuu-ui/showcase/.gitignore b/vuu-ui/showcase/.gitignore index ea571ae22..435ba83eb 100644 --- a/vuu-ui/showcase/.gitignore +++ b/vuu-ui/showcase/.gitignore @@ -1,5 +1 @@ -<<<<<<< HEAD -!templates/index.html -======= -!templates/index.html ->>>>>>> 7590e3f973ef0c9b6070abaac9c592190cd65e6f +.showcase \ No newline at end of file diff --git a/vuu-ui/showcase/index.html b/vuu-ui/showcase/index.html index 93aa3315c..000aeca9c 100644 --- a/vuu-ui/showcase/index.html +++ b/vuu-ui/showcase/index.html @@ -1,15 +1,24 @@ - + - - - - Vite Showcase + Vuu Showcase +
- diff --git a/vuu-ui/showcase/package.json b/vuu-ui/showcase/package.json index 7f9ee15ed..40dfb711e 100644 --- a/vuu-ui/showcase/package.json +++ b/vuu-ui/showcase/package.json @@ -8,8 +8,7 @@ "build": "node ./scripts/build.mjs", "dev": "vite", "docs": "node ./scripts/build-docs.mjs", - "showcase": "node ./scripts/showcase.mjs", - "stories": "node ./scripts/parse-stories.mjs" + "showcase": "tsx ./scripts/showcase.ts" }, "keywords": [], "author": "heswell", @@ -33,9 +32,10 @@ "react-router-dom": "^6.2.1" }, "devDependencies": { - "@mdx-js/esbuild": "^3.0.1", - "@mdx-js/rollup": "3.0.0", + "@mdx-js/esbuild": "3.1.0", + "@mdx-js/rollup": "3.0.1", "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3" + "@rollup/plugin-node-resolve": "^15.2.3", + "tsx": "^4.19.1" } } diff --git a/vuu-ui/showcase/public/favicon-16x16.png b/vuu-ui/showcase/public/favicon-16x16.png deleted file mode 100644 index f85891bba..000000000 Binary files a/vuu-ui/showcase/public/favicon-16x16.png and /dev/null differ diff --git a/vuu-ui/showcase/public/favicon-32x32.png b/vuu-ui/showcase/public/favicon-32x32.png deleted file mode 100644 index 84d627f7a..000000000 Binary files a/vuu-ui/showcase/public/favicon-32x32.png and /dev/null differ diff --git a/vuu-ui/showcase/public/favicon.ico b/vuu-ui/showcase/public/favicon.ico deleted file mode 100644 index cc26fb39d..000000000 Binary files a/vuu-ui/showcase/public/favicon.ico and /dev/null differ diff --git a/vuu-ui/showcase/public/manifest.json b/vuu-ui/showcase/public/manifest.json deleted file mode 100644 index fa99de77d..000000000 --- a/vuu-ui/showcase/public/manifest.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/vuu-ui/showcase/scripts/build-docs.mjs b/vuu-ui/showcase/scripts/build-docs.mjs deleted file mode 100644 index 4a9540a7f..000000000 --- a/vuu-ui/showcase/scripts/build-docs.mjs +++ /dev/null @@ -1,43 +0,0 @@ -import esbuild from "esbuild"; -import mdx from "@mdx-js/esbuild"; -import fs from "fs"; -import path from "path"; - -const targetDir = "./src/examples"; - -const build = async (path) => { - await esbuild.build({ - entryPoints: [path], - outfile: path.replace(".mdx", ".js"), - format: "esm", - plugins: [ - mdx({ - /* jsxImportSource: …, otherOptions… */ - }), - ], - }); -}; - -const buildAll = async (paths) => { - for (const path of paths) { - await build(path); - } -}; - -async function findAllMdxDocs(dir, results = []) { - const rootPath = path.resolve(dir); - fs.readdirSync(rootPath).forEach((element) => { - const childPath = path.join(rootPath, element); - if (fs.lstatSync(childPath).isDirectory()) { - findAllMdxDocs(childPath, results); - } else if (childPath.endsWith(".mdx")) { - results.push(childPath); - } - }); - return results; -} - -const mdxDocs = await findAllMdxDocs(targetDir); - -// await buildAll(mdxDocs); -export default async () => buildAll(mdxDocs); diff --git a/vuu-ui/showcase/scripts/build.mjs b/vuu-ui/showcase/scripts/build.ts similarity index 73% rename from vuu-ui/showcase/scripts/build.mjs rename to vuu-ui/showcase/scripts/build.ts index 747d71025..8047d7d9e 100644 --- a/vuu-ui/showcase/scripts/build.mjs +++ b/vuu-ui/showcase/scripts/build.ts @@ -5,24 +5,31 @@ import { formatDuration, padRight, readPackageJson, + writeFile, writeMetaFile, } from "../../scripts/utils.mjs"; import { build } from "../../scripts/esbuild.mjs"; import { buildFileList } from "./build-file-list.mjs"; import fs from "fs"; import path from "path"; +import { treeSourceFromFileSystem } from "./treeSourceFromFileSystem"; +import mdx from "@mdx-js/esbuild"; const indexFiles = buildFileList("./src/examples", /index.ts$/); const examples = buildFileList("./src/examples", /examples.tsx$/); +const mdxFiles = buildFileList("./src/examples", /.mdx$/); const features = buildFileList("./src/features", /feature.tsx$/); +console.log({ mdxFiles }); + // TODO use a separate build call for each theme, without bundling const themes = ["./src/themes/salt-theme.ts", "./src/themes/vuu-theme.ts"]; -const entryPoints = ["src/main.tsx"] +const entryPoints = ["src/index-main.tsx", "src/index-standalone.tsx"] .concat(indexFiles) .concat(features) .concat(examples) + .concat(mdxFiles) .concat(themes); const cssInlinePlugin = { @@ -37,7 +44,7 @@ const cssInlinePlugin = { const css = await fs.promises.readFile(args.path, "utf8"); // css = await esbuild.transform(css, { loader: "css", minify: true }); return { loader: "text", contents: css }; - } + }, ); }, }; @@ -48,16 +55,25 @@ const HTML_TEMPLATE = ` - - - - + Vite Showcase +
- `; @@ -75,7 +91,7 @@ const esbuildConfig = { "./themes/tar-theme.ts", ], name: "showcase", - plugins: [cssInlinePlugin], + plugins: [cssInlinePlugin, mdx()], outdir, splitting: true, target: "esnext", @@ -87,7 +103,7 @@ function writeHtmlFile() { if (err) { reject(err); } else { - resolve(); + resolve(undefined); } }); }); @@ -111,6 +127,12 @@ async function main() { await writeMetaFile(metafile, outdir); + const treeSourceJson = treeSourceFromFileSystem("./src/examples", ""); + await writeFile( + `export default ${JSON.stringify(treeSourceJson)};`, + path.resolve(outdir, "treeSourceJson.js"), + ); + console.log("[DEPLOY public assets]"); const publicContent = fs.readdirSync(`./public`); publicContent.forEach((file) => { @@ -121,7 +143,7 @@ async function main() { { recursive: true }, (err) => { if (err) throw err; - } + }, ); } }); @@ -146,11 +168,11 @@ async function main() { console.log("\ncore"); outputs.core.sort(byFileName).forEach(({ fileName, bytes }) => { - console.log(`${padRight(fileName, 30)} ${formatBytes(bytes)}`); + console.log(`${padRight(fileName, 90)} ${formatBytes(bytes)}`); }); console.log("\ncommon"); outputs.common.forEach(({ fileName, bytes }) => { - console.log(`${padRight(fileName, 30)} ${formatBytes(bytes)}`); + console.log(`${padRight(fileName, 90)} ${formatBytes(bytes)}`); }); console.log(`\nbuild took ${formatDuration(duration)}`); diff --git a/vuu-ui/showcase/scripts/parse-stories.mjs b/vuu-ui/showcase/scripts/parse-stories.mjs deleted file mode 100644 index b27c3ea02..000000000 --- a/vuu-ui/showcase/scripts/parse-stories.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import fs from "fs"; -import path from "path"; -// import { build } from 'esbuild'; - -const SRC = "./src/examples/"; -const OUT = "./src/generated/stories.json"; - -// async function loadModule(filePath, exports) { -// const { default: module } = await import(filePath); -// return { -// fileName: filePath, -// module, -// exports: exports.filter((name) => name !== 'default') -// }; -// } - -function buildPackageTree(dir, tree = {}) { - fs.readdirSync(dir).forEach((fileName) => { - const filePath = path.join(dir, fileName); - if (fs.lstatSync(filePath).isDirectory()) { - const subTree = buildPackageTree(filePath); - if (Object.keys(subTree).length > 0) { - tree[fileName] = buildPackageTree(filePath); - } - } else if (fileName.match(/(stories|examples).tsx$/)) { - const [storyName] = fileName.split("."); - tree[storyName] = `${dir}${fileName}`; - } - }); - return tree; -} - -const stories = buildPackageTree(SRC); -fs.writeFile(OUT, JSON.stringify(stories, null, 2), (err) => { - if (err) { - console.log(err); - } -}); - -// if (storyFiles.length) { -// const { metafile } = await build({ -// entryPoints: storyFiles, -// format: 'esm', -// metafile: true, -// outdir: 'dist', -// outExtension: { '.js': '.mjs' } -// }).catch(() => process.exit(1)); - -// const { outputs } = metafile; - -// const files = Object.entries(outputs).map(([fileName, { exports }]) => -// loadModule(`../${fileName}`, exports) -// ); - -// const stories = await Promise.all(files); - -console.log(JSON.stringify(stories, null, 2)); -// } diff --git a/vuu-ui/showcase/scripts/showcase.mjs b/vuu-ui/showcase/scripts/showcase.mjs deleted file mode 100644 index afb66890d..000000000 --- a/vuu-ui/showcase/scripts/showcase.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import open from "open"; -import chalk from "chalk"; -import buildMdxDocs from "./build-docs.mjs"; - -import { execWait } from "../../scripts/utils.mjs"; - -await buildMdxDocs(); - -execWait("npm run dev"); - -console.log(`opening showcase at ${chalk.green("http://localhost:5173/")} ...`); - -setTimeout(() => { - open("http://localhost:5173/"); -}, 3000); diff --git a/vuu-ui/showcase/scripts/showcase.ts b/vuu-ui/showcase/scripts/showcase.ts new file mode 100644 index 000000000..d33eccb40 --- /dev/null +++ b/vuu-ui/showcase/scripts/showcase.ts @@ -0,0 +1,26 @@ +import fs from "fs"; +import open from "open"; +import chalk from "chalk"; +import { treeSourceFromFileSystem } from "./treeSourceFromFileSystem"; +import { createFolder, execWait, writeFile } from "../../scripts/utils.mjs"; + +const start = performance.now(); +const treeSourceJson = treeSourceFromFileSystem("./src/examples", ""); +const end = performance.now(); +console.log(`building tree took ${end - start}ms`); + +if (!fs.existsSync(".showcase")) { + createFolder(".showcase"); +} + +await writeFile( + `export default ${JSON.stringify(treeSourceJson)};`, + "./.showcase/treeSourceJson.js", +); +execWait("npm run dev"); + +console.log(`opening showcase at ${chalk.green("http://localhost:5173/")} ...`); + +setTimeout(() => { + open("http://localhost:5173/"); +}, 3000); diff --git a/vuu-ui/showcase/scripts/treeSourceFromFileSystem.ts b/vuu-ui/showcase/scripts/treeSourceFromFileSystem.ts new file mode 100644 index 000000000..bddad0a1f --- /dev/null +++ b/vuu-ui/showcase/scripts/treeSourceFromFileSystem.ts @@ -0,0 +1,102 @@ +import fs from "fs"; +import path from "path"; +import { type Module, type TreeSourceNode } from "@finos/vuu-utils"; + +export type VuuExample = { + (props?: any): JSX.Element; + displaySequence: number; +}; + +export type ExamplesModule = Module; + +const getFileType = (filePath: string) => { + const pos = filePath.lastIndexOf("."); + if (pos === -1) { + throw Error(`file path ${filePath} has no file type suffix`); + } + return filePath.slice(pos + 1); +}; + +const lastPathSegment = (path: string, separator = "/") => { + const root = path.endsWith(separator) ? path.slice(0, -1) : path; + return root.slice(root.lastIndexOf(separator) + 1); +}; +// TODO use version from vuu-utils +const dropLastPathSegment = (path: string, separator = "/") => { + return path.slice(0, path.lastIndexOf(separator)); +}; + +const exportPattern = /export const ([A-Z][a-zA-Z]+) = /g; + +export const treeSourceFromFileSystem = ( + exhibitsPath: string, + route: string, + icon = "folder", +): TreeSourceNode[] => { + const treeSourceNodes: TreeSourceNode[] = []; + fs.readdirSync(exhibitsPath).forEach((fileName) => { + const filePath = path.join(exhibitsPath, fileName); + if (fs.lstatSync(filePath).isDirectory()) { + const treeSourceNode: TreeSourceNode = { + id: `${route}${fileName}`, + icon, + label: fileName, + childNodes: treeSourceFromFileSystem( + filePath, + `${route}${fileName}/`, + "box", + ), + }; + if ( + Array.isArray(treeSourceNode.childNodes) && + treeSourceNode.childNodes.length > 0 + ) { + treeSourceNodes.push(treeSourceNode); + } + } else if (fileName.match(/(examples.tsx|.mdx)$/)) { + const name = dropLastPathSegment(dropLastPathSegment(fileName, "."), "."); + const id = `${route}${name}`; + if (name !== lastPathSegment(route)) { + treeSourceNodes.push({ + id, + icon: "box", + label: name, + childNodes: treeSourceFromExportedComponents( + exhibitsPath, + `${route}${name}/`, + fileName, + ), + }); + } else { + treeSourceNodes.push( + ...treeSourceFromExportedComponents(exhibitsPath, route, fileName), + ); + } + } + }); + return treeSourceNodes; +}; + +const treeSourceFromExportedComponents = ( + exhibitsPath: string, + route, + fileName: string, +) => { + const filePath = path.join(exhibitsPath, fileName); + const text = fs.readFileSync(filePath).toString(); + let match = exportPattern.exec(text); + const treeSourceNodes: TreeSourceNode[] = []; + while (match != null) { + const componentName = match[1]; + treeSourceNodes.push({ + id: `${route}${componentName}`, + label: componentName, + nodeData: { + componentName, + path: `${exhibitsPath}/${fileName}`, + }, + }); + match = exportPattern.exec(text); + } + return treeSourceNodes; +}; diff --git a/vuu-ui/showcase/src/examples/Table/Table.mdx b/vuu-ui/showcase/src/examples/Table/Table.mdx index 9d8e96159..ca8c97f8f 100644 --- a/vuu-ui/showcase/src/examples/Table/Table.mdx +++ b/vuu-ui/showcase/src/examples/Table/Table.mdx @@ -1,7 +1,7 @@ -import { Instruments } from "./SIMUL.examples"; +import { SimulTable } from "./SIMUL.examples"; ### Table -Example od a simple Table +Example of a simple Table - + diff --git a/vuu-ui/showcase/src/index-main.tsx b/vuu-ui/showcase/src/index-main.tsx index 78bef57bc..48adc905d 100644 --- a/vuu-ui/showcase/src/index-main.tsx +++ b/vuu-ui/showcase/src/index-main.tsx @@ -1,11 +1,12 @@ import ReactDOM from "react-dom"; -import { type ExamplesModule, Showcase } from "@finos/vuu-showcase"; +import { Showcase } from "@finos/vuu-showcase"; +import { TreeSourceNode } from "@finos/vuu-utils"; -const root = document.getElementById("root") as HTMLDivElement; -// The full Showcase shell loads all examples in order to render the Navigation Tree. This can -// be a bit slow in dev mode. -import("./examples/index") - .then((examples: ExamplesModule) => { - ReactDOM.render(, root); - }) - .catch((err) => console.error(`error loading examples ${err.message}`)); +export default async (treeSource: TreeSourceNode[]) => { + console.log("Showcase index-main start", { + treeSource, + }); + + const root = document.getElementById("root") as HTMLDivElement; + ReactDOM.render(, root); +}; diff --git a/vuu-ui/showcase/src/index-standalone.tsx b/vuu-ui/showcase/src/index-standalone.tsx index 2d0ede983..0811b695b 100644 --- a/vuu-ui/showcase/src/index-standalone.tsx +++ b/vuu-ui/showcase/src/index-standalone.tsx @@ -1,6 +1,12 @@ import { ShowcaseStandalone } from "@finos/vuu-showcase"; +import { TreeSourceNode } from "@finos/vuu-utils"; import ReactDOM from "react-dom"; -const root = document.getElementById("root") as HTMLDivElement; +export default async (treeSource: TreeSourceNode[]) => { + console.log("Showcase index-standalone start", { + treeSource, + }); + const root = document.getElementById("root") as HTMLDivElement; -ReactDOM.render(, root); + ReactDOM.render(, root); +}; diff --git a/vuu-ui/showcase/src/main.tsx b/vuu-ui/showcase/src/main.tsx deleted file mode 100644 index 6fd3ab731..000000000 --- a/vuu-ui/showcase/src/main.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { hasUrlParameter } from "@finos/vuu-utils"; -if (hasUrlParameter("standalone")) { - import("./index-standalone"); -} else { - import("./index-main"); -} diff --git a/vuu-ui/showcase/vite.config.js b/vuu-ui/showcase/vite.config.js index ce4af8ffc..35d4af622 100644 --- a/vuu-ui/showcase/vite.config.js +++ b/vuu-ui/showcase/vite.config.js @@ -1,5 +1,6 @@ import { defineConfig } from "vite"; import { cssInline } from "../tools/vite-plugin-inline-css/src"; +import mdx from "@mdx-js/rollup"; export default defineConfig({ build: { @@ -15,21 +16,5 @@ export default defineConfig({ jsx: `automatic`, target: "esnext", }, - plugins: [cssInline()], - server: { - proxy: { - "/api/authn": { - target: "https://localhost:8443", - secure: false, - }, - }, - }, - preview: { - proxy: { - "/api/authn": { - target: "https://localhost:8443", - secure: false, - }, - }, - }, + plugins: [cssInline(), mdx()], }); diff --git a/vuu-ui/tools/chrome-devtools-protocol/.gitignore b/vuu-ui/tools/cd ../.gitignore similarity index 100% rename from vuu-ui/tools/chrome-devtools-protocol/.gitignore rename to vuu-ui/tools/cd ../.gitignore diff --git a/vuu-ui/tools/chrome-devtools-protocol/launch-headless.js b/vuu-ui/tools/cd ../launch-headless.js similarity index 100% rename from vuu-ui/tools/chrome-devtools-protocol/launch-headless.js rename to vuu-ui/tools/cd ../launch-headless.js diff --git a/vuu-ui/tools/chrome-devtools-protocol/package.json b/vuu-ui/tools/cd ../package.json similarity index 100% rename from vuu-ui/tools/chrome-devtools-protocol/package.json rename to vuu-ui/tools/cd ../package.json diff --git a/vuu-ui/tools/vuu-showcase/package.json b/vuu-ui/tools/vuu-showcase/package.json index 79a407573..2f5f4b094 100644 --- a/vuu-ui/tools/vuu-showcase/package.json +++ b/vuu-ui/tools/vuu-showcase/package.json @@ -29,5 +29,6 @@ "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" }, - "sideEffects": false + "sideEffects": false, + "type": "module" } diff --git a/vuu-ui/tools/vuu-showcase/src/App.tsx b/vuu-ui/tools/vuu-showcase/src/App.tsx index 2d439a95b..c47a39bc5 100644 --- a/vuu-ui/tools/vuu-showcase/src/App.tsx +++ b/vuu-ui/tools/vuu-showcase/src/App.tsx @@ -13,44 +13,12 @@ import { import { useCallback, useEffect, useMemo, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { IFrame } from "./components"; -import { - ExamplesModule, - byDisplaySequence, - keysFromPath, - loadTheme, - pathFromKey, -} from "./showcase-utils"; +import { keysFromPath, loadTheme, pathFromKey } from "./showcase-utils"; import "./App.css"; -const sourceFromImports = ( - stories: ExamplesModule, - prefix = "", - icon = "folder", -): TreeSourceNode[] => - Object.entries(stories) - .filter(([path]) => path !== "default") - .sort(byDisplaySequence) - .map(([label, stories]) => { - const id = `${prefix}${label}`; - // TODO how can we know when a potential docs node has docs - // console.log(`id=${id}`); - if (typeof stories === "function") { - return { - id, - icon: "rings", - label, - }; - } - return { - id, - icon, - label, - childNodes: sourceFromImports(stories, `${id}/`, "box"), - }; - }); export interface AppProps { - stories: ExamplesModule; + treeSource: TreeSourceNode[]; } type ThemeDescriptor = { label?: string; id: string }; @@ -76,7 +44,7 @@ const availableDensity: DensityDescriptor[] = [ { id: "touch", label: "Touch" }, ]; -export const App = ({ stories }: AppProps) => { +export const App = ({ treeSource }: AppProps) => { const navigate = useNavigate(); const [themeReady, setThemeReady] = useState(false); @@ -87,9 +55,8 @@ export const App = ({ stories }: AppProps) => { }, []); // // TODO cache source in localStorage - const source = useMemo(() => sourceFromImports(stories), [stories]); const { pathname } = useLocation(); - const handleChange: TableRowSelectHandler = (row) => { + const handleSelect: TableRowSelectHandler = (row) => { if (row) { const path = pathFromKey(row.key); navigate(path); @@ -153,11 +120,10 @@ export const App = ({ stories }: AppProps) => { data-resizeable rowHeight={30} defaultSelectedKeyValues={keysFromPath(pathname)} - // selected={[pathname.slice(1)]} showColumnHeaders={false} - onSelect={handleChange} + onSelect={handleSelect} revealSelected - source={source} + source={treeSource} width="100%" /> diff --git a/vuu-ui/tools/vuu-showcase/src/Showcase.tsx b/vuu-ui/tools/vuu-showcase/src/Showcase.tsx index 04a687274..db87507e9 100644 --- a/vuu-ui/tools/vuu-showcase/src/Showcase.tsx +++ b/vuu-ui/tools/vuu-showcase/src/Showcase.tsx @@ -1,27 +1,24 @@ import "./Showcase.css"; import { BrowserRouter, Route, Routes } from "react-router-dom"; -import { ExamplesModule } from "./showcase-utils"; import { App } from "./App"; +import { TreeSourceNode } from "@finos/vuu-utils"; -const createRoutes = (examples: ExamplesModule, prefix = ""): JSX.Element[] => - Object.entries(examples) - .filter(([path]) => path !== "default") - .reduce((routes, [label, Value]) => { - const id = `${prefix}${label}`; - return typeof Value === "object" - ? routes - .concat() - .concat(createRoutes(Value, `${id}/`)) - : routes.concat(); - }, []); +const createRoutes = (treeSource: TreeSourceNode[]): JSX.Element[] => + treeSource.reduce((routes, { childNodes, label, id }) => { + return Array.isArray(childNodes) + ? routes + .concat(createRoutes(childNodes)) + .concat() + : routes.concat(); + }, []); -export const Showcase = ({ exhibits }: { exhibits: ExamplesModule }) => { +export const Showcase = ({ treeSource }: { treeSource: TreeSourceNode[] }) => { return ( - }> - {createRoutes(exhibits)} + }> + {createRoutes(treeSource)} diff --git a/vuu-ui/tools/vuu-showcase/src/index.ts b/vuu-ui/tools/vuu-showcase/src/index.ts index 8af3c59f9..d8422d0b8 100644 --- a/vuu-ui/tools/vuu-showcase/src/index.ts +++ b/vuu-ui/tools/vuu-showcase/src/index.ts @@ -1,4 +1,4 @@ export * from "./Showcase"; export * from "./ShowcaseStandalone"; export { loadTheme } from "./showcase-utils"; -export type { ExamplesModule, VuuExample } from "./showcase-utils"; +export type { VuuExample } from "./showcase-utils"; diff --git a/vuu-ui/tools/vuu-showcase/src/showcase-utils.ts b/vuu-ui/tools/vuu-showcase/src/showcase-utils.ts index 4b8cfc25d..61ec8b7b7 100644 --- a/vuu-ui/tools/vuu-showcase/src/showcase-utils.ts +++ b/vuu-ui/tools/vuu-showcase/src/showcase-utils.ts @@ -4,37 +4,10 @@ type Environment = "development" | "production"; export const env = process.env.NODE_ENV as Environment; export type VuuExample = { - (props?: any): JSX.Element; + (props?: { [key: string]: unknown }): JSX.Element; displaySequence: number; }; -export type ExamplesModule = Module; -export type VuuTuple = [string, VuuExample | ExamplesModule]; - -export const isVuuExample = ( - item: VuuExample | ExamplesModule, -): item is VuuExample => typeof item === "function"; - -export const byDisplaySequence = ([, f1]: VuuTuple, [, f2]: VuuTuple) => { - if (isVuuExample(f1) && isVuuExample(f2)) { - const { displaySequence: ds1 } = f1; - const { displaySequence: ds2 } = f2; - - if (ds1 === undefined && ds2 === undefined) { - return 0; - } - if (ds2 === undefined) { - return -1; - } - if (ds1 === undefined) { - return 1; - } - return ds1 - ds2; - } else { - return 0; - } -}; - export const pathFromKey = (key: string) => key.slice(5).split("|").join("/"); export const keysFromPath = (path: string) => { if (path === "/") {