assign-gingerly 0.0.53 → 0.0.55
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/README.md +847 -5
- package/assignFrom.js +229 -9
- package/assignFrom.ts +338 -9
- package/assignGingerly.js +34 -1
- package/assignGingerly.ts +54 -1
- package/beVigilant.js +73 -0
- package/beVigilant.ts +85 -0
- package/enhanceAll.js +106 -0
- package/enhanceAll.ts +138 -0
- package/handlers/join.js +74 -0
- package/handlers/join.ts +80 -0
- package/handlers/lazyLoad.js +212 -0
- package/handlers/lazyLoad.ts +307 -0
- package/handlers/lazyLoadSwitch.js +58 -0
- package/handlers/lazyLoadSwitch.ts +63 -0
- package/handlers/microDataJoin.js +184 -0
- package/handlers/microDataJoin.ts +270 -0
- package/inferencer/.gitmodules +3 -0
- package/inferencer/.vscode/settings.json +2 -0
- package/inferencer/InferencedPropagator.js +230 -0
- package/inferencer/InferencedPropagator.ts +269 -0
- package/inferencer/LICENSE +21 -0
- package/inferencer/README.md +524 -0
- package/inferencer/Requirements/SupportForPropagator.md +368 -0
- package/inferencer/imports.html +7 -0
- package/inferencer/inferencer.js +254 -0
- package/inferencer/inferencer.ts +292 -0
- package/inferencer/package-lock.json +129 -0
- package/inferencer/package.json +60 -0
- package/inferencer/playwright-report/data/507ad515125e13390ea07de92f22331c913fa068.md +55 -0
- package/inferencer/playwright-report/index.html +90 -0
- package/inferencer/playwright.config.ts +54 -0
- package/inferencer/test-results/.last-run.json +6 -0
- package/inferencer/test-results/inferencer-Inferencer-Enha-535bc-inferencer-tests-in-browser-chromium/error-context.md +55 -0
- package/inferencer/tests/inferencedPropagator.html +428 -0
- package/inferencer/tests/inferencedPropagator.spec.ts +18 -0
- package/inferencer/tests/inferencer.html +355 -0
- package/inferencer/tests/inferencer.spec.ts +19 -0
- package/inferencer/tsconfig.json +19 -0
- package/inferencer/types/.kiro/specs/conversion-template/README.md +128 -0
- package/inferencer/types/.kiro/specs/conversion-template/design.md +360 -0
- package/inferencer/types/.kiro/specs/conversion-template/requirements.md +191 -0
- package/inferencer/types/.kiro/specs/conversion-template/tasks.md +174 -0
- package/inferencer/types/.kiro/steering/coding-standards.md +53 -0
- package/inferencer/types/.kiro/steering/conversion-guide.md +108 -0
- package/inferencer/types/.kiro/steering/declarative-configuration.md +108 -0
- package/inferencer/types/.kiro/steering/emc-json-serializability.md +306 -0
- package/inferencer/types/EnhancementConversionInstructions.md +1854 -0
- package/inferencer/types/LICENSE +21 -0
- package/inferencer/types/NewCustomElement.md +388 -0
- package/inferencer/types/NewCustomElementFeature.md +683 -0
- package/inferencer/types/NewEnhancementInstructions.md +705 -0
- package/inferencer/types/README.md +2 -0
- package/inferencer/types/agrace/types.d.ts +11 -0
- package/inferencer/types/assign-gingerly/types.d.ts +572 -0
- package/inferencer/types/be-a-beacon/types.d.ts +17 -0
- package/inferencer/types/be-bound/types.d.ts +66 -0
- package/inferencer/types/be-buttoned-up/types.d.ts +19 -0
- package/inferencer/types/be-calculating/types.d.ts +54 -0
- package/inferencer/types/be-clonable/types.d.ts +38 -0
- package/inferencer/types/be-committed/types.d.ts +22 -0
- package/inferencer/types/be-consoling/types.d.ts +24 -0
- package/inferencer/types/be-decked-with/types.d.ts +26 -0
- package/inferencer/types/be-delible/types.d.ts +27 -0
- package/inferencer/types/be-dispatching/types.d.ts +34 -0
- package/inferencer/types/be-evanescent/types.d.ts +20 -0
- package/inferencer/types/be-flashy/types.d.ts +21 -0
- package/inferencer/types/be-gone/types.d.ts +25 -0
- package/inferencer/types/be-observing/types.d.ts +55 -0
- package/inferencer/types/be-reflective/types.d.ts +78 -0
- package/inferencer/types/be-reformable/types.d.ts +49 -0
- package/inferencer/types/be-render-neutral/types.d.ts +32 -0
- package/inferencer/types/be-switched/types.d.ts +146 -0
- package/inferencer/types/be-typed/types.d.ts +32 -0
- package/inferencer/types/be-valued/types.d.ts +22 -0
- package/inferencer/types/data-props/types.d.ts +34 -0
- package/inferencer/types/do-inc/types.d.ts +56 -0
- package/inferencer/types/do-invoke/types.d.ts +38 -0
- package/inferencer/types/do-merge/types.d.ts +28 -0
- package/inferencer/types/do-toggle/types.d.ts +31 -0
- package/inferencer/types/face-up/types.d.ts +100 -0
- package/inferencer/types/fetch-for/types.d.ts +36 -0
- package/inferencer/types/folder-picker/types.d.ts +21 -0
- package/inferencer/types/global.d.ts +29 -0
- package/inferencer/types/id-generation/types.d.ts +26 -0
- package/inferencer/types/inferencer/types.d.ts +46 -0
- package/inferencer/types/mount-observer/types.d.ts +363 -0
- package/inferencer/types/nested-regex-groups/types.d.ts +107 -0
- package/inferencer/types/pipe-in/types.d.ts +52 -0
- package/inferencer/types/roundabout/types.d.ts +268 -0
- package/inferencer/types/soak-up/types.d.ts +40 -0
- package/inferencer/types/templ-maker/types.d.ts +43 -0
- package/inferencer/types/time-ticker/types.d.ts +62 -0
- package/inferencer/types/truth-sourcer/types.d.ts +44 -0
- package/inferencer/upSearch.js +27 -0
- package/inferencer/upSearch.ts +26 -0
- package/inferencer/withScopePerimeter.js +27 -0
- package/inferencer/withScopePerimeter.ts +33 -0
- package/inferredAssignments.js +38 -0
- package/inferredAssignments.ts +65 -0
- package/isAllowedImportPath.js +42 -0
- package/isAllowedImportPath.ts +53 -0
- package/package.json +57 -3
- package/paths.js +231 -0
- package/paths.ts +413 -0
- package/processHandlerCommands.js +188 -0
- package/processHandlerCommands.ts +217 -0
- package/resolveIdRef.js +144 -0
- package/resolveIdRef.ts +170 -0
- package/resolveValues.js +41 -2
- package/resolveValues.ts +41 -1
- package/transitionHelper.js +109 -0
- package/transitionHelper.ts +132 -0
- package/types/assign-gingerly/types.d.ts +89 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bruce B. Anderson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# New Custom Element Instructions
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
This document provides step-by-step instructions for creating a **brand new** custom element project that extends `ElementMaker`. Custom elements built this way inherit a catalog of composable features (form association, attribute sourcing, roundabout reactive wiring, CSS reflection) out of the box, and only need to declare what's unique to them.
|
|
6
|
+
|
|
7
|
+
**Note:** This guide is for **custom elements** — concrete components registered with `customElements.define()`. It does NOT apply to:
|
|
8
|
+
- Custom element features (composable behavior classes injected into elements) — see [NewCustomElementFeature.md](./NewCustomElementFeature.md)
|
|
9
|
+
- Enhancements (declarative behaviors attached to existing elements via attributes) — see [NewEnhancementInstructions.md](./NewEnhancementInstructions.md)
|
|
10
|
+
|
|
11
|
+
## Reference Implementation
|
|
12
|
+
|
|
13
|
+
- **[time-ticker](https://github.com/bahrus/time-ticker)** — A non-visual custom element that fires events periodically. Demonstrates extending `ElementMaker`, a custom feature (`TimeTicker`), roundabout wiring via `defRef.json`, and the `def.js` / `wireFeatures.js` pattern.
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Node.js installed
|
|
18
|
+
- npm installed
|
|
19
|
+
- `ncu` (npm-check-updates) installed globally: `npm install -g npm-check-updates`
|
|
20
|
+
- Chrome 146+ for testing (scoped custom element registry support required)
|
|
21
|
+
|
|
22
|
+
## Step 1: Initialize the Project
|
|
23
|
+
|
|
24
|
+
1. Create a new repository (e.g., `my-element`)
|
|
25
|
+
2. Run `npm init` or create a `package.json` manually
|
|
26
|
+
3. Add the `types` submodule:
|
|
27
|
+
```bash
|
|
28
|
+
git submodule add https://github.com/bahrus/types.git types
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Step 2: Configure package.json
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"name": "my-element",
|
|
36
|
+
"version": "0.0.0",
|
|
37
|
+
"description": "Description of what the element does",
|
|
38
|
+
"type": "module",
|
|
39
|
+
"main": "def.js",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "node defRef.mjs > defRef.json",
|
|
42
|
+
"serve": "node ./node_modules/spa-ssi/serve.js",
|
|
43
|
+
"test": "playwright test",
|
|
44
|
+
"update": "ncu -u && npm install",
|
|
45
|
+
"safari": "npx playwright wk http://localhost:8000",
|
|
46
|
+
"chrome": "npx playwright cr http://localhost:8000"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@playwright/test": "1.60.0",
|
|
50
|
+
"spa-ssi": "0.0.27"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"assign-gingerly": "0.0.48",
|
|
54
|
+
"el-maker": "0.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Notes:**
|
|
60
|
+
- Use exact versions, not ranges (no `^` or `~`)
|
|
61
|
+
- `el-maker` brings in `roundabout-lib`, `truth-sourcer`, `face-up`, and `be-reflective` transitively
|
|
62
|
+
- Only add direct dependencies for features unique to your element
|
|
63
|
+
- Run `npm run update` after creating package.json to install dependencies
|
|
64
|
+
|
|
65
|
+
## Step 3: Create Type Definitions
|
|
66
|
+
|
|
67
|
+
Create `types/[project-name]/types.d.ts` with the element's property interface:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
/**
|
|
71
|
+
* Properties specific to this custom element
|
|
72
|
+
*/
|
|
73
|
+
export interface ElementProps {
|
|
74
|
+
// Properties unique to this element
|
|
75
|
+
myProp: string;
|
|
76
|
+
disabled: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Full property set including internal state
|
|
81
|
+
*/
|
|
82
|
+
export interface AllProps extends ElementProps {
|
|
83
|
+
idx: number;
|
|
84
|
+
item: any;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type T = AllProps;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Key points:**
|
|
91
|
+
- `ElementProps` — the public API specific to this element
|
|
92
|
+
- `AllProps` — includes internal/computed state managed by roundabout
|
|
93
|
+
- Export `T` as a convenience alias for use in `defRef.mjs` type annotations
|
|
94
|
+
|
|
95
|
+
## Step 4: Create the Element Class
|
|
96
|
+
|
|
97
|
+
Create `[element-name]-element.js` (e.g., `my-element-element.js`):
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
import { ElementMaker } from 'el-maker/ElementMaker.js';
|
|
101
|
+
|
|
102
|
+
export class MyElementElement extends ElementMaker {
|
|
103
|
+
static supportedFeatures = {
|
|
104
|
+
...ElementMaker.supportedFeatures,
|
|
105
|
+
myFeature: {},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Key patterns:**
|
|
111
|
+
- Extends `ElementMaker` — inherits `propagator`, `#internals`, `attachInternals()`, and all shared features (`roundabout`, `truthSourcer`, `faceUp`, `reflector`, `templateMaker`)
|
|
112
|
+
- Spreads `ElementMaker.supportedFeatures` to inherit the base feature slots
|
|
113
|
+
- Only declares additional feature slots unique to this element
|
|
114
|
+
- No need for `static formAssociated = true` — `FaceUp.onAssigned` sets it automatically
|
|
115
|
+
- No constructor needed unless you have element-specific initialization
|
|
116
|
+
|
|
117
|
+
## Step 5: Create the Element-Specific Feature (if any)
|
|
118
|
+
|
|
119
|
+
If your element has unique behavior beyond what the inherited features provide, create a custom element feature following [NewCustomElementFeature.md](./NewCustomElementFeature.md).
|
|
120
|
+
|
|
121
|
+
For example, `time-ticker` has a `TimeTicker.js` feature that provides precise drift-correcting ticking.
|
|
122
|
+
|
|
123
|
+
## Step 6: Create defRef.mjs (Roundabout Configuration)
|
|
124
|
+
|
|
125
|
+
Create `defRef.mjs` — this generates the JSON configuration that drives the roundabout reactive wiring:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
//@ts-check
|
|
129
|
+
|
|
130
|
+
/** @import {RAConfig} from './types/roundabout/types' */
|
|
131
|
+
/** @import {T} from './types/[project-name]/types' */
|
|
132
|
+
/** @import {AttrPatterns} from './types/assign-gingerly/types' */
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @type {{ [K in keyof T]: K }}
|
|
136
|
+
*/
|
|
137
|
+
const props = {
|
|
138
|
+
myProp: 'myProp',
|
|
139
|
+
disabled: 'disabled',
|
|
140
|
+
// ... all properties that roundabout manages
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @type {RAConfig<T,T,T>}
|
|
145
|
+
*/
|
|
146
|
+
export const raConfig = {
|
|
147
|
+
propagate: /** @type {Array<keyof T>} */ (Object.keys(props)),
|
|
148
|
+
compacts: {
|
|
149
|
+
// Reactive shorthand rules
|
|
150
|
+
},
|
|
151
|
+
merges: [
|
|
152
|
+
// Reactive assignment rules
|
|
153
|
+
],
|
|
154
|
+
yields: {
|
|
155
|
+
// Derived property rules
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @type {AttrPatterns<T>}
|
|
161
|
+
*/
|
|
162
|
+
const withAttrs = {
|
|
163
|
+
// Attribute-to-property mappings for truthSourcer
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const cef = {
|
|
167
|
+
features: {
|
|
168
|
+
roundabout: {
|
|
169
|
+
customData: {
|
|
170
|
+
raConfig
|
|
171
|
+
},
|
|
172
|
+
withAttrs
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export function render() {
|
|
178
|
+
return JSON.stringify(cef, null, 4);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log(render());
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Key patterns:**
|
|
185
|
+
- The `props` object provides type-safe property name references (keys must be in `T`, values must equal the key)
|
|
186
|
+
- `raConfig` defines the reactive wiring: compacts (shorthand rules), merges (assignment rules), yields (derived values)
|
|
187
|
+
- `withAttrs` maps HTML attributes to properties (used by `truthSourcer`)
|
|
188
|
+
- The `render()` function outputs JSON for the build step
|
|
189
|
+
|
|
190
|
+
Run `npm run build` to generate `defRef.json`.
|
|
191
|
+
|
|
192
|
+
## Step 7: Create wireFeatures.js
|
|
193
|
+
|
|
194
|
+
This module resolves async fallback spawns and calls `assignFeatures` with the element-specific configuration:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
import { MyFeature } from './MyFeature.js';
|
|
198
|
+
import { resolveAndAssignFeatures } from 'assign-gingerly/resolveAndAssignFeatures.js';
|
|
199
|
+
|
|
200
|
+
export async function wireFeatures(ElementClass, cfg) {
|
|
201
|
+
const { roundabout } = cfg.features;
|
|
202
|
+
const { customData, withAttrs } = roundabout;
|
|
203
|
+
|
|
204
|
+
await resolveAndAssignFeatures(ElementClass, {
|
|
205
|
+
myFeature: { spawn: MyFeature },
|
|
206
|
+
truthSourcer: {
|
|
207
|
+
callbackForwarding: ['connectedCallback', 'attributeChangedCallback'],
|
|
208
|
+
},
|
|
209
|
+
faceUp: {
|
|
210
|
+
customData: { integrateWithRoundabout: true },
|
|
211
|
+
callbackForwarding: [
|
|
212
|
+
'connectedCallback', 'disconnectedCallback',
|
|
213
|
+
'formDisabledCallback', 'formResetCallback', 'formStateRestoreCallback',
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
roundabout: {
|
|
217
|
+
customData,
|
|
218
|
+
withAttrs,
|
|
219
|
+
callbackForwarding: ['connectedCallback'],
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Key patterns:**
|
|
226
|
+
- Only eagerly imports the feature(s) unique to this element
|
|
227
|
+
- Inherited features (`truthSourcer`, `faceUp`, `roundabout`, `reflector`) use their async `fallbackSpawn` from `ElementMaker` — no explicit `spawn` needed
|
|
228
|
+
- `resolveAndAssignFeatures` resolves async fallback spawns before calling `assignFeatures`, ensuring `onAssigned` hooks (like `FaceUp.onAssigned` setting `static formAssociated = true`) run before `define()`
|
|
229
|
+
- `callbackForwarding` and `customData` are per-element configuration that gets unioned with the author defaults from `supportedFeatures`
|
|
230
|
+
|
|
231
|
+
## Step 8: Create def.js
|
|
232
|
+
|
|
233
|
+
The side-effect module that registers the custom element with its canonical tag name and default feature wiring:
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
import { MyElementElement } from './my-element-element.js';
|
|
237
|
+
import { wireFeatures } from './wireFeatures.js';
|
|
238
|
+
import defRef from './defRef.json' with { type: 'json' };
|
|
239
|
+
|
|
240
|
+
await wireFeatures(MyElementElement, defRef);
|
|
241
|
+
customElements.define('my-element', MyElementElement);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Key patterns:**
|
|
245
|
+
- `def.js` = "default define" — centralizes all side effects
|
|
246
|
+
- Imports the JSON config and passes it to `wireFeatures`
|
|
247
|
+
- Consumers who want a different tag name, scoped registry, or DI overrides write their own version of this file
|
|
248
|
+
|
|
249
|
+
## Step 9: Create imports.html
|
|
250
|
+
|
|
251
|
+
```html
|
|
252
|
+
<script type=importmap>
|
|
253
|
+
{
|
|
254
|
+
"imports": {
|
|
255
|
+
"assign-gingerly/": "/node_modules/assign-gingerly/",
|
|
256
|
+
"el-maker/": "/node_modules/el-maker/",
|
|
257
|
+
"face-up/": "/node_modules/face-up/",
|
|
258
|
+
"on-to-me/": "/node_modules/on-to-me/",
|
|
259
|
+
"roundabout-lib/": "/node_modules/roundabout-lib/",
|
|
260
|
+
"[project-name]/": "/",
|
|
261
|
+
"truth-sourcer/": "/node_modules/truth-sourcer/"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
</script>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Notes:**
|
|
268
|
+
- Include all transitive dependencies that are loaded in the browser
|
|
269
|
+
- The project itself maps to `/` for local development
|
|
270
|
+
|
|
271
|
+
## Step 10: Set Up Auto-Build Hook
|
|
272
|
+
|
|
273
|
+
Create `.kiro/hooks/auto-build-config.kiro.hook`:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"name": "Auto-build Configuration",
|
|
278
|
+
"version": "1.0.0",
|
|
279
|
+
"description": "Automatically runs npm run build when defRef.mjs is saved",
|
|
280
|
+
"when": {
|
|
281
|
+
"type": "fileEdited",
|
|
282
|
+
"patterns": ["**/*.mjs"]
|
|
283
|
+
},
|
|
284
|
+
"then": {
|
|
285
|
+
"type": "askAgent",
|
|
286
|
+
"prompt": "A .mjs file was changed. Run npm run build to regenerate the output."
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Step 11: Create Test HTML
|
|
292
|
+
|
|
293
|
+
Create `tests/test1.html`:
|
|
294
|
+
|
|
295
|
+
```html
|
|
296
|
+
<!DOCTYPE html>
|
|
297
|
+
<html lang="en">
|
|
298
|
+
<head>
|
|
299
|
+
<meta charset="UTF-8">
|
|
300
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
301
|
+
<title>Test - my-element</title>
|
|
302
|
+
<!-- #include virtual="/imports.html" -->
|
|
303
|
+
<script type=module>
|
|
304
|
+
import '[project-name]/def.js';
|
|
305
|
+
</script>
|
|
306
|
+
</head>
|
|
307
|
+
<body>
|
|
308
|
+
<my-element></my-element>
|
|
309
|
+
</body>
|
|
310
|
+
</html>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Architecture Overview
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
[project-name]/
|
|
317
|
+
├── .kiro/
|
|
318
|
+
│ ├── hooks/
|
|
319
|
+
│ │ └── auto-build-config.kiro.hook
|
|
320
|
+
│ └── steering/
|
|
321
|
+
│ └── project-context.md
|
|
322
|
+
├── .vscode/
|
|
323
|
+
│ └── settings.json
|
|
324
|
+
├── types/ (git submodule)
|
|
325
|
+
│ └── [project-name]/
|
|
326
|
+
│ └── types.d.ts
|
|
327
|
+
├── [element-name]-element.js (element class — extends ElementMaker)
|
|
328
|
+
├── [FeatureName].js (element-specific feature, if any)
|
|
329
|
+
├── wireFeatures.js (resolves + assigns features)
|
|
330
|
+
├── def.js (side-effect: wire + define)
|
|
331
|
+
├── defRef.mjs (build script → defRef.json)
|
|
332
|
+
├── defRef.json (generated — roundabout config)
|
|
333
|
+
├── imports.html (import map for browser)
|
|
334
|
+
├── package.json
|
|
335
|
+
├── tests/
|
|
336
|
+
│ └── test1.html
|
|
337
|
+
└── README.md
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## The Three-File Pattern
|
|
341
|
+
|
|
342
|
+
Every custom element package exports three key modules:
|
|
343
|
+
|
|
344
|
+
| File | Role | Side effects? |
|
|
345
|
+
|------|------|---------------|
|
|
346
|
+
| `[element-name]-element.js` | Class definition + `supportedFeatures` declaration | No |
|
|
347
|
+
| `wireFeatures.js` | Resolves spawns + calls `assignFeatures` with config | No |
|
|
348
|
+
| `def.js` | Imports config, wires features, calls `define()` | Yes |
|
|
349
|
+
|
|
350
|
+
This separation enables:
|
|
351
|
+
- **Different tag names** — write your own `def.js` with a different `define()` call
|
|
352
|
+
- **Scoped registries** — call `scopedRegistry.define()` instead of `customElements.define()`
|
|
353
|
+
- **DI / testing** — call `resolveAndAssignFeatures` directly with mock spawns
|
|
354
|
+
- **Declarative definition** — use `defineWithFeatures` from a cede script without any JS class code
|
|
355
|
+
|
|
356
|
+
## What ElementMaker Provides
|
|
357
|
+
|
|
358
|
+
By extending `ElementMaker`, your element inherits:
|
|
359
|
+
|
|
360
|
+
| Feature | What it does |
|
|
361
|
+
|---------|-------------|
|
|
362
|
+
| `roundabout` | Reactive property wiring (compacts, merges, yields, actions) |
|
|
363
|
+
| `truthSourcer` | Attribute → property synchronization via `withAttrs` |
|
|
364
|
+
| `faceUp` | Form association (value, validation, reset, state restoration) |
|
|
365
|
+
| `reflector` | CSS custom state reflection via `ElementInternals` |
|
|
366
|
+
| `templateMaker` | HTML template instantiation and shadow DOM management |
|
|
367
|
+
|
|
368
|
+
Plus infrastructure:
|
|
369
|
+
- `propagator` (EventTarget) for inter-feature communication
|
|
370
|
+
- `#internals` (ElementInternals) shared via `getSharedContext`
|
|
371
|
+
- `attachInternals()` called in the constructor
|
|
372
|
+
- Async `fallbackSpawn` for lazy-loading all feature implementations
|
|
373
|
+
|
|
374
|
+
## Elements Without HTML (Non-Visual)
|
|
375
|
+
|
|
376
|
+
For elements like `time-ticker` that have no HTML template or shadow DOM, simply don't activate the `templateMaker` feature in `wireFeatures.js`. The feature remains declared in `supportedFeatures` (inherited from `ElementMaker`) but is never instantiated because no `assignFeatures` call references it.
|
|
377
|
+
|
|
378
|
+
## Elements With HTML (Coming Soon)
|
|
379
|
+
|
|
380
|
+
For elements that render static or dynamic HTML, the `templateMaker` feature handles template instantiation and shadow DOM attachment. Documentation for this pattern — including how to declare templates, bind data, and integrate with roundabout — will be added in a future update.
|
|
381
|
+
|
|
382
|
+
## Tips
|
|
383
|
+
|
|
384
|
+
- **Call `wireFeatures` before `customElements.define()`** — features must be on the prototype before instances exist
|
|
385
|
+
- **Use `@ts-check`** in `.mjs` files — catches type errors in the build configuration
|
|
386
|
+
- **Run `npm run build` after editing `defRef.mjs`** — the JSON must be regenerated
|
|
387
|
+
- **Don't eagerly import inherited features** — let `fallbackSpawn` lazy-load them
|
|
388
|
+
- **Keep `def.js` minimal** — it's the canonical handshake; consumers can deviate as needed
|