jj 3.0.0-rc.5 → 3.0.0-rc.6
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/package.json +1 -1
- package/skills/SKILL.md +142 -0
package/package.json
CHANGED
package/skills/SKILL.md
CHANGED
|
@@ -7,6 +7,41 @@ description: Expert guide for the JJ DOM manipulation library. Load this skill w
|
|
|
7
7
|
|
|
8
8
|
JJ is a minimal, zero-dependency TypeScript library that wraps browser DOM interfaces in fluent, type-safe classes. It complements native browser APIs rather than replacing them.
|
|
9
9
|
|
|
10
|
+
## Translation Checklist
|
|
11
|
+
|
|
12
|
+
When converting native DOM code, framework code, or vague UI requests into JJ, default to this order of thought:
|
|
13
|
+
|
|
14
|
+
- Start from wrappers, not native nodes: `JJD.from(document)`, `JJHE.create()`, `JJHE.tree()`, `JJET.from(window)`, `getShadow(true)`.
|
|
15
|
+
- Keep values wrapped and chain operations; use `.ref` only for native APIs JJ does not provide.
|
|
16
|
+
- Use `JJHE.tree` with a local `h` alias for multi-node or nested UI.
|
|
17
|
+
- Use `setChild()`/`setChildren()` to replace content and `addChildMap()`/`setChildMap()` for array rendering.
|
|
18
|
+
- Query with `find()`/`findAll()`/`closest()` instead of native `querySelector*` when JJ already covers the case.
|
|
19
|
+
- Use `setText()` for user content and treat `setHTML(..., true)` as a trusted-content escape hatch.
|
|
20
|
+
- For repeated child interactions, prefer one delegated listener on a stable parent over one listener per child.
|
|
21
|
+
- Choose shadow DOM for self-contained widgets and light DOM for page-level content that should inherit global styles.
|
|
22
|
+
- For components, keep fetched templates/styles at module scope, attach shadow root in the constructor, initialize once, then update targeted nodes instead of rebuilding the whole tree.
|
|
23
|
+
- Prefer `'open'` shadow roots unless the user explicitly needs `'closed'`; open mode is easier to test and debug.
|
|
24
|
+
- Use plain JS state plus targeted wrapper updates by default; do not invent a virtual DOM style rerender loop unless the user explicitly wants one.
|
|
25
|
+
|
|
26
|
+
## Naming Conventions
|
|
27
|
+
|
|
28
|
+
In this repository, prefix variables that hold JJ wrapper instances with `jj`.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const jjDoc = JJD.from(document)
|
|
32
|
+
const jjFruits = jjDoc.find('#fruits', true)
|
|
33
|
+
const jjSubmitBtn = jjDoc.find('button#submit', true)
|
|
34
|
+
const jjDialog = JJHE.create('dialog')
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Naming defaults:
|
|
38
|
+
|
|
39
|
+
- Use `jj*` for JJ wrappers, including private fields: `#jjHost` for `JJHE.from(this)` (the wrapped host element) and `#jjShadow` for `this.#jjHost.getShadow()` (the wrapped shadow root).
|
|
40
|
+
- Do not use `jj*` for plain data like `fruits`, `title`, `isOpen`, or `userName`.
|
|
41
|
+
- Do not use `jj*` for native DOM values; prefer names like `formEl`, `shadowRoot`, `inputRef`, or `styleSheet`.
|
|
42
|
+
- For promises, use normal names with `Promise`, like `templatePromise` or `stylePromise`.
|
|
43
|
+
- `h` is the main intentional exception: use it as the local alias for `JJHE.tree`.
|
|
44
|
+
|
|
10
45
|
## Wrapper Hierarchy
|
|
11
46
|
|
|
12
47
|
Each JJ wrapper exposes the native node via `.ref`.
|
|
@@ -54,6 +89,37 @@ const btn = JJHE.create('button')
|
|
|
54
89
|
.on('click', handleSave)
|
|
55
90
|
```
|
|
56
91
|
|
|
92
|
+
## Tutorial Defaults — Prefer JJ Idioms Over Native DOM Steps
|
|
93
|
+
|
|
94
|
+
When translating browser DOM code into JJ, do not mechanically keep native patterns like repeated `appendChild`, `querySelector`, or unwrap/re-wrap flows. Prefer the JJ equivalent that keeps work inside wrappers.
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// ✅ preferred: build a subtree once
|
|
98
|
+
const h = JJHE.tree
|
|
99
|
+
|
|
100
|
+
latestChatResponse.addChild(
|
|
101
|
+
h('section', null, h('h2', null, 'User'), h('div', null, userPrompt), h('h2', null, 'Assistant'), assistantMessage),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
// ✅ also fine for flat mapped children
|
|
105
|
+
const list = JJHE.create('ul').addChildMap(fruits, (fruit) => h('li', null, fruit))
|
|
106
|
+
|
|
107
|
+
// ❌ avoid native-style wrapper escape hatches when JJ already covers it
|
|
108
|
+
latestChatResponse.ref.appendChild(JJHE.create('h2').setText('User').ref)
|
|
109
|
+
latestChatResponse.ref.appendChild(JJHE.create('div').setText(userPrompt).ref)
|
|
110
|
+
latestChatResponse.ref.appendChild(JJHE.create('h2').setText('Assistant').ref)
|
|
111
|
+
latestChatResponse.ref.appendChild(assistantMessage.ref)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Default heuristics from the tutorial:
|
|
115
|
+
|
|
116
|
+
- Use `JJHE.tree` with a local `h` alias when creating multiple siblings or any nested subtree.
|
|
117
|
+
- Use `create()` for one-off elements; switch to `tree()` as soon as structure becomes non-trivial.
|
|
118
|
+
- Prefer `setChild()` or `setChildren()` when replacing content, not `.empty().addChild()`.
|
|
119
|
+
- Prefer `addChildMap()` or `setChildMap()` when rendering from arrays.
|
|
120
|
+
- Keep values wrapped. Reach for `.ref` only for native APIs JJ does not expose.
|
|
121
|
+
- Use JJ verb families consistently: `set*` replaces, `add*` appends, `pre*` prepends, `rm*` removes, `sw*` toggles.
|
|
122
|
+
|
|
57
123
|
## Document Queries
|
|
58
124
|
|
|
59
125
|
Wrap `document` with `JJD.from(document)` before querying.
|
|
@@ -68,6 +134,16 @@ const items = doc.findAll('.item') // always an array
|
|
|
68
134
|
const btn = this.getShadow(true).find('#submit')
|
|
69
135
|
```
|
|
70
136
|
|
|
137
|
+
Querying defaults from the tutorial:
|
|
138
|
+
|
|
139
|
+
- Start from a wrapped container like `JJD.from(document)` or a `JJSR` shadow root.
|
|
140
|
+
- Prefer `find(selector, true)` when absence is a bug; it fails earlier and more clearly than a later null access.
|
|
141
|
+
- Prefer narrower selectors that encode expectations, like `button#submit`, instead of broad lookups plus manual type checks.
|
|
142
|
+
- Use `findAll()` for arrays of wrappers and keep operating on wrappers instead of unwrapping to native elements.
|
|
143
|
+
- Do not use `.ref.querySelector(...)` or `.ref.querySelectorAll(...)` when `find()` or `findAll()` already covers the case.
|
|
144
|
+
- Use `.closest()` on wrappers for event delegation and ancestor lookup.
|
|
145
|
+
- Use `JJHE.fromId('submit-btn')` for direct ID lookup when you already know the target is an HTML element.
|
|
146
|
+
|
|
71
147
|
## Attributes, Classes, Styles
|
|
72
148
|
|
|
73
149
|
```typescript
|
|
@@ -153,10 +229,41 @@ JJHE.from(this).triggerCustomEvent('todo-toggle', { id: 1, done: true })
|
|
|
153
229
|
new CustomEvent('panel-ready', { bubbles: false, composed: false })
|
|
154
230
|
```
|
|
155
231
|
|
|
232
|
+
Event defaults from the tutorial:
|
|
233
|
+
|
|
234
|
+
- Prefer `.on()` and `.off()` on wrappers over native `addEventListener`/`removeEventListener` when already working with JJ values.
|
|
235
|
+
- Prefer `.triggerEvent()` and `.triggerCustomEvent()` for common JJ event dispatch; they default to `bubbles: true` and `composed: true`.
|
|
236
|
+
- Use `triggerCustomEvent(name, detail)` for component-to-parent communication instead of ad hoc callback plumbing.
|
|
237
|
+
- Use `bubbles: false` and `composed: false` only for intentionally internal events.
|
|
238
|
+
- Keep event code close to the wrapper it affects so later DOM updates stay targeted and local.
|
|
239
|
+
|
|
240
|
+
Guide defaults for event-heavy UI:
|
|
241
|
+
|
|
242
|
+
- Prefer event delegation on a common parent for repeated child actions instead of binding one listener per item.
|
|
243
|
+
- Use `.closest()` to recover the intended delegated target from `event.target`.
|
|
244
|
+
- When you need JJ's wrapper-bound `this` inside a listener, use `function` syntax, not an arrow.
|
|
245
|
+
- Native UI events like `click`, `input`, and `change` already cross shadow boundaries; custom events do not unless `composed: true`.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
list.on('click', function (event) {
|
|
249
|
+
const item = JJHE.from(event.target as Node).closest('[data-item-id]')
|
|
250
|
+
if (!item) return
|
|
251
|
+
this.addClass('handled')
|
|
252
|
+
item.addClass('active')
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
156
256
|
## Custom Elements — Complete Pattern
|
|
157
257
|
|
|
158
258
|
Fetch template and style at **module scope** — loaded once, shared across all instances.
|
|
159
259
|
|
|
260
|
+
Guide defaults for component shape:
|
|
261
|
+
|
|
262
|
+
- Use shadow DOM for self-contained widgets and design-system components; use light DOM for sections that should inherit page styling and normal document flow.
|
|
263
|
+
- Prefer `'open'` shadow mode unless stricter encapsulation is a hard requirement.
|
|
264
|
+
- `attributeChangedCallback()` can run before `connectedCallback()` for parsed attributes, so setters and render paths must tolerate pre-mount state.
|
|
265
|
+
- Use `disconnectedCallback()` only to clean up external side effects like document listeners, timers, observers, or subscriptions; do not tear down the shadow root just because the element was detached.
|
|
266
|
+
|
|
160
267
|
```typescript
|
|
161
268
|
import { attr2prop, defineComponent, fetchStyle, fetchTemplate, JJHE } from 'jj'
|
|
162
269
|
|
|
@@ -219,6 +326,28 @@ await MyCard.defined
|
|
|
219
326
|
await Promise.all([MyCard.defined, OtherCard.defined])
|
|
220
327
|
```
|
|
221
328
|
|
|
329
|
+
Template defaults from the tutorial:
|
|
330
|
+
|
|
331
|
+
- Prefer fetched `.html` templates for large static markup.
|
|
332
|
+
- Prefer `<template>` elements for reusable DOM snippets already present in the page.
|
|
333
|
+
- Prefer `JJHE.tree()` or `JJHE.create()` when you need live wrapper references for later updates.
|
|
334
|
+
- Keep template promises at module scope; for lazy loading, initialize them inside `connectedCallback()` with an `if (!templatePromise)` guard.
|
|
335
|
+
- Use one stable `#root` wrapper per component: `JJHE.from(this)` for light DOM or `JJHE.from(this).setShadow(...).getShadow(true)` for shadow DOM.
|
|
336
|
+
- Initialize template content once, then update specific nodes with `find(...).setText(...)` or other targeted wrapper operations.
|
|
337
|
+
|
|
338
|
+
Guide defaults for attributes and queries:
|
|
339
|
+
|
|
340
|
+
- Always coerce attribute-backed values in setters because HTML attributes arrive as strings.
|
|
341
|
+
- Query inside shadow DOM from the `JJSR` wrapper, never from `document`.
|
|
342
|
+
- Use specific selectors like `button#submit` or `[data-role="title"]` so the selector carries intent.
|
|
343
|
+
|
|
344
|
+
State defaults from the tutorial:
|
|
345
|
+
|
|
346
|
+
- Prefer plain objects or classes for state and update the exact affected wrappers in event handlers or setters.
|
|
347
|
+
- Prefer targeted updates like `value.setText(String(state.count))` over rebuilding an entire subtree for a small change.
|
|
348
|
+
- Use getters/setters or small helper methods when they make state transitions clearer, not because JJ requires a framework-style abstraction.
|
|
349
|
+
- Reach for external state libraries only when the application actually needs cross-cutting coordination beyond local JS state.
|
|
350
|
+
|
|
222
351
|
`defineComponent()` returns `Promise<boolean>`:
|
|
223
352
|
|
|
224
353
|
- `false` — newly defined by this call
|
|
@@ -260,6 +389,13 @@ el.addTemplate(await templatePromise) // clones before appending
|
|
|
260
389
|
|
|
261
390
|
`addChild` / `preChild` / `setChild` and map variants ignore `null`/`undefined`; all other non-node values are coerced to Text nodes.
|
|
262
391
|
|
|
392
|
+
Guide defaults for template and fragment usage:
|
|
393
|
+
|
|
394
|
+
- `addTemplate()` and `setTemplate()` always clone the input before appending; reuse the same template value safely.
|
|
395
|
+
- Prefer `setTemplate()` over `empty().addTemplate()` when replacing all content.
|
|
396
|
+
- Prefer `addChildMap()` or `setChildMap()` over manually building a fragment when rendering arrays.
|
|
397
|
+
- Use `JJDF.create()` when you need to assemble multiple sibling nodes before one insertion.
|
|
398
|
+
|
|
263
399
|
## Node Traversal
|
|
264
400
|
|
|
265
401
|
```typescript
|
|
@@ -299,6 +435,12 @@ document.adoptedStyleSheets = [sheet]
|
|
|
299
435
|
const fragment = await fetchTemplate(import.meta.resolve('./dialog.html'))
|
|
300
436
|
```
|
|
301
437
|
|
|
438
|
+
Guide defaults for browser-native loading hints:
|
|
439
|
+
|
|
440
|
+
- Use native `<link>` hints built with `JJHE.tree` and appended to `head` for `preload`, `prefetch`, and `modulepreload`.
|
|
441
|
+
- Keep the `as` value explicit for `preload` instead of inferring it from file extensions.
|
|
442
|
+
- Use `preload` for current-page needs, `prefetch` for probable future navigation, and `modulepreload` for module graphs you want fetched early.
|
|
443
|
+
|
|
302
444
|
## String Casing
|
|
303
445
|
|
|
304
446
|
String case-conversion helpers are internal implementation details.
|