@jay-framework/jay-stack-cli 0.22.2 → 0.23.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/designer/INSTRUCTIONS.md +4 -2
- package/agent-kit-template/designer/contracts-and-plugins.md +20 -0
- package/agent-kit-template/designer/jay-html-components.md +44 -6
- package/agent-kit-template/designer/jay-html-syntax.md +2 -0
- package/agent-kit-template/designer/jay-html-template-syntax.md +105 -1
- package/agent-kit-template/designer/navigation-patterns.md +73 -0
- package/agent-kit-template/designer/routing.md +56 -1
- package/agent-kit-template/designer/validation-guide.md +88 -0
- package/agent-kit-template/developer/routing.md +12 -1
- package/agent-kit-template/plugin/INSTRUCTIONS.md +25 -23
- package/agent-kit-template/plugin/add-menu-guide.md +114 -0
- package/agent-kit-template/plugin/aiditor-settings-guide.md +296 -0
- package/agent-kit-template/plugin/dev-server-service.md +2 -0
- package/agent-kit-template/plugin/plugin-routes.md +49 -0
- package/agent-kit-template/plugin/setup-guide.md +4 -16
- package/dist/index.d.ts +1 -88
- package/dist/index.js +277 -2445
- package/package.json +10 -11
- package/lib/vendors/README.md +0 -510
- package/lib/vendors/figma/README.md +0 -396
- package/test/vendors/figma/fixtures/README.md +0 -164
|
@@ -31,7 +31,7 @@ There is no standalone "interactive" phase. Any tag with `type: interactive` (re
|
|
|
31
31
|
4. **Read actions** — read `.jay-action` files (paths from plugins-index) to see action descriptions, input schemas, and output schemas. This tells you what data each action accepts and returns.
|
|
32
32
|
5. **Read references** — check `references/<plugin>/` for pre-generated discovery data (product catalogs, collection schemas, etc.). These are generated by `jay-stack agent-kit` and contain real data from the site.
|
|
33
33
|
6. **Discover data** — run `jay-stack params <plugin>/<contract>` for SSG route params, `jay-stack action <plugin>/<action>` for data discovery. Use reference files (step 5) first when available — they're faster than running CLI commands.
|
|
34
|
-
7. **Create pages** — write `.jay-html` files under `src/pages/` following directory-based routing. For static override routes (a static page that overrides a dynamic route for a specific URL), declare params with `<script type="application/jay-params">`.
|
|
34
|
+
7. **Create pages** — write `.jay-html` files under `src/pages/` following directory-based routing. For static override routes (a static page that overrides a dynamic route for a specific URL), declare params with `<script type="application/jay-params">`. Jay-html `if` and `{…}` bind to **tag names only** — no `.length`, method calls, or bracket indexing; derive booleans and counts in `page.ts` (see [jay-html-template-syntax.md](jay-html-template-syntax.md#expression-limits-important)).
|
|
35
35
|
8. **Validate** — run `jay-stack validate` to check for errors.
|
|
36
36
|
9. **Test** — run `jay-stack dev --test-mode` and verify pages render.
|
|
37
37
|
|
|
@@ -41,14 +41,16 @@ There is no standalone "interactive" phase. Any tag with `type: interactive` (re
|
|
|
41
41
|
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
42
42
|
| [project-structure.md](project-structure.md) | Project layout, styling patterns (CSS themes, design tokens), configuration files |
|
|
43
43
|
| [jay-html-syntax.md](jay-html-syntax.md) | Jay-HTML overview: philosophy, component types, nesting rules, links to sub-files |
|
|
44
|
-
| [jay-html-template-syntax.md](jay-html-template-syntax.md) | Template markup: data binding, conditions
|
|
44
|
+
| [jay-html-template-syntax.md](jay-html-template-syntax.md) | Template markup: data binding, conditions, expression limits (no `.length`), loops, refs |
|
|
45
45
|
| [jay-html-components.md](jay-html-components.md) | Component imports: headless (key/instance), headfull FS, nesting patterns |
|
|
46
46
|
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic style bindings, class bindings |
|
|
47
47
|
| [routing.md](routing.md) | Directory-based routing: page structure, dynamic routes, route priority |
|
|
48
|
+
| [navigation-patterns.md](navigation-patterns.md) | Active menu/sidebar patterns using `jay.url.path`, `===`, and `^=` operators |
|
|
48
49
|
| [contracts-and-plugins.md](contracts-and-plugins.md) | Reading contracts, plugin.yaml, .jay-action files, and the materialized indexes |
|
|
49
50
|
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
50
51
|
| [script-tags.md](script-tags.md) | Script tag policy: use page.ts for behavior, jay-script="allow" for third-party scripts |
|
|
51
52
|
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, params, action, dev server |
|
|
53
|
+
| [validation-guide.md](validation-guide.md) | Understanding validation output: static analysis, component warnings, how to act on findings |
|
|
52
54
|
| `../references/<plugin>/` | Pre-generated discovery data: product catalogs, collection schemas (from `jay-stack agent-kit`) |
|
|
53
55
|
|
|
54
56
|
## When to Use Headfull Components
|
|
@@ -279,3 +279,23 @@ Schemas use a compact type notation:
|
|
|
279
279
|
| `{tag: sel, type: interactive, elementType: HTMLSelectElement}` | `<select ref="sel">...</select>` |
|
|
280
280
|
| `{tag: items, type: sub-contract, repeated: true, trackBy: id}` | `<div forEach="items" trackBy="id">...</div>` |
|
|
281
281
|
| `{tag: detail, type: sub-contract}` | `{detail.fieldName}` |
|
|
282
|
+
|
|
283
|
+
### Empty list / empty state
|
|
284
|
+
|
|
285
|
+
For repeated lists, add a **boolean variant** (e.g. `hasItems`, `hasCategories`) for empty-state UI. Do **not** use JavaScript property access in jay-html — `if="items.length===0"` fails at runtime because jay-html looks for a tag named `items.length`, not the array's length.
|
|
286
|
+
|
|
287
|
+
```yaml
|
|
288
|
+
# ✅ In the contract
|
|
289
|
+
- tag: hasCategories
|
|
290
|
+
type: variant
|
|
291
|
+
dataType: boolean
|
|
292
|
+
description: Whether there are any categories
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
```html
|
|
296
|
+
<!-- ✅ In jay-html -->
|
|
297
|
+
<p if="!hasCategories">No categories yet.</p>
|
|
298
|
+
<div if="hasCategories" forEach="categories" trackBy="_id">...</div>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Alternatively, expose a **number** data tag (`itemCount`) and use numeric comparison: `if="itemCount===0"`. See [jay-html-template-syntax.md](jay-html-template-syntax.md#expression-limits-important) and [contracts/examples/category-list.md](../contracts/examples/category-list.md).
|
|
@@ -39,6 +39,8 @@ Access data and refs with the key prefix:
|
|
|
39
39
|
|
|
40
40
|
Key-based imports are only available in **pages** (not in headfull FS components).
|
|
41
41
|
|
|
42
|
+
**Important:** Do NOT use `<jay:keyName>` for key-based imports. The key is for ViewState access (`{key.field}`), not for inline elements. `<jay:>` tags use the **contract name**, not the key.
|
|
43
|
+
|
|
42
44
|
### Pattern 2: Instance-Based (jay: prefix)
|
|
43
45
|
|
|
44
46
|
Multiple instances with props and inline templates. Use when you need **multiple instances** or need to pass **props**.
|
|
@@ -99,6 +101,16 @@ Use `{path}` syntax to bind props to values from the page's ViewState. The bindi
|
|
|
99
101
|
|
|
100
102
|
Inside `<jay:...>`, bindings resolve to **that instance's** contract tags (not the parent).
|
|
101
103
|
|
|
104
|
+
### Choosing between patterns
|
|
105
|
+
|
|
106
|
+
| Need | Pattern | Key? | Tag? |
|
|
107
|
+
| ------------------------------------------------------ | -------------- | --------------- | -------------------------------------------- |
|
|
108
|
+
| One component per page, data across the whole template | Key-based | `key="product"` | No `<jay:>` — use `{product.field}` bindings |
|
|
109
|
+
| Multiple instances, each with own props and template | Instance-based | No key | `<jay:contract-name prop="...">` |
|
|
110
|
+
| One instance but with custom inline template | Instance-based | No key | `<jay:contract-name>` |
|
|
111
|
+
|
|
112
|
+
**Never combine both:** a component imported with `key` cannot also be used as `<jay:>`. These are mutually exclusive patterns.
|
|
113
|
+
|
|
102
114
|
### Prop binding summary
|
|
103
115
|
|
|
104
116
|
| Syntax | Resolves to | Example |
|
|
@@ -160,18 +172,44 @@ Each headfull component lives in its own subdirectory under `src/components/` wi
|
|
|
160
172
|
<jay:SharedHeader logoUrl="/logo.png" />
|
|
161
173
|
```
|
|
162
174
|
|
|
175
|
+
> **Route params:** Headfull and instance-based headless components do not receive route params directly. To pass a route param, expose it through the page's ViewState and bind it as a prop: `<jay:SideNav activePage="{activePage}" />`. See [routing.md](routing.md) for the full pattern.
|
|
176
|
+
|
|
163
177
|
### Component Structure
|
|
164
178
|
|
|
165
|
-
|
|
179
|
+
Each headfull component needs three files in its subdirectory under `src/components/`:
|
|
180
|
+
|
|
181
|
+
**`.jay-contract`** — declares props. Tags are optional (use `tags: []` or omit for structural components):
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
# components/site-header/site-header.jay-contract
|
|
185
|
+
name: SiteHeader
|
|
186
|
+
props:
|
|
187
|
+
- name: logoUrl
|
|
188
|
+
type: string
|
|
189
|
+
required: true
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**`.ts`** — component code. Must use `makeJayStackComponent` with `.withProps()` matching the contract props:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// components/site-header/site-header.ts
|
|
196
|
+
import { makeJayStackComponent, phaseOutput } from '@jay-framework/fullstack-component';
|
|
197
|
+
import type { SiteHeaderContract, SiteHeaderProps } from './site-header.jay-html';
|
|
198
|
+
|
|
199
|
+
export const siteHeader = makeJayStackComponent<SiteHeaderContract>()
|
|
200
|
+
.withProps<SiteHeaderProps>()
|
|
201
|
+
.withFastRender(async (props) => phaseOutput({ logoUrl: props.logoUrl }, {}));
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
For a structural component with only props and no data logic, `.withFastRender` passes props through as ViewState.
|
|
205
|
+
|
|
206
|
+
**`.jay-html`** — the template:
|
|
166
207
|
|
|
167
208
|
```html
|
|
168
|
-
<!-- components/header/header.jay-html -->
|
|
209
|
+
<!-- components/site-header/site-header.jay-html -->
|
|
169
210
|
<html>
|
|
170
211
|
<head>
|
|
171
|
-
<script type="application/jay-data">
|
|
172
|
-
data:
|
|
173
|
-
logoUrl: string
|
|
174
|
-
</script>
|
|
212
|
+
<script type="application/jay-data" contract="./site-header.jay-contract"></script>
|
|
175
213
|
</head>
|
|
176
214
|
<body>
|
|
177
215
|
<header>
|
|
@@ -6,6 +6,8 @@ Jay-HTML is standard HTML with data bindings. There is no custom component frame
|
|
|
6
6
|
|
|
7
7
|
The design tool can freely read and rewrite jay-html files as long as contract bindings stay intact. Bindings (`{expression}`, `if`, `forEach`, `ref`) are the only extension to HTML. Everything else — CSS, structure, semantics, accessibility — is native.
|
|
8
8
|
|
|
9
|
+
**Common mistake:** expressions are not JavaScript — `if="items.length===0"` fails because jay-html resolves tag names, not property access. Use a boolean tag like `hasItems` or a number tag like `itemCount` instead. See [jay-html-template-syntax.md](jay-html-template-syntax.md#expression-limits-important).
|
|
10
|
+
|
|
9
11
|
## Component Types
|
|
10
12
|
|
|
11
13
|
### Page
|
|
@@ -140,15 +140,119 @@ Use parentheses for complex expressions:
|
|
|
140
140
|
<button if="count <= 0 || isLoading" disabled>Checkout</button>
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
### String Comparison
|
|
144
|
+
|
|
145
|
+
For string-typed tags, the right side of `===`/`!==` resolves as a **field reference**. Use quotes for string literals:
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<!-- Field-to-field comparison -->
|
|
149
|
+
<a if="url === currentPath" class="active">Current page</a>
|
|
150
|
+
|
|
151
|
+
<!-- Literal comparison (use quotes) -->
|
|
152
|
+
<div if="status === 'pending'">Pending approval</div>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For enum-typed tags, the right side remains a variant literal (no quotes needed) — see Enum Variant above.
|
|
156
|
+
|
|
157
|
+
### Starts With (`^=`)
|
|
158
|
+
|
|
159
|
+
Check if a string starts with a prefix — useful for section-level highlighting in navigation:
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<a if="jay.url.path ^= '/docs/designer'" class="section-active">Designer</a>
|
|
163
|
+
<a if="currentPath ^= sectionUrl" class="active">{label}</a>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Works with both field references and quoted literals.
|
|
167
|
+
|
|
168
|
+
### Built-in Bindings (`jay.`)
|
|
169
|
+
|
|
170
|
+
The `jay.` prefix provides framework values in page templates:
|
|
171
|
+
|
|
172
|
+
| Binding | Value | Example |
|
|
173
|
+
| -------------- | ------------------------------ | ------------------------ |
|
|
174
|
+
| `jay.params.X` | Route param from `[X]` segment | `jay.params.slug` |
|
|
175
|
+
| `jay.url.path` | Current URL pathname | `/docs/designer/routing` |
|
|
176
|
+
|
|
177
|
+
Available at all render phases (slow, fast, interactive). Use in text bindings, prop bindings, and conditionals:
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<h1>Current: {jay.url.path}</h1>
|
|
181
|
+
<jay:Sidebar activePage="{jay.params.slug}" currentPath="{jay.url.path}" />
|
|
182
|
+
<a if="jay.url.path ^= '/docs'" class="docs-active">Docs</a>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`jay.` bindings are available in **page templates only** — headfull components receive this data via props.
|
|
186
|
+
|
|
187
|
+
### Choosing the Right Condition Type
|
|
188
|
+
|
|
189
|
+
The contract determines how conditions work. Choose the data type based on the use case:
|
|
190
|
+
|
|
191
|
+
| Use case | Contract type | Condition syntax | Example |
|
|
192
|
+
| ----------------------------- | ---------------- | -------------------- | -------------------------- |
|
|
193
|
+
| Show/hide a section | `boolean` | `if="flag"` | `if="inStock"` |
|
|
194
|
+
| Switch between known states | `variant` (enum) | `if="tag === value"` | `if="status === active"` |
|
|
195
|
+
| Compare against another field | `string` | `if="a === b"` | `if="url === currentPath"` |
|
|
196
|
+
| Compare against a literal | `string` | `if="a === 'text'"` | `if="role === 'admin'"` |
|
|
197
|
+
| Match URL prefix | `string` | `if="a ^= b"` | `if="path ^= '/docs'"` |
|
|
198
|
+
| Threshold / range | `number` | `if="a > n"` | `if="count > 0"` |
|
|
199
|
+
|
|
200
|
+
**Boolean** — best for simple on/off states. The contract declares `type: variant, dataType: boolean`. Most conditions are booleans.
|
|
201
|
+
|
|
202
|
+
**Enum** — best when there's a fixed set of known values (e.g., `active | inactive | pending`). The compiler validates that the value exists in the enum. Use for mutually exclusive states where each value maps to different UI.
|
|
203
|
+
|
|
204
|
+
**String** — best for dynamic comparison where values aren't known at contract time (URLs, slugs, user input). The right side of `===` resolves as a field reference; use quotes for literals. Also supports `^=` for prefix matching.
|
|
205
|
+
|
|
143
206
|
### Rules Summary
|
|
144
207
|
|
|
145
208
|
- Boolean: `if="flag"` / `if="!flag"`
|
|
146
|
-
- Enum: `if="tag===value"` / `if="tag!==value"` (no quotes around value)
|
|
209
|
+
- Enum: `if="tag === value"` / `if="tag !== value"` (no quotes around value)
|
|
210
|
+
- String field: `if="url === currentPath"` (bare identifier = field)
|
|
211
|
+
- String literal: `if="url === '/about'"` (quoted = literal)
|
|
212
|
+
- Starts with: `if="path ^= prefix"` / `if="path ^= '/docs'"`
|
|
147
213
|
- Numeric: `if="count > 0"`, `if="price <= budget"`
|
|
148
214
|
- Field comparison: `if="available >= required"`
|
|
149
215
|
- Logical: `if="a && b"`, `if="a || b"`, `if="(a || b) && c"`
|
|
150
216
|
- Negation: `!` prefix on booleans
|
|
151
217
|
|
|
218
|
+
### Expression limits (important)
|
|
219
|
+
|
|
220
|
+
Jay-html expressions resolve **contract or page tag names only**. They are **not** JavaScript — even when the syntax looks similar (`===`, `&&`, `> 0`).
|
|
221
|
+
|
|
222
|
+
❌ **Invalid** — property access, indexing, or method calls:
|
|
223
|
+
|
|
224
|
+
```html
|
|
225
|
+
<p if="items.length===0">No items</p>
|
|
226
|
+
<!-- looks for a tag named "items.length" -->
|
|
227
|
+
<span>{user.name.split(' ')[0]}</span>
|
|
228
|
+
<!-- no method calls or bracket indexing -->
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
✅ **Valid** — expose derived state in the contract or in `page.ts` ViewState:
|
|
232
|
+
|
|
233
|
+
```html
|
|
234
|
+
<p if="!hasItems">No items</p>
|
|
235
|
+
<span if="itemCount > 0">You have {itemCount} items</span>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
| Need | Contract / ViewState tag | Jay-HTML |
|
|
239
|
+
| --------------- | ---------------------------- | -------------------- |
|
|
240
|
+
| Empty list hint | `hasItems: boolean` variant | `if="!hasItems"` |
|
|
241
|
+
| Count-based UI | `itemCount: number` data tag | `if="itemCount===0"` |
|
|
242
|
+
|
|
243
|
+
See [contracts/examples/category-list.md](../contracts/examples/category-list.md) (`hasCategories`).
|
|
244
|
+
|
|
245
|
+
### Common Errors
|
|
246
|
+
|
|
247
|
+
Invalid expressions produce a visible `[INVALID: expression]` marker in the page instead of crashing. The validation message includes the parse error and a pointer to this guide.
|
|
248
|
+
|
|
249
|
+
| Error | Cause | Fix |
|
|
250
|
+
| ------------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
251
|
+
| `Expected "." or identifier` | Curly braces in non-expression context (e.g., CSS in body `<style>`) | Move `<style>` to `<head>` or use body styles per DL#164 |
|
|
252
|
+
| `unexpected operator "^="` | Using `^=` with an older framework version | Update framework or use `===` instead |
|
|
253
|
+
| `Unknown enum value "X"` | Comparing against a value not in the enum | Check the contract for valid enum values |
|
|
254
|
+
| `the data field [X] not found` | Referencing a field not in the contract | Check the contract tags for available fields |
|
|
255
|
+
|
|
152
256
|
## Loops (forEach / trackBy)
|
|
153
257
|
|
|
154
258
|
Iterate over repeated sub-contracts:
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Navigation Patterns
|
|
2
|
+
|
|
3
|
+
## Active Menu Item
|
|
4
|
+
|
|
5
|
+
Use conditional class bindings with `===` to highlight the current page:
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<nav>
|
|
9
|
+
<div forEach="menuItems" trackBy="url">
|
|
10
|
+
<a href="{url}" class="nav-link {url === currentPath ? active}">{label}</a>
|
|
11
|
+
</div>
|
|
12
|
+
</nav>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The `{url === currentPath ? active}` adds the `active` class when the menu item's URL matches the current path.
|
|
16
|
+
|
|
17
|
+
## Active Section
|
|
18
|
+
|
|
19
|
+
Use `^=` (starts with) for section-level highlighting. A link to `/docs/designer` should be active when the URL is `/docs/designer/routing`:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<nav>
|
|
23
|
+
<div forEach="sections" trackBy="url">
|
|
24
|
+
<a href="{url}" class="section-link {currentPath ^= url ? active}">{label}</a>
|
|
25
|
+
</div>
|
|
26
|
+
</nav>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Two-Level Sidebar
|
|
30
|
+
|
|
31
|
+
Combine section matching and page matching for a sidebar with expandable sections:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<nav>
|
|
35
|
+
<div forEach="sections" trackBy="url">
|
|
36
|
+
<a href="{url}" class="section {currentPath ^= url ? active}">{label}</a>
|
|
37
|
+
<div if="currentPath ^= url" forEach="pages" trackBy="url">
|
|
38
|
+
<a href="{url}" class="page {url === currentPath ? active}">{label}</a>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</nav>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- Section links use `^=` — active when any child page is current
|
|
45
|
+
- Page links within the section use `===` — active on exact match
|
|
46
|
+
- The `if="currentPath ^= url"` on the pages container shows child pages only for the active section
|
|
47
|
+
|
|
48
|
+
## Passing URL Data to Components
|
|
49
|
+
|
|
50
|
+
In page templates, use `jay.` bindings to pass URL information to nested components without needing a `page.ts`:
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<jay:Sidebar currentPath="{jay.url.path}" activeRole="{jay.params.role}" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Inside the component template, use the props as ViewState fields:
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<!-- sidebar.jay-html -->
|
|
60
|
+
<a href="/docs/designer" class="role-link {currentPath ^= '/docs/designer' ? active}">Designer</a>
|
|
61
|
+
<a href="/docs/developer" class="role-link {currentPath ^= '/docs/developer' ? active}"
|
|
62
|
+
>Developer</a
|
|
63
|
+
>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Operators
|
|
67
|
+
|
|
68
|
+
| Operator | Meaning | Use for |
|
|
69
|
+
| -------- | ----------- | --------------------------- |
|
|
70
|
+
| `===` | Exact match | Current page highlighting |
|
|
71
|
+
| `^=` | Starts with | Section/parent highlighting |
|
|
72
|
+
|
|
73
|
+
Both work with field references (bare identifier) and quoted string literals (`'/docs'`).
|
|
@@ -144,6 +144,61 @@ src/pages/products/[slug]/page.jay-html
|
|
|
144
144
|
|
|
145
145
|
Multiple components on the same page can each declare params. The route directory must provide all required params across all components. For example, if the page contract requires `lang` and a headless component requires `slug`, the page should live at `src/pages/[lang]/products/[slug]/page.jay-html`.
|
|
146
146
|
|
|
147
|
+
### Passing Route Params to Nested Components
|
|
148
|
+
|
|
149
|
+
Route params flow automatically to keyed headless components that declare them as `params` in their contract. Instance-based headless components and headfull components do not receive route params directly — they receive props from the template.
|
|
150
|
+
|
|
151
|
+
#### Direct binding with `jay.params` (no page.ts needed)
|
|
152
|
+
|
|
153
|
+
Use `jay.params.X` to bind route params directly to nested component props:
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<!-- src/pages/docs/[role]/[slug]/page.jay-html -->
|
|
157
|
+
<jay:DocsSidebar activeRole="{jay.params.role}" activePage="{jay.params.slug}" />
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
No `page.ts`, no page contract needed for param passing. `jay.params` is available at all render phases. Use `jay.url.path` for the full URL pathname:
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<jay:Sidebar currentPath="{jay.url.path}" />
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
See [jay-html-template-syntax.md](jay-html-template-syntax.md) for the full list of `jay.` bindings and [navigation-patterns.md](navigation-patterns.md) for active menu patterns.
|
|
167
|
+
|
|
168
|
+
#### Passing via page.ts (when you need data transformation)
|
|
169
|
+
|
|
170
|
+
When route params need processing before reaching the component (e.g., fetching data, computing derived values), use the `page.ts` passthrough pattern:
|
|
171
|
+
|
|
172
|
+
**1. Page contract exposes the param as ViewState:**
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
# page.jay-contract
|
|
176
|
+
name: Page
|
|
177
|
+
params:
|
|
178
|
+
slug: string
|
|
179
|
+
tags:
|
|
180
|
+
- tag: activePage
|
|
181
|
+
type: data
|
|
182
|
+
dataType: string
|
|
183
|
+
phase: slow
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**2. `page.ts` passes the param into ViewState:**
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
.withSlowlyRender(async (props) =>
|
|
190
|
+
phaseOutput({ activePage: props.slug }, {})
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**3. Template binds ViewState to the nested component prop:**
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<jay:SideNav activePage="{activePage}" />
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The same pattern works with keyed headless data — if a keyed component already provides the value, bind directly: `<jay:SideNav activePage="{product.slug}" />`.
|
|
201
|
+
|
|
147
202
|
### Discovering Param Values
|
|
148
203
|
|
|
149
204
|
For SSG with dynamic routes, the plugin component provides a `loadParams` generator that yields all valid param combinations. Use it to discover what routes will be generated:
|
|
@@ -153,7 +208,7 @@ jay-stack params wix-stores/product-page
|
|
|
153
208
|
# Output: [{"slug": "blue-shirt"}, {"slug": "red-hat"}, ...]
|
|
154
209
|
```
|
|
155
210
|
|
|
156
|
-
Params are always strings (URL params).
|
|
211
|
+
Params are always strings (URL params). Routes are **case-sensitive** — a slug of `My-Page` produces the URL `/my-page` only if the param value is exactly `my-page`. Use lowercase for all param values and filenames that become URL segments.
|
|
157
212
|
|
|
158
213
|
## Query Parameters
|
|
159
214
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Understanding Validation Output
|
|
2
|
+
|
|
3
|
+
## How Validation Works
|
|
4
|
+
|
|
5
|
+
`jay-stack validate` runs static analysis on `.jay-html` files. It parses each template and checks it against rules from installed validator plugins (SEO, a11y, design-system).
|
|
6
|
+
|
|
7
|
+
**Key concept: static analysis sees the template, not the rendered page.** The validator checks what's written in the `.jay-html` file — it cannot see:
|
|
8
|
+
|
|
9
|
+
- Dynamic content from `{bindings}` (e.g., `{post.content}` may contain images and headings)
|
|
10
|
+
- Data fetched at render time from services
|
|
11
|
+
- Content generated by other tools or scripts
|
|
12
|
+
|
|
13
|
+
## What the Validator Sees
|
|
14
|
+
|
|
15
|
+
The validator processes each `.jay-html` file with:
|
|
16
|
+
|
|
17
|
+
- **Page template** — your HTML, bindings, and inline styles
|
|
18
|
+
- **Headfull component content** — `<jay:SiteHeader />`, `<jay:DocsSidebar />` etc. are expanded into the page before validation
|
|
19
|
+
- **Headless component tags** — `<jay:product-widget>` inline templates are visible
|
|
20
|
+
- **Linked CSS files** — `<link rel="stylesheet" href="...">` referenced from `<head>` are read and validated (e.g., for CSS `@import` of external URLs)
|
|
21
|
+
- **Inline `<style>` blocks** — CSS in `<head>` is parsed for rule violations
|
|
22
|
+
|
|
23
|
+
So a warning about an `<img>` might come from a headfull component's template, not your page template. A CSS warning might come from a linked stylesheet.
|
|
24
|
+
|
|
25
|
+
## How to Read Warnings
|
|
26
|
+
|
|
27
|
+
Each warning has:
|
|
28
|
+
|
|
29
|
+
- **Message** — what was found and why it matters
|
|
30
|
+
- **Suggestion** — how to fix it
|
|
31
|
+
- **Element** — which HTML element triggered it (some include the full tag with attributes)
|
|
32
|
+
|
|
33
|
+
### Acting on Warnings
|
|
34
|
+
|
|
35
|
+
1. **Check if the element is in your template** — search your `.jay-html` file for the element. If it's not there, it comes from a headfull component.
|
|
36
|
+
|
|
37
|
+
2. **For headfull component warnings** — fix them in the component's `.jay-html` file (e.g., `src/components/site-header/site-header.jay-html`), not in the page that imports it.
|
|
38
|
+
|
|
39
|
+
3. **For dynamic content warnings** — if the warning is about content inside a `{binding}` (like `{post.content}`), you can't fix it in the template. The content is generated at render time. These are usually false positives.
|
|
40
|
+
|
|
41
|
+
4. **Don't loop** — if a warning can't be fixed in any template file, it's a validator limitation. Move on.
|
|
42
|
+
|
|
43
|
+
## Common Scenarios
|
|
44
|
+
|
|
45
|
+
### "Image without loading attribute" from a component
|
|
46
|
+
|
|
47
|
+
The image is in a headfull component (e.g., sidebar icons). Fix it in the component's `.jay-html`, not the page.
|
|
48
|
+
|
|
49
|
+
### "Heading level skipped" with dynamic content
|
|
50
|
+
|
|
51
|
+
Your page has `<h1>` and a component has `<h3>`, but the dynamic content (markdown) provides `<h2>` at render time. If the heading hierarchy is correct in the rendered page, fix the component to use the right level — don't restructure the page.
|
|
52
|
+
|
|
53
|
+
### "No fetchpriority=high" on a text-only page
|
|
54
|
+
|
|
55
|
+
Your page has no large images in the template. Small icons (under 200px) don't need fetchpriority. This warning only fires for large images.
|
|
56
|
+
|
|
57
|
+
### Warnings on component files
|
|
58
|
+
|
|
59
|
+
Components are fragments — they don't need `<h1>`, `<main>`, `<title>`, or `<meta>`. These page-level rules are skipped for files in `src/components/`. If you still see them, check the file path.
|
|
60
|
+
|
|
61
|
+
## Suppressing Warnings
|
|
62
|
+
|
|
63
|
+
Each warning's suggestion tells you exactly what to add or change to suppress it. The general suppression mechanisms are:
|
|
64
|
+
|
|
65
|
+
### Add the missing attribute
|
|
66
|
+
|
|
67
|
+
Most warnings are suppressed by adding the attribute the rule checks for. The suggestion tells you which attribute and what values are accepted. For example, `loading="lazy"` or `loading="eager"` both suppress the image loading warning.
|
|
68
|
+
|
|
69
|
+
### Design system: inline comment
|
|
70
|
+
|
|
71
|
+
For design-system token warnings, add `/* design-system: allow */` as a comment on the same CSS line:
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
padding: 96px 0; /* design-system: allow */
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### When you can't suppress
|
|
78
|
+
|
|
79
|
+
If a warning comes from dynamic content (`{post.content}`) or a generated file, you can't suppress it in the template. This is a validator limitation — the warning is a false positive. Don't loop trying to fix it.
|
|
80
|
+
|
|
81
|
+
## Running Validation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
jay-stack validate # validate all pages
|
|
85
|
+
jay-stack validate --strict # treat warnings as errors
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Validation runs automatically during `jay-stack build`. Warnings don't block the build; errors do (with `--strict`).
|
|
@@ -153,7 +153,18 @@ jay-stack params wix-stores/product-page
|
|
|
153
153
|
# Output: [{"slug": "blue-shirt"}, {"slug": "red-hat"}, ...]
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
Params are always strings (URL params).
|
|
156
|
+
Params are always strings (URL params). Routes are **case-sensitive** — use lowercase for all param values and filenames that become URL segments.
|
|
157
|
+
|
|
158
|
+
### When page.ts is not needed for params
|
|
159
|
+
|
|
160
|
+
The designer can bind route params directly to nested component props using `jay.params` in the template — no `page.ts` or page contract needed:
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<jay:DocsSidebar activeRole="{jay.params.role}" activePage="{jay.params.slug}" />
|
|
164
|
+
<jay:Sidebar currentPath="{jay.url.path}" />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Only create a `page.ts` for params when you need to **transform** them (fetch data, compute derived values, combine with service calls). If the page just passes params through to components, `jay.params` is sufficient.
|
|
157
168
|
|
|
158
169
|
## Query Parameters
|
|
159
170
|
|
|
@@ -13,7 +13,7 @@ A plugin provides headless components (data + interactions, no UI) that project
|
|
|
13
13
|
3. **Define actions** with `.jay-action` metadata
|
|
14
14
|
4. **Optionally add routes** — pages for admin tools and dashboards
|
|
15
15
|
5. **Optionally add validators** — custom jay-html validation rules
|
|
16
|
-
6. **Optionally add setup/agentkit handlers** — config templating, add-menu generation
|
|
16
|
+
6. **Optionally add setup/agentkit handlers** — config templating, add-menu generation, AIditor Project settings tabs
|
|
17
17
|
7. **Set up `plugin.yaml`** — list contracts, actions, services, contexts, routes, validators, setup, agentkit
|
|
18
18
|
8. **Configure build** — dual entry points (server + client), vite.config.ts, package.json exports
|
|
19
19
|
9. **Validate** with `jay-stack validate-plugin`
|
|
@@ -26,7 +26,7 @@ The plugin participates in four CLI commands, each running different hooks:
|
|
|
26
26
|
| --------------------------- | ------------------ | ---------------------------------------------------------------------------------- |
|
|
27
27
|
| `jay-stack validate-plugin` | Plugin development | Checks plugin.yaml structure, contracts, exports, handler references |
|
|
28
28
|
| `jay-stack setup <plugin>` | Project setup | `setup` — creates config files, validates credentials |
|
|
29
|
-
| `jay-stack agent-kit` | Before development | `agentkit` — generates add-menu items, reference data, skills
|
|
29
|
+
| `jay-stack agent-kit` | Before development | `agentkit` — generates add-menu items, settings tabs, reference data, skills |
|
|
30
30
|
| `jay-stack validate` | During development | `validators[].handler` — runs your validation rules against project jay-html files |
|
|
31
31
|
|
|
32
32
|
**`validate-plugin`** validates YOUR plugin's structure. Run it during plugin development.
|
|
@@ -34,27 +34,29 @@ The plugin participates in four CLI commands, each running different hooks:
|
|
|
34
34
|
|
|
35
35
|
## Guides
|
|
36
36
|
|
|
37
|
-
| File
|
|
38
|
-
|
|
|
39
|
-
| [Contract Authoring Guide](../contracts/GUIDE.md)
|
|
40
|
-
| [contracts-guide.md](contracts-guide.md)
|
|
41
|
-
| [plugin-structure.md](plugin-structure.md)
|
|
42
|
-
| [component-structure.md](component-structure.md)
|
|
43
|
-
| [component-state.md](component-state.md)
|
|
44
|
-
| [component-refs.md](component-refs.md)
|
|
45
|
-
| [component-data.md](component-data.md)
|
|
46
|
-
| [component-context.md](component-context.md)
|
|
47
|
-
| [render-results.md](render-results.md)
|
|
48
|
-
| [actions-guide.md](actions-guide.md)
|
|
49
|
-
| [webhooks-guide.md](webhooks-guide.md)
|
|
50
|
-
| [services-guide.md](services-guide.md)
|
|
51
|
-
| [plugin-routes.md](plugin-routes.md)
|
|
52
|
-
| [seo-guide.md](seo-guide.md)
|
|
53
|
-
| [commands-guide.md](commands-guide.md)
|
|
54
|
-
| [validation.md](validation.md)
|
|
55
|
-
| [setup-guide.md](setup-guide.md)
|
|
56
|
-
| [
|
|
57
|
-
|
|
|
37
|
+
| File | Topic |
|
|
38
|
+
| ------------------------------------------------------ | ----------------------------------------------------------------------- |
|
|
39
|
+
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
40
|
+
| [contracts-guide.md](contracts-guide.md) | Plugin-specific contract concerns |
|
|
41
|
+
| [plugin-structure.md](plugin-structure.md) | plugin.yaml, package layout, exports |
|
|
42
|
+
| [component-structure.md](component-structure.md) | makeJayStackComponent, builder API, three-phase rendering |
|
|
43
|
+
| [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray, createEvent |
|
|
44
|
+
| [component-refs.md](component-refs.md) | Refs, collection refs, element types |
|
|
45
|
+
| [component-data.md](component-data.md) | Immutable data, JSON Patch, createPatchableSignal |
|
|
46
|
+
| [component-context.md](component-context.md) | Context hooks: provide, reactive, global |
|
|
47
|
+
| [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
|
|
48
|
+
| [actions-guide.md](actions-guide.md) | makeJayAction, makeJayQuery, .jay-action files |
|
|
49
|
+
| [webhooks-guide.md](webhooks-guide.md) | makeWebhook, data change invalidation, renderer server |
|
|
50
|
+
| [services-guide.md](services-guide.md) | createJayService, makeJayInit |
|
|
51
|
+
| [plugin-routes.md](plugin-routes.md) | Plugin-provided pages: routes, jay-html templates, page components |
|
|
52
|
+
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
53
|
+
| [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
|
|
54
|
+
| [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
|
|
55
|
+
| [setup-guide.md](setup-guide.md) | Setup handlers, agent-kit handlers, references generation |
|
|
56
|
+
| [add-menu-guide.md](add-menu-guide.md) | AIditor add-menu items: schema, interaction, browse, presentation |
|
|
57
|
+
| [aiditor-settings-guide.md](aiditor-settings-guide.md) | AIditor Project settings tabs: template, materialization, devOnly route |
|
|
58
|
+
| [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
|
|
59
|
+
| `../references/<plugin>/` | Plugin reference data |
|
|
58
60
|
|
|
59
61
|
## Key Principles
|
|
60
62
|
|