@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +6 -1
  3. package/README.zh-TW.md +6 -1
  4. package/dist/{a11y-CiEJj_e6.mjs → a11y-KXbo-8o3.mjs} +119 -27
  5. package/dist/cli.mjs +273 -50
  6. package/dist/{lint-Did4w-NL.mjs → lint-DUsdDKZ-.mjs} +33 -8
  7. package/dist/oxlint-plugin.mjs +3 -3
  8. package/dist/vite-plugin.mjs +1 -1
  9. package/docs/architecture.md +188 -0
  10. package/docs/components.md +367 -0
  11. package/docs/contributing.md +80 -0
  12. package/docs/design.md +55 -0
  13. package/docs/lists.md +150 -0
  14. package/docs/performance.md +24 -0
  15. package/docs/recipes.md +189 -0
  16. package/docs/templates.md +73 -0
  17. package/docs/tooling.md +251 -0
  18. package/llms.txt +5 -5
  19. package/package.json +2 -1
  20. package/skills/README.md +51 -14
  21. package/skills/nativele-angular/SKILL.md +15 -11
  22. package/skills/nativele-architecture/SKILL.md +29 -16
  23. package/skills/nativele-ci/SKILL.md +148 -0
  24. package/skills/nativele-core/SKILL.md +16 -13
  25. package/skills/nativele-formatting/SKILL.md +167 -0
  26. package/skills/nativele-integration/SKILL.md +12 -9
  27. package/skills/nativele-linting/SKILL.md +174 -0
  28. package/skills/nativele-monorepo/SKILL.md +298 -0
  29. package/skills/nativele-react/SKILL.md +13 -10
  30. package/skills/nativele-state-management/SKILL.md +6 -6
  31. package/skills/nativele-svelte/SKILL.md +10 -8
  32. package/skills/nativele-tailwind/SKILL.md +8 -7
  33. package/skills/nativele-tanstack-query/SKILL.md +5 -5
  34. package/skills/nativele-testing/SKILL.md +22 -16
  35. package/skills/nativele-typescript/SKILL.md +186 -0
  36. package/skills/nativele-vite/SKILL.md +21 -17
  37. package/skills/nativele-vue/SKILL.md +10 -8
  38. 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.5.1 <0.6.0"
7
- verified: "2026-11-05"
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.5.1 |
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-05 in Google Chrome 148 with the example project in the Nativele repository (`skills/nativele-react/example`), which CI runs again when the example or the library changes and once a month. With a different major version of React, treat every step as unverified.
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. Set `"strict": true` in the tsconfig whose `include` covers that folder (`tsconfig.app.json` in Vite's React template, which leaves it off); Nativele's type checks depend on it. Other configs, such as the one for `vite.config.ts`, stay as they are.
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 with oxlint (`.oxlintrc.json`, as in Vite's React template), load the ts-dom rules there: add `{ "name": "ts-dom", "specifier": "@nativele/ts-dom/oxlint" }` to `jsPlugins` and `"ts-dom/unused-markup": "error"` to `rules`.
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'`. 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).
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. A root `tsconfig.json` that only lists `references` (as in Vite's template) checks nothing itself, so `tsc --noEmit` without `-p` passes even with type errors.
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. The example project's [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-react/example/verify.mjs) does these checks 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.
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.5.2 <0.6.0"
7
- verified: "2026-11-05"
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.5.2 |
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, the example project does not run it) |
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-05 in Google Chrome 148 with the example project in the Nativele repository (`skills/nativele-state-management/example`), which CI runs again when the example or the library changes and once a month. With a different major version of a state library, treat the adapter and every limitation about that library as unverified.
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. The example project's [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-state-management/example/verify.mjs) does these checks 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.
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.5.1 <0.6.0"
7
- verified: "2026-11-05"
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.5.1 |
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-05 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.
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. Leave the tsconfig as it is: Vite's Svelte template has `tsconfig.app.json` extend `@tsconfig/svelte`, which sets `"strict": true`, and its `include` already covers `src/nv`. If the project turned `strict` off, set it back in that file.
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'`. 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.
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.5.2 <0.6.0"
7
- verified: "2026-11-05"
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.5.2 |
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-05 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.
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 monorepo), add a `@source` line, with the path relative to the CSS file:
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 needs that folder too: list it in `tsDom({ dirs })`, in the arguments of `ts-dom check` and `ts-dom doctor`, and in the tsconfig `include`; 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`.
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 monorepo are not styled | they are outside the project folder Tailwind scans | `@source "<path relative to the CSS file>"` |
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.5.2 <0.6.0"
7
- verified: "2026-11-05"
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.5.2 |
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-05 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.
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`: `strict`, the `tsDom({ dirs: ["src/nv"] })` plugin, `"build": "ts-dom check src/nv && vite build"`):
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.5.2 <0.6.0"
7
- verified: "2026-11-05"
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.5.2 |
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-05 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`), which CI runs again when the example or the library changes and once a month. 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.
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/` and add it to `include` in `tsconfig.json` (`"include": ["src", "test"]`). 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.
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 the Chrome already installed on the machine (`CHROME_BIN`, or `/usr/bin/google-chrome`, which GitHub's `ubuntu-latest` runners have), so nothing is downloaded and `npx playwright install` is not needed:
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. 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.
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
- Add `e2e` to `include` in `tsconfig.json` so `ts-dom check` type-checks the specs, and `test-results` and `playwright-report` to `.gitignore`.
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 (from the example project, `src/nv/counter-card.*`):
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
- Other parts of the API, as in the example project's tests:
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. The example's `test/todo-list.test.ts` asserts the happy-dom behavior, so a later happy-dom release that adds `moveBefore` shows up as a failing test. The Vitest API in browser mode is the same: the example's other happy-dom tests also pass unchanged when run in the browser project, so moving a test there is a matter of renaming it.
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 same applies to the oxlint rule: turn `ts-dom/unused-markup` off for test folders, as the setup guide says.
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 example project's `verify` script runs exactly these, plus the same unit tests under jsdom as a third Vitest project (`"environment": "jsdom"`), which shows that jsdom works for the same tests. Its tests prove each limitation above: the module import, per-file isolation, `define()` twice, `vi.resetModules()`, slot timing in both modes, and the move that happy-dom and Chrome handle differently.
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 the Chrome or Chromium binary |
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, `ts-dom check`, and lint in test folders: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md
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`