@twobirds/microcomponents 0.9.0 → 0.10.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.
- package/README.md +2 -16
- package/dist/cli/bundle.d.ts +106 -0
- package/dist/cli/bundle.d.ts.map +1 -0
- package/dist/cli/bundler.d.ts +44 -0
- package/dist/cli/bundler.d.ts.map +1 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/dev.d.ts +87 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dispatch.d.ts +6 -2
- package/dist/cli/dispatch.d.ts.map +1 -1
- package/dist/cli/index.js +1807 -1
- package/dist/cli/inliner.d.ts +42 -0
- package/dist/cli/inliner.d.ts.map +1 -0
- package/dist/cli/preview.d.ts +48 -0
- package/dist/cli/preview.d.ts.map +1 -0
- package/dist/core/elements.js +1294 -75
- package/dist/core/mcGuards.js +5 -8
- package/dist/mcp/api.json +2 -17
- package/dist/mcp/concepts/project-layout.md +9 -8
- package/dist/mcp/index.js +450 -230
- package/dist/microcomponents.js +2882 -9
- package/dist/state/formValues.js +2236 -281
- package/dist/state/observables.js +1794 -342
- package/dist/utils/events.js +171 -197
- package/package.json +3 -7
- package/dist/cli/create.js +0 -653
- package/dist/cli/dispatch.js +0 -316
- package/dist/cli/scaffold.js +0 -109
- package/dist/cli/writeScaffold.js +0 -114
- package/dist/core/MC.js +0 -837
- package/dist/core/index.js +0 -72
- package/dist/state/index.js +0 -5
- package/dist/state/placeholders.js +0 -187
- package/dist/types/index.js +0 -1
- package/dist/types/mcTypes.js +0 -9
- package/dist/utils/autoload.js +0 -160
- package/dist/utils/helpers.js +0 -532
- package/dist/utils/index.js +0 -12
- package/dist/utils/resolveComponentPath.js +0 -39
- package/dist/vite/index.d.ts +0 -7
- package/dist/vite/index.d.ts.map +0 -1
- package/dist/vite/index.js +0 -6
- package/dist/vite/loadAssets.d.ts +0 -36
- package/dist/vite/loadAssets.d.ts.map +0 -1
- package/dist/vite/loadAssets.js +0 -221
package/dist/utils/events.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/utils/events.ts
|
|
1
2
|
/**
|
|
2
3
|
@module Events
|
|
3
4
|
|
|
@@ -18,10 +19,10 @@ The core feature is the ability to explicitly control event flow direction when
|
|
|
18
19
|
html:
|
|
19
20
|
```html
|
|
20
21
|
<div class="grandparent">
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
<div class="parent">
|
|
23
|
+
<div class="child">
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
25
26
|
</div>
|
|
26
27
|
```
|
|
27
28
|
|
|
@@ -48,52 +49,50 @@ The `dataReady` event bubbles upward from the innermost `div`, but `parentHandle
|
|
|
48
49
|
calls `ev.detail.control.stop()`, so the `grandParent` handler is never reached.
|
|
49
50
|
Handlers are detached with `off()` once they are no longer needed.
|
|
50
51
|
*/
|
|
51
|
-
'use strict';
|
|
52
52
|
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
53
|
+
* Converts a standard event name to its microcomponent-prefixed variant.
|
|
54
|
+
*
|
|
55
|
+
* This utility is used internally to namespace custom events (e.g., 'Click' → '_mcClick').
|
|
56
|
+
*
|
|
57
|
+
* @param eventName - The original event name (e.g., 'click', 'update').
|
|
58
|
+
* @returns The microcomponent-prefixed event name.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* console.log(getMcEventName('update'));
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function getMcEventName(eventName) {
|
|
66
|
+
return "_mc" + eventName[0].toUpperCase() + eventName.substring(1);
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
|
|
69
|
+
* Returns the correct event name to listen for on a DOM element.
|
|
70
|
+
*
|
|
71
|
+
* If `eventName` (case-insensitive) matches a native HTML event handler property
|
|
72
|
+
* (`'on' + eventName.toLowerCase()`) on the target, returns the lowercase native
|
|
73
|
+
* name so that standard DOM events like `'click'` are listened to correctly.
|
|
74
|
+
* Otherwise, prefixes with `_mc` for microcomponent custom events.
|
|
75
|
+
*
|
|
76
|
+
* @hidden
|
|
77
|
+
* @param target - The DOM element whose native event support is checked.
|
|
78
|
+
* @param eventName - The event name as provided by the caller (e.g., `'click'`, `'Update'`).
|
|
79
|
+
* @returns The resolved event name: lowercase native or `_mc`-prefixed custom.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const btn = document.createElement('button');
|
|
84
|
+
* console.log(trueEventName(btn, 'Click'));
|
|
85
|
+
* console.log(trueEventName(btn, 'Update'));
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* `'Click'` resolves to the native `'click'` because the button has an `onclick` handler
|
|
89
|
+
* property; `'Update'` has no native counterpart, so it becomes the `_mc`-prefixed custom
|
|
90
|
+
* event name.
|
|
91
|
+
*/
|
|
92
|
+
function trueEventName(target, eventName) {
|
|
93
|
+
const lower = eventName.toLowerCase();
|
|
94
|
+
if ("on" + lower in target) return lower;
|
|
95
|
+
return "_mc" + eventName[0].toUpperCase() + eventName.substring(1);
|
|
97
96
|
}
|
|
98
97
|
/**
|
|
99
98
|
Removes a previously attached event handler from the DOM node. See {@link on} and {@link one}.
|
|
@@ -113,19 +112,14 @@ off(myElement, 'click', handler);
|
|
|
113
112
|
```
|
|
114
113
|
@group Events
|
|
115
114
|
*/
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
// McEventHandler<D> narrows the runtime EventListener contract type-side only;
|
|
127
|
-
// the cast re-widens it at the DOM boundary.
|
|
128
|
-
target.removeEventListener(trueEventName(target, eventName), handler);
|
|
115
|
+
function off(target, eventName, handler) {
|
|
116
|
+
/* v8 ignore next */
|
|
117
|
+
if (!target) return;
|
|
118
|
+
if (typeof target === "string") {
|
|
119
|
+
document.querySelectorAll(target).forEach((el) => off(el, eventName, handler));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
target.removeEventListener(trueEventName(target, eventName), handler);
|
|
129
123
|
}
|
|
130
124
|
/**
|
|
131
125
|
Attaches a persistent event listener that will fire every time the specified event occurs.
|
|
@@ -145,27 +139,24 @@ The handler receives a `CustomEvent<McDetail<D>>`: the payload sits under
|
|
|
145
139
|
@example
|
|
146
140
|
```ts
|
|
147
141
|
const handler = on<{ value: number }>(myElement, 'update', (ev) => {
|
|
148
|
-
|
|
142
|
+
console.log(ev.detail.data.value);
|
|
149
143
|
});
|
|
150
144
|
off(myElement, 'update', handler);
|
|
151
145
|
```
|
|
152
146
|
@group Events
|
|
153
147
|
*/
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
once,
|
|
167
|
-
});
|
|
168
|
-
return handler;
|
|
148
|
+
function on(target, eventName, handler, once = false) {
|
|
149
|
+
/* v8 ignore next */
|
|
150
|
+
if (!target) return;
|
|
151
|
+
if (typeof target === "string") {
|
|
152
|
+
document.querySelectorAll(target).forEach((el) => on(el, eventName, handler));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
target.addEventListener(trueEventName(target, eventName), handler, {
|
|
156
|
+
capture: false,
|
|
157
|
+
once
|
|
158
|
+
});
|
|
159
|
+
return handler;
|
|
169
160
|
}
|
|
170
161
|
/**
|
|
171
162
|
Attaches an event listener that will fire only once.
|
|
@@ -188,128 +179,111 @@ one<{ ready: boolean }>(myElement, 'dataReady', (ev) => console.log('received:',
|
|
|
188
179
|
The listener fires only once and detaches automatically.
|
|
189
180
|
@group Events
|
|
190
181
|
*/
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
on(target, eventName, handler, true); // true indicates once
|
|
202
|
-
return handler;
|
|
182
|
+
function one(target, eventName, handler) {
|
|
183
|
+
/* v8 ignore next */
|
|
184
|
+
if (!target) return;
|
|
185
|
+
if (typeof target === "string") {
|
|
186
|
+
document.querySelectorAll(target).forEach((el) => one(el, eventName, handler));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
on(target, eventName, handler, true);
|
|
190
|
+
return handler;
|
|
203
191
|
}
|
|
204
192
|
/**
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
193
|
+
* @hidden
|
|
194
|
+
* A controller object used to manage and potentially abort event bubbling.
|
|
195
|
+
*
|
|
196
|
+
* The `trigger()` function internally creates instance of this class,
|
|
197
|
+
* allowing the an eventual handler to call `ev.detail.control.stop()` to
|
|
198
|
+
* prevent further propagation in either direction (up/down).
|
|
199
|
+
*
|
|
200
|
+
* This is only used internally.
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* trigger(myElement, 'update', { value: 42 }, 'u');
|
|
204
|
+
*
|
|
205
|
+
* onUpdate(ev) {
|
|
206
|
+
* ev.detail.control.stop();
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
var BubbleController = class {
|
|
211
|
+
stopped = false;
|
|
212
|
+
constructor() {}
|
|
213
|
+
/**
|
|
214
|
+
* Signals that event bubbling should be halted.
|
|
215
|
+
*
|
|
216
|
+
* After calling this method, subsequent `trigger()` calls will abort
|
|
217
|
+
* before dispatching the event to any targets.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* trigger(myElement, 'update', { value: 42 }, 'u');
|
|
222
|
+
*
|
|
223
|
+
* onUpdate(ev) {
|
|
224
|
+
* ev.detail.control.stop();
|
|
225
|
+
* }
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
stop() {
|
|
229
|
+
this.stopped = true;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
244
232
|
/**
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
// bubble if up or down is indicated
|
|
301
|
-
if (/[ud]/.test(bubble)) {
|
|
302
|
-
queueMicrotask(() => {
|
|
303
|
-
// bubble up towards document.body
|
|
304
|
-
if (bubble.indexOf('u') > -1) {
|
|
305
|
-
trigger(target.parentElement, eventName, data, 'lu', bubbleController);
|
|
306
|
-
}
|
|
307
|
-
// bubble down towards DOM children
|
|
308
|
-
if (bubble.indexOf('d') > -1) {
|
|
309
|
-
for (const child of target.children) {
|
|
310
|
-
trigger(child, eventName, data, 'ld'); // event multiplex - dont carry bubble controller
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
}
|
|
233
|
+
* Creates and dispatches a custom event on the specified DOM node.
|
|
234
|
+
*
|
|
235
|
+
* The event is namespaced with an `_mc` prefix by default, unless already prefixed.
|
|
236
|
+
* Supports bidirectional bubbling (up/down the DOM tree) based on the `bubble` parameter:
|
|
237
|
+
* - 'l': local dispatch only
|
|
238
|
+
* - 'u': bubble up towards ancestors
|
|
239
|
+
* - 'd': bubble down to descendants
|
|
240
|
+
*
|
|
241
|
+
* The dispatched event is a `CustomEvent<McDetail<D>>`: handlers find the payload
|
|
242
|
+
* under `ev.detail.data` and can call `ev.detail.control.stop()` to cancel bubbling.
|
|
243
|
+
*
|
|
244
|
+
* Prefer a direct target over bubbling: name the receiving element in `target` and keep the
|
|
245
|
+
* default `'l'`, so one `querySelectorAll` reaches it in a single step. Reserve `'u'`/`'d'`
|
|
246
|
+
* for receivers that cannot be named in advance, since they walk the tree and re-dispatch the
|
|
247
|
+
* event at every level. Pass a typed object as `data` rather than a bare string, so the
|
|
248
|
+
* handler reads named fields from `ev.detail.data` and the flow stays readable as it grows.
|
|
249
|
+
*
|
|
250
|
+
* @param target - The DOM element on which to trigger the event, or a querySelectorAll(selector) selector string.
|
|
251
|
+
* @param event - The name of the event (will be prefixed if needed).
|
|
252
|
+
* @param data - Additional data payload attached to `event.detail.data`.
|
|
253
|
+
* @param bubble - Bubbling direction ('l', 'u', 'd' or combinations).
|
|
254
|
+
* @param controller - Optional controller for managing bubbling behavior.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* trigger(myElement, 'update', { value: 42 }, 'l');
|
|
259
|
+
* trigger(myElement, 'dataReady', { ready: true }, 'u');
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* The first dispatch fires locally only; the second bubbles upward to ancestor components.
|
|
263
|
+
*/
|
|
264
|
+
function trigger(target, event, data = {}, bubble = "l", controller) {
|
|
265
|
+
/* v8 ignore next */
|
|
266
|
+
if (!target) return;
|
|
267
|
+
if (typeof target === "string") {
|
|
268
|
+
document.querySelectorAll(target).forEach((el) => trigger(el, event, data, bubble));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const eventName = /^_mc/.test(event) ? event : trueEventName(target, event), bubbleController = controller ? controller : new BubbleController(), ev = new CustomEvent(eventName, {
|
|
272
|
+
detail: {
|
|
273
|
+
data,
|
|
274
|
+
control: bubbleController
|
|
275
|
+
},
|
|
276
|
+
bubbles: false
|
|
277
|
+
});
|
|
278
|
+
if (bubbleController.stopped) return;
|
|
279
|
+
if (/l/.test(bubble)) {
|
|
280
|
+
target.dispatchEvent(ev);
|
|
281
|
+
if (bubbleController.stopped) return;
|
|
282
|
+
}
|
|
283
|
+
if (/[ud]/.test(bubble)) queueMicrotask(() => {
|
|
284
|
+
if (bubble.indexOf("u") > -1) trigger(target.parentElement, eventName, data, "lu", bubbleController);
|
|
285
|
+
if (bubble.indexOf("d") > -1) for (const child of target.children) trigger(child, eventName, data, "ld");
|
|
286
|
+
});
|
|
315
287
|
}
|
|
288
|
+
//#endregion
|
|
289
|
+
export { BubbleController, getMcEventName, off, on, one, trigger, trueEventName };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twobirds/microcomponents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Micro Components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"PWA",
|
|
@@ -73,10 +73,6 @@
|
|
|
73
73
|
"types": "./dist/mcp/index.d.ts",
|
|
74
74
|
"import": "./dist/mcp/index.js"
|
|
75
75
|
},
|
|
76
|
-
"./vite": {
|
|
77
|
-
"types": "./dist/vite/index.d.ts",
|
|
78
|
-
"import": "./dist/vite/index.js"
|
|
79
|
-
},
|
|
80
76
|
"./package.json": "./package.json"
|
|
81
77
|
},
|
|
82
78
|
"scripts": {
|
|
@@ -98,8 +94,8 @@
|
|
|
98
94
|
"typedoc": "typedoc --displayBasePath ./typedoc/",
|
|
99
95
|
"bundle": "tsx vite.build.ts",
|
|
100
96
|
"clean": "rm -rf dist public build coverage",
|
|
101
|
-
"build": "pnpm run clean && tsc -p tsconfig.lib.json && tsc -p tsconfig.cli.json && chmod +x dist/cli/index.js && pnpm run mcp:
|
|
102
|
-
"mcp:build": "
|
|
97
|
+
"build": "pnpm run clean && tsc --emitDeclarationOnly -p tsconfig.lib.json && tsc --emitDeclarationOnly -p tsconfig.cli.json && tsc --emitDeclarationOnly -p tsconfig.mcp.json && pnpm run bundle && chmod +x dist/cli/index.js dist/mcp/index.js && pnpm run mcp:docs && cp -r docs/concepts dist/mcp/concepts && pnpm run test:coverage && pnpm run check:pack && pnpm run typedoc && pnpm run demo:build && pnpm run demo:shop:build && pnpm run demo:todo:build",
|
|
98
|
+
"mcp:build": "node mcp-docs-generate.ts && cp -r docs/concepts dist/mcp/concepts",
|
|
103
99
|
"demo:build": "tsx demo/web-test/vite.demo.ts",
|
|
104
100
|
"dev": "vite preview --outDir build/web-test --port 10000 --host",
|
|
105
101
|
"doc": "vite preview --outDir public/typedoc --port 11000 --host",
|