@twobirds/microcomponents 0.2.0 → 0.2.1
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 +27 -38
- package/dist/MC.min.js +1 -1
- package/dist/autoload.min.js +1 -1
- package/dist/core/MC.d.ts +4 -1
- package/dist/core/MC.d.ts.map +1 -1
- package/dist/core/MC.js +46 -3
- package/dist/core/elements.d.ts +186 -100
- package/dist/core/elements.d.ts.map +1 -1
- package/dist/core/elements.js +186 -17
- package/dist/core/mcGuards.d.ts +1 -0
- package/dist/core/mcGuards.d.ts.map +1 -1
- package/dist/core/mcGuards.js +0 -10
- package/dist/elements.min.js +1 -1
- package/dist/events.min.js +1 -1
- package/dist/formValues.min.js +1 -1
- package/dist/microcomponents.d.ts +2 -2
- package/dist/microcomponents.d.ts.map +1 -1
- package/dist/microcomponents.js +2 -2
- package/dist/microcomponents.min.js +1 -1
- package/dist/observables.min.js +1 -1
- package/dist/state/observables.js +1 -1
- package/dist/utils/autoload.d.ts.map +1 -0
- package/dist/{core → utils}/autoload.js +2 -2
- package/dist/{core → utils}/events.d.ts +22 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/{core → utils}/events.js +26 -1
- package/dist/utils/helpers.d.ts +105 -20
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/utils/helpers.js +199 -25
- package/package.json +11 -10
- package/dist/core/autoload.d.ts.map +0 -1
- package/dist/core/events.d.ts.map +0 -1
- /package/dist/{core → utils}/autoload.d.ts +0 -0
|
@@ -57,7 +57,6 @@ off( grandParent, 'dataReady', grandParentHandler );
|
|
|
57
57
|
```
|
|
58
58
|
*/
|
|
59
59
|
'use strict';
|
|
60
|
-
import { trueEventName } from '../utils/helpers.js';
|
|
61
60
|
/**
|
|
62
61
|
* Converts a standard event name to its microcomponent-prefixed variant.
|
|
63
62
|
*
|
|
@@ -74,6 +73,32 @@ import { trueEventName } from '../utils/helpers.js';
|
|
|
74
73
|
export function getMcEventName(eventName) {
|
|
75
74
|
return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
|
|
76
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the correct event name to listen for on a DOM element.
|
|
78
|
+
*
|
|
79
|
+
* If `eventName` (case-insensitive) matches a native HTML event handler property
|
|
80
|
+
* (`'on' + eventName.toLowerCase()`) on the target, returns the lowercase native
|
|
81
|
+
* name so that standard DOM events like `'click'` are listened to correctly.
|
|
82
|
+
* Otherwise, prefixes with `_mc` for microcomponent custom events.
|
|
83
|
+
*
|
|
84
|
+
* @hidden
|
|
85
|
+
* @param target - The DOM element whose native event support is checked.
|
|
86
|
+
* @param eventName - The event name as provided by the caller (e.g., `'click'`, `'Update'`).
|
|
87
|
+
* @returns The resolved event name: lowercase native or `_mc`-prefixed custom.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const btn = document.createElement('button');
|
|
92
|
+
* trueEventName(btn, 'Click'); // 'click' — native handler exists
|
|
93
|
+
* trueEventName(btn, 'Update'); // '_mcUpdate' — custom event
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export function trueEventName(target, eventName) {
|
|
97
|
+
const lower = eventName.toLowerCase();
|
|
98
|
+
if ('on' + lower in target)
|
|
99
|
+
return lower;
|
|
100
|
+
return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
|
|
101
|
+
}
|
|
77
102
|
export function off(target, eventName, handler) {
|
|
78
103
|
/* v8 ignore next */
|
|
79
104
|
if (!target)
|
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ Small runtime-agnostic utilities shared across the library: environment
|
|
|
5
5
|
detection, object flattening/comparison, debouncing, accessor copying, and
|
|
6
6
|
kebab-to-PascalCase conversion.
|
|
7
7
|
*/
|
|
8
|
+
import type { McController } from '../types/mcTypes.js';
|
|
8
9
|
/**
|
|
9
10
|
* Determines whether the current runtime environment is a web browser.
|
|
10
11
|
*
|
|
@@ -147,6 +148,7 @@ export declare function debounce<A extends unknown[]>(func: (...args: A) => unkn
|
|
|
147
148
|
/**
|
|
148
149
|
* Parses an HTML string and returns an array of DOM elements.
|
|
149
150
|
* Handles self-closing tags (XHTML style) by converting them to full closing tags first.
|
|
151
|
+
* @hidden
|
|
150
152
|
* @param html - The HTML string to parse.
|
|
151
153
|
* @returns An array of HTMLElement objects representing the parsed HTML nodes.
|
|
152
154
|
*
|
|
@@ -157,29 +159,10 @@ export declare function debounce<A extends unknown[]>(func: (...args: A) => unkn
|
|
|
157
159
|
* ```
|
|
158
160
|
*/
|
|
159
161
|
export declare function htmlToElements(html: string): HTMLElement[];
|
|
160
|
-
/**
|
|
161
|
-
* Returns the correct event name to listen for on a DOM element.
|
|
162
|
-
*
|
|
163
|
-
* If `eventName` (case-insensitive) matches a native HTML event handler property
|
|
164
|
-
* (`'on' + eventName.toLowerCase()`) on the target, returns the lowercase native
|
|
165
|
-
* name so that standard DOM events like `'click'` are listened to correctly.
|
|
166
|
-
* Otherwise, prefixes with `_mc` for microcomponent custom events.
|
|
167
|
-
*
|
|
168
|
-
* @param target - The DOM element whose native event support is checked.
|
|
169
|
-
* @param eventName - The event name as provided by the caller (e.g., `'click'`, `'Update'`).
|
|
170
|
-
* @returns The resolved event name: lowercase native or `_mc`-prefixed custom.
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* ```ts
|
|
174
|
-
* const btn = document.createElement('button');
|
|
175
|
-
* trueEventName(btn, 'Click'); // 'click' — native handler exists
|
|
176
|
-
* trueEventName(btn, 'Update'); // '_mcUpdate' — custom event
|
|
177
|
-
* ```
|
|
178
|
-
*/
|
|
179
|
-
export declare function trueEventName(target: HTMLElement, eventName: string): string;
|
|
180
162
|
/**
|
|
181
163
|
* Copies all getter and setter properties from a source object to a target object.
|
|
182
164
|
* Does not copy methods or regular data properties—only accessor properties (get/set).
|
|
165
|
+
* @hidden
|
|
183
166
|
* @param source - The source object with getters and/or setters to copy.
|
|
184
167
|
* @param target - The target object to which the accessors will be copied.
|
|
185
168
|
*
|
|
@@ -192,4 +175,106 @@ export declare function trueEventName(target: HTMLElement, eventName: string): s
|
|
|
192
175
|
* ```
|
|
193
176
|
*/
|
|
194
177
|
export declare function copyGettersSetters(source: object, target: object): void;
|
|
178
|
+
/**
|
|
179
|
+
* Injects a CSS string into the given scope (document or shadow root) as an adopted stylesheet.
|
|
180
|
+
* Enables css-in-js so that every custom element is self-contained and importable.
|
|
181
|
+
*
|
|
182
|
+
* @hidden
|
|
183
|
+
* @param target - The scope to inject styles into: `document` for global styles, or a `ShadowRoot` for encapsulated component internals.
|
|
184
|
+
* @param css - The CSS string to inject.
|
|
185
|
+
* @returns The created `CSSStyleSheet` instance that was adopted into the target scope.
|
|
186
|
+
*
|
|
187
|
+
* When targeting **document**: selectors like `:host`, `::slotted()`, and shadow-internal classes are **not allowed** — they have no effect outside a shadow root. Use only global selectors, element tags, or layout presets.
|
|
188
|
+
* When targeting **shadowRoot**: use `:host` for the custom element itself, standard selectors (`.inner`, `#id`) for internal structure, and `::slotted()` for projected light-DOM content.
|
|
189
|
+
*
|
|
190
|
+
* @example Inject global styles into the document:
|
|
191
|
+
* ```ts
|
|
192
|
+
* import { injectCSS } from '@twobirds/mc/utils/helpers';
|
|
193
|
+
* injectCSS(document, 'body { display: block; }');
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* @example Inject global styles for a micro component into the document:
|
|
197
|
+
* ```ts
|
|
198
|
+
* import { injectCSS } from '@twobirds/mc/utils/helpers';
|
|
199
|
+
* injectCSS(document, 'my-microcomponent { display: block; }');
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @example Inject scoped styles into a shadow root:
|
|
203
|
+
* ```ts
|
|
204
|
+
* const shadow = element.attachShadow({ mode: 'open' });
|
|
205
|
+
* injectCSS(shadow, ':host { color: var(--text); } .inner { padding: 8px; }');
|
|
206
|
+
* ```
|
|
207
|
+
* Styles can also be added using a compound innerHTML statement: `shadow.innerHTML = \`<style>${style}</style>${template}\``
|
|
208
|
+
*/
|
|
209
|
+
export declare function injectCSS(target: Document | ShadowRoot, css: string): CSSStyleSheet;
|
|
210
|
+
/**
|
|
211
|
+
* Processes a record of asset strings and applies them to the given target element.
|
|
212
|
+
* Supports injecting CSS into document or shadow root, and setting innerHTML for
|
|
213
|
+
* both target and shadow DOM. Automatically attaches a shadow root if any key starts
|
|
214
|
+
* with `'shadow'`.
|
|
215
|
+
*
|
|
216
|
+
* Recognized keys: `'css'`, `'targetCss'` (document-level styles), `'shadowCss'`
|
|
217
|
+
* (shadow-root styles), `'shadowHtml'` (shadow innerHTML), `'targetHtml'` (target innerHTML).
|
|
218
|
+
*
|
|
219
|
+
* @param target - The HTMLElement to apply assets onto.
|
|
220
|
+
* @param assets - A record mapping asset type keys to their string content.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* processAssets(this, {
|
|
225
|
+
* css: 'body { margin: 0; }',
|
|
226
|
+
* shadowCss: ':host { display: block; }',
|
|
227
|
+
* shadowHtml: '<slot></slot>'
|
|
228
|
+
* });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
export declare function processAssets(instance: McController, assets: Record<string, string>): void;
|
|
232
|
+
/**
|
|
233
|
+
* Loads companion asset files (CSS, HTML) for a given component basename from the server.
|
|
234
|
+
*
|
|
235
|
+
* Each entry in `assets` encodes an optional variant and extension in camelCase, e.g. `'shadowCss'` → `{name}.shadow.css`,
|
|
236
|
+
* `'targetHtml'` → `{name}.target.html`. Plain entries like `'css'` or `'html'` resolve to
|
|
237
|
+
* `{name}.css` / `{name}.html`.
|
|
238
|
+
*
|
|
239
|
+
* In bundled mode the Vite plugin replaces this call with an inline array literal, so `.then()`
|
|
240
|
+
* fires synchronously — no async overhead.
|
|
241
|
+
*
|
|
242
|
+
* @hidden
|
|
243
|
+
* @param name - The component basename (e.g. `'shop-catalog'`).
|
|
244
|
+
* @param assets - Array of asset descriptors such as `'shadowCss'`, `'targetHtml'`, `'shadowHtml'`, `'css'`, `'html'`.
|
|
245
|
+
* @returns A promise resolving to an array of file contents in the same order as `assets`. If a file is not found, the corresponding entry is `'file not found: ' + filename`.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* export const MyComponent = loadAssets('my-component', ['shadowCss', 'shadowHtml']).then(([shadowCss, shadowHtml]) => {
|
|
250
|
+
* class _MyComponent extends DC { ... }
|
|
251
|
+
* defineCE('my-component', _MyComponent);
|
|
252
|
+
* return _MyComponent;
|
|
253
|
+
* });
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
export declare function loadAssets(name: string, assets: string[]): Promise<string[]>;
|
|
257
|
+
/**
|
|
258
|
+
* Binds declarative event attributes in a template fragment to microcomponent triggers.
|
|
259
|
+
*
|
|
260
|
+
* Scans all elements under `root` for attributes whose names correspond to native DOM
|
|
261
|
+
* events (e.g. `click`, `submit`, `change`). The attribute value encodes the target and
|
|
262
|
+
* handler method in the form `target#methodName`:
|
|
263
|
+
*
|
|
264
|
+
* - `this#myHandler` — triggers locally on the component attached to this element.
|
|
265
|
+
* - `#other-comp#submit` — resolves elements via `querySelectorAll('#other-comp')` and
|
|
266
|
+
* triggers the event on each matched host's `_mc`.
|
|
267
|
+
*
|
|
268
|
+
* An optional sibling `payload` attribute supplies the data argument for `trigger()`.
|
|
269
|
+
* After binding, both the event attribute and the payload attribute are removed from the DOM.
|
|
270
|
+
*
|
|
271
|
+
* @param root - The container element whose descendants should be scanned for bindings.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```html
|
|
275
|
+
* <button click="this#onSubmit" payload='{"action":"go"}'>Submit</button>
|
|
276
|
+
* <input change="#cart-form#refresh">
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export declare function bindTemplateEvents(root: HTMLElement | ShadowRoot, instance: McController): void;
|
|
195
280
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAiB1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqB7F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAiCzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,GAAE,MAAW,GAAG,OAAO,CAe1E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,EACpD,QAAQ,EAAE,CAAC,EACX,SAAS,EAAE,MAAM,EACjB,GAAG,IAAI,EAAE,OAAO,EAAE,GAChB,CAAC,CAgCH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,UAKxC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAC3C,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,EAC7B,YAAY,EAAE,MAAM,GAClB,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAStB;AAED
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,KAAK,EAAE,YAAY,EAAU,MAAM,qBAAqB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAiB1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqB7F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAiCzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,GAAG,GAAE,MAAW,GAAG,OAAO,CAe1E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,EACpD,QAAQ,EAAE,CAAC,EACX,SAAS,EAAE,MAAM,EACjB,GAAG,IAAI,EAAE,OAAO,EAAE,GAChB,CAAC,CAgCH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,UAKxC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAC3C,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,EAC7B,YAAY,EAAE,MAAM,GAClB,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAStB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAU1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOvE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAOnF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CA4B1F;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwB5E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CA0C/F"}
|
package/dist/utils/helpers.js
CHANGED
|
@@ -5,6 +5,7 @@ Small runtime-agnostic utilities shared across the library: environment
|
|
|
5
5
|
detection, object flattening/comparison, debouncing, accessor copying, and
|
|
6
6
|
kebab-to-PascalCase conversion.
|
|
7
7
|
*/
|
|
8
|
+
import { on, trigger } from './events.js';
|
|
8
9
|
/**
|
|
9
10
|
* Determines whether the current runtime environment is a web browser.
|
|
10
11
|
*
|
|
@@ -275,6 +276,7 @@ export function debounce(func, milliseconds) {
|
|
|
275
276
|
/**
|
|
276
277
|
* Parses an HTML string and returns an array of DOM elements.
|
|
277
278
|
* Handles self-closing tags (XHTML style) by converting them to full closing tags first.
|
|
279
|
+
* @hidden
|
|
278
280
|
* @param html - The HTML string to parse.
|
|
279
281
|
* @returns An array of HTMLElement objects representing the parsed HTML nodes.
|
|
280
282
|
*
|
|
@@ -291,34 +293,10 @@ export function htmlToElements(html) {
|
|
|
291
293
|
template.content.normalize();
|
|
292
294
|
return Array.from(template.content.childNodes);
|
|
293
295
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Returns the correct event name to listen for on a DOM element.
|
|
296
|
-
*
|
|
297
|
-
* If `eventName` (case-insensitive) matches a native HTML event handler property
|
|
298
|
-
* (`'on' + eventName.toLowerCase()`) on the target, returns the lowercase native
|
|
299
|
-
* name so that standard DOM events like `'click'` are listened to correctly.
|
|
300
|
-
* Otherwise, prefixes with `_mc` for microcomponent custom events.
|
|
301
|
-
*
|
|
302
|
-
* @param target - The DOM element whose native event support is checked.
|
|
303
|
-
* @param eventName - The event name as provided by the caller (e.g., `'click'`, `'Update'`).
|
|
304
|
-
* @returns The resolved event name: lowercase native or `_mc`-prefixed custom.
|
|
305
|
-
*
|
|
306
|
-
* @example
|
|
307
|
-
* ```ts
|
|
308
|
-
* const btn = document.createElement('button');
|
|
309
|
-
* trueEventName(btn, 'Click'); // 'click' — native handler exists
|
|
310
|
-
* trueEventName(btn, 'Update'); // '_mcUpdate' — custom event
|
|
311
|
-
* ```
|
|
312
|
-
*/
|
|
313
|
-
export function trueEventName(target, eventName) {
|
|
314
|
-
const lower = eventName.toLowerCase();
|
|
315
|
-
if ('on' + lower in target)
|
|
316
|
-
return lower;
|
|
317
|
-
return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
|
|
318
|
-
}
|
|
319
296
|
/**
|
|
320
297
|
* Copies all getter and setter properties from a source object to a target object.
|
|
321
298
|
* Does not copy methods or regular data properties—only accessor properties (get/set).
|
|
299
|
+
* @hidden
|
|
322
300
|
* @param source - The source object with getters and/or setters to copy.
|
|
323
301
|
* @param target - The target object to which the accessors will be copied.
|
|
324
302
|
*
|
|
@@ -338,3 +316,199 @@ export function copyGettersSetters(source, target) {
|
|
|
338
316
|
}
|
|
339
317
|
}
|
|
340
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Injects a CSS string into the given scope (document or shadow root) as an adopted stylesheet.
|
|
321
|
+
* Enables css-in-js so that every custom element is self-contained and importable.
|
|
322
|
+
*
|
|
323
|
+
* @hidden
|
|
324
|
+
* @param target - The scope to inject styles into: `document` for global styles, or a `ShadowRoot` for encapsulated component internals.
|
|
325
|
+
* @param css - The CSS string to inject.
|
|
326
|
+
* @returns The created `CSSStyleSheet` instance that was adopted into the target scope.
|
|
327
|
+
*
|
|
328
|
+
* When targeting **document**: selectors like `:host`, `::slotted()`, and shadow-internal classes are **not allowed** — they have no effect outside a shadow root. Use only global selectors, element tags, or layout presets.
|
|
329
|
+
* When targeting **shadowRoot**: use `:host` for the custom element itself, standard selectors (`.inner`, `#id`) for internal structure, and `::slotted()` for projected light-DOM content.
|
|
330
|
+
*
|
|
331
|
+
* @example Inject global styles into the document:
|
|
332
|
+
* ```ts
|
|
333
|
+
* import { injectCSS } from '@twobirds/mc/utils/helpers';
|
|
334
|
+
* injectCSS(document, 'body { display: block; }');
|
|
335
|
+
* ```
|
|
336
|
+
*
|
|
337
|
+
* @example Inject global styles for a micro component into the document:
|
|
338
|
+
* ```ts
|
|
339
|
+
* import { injectCSS } from '@twobirds/mc/utils/helpers';
|
|
340
|
+
* injectCSS(document, 'my-microcomponent { display: block; }');
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @example Inject scoped styles into a shadow root:
|
|
344
|
+
* ```ts
|
|
345
|
+
* const shadow = element.attachShadow({ mode: 'open' });
|
|
346
|
+
* injectCSS(shadow, ':host { color: var(--text); } .inner { padding: 8px; }');
|
|
347
|
+
* ```
|
|
348
|
+
* Styles can also be added using a compound innerHTML statement: `shadow.innerHTML = \`<style>${style}</style>${template}\``
|
|
349
|
+
*/
|
|
350
|
+
export function injectCSS(target, css) {
|
|
351
|
+
const sheet = new CSSStyleSheet();
|
|
352
|
+
sheet.replaceSync(css);
|
|
353
|
+
target.adoptedStyleSheets.push(sheet);
|
|
354
|
+
return sheet;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Processes a record of asset strings and applies them to the given target element.
|
|
358
|
+
* Supports injecting CSS into document or shadow root, and setting innerHTML for
|
|
359
|
+
* both target and shadow DOM. Automatically attaches a shadow root if any key starts
|
|
360
|
+
* with `'shadow'`.
|
|
361
|
+
*
|
|
362
|
+
* Recognized keys: `'css'`, `'targetCss'` (document-level styles), `'shadowCss'`
|
|
363
|
+
* (shadow-root styles), `'shadowHtml'` (shadow innerHTML), `'targetHtml'` (target innerHTML).
|
|
364
|
+
*
|
|
365
|
+
* @param target - The HTMLElement to apply assets onto.
|
|
366
|
+
* @param assets - A record mapping asset type keys to their string content.
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```ts
|
|
370
|
+
* processAssets(this, {
|
|
371
|
+
* css: 'body { margin: 0; }',
|
|
372
|
+
* shadowCss: ':host { display: block; }',
|
|
373
|
+
* shadowHtml: '<slot></slot>'
|
|
374
|
+
* });
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
export function processAssets(instance, assets) {
|
|
378
|
+
const target = instance.target;
|
|
379
|
+
let shadow = target.shadowRoot;
|
|
380
|
+
if (!shadow && Object.keys(assets).some((key) => key.indexOf('shadow') === 0)) {
|
|
381
|
+
shadow = target.attachShadow({ mode: 'open' });
|
|
382
|
+
}
|
|
383
|
+
Object.keys(assets).forEach((key) => {
|
|
384
|
+
switch (key) {
|
|
385
|
+
case 'css':
|
|
386
|
+
injectCSS(document, assets[key]);
|
|
387
|
+
break;
|
|
388
|
+
case 'targetCss':
|
|
389
|
+
injectCSS(document, assets[key]);
|
|
390
|
+
break;
|
|
391
|
+
case 'shadowCss':
|
|
392
|
+
injectCSS(shadow, assets[key]);
|
|
393
|
+
break;
|
|
394
|
+
case 'shadowHtml':
|
|
395
|
+
shadow.innerHTML = assets[key];
|
|
396
|
+
bindTemplateEvents(shadow, instance);
|
|
397
|
+
break;
|
|
398
|
+
case 'targetHtml':
|
|
399
|
+
target.innerHTML = assets[key];
|
|
400
|
+
bindTemplateEvents(target, instance);
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Loads companion asset files (CSS, HTML) for a given component basename from the server.
|
|
407
|
+
*
|
|
408
|
+
* Each entry in `assets` encodes an optional variant and extension in camelCase, e.g. `'shadowCss'` → `{name}.shadow.css`,
|
|
409
|
+
* `'targetHtml'` → `{name}.target.html`. Plain entries like `'css'` or `'html'` resolve to
|
|
410
|
+
* `{name}.css` / `{name}.html`.
|
|
411
|
+
*
|
|
412
|
+
* In bundled mode the Vite plugin replaces this call with an inline array literal, so `.then()`
|
|
413
|
+
* fires synchronously — no async overhead.
|
|
414
|
+
*
|
|
415
|
+
* @hidden
|
|
416
|
+
* @param name - The component basename (e.g. `'shop-catalog'`).
|
|
417
|
+
* @param assets - Array of asset descriptors such as `'shadowCss'`, `'targetHtml'`, `'shadowHtml'`, `'css'`, `'html'`.
|
|
418
|
+
* @returns A promise resolving to an array of file contents in the same order as `assets`. If a file is not found, the corresponding entry is `'file not found: ' + filename`.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* export const MyComponent = loadAssets('my-component', ['shadowCss', 'shadowHtml']).then(([shadowCss, shadowHtml]) => {
|
|
423
|
+
* class _MyComponent extends DC { ... }
|
|
424
|
+
* defineCE('my-component', _MyComponent);
|
|
425
|
+
* return _MyComponent;
|
|
426
|
+
* });
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
export function loadAssets(name, assets) {
|
|
430
|
+
const parseAsset = (asset) => {
|
|
431
|
+
// Match camelCase variant+ext, e.g. 'shadowCss' → ['shadow','css']
|
|
432
|
+
const m = asset.match(/^([a-z]+)([A-Z][a-z]*)$/);
|
|
433
|
+
if (m) {
|
|
434
|
+
return `./${name.replace(/-/g, '/')}.${m[1]}.${m[2].toLowerCase()}`;
|
|
435
|
+
}
|
|
436
|
+
// Plain extension, e.g. 'css' → 'catalog.css'
|
|
437
|
+
return `./${name.replace(/-/g, '/')}.${asset.toLowerCase()}`;
|
|
438
|
+
};
|
|
439
|
+
return Promise.all(assets.map(async (asset) => {
|
|
440
|
+
const filename = parseAsset(asset);
|
|
441
|
+
//console.log(filename);
|
|
442
|
+
try {
|
|
443
|
+
const resp = await fetch(filename);
|
|
444
|
+
if (!resp.ok) {
|
|
445
|
+
return `file not found: ${filename}`;
|
|
446
|
+
}
|
|
447
|
+
return resp.text();
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
return `file not found: ${filename}`;
|
|
451
|
+
}
|
|
452
|
+
}));
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Binds declarative event attributes in a template fragment to microcomponent triggers.
|
|
456
|
+
*
|
|
457
|
+
* Scans all elements under `root` for attributes whose names correspond to native DOM
|
|
458
|
+
* events (e.g. `click`, `submit`, `change`). The attribute value encodes the target and
|
|
459
|
+
* handler method in the form `target#methodName`:
|
|
460
|
+
*
|
|
461
|
+
* - `this#myHandler` — triggers locally on the component attached to this element.
|
|
462
|
+
* - `#other-comp#submit` — resolves elements via `querySelectorAll('#other-comp')` and
|
|
463
|
+
* triggers the event on each matched host's `_mc`.
|
|
464
|
+
*
|
|
465
|
+
* An optional sibling `payload` attribute supplies the data argument for `trigger()`.
|
|
466
|
+
* After binding, both the event attribute and the payload attribute are removed from the DOM.
|
|
467
|
+
*
|
|
468
|
+
* @param root - The container element whose descendants should be scanned for bindings.
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```html
|
|
472
|
+
* <button click="this#onSubmit" payload='{"action":"go"}'>Submit</button>
|
|
473
|
+
* <input change="#cart-form#refresh">
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
export function bindTemplateEvents(root, instance) {
|
|
477
|
+
// Collect all elements that carry at least one attribute matching a native event name.
|
|
478
|
+
const allElements = root.querySelectorAll('*');
|
|
479
|
+
for (const el of allElements) {
|
|
480
|
+
if (!(el instanceof HTMLElement))
|
|
481
|
+
continue;
|
|
482
|
+
const attrs = Array.from(el.attributes);
|
|
483
|
+
for (const attr of attrs) {
|
|
484
|
+
const lowerName = attr.name.toLowerCase();
|
|
485
|
+
// Check if this attribute name maps to a native event handler property.
|
|
486
|
+
if (!('on' + lowerName in el))
|
|
487
|
+
continue;
|
|
488
|
+
const [selector, event, payload] = attr.value.trim().split('#');
|
|
489
|
+
if (!event)
|
|
490
|
+
continue; // need at least selector and eventname
|
|
491
|
+
// Resolve payload from sibling attribute if present.
|
|
492
|
+
let payloadData; // intentional
|
|
493
|
+
if (payload) {
|
|
494
|
+
try {
|
|
495
|
+
payloadData = JSON.parse(payload);
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
payloadData = payload;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
// Wire the native event listener.
|
|
502
|
+
if (selector === 'this' || selector === '') {
|
|
503
|
+
// Local trigger — fire on the _mc attached to this element.
|
|
504
|
+
on(el, lowerName, () => instance.trigger(event, payloadData));
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
// Selector-based trigger — query and fire on every match.
|
|
508
|
+
on(el, lowerName, () => trigger(selector, event, payloadData));
|
|
509
|
+
}
|
|
510
|
+
// Clean up binding attributes from the DOM.
|
|
511
|
+
el.removeAttribute(attr.name);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twobirds/microcomponents",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Micro Components Organization Class",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"API",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"import": "./dist/core/mcGuards.js"
|
|
52
52
|
},
|
|
53
53
|
"./events": {
|
|
54
|
-
"types": "./dist/
|
|
55
|
-
"import": "./dist/
|
|
54
|
+
"types": "./dist/utils/events.d.ts",
|
|
55
|
+
"import": "./dist/utils/events.js"
|
|
56
56
|
},
|
|
57
57
|
"./elements": {
|
|
58
58
|
"types": "./dist/core/elements.d.ts",
|
|
@@ -78,17 +78,17 @@
|
|
|
78
78
|
"test:run": "vitest run --reporter=verbose",
|
|
79
79
|
"test:coverage": "vitest run --coverage",
|
|
80
80
|
"demo:shop": "vite --config demo/shop/vite.config.ts",
|
|
81
|
-
"demo:shop:bundled": "
|
|
82
|
-
"demo:shop:build": "
|
|
81
|
+
"demo:shop:bundled": "tsx vite.shop.bundle.ts",
|
|
82
|
+
"demo:shop:build": "tsx vite.shop.ts && pnpm run demo:shop:bundled",
|
|
83
83
|
"demo:shop:serve": "vite preview --outDir public/shop --port 5174 --host",
|
|
84
84
|
"typedoc": "typedoc",
|
|
85
|
-
"bundle": "
|
|
86
|
-
"clean": "rm -rf dist public",
|
|
87
|
-
"build": "pnpm run clean && tsc -p tsconfig.lib.json && pnpm run test:coverage && pnpm run bundle && pnpm run check:pack && pnpm run typedoc && pnpm run demo:build && pnpm run demo:shop:build",
|
|
88
|
-
"demo:build": "
|
|
85
|
+
"bundle": "tsx vite.build.ts",
|
|
86
|
+
"clean": "rm -rf dist public build",
|
|
87
|
+
"build": "pnpm run clean && tsc -p tsconfig.lib.json && pnpm run test:coverage && pnpm run bundle && pnpm run check:pack && pnpm run typedoc && pnpm run demo:build && pnpm run demo:shop:build && find src -name '*.js' -delete",
|
|
88
|
+
"demo:build": "tsx vite.demo.ts",
|
|
89
89
|
"dev": "vite preview --outDir public/test --port 10000 --host",
|
|
90
90
|
"doc": "vite preview --outDir public/typedoc --port 11000 --host",
|
|
91
|
-
"watch": "
|
|
91
|
+
"watch": "tsx watch.ts",
|
|
92
92
|
"prepublishOnly": "pnpm run build && pnpm run check"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
"oxfmt": "^0.59.0",
|
|
100
100
|
"oxlint": "^1.74.0",
|
|
101
101
|
"publint": "^0.3.21",
|
|
102
|
+
"tsx": "^4.23.12",
|
|
102
103
|
"typedoc": "^0.28.20",
|
|
103
104
|
"typescript": "^6.0.3",
|
|
104
105
|
"vite": "^8.1.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"autoload.d.ts","sourceRoot":"","sources":["../../src/core/autoload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;EASE;AAoJF;;;;;;;;;;;;EAYE;AACF,MAAM,WAAW,QAAQ;IACxB;;;;;;;;;;;;;IAaG;IACH,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B;;;;;IAKG;IACH,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;KACpB;CACD;AAID,eAAO,MAAM,QAAQ,EAAE,QAuBtB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDE;AAIF,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAElB,cAAc,EACd,MAAM,qBAAqB,CAAC;AAG7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,mBAAmB,GAAG,SAAS,GAAG,IAAI,CAAC;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,GAAG,CAAC,CAAC,GAAG,OAAO,EAC9B,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,IAAI,CAAC;AACR,wBAAgB,GAAG,CAClB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kCAAkC,GACzC,IAAI,CAAC;AA0BR;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,EAAE,CAAC,CAAC,GAAG,OAAO,EAC7B,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,IAAI,CAAC,EAAE,OAAO,GACZ,cAAc,CAAC,CAAC,CAAC,CAAC;AACrB,wBAAgB,EAAE,CACjB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kCAAkC,EAC3C,IAAI,CAAC,EAAE,OAAO,GACZ,kCAAkC,CAAC;AA8BtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,GAAG,CAAC,CAAC,GAAG,OAAO,EAC9B,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,cAAc,CAAC,CAAC,CAAC,CAAC;AACrB,wBAAgB,GAAG,CAClB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kCAAkC,GACzC,kCAAkC,CAAC;AAsBtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,gBAAiB,YAAW,kBAAkB;IAC1D,OAAO,UAAS;;IAEhB;;;;;;;;;;;;;;;OAeG;IACH,IAAI;CAGJ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EAClC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAC/C,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,CAAW,EACjB,MAAM,GAAE,gBAAsB,EAAE,wBAAwB;AACxD,UAAU,CAAC,EAAE,gBAAgB,QA+C7B"}
|
|
File without changes
|