@jay-framework/jay-stack-cli 0.15.5 → 0.15.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/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/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 +161 -0
- package/agent-kit-template/developer/seo-guide.md +93 -0
- package/agent-kit-template/plugin/INSTRUCTIONS.md +40 -0
- package/agent-kit-template/plugin/actions-guide.md +125 -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/plugin-structure.md +194 -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 +678 -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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Jay Stack Developer — Agent Kit
|
|
2
|
+
|
|
3
|
+
This folder contains guides for building jay-stack projects: project configuration, routing, page components, and wiring plugins together.
|
|
4
|
+
|
|
5
|
+
## What Does the Developer Role Do?
|
|
6
|
+
|
|
7
|
+
The developer sets up the project, configures plugins, creates page-level components (`page.ts`), defines page contracts (`page.jay-contract`), and wires everything together. This is distinct from the designer role (creates jay-html UI) and the plugin role (creates reusable headless components).
|
|
8
|
+
|
|
9
|
+
## Workflow
|
|
10
|
+
|
|
11
|
+
1. **Set up the project** — `jay-stack setup` to configure plugins
|
|
12
|
+
2. **Define routes** — create page directories under `src/pages/`
|
|
13
|
+
3. **Create page contracts** — `page.jay-contract` for page-level data
|
|
14
|
+
4. **Create page components** — `page.ts` with `makeJayStackComponent`
|
|
15
|
+
5. **Configure services** — `src/init.ts` for project-level services
|
|
16
|
+
6. **Validate** — `jay-stack validate`
|
|
17
|
+
7. **Test** — `jay-stack dev --test-mode`
|
|
18
|
+
|
|
19
|
+
## Guides
|
|
20
|
+
|
|
21
|
+
| File | Topic |
|
|
22
|
+
| -------------------------------------------- | ---------------------------------------------------------- |
|
|
23
|
+
| [project-structure.md](project-structure.md) | Directory layout, configuration files |
|
|
24
|
+
| [routing.md](routing.md) | Directory-based routing, dynamic routes |
|
|
25
|
+
| [configuration.md](configuration.md) | .jay file, plugin config, init.ts |
|
|
26
|
+
| [page-contracts.md](page-contracts.md) | Page-level contracts (page.jay-contract) |
|
|
27
|
+
| [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
|
|
28
|
+
| [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
|
|
29
|
+
| [component-refs.md](component-refs.md) | Refs, collection refs, element types |
|
|
30
|
+
| [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
|
|
31
|
+
| [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
|
|
32
|
+
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
33
|
+
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
|
|
34
|
+
| `../references/<plugin>/` | Plugin reference data |
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# CLI Commands Reference
|
|
2
|
+
|
|
3
|
+
## jay-stack setup
|
|
4
|
+
|
|
5
|
+
Run plugin setup. Plugins can create configuration files, generate reference data, and validate their prerequisites.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run setup for all installed plugins
|
|
9
|
+
jay-stack setup
|
|
10
|
+
|
|
11
|
+
# Run setup for a specific plugin
|
|
12
|
+
jay-stack setup wix-stores
|
|
13
|
+
|
|
14
|
+
# Re-run setup (e.g., after config change)
|
|
15
|
+
jay-stack setup wix-data --force
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Plugins declare their setup handler in `plugin.yaml`. Setup does two things:
|
|
19
|
+
|
|
20
|
+
1. **Config templates**: Creates `config/<plugin>.yaml` with placeholder credentials if missing
|
|
21
|
+
2. **Credential validation**: Attempts to initialize services, reports success or failure
|
|
22
|
+
|
|
23
|
+
Reference data (product catalogs, collection schemas) is generated by `jay-stack agent-kit`, not by setup.
|
|
24
|
+
|
|
25
|
+
Run this after installing new plugins, before `jay-stack agent-kit`.
|
|
26
|
+
|
|
27
|
+
## jay-stack agent-kit
|
|
28
|
+
|
|
29
|
+
Materialize contracts, generate discovery indexes, and produce plugin reference data. Run this after setup.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Default: writes to agent-kit/
|
|
33
|
+
jay-stack agent-kit
|
|
34
|
+
|
|
35
|
+
# Custom output directory for contracts
|
|
36
|
+
jay-stack agent-kit --output my-output/
|
|
37
|
+
|
|
38
|
+
# List contracts without writing files
|
|
39
|
+
jay-stack agent-kit --list
|
|
40
|
+
|
|
41
|
+
# Filter to specific plugin
|
|
42
|
+
jay-stack agent-kit --plugin wix-stores
|
|
43
|
+
|
|
44
|
+
# Force re-materialization
|
|
45
|
+
jay-stack agent-kit --force
|
|
46
|
+
|
|
47
|
+
# Skip reference data generation
|
|
48
|
+
jay-stack agent-kit --no-references
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Outputs:
|
|
52
|
+
|
|
53
|
+
- `plugins-index.yaml`
|
|
54
|
+
- `materialized-contracts/<plugin>/*.jay-contract` (dynamic contracts)
|
|
55
|
+
- `references/<plugin>/` — plugin reference data (product catalogs, collection schemas, etc.)
|
|
56
|
+
- Documentation files (INSTRUCTIONS.md and reference docs)
|
|
57
|
+
|
|
58
|
+
## jay-stack validate
|
|
59
|
+
|
|
60
|
+
Validate all `.jay-html` and `.jay-contract` files.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Validate entire project
|
|
64
|
+
jay-stack validate
|
|
65
|
+
|
|
66
|
+
# Validate a specific path
|
|
67
|
+
jay-stack validate src/pages/products/
|
|
68
|
+
|
|
69
|
+
# Verbose (per-file status)
|
|
70
|
+
jay-stack validate -v
|
|
71
|
+
|
|
72
|
+
# JSON output
|
|
73
|
+
jay-stack validate --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Example output:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
✅ Jay Stack validation successful!
|
|
80
|
+
Scanned 5 .jay-html files, 3 .jay-contract files
|
|
81
|
+
No errors found.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
On failure:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
❌ Jay Stack validation failed
|
|
88
|
+
|
|
89
|
+
Errors:
|
|
90
|
+
❌ src/pages/products/page.jay-html
|
|
91
|
+
Unknown ref "nonExistentRef" - not found in contract
|
|
92
|
+
|
|
93
|
+
1 error(s) found, 7 file(s) valid.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Always run validate after creating or editing jay-html and contract files.
|
|
97
|
+
|
|
98
|
+
## jay-stack params
|
|
99
|
+
|
|
100
|
+
Discover load param values for SSG route generation.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Discover slug values for product pages
|
|
104
|
+
jay-stack params wix-stores/product-page
|
|
105
|
+
|
|
106
|
+
# YAML output
|
|
107
|
+
jay-stack params wix-stores/product-page --yaml
|
|
108
|
+
|
|
109
|
+
# Verbose
|
|
110
|
+
jay-stack params wix-stores/product-page -v
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Format: `<plugin-name>/<contract-name>`
|
|
114
|
+
|
|
115
|
+
Example output:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
[
|
|
119
|
+
{ "slug": "ceramic-flower-vase" },
|
|
120
|
+
{ "slug": "blue-running-shoes" },
|
|
121
|
+
{ "slug": "organic-cotton-tshirt" }
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
✅ Found 3 param combination(s)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Use this to discover what param values exist for dynamic routes like `[slug]`. Only works on contracts whose component has `loadParams`.
|
|
128
|
+
|
|
129
|
+
## jay-stack action
|
|
130
|
+
|
|
131
|
+
Run a plugin action from the CLI. Use to discover data for populating pages.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Run with default input
|
|
135
|
+
jay-stack action wix-stores/searchProducts
|
|
136
|
+
|
|
137
|
+
# Run with input
|
|
138
|
+
jay-stack action wix-stores/searchProducts --input '{"query": "shoes", "limit": 5}'
|
|
139
|
+
|
|
140
|
+
# YAML output
|
|
141
|
+
jay-stack action wix-stores/getCategories --yaml
|
|
142
|
+
|
|
143
|
+
# Verbose
|
|
144
|
+
jay-stack action wix-stores/getProductBySlug --input '{"slug": "blue-shirt"}' -v
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Format: `<plugin-name>/<action-name>`
|
|
148
|
+
|
|
149
|
+
Action names are listed in `plugins-index.yaml` under each plugin's `actions:` array. Each action entry includes a `description` and a `path` to the `.jay-action` file. Read the `.jay-action` file to see the full input/output schemas before calling an action.
|
|
150
|
+
|
|
151
|
+
Example output:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"items": [
|
|
156
|
+
{ "_id": "prod-1", "name": "Blue Shirt", "slug": "blue-shirt", "price": 29.99 },
|
|
157
|
+
{ "_id": "prod-2", "name": "Red Hat", "slug": "red-hat", "price": 19.99 }
|
|
158
|
+
],
|
|
159
|
+
"totalCount": 2
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
If not found, lists available actions:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
❌ Action "badName" not found.
|
|
167
|
+
Available actions: searchProducts, getProductBySlug, getCategories
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## jay-stack dev
|
|
171
|
+
|
|
172
|
+
Start the development server.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Normal dev mode
|
|
176
|
+
jay-stack dev
|
|
177
|
+
|
|
178
|
+
# Test mode (enables health/shutdown endpoints)
|
|
179
|
+
jay-stack dev --test-mode
|
|
180
|
+
|
|
181
|
+
# Auto-timeout (implies test mode)
|
|
182
|
+
jay-stack dev --timeout 60
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Test mode endpoints
|
|
186
|
+
|
|
187
|
+
| Endpoint | Method | Response |
|
|
188
|
+
| ---------------- | ------ | --------------------------------------------------------------- |
|
|
189
|
+
| `/_jay/health` | GET | `{"status":"ready","port":3300,"editorPort":3301,"uptime":5.2}` |
|
|
190
|
+
| `/_jay/shutdown` | POST | `{"status":"shutting_down"}` |
|
|
191
|
+
|
|
192
|
+
### Wait for server ready
|
|
193
|
+
|
|
194
|
+
Poll the health endpoint:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Bash
|
|
198
|
+
for i in {1..30}; do
|
|
199
|
+
curl -s http://localhost:3300/_jay/health | grep -q "ready" && break
|
|
200
|
+
sleep 1
|
|
201
|
+
done
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// TypeScript
|
|
206
|
+
async function waitForServer(timeout = 30000): Promise<string> {
|
|
207
|
+
const start = Date.now();
|
|
208
|
+
while (Date.now() - start < timeout) {
|
|
209
|
+
try {
|
|
210
|
+
const res = await fetch('http://localhost:3300/_jay/health');
|
|
211
|
+
if (res.ok) {
|
|
212
|
+
const { port } = await res.json();
|
|
213
|
+
return `http://localhost:${port}`;
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
/* not ready */
|
|
217
|
+
}
|
|
218
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
219
|
+
}
|
|
220
|
+
throw new Error('Server not ready');
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Shutdown
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
curl -X POST http://localhost:3300/_jay/shutdown
|
|
228
|
+
```
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Immutable Data and Patching
|
|
2
|
+
|
|
3
|
+
In Jay, ViewState data is immutable. Never mutate objects directly — use signals and JSON Patch for updates.
|
|
4
|
+
|
|
5
|
+
## Immutable Data Model
|
|
6
|
+
|
|
7
|
+
ViewState objects passed to the render function are immutable snapshots. The framework compares old and new snapshots to determine what changed in the DOM.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// WRONG — never mutate directly
|
|
11
|
+
viewState.items.push(newItem);
|
|
12
|
+
viewState.count = 5;
|
|
13
|
+
|
|
14
|
+
// RIGHT — return new values from signals
|
|
15
|
+
const [count, setCount] = createSignal(0);
|
|
16
|
+
setCount(5);
|
|
17
|
+
|
|
18
|
+
return { render: () => ({ count: count() }) };
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## JSON Patch for Complex Updates
|
|
22
|
+
|
|
23
|
+
For objects with many fields, use `createPatchableSignal` with JSON Patch operations instead of replacing the entire object:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createPatchableSignal } from '@jay-framework/component';
|
|
27
|
+
import { REPLACE, ADD, REMOVE } from '@jay-framework/json-patch';
|
|
28
|
+
|
|
29
|
+
const [state, setState, patchState] = createPatchableSignal({
|
|
30
|
+
title: 'Product',
|
|
31
|
+
price: 29.99,
|
|
32
|
+
tags: ['sale', 'featured'],
|
|
33
|
+
details: { color: 'red', size: 'M' },
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Patch Operations
|
|
38
|
+
|
|
39
|
+
**REPLACE** — Update an existing value:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
patchState({ op: REPLACE, path: ['price'], value: 19.99 });
|
|
43
|
+
patchState({ op: REPLACE, path: ['details', 'color'], value: 'blue' });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**ADD** — Add a new field or array item:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
patchState({ op: ADD, path: ['tags', 1], value: 'new-tag' }); // Insert at index 1
|
|
50
|
+
patchState({ op: ADD, path: ['details', 'weight'], value: '500g' });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**REMOVE** — Remove a field or array item:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
patchState({ op: REMOVE, path: ['tags', 0] }); // Remove first tag
|
|
57
|
+
patchState({ op: REMOVE, path: ['details', 'size'] });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**MOVE** — Move a value from one path to another:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { MOVE } from '@jay-framework/json-patch';
|
|
64
|
+
|
|
65
|
+
patchState({ op: MOVE, from: ['tags', 0], path: ['tags', 2] }); // Reorder array item
|
|
66
|
+
patchState({ op: MOVE, from: ['details', 'color'], path: ['primaryColor'] }); // Relocate field
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Multiple Patches
|
|
70
|
+
|
|
71
|
+
Apply multiple patches at once — the framework batches them into a single update:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
patchState(
|
|
75
|
+
{ op: REPLACE, path: ['price'], value: 19.99 },
|
|
76
|
+
{ op: REPLACE, path: ['details', 'color'], value: 'blue' },
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### When to Use Patch vs Set
|
|
81
|
+
|
|
82
|
+
- **Simple values** (number, string, boolean): use `setSignal(newValue)`
|
|
83
|
+
- **Objects with few fields**: use `setSignal({ ...old, field: newValue })`
|
|
84
|
+
- **Complex nested objects**: use `patchState` for surgical updates
|
|
85
|
+
- **Arrays with identity tracking**: use `patchState` with ADD/REMOVE
|
|
86
|
+
|
|
87
|
+
## createDerivedArray (Map Hook)
|
|
88
|
+
|
|
89
|
+
Transform an array reactively with smart caching. Only remaps items that actually changed:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { createDerivedArray } from '@jay-framework/component';
|
|
93
|
+
|
|
94
|
+
const displayProducts = createDerivedArray(
|
|
95
|
+
() => products(),
|
|
96
|
+
(item, index, length) => ({
|
|
97
|
+
label: `${item().name} - ${formatPrice(item().price)}`,
|
|
98
|
+
position: `${index() + 1} of ${length()}`,
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Key behavior:
|
|
104
|
+
|
|
105
|
+
- If an item's object identity hasn't changed, the cached mapped result is reused
|
|
106
|
+
- `index()` and `length()` are tracked — if you don't call them, changes to index/length won't trigger a remap
|
|
107
|
+
- Returns a `Getter<U[]>` — read with `displayProducts()`
|
|
108
|
+
|
|
109
|
+
See [component-state.md](component-state.md) for the full hook reference.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Component Refs
|
|
2
|
+
|
|
3
|
+
Refs provide access to DOM elements declared as `interactive` in the contract. They are the second parameter of the interactive constructor.
|
|
4
|
+
|
|
5
|
+
## Single Refs
|
|
6
|
+
|
|
7
|
+
A ref maps to one DOM element:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
# Contract
|
|
11
|
+
- tag: addToCart
|
|
12
|
+
type: interactive
|
|
13
|
+
elementType: HTMLButtonElement
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Component
|
|
18
|
+
.withInteractive(function MyComp(props, refs) {
|
|
19
|
+
refs.addToCart.onClick(() => {
|
|
20
|
+
// handle click
|
|
21
|
+
});
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Ref Methods
|
|
26
|
+
|
|
27
|
+
Refs provide type-safe access to the DOM element:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
refs.submitButton.onClick(() => {
|
|
31
|
+
/* ... */
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// exec$ gives direct access to the element and current ViewState
|
|
35
|
+
refs.submitButton.exec$((element, viewState) => {
|
|
36
|
+
element.disabled = viewState.isSubmitting;
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Collection Refs
|
|
41
|
+
|
|
42
|
+
When an interactive tag is inside a `repeated` sub-contract, the ref becomes a collection. In jay-html, collection refs use the `$` suffix:
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div forEach="items" trackBy="id">
|
|
46
|
+
<button ref="itemButton$">Click</button>
|
|
47
|
+
</div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `$` is stripped from the name in the contract and component code:
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
# Contract
|
|
54
|
+
- tag: items
|
|
55
|
+
type: sub-contract
|
|
56
|
+
repeated: true
|
|
57
|
+
trackBy: id
|
|
58
|
+
tags:
|
|
59
|
+
- tag: id
|
|
60
|
+
type: data
|
|
61
|
+
dataType: string
|
|
62
|
+
- tag: itemButton
|
|
63
|
+
type: interactive
|
|
64
|
+
elementType: HTMLButtonElement
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Collection Ref Methods
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Map over all items in the collection
|
|
71
|
+
const labels = refs.itemButton.map((proxy, viewState, coordinate) => {
|
|
72
|
+
return viewState.name;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Find a specific item
|
|
76
|
+
const target = refs.itemButton.find((viewState) => viewState.id === 'target-id');
|
|
77
|
+
|
|
78
|
+
// Find by coordinate
|
|
79
|
+
const target = refs.itemButton.find((viewState, coordinate) =>
|
|
80
|
+
sameCoordinate(coordinate, ['item-2', 'itemButton']),
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Element Types
|
|
85
|
+
|
|
86
|
+
Common element types for interactive tags:
|
|
87
|
+
|
|
88
|
+
| Element Type | Use For |
|
|
89
|
+
| --------------------- | --------------------- |
|
|
90
|
+
| `HTMLButtonElement` | Buttons, clickable |
|
|
91
|
+
| `HTMLAnchorElement` | Links |
|
|
92
|
+
| `HTMLInputElement` | Text inputs, checkbox |
|
|
93
|
+
| `HTMLSelectElement` | Dropdowns |
|
|
94
|
+
| `HTMLTextAreaElement` | Multi-line text |
|
|
95
|
+
| `HTMLFormElement` | Forms |
|
|
96
|
+
| `HTMLDivElement` | Generic containers |
|
|
97
|
+
|
|
98
|
+
Multiple element types (when the same ref may bind to different elements):
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
- tag: trigger
|
|
102
|
+
type: interactive
|
|
103
|
+
elementType: HTMLButtonElement | HTMLAnchorElement
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Data + Interactive
|
|
107
|
+
|
|
108
|
+
A tag can be both data and interactive:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
- tag: quantityInput
|
|
112
|
+
type: [data, interactive]
|
|
113
|
+
dataType: number
|
|
114
|
+
elementType: HTMLInputElement
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This generates both a ViewState field and a ref.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Component State Hooks
|
|
2
|
+
|
|
3
|
+
All hooks are used inside the interactive phase (the `withInteractive` constructor function). They provide reactive state management for client-side behavior.
|
|
4
|
+
|
|
5
|
+
## createSignal
|
|
6
|
+
|
|
7
|
+
Creates a reactive getter/setter pair:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { createSignal } from '@jay-framework/component';
|
|
11
|
+
|
|
12
|
+
const [count, setCount] = createSignal(0);
|
|
13
|
+
|
|
14
|
+
// Read
|
|
15
|
+
count(); // 0
|
|
16
|
+
|
|
17
|
+
// Write
|
|
18
|
+
setCount(5); // set to 5
|
|
19
|
+
setCount((n) => n + 1); // increment
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Can initialize from a getter (reactive dependency):
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const [label, setLabel] = createSignal(() => 'Hello ' + props.name());
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## createPatchableSignal
|
|
29
|
+
|
|
30
|
+
Creates a signal with JSON Patch support for fine-grained updates to complex objects:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { createPatchableSignal } from '@jay-framework/component';
|
|
34
|
+
import { REPLACE } from '@jay-framework/json-patch';
|
|
35
|
+
|
|
36
|
+
const [data, setData, patchData] = createPatchableSignal({
|
|
37
|
+
label: 'Hello',
|
|
38
|
+
count: 0,
|
|
39
|
+
nested: { value: 42 },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Patch a specific field
|
|
43
|
+
patchData({ op: REPLACE, path: ['label'], value: 'Updated' });
|
|
44
|
+
|
|
45
|
+
// Patch nested field
|
|
46
|
+
patchData({ op: REPLACE, path: ['nested', 'value'], value: 99 });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
See [component-data.md](component-data.md) for more on immutable data and patching.
|
|
50
|
+
|
|
51
|
+
## createMemo
|
|
52
|
+
|
|
53
|
+
Creates a memoized computed value that recalculates only when dependencies change:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { createMemo } from '@jay-framework/component';
|
|
57
|
+
|
|
58
|
+
const fullName = createMemo(() => `${firstName()} ${lastName()}`);
|
|
59
|
+
|
|
60
|
+
// Read
|
|
61
|
+
fullName(); // recomputes only when firstName() or lastName() change
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
With initial value:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const total = createMemo((prev) => prev + latestValue(), 0);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## createEffect
|
|
71
|
+
|
|
72
|
+
Registers a side effect that runs on mount and when dependencies change. Optional cleanup function:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { createEffect } from '@jay-framework/component';
|
|
76
|
+
|
|
77
|
+
createEffect(() => {
|
|
78
|
+
const handler = () => setWindowWidth(window.innerWidth);
|
|
79
|
+
window.addEventListener('resize', handler);
|
|
80
|
+
return () => window.removeEventListener('resize', handler); // cleanup
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Effects track reactive dependencies automatically:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
createEffect(() => {
|
|
88
|
+
document.title = `${count()} items`; // reruns when count() changes
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## createDerivedArray
|
|
93
|
+
|
|
94
|
+
Efficiently maps an array with smart caching. Only remaps items that actually changed:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { createDerivedArray } from '@jay-framework/component';
|
|
98
|
+
|
|
99
|
+
const displayItems = createDerivedArray(
|
|
100
|
+
() => products(),
|
|
101
|
+
(item, index, length) => ({
|
|
102
|
+
name: item().name,
|
|
103
|
+
displayPrice: formatPrice(item().price),
|
|
104
|
+
isLast: index() === length() - 1,
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Read the mapped array
|
|
109
|
+
displayItems();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Key optimizations:
|
|
113
|
+
|
|
114
|
+
- Reuses mapped items when the source item hasn't changed
|
|
115
|
+
- Only tracks `index()` and `length()` if you actually call them
|
|
116
|
+
- Uses object identity (not deep equality) for cache hits
|
|
117
|
+
|
|
118
|
+
## createEvent
|
|
119
|
+
|
|
120
|
+
Creates an event emitter for component-to-parent communication:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { createEvent } from '@jay-framework/component';
|
|
124
|
+
|
|
125
|
+
const onChange = createEvent<{ value: number }>((emitter) => {
|
|
126
|
+
emitter.emit({ value: count() });
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## useReactive
|
|
131
|
+
|
|
132
|
+
Gets the current reactive context for advanced use cases:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { useReactive } from '@jay-framework/component';
|
|
136
|
+
|
|
137
|
+
const reactive = useReactive();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Most components won't need this — prefer the higher-level hooks above.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
## .jay File
|
|
4
|
+
|
|
5
|
+
Optional YAML file at project root configuring the dev server:
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
devServer:
|
|
9
|
+
portRange:
|
|
10
|
+
- 3000
|
|
11
|
+
- 3100
|
|
12
|
+
pagesBase: ./src/pages
|
|
13
|
+
componentsBase: ./src/components
|
|
14
|
+
publicFolder: ./public
|
|
15
|
+
editorServer:
|
|
16
|
+
portRange:
|
|
17
|
+
- 3101
|
|
18
|
+
- 3200
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Key Fields
|
|
22
|
+
|
|
23
|
+
- `devServer.pagesBase` — Root directory for pages (default: `./src/pages`)
|
|
24
|
+
- `devServer.componentsBase` — Root directory for components
|
|
25
|
+
- `devServer.publicFolder` — Static assets directory
|
|
26
|
+
- `devServer.portRange` — Port range for the dev server
|
|
27
|
+
|
|
28
|
+
## Plugin Configuration (config/)
|
|
29
|
+
|
|
30
|
+
The `config/` folder holds plugin configuration files generated by `jay-stack setup`:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
config/
|
|
34
|
+
├── project.conf.yaml # Project name and metadata
|
|
35
|
+
└── wix-data.yaml # Plugin-specific config (auto-generated)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Plugins create their config files here during setup. The location is configured via `configBase` in the `.jay` file (defaults to `./config`).
|
|
39
|
+
|
|
40
|
+
## Project Init (src/init.ts)
|
|
41
|
+
|
|
42
|
+
The project can have an `init.ts` for project-level initialization:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { makeJayInit, registerService } from '@jay-framework/fullstack-component';
|
|
46
|
+
|
|
47
|
+
export const init = makeJayInit()
|
|
48
|
+
.withServer(async () => {
|
|
49
|
+
// Register project-level services
|
|
50
|
+
registerService(MY_SERVICE, createMyService());
|
|
51
|
+
|
|
52
|
+
// Return data for client
|
|
53
|
+
return { locale: 'en-US' };
|
|
54
|
+
})
|
|
55
|
+
.withClient((data) => {
|
|
56
|
+
// Client-side init
|
|
57
|
+
console.log('Locale:', data.locale);
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Init runs after all plugin inits, in dependency order.
|
|
62
|
+
|
|
63
|
+
## package.json Scripts
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"scripts": {
|
|
68
|
+
"dev": "jay-stack-cli dev",
|
|
69
|
+
"validate": "jay-stack-cli validate",
|
|
70
|
+
"definitions": "jay-cli definitions src",
|
|
71
|
+
"build": "npm run definitions",
|
|
72
|
+
"setup": "jay-stack-cli setup",
|
|
73
|
+
"agent-kit": "jay-stack-cli agent-kit"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|