diff --git a/Changelog.md b/Changelog.md index d8fdb400..20a6e6bf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## \[1.2.2] - 2026-04-09 + +This patch release clears ESLint failures in the Next.js app pages and aligns +several code paths with the compiler target so production builds succeed without +enabling `--downlevelIteration`. + +### Change + +* Altered the avaliable types to the SlotMetadata so the default can handle + a wide variaty of types - `default?: string | number | boolean | object | any[] | null;` + +### Lint and code quality + +* Resolved `no-else-return`, `no-unused-vars`, `camelcase`, `prefer-const`, + `eqeqeq`, `no-nested-ternary`, `no-lonely-if`, and `no-use-before-define` + across static pages (catch-all docs, assets, foundations, home, system, and + design-token foundation pages). +* Removed or refactored unused `getStaticProps` context parameters, props, and + locals; normalized naming (e.g. font machine keys); simplified icon detail + routing query handling. +* Reordered helper components (token color/effect/typography tables, component + token previews) ahead of page components where required for declaration order. +* Converted `getComponentPreviews` to a hoisted `function` declaration and + refactored the component token table for clearer control flow. + +### Build / TypeScript compatibility + +* Avoid iterating `Map` / `Set` / `Iterable` / `matchAll` results directly in + `for...of` where the compile target requires it: use `Array.from(...)` or + equivalent helpers in the config-diff registry, snapshot diff, CSF import + parsing, and component artifact sync. + ## \[1.2.1] - 2026-04-08 This is a minor release that fixes a bug in the new config diff calculator. diff --git a/package-lock.json b/package-lock.json index 155eb35c..20d7c847 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "handoff-app", - "version": "1.2.1", + "version": "1.2.2-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "handoff-app", - "version": "1.2.1", + "version": "1.2.2-7", "license": "MIT", "dependencies": { "@clack/prompts": "^0.7.0", @@ -1884,9 +1884,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.14.tgz", - "integrity": "sha512-aXeirLYuASxEgi4X4WhfXsShCFxWDfNn/8ZeC5YXAS2BB4A8FJi1kwwGL6nvMVboE7fZCzmJPNdMvVHc8JpaiA==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.15.tgz", + "integrity": "sha512-vcmyu5/MyFzN7CdqRHO3uHO44p/QPCZkuTUXroeUmhNP8bL5PHFEhik22JUazt+CDDoD6EpBYRCaS2pISL+/hg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1899,9 +1899,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.14.tgz", - "integrity": "sha512-Y9K6SPzobnZvrRDPO2s0grgzC+Egf0CqfbdvYmQVaztV890zicw8Z8+4Vqw8oPck8r1TjUHxVh8299Cg4TrxXg==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.15.tgz", + "integrity": "sha512-6PvFO2Tzt10GFK2Ro9tAVEtacMqRmTarYMFKAnV2vYMdwWc73xzmDQyAV7SwEdMhzmiRoo7+m88DuiXlJlGeaw==", "cpu": [ "arm64" ], @@ -1915,9 +1915,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.14.tgz", - "integrity": "sha512-aNnkSMjSFRTOmkd7qoNI2/rETQm/vKD6c/Ac9BZGa9CtoOzy3c2njgz7LvebQJ8iPxdeTuGnAjagyis8a9ifBw==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.15.tgz", + "integrity": "sha512-G+YNV+z6FDZTp/+IdGyIMFqalBTaQSnvAA+X/hrt+eaTRFSznRMz9K7rTmzvM6tDmKegNtyzgufZW0HwVzEqaQ==", "cpu": [ "x64" ], @@ -1931,9 +1931,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.14.tgz", - "integrity": "sha512-tjlpia+yStPRS//6sdmlVwuO1Rioern4u2onafa5n+h2hCS9MAvMXqpVbSrjgiEOoCs0nJy7oPOmWgtRRNSM5Q==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.15.tgz", + "integrity": "sha512-eVkrMcVIBqGfXB+QUC7jjZ94Z6uX/dNStbQFabewAnk13Uy18Igd1YZ/GtPRzdhtm7QwC0e6o7zOQecul4iC1w==", "cpu": [ "arm64" ], @@ -1947,9 +1947,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.14.tgz", - "integrity": "sha512-8B8cngBaLadl5lbDRdxGCP1Lef8ipD6KlxS3v0ElDAGil6lafrAM3B258p1KJOglInCVFUjk751IXMr2ixeQOQ==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.15.tgz", + "integrity": "sha512-RwSHKMQ7InLy5GfkY2/n5PcFycKA08qI1VST78n09nN36nUPqCvGSMiLXlfUmzmpQpF6XeBYP2KRWHi0UW3uNg==", "cpu": [ "arm64" ], @@ -1963,9 +1963,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.14.tgz", - "integrity": "sha512-bAS6tIAg8u4Gn3Nz7fCPpSoKAexEt2d5vn1mzokcqdqyov6ZJ6gu6GdF9l8ORFrBuRHgv3go/RfzYz5BkZ6YSQ==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.15.tgz", + "integrity": "sha512-nplqvY86LakS+eeiuWsNWvfmK8pFcOEW7ZtVRt4QH70lL+0x6LG/m1OpJ/tvrbwjmR8HH9/fH2jzW1GlL03TIg==", "cpu": [ "x64" ], @@ -1979,9 +1979,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.14.tgz", - "integrity": "sha512-mMxv/FcrT7Gfaq4tsR22l17oKWXZmH/lVqcvjX0kfp5I0lKodHYLICKPoX1KRnnE+ci6oIUdriUhuA3rBCDiSw==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.15.tgz", + "integrity": "sha512-eAgl9NKQ84/sww0v81DQINl/vL2IBxD7sMybd0cWRw6wqgouVI53brVRBrggqBRP/NWeIAE1dm5cbKYoiMlqDQ==", "cpu": [ "x64" ], @@ -1995,9 +1995,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.14.tgz", - "integrity": "sha512-OTmiBlYThppnvnsqx0rBqjDRemlmIeZ8/o4zI7veaXoeO1PVHoyj2lfTfXTiiGjCyRDhA10y4h6ZvZvBiynr2g==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.15.tgz", + "integrity": "sha512-GJVZC86lzSquh0MtvZT+L7G8+jMnJcldloOjA8Kf3wXvBrvb6OGe2MzPuALxFshSm/IpwUtD2mIoof39ymf52A==", "cpu": [ "arm64" ], @@ -2011,9 +2011,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.14.tgz", - "integrity": "sha512-+W7eFf3RS7m4G6tppVTOSyP9Y6FsJXfOuKzav1qKniiFm3KFByQfPEcouHdjlZmysl4zJGuGLQ/M9XyVeyeNEg==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.15.tgz", + "integrity": "sha512-nFucjVdwlFqxh/JG3hWSJ4p8+YJV7Ii8aPDuBQULB6DzUF4UNZETXLfEUk+oI2zEznWWULPt7MeuTE6xtK1HSA==", "cpu": [ "x64" ], @@ -10988,9 +10988,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.defaults": { @@ -12242,12 +12242,12 @@ } }, "node_modules/next": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.14.tgz", - "integrity": "sha512-M6S+4JyRjmKic2Ssm7jHUPkE6YUJ6lv4507jprsSZLulubz0ihO2E+S4zmQK3JZ2ov81JrugukKU4Tz0ivgqqQ==", + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.15.tgz", + "integrity": "sha512-VSqCrJwtLVGwAVE0Sb/yikrQfkwkZW9p+lL/J4+xe+G3ZA+QnWPqgcfH1tDUEuk9y+pthzzVFp4L/U8JerMfMQ==", "license": "MIT", "dependencies": { - "@next/env": "15.5.14", + "@next/env": "15.5.15", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -12260,14 +12260,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.14", - "@next/swc-darwin-x64": "15.5.14", - "@next/swc-linux-arm64-gnu": "15.5.14", - "@next/swc-linux-arm64-musl": "15.5.14", - "@next/swc-linux-x64-gnu": "15.5.14", - "@next/swc-linux-x64-musl": "15.5.14", - "@next/swc-win32-arm64-msvc": "15.5.14", - "@next/swc-win32-x64-msvc": "15.5.14", + "@next/swc-darwin-arm64": "15.5.15", + "@next/swc-darwin-x64": "15.5.15", + "@next/swc-linux-arm64-gnu": "15.5.15", + "@next/swc-linux-arm64-musl": "15.5.15", + "@next/swc-linux-x64-gnu": "15.5.15", + "@next/swc-linux-x64-musl": "15.5.15", + "@next/swc-win32-arm64-msvc": "15.5.15", + "@next/swc-win32-x64-msvc": "15.5.15", "sharp": "^0.34.3" }, "peerDependencies": { @@ -16186,9 +16186,9 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", "license": "MIT", "dependencies": { "esbuild": "^0.25.0", diff --git a/package.json b/package.json index 676351a8..5877450f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "handoff-app", - "version": "1.2.1", + "version": "1.2.2-7", "description": "Automated documentation toolchain for building client side documentation from figma", "author ": { "name": "Convertiv", diff --git a/src/app-builder/build.ts b/src/app-builder/build.ts index 43929368..964185cf 100644 --- a/src/app-builder/build.ts +++ b/src/app-builder/build.ts @@ -4,13 +4,23 @@ import path from 'path'; import Handoff from '..'; import { buildComponents } from '../pipeline/components'; import { buildPatterns } from '../pipeline/patterns'; +import processComponents from '../transformers/preview/component/builder'; import { buildMainCss } from '../transformers/preview/component/css'; import { buildMainJS } from '../transformers/preview/component/javascript'; -import processComponents from '../transformers/preview/component/builder'; import { Logger } from '../utils/logger'; import { generateTokensApi, persistClientConfig } from './client-config'; import { getAppPath, syncPublicFiles } from './paths'; -import { WatcherState, getRuntimeComponentsPathsToWatch, watchAppSource, watchComponentDirectories, watchGlobalEntries, watchPages, watchPublicDirectory, watchRuntimeComponents, watchRuntimeConfiguration } from './watchers'; +import { + WatcherState, + getRuntimeComponentsPathsToWatch, + watchAppSource, + watchComponentDirectories, + watchGlobalEntries, + watchPages, + watchPublicDirectory, + watchRuntimeComponents, + watchRuntimeConfiguration, +} from './watchers'; import { createWebSocketServer } from './websocket'; const escapeForSingleQuotedJsString = (value: string): string => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); @@ -46,10 +56,13 @@ const initializeProjectApp = async (handoff: Handoff): Promise => { // Copy custom theme CSS if it exists in the user's project const customThemePath = path.resolve(handoff.workingPath, 'theme.css'); + const destPath = path.resolve(appPath, 'css', 'theme.css'); if (fs.existsSync(customThemePath)) { - const destPath = path.resolve(appPath, 'css', 'theme.css'); await fs.copy(customThemePath, destPath, { overwrite: true }); Logger.success(`Custom theme.css loaded`); + } else { + // create a empty theme.css file + await fs.writeFile(destPath, ''); } // Prepare project app configuration using stable placeholder replacement. diff --git a/src/app/components/Component/ComponentLists.tsx b/src/app/components/Component/ComponentLists.tsx index 03427658..163c6eb3 100644 --- a/src/app/components/Component/ComponentLists.tsx +++ b/src/app/components/Component/ComponentLists.tsx @@ -42,7 +42,7 @@ export const ComponentList = ({ const [groupedList, setGroupedList] = React.useState>({}); const categories = React.useMemo(() => { - const categories = new Set(components.map((component) => component.group).flat()); + const categories = new Set(components.map((component) => component.group).flat().filter((g): g is string => !!g)); return Array.from(categories); }, [components]); @@ -76,114 +76,114 @@ export const ComponentList = ({ return (
-
-
-
- - setSearch(e.currentTarget.value)} - aria-label="Search components" - style={{ minWidth: 200 }} - - /> -
+
+
+
+ + setSearch(e.currentTarget.value)} + aria-label="Search components" + style={{ minWidth: 200 }} + + /> +
-
-
-
- - -
- - - - - - - Group by category - -
- storeLayout(value)}> - - - - - - - - Grid layout - - - - - - - - - - Column layout - - - +
+
+ + +
+ + + + + + + Group by category + + +
+ storeLayout(value)}> + + + + + + + + Grid layout + + + + + + + + + + Column layout + + + +
-
- {groupBy ? ( - <> - {Object.keys(groupedList).map((group) => { - return ( -
- {group} -
- {groupedList[group].map((component) => { - return ; - })} + {groupBy ? ( + <> + {Object.keys(groupedList).map((group) => { + return ( +
+ {group} +
+ {groupedList[group].map((component) => { + return ; + })} +
-
- ); + ); + })} + + ) : ( +
{list.map((component) => { + return ; })} - - ) : ( -
{list.map((component) => { - return ; - })} -
- )} +
+ )}
); diff --git a/src/app/components/Component/Preview.tsx b/src/app/components/Component/Preview.tsx index 00a1a1cf..1cda77f1 100644 --- a/src/app/components/Component/Preview.tsx +++ b/src/app/components/Component/Preview.tsx @@ -78,10 +78,12 @@ export const ComponentDisplay: React.FC<{ const variantMap: Record> = {}; Object.values(component.previews).forEach((preview: any) => { Object.entries(preview.values).forEach(([key, value]) => { + const strValue = String(value); + if (!strValue) return; if (!variantMap[key]) { variantMap[key] = new Set(); } - variantMap[key].add(String(value)); + variantMap[key].add(strValue); }); }); diff --git a/src/app/components/context/PreviewContext.tsx b/src/app/components/context/PreviewContext.tsx index 5819bcbf..1e99d1cd 100644 --- a/src/app/components/context/PreviewContext.tsx +++ b/src/app/components/context/PreviewContext.tsx @@ -33,13 +33,13 @@ function groupVariantProperties(items: Record[]): Record [key, Array.from(set)]) - // .filter((i) => i[1].length > 1) ); } diff --git a/src/app/css.d.ts b/src/app/css.d.ts new file mode 100644 index 00000000..a839446c --- /dev/null +++ b/src/app/css.d.ts @@ -0,0 +1 @@ +declare module '*.css' {} diff --git a/src/app/pages/[...slug]/index.tsx b/src/app/pages/[...slug]/index.tsx index 3434f8e2..95967318 100644 --- a/src/app/pages/[...slug]/index.tsx +++ b/src/app/pages/[...slug]/index.tsx @@ -41,26 +41,7 @@ export const getStaticProps: GetStaticProps = (context) => { export default function DocCatchAllPage({ content, menu, metadata, current, config }: DocumentationProps) { const bodyRef = useRef(null); - if (content) { - return ( - -
- {metadata.title} -

{metadata.description}

-
-
-
-
- - {content} - -
-
- -
-
- ); - } else { + if (!content) { return (
@@ -85,4 +66,23 @@ export default function DocCatchAllPage({ content, menu, metadata, current, conf
); } + + return ( + +
+ {metadata.title} +

{metadata.description}

+
+
+
+
+ + {content} + +
+
+ +
+
+ ); } diff --git a/src/app/pages/assets/fonts.tsx b/src/app/pages/assets/fonts.tsx index 6f17de0c..1be4caee 100644 --- a/src/app/pages/assets/fonts.tsx +++ b/src/app/pages/assets/fonts.tsx @@ -21,7 +21,7 @@ import { fetchDocPageMarkdown, FontDocumentationProps, getClientRuntimeConfig, g * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { const fonts = fs.readdirSync( path.resolve(process.env.HANDOFF_MODULE_PATH ?? '', '.handoff', `${process.env.HANDOFF_PROJECT_ID}`, 'public', 'fonts') ); @@ -45,16 +45,15 @@ export const getStaticProps: GetStaticProps = async (context) => { }; }; -const FontsPage = ({ content, menu, metadata, current, customFonts, design, config }: FontDocumentationProps) => { +const FontsPage = ({ content, menu, metadata, customFonts, design, config }: FontDocumentationProps) => { const fontFamilies: string[] = uniq(design.typography.map((type) => type.values.fontFamily)); const fontLinks: string[] = fontFamilies.map((fontFamily) => { - const machine_name = fontFamily.replace(/\s/g, ''); - const custom = customFonts.find((font) => font === machine_name); + const machineName = fontFamily.replace(/\s/g, ''); + const custom = customFonts.find((font) => font === machineName); if (custom) { - return `/fonts/${machine_name}.zip`; - } else { - return `https://fonts.google.com/specimen/${fontFamily}`; + return `/fonts/${machineName}.zip`; } + return `https://fonts.google.com/specimen/${fontFamily}`; }); return (
diff --git a/src/app/pages/assets/index.tsx b/src/app/pages/assets/index.tsx index 7d1d08e0..ae8a684c 100644 --- a/src/app/pages/assets/index.tsx +++ b/src/app/pages/assets/index.tsx @@ -18,7 +18,7 @@ import { DocumentationProps, fetchDocPageMarkdown, getClientRuntimeConfig } from * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/', 'assets', `/assets`).props, @@ -27,7 +27,7 @@ export const getStaticProps: GetStaticProps = async (context) => { }; }; -const AssetsPage = ({ content, menu, metadata, current, config }: DocumentationProps) => { +const AssetsPage = ({ content, menu, metadata, config }: DocumentationProps) => { return (
diff --git a/src/app/pages/assets/logos.tsx b/src/app/pages/assets/logos.tsx index 4ee58770..e25e4ae2 100644 --- a/src/app/pages/assets/logos.tsx +++ b/src/app/pages/assets/logos.tsx @@ -17,7 +17,7 @@ import { DocumentationProps, fetchDocPageMarkdown, getClientRuntimeConfig } from * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/assets/', 'logos', `/assets`).props, @@ -26,7 +26,7 @@ export const getStaticProps: GetStaticProps = async (context) => { }; }; -const AssetsLogosPage = ({ content, menu, metadata, current, config }: DocumentationProps) => { +const AssetsLogosPage = ({ content, menu, metadata, config }: DocumentationProps) => { return (
diff --git a/src/app/pages/foundations/colors.tsx b/src/app/pages/foundations/colors.tsx index da9bf5d7..683ba29a 100644 --- a/src/app/pages/foundations/colors.tsx +++ b/src/app/pages/foundations/colors.tsx @@ -22,7 +22,7 @@ import { getTokens } from '../../components/util'; * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...util.fetchFoundationDocPageMarkdown('docs/foundations/', 'colors', `/foundations`).props, diff --git a/src/app/pages/foundations/icons/[name]/index.tsx b/src/app/pages/foundations/icons/[name]/index.tsx index f3455b0e..16874157 100644 --- a/src/app/pages/foundations/icons/[name]/index.tsx +++ b/src/app/pages/foundations/icons/[name]/index.tsx @@ -58,7 +58,7 @@ export async function getStaticPaths() { * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = (context) => { +export const getStaticProps: GetStaticProps = () => { return { props: { ...fetchDocPageMarkdown('docs/foundations/', 'icons', `/foundations`).props, @@ -68,10 +68,13 @@ export const getStaticProps: GetStaticProps = (context) => { }; }; -export default function SingleIcon({ content, menu, metadata, current, config, assets }: AssetDocumentationProps) { +export default function SingleIcon({ menu, metadata, current, config, assets }: AssetDocumentationProps) { const router = useRouter(); - let { name } = router.query; - const icon = assets?.icons.find((icon) => icon.icon === name); + const nameParam = router.query.name; + let name = undefined; + if (typeof nameParam === 'string') { name = nameParam } else if (Array.isArray(nameParam)) { name = nameParam[0] } else { name = undefined } + const icon = assets?.icons.find((i) => i.icon === name); + const copySvg = React.useCallback( (event) => { event.preventDefault(); diff --git a/src/app/pages/foundations/icons/index.tsx b/src/app/pages/foundations/icons/index.tsx index c3270178..3a749bfc 100644 --- a/src/app/pages/foundations/icons/index.tsx +++ b/src/app/pages/foundations/icons/index.tsx @@ -52,7 +52,7 @@ export const DisplayIcon: React.FC<{ icon: CoreTypes.IAssetObject }> = ({ icon } * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/foundations/', 'icons', `/foundations`).props, diff --git a/src/app/pages/foundations/index.tsx b/src/app/pages/foundations/index.tsx index d4fcbb1c..2bfcd8c3 100644 --- a/src/app/pages/foundations/index.tsx +++ b/src/app/pages/foundations/index.tsx @@ -17,7 +17,7 @@ import { DocumentationProps, fetchDocPageMarkdown, getClientRuntimeConfig } from * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/', 'foundations', `/foundations`).props, diff --git a/src/app/pages/foundations/logo.tsx b/src/app/pages/foundations/logo.tsx index 6d619c63..c7a378b4 100644 --- a/src/app/pages/foundations/logo.tsx +++ b/src/app/pages/foundations/logo.tsx @@ -36,7 +36,7 @@ import { buttonVariants } from '../../components/ui/button'; * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/foundations/', 'logo', `/foundations`).props, diff --git a/src/app/pages/foundations/typography.tsx b/src/app/pages/foundations/typography.tsx index dfc29722..611557bc 100644 --- a/src/app/pages/foundations/typography.tsx +++ b/src/app/pages/foundations/typography.tsx @@ -62,16 +62,6 @@ const Typography = ({ }; }, {} as FontFamily); - const type_copy = config?.app?.type_copy ?? 'Almost before we knew it, we had left the ground.'; - - const typographyCategories = typography.reduce((acc, type) => { - if (type.name.includes('/')) { - const category = type.name.split('/')[0].trim(); - acc.add(category); - } - return acc; - }, new Set()); - return (
diff --git a/src/app/pages/index.tsx b/src/app/pages/index.tsx index d0db0211..ed0aabd0 100644 --- a/src/app/pages/index.tsx +++ b/src/app/pages/index.tsx @@ -2,7 +2,6 @@ import { ArrowRight, Component, Hexagon, Layers, Shapes } from 'lucide-react'; import { GetStaticProps } from 'next'; import Image from 'next/image'; import Link from 'next/link'; -import { useRouter } from 'next/router'; import ReactMarkdown from 'react-markdown'; import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; @@ -21,7 +20,7 @@ import { DocumentationProps, fetchDocPageMarkdown, getClientRuntimeConfig } from * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { return { props: { ...fetchDocPageMarkdown('docs/', 'index', `/`).props, @@ -31,8 +30,6 @@ export const getStaticProps: GetStaticProps = async (context) => { }; const Home = ({ content, menu, metadata, config, current }: DocumentationProps) => { - const router = useRouter(); - return (
diff --git a/src/app/pages/system/component/[component]/index.tsx b/src/app/pages/system/component/[component]/index.tsx index 3a801938..978ecb08 100644 --- a/src/app/pages/system/component/[component]/index.tsx +++ b/src/app/pages/system/component/[component]/index.tsx @@ -110,7 +110,7 @@ export const getStaticProps = async (context) => { }; function filterPreviews(previews: Record, filter: Filter): Record { - return Object.fromEntries(Object.entries(previews).filter(([_, preview]) => evaluateFilter(preview.values, filter))); + return Object.fromEntries(Object.entries(previews).filter(([, preview]) => evaluateFilter(preview.values, filter))); } const GenericComponentPage = ({ menu, metadata, current, id, config, componentHotReloadIsAvailable, previousComponent, nextComponent }) => { @@ -123,7 +123,7 @@ const GenericComponentPage = ({ menu, metadata, current, id, config, componentHo const componentRoute = (componentId: string) => `${normalizedBasePath}/system/component/${componentId}`; const fetchComponents = async () => { - let data = await fetch(`${normalizedBasePath}/api/component/${id}.json`).then((res) => res.json()); + const data = await fetch(`${normalizedBasePath}/api/component/${id}.json`).then((res) => res.json()); setComponent(data as PreviewObject); }; diff --git a/src/app/pages/system/index.tsx b/src/app/pages/system/index.tsx index 0a2b1650..41df768c 100644 --- a/src/app/pages/system/index.tsx +++ b/src/app/pages/system/index.tsx @@ -30,7 +30,7 @@ type ComponentPageDocumentationProps = DocumentationProps; * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { +export const getStaticProps: GetStaticProps = async () => { // Read current slug const config = getClientRuntimeConfig(); return { @@ -49,7 +49,7 @@ const ComponentsPage = ({ content, menu, metadata, current, config }: ComponentP // Fetch components from api const [components, setComponents] = useState(undefined); const fetchComponents = async () => { - let data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`).then((res) => res.json()); + const data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`).then((res) => res.json()); setComponents(data as PreviewObject[]); }; useEffect(() => { diff --git a/src/app/pages/system/tokens/components/[component]/index.tsx b/src/app/pages/system/tokens/components/[component]/index.tsx index 6b3c4ab8..87aa2779 100644 --- a/src/app/pages/system/tokens/components/[component]/index.tsx +++ b/src/app/pages/system/tokens/components/[component]/index.tsx @@ -67,7 +67,6 @@ const GenericComponentPage = ({ menu, metadata, current, - id, config, component, options, @@ -101,11 +100,11 @@ const GenericComponentPage = ({ ); }; -export const getComponentPreviews = ( +export function getComponentPreviews( tab: 'overview' | 'tokens', component: CoreTypes.IFileComponentObject, options: ComponentDocumentationOptions -) => { +): ComponentPreview[] { const instances = component.instances; const view = (options?.views ?? {})[tab] ?? {}; const viewFilters = view.condition ?? {}; @@ -147,13 +146,10 @@ export const getComponentPreviews = ( // Filter value object keys do not contain the value of the respective component property // Since component should not be displayed we return null value return null; - } else { - // Filter value object keys do contain the value of the respective component property - // We will store the property value of the filter value object for later use - overrides = filterValue[variantProps.get(filterProp)]; - // Use as a default possibly distinctive name - name ??= variantProps.get(filterProp); } + // Filter value object keys do contain the value of the respective component property + overrides = filterValue[variantProps.get(filterProp)]; + name ??= variantProps.get(filterProp); } } else if (typeof filterValue === 'string' && variantProps.get(filterProp) !== filterValue) { return null; @@ -175,7 +171,7 @@ export const getComponentPreviews = ( } return tabComponents; -}; +} function multiPropSort(properties: string[], array: ComponentPreview[]) { return array.sort((l, r) => { @@ -199,14 +195,10 @@ function multiPropSort(properties: string[], array: ComponentPreview[]) { }); } -const IsColorValue = (value: string) => { - return value.match(/^#[0-9A-F]{6}$/i) || value.match(/linear-gradient\(.*?\)|rgba\(.*?\)/); -}; - const NormalizeValue = (value: string): string => { if (!Number.isNaN(Number(value))) { const numericValue = Number(value); - if (numericValue % 1 != 0) { + if (numericValue % 1 !== 0) { return round(numericValue, 2).toFixed(2); } } @@ -220,7 +212,6 @@ export interface ComponentDesignTokensProps { previewObjectOptions?: CoreTypes.IHandoffConfigurationComponentOptions; componentInstances: CoreTypes.IComponentInstance[]; overrides?: { [variantProp: string]: string[] }; - children?: React.ReactNode; renderPreviews: boolean; useReferences: boolean; } @@ -228,23 +219,19 @@ export interface ComponentDesignTokensProps { interface DataTableRow extends Map { } interface DataTable extends Map { } -export const ComponentDesignTokens: React.FC = ({ +export function ComponentDesignTokens({ title, componentInstances, previewObject, previewObjectOptions, overrides, - children, - renderPreviews, useReferences, -}) => { +}: ComponentDesignTokensProps) { const previewObjectVariantPropsMap = new Map(previewObject.variantProperties); - const [showReference, setShowReference] = React.useState(useReferences); + const [showReference] = React.useState(useReferences); const headings: Set = new Set(); const dataTable = new Map() as DataTable; - let numberOfColumns = 0; - if (overrides) { const overrideVariantProps = Object.keys(overrides) ?? []; const masterOverride = overrideVariantProps[0]; @@ -278,9 +265,6 @@ export const ComponentDesignTokens: React.FC = ({ .push([token.name, token.value, token ?? undefined]); }); - // Increase columns count - numberOfColumns++; - // Append heading to the list of headings headings.add(componentVariantPropsMap.get(masterOverride)); }); @@ -299,9 +283,6 @@ export const ComponentDesignTokens: React.FC = ({ .push([token.name, token.value, token ?? undefined]); }); - // Increase columns count - numberOfColumns++; - // Append heading to the list of headings headings.add('Value'); } @@ -310,8 +291,6 @@ export const ComponentDesignTokens: React.FC = ({ return <>; } - const layoutLeftColWidth = renderPreviews ? (numberOfColumns >= 7 ? 11 : 4 + numberOfColumns) : 12; - const layoutRightColWidth = 12 - layoutLeftColWidth; const headingsTotal = Array.from(headings).length + 1; return ( @@ -341,26 +320,19 @@ export const ComponentDesignTokens: React.FC = ({ {Array.from(propertiesMap) .sort(([lProp], [rProp]) => lProp.localeCompare(rProp)) - .map(([prop, cells], i) => ( + .map(([, cells], i) => ( - {/*

{prop}

*/} {cells[0][0]}
- {cells.map(([_, tokenValue, tokenReference], i) => ( - - {/* {IsColorValue(tokenValue) && ( -
- )} */} - {/* */} - {!showReference ? ( - NormalizeValue(tokenValue) - ) : tokenReference ? ( - <>{tokenReferenceFormat(tokenReference, 'css')} - ) : ( - NormalizeValue(tokenValue) - )} + {cells.map(([, tokenValue, tokenReference], cellIdx) => ( + + {(() => { + if (!showReference) return NormalizeValue(tokenValue); + if (tokenReference) return <>{tokenReferenceFormat(tokenReference, 'css')} ; + return NormalizeValue(tokenValue); + })()} ))}
@@ -371,6 +343,6 @@ export const ComponentDesignTokens: React.FC = ({ ); -}; +} export default GenericComponentPage; diff --git a/src/app/pages/system/tokens/foundations/colors.tsx b/src/app/pages/system/tokens/foundations/colors.tsx index f3b6a7b1..c3002587 100644 --- a/src/app/pages/system/tokens/foundations/colors.tsx +++ b/src/app/pages/system/tokens/foundations/colors.tsx @@ -19,8 +19,7 @@ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeCon * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { - // Read current slug +export const getStaticProps: GetStaticProps = async () => { const config = getClientRuntimeConfig(); return { ...{ @@ -32,6 +31,36 @@ export const getStaticProps: GetStaticProps = async (context) => { }, }; }; + +const ColorGroupTable = ({ colors }: { group: string; colors: CoreTypes.IColorObject[] }) => { + return ( + + + + Name + Value + + + + {colors.map((color) => ( + + {color.reference} + +
+ + {color.value} +
+
+
+ ))} +
+
+ ); +}; + /** * Define the components page * @param param0 @@ -94,33 +123,4 @@ const ComponentsPage = ({ content, menu, metadata, current, config, design }: Fo ); }; -const ColorGroupTable = ({ group, colors }: { group: string; colors: CoreTypes.IColorObject[] }) => { - return ( - - - - Name - Value - - - - {colors.map((color) => ( - - {color.reference} - -
- - {color.value} -
-
-
- ))} -
-
- ); -}; - export default ComponentsPage; diff --git a/src/app/pages/system/tokens/foundations/effects.tsx b/src/app/pages/system/tokens/foundations/effects.tsx index 127c4821..b2949feb 100644 --- a/src/app/pages/system/tokens/foundations/effects.tsx +++ b/src/app/pages/system/tokens/foundations/effects.tsx @@ -19,8 +19,7 @@ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeCon * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { - // Read current slug +export const getStaticProps: GetStaticProps = async () => { const config = getClientRuntimeConfig(); return { ...{ @@ -32,6 +31,30 @@ export const getStaticProps: GetStaticProps = async (context) => { }, }; }; + +const EffectsTable = ({ effects }: { group: string; effects: CoreTypes.IEffectObject[] }) => { + return ( + + + + Reference + Effects + + + + {effects.map((effect) => ( + + {effect.reference.replace(/-+/g, '-')} + + {effect.effects.map((effect) => effect.value).join(', ') || 'none'} + + + ))} + +
+ ); +}; + /** * Define the components page * @param param0 @@ -87,27 +110,4 @@ const ComponentsPage = ({ content, menu, metadata, current, config, design }: Fo ); }; -const EffectsTable = ({ group, effects }: { group: string; effects: CoreTypes.IEffectObject[] }) => { - return ( - - - - Reference - Effects - - - - {effects.map((effect) => ( - - {effect.reference.replace(/-+/g, '-')} - - {effect.effects.map((effect) => effect.value).join(', ') || 'none'} - - - ))} - -
- ); -}; - export default ComponentsPage; diff --git a/src/app/pages/system/tokens/foundations/typography.tsx b/src/app/pages/system/tokens/foundations/typography.tsx index 4d79e287..254add6a 100644 --- a/src/app/pages/system/tokens/foundations/typography.tsx +++ b/src/app/pages/system/tokens/foundations/typography.tsx @@ -20,8 +20,7 @@ import { fetchDocPageMarkdown, FoundationDocumentationProps, getClientRuntimeCon * @param context GetStaticProps * @returns */ -export const getStaticProps: GetStaticProps = async (context) => { - // Read current slug +export const getStaticProps: GetStaticProps = async () => { const config = getClientRuntimeConfig(); return { ...{ @@ -33,40 +32,6 @@ export const getStaticProps: GetStaticProps = async (context) => { }, }; }; -/** - * Define the components page - * @param param0 - * @returns - */ -const ComponentsPage = ({ content, menu, metadata, current, config, design }: FoundationDocumentationProps) => { - const typography = design.typography.slice().sort((a, b) => { - const l = (config?.app?.type_sort ?? []).indexOf(a.name) >>> 0; - const r = (config?.app?.type_sort ?? []).indexOf(b.name) >>> 0; - return l !== r ? l - r : a.name.localeCompare(b.name); - }); - - return ( - -
- {metadata.title} -

{metadata.description}

-
-
-
-
- - {content} - -
- -
- ({ [`${type.name}-typography`]: `${upperFirst(type.name)}` }))])]} - /> -
-
- ); -}; const FontsTable = ({ types }: { types: CoreTypes.ITypographyObject[] }) => { return ( @@ -114,6 +79,41 @@ const FontsTable = ({ types }: { types: CoreTypes.ITypographyObject[] }) => { ); }; +/** + * Define the components page + * @param param0 + * @returns + */ +const ComponentsPage = ({ content, menu, metadata, current, config, design }: FoundationDocumentationProps) => { + const typography = design.typography.slice().sort((a, b) => { + const l = (config?.app?.type_sort ?? []).indexOf(a.name) >>> 0; + const r = (config?.app?.type_sort ?? []).indexOf(b.name) >>> 0; + return l !== r ? l - r : a.name.localeCompare(b.name); + }); + + return ( + +
+ {metadata.title} +

{metadata.description}

+
+
+
+
+ + {content} + +
+ +
+ ({ [`${type.name}-typography`]: `${upperFirst(type.name)}` }))])]} + /> +
+
+ ); +}; + export const pluckStyle = (type: CoreTypes.ITypographyObject) => { return { fontFamily: type.values.fontFamily, diff --git a/src/cli.ts b/src/cli.ts index 553f21b3..48d397b8 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -19,7 +19,7 @@ class HandoffCliError extends Error { * Show the help message */ const showVersion = () => { - return 'Handoff App - 1.2.1'; + return 'Handoff App - 1.2.2'; }; /** diff --git a/src/transformers/preview/component.ts b/src/transformers/preview/component.ts index 1f8bdf8f..9f854f3a 100644 --- a/src/transformers/preview/component.ts +++ b/src/transformers/preview/component.ts @@ -2,10 +2,10 @@ import type { DocAnnotation, TypeNode } from 'handoff-docgen'; import path from 'path'; import Handoff from '../../index'; import { getAPIPath } from './component/api'; -import writeComponentSummaryAPI from './component/summary'; import processComponents from './component/builder'; import { buildMainCss } from './component/css'; import { buildMainJS } from './component/javascript'; +import writeComponentSummaryAPI from './component/summary'; export interface ComponentMetadata { title: string; @@ -33,7 +33,7 @@ export interface SlotMetadata { name: string; description: string; generic: string; - default?: string; + default?: string | number | boolean | object | any[] | null; type: SlotType; // used if type is array items?: {