@jay-framework/jay-stack-cli 0.23.0 → 0.24.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/agent-kit-template/developer/component-refs.md +129 -12
- package/agent-kit-template/plugin/add-menu-guide.md +17 -17
- package/dist/index.d.ts +4 -1
- package/dist/index.js +317 -221
- package/package.json +10 -10
|
@@ -124,6 +124,8 @@ This generates both a ViewState field and a ref.
|
|
|
124
124
|
|
|
125
125
|
Refs are the **only supported path** from TypeScript to elements Jay renders. Direct `document` access bypasses the framework and can break rendering, updates, and performance.
|
|
126
126
|
|
|
127
|
+
`jay-stack validate` warns on `document.querySelector`, `document.getElementById`, `document.createElement`, and `document.addEventListener` in page and component `.ts` files. Suppress with `// jay-dom: allow` on the same line when an exception is genuinely needed.
|
|
128
|
+
|
|
127
129
|
### Do
|
|
128
130
|
|
|
129
131
|
- Declare elements in **jay-html** with `ref="..."`.
|
|
@@ -134,20 +136,135 @@ Refs are the **only supported path** from TypeScript to elements Jay renders. Di
|
|
|
134
136
|
|
|
135
137
|
### Avoid
|
|
136
138
|
|
|
137
|
-
- `document.querySelector` / `getElementById` to find template elements
|
|
138
|
-
- `document.createElement` + `appendChild` for UI that belongs in jay-html
|
|
139
|
-
- `document.addEventListener
|
|
139
|
+
- `document.querySelector` / `getElementById` to find template elements — use refs
|
|
140
|
+
- `document.createElement` + `appendChild` for UI that belongs in jay-html — use `forEach` with ViewState
|
|
141
|
+
- `document.addEventListener` for global events — use the root ref pattern (below)
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
## Root ref pattern — replacing `document.addEventListener`
|
|
144
|
+
|
|
145
|
+
Wrap the page content in a shell element with a ref. Use capture-phase listeners on the shell to intercept events before they reach children — functionally equivalent to `document.addEventListener`.
|
|
146
|
+
|
|
147
|
+
### Setup
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<!-- jay-html -->
|
|
151
|
+
<div ref="shell" class="page-shell">... entire page content ...</div>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
# Contract
|
|
156
|
+
- tag: shell
|
|
157
|
+
type: interactive
|
|
158
|
+
elementType: HTMLDivElement
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Global keyboard navigation
|
|
162
|
+
|
|
163
|
+
Instead of `document.addEventListener('keydown', ...)`:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
.withInteractive(function Page(_props, refs) {
|
|
167
|
+
let keyboardNav = false;
|
|
168
|
+
|
|
169
|
+
refs.shell.onkeydown(({ event }) => {
|
|
170
|
+
if (event.key === 'Tab') keyboardNav = true;
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
refs.shell.onmousedown(() => {
|
|
174
|
+
keyboardNav = false;
|
|
175
|
+
});
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Events bubble up from children to the shell — a handler on the shell sees all keyboard and mouse events from the entire page.
|
|
180
|
+
|
|
181
|
+
Use `refs.shell.addEventListener(type, handler, { capture: true })` only when you need to intercept events _before_ children handle them (e.g., preventing default on specific keys).
|
|
182
|
+
|
|
183
|
+
### Focus management (scroll into view)
|
|
184
|
+
|
|
185
|
+
Instead of `document.addEventListener('focusin', ...)`:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
refs.shell.onfocusin(({ event }) => {
|
|
189
|
+
if (!keyboardNav) return;
|
|
190
|
+
const el = event.target as HTMLElement;
|
|
191
|
+
refs.shell.exec$(() => {
|
|
192
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Detecting pointer leaving the page
|
|
198
|
+
|
|
199
|
+
Instead of `document.addEventListener('mouseleave', ...)`:
|
|
142
200
|
|
|
143
|
-
|
|
201
|
+
```typescript
|
|
202
|
+
refs.shell.onpointerleave(({ event }) => {
|
|
203
|
+
// Pointer left the shell — equivalent to leaving the viewport
|
|
204
|
+
// if the shell covers the full viewport
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Ensure the shell has no margin/padding gap so it covers the full viewport. `pointer-events: auto` (the default) is sufficient.
|
|
209
|
+
|
|
210
|
+
### Finding elements by class → use refs
|
|
211
|
+
|
|
212
|
+
Instead of `document.querySelector('.site-header')`:
|
|
213
|
+
|
|
214
|
+
```html
|
|
215
|
+
<!-- jay-html -->
|
|
216
|
+
<header ref="siteHeader" class="site-header">...</header>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
refs.siteHeader.onclick(() => {
|
|
221
|
+
/* ... */
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
refs.siteHeader.exec$((el) => {
|
|
225
|
+
el.classList.add('is-hidden');
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Dynamic lists → use forEach
|
|
144
230
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
231
|
+
Instead of creating elements with `document.createElement` in a loop:
|
|
232
|
+
|
|
233
|
+
```html
|
|
234
|
+
<!-- jay-html -->
|
|
235
|
+
<div forEach="cards" trackBy="id" class="card-grid">
|
|
236
|
+
<div class="card">
|
|
237
|
+
<img src="{imageUrl}" alt="{title}" />
|
|
238
|
+
<span>{title}</span>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Update the ViewState to add/remove cards — the framework handles DOM creation.
|
|
244
|
+
|
|
245
|
+
### Using `exec$` for native DOM APIs
|
|
246
|
+
|
|
247
|
+
For DOM operations that refs don't wrap (scroll, focus, measurements), use `exec$` inside an event handler:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
refs.myInput.onclick(() => {
|
|
251
|
+
refs.myInput.exec$((el) => {
|
|
252
|
+
el.focus();
|
|
253
|
+
el.select();
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
refs.scrollContainer.exec$((el) => {
|
|
258
|
+
el.scrollTo({ top: 0, behavior: 'smooth' });
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Rare `document` exceptions
|
|
150
263
|
|
|
151
|
-
|
|
264
|
+
Use only when no ref can exist, with `// jay-dom: allow` to suppress the validation warning:
|
|
152
265
|
|
|
153
|
-
|
|
266
|
+
| Case | Example |
|
|
267
|
+
| ---------------------- | --------------------------------------------------------------------- |
|
|
268
|
+
| Offscreen processing | `document.createElement('canvas') // jay-dom: allow` for image export |
|
|
269
|
+
| Coordinate hit-testing | `document.elementFromPoint(...) // jay-dom: allow` during drag |
|
|
270
|
+
| Tests | `document.dispatchEvent // jay-dom: allow` in Vitest |
|
|
@@ -44,10 +44,10 @@ Use `reference` for data sources (contracts, categories). Use `stage-place` for
|
|
|
44
44
|
Controls card size in the browse grid:
|
|
45
45
|
|
|
46
46
|
```yaml
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
browse:
|
|
48
|
+
size: small # 4 per row — color swatches, small tokens
|
|
49
|
+
size: medium # 2 per row — default
|
|
50
|
+
size: large # 1 per row — full-width previews
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
## Presentation (preview)
|
|
@@ -55,19 +55,19 @@ Controls card size in the browse grid:
|
|
|
55
55
|
Optional visual preview in the browse grid:
|
|
56
56
|
|
|
57
57
|
```yaml
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
# Static image
|
|
59
|
+
presentation:
|
|
60
|
+
type: image
|
|
61
|
+
src: thumbnails/my-plugin/feature.png
|
|
62
|
+
|
|
63
|
+
# HTML fragment — must use @scope for CSS isolation
|
|
64
|
+
presentation:
|
|
65
|
+
type: html-fragment
|
|
66
|
+
html: |
|
|
67
|
+
<div>
|
|
68
|
+
<style>@scope { .demo { color: blue; } }</style>
|
|
69
|
+
<div class="demo">Preview content</div>
|
|
70
|
+
</div>
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Html-fragment rules:
|
package/dist/index.d.ts
CHANGED
|
@@ -17,9 +17,12 @@ interface JayConfig {
|
|
|
17
17
|
publicFolder?: string;
|
|
18
18
|
configBase?: string;
|
|
19
19
|
};
|
|
20
|
+
site?: {
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
};
|
|
20
23
|
}
|
|
21
24
|
declare function loadConfig(): JayConfig;
|
|
22
|
-
declare function getConfigWithDefaults(config: JayConfig): Required<JayConfig>;
|
|
25
|
+
declare function getConfigWithDefaults(config: JayConfig): Required<Pick<JayConfig, 'devServer'>> & Pick<JayConfig, 'site'>;
|
|
23
26
|
declare function updateConfig(updates: Partial<JayConfig>): void;
|
|
24
27
|
|
|
25
28
|
export { type JayConfig, type StartDevServerOptions, getConfigWithDefaults, loadConfig, startDevServer, updateConfig };
|