diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5ad9cb0..ceb91338 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,9 +4,11 @@ on: pull_request: branches: - main + # - solid2 # enable later push: branches: - main + # - solid2 # enable later jobs: build: @@ -20,10 +22,10 @@ jobs: - uses: pnpm/action-setup@v4 - - name: Setup Node.js 21.6.1 - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@v6 with: - node-version: 21.6.1 + node-version: "24" cache: pnpm - name: Install dependencies diff --git a/.github/workflows/format-files-prettier.yml b/.github/workflows/format-files-prettier.yml index 804f4efa..80d81461 100644 --- a/.github/workflows/format-files-prettier.yml +++ b/.github/workflows/format-files-prettier.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - solid2 paths: - "**.md" - "**.mdx" @@ -15,6 +16,7 @@ on: push: branches: - main + - solid2 jobs: prettier: diff --git a/.github/workflows/format-files.yml b/.github/workflows/format-files.yml index b2d1d923..8b20880c 100644 --- a/.github/workflows/format-files.yml +++ b/.github/workflows/format-files.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - solid2 paths: - "**.js" - "**.jsx" @@ -14,6 +15,7 @@ on: push: branches: - main + - solid2 jobs: biome: diff --git a/.github/workflows/jsr-ci.yml b/.github/workflows/jsr-ci.yml new file mode 100644 index 00000000..3bf71bcd --- /dev/null +++ b/.github/workflows/jsr-ci.yml @@ -0,0 +1,47 @@ +name: JSR validation + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + jsr: + name: Validate JSR workspace + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: pnpm + + - name: Set up Deno + uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + + - name: Install dependencies + run: pnpm install + + - name: Check deno.jsonc/package.json version and exports sync + run: pnpm jsr:sync:check + + - name: Build libraries + run: pnpm build:libs + env: + NODE_OPTIONS: "--max_old_space_size=4096" + + - name: Publish dry run with full type checks + run: deno publish --dry-run --allow-slow-types diff --git a/.github/workflows/jsr-publish.yml b/.github/workflows/jsr-publish.yml new file mode 100644 index 00000000..19899dbf --- /dev/null +++ b/.github/workflows/jsr-publish.yml @@ -0,0 +1,57 @@ +name: Publish JSR + +on: + workflow_dispatch: + inputs: + publish: + description: Run the real JSR publish after the dry run passes + required: true + default: "false" + type: choice + options: + - "false" + - "true" + +permissions: + contents: read + id-token: write + +jobs: + publish: + name: Publish JSR workspace + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: pnpm + + - name: Set up Deno + uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + + - name: Install dependencies + run: pnpm install + + - name: Sync deno.jsonc versions and exports from package.json + run: pnpm jsr:sync + + - name: Build libraries + run: pnpm build:libs + env: + NODE_OPTIONS: "--max_old_space_size=4096" + + - name: Publish dry run + run: deno publish --dry-run --allow-slow-types + + - name: Publish to JSR + if: ${{ inputs.publish == 'true' }} + run: deno publish --allow-slow-types diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 004b912e..7d864531 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: [workflow_dispatch] permissions: id-token: write - contents: read + contents: write concurrency: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 21dd48e0..c290df3a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,9 +4,11 @@ on: pull_request: branches: - main + - solid2 push: branches: - main + - solid2 jobs: build: @@ -20,10 +22,10 @@ jobs: - uses: pnpm/action-setup@v4 - - name: Setup Node.js 21.6.1 - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@v6 with: - node-version: 21.6.1 + node-version: "24" cache: pnpm - name: Install dependencies diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index b4878ca3..db71b8ed 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -16,10 +16,10 @@ jobs: - uses: pnpm/action-setup@v4 - - name: Setup Node.js 21.6.1 - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@v6 with: - node-version: 21.6.1 + node-version: "24" cache: pnpm - name: Install Dependencies diff --git a/.gitignore b/.gitignore index 34a09ff9..b18d7a7d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log +.claude # local env files .env.local @@ -17,9 +18,6 @@ lerna-debug.log .env.test.local .env.production.local -# turbo -.turbo - # solid .solid .vinxi @@ -43,3 +41,4 @@ packages/core/NOTICE.txt .DS_Store Thumbs.db .vercel +/storybook-static diff --git a/.storybook/globals.css b/.storybook/globals.css new file mode 100644 index 00000000..426571b7 --- /dev/null +++ b/.storybook/globals.css @@ -0,0 +1,2 @@ +@source "./.storybook/**/*.{ts,tsx}"; +@source "./packages/core/src/**/*.{ts,tsx}"; diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 00000000..3f667384 --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,88 @@ +import type { StorybookConfig } from "storybook-solidjs-vite"; +import { mergeConfig } from "vite"; + +const config: StorybookConfig = { + stories: ["../packages/core/src/**/stories/*.stories.{ts,tsx}"], + staticDirs: ["./public"], + addons: ["@storybook/addon-docs"], + framework: { + name: "storybook-solidjs-vite", + // docgen: false — storybook-solidjs-vite@10.5.2 bug: dynamic import('typescript') + // returns { default: ts } in ESM context so ts.sys is undefined inside the plugin + options: { docgen: false }, + }, + docs: {}, + async viteFinal(config) { + return mergeConfig(config, { + plugins: [ + { + name: "solid-addEventListener-compat", + transform(code: string, id: string) { + if ( + /\.(tsx?|jsx?)$/.test(id) && + code.includes("addEventListener as _$addEventListener") + ) { + return { + code: code.replace( + /\{ addEventListener as _\$addEventListener \}/g, + "{ addEvent as _$addEventListener }", + ), + map: null, + }; + } + }, + }, + // Intercept any file that imports the removed `on` helper from solid-js. + // Logs the filename so we can find the culprit, and replaces the import + // with a shim so rendering continues. + { + name: "solid-on-shim", + transform(code: string, id: string) { + if ( + code.includes("from 'solid-js'") || + code.includes('from "solid-js"') + ) { + if (/\bon\b/.test(code)) { + const hasOnImport = + /import\s*\{[^}]*\bon\b[^}]*\}\s*from\s*['"]solid-js['"]/.test( + code, + ); + if (hasOnImport) { + console.warn( + `[solid-on-shim] Found legacy 'on' import in: ${id}`, + ); + // Remove 'on' from the import and inject a no-op shim after the import + const patched = code + .replace(/,\s*\bon\b/g, "") + .replace(/\bon\b\s*,/g, "") + .replace(/\{\s*\bon\b\s*\}/g, "{ createEffect }"); + return { + code: + patched + + "\nconst on = (deps, fn) => { createEffect(deps, fn); };\n", + map: null, + }; + } + } + } + }, + }, + ], + resolve: { + alias: [ + { find: "solid-js/web", replacement: "@solidjs/web" }, + { + find: "@kobalte/utils", + replacement: new URL( + "../packages/utils/src/index.ts", + import.meta.url, + ).pathname, + }, + ], + dedupe: ["react", "react-dom", "solid-js", "@solidjs/signals", "@solidjs/web"], + }, + }); + }, +}; + +export default config; diff --git a/.storybook/manager.ts b/.storybook/manager.ts new file mode 100644 index 00000000..468395a8 --- /dev/null +++ b/.storybook/manager.ts @@ -0,0 +1,12 @@ +import { addons } from "storybook/manager-api"; +import { create } from "storybook/theming/create"; + +addons.setConfig({ + theme: create({ + base: "light", + brandTitle: "Kobalte", + brandImage: "/kobalte-logo.svg", + brandUrl: "https://kobalte.dev", + brandTarget: "_blank", + }), +}); diff --git a/.storybook/preview.ts b/.storybook/preview.ts new file mode 100644 index 00000000..d08dbb0e --- /dev/null +++ b/.storybook/preview.ts @@ -0,0 +1,8 @@ +import * as docsAnnotations from "@storybook/addon-docs/preview"; +import { definePreview } from "storybook-solidjs-vite/next"; +import "./globals.css"; + +export default definePreview({ + addons: [docsAnnotations], + parameters: { layout: "centered", docs: { toc: true } }, +}); diff --git a/.storybook/public/kobalte-logo.svg b/.storybook/public/kobalte-logo.svg new file mode 100644 index 00000000..3cfa8037 --- /dev/null +++ b/.storybook/public/kobalte-logo.svg @@ -0,0 +1,9 @@ + diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json new file mode 100644 index 00000000..e7ea5eb1 --- /dev/null +++ b/.storybook/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "jsxImportSource": "@solidjs/web", + "customConditions": ["@solid-primitives/source"], + "verbatimModuleSyntax": false, + "types": ["vite/client"] + }, + "include": ["./**/*", "../packages/core/src/*/stories/**/*"] +} diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 00000000..39aad710 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,102 @@ +# Solid 2.0 Migration Guide + +## Import paths + +`JSX`, `ValidComponent`, and `ComponentProps` moved out of `solid-js` into `@solidjs/web`. + +```ts +// before +import type { JSX, ValidComponent, ComponentProps } from "solid-js"; + +// after +import type { JSX, ValidComponent, ComponentProps } from "@solidjs/web"; +``` + +`solid-js/web` (the DOM renderer) is now `@solidjs/web`. + +```ts +import { render } from "@solidjs/web"; +``` + +## HTML attributes are lowercase + +Solid 2.0 uses lowercase HTML attribute names on native elements, matching the HTML spec rather than React conventions. + +```tsx +// before +
+ + +// after + + +``` + +This affects any `RenderProps` interface whose props are spread onto native elements via `Polymorphic`. Both the interface definition and the JSX must use the lowercase name. + +Other affected attributes: `autocomplete`, `autocorrect`, `spellcheck`, `enterkeyhint`, `contenteditable`, `inputmode`. + +## Renamed helpers + +| Solid 1.x | Solid 2.0 | +|-----------|-----------| +| `mergeProps` | `merge` | +| `splitProps` | `omit` | +| `unwrap` | `snapshot` | +| `onMount` | `onSettled` | +| `createComputed` | `createEffect` (split form) / `createMemo` | +| `Index` | `