diff --git a/.changeset/add-ci-workflow.md b/.changeset/add-ci-workflow.md new file mode 100644 index 0000000..7e709c8 --- /dev/null +++ b/.changeset/add-ci-workflow.md @@ -0,0 +1,5 @@ +--- +typestyles: patch +--- + +Add CI workflow for lint, typecheck, and test diff --git a/.changeset/add-next-package.md b/.changeset/add-next-package.md new file mode 100644 index 0000000..e86bb2e --- /dev/null +++ b/.changeset/add-next-package.md @@ -0,0 +1,5 @@ +--- +'@typestyles/next': minor +--- + +Add @typestyles/next package for Next.js SSR integration diff --git a/.changeset/add-vite-tests.md b/.changeset/add-vite-tests.md new file mode 100644 index 0000000..8416331 --- /dev/null +++ b/.changeset/add-vite-tests.md @@ -0,0 +1,5 @@ +--- +'@typestyles/vite': patch +--- + +Add additional test coverage for vite plugin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c5f02b3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,76 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run lint + run: pnpm run lint + + typecheck: + name: Typecheck + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run typecheck + run: pnpm run typecheck + + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run tests + run: pnpm run test diff --git a/packages/next/package.json b/packages/next/package.json new file mode 100644 index 0000000..37008fa --- /dev/null +++ b/packages/next/package.json @@ -0,0 +1,63 @@ +{ + "name": "@typestyles/next", + "version": "0.1.0", + "description": "Next.js integration for typestyles SSR", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./src/index.d.ts", + "exports": { + ".": { + "types": "./src/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "tsup" + }, + "keywords": [ + "next", + "nextjs", + "typestyles", + "ssr", + "react" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/dbanksdesign/typestyles", + "directory": "packages/next" + }, + "peerDependencies": { + "next": ">=13.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0", + "typestyles": "workspace:*" + }, + "peerDependenciesMeta": { + "next": { + "optional": false + }, + "react": { + "optional": false + }, + "react-dom": { + "optional": false + } + }, + "devDependencies": { + "@types/node": "^25.2.1", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "next": "^14.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "tsup": "^8.0.0", + "typescript": "^5.4.0" + } +} diff --git a/packages/next/src/index.d.ts b/packages/next/src/index.d.ts new file mode 100644 index 0000000..f631ad0 --- /dev/null +++ b/packages/next/src/index.d.ts @@ -0,0 +1,13 @@ +export { getRegisteredCss } from 'typestyles/server'; + +export interface TypestylesStylesheetProps { + children?: React.ReactNode; +} + +export function TypestylesStylesheet(props: TypestylesStylesheetProps): React.JSX.Element; + +export function collectStylesFromComponent(component: React.ReactElement): Promise; + +export function createTypestylesLayout

( + layout: (props: P) => React.ReactNode, +): (props: P) => React.JSX.Element; diff --git a/packages/next/src/index.tsx b/packages/next/src/index.tsx new file mode 100644 index 0000000..e1abd60 --- /dev/null +++ b/packages/next/src/index.tsx @@ -0,0 +1,106 @@ +import React, { useEffect, useState } from 'react'; +import { collectStyles, getRegisteredCss } from 'typestyles/server'; + +export { getRegisteredCss }; + +/** + * Props for the TypestylesStylesheet component. + */ +export interface TypestylesStylesheetProps { + /** + * The children to render (styles will be collected from these). + * If not provided, only the existing registered CSS will be included. + */ + children?: React.ReactNode; +} + +/** + * A React component that renders typestyles CSS. + * + * For App Router: Use this in your root layout to collect and render styles. + * + * @example + * ```tsx + * // app/layout.tsx + * import { TypestylesStylesheet } from '@typestyles/next'; + * + * export default function RootLayout({ children }) { + * return ( + * + * + * + * + * {children} + * + * ); + * } + * ``` + */ +export function TypestylesStylesheet({ children }: TypestylesStylesheetProps) { + const [css, setCss] = useState(''); + + useEffect(() => { + // On client: get any CSS that was registered before hydration + setCss(getRegisteredCss()); + }, []); + + if (children) { + return ( + <> + {children} +