@jay-framework/jay-stack-cli 0.24.5 → 0.24.7
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 +24 -1
- package/agent-kit-template/contracts/GUIDE.md +1 -1
- package/agent-kit-template/contracts/component-contracts.md +42 -12
- package/agent-kit-template/designer/INSTRUCTIONS.md +23 -20
- package/agent-kit-template/designer/cli-commands.md +46 -0
- package/agent-kit-template/designer/contracts-and-plugins.md +30 -1
- package/agent-kit-template/designer/design-system-guide.md +535 -0
- package/agent-kit-template/designer/jay-html-components.md +101 -31
- package/agent-kit-template/designer/jay-html-styling.md +69 -0
- package/agent-kit-template/designer/jay-html-syntax.md +22 -13
- package/agent-kit-template/designer/jay-html-template-syntax.md +3 -3
- package/agent-kit-template/designer/project-structure.md +1 -1
- package/agent-kit-template/designer/routing.md +2 -2
- package/agent-kit-template/designer/validation-guide.md +31 -5
- package/agent-kit-template/developer/INSTRUCTIONS.md +24 -19
- package/agent-kit-template/developer/page-components.md +23 -2
- package/agent-kit-template/developer/project-structure.md +1 -1
- package/agent-kit-template/developer/routing.md +1 -1
- package/agent-kit-template/devops/production-build.md +1 -1
- package/agent-kit-template/plugin/INSTRUCTIONS.md +3 -1
- package/agent-kit-template/plugin/component-structure.md +1 -1
- package/agent-kit-template/plugin/contracts-guide.md +18 -0
- package/agent-kit-template/plugin/design-system-guide.md +173 -0
- package/dist/{index-B9vCxAZ1.js → index-l6QVpvnY.js} +19 -14
- package/dist/index.js +1903 -199
- package/package.json +13 -12
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Headless Components
|
|
4
4
|
|
|
5
|
-
Headless components provide data and interactions with no UI. The page or
|
|
5
|
+
`Headless components provide data and interactions with no UI of their own. The page (or a consuming component) provides the template. **Every component a Jay Stack page composes is headless** — imported with `application/jay-headless`.
|
|
6
|
+
|
|
7
|
+
The page can supply that template two ways: **write the `<jay:X>` body by hand**, or **flatten one the component ships** — a _design-system element_. **Prefer flattening a shipped template** when the component provides one: a component can offer one or more `.jay-html` templates, so add `template=` to the import and run `jay-stack sync` to copy a chosen one into your page, then edit the copy. You get UI that stays consistent across pages and upgrades in one step, with `jay-stack validate` tracking drift from the source and `jay-stack sync` re-flattening it. Hand-author the `<jay:X>` body only when no template is shipped. See [design-system-guide.md](design-system-guide.md) for the full model.
|
|
6
8
|
|
|
7
9
|
### Pattern 1: Key-Based Import
|
|
8
10
|
|
|
@@ -37,7 +39,7 @@ Access data and refs with the key prefix:
|
|
|
37
39
|
</div>
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
Key-based imports are only available in **pages** (not in
|
|
42
|
+
Key-based imports are only available in **pages** (not in shared full-stack components).
|
|
41
43
|
|
|
42
44
|
**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
45
|
|
|
@@ -139,44 +141,60 @@ props:
|
|
|
139
141
|
phase: fast # Only needs to be available at request time
|
|
140
142
|
```
|
|
141
143
|
|
|
142
|
-
##
|
|
143
|
-
|
|
144
|
-
In Jay Stack, headfull components are full-stack. They must have a `.jay-contract` file and are created using `makeJayStackComponent` in their `.ts` file. They support server rendering (slow/fast/interactive phases) and must include a `contract` attribute in the import.
|
|
144
|
+
## Full-Stack Shared Components (Headless)
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
A shared UI section with its own logic — a site header, a footer, a side nav — is a **headless full-stack
|
|
147
|
+
component**: logic authored with `makeJayStackComponent` against a `.jay-contract`, with its template
|
|
148
|
+
provided by the consuming page. It supports server rendering (slow/fast/interactive phases). Like every
|
|
149
|
+
Jay Stack component, it is imported with `application/jay-headless` — **not** `application/jay-headfull`
|
|
150
|
+
(see [Headfull components are not for Jay Stack](#headfull-components-are-not-for-jay-stack) below).
|
|
147
151
|
|
|
148
|
-
|
|
152
|
+
Each lives in its own subdirectory under `src/components/` with three files: `.ts`, `.jay-html` (its
|
|
153
|
+
source template), and `.jay-contract`. The production build only discovers server-side component modules
|
|
154
|
+
from `src/components/` and `src/plugins/`. Placing them inside page directories works in dev mode but
|
|
155
|
+
fails in production.
|
|
149
156
|
|
|
150
157
|
### Import Declaration
|
|
151
158
|
|
|
159
|
+
Import it like any coded headless component — `src=` for the logic, `contract=` for the data shape, and
|
|
160
|
+
`template=` so its markup can be flattened into your page:
|
|
161
|
+
|
|
152
162
|
```html
|
|
153
163
|
<head>
|
|
154
164
|
<script
|
|
155
|
-
type="application/jay-
|
|
165
|
+
type="application/jay-headless"
|
|
156
166
|
src="../components/shared-header/shared-header"
|
|
157
|
-
names="SharedHeader"
|
|
158
167
|
contract="../components/shared-header/shared-header.jay-contract"
|
|
168
|
+
template="../components/shared-header/shared-header.jay-html"
|
|
159
169
|
></script>
|
|
160
170
|
</head>
|
|
161
171
|
```
|
|
162
172
|
|
|
163
173
|
**Attributes:**
|
|
164
174
|
|
|
165
|
-
- `src` —
|
|
166
|
-
- `
|
|
167
|
-
- `
|
|
175
|
+
- `src` — path to the component logic (include the filename, not just the directory)
|
|
176
|
+
- `contract` — path to the component's `.jay-contract` file
|
|
177
|
+
- `template` — path to the component's source `.jay-html`, so `jay-stack sync` can flatten its markup
|
|
178
|
+
into the region
|
|
168
179
|
|
|
169
180
|
### Usage
|
|
170
181
|
|
|
182
|
+
Place a `<jay:X>` region (the tag is the contract's `name:`) and run `jay-stack sync` to flatten its body:
|
|
183
|
+
|
|
171
184
|
```html
|
|
172
|
-
<jay:SharedHeader logoUrl="/logo.png" />
|
|
185
|
+
<jay:SharedHeader ref="header" logoUrl="/logo.png" />
|
|
173
186
|
```
|
|
174
187
|
|
|
175
|
-
|
|
188
|
+
After sync the region carries a flattened, editable copy of the component's template. See
|
|
189
|
+
[design-system-guide.md](design-system-guide.md) for drift, facet-marking, and upgrades.
|
|
190
|
+
|
|
191
|
+
> **Route params:** instance-based components do not receive route params directly. To pass a route param,
|
|
192
|
+
> expose it through the page's ViewState and bind it as a prop: `<jay:SideNav activePage="{activePage}" />`.
|
|
193
|
+
> See [routing.md](routing.md) for the full pattern.
|
|
176
194
|
|
|
177
195
|
### Component Structure
|
|
178
196
|
|
|
179
|
-
Each
|
|
197
|
+
Each shared full-stack component needs three files in its subdirectory under `src/components/`:
|
|
180
198
|
|
|
181
199
|
**`.jay-contract`** — declares props. Tags are optional (use `tags: []` or omit for structural components):
|
|
182
200
|
|
|
@@ -220,21 +238,72 @@ For a structural component with only props and no data logic, `.withFastRender`
|
|
|
220
238
|
</html>
|
|
221
239
|
```
|
|
222
240
|
|
|
241
|
+
### Headfull components are not for Jay Stack
|
|
242
|
+
|
|
243
|
+
`application/jay-headfull` is the **lower-level Jay** component model: logic bundled with its _own_ template
|
|
244
|
+
via `makeJayComponent`, imported with `src=` + `names=` and **no** `contract=`. It has no server rendering,
|
|
245
|
+
so **it is never used directly in a Jay Stack page**. A `jay-headfull` import that carries a `contract=`
|
|
246
|
+
attribute is a **hard build error** (DL#196) — declare the component with `application/jay-headless` and
|
|
247
|
+
flatten it into a `<jay:X>` region instead. Reach for `makeJayComponent` / headfull only in standalone,
|
|
248
|
+
client-only Jay apps, never in Jay Stack.
|
|
249
|
+
|
|
250
|
+
## Customizing Component Markup — flatten, then edit
|
|
251
|
+
|
|
252
|
+
To reuse a component but tweak **this one instance** — a label, an image, whether a paragraph appears, a
|
|
253
|
+
container's children — you **flatten** (copy) its template into your page and edit the copy. There is no
|
|
254
|
+
`<override>` tag; you edit real markup and mark the parts you own.
|
|
255
|
+
|
|
256
|
+
Give the import a `template=` provenance marker, place the region, and run `jay-stack sync` to fill it:
|
|
257
|
+
|
|
258
|
+
```html
|
|
259
|
+
<head>
|
|
260
|
+
<script
|
|
261
|
+
type="application/jay-headless"
|
|
262
|
+
contract="./components/pricing-card/pricing-card.jay-contract"
|
|
263
|
+
template="./components/pricing-card/pricing-card.jay-html"
|
|
264
|
+
></script>
|
|
265
|
+
</head>
|
|
266
|
+
<body>
|
|
267
|
+
<!-- after `jay-stack sync` fills the body, edit it freely -->
|
|
268
|
+
<jay:pricing-card ref="hero">
|
|
269
|
+
<button class="cta">Start free trial</button>
|
|
270
|
+
<!-- text rewritten; mark the facet you own so sync keeps it -->
|
|
271
|
+
</jay:pricing-card>
|
|
272
|
+
</body>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
- **Replace content:** rewrite the element's text/children in the copy; mark the element `override="children"`.
|
|
276
|
+
- **Change an attribute:** edit it; mark `override="<attr>"` (e.g. `override="src"`). Others reconcile.
|
|
277
|
+
- **Change one style property:** edit it; mark `override="style.<prop>"`. Other props reconcile.
|
|
278
|
+
- **Remove an element:** delete it and mark the parent `override="children"` (else `sync` restores it).
|
|
279
|
+
- **Own a whole node:** mark it with a bare `override`.
|
|
280
|
+
|
|
281
|
+
`{binding}` expressions inside the region resolve against the **component's own** contract, exactly as its
|
|
282
|
+
source template does. `jay-stack validate` reports any unmarked edit as drift, and `jay-stack sync`
|
|
283
|
+
re-flattens from the current source while preserving your marked facets.
|
|
284
|
+
|
|
285
|
+
**See [design-system-guide.md](design-system-guide.md)** for the full model: creating design-system
|
|
286
|
+
elements, reading drift warnings, the complete facet-marking vocabulary (markup `override` + CSS
|
|
287
|
+
`jay:override`), and upgrading with `sync`.
|
|
288
|
+
|
|
223
289
|
## Nesting Components
|
|
224
290
|
|
|
225
|
-
|
|
291
|
+
Components nest by importing other headless components in their own `<head>` and composing them in their
|
|
292
|
+
template.
|
|
226
293
|
|
|
227
|
-
A
|
|
294
|
+
### A shared component composing another shared component
|
|
295
|
+
|
|
296
|
+
A layout component flattens a header component:
|
|
228
297
|
|
|
229
298
|
```html
|
|
230
299
|
<!-- layout/layout.jay-html -->
|
|
231
300
|
<html>
|
|
232
301
|
<head>
|
|
233
302
|
<script
|
|
234
|
-
type="application/jay-
|
|
303
|
+
type="application/jay-headless"
|
|
235
304
|
src="../header/header"
|
|
236
305
|
contract="../header/header.jay-contract"
|
|
237
|
-
|
|
306
|
+
template="../header/header.jay-html"
|
|
238
307
|
></script>
|
|
239
308
|
<script type="application/jay-data">
|
|
240
309
|
data:
|
|
@@ -243,14 +312,14 @@ A layout component imports a header component:
|
|
|
243
312
|
</head>
|
|
244
313
|
<body>
|
|
245
314
|
<div class="layout">
|
|
246
|
-
<jay:header logoUrl="/logo.png" />
|
|
315
|
+
<jay:header ref="header" logoUrl="/logo.png" />
|
|
247
316
|
<aside>{sidebarLabel}</aside>
|
|
248
317
|
</div>
|
|
249
318
|
</body>
|
|
250
319
|
</html>
|
|
251
320
|
```
|
|
252
321
|
|
|
253
|
-
###
|
|
322
|
+
### A shared component using a plugin widget
|
|
254
323
|
|
|
255
324
|
A header component uses a headless plugin widget:
|
|
256
325
|
|
|
@@ -275,19 +344,20 @@ A header component uses a headless plugin widget:
|
|
|
275
344
|
</html>
|
|
276
345
|
```
|
|
277
346
|
|
|
278
|
-
Nesting depth is unlimited. Circular imports are detected as errors. Key-based headless imports
|
|
347
|
+
Nesting depth is unlimited. Circular imports are detected as errors. Key-based headless imports
|
|
348
|
+
(`key="..."`) are only allowed in pages — inside a shared component use instance-based (`<jay:X>`) imports.
|
|
279
349
|
|
|
280
350
|
## Nesting Rules
|
|
281
351
|
|
|
282
|
-
| Parent component
|
|
283
|
-
|
|
|
284
|
-
| **Page**
|
|
285
|
-
| **
|
|
286
|
-
| **
|
|
352
|
+
| Parent component | Can compose full-stack components? | Can import instance headless? | Can import keyed headless? |
|
|
353
|
+
| --------------------------- | ---------------------------------- | ----------------------------- | -------------------------- |
|
|
354
|
+
| **Page** | Yes | Yes | Yes |
|
|
355
|
+
| **Full-stack component** | Yes (recursive) | Yes (in its own head) | No |
|
|
356
|
+
| **Keyed / plugin headless** | No (consumer owns the template) | No | No |
|
|
287
357
|
|
|
288
358
|
## Complete Example
|
|
289
359
|
|
|
290
|
-
A homepage with key-based, instance-based, and
|
|
360
|
+
A homepage with key-based, instance-based, and shared full-stack components — all headless:
|
|
291
361
|
|
|
292
362
|
```html
|
|
293
363
|
<html>
|
|
@@ -304,10 +374,10 @@ A homepage with key-based, instance-based, and headfull components:
|
|
|
304
374
|
contract="product-widget"
|
|
305
375
|
></script>
|
|
306
376
|
<script
|
|
307
|
-
type="application/jay-
|
|
377
|
+
type="application/jay-headless"
|
|
308
378
|
src="../components/shared-header/shared-header"
|
|
309
|
-
names="SharedHeader"
|
|
310
379
|
contract="../components/shared-header/shared-header.jay-contract"
|
|
380
|
+
template="../components/shared-header/shared-header.jay-html"
|
|
311
381
|
></script>
|
|
312
382
|
<script type="application/jay-data" contract="./page.jay-contract"></script>
|
|
313
383
|
<style>
|
|
@@ -323,7 +393,7 @@ A homepage with key-based, instance-based, and headfull components:
|
|
|
323
393
|
</style>
|
|
324
394
|
</head>
|
|
325
395
|
<body>
|
|
326
|
-
<jay:SharedHeader logoUrl="/logo.png" />
|
|
396
|
+
<jay:SharedHeader ref="header" logoUrl="/logo.png" />
|
|
327
397
|
<h1>Homepage</h1>
|
|
328
398
|
|
|
329
399
|
<!-- Key-based: mood tracker -->
|
|
@@ -19,6 +19,15 @@ Add `<style>` blocks in `<head>`:
|
|
|
19
19
|
</head>
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
## Styling a design-system region (`@scope` + `:scope`)
|
|
23
|
+
|
|
24
|
+
CSS for a `<jay:X>` **design-system element** (a region with `template=` provenance) is not written as plain
|
|
25
|
+
page rules — it lives in an `@scope (.<ref>)` block, and the component's own root rule must target `:scope`,
|
|
26
|
+
not its block class (inside `@scope`, a class selector matches descendants of the scope root only). This has
|
|
27
|
+
its own rules and is covered in full in
|
|
28
|
+
[design-system-guide.md → The shape of a region's CSS](design-system-guide.md#the-shape-of-a-regions-css).
|
|
29
|
+
The plain-`<style>` patterns on this page apply to ordinary page markup.
|
|
30
|
+
|
|
22
31
|
## External Stylesheets
|
|
23
32
|
|
|
24
33
|
Link external CSS files:
|
|
@@ -95,3 +104,63 @@ Mix static, dynamic, and conditional classes:
|
|
|
95
104
|
- `{condition ? classA : classB}` switches between two classes
|
|
96
105
|
- `{!condition ? class}` uses negation
|
|
97
106
|
- Multiple bindings can be combined in one `class` attribute
|
|
107
|
+
|
|
108
|
+
## Viewport Height & Google Search Console
|
|
109
|
+
|
|
110
|
+
Googlebot's Web Rendering Service does **not** render at a normal phone height. To capture lazy-loaded and
|
|
111
|
+
below-the-fold content in one pass, it renders the page once into a **very tall viewport**
|
|
112
|
+
(~9,000–12,000px). Any element sized to a fraction of viewport height resolves against that tall value:
|
|
113
|
+
|
|
114
|
+
```css
|
|
115
|
+
.hero {
|
|
116
|
+
min-height: 100vh;
|
|
117
|
+
} /* phone: ~800px. Googlebot: ~12,000px. */
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
On a **top-level container** (`<html>`/`<body>`/`<main>`, or a direct child of `<body>`/`<main>`) that
|
|
121
|
+
makes the section enormous in the crawler's render — distorting Search Console screenshots and mobile
|
|
122
|
+
usability / layout signals. The `design-viewport-height` validator flags unbounded viewport-height units
|
|
123
|
+
(`vh`, `svh`, `lvh`, `dvh`, `vmax`) on these containers.
|
|
124
|
+
|
|
125
|
+
**Swapping the unit is NOT a fix.** `svh`/`lvh`/`dvh` all resolve against the same tall viewport under
|
|
126
|
+
Googlebot (there is no browser chrome to differentiate them), so `vh → dvh` changes nothing here.
|
|
127
|
+
|
|
128
|
+
Choose the fix by what the container holds:
|
|
129
|
+
|
|
130
|
+
- **Text-heavy section** — don't force full-viewport height at all. Let content determine height, or chain
|
|
131
|
+
from a bounded ancestor:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
main {
|
|
135
|
+
min-height: 100%;
|
|
136
|
+
} /* inherits a real height, not the viewport */
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- **Hero / visual section** that genuinely wants a full-screen feel — cap it, and scope the viewport height
|
|
140
|
+
to a real screen via a media query so it never applies to Googlebot's tall canvas:
|
|
141
|
+
|
|
142
|
+
```css
|
|
143
|
+
.hero {
|
|
144
|
+
max-height: 900px;
|
|
145
|
+
}
|
|
146
|
+
@media (min-width: 480px) {
|
|
147
|
+
.hero {
|
|
148
|
+
min-height: 100vh;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
A `max-height` in an **absolute** unit (`px`/`rem`, or `%` of a bounded ancestor) clears the warning. A
|
|
154
|
+
`max-height` that also uses a viewport unit (`max-height: 100vh`) does **not** — it caps against the same
|
|
155
|
+
~12,000px viewport.
|
|
156
|
+
|
|
157
|
+
- **Overlay / modal / drawer** that is out of flow (`position: fixed/absolute/sticky`) — this is safe (it
|
|
158
|
+
doesn't expand the document canvas) and the validator already ignores it. If a false positive slips
|
|
159
|
+
through, suppress it per-page (see `validation-guide.md`):
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<script type="application/jay-validations">
|
|
163
|
+
design-system:
|
|
164
|
+
allow-viewport-height: true
|
|
165
|
+
</script>
|
|
166
|
+
```
|
|
@@ -14,24 +14,33 @@ The design tool can freely read and rewrite jay-html files as long as contract b
|
|
|
14
14
|
|
|
15
15
|
Entry point at `src/pages/`. Can import all component types.
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Full-stack component (headless)
|
|
18
18
|
|
|
19
|
-
Reusable component with
|
|
19
|
+
Reusable component with logic + contract + three-phase rendering (slow/fast/interactive), authored with
|
|
20
|
+
`makeJayStackComponent`. It has **no template of its own** — the consuming page flattens its template into a
|
|
21
|
+
`<jay:X>` region. Must live in `src/components/` (not inside page directories) so the production build can
|
|
22
|
+
discover and compile them. Can nest other full-stack components and instance headless in its own `<head>`.
|
|
23
|
+
Cannot use keyed headless. (Imported with `application/jay-headless`, not `application/jay-headfull` — see
|
|
24
|
+
[jay-html-components.md](jay-html-components.md#headfull-components-are-not-for-jay-stack).)
|
|
20
25
|
|
|
21
26
|
### Headless
|
|
22
27
|
|
|
23
|
-
Plugin-provided logic component. No template — the page or
|
|
28
|
+
Plugin-provided logic component. No template of its own — the page or consuming component provides the UI via inline template (`<jay:xxx>`). Two import patterns:
|
|
24
29
|
|
|
25
30
|
- **Key-based** — one instance per page, data merged under a key prefix (`{key.tag}`)
|
|
26
31
|
- **Instance-based** — multiple instances with props, each gets its own inline template
|
|
27
32
|
|
|
33
|
+
**Prefer a design system:** if the component ships a `.jay-html` template, flatten it (`template=` +
|
|
34
|
+
`jay-stack sync`) instead of hand-writing the inline body — see
|
|
35
|
+
[design-system-guide.md](design-system-guide.md).
|
|
36
|
+
|
|
28
37
|
## Nesting Rules
|
|
29
38
|
|
|
30
|
-
| Parent component
|
|
31
|
-
|
|
|
32
|
-
| **Page**
|
|
33
|
-
| **
|
|
34
|
-
| **
|
|
39
|
+
| Parent component | Can compose full-stack components? | Can import headless (instance)? | Can import keyed headless? |
|
|
40
|
+
| --------------------------- | ---------------------------------- | ------------------------------- | -------------------------- |
|
|
41
|
+
| **Page** | Yes | Yes | Yes |
|
|
42
|
+
| **Full-stack component** | Yes (recursive) | Yes (in its own head) | No |
|
|
43
|
+
| **Keyed / plugin headless** | No (consumer owns the template) | No | No |
|
|
35
44
|
|
|
36
45
|
## Validation
|
|
37
46
|
|
|
@@ -39,8 +48,8 @@ After creating or editing jay-html files, run `jay-stack validate` to check for
|
|
|
39
48
|
|
|
40
49
|
## Reference
|
|
41
50
|
|
|
42
|
-
| File | Topic
|
|
43
|
-
| ---------------------------------------------------------- |
|
|
44
|
-
| [jay-html-template-syntax.md](jay-html-template-syntax.md) | Template markup: file structure, data binding, conditions, loops, refs
|
|
45
|
-
| [jay-html-components.md](jay-html-components.md) | Component imports: headless (key/instance),
|
|
46
|
-
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic styles, class bindings
|
|
51
|
+
| File | Topic |
|
|
52
|
+
| ---------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
53
|
+
| [jay-html-template-syntax.md](jay-html-template-syntax.md) | Template markup: file structure, data binding, conditions, loops, refs |
|
|
54
|
+
| [jay-html-components.md](jay-html-components.md) | Component imports: headless (key/instance), full-stack components, nesting |
|
|
55
|
+
| [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic styles, class bindings |
|
|
@@ -18,8 +18,8 @@ A `.jay-html` file is standard HTML with jay-specific extensions.
|
|
|
18
18
|
<!-- Headless component imports -->
|
|
19
19
|
<script type="application/jay-headless" plugin="..." contract="..." key="..."></script>
|
|
20
20
|
|
|
21
|
-
<!--
|
|
22
|
-
<script type="application/jay-
|
|
21
|
+
<!-- Shared full-stack component imports (headless) -->
|
|
22
|
+
<script type="application/jay-headless" src="..." contract="..." template="..."></script>
|
|
23
23
|
|
|
24
24
|
<!-- SEO head tags (support {binding} syntax) -->
|
|
25
25
|
<title>{productPage.name} | My Store</title>
|
|
@@ -182,7 +182,7 @@ Available at all render phases (slow, fast, interactive). Use in text bindings,
|
|
|
182
182
|
<a if="jay.url.path ^= '/docs'" class="docs-active">Docs</a>
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
`jay.` bindings are available in **page templates only** —
|
|
185
|
+
`jay.` bindings are available in **page templates only** — shared full-stack components receive this data via props.
|
|
186
186
|
|
|
187
187
|
### Choosing the Right Condition Type
|
|
188
188
|
|
|
@@ -14,7 +14,7 @@ my-project/
|
|
|
14
14
|
│ ├── project.conf.yaml # Project metadata (name, etc.)
|
|
15
15
|
│ └── <plugin-name>.yaml # Plugin-specific config files
|
|
16
16
|
├── src/
|
|
17
|
-
│ ├── components/ #
|
|
17
|
+
│ ├── components/ # Shared full-stack components, headless (shared across pages)
|
|
18
18
|
│ │ └── site-header/
|
|
19
19
|
│ │ ├── site-header.ts
|
|
20
20
|
│ │ ├── site-header.jay-html
|
|
@@ -124,7 +124,7 @@ tags:
|
|
|
124
124
|
|
|
125
125
|
## Dynamic Routes and Contract Params
|
|
126
126
|
|
|
127
|
-
When a component on the page — whether the page contract, a headless component, or a
|
|
127
|
+
When a component on the page — whether the page contract, a plugin headless component, or a shared full-stack component — declares `params`, the page should be placed in a dynamic route directory that provides those params.
|
|
128
128
|
|
|
129
129
|
For example, if a headless component's contract declares:
|
|
130
130
|
|
|
@@ -146,7 +146,7 @@ Multiple components on the same page can each declare params. The route director
|
|
|
146
146
|
|
|
147
147
|
### Passing Route Params to Nested Components
|
|
148
148
|
|
|
149
|
-
Route params flow automatically to keyed headless components that declare them as `params` in their contract. Instance-based headless components and
|
|
149
|
+
Route params flow automatically to keyed headless components that declare them as `params` in their contract. Instance-based headless components and shared full-stack components do not receive route params directly — they receive props from the template.
|
|
150
150
|
|
|
151
151
|
#### Direct binding with `jay.params` (no page.ts needed)
|
|
152
152
|
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
The validator processes each `.jay-html` file with:
|
|
16
16
|
|
|
17
17
|
- **Page template** — your HTML, bindings, and inline styles
|
|
18
|
-
- **
|
|
18
|
+
- **Full-stack component content** — `<jay:SiteHeader />`, `<jay:DocsSidebar />` etc. are flattened into the page before validation
|
|
19
19
|
- **Headless component tags** — `<jay:product-widget>` inline templates are visible
|
|
20
20
|
- **Linked CSS files** — `<link rel="stylesheet" href="...">` referenced from `<head>` are read and validated (e.g., for CSS `@import` of external URLs)
|
|
21
21
|
- **Inline `<style>` blocks** — CSS in `<head>` is parsed for rule violations
|
|
22
22
|
|
|
23
|
-
So a warning about an `<img>` might come from a
|
|
23
|
+
So a warning about an `<img>` might come from a full-stack component's template, not your page template. A CSS warning might come from a linked stylesheet.
|
|
24
24
|
|
|
25
25
|
## Errors vs Warnings
|
|
26
26
|
|
|
@@ -37,9 +37,9 @@ Each warning has:
|
|
|
37
37
|
|
|
38
38
|
### Acting on Warnings
|
|
39
39
|
|
|
40
|
-
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
|
|
40
|
+
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 full-stack component.
|
|
41
41
|
|
|
42
|
-
2. **For
|
|
42
|
+
2. **For full-stack 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.
|
|
43
43
|
|
|
44
44
|
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.
|
|
45
45
|
|
|
@@ -49,7 +49,7 @@ Each warning has:
|
|
|
49
49
|
|
|
50
50
|
### "Image without loading attribute" from a component
|
|
51
51
|
|
|
52
|
-
The image is in a
|
|
52
|
+
The image is in a full-stack component (e.g., sidebar icons). Fix it in the component's `.jay-html`, not the page.
|
|
53
53
|
|
|
54
54
|
### "Heading level skipped" with dynamic content
|
|
55
55
|
|
|
@@ -102,6 +102,32 @@ Multiple plugins can be configured in one tag:
|
|
|
102
102
|
no-lcp-image: true
|
|
103
103
|
design-system:
|
|
104
104
|
allow-undefined-vars: true
|
|
105
|
+
allow-viewport-height: true
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Design-system suppression keys include `allow-undefined-vars`, `allow-viewport-height` (top-level
|
|
110
|
+
viewport-height containers — see `jay-html-styling.md`), `allow-custom-breakpoints`,
|
|
111
|
+
`allow-no-reduced-motion`, and `allow-font-no-fallback`.
|
|
112
|
+
|
|
113
|
+
### Prefer-design-system-elements warnings (jay-stack namespace)
|
|
114
|
+
|
|
115
|
+
The core `jay-stack validate` emits four warnings that nudge you to reuse UI through design-system elements
|
|
116
|
+
(see `design-system-guide.md`). Suppress the legitimate case:
|
|
117
|
+
|
|
118
|
+
| Rule | How to suppress |
|
|
119
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
120
|
+
| `REGION-NOT-LINKED` | `jay-validations="REGION-NOT-LINKED"` on the `application/jay-headless` import, or `jay-stack: allow-inline-region: [Contract]` |
|
|
121
|
+
| `REGION-OVERRIDE-NON-CONTENT` | `jay-validations="REGION-OVERRIDE-NON-CONTENT"` on the import |
|
|
122
|
+
| `COMPONENT-NO-TEMPLATE` | `jay-stack: allow-no-template: [Contract]` |
|
|
123
|
+
| `NO-DESIGN-SYSTEM` | `jay-stack: allow-no-design-system: true` |
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<script type="application/jay-validations">
|
|
127
|
+
jay-stack:
|
|
128
|
+
allow-inline-region: [Card]
|
|
129
|
+
allow-no-template: [MetricsProvider]
|
|
130
|
+
allow-no-design-system: true
|
|
105
131
|
</script>
|
|
106
132
|
```
|
|
107
133
|
|
|
@@ -4,7 +4,9 @@ This folder contains guides for building jay-stack projects: project configurati
|
|
|
4
4
|
|
|
5
5
|
## What Does the Developer Role Do?
|
|
6
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).
|
|
7
|
+
The developer sets up the project, configures plugins, creates page-level components (`page.ts`), defines page contracts (`page.jay-contract`), authors shared full-stack components (headless) for reusable UI sections like headers and footers, 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
|
+
**Shared components are headless** — logic (`makeJayStackComponent`) + a `.jay-contract`, placed in `src/components/<name>/`. **Prefer shipping each with a `.jay-html` template** (one or more) so pages flatten it as a design-system element (`template=` + `jay-stack sync`) instead of hand-writing the UI. See [design-system-guide.md](../designer/design-system-guide.md) for the model and [component-structure.md](../plugin/component-structure.md) for the builder API.
|
|
8
10
|
|
|
9
11
|
## Workflow
|
|
10
12
|
|
|
@@ -12,24 +14,27 @@ The developer sets up the project, configures plugins, creates page-level compon
|
|
|
12
14
|
2. **Define routes** — create page directories under `src/pages/`
|
|
13
15
|
3. **Create page contracts** — `page.jay-contract` for page-level data
|
|
14
16
|
4. **Create page components** — `page.ts` with `makeJayStackComponent`
|
|
15
|
-
5. **
|
|
16
|
-
6. **
|
|
17
|
-
7. **
|
|
17
|
+
5. **Author shared components** (when UI repeats across pages) — headless `makeJayStackComponent` + `.jay-contract` in `src/components/`, preferably shipping a `.jay-html` template for pages to flatten
|
|
18
|
+
6. **Configure services** — `src/init.ts` for project-level services
|
|
19
|
+
7. **Validate** — `jay-stack validate`
|
|
20
|
+
8. **Test** — `jay-stack dev --test-mode`
|
|
18
21
|
|
|
19
22
|
## Guides
|
|
20
23
|
|
|
21
|
-
| File
|
|
22
|
-
|
|
|
23
|
-
| [project-structure.md](project-structure.md)
|
|
24
|
-
| [routing.md](routing.md)
|
|
25
|
-
| [configuration.md](configuration.md)
|
|
26
|
-
| [page-contracts.md](page-contracts.md)
|
|
27
|
-
| [Contract Authoring Guide](../contracts/GUIDE.md)
|
|
28
|
-
| [page-components.md](page-components.md)
|
|
29
|
-
| [
|
|
30
|
-
| [component-
|
|
31
|
-
| [component-
|
|
32
|
-
| [
|
|
33
|
-
| [
|
|
34
|
-
| [
|
|
35
|
-
|
|
|
24
|
+
| File | Topic |
|
|
25
|
+
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
|
|
26
|
+
| [project-structure.md](project-structure.md) | Directory layout, configuration files |
|
|
27
|
+
| [routing.md](routing.md) | Directory-based routing, dynamic routes |
|
|
28
|
+
| [configuration.md](configuration.md) | .jay file, plugin config, init.ts |
|
|
29
|
+
| [page-contracts.md](page-contracts.md) | Page-level contracts (page.jay-contract) |
|
|
30
|
+
| [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
|
|
31
|
+
| [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
|
|
32
|
+
| [design-system-guide.md](../designer/design-system-guide.md) | Shared components as design-system elements: ship a template, flatten, drift, `sync` |
|
|
33
|
+
| [component-structure.md](../plugin/component-structure.md) | Builder API for shared/headless components: `.withProps()`, phases, render results |
|
|
34
|
+
| [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
|
|
35
|
+
| [component-refs.md](component-refs.md) | Refs, collection refs, element types |
|
|
36
|
+
| [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
|
|
37
|
+
| [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
|
|
38
|
+
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
39
|
+
| [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
|
|
40
|
+
| `../references/<plugin>/` | Plugin reference data |
|
|
@@ -6,9 +6,9 @@ A page component (`page.ts`) uses `makeJayStackComponent` to provide page-level
|
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
import { makeJayStackComponent, phaseOutput } from '@jay-framework/fullstack-component';
|
|
9
|
-
import type {
|
|
9
|
+
import type { PageContract } from './page.jay-contract';
|
|
10
10
|
|
|
11
|
-
export const page = makeJayStackComponent<
|
|
11
|
+
export const page = makeJayStackComponent<PageContract>()
|
|
12
12
|
.withSlowlyRender(async () => {
|
|
13
13
|
return phaseOutput({ heroTitle: 'Welcome', heroSubtitle: 'Build something great' }, {});
|
|
14
14
|
})
|
|
@@ -19,6 +19,27 @@ export const page = makeJayStackComponent<HomePageContract>()
|
|
|
19
19
|
|
|
20
20
|
The export name must be `page` for page-level components.
|
|
21
21
|
|
|
22
|
+
## Where to import page types from
|
|
23
|
+
|
|
24
|
+
Both `page.jay-contract.d.ts` and `page.jay-html.d.ts` are generated next to your page (on `dev`/`build`).
|
|
25
|
+
They cover **different surfaces** — import from the right one:
|
|
26
|
+
|
|
27
|
+
- **Data types and runtime enum/variant _values_** (`PageContract`, `PageViewState`, `PageSlowViewState`,
|
|
28
|
+
`PageFastViewState`, `PageRefs`, and any `enum` your contract declares) → import from **`./page.jay-contract`**.
|
|
29
|
+
This mirrors how a component's `.ts` imports from its own `./X.jay-contract`. A runtime enum value
|
|
30
|
+
(e.g. `Status.warning`) **must** come from here — importing it from `./page.jay-html` pulls the browser element
|
|
31
|
+
module into server-side SSR and fails.
|
|
32
|
+
- **Composed refs that come from the template** — child-component refs, and DL#198 free refs like
|
|
33
|
+
`refs.card.dismiss` — live only in `page.jay-html.d.ts`. Import them **type-only** from **`./page.jay-html`**
|
|
34
|
+
(type-only so nothing is loaded at runtime):
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import type { PageElementRefs } from './page.jay-html';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Rule of thumb: **data → `./page.jay-contract`; template/composed refs → `./page.jay-html` (type-only)**.
|
|
41
|
+
Do not import runtime values from `./page.jay-html`, and there is no `.generated` suffix.
|
|
42
|
+
|
|
22
43
|
## Page Component with Params
|
|
23
44
|
|
|
24
45
|
For dynamic routes, use `withLoadParams` and access params via props:
|
|
@@ -14,7 +14,7 @@ my-project/
|
|
|
14
14
|
│ ├── project.conf.yaml # Project metadata (name, etc.)
|
|
15
15
|
│ └── <plugin-name>.yaml # Plugin-specific config files
|
|
16
16
|
├── src/
|
|
17
|
-
│ ├── components/ #
|
|
17
|
+
│ ├── components/ # Shared full-stack components, headless (shared across pages)
|
|
18
18
|
│ │ └── site-header/
|
|
19
19
|
│ │ ├── site-header.ts
|
|
20
20
|
│ │ ├── site-header.jay-html
|
|
@@ -124,7 +124,7 @@ tags:
|
|
|
124
124
|
|
|
125
125
|
## Dynamic Routes and Contract Params
|
|
126
126
|
|
|
127
|
-
When a component on the page — whether the page contract, a headless component, or a
|
|
127
|
+
When a component on the page — whether the page contract, a plugin headless component, or a shared full-stack component — declares `params`, the page should be placed in a dynamic route directory that provides those params.
|
|
128
128
|
|
|
129
129
|
For example, if a headless component's contract declares:
|
|
130
130
|
|
|
@@ -72,7 +72,7 @@ The build is **environment-agnostic**. The same output serves any deployment mod
|
|
|
72
72
|
|
|
73
73
|
For production builds to work correctly:
|
|
74
74
|
|
|
75
|
-
- **
|
|
75
|
+
- **Full-stack components** (headless) must be in `src/components/` (not inside page directories)
|
|
76
76
|
- **Headless plugins** must be in `src/plugins/`
|
|
77
77
|
- **Actions** must be in `src/actions/` with `*.actions.ts` naming
|
|
78
78
|
- **Init** must be at `src/init.ts`
|