@nativele/ts-dom 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/README.md +6 -1
- package/README.zh-TW.md +6 -1
- package/dist/{a11y-CiEJj_e6.mjs → a11y-KXbo-8o3.mjs} +119 -27
- package/dist/cli.mjs +273 -50
- package/dist/{lint-Did4w-NL.mjs → lint-DUsdDKZ-.mjs} +33 -8
- package/dist/oxlint-plugin.mjs +3 -3
- package/dist/vite-plugin.mjs +1 -1
- package/docs/architecture.md +188 -0
- package/docs/components.md +367 -0
- package/docs/contributing.md +80 -0
- package/docs/design.md +55 -0
- package/docs/lists.md +150 -0
- package/docs/performance.md +24 -0
- package/docs/recipes.md +189 -0
- package/docs/templates.md +73 -0
- package/docs/tooling.md +251 -0
- package/llms.txt +5 -5
- package/package.json +2 -1
- package/skills/README.md +51 -14
- package/skills/nativele-angular/SKILL.md +15 -11
- package/skills/nativele-architecture/SKILL.md +29 -16
- package/skills/nativele-ci/SKILL.md +148 -0
- package/skills/nativele-core/SKILL.md +16 -13
- package/skills/nativele-formatting/SKILL.md +167 -0
- package/skills/nativele-integration/SKILL.md +12 -9
- package/skills/nativele-linting/SKILL.md +174 -0
- package/skills/nativele-monorepo/SKILL.md +298 -0
- package/skills/nativele-react/SKILL.md +13 -10
- package/skills/nativele-state-management/SKILL.md +6 -6
- package/skills/nativele-svelte/SKILL.md +10 -8
- package/skills/nativele-tailwind/SKILL.md +8 -7
- package/skills/nativele-tanstack-query/SKILL.md +5 -5
- package/skills/nativele-testing/SKILL.md +22 -16
- package/skills/nativele-typescript/SKILL.md +186 -0
- package/skills/nativele-vite/SKILL.md +21 -17
- package/skills/nativele-vue/SKILL.md +10 -8
- package/skills/nativele-zod/SKILL.md +6 -6
|
@@ -3,8 +3,8 @@ name: nativele-react
|
|
|
3
3
|
description: "Use Nativele web components inside a React 19 app: passing props, receiving events, children and slots, lifecycle, and TSX types. Use when a project depends on react and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: official
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "react@19.3.1 react-dom@19.3.1 @types/react@19.3.0 @types/react-dom@19.3.0 vite@8.3.5 @vitejs/plugin-react@6.2.1 typescript@7.0.2"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "react"
|
|
@@ -24,20 +24,20 @@ Nativele components are native custom elements. React renders them like any othe
|
|
|
24
24
|
|
|
25
25
|
| Tool | Verified version |
|
|
26
26
|
|---|---|
|
|
27
|
-
| @nativele/ts-dom | 0.
|
|
27
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
28
28
|
| react, react-dom | 19.3.1 |
|
|
29
29
|
| @types/react, @types/react-dom | 19.3.0 |
|
|
30
30
|
| vite | 8.3.5 |
|
|
31
31
|
| @vitejs/plugin-react | 6.2.1 |
|
|
32
32
|
| typescript | 7.0.2 |
|
|
33
33
|
|
|
34
|
-
Verified on 2026-11-
|
|
34
|
+
Verified on 2026-11-06 in Google Chrome 148 with the example project in the Nativele repository (`skills/nativele-react/example`), and by an agent trial: a fresh agent did real work with only the Skill, and the result was checked independently. The example is a reference; it is not run in CI. With a different major version of React, treat every step as unverified.
|
|
35
35
|
|
|
36
36
|
## Set-up
|
|
37
37
|
|
|
38
38
|
1. Keep the Nativele components in their own folder, for example `src/nv/`, each as `x.html` plus `x.ts`. Write them with the core Skill: `npx ts-dom skills add nativele-core`.
|
|
39
39
|
2. Install: `npm i @nativele/ts-dom`.
|
|
40
|
-
3.
|
|
40
|
+
3. The tsconfig whose `include` covers that folder (`tsconfig.app.json` in Vite's React template, which does not set `strict`) must meet Nativele's requirements: check and adjust it with the TypeScript Skill (`npx ts-dom skills nativele-typescript`).
|
|
41
41
|
4. Add the Nativele Vite plugin next to the React plugin, pointing at that folder:
|
|
42
42
|
|
|
43
43
|
```ts
|
|
@@ -51,7 +51,7 @@ Verified on 2026-11-05 in Google Chrome 148 with the example project in the Nati
|
|
|
51
51
|
|
|
52
52
|
Pass the same folder to every `ts-dom` command (`npx ts-dom check src/nv`), so there is one `ts-dom-tags.ts`, in `src/nv`.
|
|
53
53
|
|
|
54
|
-
5. If the project lints
|
|
54
|
+
5. If the project lints (Vite's React template has oxlint), the ts-dom rules go into its linter: follow the linting Skill (`npx ts-dom skills nativele-linting`).
|
|
55
55
|
|
|
56
56
|
6. Import every Nativele component module in the entry file, before React renders anything:
|
|
57
57
|
|
|
@@ -89,7 +89,7 @@ Verified on 2026-11-05 in Google Chrome 148 with the example project in the Nati
|
|
|
89
89
|
|
|
90
90
|
The component class must be exported and passed to `define()` in a folder that `ts-dom gen` scans, so it appears in `ts-dom-tags.ts`.
|
|
91
91
|
|
|
92
|
-
The generated files are not committed, so on a clean checkout the type check in `npm run build` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'
|
|
92
|
+
The generated files are not committed, so on a clean checkout the type check in `npm run build` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'` (why: `nativele-typescript`). Generate them first: `"build": "ts-dom gen src/nv && tsc -b && vite build"` (the template's script with `ts-dom gen src/nv &&` in front). CI starts from such a checkout; the rest of what its job needs is in `npx ts-dom skills nativele-ci`.
|
|
93
93
|
|
|
94
94
|
## Example
|
|
95
95
|
|
|
@@ -187,15 +187,15 @@ npx tsc --noEmit -p tsconfig.app.json # expect: no errors (keep one @ts-expect
|
|
|
187
187
|
npm run build # expect: ✓ built (it runs ts-dom gen, tsc -b and vite build)
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
Pass `tsc` the tsconfig from step 3
|
|
190
|
+
Pass `tsc` the tsconfig from step 3: the template's root `tsconfig.json` only lists `references`, so `tsc --noEmit` without `-p` checks nothing (`nativele-typescript`).
|
|
191
191
|
|
|
192
|
-
In the browser, render a component with an object prop and an event handler, and check that the element has no `item` attribute (`el.getAttributeNames()`), that `el.item` is the object, and that the handler fires once per click.
|
|
192
|
+
In the browser, render a component with an object prop and an event handler, and check that the element has no `item` attribute (`el.getAttributeNames()`), that `el.item` is the object, and that the handler fires once per click. A reference implementation of these checks is the [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-react/example/verify.mjs) of the trial's example project, which does them with Playwright, plus children that React reorders, adds and removes inside a `shadow: true` component and inside stable wrappers in a Light DOM component. A Light DOM component has no `<slot>` elements once rendered; check where the children ended up with `el.assignedNodes(name)`, where `""` is the default slot.
|
|
193
193
|
|
|
194
194
|
## Troubleshooting
|
|
195
195
|
|
|
196
196
|
| Symptom | Cause | Fix |
|
|
197
197
|
|---|---|---|
|
|
198
|
-
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | `tsc -b` runs before the generated files exist | start the script with `ts-dom gen src/nv
|
|
198
|
+
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | `tsc -b` runs before the generated files exist | start the script with `ts-dom gen src/nv &&`; for CI, `nativele-ci` |
|
|
199
199
|
| An object prop shows `[object Object]` or is missing | the component was rendered before `define()` ran | import the component module in the entry file before rendering |
|
|
200
200
|
| The event handler never runs | the prop name is camelCased (`onItemSelect`) | use `on` plus the exact event name (`onitem-select`) |
|
|
201
201
|
| `insertBefore`/`removeChild` errors, the React root disappears | React children changed inside a Light DOM component with slots | use `shadow: true`, or stable wrapper elements per slot |
|
|
@@ -207,3 +207,6 @@ In the browser, render a component with an object prop and an event handler, and
|
|
|
207
207
|
- Components, props and events: https://github.com/Pixmi/nativele/blob/main/docs/components.md
|
|
208
208
|
- Slots, Light DOM and Shadow DOM: https://github.com/Pixmi/nativele/blob/main/docs/components.md#light-default-and-shadow
|
|
209
209
|
- Setup and checks: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md
|
|
210
|
+
- The tsconfig: https://github.com/Pixmi/nativele/blob/main/skills/nativele-typescript/SKILL.md
|
|
211
|
+
- The ts-dom rules in the project's linter: https://github.com/Pixmi/nativele/blob/main/skills/nativele-linting/SKILL.md
|
|
212
|
+
- CI: https://github.com/Pixmi/nativele/blob/main/skills/nativele-ci/SKILL.md
|
|
@@ -3,8 +3,8 @@ name: nativele-state-management
|
|
|
3
3
|
description: "Decide where state lives in an app built with Nativele (component state, a shared createStore, or an existing Zustand, Redux Toolkit or nanostores store) and connect external stores to this.bind with a small adapter: selectors that limit re-rendering, actions and dispatch from event handlers, unsubscribing when a component is removed. Use when a project depends on @nativele/ts-dom and on zustand, @reduxjs/toolkit, redux or nanostores, or when components need to share data."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: official
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "zustand@5.0.16 @reduxjs/toolkit@2.14.0 redux@5.0.1 nanostores@1.5.5 vite@8.3.6 typescript@7.0.2 create-vite@9.3.4"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "zustand @reduxjs/toolkit redux nanostores"
|
|
@@ -24,16 +24,16 @@ metadata:
|
|
|
24
24
|
|
|
25
25
|
| Tool | Verified version |
|
|
26
26
|
|---|---|
|
|
27
|
-
| @nativele/ts-dom | 0.
|
|
27
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
28
28
|
| zustand (`zustand/vanilla`) | 5.0.16 |
|
|
29
29
|
| @reduxjs/toolkit | 2.14.0 |
|
|
30
|
-
| redux | 5.0.1 (installed by `@reduxjs/toolkit`; a `legacy_createStore` store with the adapter was checked by hand with `tsc` and Node
|
|
30
|
+
| redux | 5.0.1 (installed by `@reduxjs/toolkit`; a `legacy_createStore` store with the adapter was checked by hand with `tsc` and Node) |
|
|
31
31
|
| nanostores | 1.5.5 (`atom` only) |
|
|
32
32
|
| vite | 8.3.6 |
|
|
33
33
|
| typescript | 7.0.2 |
|
|
34
34
|
| create-vite (`vanilla-ts` template, the starting point) | 9.3.4 |
|
|
35
35
|
|
|
36
|
-
Verified on 2026-11-
|
|
36
|
+
Verified on 2026-11-06 in Google Chrome 148 with the example project in the Nativele repository (`skills/nativele-state-management/example`). With a different major version of a state library, treat the adapter and every limitation about that library as unverified.
|
|
37
37
|
|
|
38
38
|
## Set-up
|
|
39
39
|
|
|
@@ -294,7 +294,7 @@ for (const name of ["set", "render"]) {
|
|
|
294
294
|
}
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
-
Then typing a note must log nothing for `cart-badge`, and adding an item must log `set` and `render` once each.
|
|
297
|
+
Then typing a note must log nothing for `cart-badge`, and adding an item must log `set` and `render` once each. A reference implementation of these checks is the [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-state-management/example/verify.mjs) of the trial's example project, which does them with Playwright for Zustand, Redux, nanostores and `createStore`, plus the `bind` contract itself (an immediate call, no call for an `Object.is`-equal set, nothing after removal), the nanostores double call, selectors that return a new object or a kept slice, and no console errors.
|
|
298
298
|
|
|
299
299
|
## Troubleshooting
|
|
300
300
|
|
|
@@ -3,8 +3,8 @@ name: nativele-svelte
|
|
|
3
3
|
description: "Use Nativele web components inside an existing Svelte 5 app: passing props, listening to events, children and slots, lifecycle, template types with svelte-check, and ts-dom check. Use when a project depends on svelte and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: experimental
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "svelte@5.57.3 vite@8.3.6 @sveltejs/vite-plugin-svelte@7.3.1 svelte-check@4.7.8 @tsconfig/svelte@5.0.8 typescript@6.0.3"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "svelte"
|
|
@@ -25,7 +25,7 @@ Nativele components are native custom elements. Svelte renders them like any oth
|
|
|
25
25
|
|
|
26
26
|
| Tool | Verified version |
|
|
27
27
|
|---|---|
|
|
28
|
-
| @nativele/ts-dom | 0.
|
|
28
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
29
29
|
| svelte | 5.57.3 |
|
|
30
30
|
| @sveltejs/vite-plugin-svelte | 7.3.1 |
|
|
31
31
|
| svelte-check | 4.7.8 |
|
|
@@ -33,13 +33,13 @@ Nativele components are native custom elements. Svelte renders them like any oth
|
|
|
33
33
|
| vite | 8.3.6 |
|
|
34
34
|
| typescript | 6.0.3 |
|
|
35
35
|
|
|
36
|
-
Verified on 2026-11-
|
|
36
|
+
Verified on 2026-11-06 in Google Chrome 148, against the Vite dev server (so Svelte's development warnings would show), in a fresh app made with `npm create vite@latest -- --template svelte-ts`. Runes mode (`$state`) is what was verified; legacy mode was checked only for the `on:` directive (limitation 2). With a different major version of Svelte, treat every step as unverified.
|
|
37
37
|
|
|
38
38
|
## Set-up
|
|
39
39
|
|
|
40
40
|
1. Keep the Nativele components in their own folder, for example `src/nv/`, each as `x.html` plus `x.ts`. Write them with the core Skill: `npx ts-dom skills add nativele-core`.
|
|
41
41
|
2. Install: `npm i @nativele/ts-dom`.
|
|
42
|
-
3.
|
|
42
|
+
3. The tsconfig that covers that folder must meet Nativele's requirements: in Vite's Svelte template, `tsconfig.app.json` extends `@tsconfig/svelte`, which sets `"strict": true`, and its `include` already covers `src/nv`, so nothing changes. In any other case, check and adjust it with the TypeScript Skill (`npx ts-dom skills nativele-typescript`).
|
|
43
43
|
4. Add the Nativele Vite plugin before the Svelte plugin, pointing at that folder:
|
|
44
44
|
|
|
45
45
|
```ts
|
|
@@ -109,7 +109,7 @@ Verified on 2026-11-05 in Google Chrome 148, against the Vite dev server (so Sve
|
|
|
109
109
|
export const badEvent: SvelteHTMLElements["info-card"] = { "onitem-select": (e) => e.detail.name };
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
The generated files are not committed, so on a clean checkout the type check in `npm run check` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'
|
|
112
|
+
The generated files are not committed, so on a clean checkout the type check in `npm run check` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'` (why: `nativele-typescript`). Generate them first: `"check": "ts-dom gen src/nv && svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"` (the template's script with `ts-dom gen src/nv &&` in front). `npm run build` needs no change: the Vite plugin generates the files. CI starts from such a checkout; the rest of what its job needs is in `npx ts-dom skills nativele-ci`.
|
|
113
113
|
|
|
114
114
|
## Example
|
|
115
115
|
|
|
@@ -222,7 +222,7 @@ npm run check # svelte-check plus tsc for vite.config.ts; expect:
|
|
|
222
222
|
npm run build # expect: built
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
When `npm run check` is not run in a terminal (an agent, CI), `svelte-check` prints `COMPLETED ... 0 ERRORS 0 WARNINGS ...` instead. Delete `src/nativele-svelte.d.ts` once to see the check work: `svelte-check` must then report `Unused '@ts-expect-error' directive` in `src/types-check.ts`.
|
|
225
|
+
When `npm run check` is not run in a terminal (an agent, CI; the CI steps are in `nativele-ci`), `svelte-check` prints `COMPLETED ... 0 ERRORS 0 WARNINGS ...` instead. Delete `src/nativele-svelte.d.ts` once to see the check work: `svelte-check` must then report `Unused '@ts-expect-error' directive` in `src/types-check.ts`.
|
|
226
226
|
|
|
227
227
|
In the browser, against the dev server (production builds drop Svelte's warnings), render a component with an object prop and an event attribute, and check:
|
|
228
228
|
|
|
@@ -234,7 +234,7 @@ In the browser, against the dev server (production builds drop Svelte's warnings
|
|
|
234
234
|
|
|
235
235
|
| Symptom | Cause | Fix |
|
|
236
236
|
|---|---|---|
|
|
237
|
-
| `svelte-check` reports `Cannot find module './x.html.js'` on a clean checkout | it runs before the generated files exist | start the `check` script with `ts-dom gen src/nv
|
|
237
|
+
| `svelte-check` reports `Cannot find module './x.html.js'` on a clean checkout | it runs before the generated files exist | start the `check` script with `ts-dom gen src/nv &&`; for CI, `nativele-ci` |
|
|
238
238
|
| The event handler never runs | the attribute is camelCased (`onItemSelect`), or it is on an ancestor | use `on` plus the exact event name (`onitem-select`) on the element that emits |
|
|
239
239
|
| `svelte-check`: `'"on:item-select"' does not exist in type 'NativeleElementProps<...>'` | the legacy `on:` directive, which the declaration does not type | use the event attribute `onitem-select` |
|
|
240
240
|
| `Mixing old (on:item-select) and new syntaxes for event handling is not allowed` | `on:` and event attributes in the same component | use only event attributes |
|
|
@@ -252,4 +252,6 @@ In the browser, against the dev server (production builds drop Svelte's warnings
|
|
|
252
252
|
- Slots, Light DOM and Shadow DOM: https://github.com/Pixmi/nativele/blob/main/docs/components.md#light-default-and-shadow
|
|
253
253
|
- Stores and `bind`: https://github.com/Pixmi/nativele/blob/main/docs/components.md#state-store-when-not-using-state
|
|
254
254
|
- Setup and checks: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md
|
|
255
|
+
- The tsconfig and `svelte-check`'s TypeScript version: https://github.com/Pixmi/nativele/blob/main/skills/nativele-typescript/SKILL.md
|
|
256
|
+
- CI: https://github.com/Pixmi/nativele/blob/main/skills/nativele-ci/SKILL.md
|
|
255
257
|
- The framework-neutral rules: `npx ts-dom skills nativele-integration`
|
|
@@ -3,8 +3,8 @@ name: nativele-tailwind
|
|
|
3
3
|
description: "Style Nativele components with Tailwind CSS v4 in a Vite app that already uses Tailwind: classes in .html templates and in render, which files Tailwind scans, dynamic class names, <style scoped> next to utilities, and bringing the Tailwind stylesheet into shadow: true components. Use when a project depends on tailwindcss and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: experimental
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "tailwindcss@4.3.4 @tailwindcss/vite@4.3.4 vite@8.3.6 typescript@7.0.2 create-vite@9.3.4"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "tailwindcss"
|
|
@@ -23,14 +23,14 @@ metadata:
|
|
|
23
23
|
|
|
24
24
|
| Tool | Verified version |
|
|
25
25
|
|---|---|
|
|
26
|
-
| @nativele/ts-dom | 0.
|
|
26
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
27
27
|
| tailwindcss | 4.3.4 |
|
|
28
28
|
| @tailwindcss/vite | 4.3.4 |
|
|
29
29
|
| vite | 8.3.6 |
|
|
30
30
|
| typescript | 7.0.2 |
|
|
31
31
|
| create-vite (`vanilla-ts` template, the starting point) | 9.3.4 |
|
|
32
32
|
|
|
33
|
-
Verified on 2026-11-
|
|
33
|
+
Verified on 2026-11-06 in Google Chrome 148, by reading computed styles with Playwright both against `vite` (dev) and against `vite build` served by `vite preview`, in an app made with `npm create vite@latest -- --template vanilla-ts`, given Tailwind by Tailwind's Vite guide, then Nativele by `nativele-vite`, in a git repository. With a different major version of Tailwind, treat every step as unverified.
|
|
34
34
|
|
|
35
35
|
## Set-up
|
|
36
36
|
|
|
@@ -48,7 +48,7 @@ The starting point: `src/style.css` is `@import "tailwindcss";`, `src/main.ts` i
|
|
|
48
48
|
|
|
49
49
|
2. Keep `import "./style.css"` in the entry module. For Light DOM components (the default) nothing else is needed: Tailwind's automatic source detection reads the `.html` templates and the component `.ts` files, so a class written only in a template, only on a tag in `index.html`, or only as a full string in TypeScript (`classList.toggle("tracking-[0.3em]", on)` in `render`) is generated, in `vite dev` and in `vite build`. No `@source` is needed while the components are inside the project folder.
|
|
50
50
|
3. The generated `*.html.ts` files do not need to be scanned. Tailwind skips every file matched by `.gitignore` (also outside a git repository), and with the generated files not ignored the built CSS was byte for byte the same. The Skills that `ts-dom skills add` copies into `.agents/` (or `.claude/`) are scanned, though, and their example classes end up in the build; exclude that folder under the import, relative to the CSS file: `@source not "../.agents";`.
|
|
51
|
-
4. Only when templates live outside the project folder (for example a sibling package of a
|
|
51
|
+
4. Only when templates live outside the project folder (for example a sibling package of a workspace), add a `@source` line, with the path relative to the CSS file:
|
|
52
52
|
|
|
53
53
|
```css
|
|
54
54
|
/* src/style.css */
|
|
@@ -56,7 +56,7 @@ The starting point: `src/style.css` is `@import "tailwindcss";`, `src/main.ts` i
|
|
|
56
56
|
@source "../../shared-nv";
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Nativele
|
|
59
|
+
For Nativele, a package of the workspace generates and checks its own components and the app imports it, as `npx ts-dom skills nativele-monorepo` sets up. A plain folder outside the project that the app scans itself goes into `tsDom({ dirs })`, the arguments of `ts-dom check` and `ts-dom doctor`, and the tsconfig (`nativele-typescript`); keep each component's `.ts` next to its template there (a template whose importer is in another folder is reported as `no-importer`), and the folder must resolve `@nativele/ts-dom` itself, or `tsc` reports `TS2307` for its generated `.html.ts`.
|
|
60
60
|
|
|
61
61
|
5. Only for `shadow: true` components: add one module that turns the same CSS into a constructable stylesheet, and adopt it in each Shadow component's constructor (limitation 3 explains why and what it costs):
|
|
62
62
|
|
|
@@ -207,7 +207,7 @@ getComputedStyle(document.querySelector("badge-box").shadowRoot.firstElementChil
|
|
|
207
207
|
| A Shadow component flashes unstyled on load | the stylesheet comes from a `<link>` | `adoptedStyleSheets` (step 5) |
|
|
208
208
|
| A utility on an element does not override the template's `<style scoped>` rule | unlayered template styles beat `@layer utilities` | wrap the template rule in `@layer components { }`, or use the `!` modifier |
|
|
209
209
|
| `@apply` in a template `<style>` has no effect | template styles are not processed by Tailwind | use theme variables (`var(--color-...)`) or utility classes in the markup |
|
|
210
|
-
| Templates in another folder of a
|
|
210
|
+
| Templates in another folder of a workspace are not styled | they are outside the project folder Tailwind scans | `@source "<path relative to the CSS file>"`; how the app gets the package's components is in `nativele-monorepo` |
|
|
211
211
|
| The built CSS has classes no component uses, from the Skill files | Tailwind scans `.agents/` (or `.claude/`), where `ts-dom skills add` puts the Skills, unless `.gitignore` matches it | add `@source not "../.agents";` (relative to the CSS file) under `@import "tailwindcss";` |
|
|
212
212
|
| A check that a class is absent from the build fails, although no component uses it | Tailwind scans every file in the project that `.gitignore` does not match, including test scripts that name the class | keep such scripts outside the project, or build the class name from pieces in them |
|
|
213
213
|
|
|
@@ -218,3 +218,4 @@ getComputedStyle(document.querySelector("badge-box").shadowRoot.firstElementChil
|
|
|
218
218
|
- Common DOM operations in `render` (classes): https://github.com/Pixmi/nativele/blob/main/docs/components.md#common-dom-operations-in-render
|
|
219
219
|
- The Vite plugin: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md#with-vite-optional
|
|
220
220
|
- Adding Nativele to Vite: `npx ts-dom skills nativele-vite`
|
|
221
|
+
- Components from another package of a workspace: https://github.com/Pixmi/nativele/blob/main/skills/nativele-monorepo/SKILL.md
|
|
@@ -3,8 +3,8 @@ name: nativele-tanstack-query
|
|
|
3
3
|
description: "Fetch server data with TanStack Query (@tanstack/query-core) and show it in Nativele components: an adapter from QueryObserver and MutationObserver to bind, loading, error and refetching states with data-if, lists with data-each, query keys from props, unsubscribing on removal, and mutations with invalidation. Use when a project depends on @tanstack/query-core and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: experimental
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "@tanstack/query-core@5.106.1 vite@8.3.6 typescript@7.0.2 create-vite@9.3.4"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "@tanstack/query-core"
|
|
@@ -25,17 +25,17 @@ metadata:
|
|
|
25
25
|
|
|
26
26
|
| Tool | Verified version |
|
|
27
27
|
|---|---|
|
|
28
|
-
| @nativele/ts-dom | 0.
|
|
28
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
29
29
|
| @tanstack/query-core | 5.106.1 |
|
|
30
30
|
| vite | 8.3.6 |
|
|
31
31
|
| typescript | 7.0.2 |
|
|
32
32
|
| create-vite (`vanilla-ts` template, the starting point) | 9.3.4 |
|
|
33
33
|
|
|
34
|
-
Verified on 2026-11-
|
|
34
|
+
Verified on 2026-11-06 in Google Chrome 148 against the Vite dev server, in an app made with `npm create vite@latest -- --template vanilla-ts` and set up with the `nativele-vite` Skill, with a local mock API and Playwright 1.64 holding, failing and counting requests. With a different major version of TanStack Query, treat every step as unverified.
|
|
35
35
|
|
|
36
36
|
## Set-up
|
|
37
37
|
|
|
38
|
-
Starting from a Vite app with Nativele already set up (`npx ts-dom skills nativele-vite`:
|
|
38
|
+
Starting from a Vite app with Nativele already set up (`npx ts-dom skills nativele-vite`: the `tsDom({ dirs: ["src/nv"] })` plugin, `"build": "ts-dom check src/nv && vite build"`, and a tsconfig that meets `nativele-typescript`):
|
|
39
39
|
|
|
40
40
|
1. `npm i @tanstack/query-core`.
|
|
41
41
|
2. Create one `QueryClient` for the whole app in its own module, call `mount()` once, and add the adapter next to it:
|
|
@@ -3,8 +3,8 @@ name: nativele-testing
|
|
|
3
3
|
description: "Test Nativele components in an app: component tests with Vitest and happy-dom (or jsdom), real-browser tests with Vitest browser mode in headless Chrome, and page tests with Playwright. Covers generating the templates before tests, creating elements, props, events, lists, data-if, stores, slots, test isolation, and what a DOM shim cannot show. Use when a project depends on @nativele/ts-dom and on vitest, @playwright/test or playwright."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: official
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "vitest@5.1.0 happy-dom@21.0.4 jsdom@30.1.3 @vitest/browser-playwright@5.1.0 playwright@1.64.1 @playwright/test@1.64.1 vite@8.3.6 typescript@7.0.2"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "vitest @playwright/test playwright"
|
|
@@ -25,7 +25,7 @@ The recommended path is Vitest: component tests in happy-dom, and the few behavi
|
|
|
25
25
|
|
|
26
26
|
| Tool | Verified version |
|
|
27
27
|
|---|---|
|
|
28
|
-
| @nativele/ts-dom | 0.
|
|
28
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
29
29
|
| vitest | 5.1.0 |
|
|
30
30
|
| happy-dom | 21.0.4 |
|
|
31
31
|
| jsdom | 30.1.3 (the same component tests pass; not the recommended environment) |
|
|
@@ -35,7 +35,7 @@ The recommended path is Vitest: component tests in happy-dom, and the few behavi
|
|
|
35
35
|
| vite | 8.3.6 |
|
|
36
36
|
| typescript | 7.0.2 |
|
|
37
37
|
|
|
38
|
-
Verified on 2026-11-
|
|
38
|
+
Verified on 2026-11-06 with Node 24 and Google Chrome 148, starting from `create-vite` 9.3.4 with the `vanilla-ts` template, with the example project in the Nativele repository (`skills/nativele-testing/example`). Vitest 5 changed its configuration (`test.api`, `test.projects`, providers as separate packages); with Vitest 4 or older, or another major version of any tool above, treat every step as unverified.
|
|
39
39
|
|
|
40
40
|
## Set-up
|
|
41
41
|
|
|
@@ -62,16 +62,16 @@ Verified on 2026-11-05 with Node 24 and Google Chrome 148, starting from `create
|
|
|
62
62
|
});
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
3. Keep the tests in `test
|
|
65
|
+
3. Keep the tests in `test/`, and make the tsconfig cover that folder too (`"include": ["src", "test"]` in the trial; the TypeScript Skill, `npx ts-dom skills nativele-typescript`, checks and adjusts it). Vitest does not type-check; `ts-dom check src/nv` runs the project's `tsc`, which then checks the tests too, and `ts-dom-tags.ts` types `document.createElement("counter-card")` as the component class, with its props.
|
|
66
66
|
4. Add the scripts:
|
|
67
67
|
|
|
68
68
|
```sh
|
|
69
69
|
npm pkg set scripts.test="vitest run --project unit"
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
`ts-dom check src/nv` is what reports type errors in the tests and the templates. In a project whose type check is plain `tsc`, the build script `ts-dom check src/nv && vite build` (as `nativele-vite` sets it up) runs it; in a framework project, whose build puts `ts-dom gen src/nv &&` in front of its own type check (`tsc -b`, `vue-tsc -b`, `svelte-check`), run `ts-dom check src/nv` before or after the tests.
|
|
72
|
+
`ts-dom check src/nv` is what reports type errors in the tests and the templates. In a project whose type check is plain `tsc`, the build script `ts-dom check src/nv && vite build` (as `nativele-vite` sets it up) runs it; in a framework project, whose build puts `ts-dom gen src/nv &&` in front of its own type check (`tsc -b`, `vue-tsc -b`, `svelte-check`), run `ts-dom check src/nv` before or after the tests. Where these steps go in CI is covered by `npx ts-dom skills nativele-ci`.
|
|
73
73
|
|
|
74
|
-
5. For the real-browser tests, install the Vitest provider and Playwright, and add a second project. It drives
|
|
74
|
+
5. For the real-browser tests, install the Vitest provider and Playwright, and add a second project. It drives a Chromium-based browser already installed on the machine (`CHROME_BIN`, or `/usr/bin/google-chrome`), so nothing is downloaded and `npx playwright install` is not needed; a CI runner needs such a browser too (`nativele-ci`):
|
|
75
75
|
|
|
76
76
|
```sh
|
|
77
77
|
npm i -D @vitest/browser-playwright@5.1.0 playwright@1.64.1
|
|
@@ -100,7 +100,7 @@ Verified on 2026-11-05 with Node 24 and Google Chrome 148, starting from `create
|
|
|
100
100
|
},
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
`headless: true` keeps the run the same locally and in CI. The launch arguments suit containers, WSL and CI runners
|
|
103
|
+
`headless: true` keeps the run the same locally and in CI. The launch arguments suit containers, WSL and CI runners; the CI job itself is covered by `nativele-ci`. Name only the tests that need a real browser `*.browser.test.ts` (limitation 1); everything else stays in happy-dom, which starts in a fraction of the time.
|
|
104
104
|
|
|
105
105
|
6. Alternative, for tests of whole pages (the built app, every component on it, navigation): Playwright Test against `vite preview`, with the same Chrome:
|
|
106
106
|
|
|
@@ -125,11 +125,11 @@ Verified on 2026-11-05 with Node 24 and Google Chrome 148, starting from `create
|
|
|
125
125
|
});
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
The tsconfig must cover `e2e` too, so `ts-dom check` type-checks the specs (`nativele-typescript`). Add `test-results` and `playwright-report` to `.gitignore`.
|
|
129
129
|
|
|
130
130
|
## Example
|
|
131
131
|
|
|
132
|
-
The component under test (
|
|
132
|
+
The component under test (`src/nv/counter-card.*`):
|
|
133
133
|
|
|
134
134
|
```html
|
|
135
135
|
<!-- src/nv/counter-card.html -->
|
|
@@ -224,7 +224,9 @@ The steps every test follows:
|
|
|
224
224
|
4. Assert at once. Rendering is synchronous: after `append`, a prop assignment, `setAttribute`, `el.click()` or `store.set()`, the DOM is already updated, and `emit` listeners have already run. For a form, set the input's `value`, then call `click()` on its submit button or `form.requestSubmit()`: both run the template's `data-on-submit` handler, in happy-dom too. The only waits are for slot changes made after connection (one microtask, below).
|
|
225
225
|
5. Empty the document in `afterEach` (`document.body.replaceChildren()`): removing the elements runs `disconnected()` and ends their `bind`, `on` and `onCleanup` registrations.
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
These tests compare `textContent` exactly. When the project formats its templates, the formatter's line breaks and indentation can become part of `textContent`, depending on the whitespace mode: the formatting Skill (`npx ts-dom skills nativele-formatting`) decides the mode and says how to assert on such text.
|
|
228
|
+
|
|
229
|
+
Other parts of the API:
|
|
228
230
|
|
|
229
231
|
```ts
|
|
230
232
|
// lists (test/todo-list.test.ts): items as components; an item's event reaches the parent with hit.key
|
|
@@ -286,7 +288,7 @@ test("Chrome moves a list item with moveBefore: it stays connected and keeps foc
|
|
|
286
288
|
});
|
|
287
289
|
```
|
|
288
290
|
|
|
289
|
-
Under happy-dom this test fails: there is no `moveBefore`, both callbacks run and the input loses focus.
|
|
291
|
+
Under happy-dom this test fails: there is no `moveBefore`, both callbacks run and the input loses focus. A unit test can assert the happy-dom behavior, so that a later happy-dom release that adds `moveBefore` shows up as a failing test. The Vitest API in browser mode is the same: happy-dom tests also pass unchanged when run in the browser project, so moving a test there is a matter of renaming it.
|
|
290
292
|
|
|
291
293
|
A page test with Playwright (the alternative):
|
|
292
294
|
|
|
@@ -318,7 +320,7 @@ Playwright locators reach into open shadow roots, so `page.locator("shadow-panel
|
|
|
318
320
|
2. **Import the module, not only the type.** `import type { CounterCard }` (or `import { type CounterCard }`) is erased, so `define()` never runs: `document.createElement("counter-card")` returns a plain element that never renders, and `tsc` still types it as `CounterCard` through `ts-dom-tags.ts`. The symptom is `expected undefined to be ...` or `Cannot read properties of null (reading 'click')`. Add `import "../src/nv/counter-card.ts"`. Child components used in a template are imported by its generated module, so importing the parent is enough.
|
|
319
321
|
3. **One registry per test file.** Vitest runs each test file in a new environment by default (`isolate: true`), in happy-dom and in browser mode: each file starts with an empty document and an empty `customElements`. Inside a file, the document and the registry are shared by all its tests, so empty the document in `afterEach`. With `isolate: false` and the files run one after another in the same worker (`--no-isolate --no-file-parallelism`), they share both: the document keeps the previous file's elements, and a direct `customElements.define()` of a name already defined throws.
|
|
320
322
|
4. **A tag cannot be redefined.** `define()` with a name that is already defined does nothing and keeps the first class; `customElements.define()` throws an error whose message says the name is already used or registered (in happy-dom, jsdom and Chrome). `vi.resetModules()` followed by a new `import()` creates a new class and new module-level stores, but the tag keeps running the first class, bound to the first store. Reset shared stores with `store.set(...)` in `beforeEach` instead, and give a component defined only for one test file a name no other module uses.
|
|
321
|
-
5. **Do not add a `data-ref` only for a test.** `ts-dom check` reports a ref that the component class never reads as `unused-ref`, and access from a test does not count. Query the rendered DOM in the test (`el.querySelector("button")`, `el.shadowRoot.querySelector(...)`, `el.assignedNodes(name)`). The
|
|
323
|
+
5. **Do not add a `data-ref` only for a test.** `ts-dom check` reports a ref that the component class never reads as `unused-ref`, and access from a test does not count. Query the rendered DOM in the test (`el.querySelector("button")`, `el.shadowRoot.querySelector(...)`, `el.assignedNodes(name)`). The linter's `ts-dom/unused-markup` rule does the same; turning it off for test folders silences only templates that test files import themselves (`npx ts-dom skills nativele-linting`).
|
|
322
324
|
6. **Text of a slotted heading in a Shadow DOM component.** `textContent` (and Playwright's `toHaveText` on the element inside the shadow root) reads the slot's fallback content, not the slotted nodes: in the example, `shadow-panel h2` has the text `Untitled` while it shows `Shadow`. Read the slot with `el.assignedNodes(name)`, or in Playwright use `getByRole("heading", { name: "Shadow" })`, which follows what is shown. A Light DOM component has the slotted nodes in place, so its text is what is shown.
|
|
323
325
|
7. **Slot changes after connection are asynchronous.** Children added to a Light DOM component after it is connected are placed by a `MutationObserver`, and `slotchange(name)` runs then; for a Shadow DOM component, the native `slotchange` event fires at the same point. `await Promise.resolve()` once before asserting is enough in happy-dom, jsdom and Chrome. Children present when the element is appended are placed synchronously.
|
|
324
326
|
8. **Typing custom events.** `addEventListener` types an unknown event name as `Event`, so `e.detail` is a `tsc` error (`TS2339`); cast with `EmitEvent<CounterCard, "count-change">`.
|
|
@@ -336,7 +338,7 @@ npx vitest run --project browser # expect: the *.browser.test.ts files pass in
|
|
|
336
338
|
npx playwright test # if you use the alternative: builds, serves on port 4432, passes
|
|
337
339
|
```
|
|
338
340
|
|
|
339
|
-
The
|
|
341
|
+
The same unit tests also pass under jsdom, as a third Vitest project with `"environment": "jsdom"`.
|
|
340
342
|
|
|
341
343
|
## Troubleshooting
|
|
342
344
|
|
|
@@ -348,7 +350,7 @@ The example project's `verify` script runs exactly these, plus the same unit tes
|
|
|
348
350
|
| `TS2339: Property 'label' does not exist on type 'HTMLElement'` on `document.createElement("counter-card")` | `tsc` ran without `ts-dom-tags.ts` (nothing generated it), or the component class is not exported | run `ts-dom check src/nv` instead of plain `tsc`; export the class |
|
|
349
351
|
| `src/nv/x.html:1:1 error [unused-ref] data-ref="..." is never used by the component class` | a ref added for a test | query the DOM in the test and remove the ref (limitation 5) |
|
|
350
352
|
| A test passes alone and fails with others in the same file, or sees elements from another test | the document is shared within a file | `afterEach(() => document.body.replaceChildren())`; reset module-level stores in `beforeEach` |
|
|
351
|
-
| `Error: browserType.launch: Failed to launch chromium because executable doesn't exist at /usr/bin/google-chrome` | no Chrome at that path | set `CHROME_BIN` to
|
|
353
|
+
| `Error: browserType.launch: Failed to launch chromium because executable doesn't exist at /usr/bin/google-chrome` | no Chrome at that path | set `CHROME_BIN` to a Chrome or Chromium binary; on a CI runner, install one first (`nativele-ci`) |
|
|
352
354
|
| `Error: browserType.launch: Executable doesn't exist at ~/.cache/ms-playwright/...` and `Looks like Playwright was just installed or updated` | `executablePath` is missing from `launchOptions`, so Playwright looks for its own downloaded browser | set `executablePath` as in step 5 |
|
|
353
355
|
| DEPRECATED: `test.browser.api` was deprecated in Vitest 5. Use `test.api` instead. | the port is set where Vitest 4 had it | move `api` from `test.browser` to `test` of the browser project |
|
|
354
356
|
| A test that moves list items passes in happy-dom and fails in Chrome (or the reverse) | happy-dom has no `moveBefore` | assert moves in a `*.browser.test.ts` (limitation 1) |
|
|
@@ -360,5 +362,9 @@ The example project's `verify` script runs exactly these, plus the same unit tes
|
|
|
360
362
|
- Light DOM and Shadow DOM slots, `assignedNodes`, `slotchange`: https://github.com/Pixmi/nativele/blob/main/docs/components.md#light-default-and-shadow
|
|
361
363
|
- Stores and `bind`: https://github.com/Pixmi/nativele/blob/main/docs/components.md#state-store-when-not-using-state
|
|
362
364
|
- Lists, and what moving an item does with and without `moveBefore`: https://github.com/Pixmi/nativele/blob/main/docs/lists.md#moving-items-connecting-and-subscriptions
|
|
363
|
-
- The Vite plugin
|
|
365
|
+
- The Vite plugin and `ts-dom check`: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md
|
|
366
|
+
- The tsconfig: https://github.com/Pixmi/nativele/blob/main/skills/nativele-typescript/SKILL.md
|
|
367
|
+
- The ts-dom rules and test folders in the project's linter: https://github.com/Pixmi/nativele/blob/main/skills/nativele-linting/SKILL.md
|
|
368
|
+
- Whitespace in `textContent` with a formatter: https://github.com/Pixmi/nativele/blob/main/skills/nativele-formatting/SKILL.md
|
|
369
|
+
- CI and the browser on the runner: https://github.com/Pixmi/nativele/blob/main/skills/nativele-ci/SKILL.md
|
|
364
370
|
- Setting up the Vite app first: `npx ts-dom skills nativele-vite`
|