From 1bd9053794b01e035483a81237a5c3e238ee9e85 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Jul 2026 17:51:31 +1000 Subject: [PATCH] Clean up generator, docs generation, and docs app validation (#57) --- README.md | 2 +- apps/docs/package.json | 3 +- apps/docs/src/routes/docs/$.tsx | 3 +- apps/docs/vite.config.ts | 48 ++++++++++++++----- .../src/__tests__/discover-exports.test.ts | 11 +++++ .../docs-tools/src/discover-exports.ts | 1 + .../@luke-ui/react/scripts/generate-docs.ts | 14 +++++- .../react/src/build/package-scripts.test.ts | 25 +++++++++- packages/turbo-generators/config.ts | 44 +++++------------ packages/turbo-generators/package.json | 1 + .../src/apply-component-creation-plan.test.ts | 2 +- .../src/apply-component-creation-plan.ts | 2 +- .../src/component-creation-plan.test.ts | 17 +++++++ .../src/component-creation-plan.ts | 8 ++-- packages/turbo-generators/src/config.test.ts | 24 ++++++++++ .../component/component.docs-page.mdx.hbs | 9 ---- .../component/component.docs.mdx.hbs | 18 ------- .../component/component.recipe.css.ts.hbs | 39 --------------- .../component/component.stories.tsx.hbs | 21 -------- .../templates/component/component.tsx.hbs | 24 ---------- pnpm-lock.yaml | 6 +++ 21 files changed, 156 insertions(+), 166 deletions(-) create mode 100644 packages/turbo-generators/src/config.test.ts delete mode 100644 packages/turbo-generators/templates/component/component.docs-page.mdx.hbs delete mode 100644 packages/turbo-generators/templates/component/component.docs.mdx.hbs delete mode 100644 packages/turbo-generators/templates/component/component.recipe.css.ts.hbs delete mode 100644 packages/turbo-generators/templates/component/component.stories.tsx.hbs delete mode 100644 packages/turbo-generators/templates/component/component.tsx.hbs diff --git a/README.md b/README.md index a1980487..9d8e62ea 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Components to build: - [ ] Badge - [ ] EmptyState -- [ ] LoadingSkeleton +- [x] LoadingSkeleton - [ ] Notice - [ ] ShowMore - [ ] Toast diff --git a/apps/docs/package.json b/apps/docs/package.json index f01617a6..d5d32574 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -36,7 +36,8 @@ "react": "catalog:", "react-dom": "catalog:", "ts-morph": "catalog:", - "vite": "catalog:" + "vite": "catalog:", + "zod": "catalog:" }, "devDependencies": { "@tailwindcss/vite": "catalog:", diff --git a/apps/docs/src/routes/docs/$.tsx b/apps/docs/src/routes/docs/$.tsx index 3ef0426d..74acb15a 100644 --- a/apps/docs/src/routes/docs/$.tsx +++ b/apps/docs/src/routes/docs/$.tsx @@ -6,6 +6,7 @@ import { DocsLayout } from 'fumadocs-ui/layouts/docs'; import { DocsBody, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'; import defaultMdxComponents from 'fumadocs-ui/mdx'; import { Suspense } from 'react'; +import * as z from 'zod'; import browserCollections from '../../../.source/browser'; import { PageActions } from '../../components/page-actions'; import { baseOptions } from '../../lib/layout.shared'; @@ -28,7 +29,7 @@ export const Route = createFileRoute('/docs/$')({ const loader = createServerFn({ method: 'GET', }) - .inputValidator((slugs: Array) => slugs) + .inputValidator((slugs) => z.array(z.string()).parse(slugs)) // staticFunctionMiddleware breaks Vite HMR in dev — only apply in prod build. .middleware(import.meta.env.PROD ? [staticFunctionMiddleware] : []) .handler(async ({ data: slugs }) => { diff --git a/apps/docs/vite.config.ts b/apps/docs/vite.config.ts index 108340f9..f63d8a98 100644 --- a/apps/docs/vite.config.ts +++ b/apps/docs/vite.config.ts @@ -15,6 +15,7 @@ import { nitro } from 'nitro/vite'; import { readdir, readFile } from 'node:fs/promises'; import type { Plugin } from 'vite-plus'; import { defineConfig, lazyPlugins } from 'vite-plus'; +import * as z from 'zod'; import packageJson from '../../packages/@luke-ui/react/package.json' with { type: 'json' }; import { mapPublicToInternal, toInternal, toPublic } from './src/lib/markdown-url'; @@ -68,24 +69,32 @@ const packageDocsDir = fileURLToPath( // routes serve these to AI agents fetching public `.md` URLs. We can't read them via // `import.meta.glob` because `fumadocs-mdx/vite` compiles any `.md`/`.mdx` it // sees into a React component, even with the `?raw` query. -function packageDocsPlugin(catalog: Array): Plugin { +const packageJsonPath = join(packageRootDir, 'package.json'); +const packageJsonSchema = z.object({ + exports: z.record(z.string(), z.string()), +}); + +async function readPackageDocsCatalog(): Promise> { + const currentPackageJson = packageJsonSchema.parse( + JSON.parse(await readFile(packageJsonPath, 'utf8')), + ); + return resolvePackageDocsCatalog({ + exportsField: currentPackageJson.exports, + packageRoot: packageRootDir, + }); +} + +function packageDocsPlugin(): Plugin { const id = 'virtual:package-docs'; const resolved = `\0${id}`; - const metadata: Array = catalog.map((entry) => ({ - description: entry.description, - pageKind: entry.pageKind, - path: entry.path, - shape: entry.shape, - slug: entry.slug, - target: entry.target, - tier: entry.tier, - title: entry.title, - })); return { configureServer(server) { server.watcher.add(packageDocsDir); + server.watcher.add(packageJsonPath); const handle = (filePath: string) => { - if (!filePath.endsWith('.md') || !filePath.startsWith(packageDocsDir)) return; + const isPackageDoc = filePath.endsWith('.md') && filePath.startsWith(packageDocsDir); + const isPackageJson = filePath === packageJsonPath; + if (!isPackageDoc && !isPackageJson) return; const mod = server.moduleGraph.getModuleById(resolved); if (mod) { server.moduleGraph.invalidateModule(mod); @@ -99,6 +108,17 @@ function packageDocsPlugin(catalog: Array): Plugin { enforce: 'pre', async load(loadId) { if (loadId !== resolved) return null; + const catalog = await readPackageDocsCatalog(); + const metadata: Array = catalog.map((entry) => ({ + description: entry.description, + pageKind: entry.pageKind, + path: entry.path, + shape: entry.shape, + slug: entry.slug, + target: entry.target, + tier: entry.tier, + title: entry.title, + })); const entries = await Promise.all( catalog .filter((entry) => entry.pageKind !== 'asset') @@ -179,6 +199,7 @@ function packageSourceWatcherPlugin(): Plugin { let pendingRun = false; function shouldTrigger(filePath: string): boolean { + if (filePath === packageJsonPath) return true; if (!filePath.startsWith(packageSrcDir)) return false; return filePath.endsWith('.tsx') || filePath.endsWith('.ts') || filePath.endsWith('.docs.md'); } @@ -238,6 +259,7 @@ function packageSourceWatcherPlugin(): Plugin { apply: 'serve', configureServer(server) { server.watcher.add(packageSrcDir); + server.watcher.add(packageJsonPath); const logger = { error: (msg: string) => server.config.logger.error(msg, { timestamp: true }), info: (msg: string) => server.config.logger.info(msg, { timestamp: true }), @@ -296,7 +318,7 @@ export default defineConfig(async () => { plugins: lazyPlugins(async () => [ staticFunctionBasePathPlugin(), markdownRewritePlugin(), - packageDocsPlugin(packageDocsCatalog), + packageDocsPlugin(), packageSourceWatcherPlugin(), mdx(await import('./source.config')), story({ tsconfigPath: fileURLToPath(new URL('./tsconfig.json', import.meta.url)) }), diff --git a/packages/@luke-ui/docs-tools/src/__tests__/discover-exports.test.ts b/packages/@luke-ui/docs-tools/src/__tests__/discover-exports.test.ts index 57324b3b..9e49a86c 100644 --- a/packages/@luke-ui/docs-tools/src/__tests__/discover-exports.test.ts +++ b/packages/@luke-ui/docs-tools/src/__tests__/discover-exports.test.ts @@ -56,6 +56,17 @@ describe('discoverExports', () => { expect(result.every((e) => e.pageKind === 'barrel')).toBe(true); }); + it('classifies styles as foundation barrel API', () => { + const exports = { './styles': './dist/styles/index.js' }; + + const result = discoverExports(exports); + + expect(result.find((e) => e.path === './styles')).toMatchObject({ + pageKind: 'barrel', + shape: 'barrel', + }); + }); + it('classifies stylesheet/spritesheet/package.json as asset', () => { const exports = { './package.json': './package.json', diff --git a/packages/@luke-ui/docs-tools/src/discover-exports.ts b/packages/@luke-ui/docs-tools/src/discover-exports.ts index f0c8d3e5..98b179d1 100644 --- a/packages/@luke-ui/docs-tools/src/discover-exports.ts +++ b/packages/@luke-ui/docs-tools/src/discover-exports.ts @@ -41,6 +41,7 @@ export const DEFAULT_BARREL_PATHS: ReadonlyArray = [ './heading-context', './icon-size-context', './recipes', + './styles', './theme', './tokens', './utils', diff --git a/packages/@luke-ui/react/scripts/generate-docs.ts b/packages/@luke-ui/react/scripts/generate-docs.ts index 8acf070f..d90e16db 100644 --- a/packages/@luke-ui/react/scripts/generate-docs.ts +++ b/packages/@luke-ui/react/scripts/generate-docs.ts @@ -4,7 +4,7 @@ import { resolvePackageDocsCatalog } from '@luke-ui/docs-tools/package-docs-cata import { renderIndex } from '@luke-ui/docs-tools/render-index'; import { renderLlmsFull } from '@luke-ui/docs-tools/render-llms-full'; import { renderPage } from '@luke-ui/docs-tools/render-page'; -import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'; import packageJson from '../package.json' with { type: 'json' }; const packageRoot = fileURLToPath(new URL('../', import.meta.url)); @@ -16,6 +16,7 @@ const catalog = resolvePackageDocsCatalog({ }); await mkdir(docsDir, { recursive: true }); +await removeGeneratedMarkdown(docsDir); const pages = await Promise.all( catalog.map(async (entry) => { @@ -50,6 +51,7 @@ await writeFile(join(docsDir, 'llms.txt'), llmsTxt, 'utf8'); const distDocsDir = join(packageRoot, 'dist', 'docs'); await mkdir(distDocsDir, { recursive: true }); +await removeGeneratedMarkdown(distDocsDir); const llmsFull = renderLlmsFull(pages.filter((page) => page != null)); await writeFile(join(distDocsDir, 'llms-full.md'), llmsFull, 'utf8'); @@ -64,3 +66,13 @@ async function readProse(root: string, entry: { path: string }): Promise { + const files = await readdir(dir); + + await Promise.all( + files + .filter((file) => file.endsWith('.md')) + .map((file) => rm(join(dir, file), { force: true })), + ); +} diff --git a/packages/@luke-ui/react/src/build/package-scripts.test.ts b/packages/@luke-ui/react/src/build/package-scripts.test.ts index 0448d286..1911d897 100644 --- a/packages/@luke-ui/react/src/build/package-scripts.test.ts +++ b/packages/@luke-ui/react/src/build/package-scripts.test.ts @@ -1,9 +1,17 @@ +import { execFile } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { readFile } from 'node:fs/promises'; +import { promisify } from 'node:util'; +import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import { describe, expect, it } from 'vite-plus/test'; import { z } from 'zod'; +const execFileAsync = promisify(execFile); const packageJsonPath = fileURLToPath(new URL('../../package.json', import.meta.url)); +const packageRoot = fileURLToPath(new URL('../../', import.meta.url)); +const docsDir = fileURLToPath(new URL('../../docs/', import.meta.url)); +const staleDocsPath = fileURLToPath( + new URL('../../docs/use-synchronize-animations.md', import.meta.url), +); const turboJsonPath = fileURLToPath(new URL('../../../../../turbo.json', import.meta.url)); const packageJsonSchema = z.object({ scripts: z.record(z.string(), z.string()), @@ -29,4 +37,19 @@ describe('package scripts', () => { expect(turboJson.tasks['@luke-ui/react#generate:docs']?.dependsOn).toContain('build'); expect(turboJson.tasks['docs#dev']?.dependsOn).toContain('@luke-ui/react#generate:docs'); }); + + it('removes stale generated package docs before writing current pages', async () => { + await mkdir(docsDir, { recursive: true }); + await writeFile(staleDocsPath, '# stale page\n', 'utf8'); + + try { + await execFileAsync('pnpm', ['exec', 'tsx', 'scripts/generate-docs.ts'], { + cwd: packageRoot, + }); + + await expect(access(staleDocsPath)).rejects.toMatchObject({ code: 'ENOENT' }); + } finally { + await rm(staleDocsPath, { force: true }); + } + }); }); diff --git a/packages/turbo-generators/config.ts b/packages/turbo-generators/config.ts index 97c9e862..58493f32 100644 --- a/packages/turbo-generators/config.ts +++ b/packages/turbo-generators/config.ts @@ -1,27 +1,26 @@ import type { PlopTypes } from '@turbo/gen'; +import * as z from 'zod'; import { applyComponentCreationPlan } from './src/apply-component-creation-plan.js'; -import type { - ComponentStyling, - ComponentTier, - CreateComponentInput, -} from './src/component-creation-plan.js'; +import type { CreateComponentInput } from './src/component-creation-plan.js'; import { createComponentPlan } from './src/component-creation-plan.js'; const DOCS_GROUPS = ['actions', 'feedback', 'forms', 'typography', 'visuals'] as const; const COMPONENT_NAME_RE = /^[A-Za-z][A-Za-z0-9-]*$/; +const COMPONENT_TIERS = ['atom', 'composed'] as const; +const COMPONENT_STYLING = ['none', 'recipe'] as const; -interface ComponentAnswers { - docsGroup?: string; - name?: string; - styling?: ComponentStyling; - tier?: ComponentTier; -} +const componentAnswersSchema = z.object({ + docsGroup: z.enum(DOCS_GROUPS), + name: z.string().min(1), + styling: z.enum(COMPONENT_STYLING), + tier: z.enum(COMPONENT_TIERS), +}); export default function generator(plop: PlopTypes.NodePlopAPI): void { plop.setGenerator('component', { actions: [ async (answers) => { - const input = toComponentInput(answers as ComponentAnswers); + const input = parseComponentAnswers(answers); const plan = createComponentPlan(input); await applyComponentCreationPlan(process.cwd(), plan); return `Created ${plan.expected.packageExportPath}`; @@ -63,25 +62,8 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void { }); } -function toComponentInput(answers: ComponentAnswers): CreateComponentInput { - if (!answers.name) { - throw new Error('Component name required.'); - } - if (!answers.tier) { - throw new Error('Component tier required.'); - } - if (!answers.docsGroup) { - throw new Error('Docs group required.'); - } - if (!answers.styling) { - throw new Error('Styling required.'); - } - return { - docsGroup: answers.docsGroup, - name: answers.name, - styling: answers.styling, - tier: answers.tier, - }; +export function parseComponentAnswers(answers: unknown): CreateComponentInput { + return componentAnswersSchema.parse(answers); } function validateComponentName(value: unknown): true | string { diff --git a/packages/turbo-generators/package.json b/packages/turbo-generators/package.json index ed059a1f..951b2b71 100644 --- a/packages/turbo-generators/package.json +++ b/packages/turbo-generators/package.json @@ -13,6 +13,7 @@ "devDependencies": { "@types/node": "catalog:", "tsx": "catalog:", + "vite-plus": "catalog:", "zod": "catalog:" } } diff --git a/packages/turbo-generators/src/apply-component-creation-plan.test.ts b/packages/turbo-generators/src/apply-component-creation-plan.test.ts index ed2e5a17..ccca8c17 100644 --- a/packages/turbo-generators/src/apply-component-creation-plan.test.ts +++ b/packages/turbo-generators/src/apply-component-creation-plan.test.ts @@ -2,7 +2,7 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; import { afterEach, describe, expect, it } from 'vite-plus/test'; -import { z } from 'zod'; +import * as z from 'zod'; import { applyComponentCreationPlan } from './apply-component-creation-plan.js'; import type { ComponentCreationPlan } from './component-creation-plan.js'; diff --git a/packages/turbo-generators/src/apply-component-creation-plan.ts b/packages/turbo-generators/src/apply-component-creation-plan.ts index 0455fd58..dd9cfc45 100644 --- a/packages/turbo-generators/src/apply-component-creation-plan.ts +++ b/packages/turbo-generators/src/apply-component-creation-plan.ts @@ -1,6 +1,6 @@ import { dirname, join } from 'node:path'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; -import { z } from 'zod'; +import * as z from 'zod'; import type { ComponentCreationPlan, JsonArrayAddSortedEdit, diff --git a/packages/turbo-generators/src/component-creation-plan.test.ts b/packages/turbo-generators/src/component-creation-plan.test.ts index 3c77d024..86b2c7f7 100644 --- a/packages/turbo-generators/src/component-creation-plan.test.ts +++ b/packages/turbo-generators/src/component-creation-plan.test.ts @@ -92,4 +92,21 @@ describe('createComponentPlan', () => { 'apps/docs/content/docs/components/actions/meta.json', ]); }); + + it('omits cx from components without styling', () => { + const plan = createComponentPlan({ + docsGroup: 'feedback', + name: 'PlainBadge', + styling: 'none', + tier: 'atom', + }); + + const source = plan.files.find((file) => + file.path.endsWith('/plain-badge/index.tsx'), + )?.contents; + + expect(source).not.toContain("import { cx } from '../utils/index.js';"); + expect(source).not.toContain('cx('); + expect(source).toContain('className={className}'); + }); }); diff --git a/packages/turbo-generators/src/component-creation-plan.ts b/packages/turbo-generators/src/component-creation-plan.ts index 1feed1b7..38c0e865 100644 --- a/packages/turbo-generators/src/component-creation-plan.ts +++ b/packages/turbo-generators/src/component-creation-plan.ts @@ -1,5 +1,5 @@ -export type ComponentTier = 'atom' | 'composed'; -export type ComponentStyling = 'none' | 'recipe'; +type ComponentTier = 'atom' | 'composed'; +type ComponentStyling = 'none' | 'recipe'; export interface CreateComponentInput { docsGroup: string; @@ -156,6 +156,7 @@ function renderComponentSource(input: { styling: ComponentStyling; tier: ComponentTier; }): string { + const cxImport = input.styling === 'recipe' ? "import { cx } from '../utils/index.js';\n" : ''; const styleImport = input.styling === 'recipe' ? `import * as styles from '../recipes/${input.name}.css.js';\n` @@ -167,8 +168,7 @@ function renderComponentSource(input: { : ' className={className}'; return `import type { ComponentProps, JSX } from 'react'; -import { cx } from '../utils/index.js'; -${styleImport} +${cxImport}${styleImport} /** Props for \`${input.pascalName}\`. * * @tier ${input.tier} diff --git a/packages/turbo-generators/src/config.test.ts b/packages/turbo-generators/src/config.test.ts new file mode 100644 index 00000000..772ad970 --- /dev/null +++ b/packages/turbo-generators/src/config.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vite-plus/test'; +import { ZodError } from 'zod'; +import { parseComponentAnswers } from '../config.js'; + +const validAnswers = { + docsGroup: 'feedback', + name: 'StatusBadge', + styling: 'recipe', + tier: 'atom', +}; + +describe('parseComponentAnswers', () => { + it('rejects invalid tier answers', () => { + expect(() => parseComponentAnswers({ ...validAnswers, tier: 'molecule' })).toThrow(ZodError); + }); + + it('rejects invalid styling answers', () => { + expect(() => parseComponentAnswers({ ...validAnswers, styling: 'css' })).toThrow(ZodError); + }); + + it('rejects invalid docs group answers', () => { + expect(() => parseComponentAnswers({ ...validAnswers, docsGroup: 'layout' })).toThrow(ZodError); + }); +}); diff --git a/packages/turbo-generators/templates/component/component.docs-page.mdx.hbs b/packages/turbo-generators/templates/component/component.docs-page.mdx.hbs deleted file mode 100644 index 894d9de7..00000000 --- a/packages/turbo-generators/templates/component/component.docs-page.mdx.hbs +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: {{displayName name}} -description: Documentation for the {{displayName name}} component. ---- - -import {{pascalCase name}}Docs from '../../../../../../packages/@luke-ui/react/src/{{kebabCase name}}.docs.mdx'; -import defaultMdxComponents from 'fumadocs-ui/mdx'; - -<{{pascalCase name}}Docs components={defaultMdxComponents} /> diff --git a/packages/turbo-generators/templates/component/component.docs.mdx.hbs b/packages/turbo-generators/templates/component/component.docs.mdx.hbs deleted file mode 100644 index 43c1c425..00000000 --- a/packages/turbo-generators/templates/component/component.docs.mdx.hbs +++ /dev/null @@ -1,18 +0,0 @@ -`{{pascalCase name}}` from `@luke-ui/react/{{kebabCase name}}`. - -## Import - -```ts -import { {{pascalCase name}} } from '@luke-ui/react/{{kebabCase name}}'; -``` - -## Usage - -## Props - -| Prop | Type | Default | Notes | -| ----------- | -------- | ------------ | ----- | -| `children` | `ReactNode` | | | -| `className` | `string` | | | -| `color` | `string` | `'neutralBold'` | Foreground color token. | -| `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Size variant. | diff --git a/packages/turbo-generators/templates/component/component.recipe.css.ts.hbs b/packages/turbo-generators/templates/component/component.recipe.css.ts.hbs deleted file mode 100644 index d68ae0da..00000000 --- a/packages/turbo-generators/templates/component/component.recipe.css.ts.hbs +++ /dev/null @@ -1,39 +0,0 @@ -import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { recipeInLayer } from '../styles/layered-style.css.js'; -import { vars } from '../styles/vars.css.js'; -import { tokenKeys, tokens } from '../tokens.js'; - -const colorKeys = tokenKeys(tokens.foregroundColor); - -const colorVariants = Object.fromEntries( - colorKeys.map((key) => [key, { color: vars.color[key] }]), -); - -export const {{camelCase name}} = recipeInLayer('recipes', { - base: { - display: 'inline-flex', - fontFamily: vars.font.family.body, - fontWeight: vars.font.weight.medium, - lineHeight: vars.font.lineHeight.loose, - }, - defaultVariants: { - color: 'neutralBold', - size: 'medium', - }, - variants: { - color: colorVariants, - size: { - small: { - fontSize: vars.font.size.small, - }, - medium: { - fontSize: vars.font.size.standard, - }, - large: { - fontSize: vars.font.size.large, - }, - }, - }, -}); - -export type {{pascalCase name}}Variants = RecipeVariants; diff --git a/packages/turbo-generators/templates/component/component.stories.tsx.hbs b/packages/turbo-generators/templates/component/component.stories.tsx.hbs deleted file mode 100644 index 4e9b9638..00000000 --- a/packages/turbo-generators/templates/component/component.stories.tsx.hbs +++ /dev/null @@ -1,21 +0,0 @@ -import type { {{pascalCase name}}Props } from '@luke-ui/react/{{kebabCase name}}'; -import { {{pascalCase name}} } from '@luke-ui/react/{{kebabCase name}}'; -import { expect } from 'storybook/test'; -import preview from '../.storybook/preview.js'; - -const meta = preview.meta({ - component: {{pascalCase name}}, - tags: ['{{kebabCase group}}'], - title: '{{displayName group}}/{{pascalCase name}}', -}); - -const baseArgs = { - children: '{{pascalCase name}}', -} satisfies Partial<{{pascalCase name}}Props>; - -export const Default = meta.story({ - args: baseArgs, - play: async ({ canvas }) => { - await expect(canvas.getByText('{{pascalCase name}}')).toBeInTheDocument(); - }, -}); diff --git a/packages/turbo-generators/templates/component/component.tsx.hbs b/packages/turbo-generators/templates/component/component.tsx.hbs deleted file mode 100644 index 882556be..00000000 --- a/packages/turbo-generators/templates/component/component.tsx.hbs +++ /dev/null @@ -1,24 +0,0 @@ -import type { ComponentProps, JSX } from 'react'; -import type { DistributiveOmit } from '../types/distributive-omit.js'; -import { cx } from '../utils/index.js'; -import * as styles from '../recipes/{{kebabCase name}}.css.js'; - -interface {{pascalCase name}}VariantProps - extends NonNullable {} - -/** Props for `{{pascalCase name}}`. */ -export interface {{pascalCase name}}Props - extends DistributiveOmit, 'color'>, - {{pascalCase name}}VariantProps {} - -/** Styled `{{pascalCase name}}` primitive component. */ -export function {{pascalCase name}}(props: {{pascalCase name}}Props): JSX.Element { - const { className, color, size, ...divProps } = props; - - return ( -
- ); -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 713ba24d..a38b6fd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -258,6 +258,9 @@ importers: vite: specifier: npm:@voidzero-dev/vite-plus-core@latest version: '@voidzero-dev/vite-plus-core@0.2.1(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0)' + zod: + specifier: 'catalog:' + version: 4.4.3 devDependencies: '@tailwindcss/vite': specifier: 'catalog:' @@ -472,6 +475,9 @@ importers: tsx: specifier: 'catalog:' version: 4.22.4 + vite-plus: + specifier: 'catalog:' + version: 0.2.1(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) zod: specifier: 'catalog:' version: 4.4.3 -- 2.51.2