From 774daf0ce4e0f38c897fd3fb2a743bd706fbcbc0 Mon Sep 17 00:00:00 2001 From: Kholiq Amrulloh Date: Wed, 16 Sep 2026 10:06:06 +0700 Subject: [PATCH] feat(solid): add SolidJS adapter with SSR and hydration support --- .github/workflows/ci-solid.yml | 57 + .github/workflows/publish-solid.yml | 76 + README.md | 134 +- SolidJS Adapter Contribution Draft.md | 53 + ...JS Adapter Contribution Plan for uiGrid.md | 1974 ++++++++++++++ SolidJS Adapter Implementation.md | 190 ++ SolidJS Adapter Work Flow.md | 323 +++ package.json | 3 + projects/ui-grid-solid/README.md | 203 ++ projects/ui-grid-solid/demo/index.html | 3 + projects/ui-grid-solid/demo/main.tsx | 197 ++ projects/ui-grid-solid/demo/styles.css | 202 ++ .../examples/solid-start/README.md | 14 + .../examples/solid-start/src/routes/about.tsx | 8 + .../examples/solid-start/src/routes/index.tsx | 32 + .../examples/solid-start/tsconfig.json | 13 + projects/ui-grid-solid/package-lock.json | 2401 +++++++++++++++++ projects/ui-grid-solid/package.json | 44 + .../ui-grid-solid/scripts/hydration.test.mjs | 94 + .../scripts/package-consumer.test.mjs | 93 + .../scripts/render-hydration-fixture.mjs | 14 + projects/ui-grid-solid/scripts/ssr.test.mjs | 29 + projects/ui-grid-solid/src/UiGrid.test.tsx | 635 +++++ projects/ui-grid-solid/src/UiGrid.tsx | 204 ++ projects/ui-grid-solid/src/cellEditors.ts | 168 ++ projects/ui-grid-solid/src/cellRenderers.ts | 137 + projects/ui-grid-solid/src/detailRenderer.ts | 142 + projects/ui-grid-solid/src/headerRenderers.ts | 171 ++ projects/ui-grid-solid/src/index.ts | 6 + projects/ui-grid-solid/src/styles.d.ts | 1 + projects/ui-grid-solid/tsconfig.build.json | 8 + projects/ui-grid-solid/tsconfig.json | 13 + projects/ui-grid-solid/vite.config.ts | 18 + projects/ui-grid-solid/vitest.config.ts | 18 + scripts/build-solid.mjs | 21 + scripts/sync-versions.mjs | 3 + 36 files changed, 7672 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/ci-solid.yml create mode 100644 .github/workflows/publish-solid.yml create mode 100644 SolidJS Adapter Contribution Draft.md create mode 100644 SolidJS Adapter Contribution Plan for uiGrid.md create mode 100644 SolidJS Adapter Implementation.md create mode 100644 SolidJS Adapter Work Flow.md create mode 100644 projects/ui-grid-solid/README.md create mode 100644 projects/ui-grid-solid/demo/index.html create mode 100644 projects/ui-grid-solid/demo/main.tsx create mode 100644 projects/ui-grid-solid/demo/styles.css create mode 100644 projects/ui-grid-solid/examples/solid-start/README.md create mode 100644 projects/ui-grid-solid/examples/solid-start/src/routes/about.tsx create mode 100644 projects/ui-grid-solid/examples/solid-start/src/routes/index.tsx create mode 100644 projects/ui-grid-solid/examples/solid-start/tsconfig.json create mode 100644 projects/ui-grid-solid/package-lock.json create mode 100644 projects/ui-grid-solid/package.json create mode 100644 projects/ui-grid-solid/scripts/hydration.test.mjs create mode 100644 projects/ui-grid-solid/scripts/package-consumer.test.mjs create mode 100644 projects/ui-grid-solid/scripts/render-hydration-fixture.mjs create mode 100644 projects/ui-grid-solid/scripts/ssr.test.mjs create mode 100644 projects/ui-grid-solid/src/UiGrid.test.tsx create mode 100644 projects/ui-grid-solid/src/UiGrid.tsx create mode 100644 projects/ui-grid-solid/src/cellEditors.ts create mode 100644 projects/ui-grid-solid/src/cellRenderers.ts create mode 100644 projects/ui-grid-solid/src/detailRenderer.ts create mode 100644 projects/ui-grid-solid/src/headerRenderers.ts create mode 100644 projects/ui-grid-solid/src/index.ts create mode 100644 projects/ui-grid-solid/src/styles.d.ts create mode 100644 projects/ui-grid-solid/tsconfig.build.json create mode 100644 projects/ui-grid-solid/tsconfig.json create mode 100644 projects/ui-grid-solid/vite.config.ts create mode 100644 projects/ui-grid-solid/vitest.config.ts create mode 100644 scripts/build-solid.mjs diff --git a/.github/workflows/ci-solid.yml b/.github/workflows/ci-solid.yml new file mode 100644 index 0000000..475842f --- /dev/null +++ b/.github/workflows/ci-solid.yml @@ -0,0 +1,57 @@ +name: CI Solid + +on: + pull_request: + paths: + - '.github/workflows/ci-solid.yml' + - '.github/workflows/publish-solid.yml' + - 'projects/ui-grid-solid/**' + - 'projects/ui-grid-core/**' + - 'projects/ui-grid-vanilla/**' + - 'scripts/build-solid.mjs' + - 'scripts/sync-versions.mjs' + - 'package.json' + - 'package-lock.json' + push: + branches: + - main + paths: + - '.github/workflows/ci-solid.yml' + - '.github/workflows/publish-solid.yml' + - 'projects/ui-grid-solid/**' + - 'projects/ui-grid-core/**' + - 'projects/ui-grid-vanilla/**' + - 'scripts/build-solid.mjs' + - 'scripts/sync-versions.mjs' + - 'package.json' + - 'package-lock.json' + workflow_dispatch: + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v7 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 26.4.0 + cache: npm + cache-dependency-path: | + package-lock.json + projects/ui-grid-solid/package-lock.json + + - name: Install repository dependencies + run: npm ci --legacy-peer-deps + + - name: Install Solid adapter dependencies + run: npm ci --prefix projects/ui-grid-solid + + - name: Build Solid adapter and internal dependencies + run: npm run build:solid + + - name: Run Solid integration, SSR, hydration, package, and example checks + run: npm run test:solid diff --git a/.github/workflows/publish-solid.yml b/.github/workflows/publish-solid.yml new file mode 100644 index 0000000..32f9bde --- /dev/null +++ b/.github/workflows/publish-solid.yml @@ -0,0 +1,76 @@ +name: Publish Solid package + +on: + workflow_dispatch: + inputs: + ref: + description: Branch, tag, or commit to publish + required: true + default: main + version: + description: Public version to publish + required: true + default: 0.1.0 + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v7 + with: + ref: ${{ inputs.ref }} + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 26.4.0 + registry-url: https://registry.npmjs.org + scope: '@ornery' + always-auth: true + cache: npm + cache-dependency-path: | + package-lock.json + projects/ui-grid-solid/package-lock.json + + - name: Install repository dependencies + run: npm ci --legacy-peer-deps + + - name: Install Solid adapter dependencies + run: npm ci --prefix projects/ui-grid-solid + + - name: Verify internal packages are published + run: | + VERSION="${{ inputs.version }}" + npm view "@ornery/ui-grid-core@$VERSION" version + npm view "@ornery/ui-grid-vanilla@$VERSION" version + + - name: Build and test the Solid package + run: | + npm run build:solid + npm run test:solid + + - name: Set and verify the publish manifest + env: + VERSION: ${{ inputs.version }} + run: | + node - <<'NODE' + const fs = require('node:fs'); + const path = './projects/ui-grid-solid/package.json'; + const pkg = require(path); + pkg.version = process.env.VERSION; + for (const name of ['@ornery/ui-grid-core', '@ornery/ui-grid-vanilla']) { + pkg.peerDependencies[name] = process.env.VERSION; + } + fs.writeFileSync(path, `${JSON.stringify(pkg, null, 2)}\n`); + if (pkg.version !== process.env.VERSION) throw new Error('Package version was not updated'); + for (const name of ['@ornery/ui-grid-core', '@ornery/ui-grid-vanilla']) { + if (pkg.peerDependencies[name] !== process.env.VERSION) throw new Error(`Invalid ${name} peer`); + } + NODE + + - name: Publish to npm + run: npm publish ./projects/ui-grid-solid --access public --registry=https://registry.npmjs.org + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 2195c01..5486d45 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ # UI Grid — Remastered -**The modern multi-platform data grid. Every feature free and open source. Built for Angular, Web-Components, React, native Rust/egui, and native C/LVGL.** +**The modern multi-platform data grid. Every feature free and open source. Built for Angular, Web Components, React, SolidJS, native Rust/egui, and native C/LVGL.** A from-scratch rewrite of the original [AngularJS ui-grid](https://github.com/angular-ui/ui-grid) — by the original author. Same `gridOptions` / `columnDefs` / `onRegisterApi` api surface, modern Angular signals internals, and zero legacy baggage. @@ -24,7 +24,7 @@ It proves that the datagrid cabal wants you to think it's hard to write a data g - **Original authorship** — built by the same engineer who created AngularJS ui-grid, with a decade of hindsight on what worked and what didn't - **Familiar API** — if you used the original ui-grid, you already know this one: `gridOptions`, `columnDefs`, `onRegisterApi`, `gridApi.core.*` -- **Modern internals** — shared vanilla web component core with Shadow DOM encapsulation; Angular and React wrappers are thin bridges that project framework templates into the vanilla element via slot-based portals +- **Modern internals** — shared vanilla web component core with Shadow DOM encapsulation; Angular, React, and SolidJS wrappers are thin bridges that project framework templates into the vanilla element via slot-based portals - **No legacy** — no `$scope`, no Bower, no Grunt, no jQuery, no module system from 2013 --- @@ -62,6 +62,7 @@ Everything below ships free and MIT-licensed. No enterprise tier, no license key | **SSR Support** | **Free** | — | ~$999/dev/yr | — | — | — | | i18n (6 locales built-in) | **Free** | Free | — | Free | Paid | Community\* | | React | **Yes** | Wrapper | Wrapper | No | Wrapper | Wrapper | +| SolidJS | **Yes** | Wrapper | Wrapper | No | Wrapper | Wrapper | | Rust/egui Native | **Yes** | No | No | No | No | No | | C/LVGL Native | **Yes** | No | No | No | No | No | | Angular | **Yes** | Wrapper | Wrapper | No | Wrapper | Wrapper | @@ -138,9 +139,76 @@ function MyGrid() { } ``` +### SolidJS + +The SolidJS adapter mounts the same vanilla Web Component while preserving +SolidJS ownership, reactive props, local renderer state, and lifecycle cleanup. +It supports browser rendering, SSR and hydration, custom JSX cells and headers, +expandable detail rows, and JSX cell editors. + +```bash +npm install @ornery/ui-grid-solid @ornery/ui-grid-core @ornery/ui-grid-vanilla solid-js @solidjs/web +``` + +Configure the SolidJS JSX runtime with `jsxImportSource: "@solidjs/web"`, then +pass reactive options to `UiGrid`: + +```tsx +/** @jsxImportSource @solidjs/web */ +import { createSignal } from 'solid-js'; +import { UiGrid, type GridOptions, type UiGridCellRenderers } from '@ornery/ui-grid-solid'; + +const cellRenderers: UiGridCellRenderers = { + name: (context) => {String(context.value)}, +}; + +export function PeopleGrid() { + const [rows, setRows] = createSignal([ + { id: 1, name: 'Alice', role: 'Engineer' }, + { id: 2, name: 'Bob', role: 'Designer' }, + ]); + + const options = (): GridOptions => ({ + id: 'people-grid', + data: rows(), + columnDefs: [{ name: 'name' }, { name: 'role' }], + rowIdentity: (row) => String(row['id']), + enableSorting: true, + enableFiltering: true, + enableVirtualization: true, + }); + + return ( +
+ + +
+ ); +} +``` + +`options` uses the shared `GridOptions` contract. The adapter updates the same +grid element when signals change, so interactive sorting, filters, column order, +and other controller state remain intact. `onRegisterApi` exposes the shared +`UiGridApi`; all projected SolidJS roots and subscriptions are disposed when the +component unmounts. + +See the [SolidJS adapter guide](projects/ui-grid-solid/README.md), the +[implementation notes](), and the +[SolidStart example](projects/ui-grid-solid/examples/solid-start/README.md). + ### Web Components (Vanilla) -The grid's rendering engine is a framework-free custom element (``) built on `@ornery/ui-grid-core` with pure DOM rendering and Shadow DOM encapsulation. Both the Angular and React wrappers are thin bridges around this same element — they mount ``, pass options, and project framework-specific templates into it via a slot-based portal system. +The grid's rendering engine is a framework-free custom element (``) built on `@ornery/ui-grid-core` with pure DOM rendering and Shadow DOM encapsulation. The Angular, React, and SolidJS wrappers are thin bridges around this same element — they mount ``, pass options, and project framework-specific templates into it via a slot-based portal system. ```bash npm install @ornery/ui-grid-vanilla @ornery/ui-grid-core @@ -282,9 +350,9 @@ The LVGL demo currently exercises the native C grid shell with sorting, grouping - **Save/Restore State** — serialize and restore sort, filters, grouping, collapsed groups, pinning, column order, column widths, pagination, selection, focused cell, tree/expandable expansion, and scroll position (per-field opt-in flags) - **Native Rust and C Grids** — shared Rust core with native Rust/egui and native C/LVGL adapters driven by the same projection and command contract - **Auto Resize** — ResizeObserver-driven viewport height recalculation -- **Custom Cell Templates** — Angular `ng-template`, React `cellRenderers` map (per-column render functions), vanilla `