@homepages/template-kit 0.8.1-dev-20260718224903 → 0.9.0-dev-20260719224319
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/CHANGELOG.md +61 -1
- package/README.md +2 -2
- package/dist/canvas-core/chrome-css.d.ts +24 -0
- package/dist/canvas-core/chrome-css.js +403 -0
- package/dist/canvas-core/chrome.d.ts +49 -0
- package/dist/canvas-core/chrome.js +147 -0
- package/dist/canvas-core/frame.d.ts +20 -0
- package/dist/canvas-core/frame.js +23 -0
- package/dist/canvas-core/hidden-tabs.d.ts +16 -0
- package/dist/canvas-core/hidden-tabs.js +84 -0
- package/dist/canvas-core/resolve-target.js +55 -0
- package/dist/canvas-core/scroll.d.ts +10 -0
- package/dist/canvas-core/scroll.js +15 -0
- package/dist/canvas-core/section-dom.d.ts +6 -0
- package/dist/canvas-core/section-dom.js +43 -0
- package/dist/canvas-core/srcdoc.d.ts +8 -0
- package/dist/canvas-core/srcdoc.js +77 -0
- package/dist/canvas-core/types.d.ts +76 -0
- package/dist/canvas-core.d.ts +9 -0
- package/dist/canvas-core.js +9 -0
- package/dist/cli/check/css.js +2 -2
- package/dist/cli/check/loader.js +1 -1
- package/dist/cli/check/stages/deps.js +1 -1
- package/dist/cli/check/stages/render.js +3 -2
- package/dist/cli/check/stages/size.js +2 -2
- package/dist/cli/check/stages/tree.js +1 -1
- package/dist/cli/check/stages/validate/index.js +1 -1
- package/dist/cli/check/stages/validate/nav-contract.js +4 -3
- package/dist/cli/check/stages/validate/orchestrator.js +1 -1
- package/dist/cli/check/workspace.js +2 -2
- package/dist/cli/dev/build-css.js +1 -1
- package/dist/cli/dev/discover.js +2 -2
- package/dist/cli/dev/inspect.js +1 -1
- package/dist/cli/dev/island-bootstrap.js +1 -1
- package/dist/cli/dev/island-canvas-bootstrap.js +37 -5
- package/dist/cli/dev/section-page.js +1 -1
- package/dist/cli/dev/server.js +12 -5
- package/dist/cli/dev/tailwind.js +1 -1
- package/dist/cli/dev/tsconfig-paths-plugin.js +1 -1
- package/dist/cli/dev/workspace.js +2 -2
- package/dist/cli/link/index.js +1 -1
- package/dist/cli/link/overlay.js +1 -1
- package/dist/cli/new/emit.js +1 -1
- package/dist/cli/new/index.js +1 -1
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +4 -4
- package/dist/cli/new/scaffold-assets.js +2 -2
- package/dist/cli/pack/collect.js +1 -1
- package/dist/cli/pack/guards.js +1 -1
- package/dist/cli/pack/index.js +1 -1
- package/dist/cli/theme/generate.js +1 -1
- package/dist/cli/theme/load-theme.js +1 -1
- package/dist/dev-client/assets/index-CJa9G1Na.css +1 -0
- package/dist/dev-client/assets/index-C_1atZs4.js +450 -0
- package/dist/dev-client/index.html +2 -2
- package/dist/fixtures/sample-property.d.ts +4 -7
- package/dist/fixtures/sample-property.js +41 -97
- package/dist/fixtures/scenario.d.ts +1 -1
- package/dist/fixtures/scenarios/for-rent-condo.js +24 -44
- package/dist/fixtures/scenarios/luxury-multi-unit.js +1 -1
- package/dist/fixtures/scenarios/sparse-single-family.js +14 -26
- package/dist/fixtures.d.ts +2 -2
- package/dist/fixtures.js +1 -2
- package/dist/islands/client-directive.d.ts +7 -0
- package/dist/{eslint/is-client-file.js → islands/client-directive.js} +6 -3
- package/dist/islands/detect.d.ts +1 -1
- package/dist/islands/detect.js +1 -1
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.js +1 -1
- package/dist/manifest.json +940 -0
- package/dist/media/pack.d.ts +49 -0
- package/dist/media/pack.js +69 -0
- package/dist/media/resolve-fixture-media.js +73 -0
- package/dist/media/resolve-media.js +195 -0
- package/dist/package.js +1 -1
- package/dist/rules.d.ts +176 -0
- package/dist/rules.js +209 -0
- package/dist/schema/property-facts.d.ts +2 -2
- package/dist/ssr.d.ts +14 -2
- package/dist/ssr.js +28 -13
- package/dist/tokens.css +21 -0
- package/guide/INDEX.md +2 -2
- package/guide/check.md +5 -5
- package/guide/dev.md +39 -30
- package/guide/eslint.md +13 -10
- package/guide/llms.txt +4 -3
- package/guide/quickstart.md +1 -1
- package/guide/recipes/image-slot-crop.md +6 -6
- package/guide/recipes/pick-a-scenario.md +13 -5
- package/guide/rules/INDEX.md +3 -2
- package/guide/schema-system.md +36 -12
- package/guide/upgrading.md +18 -2
- package/package.json +8 -4
- package/tsconfig.json +1 -1
- package/dist/dev-client/assets/index-3Gn34X_P.js +0 -50
- package/dist/dev-client/assets/index-DxQeiHfu.css +0 -1
- package/dist/eslint/is-client-file.d.ts +0 -4
- package/dist/eslint/rules/image-bare-needs-reason.js +0 -43
- package/dist/eslint/rules/no-client-directive-in-contract.js +0 -31
- package/dist/eslint/rules/no-client-runtime-in-server.js +0 -103
- package/dist/eslint/rules/no-css-import-from-render-path.js +0 -29
- package/dist/eslint/rules/no-hex.js +0 -188
- package/dist/eslint/rules/no-inline-style.js +0 -27
- package/dist/eslint/rules/no-nondeterminism.js +0 -48
- package/dist/eslint/rules/no-raw-element.js +0 -38
- package/dist/eslint/rules/props-from-schema.js +0 -37
- package/dist/eslint/rules/require-island-editor.js +0 -74
- package/dist/eslint/rules/serializable-island-props.js +0 -112
- package/dist/eslint/rules/slot-marker-literal.js +0 -38
- package/dist/eslint.d.ts +0 -6
- package/dist/eslint.js +0 -80
- package/dist/rules/registry.js +0 -16
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
purpose: Source a fixture's slots from real property data, by the fill-by-source rule.
|
|
3
3
|
status: living
|
|
4
4
|
related: [../schema-system.md, fixture-states.md, ../vocabulary.md]
|
|
5
|
-
updated: 2026-07-
|
|
5
|
+
updated: 2026-07-19
|
|
6
6
|
---
|
|
7
7
|
# Pick a scenario for a fixture
|
|
8
8
|
|
|
@@ -59,7 +59,6 @@ nothing about the layout it's supposed to preview.
|
|
|
59
59
|
```ts
|
|
60
60
|
import {
|
|
61
61
|
contactCards,
|
|
62
|
-
mkResponsive,
|
|
63
62
|
poisByCategory,
|
|
64
63
|
primaryContact,
|
|
65
64
|
propertyMetrics,
|
|
@@ -75,7 +74,6 @@ const s = scenarios.luxuryMultiUnit;
|
|
|
75
74
|
| `contactCards(s)` | Every attached contact, in order (`ContactFixture[]`) |
|
|
76
75
|
| `poisByCategory(s)` | The scenario's POIs bucketed by category (`Record<PoiFixture["category"], PoiFixture[]>`) |
|
|
77
76
|
| `propertyMetrics(s)` | `beds`/`baths`/`sqft`/`price` off the lowest-position unit, `bedsMin`/`bedsMax`/`bathsMin`/`bathsMax`/`sqftMax`/`priceStart` across all units, and `addressLine1`/`addressLine2` |
|
|
78
|
-
| `mkResponsive(url, width, height)` | A deterministic `ResponsiveImage` descriptor so `<Image responsive>` can be previewed and snapshotted |
|
|
79
77
|
|
|
80
78
|
`propertyMetrics` returns kit fact vocabulary — `addressLine1`/`addressLine2`, not a
|
|
81
79
|
template's own slot names, so the kit never learns what a section calls its slots. Map
|
|
@@ -90,10 +88,20 @@ address_locality: m.addressLine2,
|
|
|
90
88
|
|
|
91
89
|
Fields the helpers don't cover are readable straight off the scenario: `s.photos`,
|
|
92
90
|
`s.pois`, `s.amenities`, `s.contacts`, `s.media`, and `s.facts` (the raw
|
|
93
|
-
`PropertyFacts`). A contact's org name and logos (`
|
|
94
|
-
`ContactFixture["fields"]`, not on a sibling "brand" object — read them off
|
|
91
|
+
`PropertyFacts`). A contact's org name and logos (`logo_light_id`/`logo_dark_id`) live
|
|
92
|
+
on `ContactFixture["fields"]`, not on a sibling "brand" object — read them off
|
|
95
93
|
`primaryContact(s).fields` or `s.contacts`.
|
|
96
94
|
|
|
95
|
+
### Media comes off the scenario as an id
|
|
96
|
+
|
|
97
|
+
Every media reference in a scenario is an **asset id**, the same thing a saved page
|
|
98
|
+
holds — `s.photos[n].id`, `primaryContact(s).fields.headshot_id` / `.logo_light_id` /
|
|
99
|
+
`.logo_dark_id`, `s.media.video_id`, and a floor plan ref's `id`. Put the id in the
|
|
100
|
+
fixture and stop there: the url, the `alt` fallback, and the responsive ladder are
|
|
101
|
+
attached for you when the fixture loads. Never state a url in a fixture.
|
|
102
|
+
(`s.media.tour_3d_url` is the one exception — a 3D tour is a third-party embed with no
|
|
103
|
+
asset behind it.)
|
|
104
|
+
|
|
97
105
|
### Add a scenario-driven state
|
|
98
106
|
|
|
99
107
|
A `states` entry designed to look different against a sparser property sources from a
|
package/guide/rules/INDEX.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
purpose: Router for the rule corpus — every template-kit/<id> an author can hit, and the page that explains it.
|
|
3
3
|
status: living
|
|
4
4
|
related: [server-vs-client.md, ../eslint.md, ../check.md, ../INDEX.md]
|
|
5
|
-
updated: 2026-07-
|
|
5
|
+
updated: 2026-07-19
|
|
6
6
|
---
|
|
7
7
|
# Rules
|
|
8
8
|
|
|
@@ -10,7 +10,8 @@ Every authoring rule the kit enforces is printed under one namespace, `template-
|
|
|
10
10
|
and resolves to exactly one page here: `guide/rules/<id>.md`.
|
|
11
11
|
|
|
12
12
|
**One namespace, two venues.** Some rules are properties of **one file** (a `Date.now()`
|
|
13
|
-
in a Renderer) and are enforced by the ESLint preset.
|
|
13
|
+
in a Renderer) and are enforced by the [ESLint preset](../eslint.md), which ships as its
|
|
14
|
+
own package, `@homepages/eslint-plugin-template`. Others are properties of the
|
|
14
15
|
**tree** (a slot declared in `schema.ts` but never marked in the JSX, a stylesheet, a
|
|
15
16
|
dependency, a byte budget) and cannot be expressed one file at a time; those are enforced
|
|
16
17
|
by [`template-kit check`](../check.md). You never need to know which engine produced a
|
package/guide/schema-system.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
purpose: The section authoring contract — schema.ts, fill-spec.ts, fixtures.ts, and the closed source/transform vocabulary.
|
|
3
3
|
status: living
|
|
4
4
|
related: [primitives.md, theme-and-css.md, vocabulary.md, recipes/pick-a-scenario.md]
|
|
5
|
-
updated: 2026-07-
|
|
5
|
+
updated: 2026-07-19
|
|
6
6
|
---
|
|
7
7
|
# The schema system
|
|
8
8
|
|
|
@@ -229,12 +229,16 @@ headline, an empty list).
|
|
|
229
229
|
|
|
230
230
|
```ts
|
|
231
231
|
import type { FixtureModule } from "@homepages/template-kit";
|
|
232
|
+
import { scenarios } from "@homepages/template-kit/fixtures";
|
|
232
233
|
|
|
233
234
|
const fixtures: FixtureModule = {
|
|
234
235
|
base: {
|
|
235
236
|
slots: {
|
|
236
237
|
headline: "101 Queensway, Jamaica Plain, MA 02130",
|
|
237
|
-
|
|
238
|
+
// An image slot states the asset id a real page holds — never a URL. The
|
|
239
|
+
// preview server resolves it to a url, an alt fallback, and a responsive
|
|
240
|
+
// ladder, exactly as the platform does when the page is published.
|
|
241
|
+
hero_image: { photo_id: scenarios.luxuryMultiUnit.photos[19]!.id, alt: "Front elevation" },
|
|
238
242
|
blurb: "A bright corner home moments from the Emerald Necklace.",
|
|
239
243
|
},
|
|
240
244
|
options: { align: "center" },
|
|
@@ -255,7 +259,7 @@ contacts, the cases that actually break a layout. Pick the one whose breadth mat
|
|
|
255
259
|
state you're exercising:
|
|
256
260
|
|
|
257
261
|
```ts
|
|
258
|
-
import { scenarios, primaryContact, poisByCategory, propertyMetrics, contactCards
|
|
262
|
+
import { scenarios, primaryContact, poisByCategory, propertyMetrics, contactCards }
|
|
259
263
|
from "@homepages/template-kit/fixtures";
|
|
260
264
|
|
|
261
265
|
const s = scenarios.luxuryMultiUnit; // or sparseSingleFamily / forRentCondo
|
|
@@ -298,7 +302,6 @@ wants, without re-typing the scenario's data:
|
|
|
298
302
|
| `contactCards(s)` | Every attached contact, in order (`ContactFixture[]`) |
|
|
299
303
|
| `poisByCategory(s)` | The scenario's POIs bucketed by category (`Record<PoiFixture["category"], PoiFixture[]>`) |
|
|
300
304
|
| `propertyMetrics(s)` | Beds/baths/sqft/price off the lowest-position unit, `*Min`/`*Max`/`priceStart` across all units, and `addressLine1`/`addressLine2` |
|
|
301
|
-
| `mkResponsive(url, width, height)` | Synthesizes a deterministic `ResponsiveImage` descriptor so `<Image responsive>` can be previewed and snapshotted |
|
|
302
305
|
|
|
303
306
|
`propertyMetrics` returns kit fact vocabulary — `addressLine1`/`addressLine2`, never a
|
|
304
307
|
template's own slot names, so the kit never learns what a section calls its slots. Map it
|
|
@@ -307,8 +310,29 @@ to your slots at the call site: `address_street: m.addressLine1`.
|
|
|
307
310
|
`s.photos`, `s.pois`, `s.amenities`, `s.contacts`, `s.media`, and `s.facts`
|
|
308
311
|
(the raw `PropertyFacts`) are also readable straight off the scenario for slots that don't
|
|
309
312
|
need a helper's projection — a gallery slot can bind directly to `s.photos`. A contact's
|
|
310
|
-
org name and logos (`
|
|
311
|
-
a sibling "brand" object — read them off `primaryContact(s).fields` or
|
|
313
|
+
org name and logos (`logo_light_id`/`logo_dark_id`) live on `ContactFixture["fields"]`,
|
|
314
|
+
not on a sibling "brand" object — read them off `primaryContact(s).fields` or
|
|
315
|
+
`s.contacts`.
|
|
316
|
+
|
|
317
|
+
### Media is stated by id, never by URL
|
|
318
|
+
|
|
319
|
+
A fixture's job is to state what a **saved page** holds, and a saved page holds an
|
|
320
|
+
asset id — the platform turns that id into a served URL at render time. So a fixture
|
|
321
|
+
does the same: give an image slot a `photo_id` (a video slot a `video_id`), and the
|
|
322
|
+
url, the `alt` fallback, and the responsive ladder are attached for you when the
|
|
323
|
+
fixture loads, in the preview server and in `check` alike. A fixture that states a
|
|
324
|
+
URL is exercising a path real content never takes.
|
|
325
|
+
|
|
326
|
+
The ids to use are the scenario's own: `s.photos[n].id` for a photo,
|
|
327
|
+
`primaryContact(s).fields.headshot_id` / `.logo_light_id` / `.logo_dark_id` for a
|
|
328
|
+
contact's images, `s.media.video_id` for the hosted video. `s.media.tour_3d_url`
|
|
329
|
+
stays a URL on purpose — a 3D tour is a third-party embed the platform does not host,
|
|
330
|
+
so there is no asset to name. Floor plan refs
|
|
331
|
+
(`s.facts.units[*].floor_plans`) likewise carry only `id`/`floor_label`/`position`;
|
|
332
|
+
their `url`, `alt`, and `responsive` are optional and appear only after resolution.
|
|
333
|
+
|
|
334
|
+
An id that names nothing resolves to an empty image, which previews as an empty slot
|
|
335
|
+
rather than an error — so take the ids off the scenario rather than typing them.
|
|
312
336
|
|
|
313
337
|
See [Pick a scenario](recipes/pick-a-scenario.md) for the full picker and helper
|
|
314
338
|
cheat-sheet.
|
|
@@ -318,14 +342,14 @@ cheat-sheet.
|
|
|
318
342
|
A scenario is the **fixture view** of a property, not the fact bundle the AI-fill pipeline
|
|
319
343
|
reads. The difference matters when you write a `fill-spec.ts`:
|
|
320
344
|
|
|
321
|
-
- Scenarios carry values that only exist *after* fill
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
something real to draw.
|
|
345
|
+
- Scenarios carry values that only exist *after* fill — `UnitRow.description` and
|
|
346
|
+
`features` are AI-written copy. Nothing upstream produces these; they are here so your
|
|
347
|
+
renderer has something real to draw.
|
|
325
348
|
- Scenarios hoist some facts **out** of `facts` and onto the scenario itself, in the shapes
|
|
326
349
|
a renderer wants: `photos` → `s.photos` (`PhotoFixture[]`), `pois` → `s.pois`
|
|
327
|
-
(`PoiFixture[]`), and the fact bundle's `tours` → `s.media` — a
|
|
328
|
-
|
|
350
|
+
(`PoiFixture[]`), and the fact bundle's hosted videos and `tours` → `s.media` — a
|
|
351
|
+
single `MediaFixture` **object**, not an array: `video_id` names one hosted video
|
|
352
|
+
asset, `tour_3d_url` the third-party embed link. Floor plans hoist too, but onto
|
|
329
353
|
each unit: `s.facts.units[*].floor_plans` (`FloorplanAssignment[]`).
|
|
330
354
|
- `contacts` is **duplicated, not hoisted**. `s.contacts` holds the render-shaped
|
|
331
355
|
`ContactFixture[]` your renderer draws, and `facts.contacts` still exists as well — so a
|
package/guide/upgrading.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
purpose: How to move a workspace to a new template-kit version, and what each kind of release means for you.
|
|
3
3
|
status: living
|
|
4
|
-
related: [check.md, pack.md, overview.md]
|
|
5
|
-
updated: 2026-07-
|
|
4
|
+
related: [check.md, pack.md, overview.md, eslint.md]
|
|
5
|
+
updated: 2026-07-19
|
|
6
6
|
---
|
|
7
7
|
# Upgrading the kit
|
|
8
8
|
|
|
@@ -43,6 +43,20 @@ npm run check
|
|
|
43
43
|
CHANGELOG in the package (`node_modules/@homepages/template-kit/CHANGELOG.md`) for
|
|
44
44
|
what changed and why.
|
|
45
45
|
|
|
46
|
+
## The lint preset upgrades separately
|
|
47
|
+
|
|
48
|
+
`@homepages/eslint-plugin-template` is its own package with its own version line,
|
|
49
|
+
so the kit's number tells you nothing about it and `npm update
|
|
50
|
+
@homepages/template-kit` never moves it. Update it the same way, on its own:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm update @homepages/eslint-plugin-template
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
It declares the kit as a **peer dependency**, so its range says which kit line it
|
|
57
|
+
supports. If `npm install` reports a peer conflict after a kit minor, the preset is
|
|
58
|
+
the package to bump — not the kit to hold back.
|
|
59
|
+
|
|
46
60
|
## How long you have
|
|
47
61
|
|
|
48
62
|
Submissions are accepted against the current kit line **and the one before it**.
|
|
@@ -59,3 +73,5 @@ message.
|
|
|
59
73
|
npm ls @homepages/template-kit # what you have installed
|
|
60
74
|
npm view @homepages/template-kit version # the current release
|
|
61
75
|
```
|
|
76
|
+
|
|
77
|
+
The same two commands work for `@homepages/eslint-plugin-template`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homepages/template-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-dev-20260719224319",
|
|
4
4
|
"description": "Authoring kit for HomePages marketing-section templates: schema system, contract primitives, theme tokens, and the template-kit CLI.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -46,9 +46,13 @@
|
|
|
46
46
|
"types": "./dist/ssr.d.ts",
|
|
47
47
|
"default": "./dist/ssr.js"
|
|
48
48
|
},
|
|
49
|
-
"./
|
|
50
|
-
"types": "./dist/
|
|
51
|
-
"default": "./dist/
|
|
49
|
+
"./rules": {
|
|
50
|
+
"types": "./dist/rules.d.ts",
|
|
51
|
+
"default": "./dist/rules.js"
|
|
52
|
+
},
|
|
53
|
+
"./canvas-core": {
|
|
54
|
+
"types": "./dist/canvas-core.d.ts",
|
|
55
|
+
"default": "./dist/canvas-core.js"
|
|
52
56
|
},
|
|
53
57
|
"./styles.css": "./dist/styles.css",
|
|
54
58
|
"./base.css": "./dist/base.css",
|
package/tsconfig.json
CHANGED