@homepages/template-kit 0.3.0 → 0.4.0

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 (111) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +39 -4
  3. package/dist/asset-modules.d.ts +81 -0
  4. package/dist/cli/check/config.js +5 -1
  5. package/dist/cli/check/css.js +27 -13
  6. package/dist/cli/check/loader.js +4 -0
  7. package/dist/cli/check/section-assets.js +58 -0
  8. package/dist/cli/check/stages/size.js +124 -8
  9. package/dist/cli/check/stages/tree.js +26 -27
  10. package/dist/cli/dev/build-css.js +91 -0
  11. package/dist/cli/dev/catalog.js +35 -0
  12. package/dist/cli/dev/compose-template.js +38 -0
  13. package/dist/cli/dev/content-override.js +58 -0
  14. package/dist/cli/dev/discover.js +35 -0
  15. package/dist/cli/dev/fill-state.js +75 -0
  16. package/dist/cli/dev/index.js +32 -0
  17. package/dist/cli/dev/inspect.js +38 -0
  18. package/dist/cli/dev/island-bootstrap.js +38 -0
  19. package/dist/cli/dev/island-map.js +35 -0
  20. package/dist/cli/dev/island-transform.js +31 -0
  21. package/dist/cli/dev/manifest-instances.js +31 -0
  22. package/dist/cli/dev/render-section.js +24 -0
  23. package/dist/cli/dev/screenshot-target.js +24 -0
  24. package/dist/cli/dev/section-page.js +54 -0
  25. package/dist/cli/dev/server.js +480 -0
  26. package/dist/cli/dev/slot-schema.js +12 -0
  27. package/dist/cli/dev/structure-summary.js +118 -0
  28. package/dist/cli/dev/tailwind.js +32 -0
  29. package/dist/cli/dev/vite-server.js +33 -0
  30. package/dist/cli/dev/workspace.js +63 -0
  31. package/dist/cli/link/index.js +74 -0
  32. package/dist/cli/link/overlay.js +59 -0
  33. package/dist/cli/link/watch.js +25 -0
  34. package/dist/cli/new/emit.js +48 -0
  35. package/dist/cli/new/index.js +69 -0
  36. package/dist/cli/new/scaffold/section/_Renderer.tsx +20 -0
  37. package/dist/cli/new/scaffold/section/_fill-spec.ts +18 -0
  38. package/dist/cli/new/scaffold/section/_fixtures.ts +13 -0
  39. package/dist/cli/new/scaffold/section/_schema.ts +24 -0
  40. package/dist/cli/new/scaffold/template/_manifest.json +9 -0
  41. package/dist/cli/new/scaffold/template/sections/hero/ExpandableText.tsx +45 -0
  42. package/dist/cli/new/scaffold/template/sections/hero/Renderer.tsx +40 -0
  43. package/dist/cli/new/scaffold/template/sections/hero/components/Feature.tsx +14 -0
  44. package/dist/cli/new/scaffold/template/sections/hero/fill-spec.ts +29 -0
  45. package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +41 -0
  46. package/dist/cli/new/scaffold/template/sections/hero/schema.ts +60 -0
  47. package/dist/cli/new/scaffold/template/theme.css +24 -0
  48. package/dist/cli/new/scaffold/template/theme.ts +27 -0
  49. package/dist/cli/new/scaffold-assets.js +20 -0
  50. package/dist/cli/pack/collect.js +44 -0
  51. package/dist/cli/pack/guards.js +57 -0
  52. package/dist/cli/pack/index.js +66 -0
  53. package/dist/cli/pack/manifest.js +15 -0
  54. package/dist/cli/pack/zip.js +86 -0
  55. package/dist/cli.js +80 -14
  56. package/dist/dev-client/assets/index-DfEfrp6P.css +1 -0
  57. package/dist/dev-client/assets/index-bpMP0b0W.js +50 -0
  58. package/dist/dev-client/index.html +13 -0
  59. package/dist/eslint/is-client-file.d.ts +4 -0
  60. package/dist/index.d.ts +1 -0
  61. package/dist/islands/detect.d.ts +16 -0
  62. package/dist/islands/detect.js +22 -0
  63. package/dist/islands/discover.d.ts +5 -0
  64. package/dist/islands/discover.js +19 -0
  65. package/dist/islands/esbuild-plugin.d.ts +13 -0
  66. package/dist/islands/esbuild-plugin.js +39 -0
  67. package/dist/islands/wrap.d.ts +11 -0
  68. package/dist/islands/wrap.js +48 -0
  69. package/dist/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +77 -0
  70. package/dist/node_modules/magic-string/dist/magic-string.es.js +939 -0
  71. package/dist/package.js +1 -1
  72. package/dist/ssr.d.ts +31 -0
  73. package/dist/ssr.js +46 -0
  74. package/docs/INDEX.md +9 -1
  75. package/docs/assets.md +128 -0
  76. package/docs/check.md +6 -3
  77. package/docs/dev.md +187 -0
  78. package/docs/islands.md +5 -2
  79. package/docs/llms.txt +41 -3
  80. package/docs/new.md +27 -0
  81. package/docs/overview.md +57 -0
  82. package/docs/pack.md +46 -0
  83. package/docs/primitives.md +5 -6
  84. package/docs/quickstart.md +102 -0
  85. package/docs/recipes/INDEX.md +27 -0
  86. package/docs/recipes/bind-property-fact.md +58 -0
  87. package/docs/recipes/collection-slot.md +100 -0
  88. package/docs/recipes/fill-spec-decision.md +66 -0
  89. package/docs/recipes/fixture-states.md +68 -0
  90. package/docs/recipes/image-slot-crop.md +98 -0
  91. package/docs/recipes/interactive-island.md +100 -0
  92. package/docs/recipes/organize-section-folder.md +72 -0
  93. package/docs/recipes/prepare-submission.md +55 -0
  94. package/docs/recipes/second-template.md +49 -0
  95. package/docs/recipes/select-slot.md +59 -0
  96. package/docs/recipes/static-asset.md +103 -0
  97. package/docs/recipes/third-party-package.md +90 -0
  98. package/docs/rules/INDEX.md +4 -2
  99. package/docs/rules/bundle-binary-asset.md +33 -52
  100. package/docs/rules/bundle-incomplete.md +2 -2
  101. package/docs/rules/css-reason.md +3 -3
  102. package/docs/rules/no-bare-css-import.md +8 -8
  103. package/docs/rules/no-css-import-from-render-path.md +7 -8
  104. package/docs/rules/size-assets.md +88 -0
  105. package/docs/rules/size-island-bundle.md +123 -0
  106. package/docs/rules/size-section-css.md +19 -14
  107. package/docs/schema-system.md +28 -28
  108. package/docs/theme-and-css.md +2 -2
  109. package/docs/vocabulary.md +98 -0
  110. package/package.json +11 -3
  111. package/tsconfig.json +1 -1
@@ -177,8 +177,8 @@ never write an import to make either happen:
177
177
  template's own hand-written stylesheet is collected the same way, into
178
178
  `@layer template`.
179
179
  2. **Package CSS, harvested from the render path.** The build also bundles
180
- `Renderer.tsx`'s module graph — and any component that carries `export const
181
- enhancer` — and pulls in whatever `.css` those imports resolve to. A bare specifier
180
+ `Renderer.tsx`'s module graph — every component and island it imports and pulls in
181
+ whatever `.css` those imports resolve to. A bare specifier
182
182
  (`import "swiper/css";`) resolves into `node_modules` and lands in the same
183
183
  `@layer sections`; that is the sanctioned way for a third-party package's
184
184
  stylesheet to reach the page.
@@ -0,0 +1,98 @@
1
+ ---
2
+ purpose: The closed authoring vocabulary — slot types, direct() sources, derived() transforms, with selection semantics.
3
+ status: living
4
+ related: [schema-system.md]
5
+ updated: 2026-07-15
6
+ ---
7
+ # The closed authoring vocabulary
8
+
9
+ Three closed sets. A slot's `type` picks its runtime value shape; a slot's
10
+ `source` (`direct()` or `derived()`) picks which fact or computation fills it.
11
+ This page is a selection reference — *which one to pick* — not a restatement
12
+ of their field shapes.
13
+
14
+ ## Slot types
15
+
16
+ | type | runtime value shape | pick it when |
17
+ |---|---|---|
18
+ | `text` | `string` (`string \| null` if optional) | one editable line/paragraph (`size` short\|medium\|long) |
19
+ | `number` | `number` (`number \| null` if optional) | a numeric fact with formatting |
20
+ | `select` | `string` (`string \| null` if optional) | a closed set of choices the user picks from |
21
+ | `image` | `ImageValue` (`ImageValue \| null` if optional) | one framed photo (add `crop`/`frame`) |
22
+ | `image_collection` | `ImageCollectionValue` | a gallery of framed photos |
23
+ | `list` | `string[]` for a `text` element, `unknown[]` otherwise | a flat list of scalar items |
24
+ | `poi_list` | `PoiRow[]` | neighborhood points of interest |
25
+ | `url` | `string` (`string \| null` if optional) | a link the user edits in a URL field |
26
+ | `object_list` | `Record<string, unknown>[]` | repeating, independently-editable multi-field items |
27
+
28
+ The full per-type field shapes live in your editor's autocomplete and
29
+ [schema-system.md](schema-system.md) — this page is only *which to pick*.
30
+
31
+ ## `direct()` sources
32
+
33
+ The property facts a slot binds verbatim. A bad name is a compile error at
34
+ the `direct(...)` call site.
35
+
36
+ **Property facts** (resolve once per property):
37
+ - `address` — the full formatted address
38
+ - `listing_intent` — for-sale vs. for-rent state
39
+ - `status` — the listing status, free text as shown on the listing (e.g. "For Sale")
40
+ - `property_type` — the property type (`single_family` \| `condo_townhome` \| `multi_family` \| `investment`)
41
+ - `year_built` — the year the property was built
42
+ - `lot_size` — the lot size, pre-formatted text
43
+
44
+ **Per-unit facts** (resolve against the current/single unit row):
45
+ - `unit_label` — the unit's display label (e.g. "Unit 3B")
46
+ - `beds` — bedroom count for this unit
47
+ - `baths` — bathroom count for this unit
48
+ - `sqft` — square footage for this unit
49
+ - `price` — this unit's price, pre-formatted text
50
+ - `notes` — free-text notes on this unit
51
+
52
+ **List sources** (bind the whole array verbatim — pick these for `object_list`
53
+ slots that repeat over every row):
54
+ - `units` — every unit row on the property
55
+ - `contacts` — every contact attached to the section
56
+
57
+ **Per-contact fields** (resolve against the attached contact):
58
+ - `name` — the contact's display name
59
+ - `title` — the contact's job title/role
60
+ - `bio` — the contact's bio copy
61
+ - `email` — the contact's email address
62
+ - `phone` — the contact's phone number
63
+ - `website` — the contact's website URL
64
+ - `instagram` — the contact's Instagram handle/URL
65
+ - `linkedin` — the contact's LinkedIn handle/URL
66
+ - `x` — the contact's X (Twitter) handle/URL
67
+ - `facebook` — the contact's Facebook handle/URL
68
+
69
+ **Contact images** (bind only to `image` slots):
70
+ - `headshot` — the contact's headshot photo
71
+ - `logo_dark` — the contact's logo, dark-background variant
72
+ - `logo_light` — the contact's logo, light-background variant
73
+
74
+ ## `derived()` transforms
75
+
76
+ Computed values, grouped by family. A bad name is a compile error at the
77
+ `derived(...)` call site.
78
+
79
+ | transform | what it computes |
80
+ |---|---|
81
+ | `units.bedsPrimary` | beds of the primary (lowest-position) unit |
82
+ | `units.bathsPrimary` | baths of the primary unit |
83
+ | `units.sqftPrimary` | sqft of the primary unit |
84
+ | `units.pricePrimary` | price of the primary unit, pre-formatted text |
85
+ | `units.bedsRange` | formatted beds range across all units (e.g. "2–4"), collapsing to one value when uniform |
86
+ | `units.priceStart` | the lowest numeric unit price; falls back to the first non-numeric price (e.g. "Sold") when none is numeric |
87
+ | `units.bedsMin` | the minimum beds across all units, formatted |
88
+ | `units.bedsMax` | the maximum beds across all units, formatted |
89
+ | `units.bathsMin` | the minimum baths across all units, formatted |
90
+ | `units.bathsMax` | the maximum baths across all units, formatted |
91
+ | `units.sqftMax` | the maximum sqft across all units, formatted |
92
+ | `address.line1` | the property address's street line |
93
+ | `address.line2` | the property address's city/state/zip line |
94
+ | `contact_address.line1` | a contact's address street line |
95
+ | `contact_address.line2` | a contact's address city/state/zip line |
96
+ | `clock.currentYear` | the current year (e.g. for a copyright line) |
97
+ | `coordinate.lat` | latitude, split from the property's geocode |
98
+ | `coordinate.lng` | longitude, split from the property's geocode |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homepages/template-kit",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
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",
@@ -41,6 +41,10 @@
41
41
  "types": "./dist/browser.d.ts",
42
42
  "default": "./dist/browser.js"
43
43
  },
44
+ "./ssr": {
45
+ "types": "./dist/ssr.d.ts",
46
+ "default": "./dist/ssr.js"
47
+ },
44
48
  "./eslint": {
45
49
  "types": "./dist/eslint.d.ts",
46
50
  "default": "./dist/eslint.js"
@@ -55,7 +59,7 @@
55
59
  ],
56
60
  "scripts": {
57
61
  "prepack": "npm run build",
58
- "build": "tsdown",
62
+ "build": "tsdown && node scripts/build-dev-client.mjs && node scripts/build-cli-assets.mjs",
59
63
  "typecheck": "tsc --noEmit",
60
64
  "lint": "eslint .",
61
65
  "pretest": "node test/link-fixture-workspace.mjs",
@@ -75,12 +79,15 @@
75
79
  "@arethetypeswrong/cli": "^0.18.5",
76
80
  "@changesets/cli": "^2.29.8",
77
81
  "@eslint/js": "^9.39.4",
82
+ "@playwright/test": "^1.60.0",
78
83
  "@tailwindcss/cli": "^4.3.0",
79
84
  "@types/jsdom": "^21.1.7",
80
85
  "@types/node": "^20.17.10",
81
86
  "@types/react": "^19.0.0",
82
87
  "@types/react-dom": "^19.0.0",
83
88
  "@typescript-eslint/parser": "^8.60.1",
89
+ "@vitejs/plugin-react": "^4.3.4",
90
+ "chokidar": "^4.0.1",
84
91
  "esbuild": "^0.28.1",
85
92
  "eslint": "^9.39.4",
86
93
  "jsdom": "^26.1.0",
@@ -91,7 +98,8 @@
91
98
  "tsdown": "0.22.7",
92
99
  "tsx": "^4.19.2",
93
100
  "typescript": "^5.7.2",
94
- "typescript-eslint": "^8.60.1"
101
+ "typescript-eslint": "^8.60.1",
102
+ "vite": "^6.0.5"
95
103
  },
96
104
  "dependencies": {
97
105
  "zod": "^4.4.3"
package/tsconfig.json CHANGED
@@ -3,5 +3,5 @@
3
3
  "compilerOptions": {
4
4
  "noEmit": true
5
5
  },
6
- "exclude": ["node_modules", "dist", ".tmp-consumer", "test/fixtures"]
6
+ "exclude": ["node_modules", "dist", ".tmp-consumer", "test/fixtures", "create-homepages-workspace"]
7
7
  }