diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..5de781e45 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ +### Context + + +### Types of changes + +- [ ] New example +- [ ] Update to an existing example +- [ ] README / documentation change +- [ ] Demo runner (`runner/`) change +- [ ] CI / tooling change + +### How was this verified? + + +### Checklist +- [ ] New/renamed example: added to `runner/config/frameworks.json` (see [CONTRIBUTING.md](CONTRIBUTING.md)); otherwise it won't appear on demos.handsontable.com +- [ ] New example: added a row to the tables in [README.md](README.md) +- [ ] Ran `pnpm build` (and `pnpm dev`) in the affected example/server-example locally + +### Related issue(s): +1. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..cf0f3c05b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,22 @@ +# AGENTS.md, handsontable/examples + +This repository holds runnable Handsontable example projects (`examples/`, +`server-examples/`) and the self-hosted demo runner behind +demos.handsontable.com (`runner/`, see [`runner/AGENTS.md`](./runner/AGENTS.md) +for that subsystem specifically). + +## Adding or changing an example + +Follow [CONTRIBUTING.md](./CONTRIBUTING.md), in particular registering a new +example in `runner/config/frameworks.json` so it appears on the live demo +site. Skipping that step fails silently (no error, the example just never +shows up on demos.handsontable.com), so don't assume it's covered by CI +passing. + +## Opening a pull request + +Always fill in [`.github/PULL_REQUEST_TEMPLATE.md`](./.github/PULL_REQUEST_TEMPLATE.md), +including its Context, Types of changes, How was this verified, Checklist, and +Related issue(s) sections. Do not leave GitHub's default blank PR body, and do +not compose a PR description that skips the template. This applies equally to +PRs opened by an AI agent and PRs opened by a person. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..0ed94c93a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing to handsontable/examples + +Thanks for wanting to add or improve an example. + +## Adding a new example + +1. Create `examples//` (or `server-examples//`) as a self-contained + project: its own `package.json`, its own lockfile, its own README describing + what it shows. Use an existing example's README as the template rather than + starting from scratch, e.g. [`examples/react/README.md`](./examples/react/README.md). +2. Give it a `build` script and commit a `pnpm-lock.yaml`. + [`.github/workflows/examples-build.yml`](./.github/workflows/examples-build.yml) + discovers example folders at CI runtime by scanning for exactly that + combination. No workflow file needs editing to get build coverage. +3. Add a row for it to the relevant table in [README.md](./README.md). + +### Register it with the live demo runner (easy to miss) + +A new `examples//` folder does **not** automatically show up on +[demos.handsontable.com](https://demos.handsontable.com). The demo runner only +imports frameworks that have a matching key in +[`runner/config/frameworks.json`](./runner/config/frameworks.json). +`runner/pipeline/import.mjs` reads that file's keys, not the `examples/` +directory. Miss this step and the folder still builds fine in CI, but stays +invisible on the live demo site: no error, it just never appears. + +- Add an entry for your example to `runner/config/frameworks.json` (tier, + engine/container, entry file, dev/build commands, etc.), copying the shape + of a similar existing entry. +- If it's a Tier-2 (container-based, e.g. meta-framework) example, also + regenerate the container assets: `node runner/scripts/prepare-container.mjs`. +- The demo catalog then regenerates automatically the next time a push to + `master` touches `examples/**` + ([`.github/workflows/import-starters.yml`](./.github/workflows/import-starters.yml) + opens a `chore/starter-example-buckets` PR), or you can run it locally from + `runner/`: `node pipeline/import.mjs`. + +## Updating an existing example + +Same rules apply: keep it self-contained, keep its README accurate, and +re-run `node pipeline/import.mjs` (or push to `master`) if you changed anything +the runner reads from `frameworks.json`. + +## Pull requests + +Fill in `.github/PULL_REQUEST_TEMPLATE.md` when you open the PR, in particular +the `frameworks.json` checklist item; that's the step people forget. diff --git a/README.md b/README.md index 68505efed..a1a7b4c68 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,30 @@ -# Handsontable examples - -Runnable code examples for [Handsontable](https://handsontable.com), the JavaScript -data grid. Every example here is a real, self-contained project you can clone, run, +
+ + + + Logo of Handsontable data grid + +

Runnable code examples for the Handsontable JavaScript data grid.

+ + Website +  •  + Documentation +  •  + Live demos +  •  + Community +
+ +
+ +Every example here is a real, self-contained project you can clone, run, and copy into your own codebase. The same examples power the live demos in the [Handsontable documentation](https://handsontable.com/docs) and at **[demos.handsontable.com](https://demos.handsontable.com)**, where you can open any of them in the browser, edit the code, switch the Handsontable version, and share a -permanent link — no install needed. +permanent link. No install needed. ## Client examples @@ -16,29 +32,29 @@ Each folder in [`examples/`](./examples) is an independent project with its own `package.json` and lockfile. Install and run one on its own; there is no root install step. -| Example | What it shows | -|---------|---------------| -| [`example1`](./examples/example1) | Vanilla TypeScript (Vite) — the general-purpose feature tour | -| [`javascript`](./examples/javascript) | Plain JavaScript (Vite) | -| [`typescript`](./examples/typescript) | TypeScript (Vite) | -| [`react`](./examples/react) | React with TypeScript (Vite) | -| [`react-js`](./examples/react-js) | React with JavaScript (Vite) | -| [`vue`](./examples/vue) | Vue 3 (Vite) | -| [`angular`](./examples/angular) | Angular | -| [`next.js`](./examples/next.js) | Next.js, App Router | -| [`next-shadcn.js`](./examples/next-shadcn.js) | Next.js with shadcn/ui | -| [`nuxt`](./examples/nuxt) | Nuxt 3 | -| [`astro`](./examples/astro) | Astro | -| [`remix`](./examples/remix) | Remix | -| [`ant-design`](./examples/ant-design) | Handsontable themed to match Ant Design | -| [`mui`](./examples/mui) | Handsontable themed to match MUI | -| [`base-web`](./examples/base-web) | Handsontable themed to match Base Web | -| [`fluent-ui`](./examples/fluent-ui) | Handsontable themed to match Fluent UI | +| Example | What it shows | Live demo | +|---------|---------------|-----------| +| [`example1`](./examples/example1) | Vanilla TypeScript (Vite), the general-purpose feature tour | [Open](https://demos.handsontable.com/?example=example1) | +| [`javascript`](./examples/javascript) | Plain JavaScript (Vite) | [Open](https://demos.handsontable.com/?example=javascript) | +| [`typescript`](./examples/typescript) | TypeScript (Vite) | [Open](https://demos.handsontable.com/?example=typescript) | +| [`react`](./examples/react) | React with TypeScript (Vite) | [Open](https://demos.handsontable.com/?example=react) | +| [`react-js`](./examples/react-js) | React with JavaScript (Vite) | [Open](https://demos.handsontable.com/?example=react-js) | +| [`vue`](./examples/vue) | Vue 3 (Vite) | [Open](https://demos.handsontable.com/?example=vue) | +| [`angular`](./examples/angular) | Angular | [Open](https://demos.handsontable.com/?example=angular) | +| [`next.js`](./examples/next.js) | Next.js, App Router | [Open](https://demos.handsontable.com/?example=next.js) | +| [`next-shadcn.js`](./examples/next-shadcn.js) | Next.js with shadcn/ui | [Open](https://demos.handsontable.com/?example=next-shadcn.js) | +| [`nuxt`](./examples/nuxt) | Nuxt 3 | [Open](https://demos.handsontable.com/?example=nuxt) | +| [`astro`](./examples/astro) | Astro | [Open](https://demos.handsontable.com/?example=astro) | +| [`remix`](./examples/remix) | Remix | [Open](https://demos.handsontable.com/?example=remix) | +| [`ant-design`](./examples/ant-design) | Handsontable themed to match Ant Design | [Open](https://demos.handsontable.com/?example=ant-design) | +| [`mui`](./examples/mui) | Handsontable themed to match MUI | [Open](https://demos.handsontable.com/?example=mui) | +| [`base-web`](./examples/base-web) | Handsontable themed to match Base Web | [Open](https://demos.handsontable.com/?example=base-web) | +| [`fluent-ui`](./examples/fluent-ui) | Handsontable themed to match Fluent UI | [Open](https://demos.handsontable.com/?example=fluent-ui) | ## Server examples -Each folder in [`server-examples/`](./server-examples) is a full stack — a backend -plus a Handsontable frontend — demonstrating server-side **pagination, sorting, +Each folder in [`server-examples/`](./server-examples) is a full stack: a backend +plus a Handsontable frontend, demonstrating server-side **pagination, sorting, filtering and CRUD** through the `dataProvider` plugin. Useful when your dataset is too large to send to the browser at once. @@ -66,7 +82,7 @@ pnpm dev # then open the URL it prints Every example has `dev` and `build`; most also have `preview` to serve the built output. Run `pnpm run` in an example folder to see its own scripts, and check its -README for anything specific — Angular, for instance, also answers to `pnpm start` +README for anything specific. Angular, for instance, also answers to `pnpm start` and serves on a different port. ## Copying an example to a separate repo @@ -78,7 +94,7 @@ The examples are deliberately standalone, so this is mostly a copy: cp -R examples/react ~/my-handsontable-app cd ~/my-handsontable-app ``` -2. Edit `package.json` — set `name`, `version` and `description` to your own, and +2. Edit `package.json`: set `name`, `version` and `description` to your own, and drop the `license` field or replace it with yours. 3. Initialise a repository and install: ```bash @@ -98,12 +114,12 @@ with it. **[demos.handsontable.com](https://demos.handsontable.com)** runs every example in this repository live, in the browser: -- **Any Handsontable version** — switch versions and watch the same code re-render. -- **Two runtimes behind one editor** — simple examples bundle in the browser with +- **Any Handsontable version**: switch versions and watch the same code re-render. +- **Two runtimes behind one editor**: simple examples bundle in the browser with the open-source [Sandpack](https://sandpack.codesandbox.io/) bundler; the meta-framework examples (Next.js, Nuxt, Astro, Remix, Angular) run a real dev server in a container, so SSR behaves the way it does locally. -- **Permanent share links** — save an edited demo and link to it. +- **Permanent share links**: save an edited demo and link to it. It also renders every code example from the Handsontable documentation guides. The system is self-hosted and lives in [`runner/`](./runner); its @@ -116,18 +132,23 @@ system is self-hosted and lives in [`runner/`](./runner); its | `examples/` | The 16 client examples above. Independent projects. | | `server-examples/` | The 7 server-side stacks above. Independent projects. | | `runner/` | The self-hosted demo runner behind demos.handsontable.com. | -| `runner/apps/authoring/public/docs-examples/` | **Generated** — a snapshot of every documentation-guide example, imported from the docs repository. Do not edit by hand; it is the bulk of this repository's size. | +| `runner/apps/authoring/public/docs-examples/` | **Generated**: a snapshot of every documentation-guide example, imported from the docs repository. Do not edit by hand; it is the bulk of this repository's size. | + +## Contributing + +Want to add a new example, or fix one? See [CONTRIBUTING.md](./CONTRIBUTING.md). +There's a registration step that's easy to miss and fails silently if skipped. ## License -The example code in this repository is MIT-licensed — see [LICENSE](./LICENSE). Copy +The example code in this repository is MIT-licensed, see [LICENSE](./LICENSE). Copy it, change it, ship it. Handsontable itself is separate, commercial software, dual-licensed: - **Free** for non-commercial use such as teaching, academic research and - evaluation — [read the license](https://github.com/handsontable/handsontable/blob/master/handsontable-non-commercial-license.pdf). -- **Commercial**, with support and maintenance — see [pricing](https://handsontable.com/pricing). + evaluation: [read the license](https://github.com/handsontable/handsontable/blob/master/handsontable-non-commercial-license.pdf). +- **Commercial**, with support and maintenance: see [pricing](https://handsontable.com/pricing). The examples install Handsontable under the non-commercial evaluation terms. Using one as the basis for a commercial product means buying a license.