@jay-framework/jay-stack-cli 0.19.6 → 0.19.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 +37 -0
- package/agent-kit-template/contracts/GUIDE.md +70 -0
- package/agent-kit-template/contracts/component-contracts.md +82 -0
- package/agent-kit-template/contracts/examples/cart-indicator.md +60 -0
- package/agent-kit-template/contracts/examples/category-list.md +77 -0
- package/agent-kit-template/contracts/examples/composing-contracts.md +100 -0
- package/agent-kit-template/contracts/examples/mini-cart.md +43 -0
- package/agent-kit-template/contracts/examples/product-card.md +70 -0
- package/agent-kit-template/contracts/examples/product-page.md +125 -0
- package/agent-kit-template/contracts/linked-contracts.md +75 -0
- package/agent-kit-template/contracts/page-contracts.md +73 -0
- package/agent-kit-template/contracts/syntax.md +190 -0
- package/agent-kit-template/designer/INSTRUCTIONS.md +10 -0
- package/agent-kit-template/designer/jay-html-components.md +11 -13
- package/agent-kit-template/designer/jay-html-template-syntax.md +1 -0
- package/agent-kit-template/designer/script-tags.md +83 -0
- package/agent-kit-template/developer/INSTRUCTIONS.md +15 -14
- package/agent-kit-template/developer/page-contracts.md +1 -1
- package/agent-kit-template/plugin/INSTRUCTIONS.md +20 -19
- package/agent-kit-template/plugin/contracts-guide.md +4 -2
- package/dist/index.js +27 -1
- package/package.json +11 -11
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Jay Stack Agent Kit
|
|
2
|
+
|
|
3
|
+
This agent kit provides role-specific guides for building a Jay Stack application. Each role covers a different aspect of the project.
|
|
4
|
+
|
|
5
|
+
## Roles
|
|
6
|
+
|
|
7
|
+
### Designer (`designer/`)
|
|
8
|
+
|
|
9
|
+
Creates `.jay-html` pages and templates. Binds to contract data using template syntax — data bindings, conditions, loops, and refs. Styles pages with CSS.
|
|
10
|
+
|
|
11
|
+
**Use when:** building or modifying the visual UI of pages and components.
|
|
12
|
+
|
|
13
|
+
### Developer (`developer/`)
|
|
14
|
+
|
|
15
|
+
Creates page components (`page.ts`) using `makeJayStackComponent`, defines page contracts (`page.jay-contract`), configures routing, and sets up project services. Also creates headfull components for shared UI sections (headers, footers).
|
|
16
|
+
|
|
17
|
+
**Use when:** adding page logic, defining data shapes, configuring the project, or creating shared components.
|
|
18
|
+
|
|
19
|
+
### Plugin (`plugin/`)
|
|
20
|
+
|
|
21
|
+
Creates reusable headless components packaged as plugins. Defines contracts, actions, services, and CLI commands that other projects consume.
|
|
22
|
+
|
|
23
|
+
**Use when:** building a reusable plugin that will be installed by other projects.
|
|
24
|
+
|
|
25
|
+
### DevOps (`devops/`)
|
|
26
|
+
|
|
27
|
+
Handles production builds, deployment configuration, serving modes, and cache invalidation.
|
|
28
|
+
|
|
29
|
+
**Use when:** deploying the application or configuring production infrastructure.
|
|
30
|
+
|
|
31
|
+
## Shared Guides
|
|
32
|
+
|
|
33
|
+
### Contracts (`contracts/`)
|
|
34
|
+
|
|
35
|
+
Contract authoring guide shared across all roles. Covers syntax, page contracts, component contracts, linked contracts, and graduated examples.
|
|
36
|
+
|
|
37
|
+
**Start here:** [contracts/GUIDE.md](contracts/GUIDE.md) — decision tree for what kind of contract to write.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contract Authoring Guide
|
|
2
|
+
|
|
3
|
+
Contracts (`.jay-contract` files) define the data shape, interaction points, and rendering phases for a component. They are the source of truth shared between the component implementation and the template.
|
|
4
|
+
|
|
5
|
+
## What Kind of Contract Do I Need?
|
|
6
|
+
|
|
7
|
+
### Page contract
|
|
8
|
+
|
|
9
|
+
A page has its own data that isn't fully provided by plugins.
|
|
10
|
+
|
|
11
|
+
- Place as `page.jay-contract` next to `page.jay-html` and `page.ts`
|
|
12
|
+
- Use `params` for dynamic route segments (`slug`, `category`)
|
|
13
|
+
- Can coexist with plugin headless contracts on the same page
|
|
14
|
+
- See [page-contracts.md](page-contracts.md)
|
|
15
|
+
|
|
16
|
+
### Headfull component contract
|
|
17
|
+
|
|
18
|
+
A shared UI section (header, footer, sidebar) that appears across multiple pages.
|
|
19
|
+
|
|
20
|
+
- Place in `src/components/<name>/` alongside the `.ts` and `.jay-html` files
|
|
21
|
+
- Use `props` for configuration passed by the parent page
|
|
22
|
+
- No `params` (components don't own routes)
|
|
23
|
+
- See [component-contracts.md](component-contracts.md)
|
|
24
|
+
|
|
25
|
+
### Plugin contract
|
|
26
|
+
|
|
27
|
+
A headless component provided by a plugin for others to consume.
|
|
28
|
+
|
|
29
|
+
- Place in the plugin's `lib/contracts/` directory
|
|
30
|
+
- Declared in `plugin.yaml`
|
|
31
|
+
- Can be static (file) or dynamic (generated at build time)
|
|
32
|
+
- See the plugin role guide for plugin-specific concerns
|
|
33
|
+
|
|
34
|
+
### Shared sub-contract
|
|
35
|
+
|
|
36
|
+
A reusable piece extracted from a larger contract and linked via `link:` syntax.
|
|
37
|
+
|
|
38
|
+
- Place alongside the contracts that reference it
|
|
39
|
+
- No `props` or `params` (data flows from the parent)
|
|
40
|
+
- See [linked-contracts.md](linked-contracts.md)
|
|
41
|
+
|
|
42
|
+
## Decision Checklist
|
|
43
|
+
|
|
44
|
+
| Question | If yes |
|
|
45
|
+
| --------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
46
|
+
| Does the component own a URL route? | Add `params` — see [page-contracts.md](page-contracts.md) |
|
|
47
|
+
| Is it configured by a parent? | Add `props` — see [component-contracts.md](component-contracts.md) |
|
|
48
|
+
| Does it have nested repeated data? | Use `sub-contract` with `repeated: true` and `trackBy` |
|
|
49
|
+
| Is a sub-contract reused across multiple contracts? | Extract to a separate file, use `link:` — see [linked-contracts.md](linked-contracts.md) |
|
|
50
|
+
| Does data change per request? | Use `fast` or `fast+interactive` phase |
|
|
51
|
+
| Does data update on the client after interaction? | Use `fast+interactive` phase |
|
|
52
|
+
| Is the data static / known at build time? | Use `slow` phase |
|
|
53
|
+
| Does the user click, type, or select something? | Add `interactive` tag with the right `elementType` |
|
|
54
|
+
|
|
55
|
+
## Contract Syntax Reference
|
|
56
|
+
|
|
57
|
+
See [syntax.md](syntax.md) for the full YAML format: tag types, phases, data types, props, params, async data, and validation rules.
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
Start with the simplest example that matches your use case, then add complexity as needed:
|
|
62
|
+
|
|
63
|
+
| Example | Complexity | Key patterns |
|
|
64
|
+
| ------------------------------------------------------ | -------------- | ----------------------------------------------------------- |
|
|
65
|
+
| [mini-cart](examples/mini-cart.md) | Trivial | Variant + interactive refs |
|
|
66
|
+
| [cart-indicator](examples/cart-indicator.md) | Simple | Flat data, variants, phase choices |
|
|
67
|
+
| [category-list](examples/category-list.md) | Medium | Props, repeated sub-contracts |
|
|
68
|
+
| [product-card](examples/product-card.md) | Medium-complex | Linked sub-contracts, variants, multiple ref types |
|
|
69
|
+
| [product-page](examples/product-page.md) | Complex | Params, nested repeated sub-contracts, linked sub-contracts |
|
|
70
|
+
| [composing-contracts](examples/composing-contracts.md) | Pattern | How contracts link together into a hierarchy |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Headfull Component Contracts
|
|
2
|
+
|
|
3
|
+
Headfull components in Jay Stack are full-stack and must have a contract. The contract defines the data the component provides to its template.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use a headfull component contract for shared UI sections that appear across multiple pages: headers, footers, sidebars, navigation menus.
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
Each headfull component lives in its own subdirectory under `src/components/`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/components/site-header/
|
|
15
|
+
site-header.ts # makeJayStackComponent logic
|
|
16
|
+
site-header.jay-html # template
|
|
17
|
+
site-header.jay-contract # contract (required)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Contract with Props
|
|
21
|
+
|
|
22
|
+
Headfull components use `props` (not `params`) for configuration passed by the parent page:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
name: site-header
|
|
26
|
+
description: Site-wide header with navigation and cart indicator.
|
|
27
|
+
props:
|
|
28
|
+
- name: logoUrl
|
|
29
|
+
type: string
|
|
30
|
+
description: URL for the site logo
|
|
31
|
+
- name: showSearch
|
|
32
|
+
type: boolean
|
|
33
|
+
default: 'true'
|
|
34
|
+
description: Whether to show the search bar
|
|
35
|
+
tags:
|
|
36
|
+
- tag: siteName
|
|
37
|
+
type: data
|
|
38
|
+
dataType: string
|
|
39
|
+
phase: slow
|
|
40
|
+
- tag: navLinks
|
|
41
|
+
type: sub-contract
|
|
42
|
+
repeated: true
|
|
43
|
+
trackBy: _id
|
|
44
|
+
tags:
|
|
45
|
+
- tag: _id
|
|
46
|
+
type: data
|
|
47
|
+
dataType: string
|
|
48
|
+
- tag: label
|
|
49
|
+
type: data
|
|
50
|
+
dataType: string
|
|
51
|
+
- tag: navLink
|
|
52
|
+
type: interactive
|
|
53
|
+
elementType: HTMLAnchorElement
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Importing in jay-html
|
|
57
|
+
|
|
58
|
+
The import must include the `contract` attribute:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script
|
|
62
|
+
type="application/jay-headfull"
|
|
63
|
+
src="../components/site-header/site-header"
|
|
64
|
+
names="SiteHeader"
|
|
65
|
+
contract="../components/site-header/site-header.jay-contract"
|
|
66
|
+
></script>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Usage in the page body:
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<jay:SiteHeader logoUrl="/logo.png" />
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Component Contract vs Page Contract
|
|
76
|
+
|
|
77
|
+
| | Page contract | Component contract |
|
|
78
|
+
| ------------ | -------------------------------------- | -------------------------------------------------------------------- |
|
|
79
|
+
| **Location** | `src/pages/.../page.jay-contract` | `src/components/<name>/<name>.jay-contract` |
|
|
80
|
+
| **Params** | Yes (from route segments) | No (components don't own routes) |
|
|
81
|
+
| **Props** | Rarely | Yes (configured by parent) |
|
|
82
|
+
| **Import** | `<script type="application/jay-data">` | `<script type="application/jay-headfull">` with `contract` attribute |
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Example: Cart Indicator
|
|
2
|
+
|
|
3
|
+
A simple flat contract for a header widget. Shows phase choices and the difference between data, variant, and interactive tags.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: cart-indicator
|
|
7
|
+
description: Cart indicator showing item count, typically used in site header.
|
|
8
|
+
|
|
9
|
+
tags:
|
|
10
|
+
- tag: itemCount
|
|
11
|
+
type: data
|
|
12
|
+
dataType: number
|
|
13
|
+
phase: fast+interactive
|
|
14
|
+
description: Total number of items in cart
|
|
15
|
+
|
|
16
|
+
- tag: hasItems
|
|
17
|
+
type: variant
|
|
18
|
+
dataType: boolean
|
|
19
|
+
phase: fast+interactive
|
|
20
|
+
description: Whether cart has any items
|
|
21
|
+
|
|
22
|
+
- tag: cartButton
|
|
23
|
+
type: interactive
|
|
24
|
+
elementType: HTMLButtonElement
|
|
25
|
+
description: Button to open cart
|
|
26
|
+
|
|
27
|
+
- tag: cartLink
|
|
28
|
+
type: interactive
|
|
29
|
+
elementType: HTMLAnchorElement
|
|
30
|
+
description: Link to cart page
|
|
31
|
+
|
|
32
|
+
- tag: isLoading
|
|
33
|
+
type: variant
|
|
34
|
+
dataType: boolean
|
|
35
|
+
phase: fast+interactive
|
|
36
|
+
description: Whether cart data is loading
|
|
37
|
+
|
|
38
|
+
- tag: justAdded
|
|
39
|
+
type: variant
|
|
40
|
+
dataType: boolean
|
|
41
|
+
phase: fast+interactive
|
|
42
|
+
description: Briefly true after an item is added (for animation)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Why these choices
|
|
46
|
+
|
|
47
|
+
- **Everything is `fast+interactive`** — cart data is per-session (not build-time), and updates live when items are added.
|
|
48
|
+
- **`hasItems` is a variant, not computed from `itemCount`** — the template can use `if="hasItems"` directly without comparing numbers.
|
|
49
|
+
- **`justAdded` is a transient variant** — the component briefly sets it to true for CSS animation, then resets it.
|
|
50
|
+
- **Both `cartButton` and `cartLink`** — gives the designer flexibility to use either a button (opens mini-cart) or a link (navigates to cart page).
|
|
51
|
+
|
|
52
|
+
## Jay-HTML usage
|
|
53
|
+
|
|
54
|
+
```html
|
|
55
|
+
<div class="cart-indicator">
|
|
56
|
+
<a ref="cartLink" class="cart-icon">
|
|
57
|
+
<span if="hasItems" class="badge">{itemCount}</span>
|
|
58
|
+
</a>
|
|
59
|
+
</div>
|
|
60
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Example: Category List
|
|
2
|
+
|
|
3
|
+
A medium-complexity contract with props and a repeated sub-contract. Shows how to configure a component at design time.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: category-list
|
|
7
|
+
description: Displays store categories. Use for category navigation grids and menus.
|
|
8
|
+
props:
|
|
9
|
+
- name: parentCategory
|
|
10
|
+
type: string
|
|
11
|
+
description: Parent category slug. Only direct children of this category are shown.
|
|
12
|
+
tags:
|
|
13
|
+
- tag: categories
|
|
14
|
+
type: sub-contract
|
|
15
|
+
repeated: true
|
|
16
|
+
trackBy: _id
|
|
17
|
+
description: List of visible store categories
|
|
18
|
+
tags:
|
|
19
|
+
- tag: _id
|
|
20
|
+
type: data
|
|
21
|
+
dataType: string
|
|
22
|
+
|
|
23
|
+
- tag: name
|
|
24
|
+
type: data
|
|
25
|
+
dataType: string
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- tag: slug
|
|
29
|
+
type: data
|
|
30
|
+
dataType: string
|
|
31
|
+
|
|
32
|
+
- tag: description
|
|
33
|
+
type: data
|
|
34
|
+
dataType: string
|
|
35
|
+
|
|
36
|
+
- tag: productCount
|
|
37
|
+
type: data
|
|
38
|
+
dataType: number
|
|
39
|
+
|
|
40
|
+
- tag: imageUrl
|
|
41
|
+
type: data
|
|
42
|
+
dataType: string
|
|
43
|
+
meta: { mediaType: wix-image }
|
|
44
|
+
|
|
45
|
+
- tag: categoryLink
|
|
46
|
+
type: interactive
|
|
47
|
+
elementType: HTMLAnchorElement
|
|
48
|
+
|
|
49
|
+
- tag: hasCategories
|
|
50
|
+
type: variant
|
|
51
|
+
dataType: boolean
|
|
52
|
+
description: Whether there are any categories
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Why these choices
|
|
56
|
+
|
|
57
|
+
- **`props` instead of `params`** — this is a widget placed on a page, not a page itself. The parent decides which categories to show.
|
|
58
|
+
- **No explicit phases** — category data is static and available at all phases.
|
|
59
|
+
- **`trackBy: _id`** — each category has a stable GUID for efficient list diffing.
|
|
60
|
+
- **`hasCategories` variant** — lets the template show an empty state without checking array length.
|
|
61
|
+
- **`meta: { mediaType: wix-image }`** — tells validators this string is a Wix media URL.
|
|
62
|
+
|
|
63
|
+
## Jay-HTML usage
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<jay:category-list parentCategory="shop">
|
|
67
|
+
<div if="hasCategories" class="category-grid">
|
|
68
|
+
<div forEach="categories" trackBy="_id">
|
|
69
|
+
<a ref="categoryLink" class="category-card">
|
|
70
|
+
<img src="{imageUrl}" alt="{name}" />
|
|
71
|
+
<span>{name}</span>
|
|
72
|
+
<span class="count">({productCount})</span>
|
|
73
|
+
</a>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</jay:category-list>
|
|
77
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Example: Composing Contracts
|
|
2
|
+
|
|
3
|
+
How contracts link together into a reusable hierarchy. This example shows the wix-stores composition pattern.
|
|
4
|
+
|
|
5
|
+
## The Hierarchy
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
media.jay-contract ← Trivial: url + mediaType
|
|
9
|
+
↑
|
|
10
|
+
media-gallery.jay-contract ← Links to media, adds thumbnail navigation
|
|
11
|
+
↑
|
|
12
|
+
product-page.jay-contract ← Links to media-gallery, adds options, pricing
|
|
13
|
+
|
|
14
|
+
product-options.jay-contract ← Reusable option/choice structure
|
|
15
|
+
↑
|
|
16
|
+
product-card.jay-contract ← Links to product-options for quick-add
|
|
17
|
+
↑
|
|
18
|
+
product-search.jay-contract ← Links to product-card for search results
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Level 1: Leaf contract
|
|
22
|
+
|
|
23
|
+
The simplest building block. No sub-contracts, no links.
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
# media.jay-contract
|
|
27
|
+
name: media
|
|
28
|
+
description: Single media item.
|
|
29
|
+
tags:
|
|
30
|
+
- { tag: url, type: data, dataType: string, meta: { mediaType: wix-image } }
|
|
31
|
+
- { tag: mediaType, type: variant, dataType: 'enum (IMAGE | VIDEO)' }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Level 2: Composing leaves
|
|
35
|
+
|
|
36
|
+
Links to a leaf contract and adds its own structure.
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
# media-gallery.jay-contract
|
|
40
|
+
name: mediaGallery
|
|
41
|
+
description: Image/video gallery with thumbnail navigation.
|
|
42
|
+
tags:
|
|
43
|
+
- tag: selectedMedia
|
|
44
|
+
type: sub-contract
|
|
45
|
+
link: ./media
|
|
46
|
+
|
|
47
|
+
- tag: availableMedia
|
|
48
|
+
type: sub-contract
|
|
49
|
+
repeated: true
|
|
50
|
+
trackBy: mediaId
|
|
51
|
+
tags:
|
|
52
|
+
- { tag: mediaId, type: data }
|
|
53
|
+
- { tag: media, type: sub-contract, link: ./media }
|
|
54
|
+
- tag: selected
|
|
55
|
+
type: [variant, interactive]
|
|
56
|
+
dataType: enum(selected | notSelected)
|
|
57
|
+
elementType: HTMLImageElement | HTMLDivElement
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Level 3: Page contract composing everything
|
|
61
|
+
|
|
62
|
+
The product page links to the gallery (which links to media) and adds its own options, pricing, and actions.
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# product-page.jay-contract (abbreviated)
|
|
66
|
+
name: product-page
|
|
67
|
+
params:
|
|
68
|
+
slug: string
|
|
69
|
+
tags:
|
|
70
|
+
- { tag: productName, type: data, dataType: string }
|
|
71
|
+
- { tag: mediaGallery, type: sub-contract, phase: fast+interactive, link: ./media-gallery }
|
|
72
|
+
- { tag: price, type: data, dataType: string, phase: fast+interactive }
|
|
73
|
+
# ... options, actions, etc.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Parallel composition
|
|
77
|
+
|
|
78
|
+
The same `product-options.jay-contract` is linked by both the product page (inline options) and the product card (quick-add):
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
# In product-card.jay-contract
|
|
82
|
+
- { tag: quickOption, type: sub-contract, link: ./product-options }
|
|
83
|
+
# In product-page.jay-contract — options are defined inline because they have
|
|
84
|
+
# page-specific additions (text choice dropdown, modifier support)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## When to extract vs inline
|
|
88
|
+
|
|
89
|
+
| Extract into a linked file | Keep inline |
|
|
90
|
+
| ---------------------------------------------------------- | --------------------------------------- |
|
|
91
|
+
| Used by 2+ contracts | Used by only one contract |
|
|
92
|
+
| Complex enough to be its own concept (media, product-card) | Simple nested object (pricing, summary) |
|
|
93
|
+
| Has its own identity that designers/developers reference | Just a grouping of related fields |
|
|
94
|
+
|
|
95
|
+
## Benefits of composition
|
|
96
|
+
|
|
97
|
+
- **Single source of truth** — change `media.jay-contract` once, all galleries update
|
|
98
|
+
- **Readability** — each file stays focused on one concept
|
|
99
|
+
- **Reusability** — `product-card` is used in search, related products, and category pages
|
|
100
|
+
- **Independent testing** — each contract level can be validated independently
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Example: Mini Cart
|
|
2
|
+
|
|
3
|
+
A trivial contract with one variant and two interactive refs. Good starting point for understanding the basics.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: mini-cart
|
|
7
|
+
description: Drawer that auto-opens when a product is added to cart.
|
|
8
|
+
|
|
9
|
+
tags:
|
|
10
|
+
- tag: isOpen
|
|
11
|
+
type: variant
|
|
12
|
+
dataType: boolean
|
|
13
|
+
phase: fast+interactive
|
|
14
|
+
description: Whether the mini-cart drawer is currently open
|
|
15
|
+
|
|
16
|
+
- tag: openButton
|
|
17
|
+
type: interactive
|
|
18
|
+
elementType: HTMLButtonElement
|
|
19
|
+
description: Button to manually open the mini-cart drawer
|
|
20
|
+
|
|
21
|
+
- tag: closeButton
|
|
22
|
+
type: interactive
|
|
23
|
+
elementType: HTMLButtonElement
|
|
24
|
+
description: Button to close the mini-cart drawer
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Why these choices
|
|
28
|
+
|
|
29
|
+
- **`isOpen` is `fast+interactive`** — the drawer state starts on the server (closed) and toggles on the client.
|
|
30
|
+
- **Interactive tags have no explicit phase** — they're always `fast+interactive`.
|
|
31
|
+
- **No props or params** — the mini-cart doesn't need configuration and doesn't own a route.
|
|
32
|
+
|
|
33
|
+
## Jay-HTML usage
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<div class="mini-cart-overlay" if="isOpen">
|
|
37
|
+
<div class="mini-cart-drawer">
|
|
38
|
+
<button ref="closeButton">Close</button>
|
|
39
|
+
<!-- cart content here -->
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<button ref="openButton">Cart</button>
|
|
43
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Example: Product Card
|
|
2
|
+
|
|
3
|
+
A medium-complex contract designed as a reusable sub-contract. Shows linked sub-contracts, variants for conditional rendering, and multiple interactive element types.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: product-card
|
|
7
|
+
description: Single product card with image, price, and quick-add. Used in product grids and search results.
|
|
8
|
+
tags:
|
|
9
|
+
- { tag: _id, type: data, dataType: string }
|
|
10
|
+
- { tag: name, type: data, dataType: string, required: true }
|
|
11
|
+
- { tag: slug, type: data, dataType: string }
|
|
12
|
+
- { tag: productUrl, type: data, dataType: string }
|
|
13
|
+
- { tag: productLink, type: interactive, elementType: HTMLAnchorElement }
|
|
14
|
+
|
|
15
|
+
# Media — inline sub-contract for the card thumbnail
|
|
16
|
+
- tag: thumbnail
|
|
17
|
+
type: sub-contract
|
|
18
|
+
tags:
|
|
19
|
+
- { tag: url, type: data, dataType: string, meta: { mediaType: wix-image } }
|
|
20
|
+
- { tag: altText, type: data, dataType: string }
|
|
21
|
+
- { tag: width, type: data, dataType: number }
|
|
22
|
+
- { tag: height, type: data, dataType: number }
|
|
23
|
+
|
|
24
|
+
# Pricing — fast+interactive because it changes with variant selection
|
|
25
|
+
- { tag: price, type: data, dataType: string, phase: fast+interactive }
|
|
26
|
+
- { tag: strikethroughPrice, type: data, dataType: string, phase: fast+interactive }
|
|
27
|
+
- { tag: hasDiscount, type: variant, dataType: boolean }
|
|
28
|
+
|
|
29
|
+
# Inventory — inline sub-contract with enum variant
|
|
30
|
+
- tag: inventory
|
|
31
|
+
type: sub-contract
|
|
32
|
+
tags:
|
|
33
|
+
- tag: availabilityStatus
|
|
34
|
+
type: variant
|
|
35
|
+
dataType: enum (IN_STOCK | OUT_OF_STOCK | PARTIALLY_OUT_OF_STOCK)
|
|
36
|
+
|
|
37
|
+
# Quick-add — linked sub-contracts for option selection
|
|
38
|
+
- tag: quickAddType
|
|
39
|
+
type: variant
|
|
40
|
+
dataType: enum (SIMPLE | SINGLE_OPTION | COLOR_AND_TEXT_OPTIONS | NEEDS_CONFIGURATION)
|
|
41
|
+
|
|
42
|
+
- { tag: quickOption, type: sub-contract, link: ./product-options }
|
|
43
|
+
- { tag: secondQuickOption, type: sub-contract, link: ./product-options }
|
|
44
|
+
|
|
45
|
+
- { tag: addToCartButton, type: interactive, elementType: HTMLButtonElement }
|
|
46
|
+
- { tag: isAddingToCart, type: variant, dataType: boolean, phase: fast+interactive }
|
|
47
|
+
- { tag: cardContainer, type: interactive, elementType: HTMLElement }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Why these choices
|
|
51
|
+
|
|
52
|
+
- **No props or params** — this is a sub-contract, not a standalone component. Data flows from the parent (search results, related products).
|
|
53
|
+
- **`link: ./product-options`** — the option/choice structure is shared with the product page, so it's extracted into its own file.
|
|
54
|
+
- **`quickAddType` enum** — drives which quick-add UI to show. The designer uses `if="quickAddType===SIMPLE"` etc.
|
|
55
|
+
- **`cardContainer` is `HTMLElement`** — not a button or link, just a generic element for mouseenter preloading.
|
|
56
|
+
- **Inline `thumbnail` sub-contract** — only used here, so no need to extract.
|
|
57
|
+
|
|
58
|
+
## Jay-HTML usage
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<a ref="productLink" class="product-card" ref="cardContainer">
|
|
62
|
+
<img src="{thumbnail.url}" alt="{thumbnail.altText}" />
|
|
63
|
+
<h3>{name}</h3>
|
|
64
|
+
<div class="price">
|
|
65
|
+
<span if="hasDiscount" class="original">{strikethroughPrice}</span>
|
|
66
|
+
<span>{price}</span>
|
|
67
|
+
</div>
|
|
68
|
+
<button if="quickAddType===SIMPLE" ref="addToCartButton">Add to Cart</button>
|
|
69
|
+
</a>
|
|
70
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Example: Product Page
|
|
2
|
+
|
|
3
|
+
A complex page contract with params, nested repeated sub-contracts, linked sub-contracts, and multiple rendering phases.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
name: product-page
|
|
7
|
+
description: Full product detail page with variants, options, media gallery, and add-to-cart.
|
|
8
|
+
params:
|
|
9
|
+
slug: string
|
|
10
|
+
prefix: string?
|
|
11
|
+
category: string?
|
|
12
|
+
tags:
|
|
13
|
+
- { tag: _id, type: data, dataType: string }
|
|
14
|
+
- { tag: productName, type: data, dataType: string, required: true }
|
|
15
|
+
- { tag: description, type: data, dataType: html-string }
|
|
16
|
+
- { tag: brand, type: data, dataType: string }
|
|
17
|
+
- { tag: ribbon, type: data, dataType: string }
|
|
18
|
+
- { tag: productType, type: variant, dataType: 'enum (PHYSICAL | DIGITAL)' }
|
|
19
|
+
|
|
20
|
+
# Linked sub-contract for the media gallery
|
|
21
|
+
- tag: mediaGallery
|
|
22
|
+
type: sub-contract
|
|
23
|
+
phase: fast+interactive
|
|
24
|
+
link: ./media-gallery
|
|
25
|
+
|
|
26
|
+
# Pricing — per-variant, changes on client
|
|
27
|
+
- { tag: sku, type: data, dataType: string, phase: fast+interactive }
|
|
28
|
+
- { tag: price, type: data, dataType: string, phase: fast+interactive }
|
|
29
|
+
- { tag: strikethroughPrice, type: data, dataType: string, phase: fast+interactive }
|
|
30
|
+
- {
|
|
31
|
+
tag: stockStatus,
|
|
32
|
+
type: variant,
|
|
33
|
+
dataType: 'enum (OUT_OF_STOCK | IN_STOCK)',
|
|
34
|
+
phase: fast+interactive,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Quantity controls — dual-type tag (data + interactive)
|
|
38
|
+
- tag: quantity
|
|
39
|
+
type: sub-contract
|
|
40
|
+
tags:
|
|
41
|
+
- { tag: decrementButton, type: interactive, elementType: HTMLButtonElement }
|
|
42
|
+
- { tag: incrementButton, type: interactive, elementType: HTMLButtonElement }
|
|
43
|
+
- {
|
|
44
|
+
tag: quantity,
|
|
45
|
+
type: [data, interactive],
|
|
46
|
+
dataType: number,
|
|
47
|
+
elementType: HTMLInputElement,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Call to action
|
|
51
|
+
- { tag: addToCartButton, type: interactive, elementType: HTMLButtonElement, required: true }
|
|
52
|
+
- { tag: buyNowButton, type: interactive, elementType: HTMLButtonElement, required: true }
|
|
53
|
+
- { tag: actionsEnabled, type: variant, dataType: boolean, phase: fast+interactive }
|
|
54
|
+
|
|
55
|
+
# Options — nested repeated sub-contracts (options → choices)
|
|
56
|
+
- tag: options
|
|
57
|
+
type: sub-contract
|
|
58
|
+
repeated: true
|
|
59
|
+
trackBy: _id
|
|
60
|
+
tags:
|
|
61
|
+
- { tag: _id, type: data, dataType: string }
|
|
62
|
+
- { tag: name, type: data, dataType: string }
|
|
63
|
+
- {
|
|
64
|
+
tag: optionRenderType,
|
|
65
|
+
type: variant,
|
|
66
|
+
dataType: 'enum (TEXT_CHOICES | COLOR_SWATCH_CHOICES)',
|
|
67
|
+
}
|
|
68
|
+
- { tag: textChoice, type: interactive, elementType: HTMLSelectElement }
|
|
69
|
+
|
|
70
|
+
- tag: choices
|
|
71
|
+
type: sub-contract
|
|
72
|
+
repeated: true
|
|
73
|
+
trackBy: choiceId
|
|
74
|
+
tags:
|
|
75
|
+
- { tag: choiceId, type: data, dataType: string }
|
|
76
|
+
- { tag: name, type: data, dataType: string }
|
|
77
|
+
- { tag: colorCode, type: data, dataType: string }
|
|
78
|
+
- { tag: inStock, type: data, dataType: boolean }
|
|
79
|
+
- { tag: isSelected, type: variant, dataType: boolean, phase: fast+interactive }
|
|
80
|
+
- { tag: choiceButton, type: interactive, elementType: HTMLButtonElement }
|
|
81
|
+
|
|
82
|
+
# Info sections — repeated content blocks
|
|
83
|
+
- tag: infoSections
|
|
84
|
+
type: sub-contract
|
|
85
|
+
repeated: true
|
|
86
|
+
trackBy: _id
|
|
87
|
+
tags:
|
|
88
|
+
- { tag: _id, type: data, dataType: string }
|
|
89
|
+
- { tag: title, type: data, dataType: string }
|
|
90
|
+
- { tag: plainDescription, type: data, dataType: html-string }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Why these choices
|
|
94
|
+
|
|
95
|
+
- **`params`** — this is a page contract with dynamic route segments (`/products/[slug]`).
|
|
96
|
+
- **`link: ./media-gallery`** — the gallery is complex enough to warrant its own file and is reusable.
|
|
97
|
+
- **Options are inline** — despite being complex, they're specific to the product page and not reused elsewhere.
|
|
98
|
+
- **`html-string` for description** — the product description contains HTML formatting from the CMS.
|
|
99
|
+
- **`[data, interactive]` for quantity** — the input both displays the current value and accepts user input.
|
|
100
|
+
- **No phase on product name** — available at all phases (SSG, SSR, and client).
|
|
101
|
+
- **`fast+interactive` on pricing** — prices change when a variant is selected on the client.
|
|
102
|
+
- **Nested `repeated`** — options contain choices, both with their own `trackBy` for efficient diffing.
|
|
103
|
+
|
|
104
|
+
## Jay-HTML usage
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<h1>{productName}</h1>
|
|
108
|
+
<div class="price">
|
|
109
|
+
<span>{price}</span>
|
|
110
|
+
<span if="stockStatus===OUT_OF_STOCK" class="out-of-stock">Out of Stock</span>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div forEach="options" trackBy="_id">
|
|
114
|
+
<h3>{name}</h3>
|
|
115
|
+
<div if="optionRenderType===COLOR_SWATCH_CHOICES">
|
|
116
|
+
<div forEach="choices" trackBy="choiceId">
|
|
117
|
+
<button ref="choiceButton" style="background: {colorCode}" class="swatch" if="isSelected">
|
|
118
|
+
selected
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<button ref="addToCartButton">Add to Cart</button>
|
|
125
|
+
```
|