@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.
Files changed (26) hide show
  1. package/agent-kit-template/INSTRUCTIONS.md +24 -1
  2. package/agent-kit-template/contracts/GUIDE.md +1 -1
  3. package/agent-kit-template/contracts/component-contracts.md +42 -12
  4. package/agent-kit-template/designer/INSTRUCTIONS.md +23 -20
  5. package/agent-kit-template/designer/cli-commands.md +46 -0
  6. package/agent-kit-template/designer/contracts-and-plugins.md +30 -1
  7. package/agent-kit-template/designer/design-system-guide.md +535 -0
  8. package/agent-kit-template/designer/jay-html-components.md +101 -31
  9. package/agent-kit-template/designer/jay-html-styling.md +69 -0
  10. package/agent-kit-template/designer/jay-html-syntax.md +22 -13
  11. package/agent-kit-template/designer/jay-html-template-syntax.md +3 -3
  12. package/agent-kit-template/designer/project-structure.md +1 -1
  13. package/agent-kit-template/designer/routing.md +2 -2
  14. package/agent-kit-template/designer/validation-guide.md +31 -5
  15. package/agent-kit-template/developer/INSTRUCTIONS.md +24 -19
  16. package/agent-kit-template/developer/page-components.md +23 -2
  17. package/agent-kit-template/developer/project-structure.md +1 -1
  18. package/agent-kit-template/developer/routing.md +1 -1
  19. package/agent-kit-template/devops/production-build.md +1 -1
  20. package/agent-kit-template/plugin/INSTRUCTIONS.md +3 -1
  21. package/agent-kit-template/plugin/component-structure.md +1 -1
  22. package/agent-kit-template/plugin/contracts-guide.md +18 -0
  23. package/agent-kit-template/plugin/design-system-guide.md +173 -0
  24. package/dist/{index-B9vCxAZ1.js → index-l6QVpvnY.js} +19 -14
  25. package/dist/index.js +1903 -199
  26. 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 headfull component provides the template.
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 headfull FS components).
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
- ## Headfull Components
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
- Each headfull component lives in its own subdirectory under `src/components/` with three files: `.ts`, `.jay-html`, and `.jay-contract`. The production build only discovers server-side component modules from `src/components/` and `src/plugins/`. Placing them inside page directories will work in dev mode but fail in production.
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
- > **Note:** In Jay (without Jay Stack), headfull components use `makeJayComponent` and do not require a contract. However, `makeJayComponent` components should not be used in Jay Stack because they do not support server rendering.
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-headfull"
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` — Path to the component file (must include the filename, not just the directory)
166
- - `names` — Component name to import
167
- - `contract` — Path to the component's `.jay-contract` file (required in Jay Stack)
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
- > **Route params:** Headfull and instance-based headless components do not receive route params directly. To pass a route param, expose it through the page's ViewState and bind it as a prop: `<jay:SideNav activePage="{activePage}" />`. See [routing.md](routing.md) for the full pattern.
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 headfull component needs three files in its subdirectory under `src/components/`:
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
- ### Headfull Inside Headfull
291
+ Components nest by importing other headless components in their own `<head>` and composing them in their
292
+ template.
226
293
 
227
- A layout component imports a header component:
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-headfull"
303
+ type="application/jay-headless"
235
304
  src="../header/header"
236
305
  contract="../header/header.jay-contract"
237
- names="header"
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
- ### Headless Inside Headfull
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 (`key="..."`) are not allowed inside headfull FS components — use instance-based imports instead.
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 | Can import headfull FS? | Can import headless (instance)? | Can import keyed headless? |
283
- | ---------------- | ----------------------- | ------------------------------- | -------------------------- |
284
- | **Page** | Yes | Yes | Yes |
285
- | **Headfull FS** | Yes (recursive) | Yes (in its own head) | No |
286
- | **Headless** | No (no template) | No (no template) | No (no template) |
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 headfull components:
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-headfull"
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
- ### Headfull FS
17
+ ### Full-stack component (headless)
18
18
 
19
- Reusable component with its own template + contract + three-phase rendering (slow/fast/interactive). Must live in `src/components/` (not inside page directories) so the production build can discover and compile them. Can nest other headfull FS and instance headless in its own `<head>`. Cannot use keyed headless.
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 headfull component provides the UI via inline template (`<jay:xxx>`). Two import patterns:
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 | Can import headfull FS? | Can import headless (instance)? | Can import keyed headless? |
31
- | ---------------- | ----------------------- | ------------------------------- | -------------------------- |
32
- | **Page** | Yes | Yes | Yes |
33
- | **Headfull FS** | Yes (recursive) | Yes (in its own head) | No |
34
- | **Headless** | No (no template) | No (no template) | No (no template) |
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), headfull FS, nesting |
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
- <!-- Headfull component imports -->
22
- <script type="application/jay-headfull" src="..." names="..." contract="..."></script>
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** — headfull components receive this data via props.
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/ # Headfull full-stack components (shared across pages)
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 headfull full-stack component — declares `params`, the page should be placed in a dynamic route directory that provides those params.
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 headfull components do not receive route params directly — they receive props from the template.
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
- - **Headfull component content** — `<jay:SiteHeader />`, `<jay:DocsSidebar />` etc. are expanded into the page before validation
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 headfull component's template, not your page template. A CSS warning might come from a linked stylesheet.
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 headfull component.
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 headfull component warnings** — fix them in the component's `.jay-html` file (e.g., `src/components/site-header/site-header.jay-html`), not in the page that imports it.
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 headfull component (e.g., sidebar icons). Fix it in the component's `.jay-html`, not the page.
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. **Configure services** — `src/init.ts` for project-level services
16
- 6. **Validate** — `jay-stack validate`
17
- 7. **Test** — `jay-stack dev --test-mode`
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 | 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
- | [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
28
- | [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
29
- | [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
30
- | [component-refs.md](component-refs.md) | Refs, collection refs, element types |
31
- | [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
32
- | [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
33
- | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
34
- | [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
35
- | `../references/<plugin>/` | Plugin reference data |
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 { HomePageContract } from './page.jay-contract.generated';
9
+ import type { PageContract } from './page.jay-contract';
10
10
 
11
- export const page = makeJayStackComponent<HomePageContract>()
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/ # Headfull full-stack components (shared across pages)
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 headfull full-stack component — declares `params`, the page should be placed in a dynamic route directory that provides those params.
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
- - **Headfull FS components** must be in `src/components/` (not inside page directories)
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`