@jay-framework/jay-stack-cli 0.15.5 → 0.16.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/{INSTRUCTIONS.md → designer/INSTRUCTIONS.md} +11 -8
- package/agent-kit-template/{jay-html-syntax.md → designer/jay-html-components.md} +89 -158
- package/agent-kit-template/designer/jay-html-styling.md +97 -0
- package/agent-kit-template/designer/jay-html-syntax.md +44 -0
- package/agent-kit-template/designer/jay-html-template-syntax.md +203 -0
- package/agent-kit-template/developer/INSTRUCTIONS.md +34 -0
- package/agent-kit-template/developer/cli-commands.md +228 -0
- package/agent-kit-template/developer/component-data.md +109 -0
- package/agent-kit-template/developer/component-refs.md +117 -0
- package/agent-kit-template/developer/component-state.md +140 -0
- package/agent-kit-template/developer/configuration.md +76 -0
- package/agent-kit-template/developer/dev-server-service.md +126 -0
- package/agent-kit-template/developer/page-components.md +103 -0
- package/agent-kit-template/developer/page-contracts.md +114 -0
- package/agent-kit-template/developer/project-structure.md +242 -0
- package/agent-kit-template/developer/render-results.md +112 -0
- package/agent-kit-template/developer/routing.md +175 -0
- package/agent-kit-template/developer/seo-guide.md +93 -0
- package/agent-kit-template/plugin/INSTRUCTIONS.md +43 -0
- package/agent-kit-template/plugin/actions-guide.md +184 -0
- package/agent-kit-template/plugin/component-context.md +103 -0
- package/agent-kit-template/plugin/component-data.md +109 -0
- package/agent-kit-template/plugin/component-refs.md +117 -0
- package/agent-kit-template/plugin/component-state.md +140 -0
- package/agent-kit-template/plugin/component-structure.md +174 -0
- package/agent-kit-template/plugin/contracts-guide.md +193 -0
- package/agent-kit-template/plugin/dev-server-service.md +137 -0
- package/agent-kit-template/plugin/plugin-routes.md +146 -0
- package/agent-kit-template/plugin/plugin-structure.md +210 -0
- package/agent-kit-template/plugin/render-results.md +112 -0
- package/agent-kit-template/plugin/seo-guide.md +93 -0
- package/agent-kit-template/plugin/services-guide.md +116 -0
- package/agent-kit-template/plugin/validation.md +101 -0
- package/dist/index.js +791 -60
- package/package.json +10 -10
- /package/agent-kit-template/{cli-commands.md → designer/cli-commands.md} +0 -0
- /package/agent-kit-template/{contracts-and-plugins.md → designer/contracts-and-plugins.md} +0 -0
- /package/agent-kit-template/{project-structure.md → designer/project-structure.md} +0 -0
- /package/agent-kit-template/{routing.md → designer/routing.md} +0 -0
|
@@ -37,14 +37,17 @@ There is no standalone "interactive" phase. Any tag with `type: interactive` (re
|
|
|
37
37
|
|
|
38
38
|
## Reference Docs
|
|
39
39
|
|
|
40
|
-
| File
|
|
41
|
-
|
|
|
42
|
-
| [project-structure.md](project-structure.md)
|
|
43
|
-
| [jay-html-syntax.md](jay-html-syntax.md)
|
|
44
|
-
| [
|
|
45
|
-
| [
|
|
46
|
-
| [
|
|
47
|
-
|
|
|
40
|
+
| File | Topic |
|
|
41
|
+
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
42
|
+
| [project-structure.md](project-structure.md) | Project layout, styling patterns (CSS themes, design tokens), configuration files |
|
|
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 (boolean, enum, numeric, &&/\|\|), loops, refs |
|
|
45
|
+
| [jay-html-components.md](jay-html-components.md) | Component imports: headless (key/instance), headfull FS, nesting patterns |
|
|
46
|
+
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic style bindings, class bindings |
|
|
47
|
+
| [routing.md](routing.md) | Directory-based routing: page structure, dynamic routes, route priority |
|
|
48
|
+
| [contracts-and-plugins.md](contracts-and-plugins.md) | Reading contracts, plugin.yaml, .jay-action files, and the materialized indexes |
|
|
49
|
+
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, params, action, dev server |
|
|
50
|
+
| `../references/<plugin>/` | Pre-generated discovery data: product catalogs, collection schemas (from `jay-stack agent-kit`) |
|
|
48
51
|
|
|
49
52
|
## Quick Start
|
|
50
53
|
|
|
@@ -1,137 +1,9 @@
|
|
|
1
|
-
# Jay-HTML
|
|
2
|
-
|
|
3
|
-
## File Structure
|
|
4
|
-
|
|
5
|
-
A `.jay-html` file is standard HTML with jay-specific extensions.
|
|
6
|
-
|
|
7
|
-
```html
|
|
8
|
-
<html>
|
|
9
|
-
<head>
|
|
10
|
-
<!-- Page contract (optional — defines page-level data) -->
|
|
11
|
-
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
12
|
-
|
|
13
|
-
<!-- Explicit route params (for static override routes) -->
|
|
14
|
-
<script type="application/jay-params">
|
|
15
|
-
slug: ceramic-flower-vase
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<!-- Headless component imports -->
|
|
19
|
-
<script type="application/jay-headless" plugin="..." contract="..." key="..."></script>
|
|
20
|
-
|
|
21
|
-
<!-- Headfull component imports -->
|
|
22
|
-
<script type="application/jay-headfull" src="..." names="..." contract="..."></script>
|
|
23
|
-
|
|
24
|
-
<!-- Styles -->
|
|
25
|
-
<style>
|
|
26
|
-
/* inline CSS */
|
|
27
|
-
</style>
|
|
28
|
-
<link rel="stylesheet" href="../../styles/theme.css" />
|
|
29
|
-
</head>
|
|
30
|
-
<body>
|
|
31
|
-
<!-- Template with data bindings -->
|
|
32
|
-
<h1>{title}</h1>
|
|
33
|
-
</body>
|
|
34
|
-
</html>
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Data Binding
|
|
38
|
-
|
|
39
|
-
Use `{expression}` to bind contract data:
|
|
40
|
-
|
|
41
|
-
```html
|
|
42
|
-
<h1>{productName}</h1>
|
|
43
|
-
<!-- simple -->
|
|
44
|
-
<span>{product.price}</span>
|
|
45
|
-
<!-- nested via key -->
|
|
46
|
-
<div style="color: {textColor}">{msg}</div>
|
|
47
|
-
<!-- in attributes -->
|
|
48
|
-
<a href="/products/{slug}">{name}</a>
|
|
49
|
-
<!-- interpolated in attr values -->
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Conditional Rendering
|
|
53
|
-
|
|
54
|
-
Use the `if` attribute:
|
|
55
|
-
|
|
56
|
-
```html
|
|
57
|
-
<span if="inStock">In Stock</span>
|
|
58
|
-
<span if="!inStock">Out of Stock</span>
|
|
59
|
-
<div if="type===physical">Ships to your door</div>
|
|
60
|
-
<div if="type===virtual">Instant download</div>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Rules:
|
|
64
|
-
|
|
65
|
-
- Boolean: `if="tagName"` / `if="!tagName"`
|
|
66
|
-
- Enum variant: `if="tagName===value"` / `if="tagName!==value"` (no quotes around value)
|
|
67
|
-
- Negation: `!` prefix
|
|
68
|
-
|
|
69
|
-
## Loops (forEach / trackBy)
|
|
70
|
-
|
|
71
|
-
Iterate over repeated sub-contracts:
|
|
72
|
-
|
|
73
|
-
```html
|
|
74
|
-
<li forEach="products" trackBy="id">
|
|
75
|
-
<a href="/products/{slug}">
|
|
76
|
-
<div>{name}</div>
|
|
77
|
-
<div>{price}</div>
|
|
78
|
-
</a>
|
|
79
|
-
</li>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
- `forEach` — the repeated tag name from the contract
|
|
83
|
-
- `trackBy` — stable unique key for each item (must match contract's trackBy)
|
|
84
|
-
- Inside the loop, bindings resolve to the **current item's** tags
|
|
85
|
-
|
|
86
|
-
**Nested loops:**
|
|
87
|
-
|
|
88
|
-
```html
|
|
89
|
-
<div forEach="options" trackBy="_id">
|
|
90
|
-
<h3>{name}</h3>
|
|
91
|
-
<div forEach="choices" trackBy="choiceId">
|
|
92
|
-
<button ref="choiceButton">{name}</button>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Refs (Interactions)
|
|
98
|
-
|
|
99
|
-
Map elements to contract `interactive` tags using `ref`:
|
|
100
|
-
|
|
101
|
-
```html
|
|
102
|
-
<button ref="addToCart">Add to Cart</button>
|
|
103
|
-
<input value="{quantity}" ref="quantityInput" />
|
|
104
|
-
<a ref="productLink" href="/products/{slug}">{name}</a>
|
|
105
|
-
<select ref="sizeSelector">
|
|
106
|
-
...
|
|
107
|
-
</select>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Match the element type to the contract's `elementType`:
|
|
111
|
-
|
|
112
|
-
- `HTMLButtonElement` → `<button>`
|
|
113
|
-
- `HTMLInputElement` → `<input>`
|
|
114
|
-
- `HTMLAnchorElement` → `<a>`
|
|
115
|
-
- `HTMLSelectElement` → `<select>`
|
|
116
|
-
|
|
117
|
-
**Key-based headless refs** — prefix with the key:
|
|
118
|
-
|
|
119
|
-
```html
|
|
120
|
-
<button ref="rating.submitButton">Submit</button> <button ref="mt.happy">+1 Happy</button>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
**Refs inside forEach** — use the tag path from the contract:
|
|
124
|
-
|
|
125
|
-
```html
|
|
126
|
-
<div forEach="options" trackBy="_id">
|
|
127
|
-
<div forEach="choices" trackBy="choiceId">
|
|
128
|
-
<button ref="choiceButton">{name}</button>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
```
|
|
1
|
+
# Jay-HTML Component Imports
|
|
132
2
|
|
|
133
3
|
## Headless Components
|
|
134
4
|
|
|
5
|
+
Headless components provide data and interactions with no UI. The page or headfull component provides the template.
|
|
6
|
+
|
|
135
7
|
### Pattern 1: Key-Based Import
|
|
136
8
|
|
|
137
9
|
Data merged into parent ViewState under a key. Use when you have **one instance** of a component per page.
|
|
@@ -165,6 +37,8 @@ Access data and refs with the key prefix:
|
|
|
165
37
|
</div>
|
|
166
38
|
```
|
|
167
39
|
|
|
40
|
+
Key-based imports are only available in **pages** (not in headfull FS components).
|
|
41
|
+
|
|
168
42
|
### Pattern 2: Instance-Based (jay: prefix)
|
|
169
43
|
|
|
170
44
|
Multiple instances with props and inline templates. Use when you need **multiple instances** or need to pass **props**.
|
|
@@ -213,7 +87,9 @@ Inside `<jay:...>`, bindings resolve to **that instance's** contract tags (not t
|
|
|
213
87
|
|
|
214
88
|
## Headfull Full-Stack Components
|
|
215
89
|
|
|
216
|
-
Headfull components
|
|
90
|
+
Headfull components own their UI and can be made full-stack by adding a `contract` attribute.
|
|
91
|
+
|
|
92
|
+
### Import Declaration
|
|
217
93
|
|
|
218
94
|
```html
|
|
219
95
|
<head>
|
|
@@ -232,7 +108,9 @@ Headfull components that own their UI can be made full-stack by adding a `contra
|
|
|
232
108
|
- `names` — Component name to import
|
|
233
109
|
- `contract` — Path to the contract file (makes the component full-stack with SSR)
|
|
234
110
|
|
|
235
|
-
|
|
111
|
+
### Usage
|
|
112
|
+
|
|
113
|
+
Same as client-only headfull, with props:
|
|
236
114
|
|
|
237
115
|
```html
|
|
238
116
|
<jay:SharedHeader logoUrl="/logo.png" />
|
|
@@ -240,50 +118,96 @@ Headfull components that own their UI can be made full-stack by adding a `contra
|
|
|
240
118
|
|
|
241
119
|
Without `contract`, the component is client-only. With `contract`, it participates in slow/fast/interactive phases and is server-side rendered. Use headfull full-stack components for reusable UI with fixed layout that needs SSR (headers, footers, sidebars).
|
|
242
120
|
|
|
243
|
-
|
|
121
|
+
### Headfull FS Component Structure
|
|
244
122
|
|
|
245
|
-
A
|
|
123
|
+
A headfull FS component has its own `.jay-html` file with the same structure as a page:
|
|
246
124
|
|
|
247
125
|
```html
|
|
248
|
-
|
|
126
|
+
<!-- components/header/header.jay-html -->
|
|
127
|
+
<html>
|
|
128
|
+
<head>
|
|
129
|
+
<script type="application/jay-data">
|
|
130
|
+
data:
|
|
131
|
+
logoUrl: string
|
|
132
|
+
</script>
|
|
133
|
+
</head>
|
|
134
|
+
<body>
|
|
135
|
+
<header>
|
|
136
|
+
<img src="{logoUrl}" />
|
|
137
|
+
<nav>Navigation here</nav>
|
|
138
|
+
</header>
|
|
139
|
+
</body>
|
|
140
|
+
</html>
|
|
249
141
|
```
|
|
250
142
|
|
|
251
|
-
|
|
143
|
+
## Nesting Components
|
|
252
144
|
|
|
253
|
-
|
|
145
|
+
### Headfull Inside Headfull
|
|
254
146
|
|
|
255
|
-
|
|
147
|
+
A layout component imports a header component:
|
|
256
148
|
|
|
257
149
|
```html
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
150
|
+
<!-- layout/layout.jay-html -->
|
|
151
|
+
<html>
|
|
152
|
+
<head>
|
|
153
|
+
<script
|
|
154
|
+
type="application/jay-headfull"
|
|
155
|
+
src="../header/header"
|
|
156
|
+
contract="../header/header.jay-contract"
|
|
157
|
+
names="header"
|
|
158
|
+
></script>
|
|
159
|
+
<script type="application/jay-data">
|
|
160
|
+
data:
|
|
161
|
+
sidebarLabel: string
|
|
162
|
+
</script>
|
|
163
|
+
</head>
|
|
164
|
+
<body>
|
|
165
|
+
<div class="layout">
|
|
166
|
+
<jay:header logoUrl="/logo.png" />
|
|
167
|
+
<aside>{sidebarLabel}</aside>
|
|
168
|
+
</div>
|
|
169
|
+
</body>
|
|
170
|
+
</html>
|
|
270
171
|
```
|
|
271
172
|
|
|
272
|
-
|
|
173
|
+
### Headless Inside Headfull
|
|
174
|
+
|
|
175
|
+
A header component uses a headless plugin widget:
|
|
273
176
|
|
|
274
177
|
```html
|
|
275
|
-
|
|
178
|
+
<!-- header/header.jay-html -->
|
|
179
|
+
<html>
|
|
180
|
+
<head>
|
|
181
|
+
<script type="application/jay-headless" plugin="my-plugin" contract="cart-indicator"></script>
|
|
182
|
+
<script type="application/jay-data">
|
|
183
|
+
data:
|
|
184
|
+
logoUrl: string
|
|
185
|
+
</script>
|
|
186
|
+
</head>
|
|
187
|
+
<body>
|
|
188
|
+
<header>
|
|
189
|
+
<img src="{logoUrl}" />
|
|
190
|
+
<jay:cart-indicator>
|
|
191
|
+
<span class="count">{itemCount}</span>
|
|
192
|
+
</jay:cart-indicator>
|
|
193
|
+
</header>
|
|
194
|
+
</body>
|
|
195
|
+
</html>
|
|
276
196
|
```
|
|
277
197
|
|
|
278
|
-
|
|
198
|
+
Nesting depth is unlimited. Circular imports are detected as errors. Key-based headless imports (`key="..."`) are not allowed inside headfull FS components — use instance-based imports instead.
|
|
279
199
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
200
|
+
## Nesting Rules
|
|
201
|
+
|
|
202
|
+
| Parent component | Can import headfull FS? | Can import headless (instance)? | Can import keyed headless? |
|
|
203
|
+
| ---------------- | ----------------------- | ------------------------------- | -------------------------- |
|
|
204
|
+
| **Page** | Yes | Yes | Yes |
|
|
205
|
+
| **Headfull FS** | Yes (recursive) | Yes (in its own head) | No |
|
|
206
|
+
| **Headless** | No (no template) | No (no template) | No (no template) |
|
|
283
207
|
|
|
284
208
|
## Complete Example
|
|
285
209
|
|
|
286
|
-
A homepage with key-based
|
|
210
|
+
A homepage with key-based, instance-based, and headfull components:
|
|
287
211
|
|
|
288
212
|
```html
|
|
289
213
|
<html>
|
|
@@ -299,6 +223,12 @@ A homepage with key-based and instance-based headless components:
|
|
|
299
223
|
plugin="product-widget"
|
|
300
224
|
contract="product-widget"
|
|
301
225
|
></script>
|
|
226
|
+
<script
|
|
227
|
+
type="application/jay-headfull"
|
|
228
|
+
src="../components/shared-header"
|
|
229
|
+
names="SharedHeader"
|
|
230
|
+
contract="../components/shared-header/shared-header.jay-contract"
|
|
231
|
+
></script>
|
|
302
232
|
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
303
233
|
<style>
|
|
304
234
|
.section {
|
|
@@ -313,6 +243,7 @@ A homepage with key-based and instance-based headless components:
|
|
|
313
243
|
</style>
|
|
314
244
|
</head>
|
|
315
245
|
<body>
|
|
246
|
+
<jay:SharedHeader logoUrl="/logo.png" />
|
|
316
247
|
<h1>Homepage</h1>
|
|
317
248
|
|
|
318
249
|
<!-- Key-based: mood tracker -->
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Jay-HTML Styling
|
|
2
|
+
|
|
3
|
+
## Inline Styles
|
|
4
|
+
|
|
5
|
+
Add `<style>` blocks in `<head>`:
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<head>
|
|
9
|
+
<style>
|
|
10
|
+
.product-card {
|
|
11
|
+
border: 1px solid #ccc;
|
|
12
|
+
padding: 16px;
|
|
13
|
+
}
|
|
14
|
+
.price {
|
|
15
|
+
font-weight: bold;
|
|
16
|
+
color: #2d7d2d;
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## External Stylesheets
|
|
23
|
+
|
|
24
|
+
Link external CSS files:
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<link rel="stylesheet" href="../../styles/theme.css" />
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Dynamic Style Bindings
|
|
31
|
+
|
|
32
|
+
Use `{expression}` inside `style` attribute values:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<div style="color: {textColor}; width: {width}px">styled</div>
|
|
36
|
+
<div style="margin: 10px; color: {color}; padding: 20px">mixed static and dynamic</div>
|
|
37
|
+
<div style="background-color: {bgColor}; font-size: {fontSize}px">with units</div>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Class Binding
|
|
41
|
+
|
|
42
|
+
### Static Classes
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div class="button primary">Click me</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Dynamic Class Value
|
|
49
|
+
|
|
50
|
+
Bind a contract value as a class name:
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<div class="button {variant}">Click me</div>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Conditional Class
|
|
57
|
+
|
|
58
|
+
Add a class only when a condition is true:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<div class="{isActive ? active}">Tab</div>
|
|
62
|
+
<div class="{hasItems ? has-items}">Cart</div>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Ternary Class
|
|
66
|
+
|
|
67
|
+
Switch between two classes based on a condition:
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<div class="{isPrimary ? primary : secondary}">Button</div>
|
|
71
|
+
<div class="{isExpanded ? expanded : collapsed}">Panel</div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Combined Classes
|
|
75
|
+
|
|
76
|
+
Mix static, dynamic, and conditional classes:
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<div class="button {isPrimary ? primary : secondary}">Click me</div>
|
|
80
|
+
<a class="cart-indicator {hasItems ? has-items} {isLoading ? is-loading}">Cart</a>
|
|
81
|
+
<div class="first-class {bool1 ? main : second} {!bool1 ? third : forth}">mixed</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### With Enum Conditions
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<div class="{status === active ? highlighted}">Item</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Class Binding Rules
|
|
91
|
+
|
|
92
|
+
- Static classes are always present: `class="button"`
|
|
93
|
+
- `{value}` inserts the contract value as a class name
|
|
94
|
+
- `{condition ? class}` adds `class` when condition is truthy
|
|
95
|
+
- `{condition ? classA : classB}` switches between two classes
|
|
96
|
+
- `{!condition ? class}` uses negation
|
|
97
|
+
- Multiple bindings can be combined in one `class` attribute
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Jay-HTML — AI Designer Instructions
|
|
2
|
+
|
|
3
|
+
## Philosophy
|
|
4
|
+
|
|
5
|
+
Jay-HTML is standard HTML with data bindings. There is no custom component framework — just native HTML + CSS with `{expression}` bindings for dynamic content.
|
|
6
|
+
|
|
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
|
+
|
|
9
|
+
## Component Types
|
|
10
|
+
|
|
11
|
+
### Page
|
|
12
|
+
|
|
13
|
+
Entry point at `src/pages/`. Can import all component types.
|
|
14
|
+
|
|
15
|
+
### Headfull FS
|
|
16
|
+
|
|
17
|
+
Reusable component with its own template + contract + three-phase rendering (slow/fast/interactive). Lives alongside the page in a components directory. Can nest other headfull FS and instance headless in its own `<head>`. Cannot use keyed headless.
|
|
18
|
+
|
|
19
|
+
### Headless
|
|
20
|
+
|
|
21
|
+
Plugin-provided logic component. No template — the page or headfull component provides the UI via inline template (`<jay:xxx>`). Two import patterns:
|
|
22
|
+
|
|
23
|
+
- **Key-based** — one instance per page, data merged under a key prefix (`{key.tag}`)
|
|
24
|
+
- **Instance-based** — multiple instances with props, each gets its own inline template
|
|
25
|
+
|
|
26
|
+
## Nesting Rules
|
|
27
|
+
|
|
28
|
+
| Parent component | Can import headfull FS? | Can import headless (instance)? | Can import keyed headless? |
|
|
29
|
+
| ---------------- | ----------------------- | ------------------------------- | -------------------------- |
|
|
30
|
+
| **Page** | Yes | Yes | Yes |
|
|
31
|
+
| **Headfull FS** | Yes (recursive) | Yes (in its own head) | No |
|
|
32
|
+
| **Headless** | No (no template) | No (no template) | No (no template) |
|
|
33
|
+
|
|
34
|
+
## Validation
|
|
35
|
+
|
|
36
|
+
After creating or editing jay-html files, run `jay-stack validate` to check for errors. It catches issues like unknown refs, missing contracts, and invalid bindings. See [cli-commands.md](cli-commands.md) for details.
|
|
37
|
+
|
|
38
|
+
## Reference
|
|
39
|
+
|
|
40
|
+
| File | Topic |
|
|
41
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
42
|
+
| [jay-html-template-syntax.md](jay-html-template-syntax.md) | Template markup: file structure, data binding, conditions, loops, refs |
|
|
43
|
+
| [jay-html-components.md](jay-html-components.md) | Component imports: headless (key/instance), headfull FS, nesting |
|
|
44
|
+
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic styles, class bindings |
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Jay-HTML Template Syntax
|
|
2
|
+
|
|
3
|
+
## File Structure
|
|
4
|
+
|
|
5
|
+
A `.jay-html` file is standard HTML with jay-specific extensions.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<html>
|
|
9
|
+
<head>
|
|
10
|
+
<!-- Page contract (optional — defines page-level data) -->
|
|
11
|
+
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
12
|
+
|
|
13
|
+
<!-- Explicit route params (for static override routes) -->
|
|
14
|
+
<script type="application/jay-params">
|
|
15
|
+
slug: ceramic-flower-vase
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<!-- Headless component imports -->
|
|
19
|
+
<script type="application/jay-headless" plugin="..." contract="..." key="..."></script>
|
|
20
|
+
|
|
21
|
+
<!-- Headfull component imports -->
|
|
22
|
+
<script type="application/jay-headfull" src="..." names="..." contract="..."></script>
|
|
23
|
+
|
|
24
|
+
<!-- Styles -->
|
|
25
|
+
<style>
|
|
26
|
+
/* inline CSS */
|
|
27
|
+
</style>
|
|
28
|
+
<link rel="stylesheet" href="../../styles/theme.css" />
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<!-- Template with data bindings -->
|
|
32
|
+
<h1>{title}</h1>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Data Binding
|
|
38
|
+
|
|
39
|
+
Use `{expression}` to bind contract data:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<h1>{productName}</h1>
|
|
43
|
+
<!-- simple -->
|
|
44
|
+
<span>{product.price}</span>
|
|
45
|
+
<!-- nested via key -->
|
|
46
|
+
<div style="color: {textColor}">{msg}</div>
|
|
47
|
+
<!-- in attributes -->
|
|
48
|
+
<a href="/products/{slug}">{name}</a>
|
|
49
|
+
<!-- interpolated in attr values -->
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Boolean Attributes
|
|
53
|
+
|
|
54
|
+
HTML boolean attributes (`disabled`, `checked`, `hidden`, `readonly`) can be bound to contract data:
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<button disabled="isSubmitting">Submit</button>
|
|
58
|
+
<!-- disabled when isSubmitting is true -->
|
|
59
|
+
<button disabled="!inStock">Add to Cart</button>
|
|
60
|
+
<!-- disabled when inStock is false -->
|
|
61
|
+
<input type="checkbox" checked="isSelected" />
|
|
62
|
+
<!-- checked when isSelected is true -->
|
|
63
|
+
<div hidden="!isVisible">Content</div>
|
|
64
|
+
<!-- hidden when isVisible is false -->
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- Set the attribute value to a **boolean tag name** — the attribute is present when true, absent when false
|
|
68
|
+
- Use `!` prefix to negate: `disabled="!enabled"` means disabled when enabled is false
|
|
69
|
+
- Without a value (`disabled` alone), the attribute is always present (standard HTML behavior)
|
|
70
|
+
|
|
71
|
+
## Conditional Rendering
|
|
72
|
+
|
|
73
|
+
Use the `if` attribute to conditionally show elements.
|
|
74
|
+
|
|
75
|
+
### Boolean
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<span if="inStock">In Stock</span> <span if="!inStock">Out of Stock</span>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Enum Variant
|
|
82
|
+
|
|
83
|
+
No quotes around the value:
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<div if="type===physical">Ships to your door</div>
|
|
87
|
+
<div if="type!==physical">Not a physical product</div>
|
|
88
|
+
<div if="status===active">Active</div>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Numeric Comparisons
|
|
92
|
+
|
|
93
|
+
Compare against numbers or other fields:
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<span if="count > 0">You have {count} items</span>
|
|
97
|
+
<span if="count <= 0">No items</span>
|
|
98
|
+
<button if="currentPage <= 1" disabled>Previous</button>
|
|
99
|
+
<span if="price <= budget">Affordable</span>
|
|
100
|
+
<span if="available >= required">In stock</span>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Operators: `>`, `<`, `>=`, `<=`, `==`, `!=`
|
|
104
|
+
|
|
105
|
+
### Logical AND / OR
|
|
106
|
+
|
|
107
|
+
Combine conditions with `&&` and `||`:
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<div if="inStock && hasDiscount">Great deal!</div>
|
|
111
|
+
<span if="isPromoted || hasDiscount">Has offer</span>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use parentheses for complex expressions:
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<div if="(inStock && hasDiscount) || isPromoted">Buyable</div>
|
|
118
|
+
<div if="inStock && price > 0">Purchasable</div>
|
|
119
|
+
<button if="count <= 0 || isLoading" disabled>Checkout</button>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Rules Summary
|
|
123
|
+
|
|
124
|
+
- Boolean: `if="flag"` / `if="!flag"`
|
|
125
|
+
- Enum: `if="tag===value"` / `if="tag!==value"` (no quotes around value)
|
|
126
|
+
- Numeric: `if="count > 0"`, `if="price <= budget"`
|
|
127
|
+
- Field comparison: `if="available >= required"`
|
|
128
|
+
- Logical: `if="a && b"`, `if="a || b"`, `if="(a || b) && c"`
|
|
129
|
+
- Negation: `!` prefix on booleans
|
|
130
|
+
|
|
131
|
+
## Loops (forEach / trackBy)
|
|
132
|
+
|
|
133
|
+
Iterate over repeated sub-contracts:
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<li forEach="products" trackBy="id">
|
|
137
|
+
<a href="/products/{slug}">
|
|
138
|
+
<div>{name}</div>
|
|
139
|
+
<div>{price}</div>
|
|
140
|
+
</a>
|
|
141
|
+
</li>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `forEach` — the repeated tag name from the contract
|
|
145
|
+
- `trackBy` — stable unique key for each item (must match contract's trackBy)
|
|
146
|
+
- Inside the loop, bindings resolve to the **current item's** tags
|
|
147
|
+
|
|
148
|
+
**Nested loops:**
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<div forEach="options" trackBy="_id">
|
|
152
|
+
<h3>{name}</h3>
|
|
153
|
+
<div forEach="choices" trackBy="choiceId">
|
|
154
|
+
<button ref="choiceButton">{name}</button>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Refs (Interactions)
|
|
160
|
+
|
|
161
|
+
Map elements to contract `interactive` tags using `ref`:
|
|
162
|
+
|
|
163
|
+
```html
|
|
164
|
+
<button ref="addToCart">Add to Cart</button>
|
|
165
|
+
<input value="{quantity}" ref="quantityInput" />
|
|
166
|
+
<a ref="productLink" href="/products/{slug}">{name}</a>
|
|
167
|
+
<select ref="sizeSelector">
|
|
168
|
+
...
|
|
169
|
+
</select>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Match the element type to the contract's `elementType`:
|
|
173
|
+
|
|
174
|
+
- `HTMLButtonElement` → `<button>`
|
|
175
|
+
- `HTMLInputElement` → `<input>`
|
|
176
|
+
- `HTMLAnchorElement` → `<a>`
|
|
177
|
+
- `HTMLSelectElement` → `<select>`
|
|
178
|
+
|
|
179
|
+
**Key-based headless refs** — prefix with the key:
|
|
180
|
+
|
|
181
|
+
```html
|
|
182
|
+
<button ref="rating.submitButton">Submit</button> <button ref="mt.happy">+1 Happy</button>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Refs inside forEach** — use the tag path from the contract:
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<div forEach="options" trackBy="_id">
|
|
189
|
+
<div forEach="choices" trackBy="choiceId">
|
|
190
|
+
<button ref="choiceButton">{name}</button>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Page-Level Contract
|
|
196
|
+
|
|
197
|
+
A page can define its own data contract:
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Tags from the page contract are bound directly (no key prefix).
|