@twobirds/microcomponents 0.1.21 → 0.2.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/LICENSE +21 -0
- package/README.md +91 -92
- package/dist/MC.min.js +1 -345
- package/dist/autoload.min.js +1 -0
- package/dist/core/MC.d.ts +401 -0
- package/dist/core/MC.d.ts.map +1 -0
- package/dist/core/MC.js +471 -0
- package/dist/core/autoload.d.ts +54 -0
- package/dist/core/autoload.d.ts.map +1 -0
- package/dist/core/autoload.js +158 -0
- package/dist/core/elements.d.ts +232 -0
- package/dist/core/elements.d.ts.map +1 -0
- package/dist/core/elements.js +123 -0
- package/dist/core/events.d.ts +231 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +228 -0
- package/dist/core/mcGuards.d.ts +49 -0
- package/dist/core/mcGuards.d.ts.map +1 -0
- package/dist/core/mcGuards.js +19 -0
- package/dist/elements.min.js +1 -1
- package/dist/events.min.js +1 -0
- package/dist/formValues.min.js +1 -1
- package/dist/mcGuards.min.js +1 -0
- package/dist/microcomponents.d.ts +8 -5
- package/dist/microcomponents.d.ts.map +1 -1
- package/dist/microcomponents.js +8 -5
- package/dist/microcomponents.min.js +1 -1
- package/dist/observables.min.js +1 -1
- package/dist/state/formValues.d.ts +70 -0
- package/dist/state/formValues.d.ts.map +1 -0
- package/dist/state/formValues.js +334 -0
- package/dist/state/observables.d.ts +276 -0
- package/dist/state/observables.d.ts.map +1 -0
- package/dist/state/observables.js +382 -0
- package/dist/state/placeholders.d.ts +62 -0
- package/dist/state/placeholders.d.ts.map +1 -0
- package/dist/state/placeholders.js +181 -0
- package/dist/types/mcTypes.d.ts +201 -0
- package/dist/types/mcTypes.d.ts.map +1 -0
- package/dist/types/mcTypes.js +9 -0
- package/dist/utils/helpers.d.ts +195 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +340 -0
- package/package.json +96 -62
- package/dist/MC.d.ts +0 -31
- package/dist/MC.d.ts.map +0 -1
- package/dist/MC.js +0 -249
- package/dist/MC.ts +0 -613
- package/dist/MicroComponents.svg +0 -15
- package/dist/elements.d.ts +0 -5
- package/dist/elements.d.ts.map +0 -1
- package/dist/elements.js +0 -49
- package/dist/elements.ts +0 -114
- package/dist/events.d.ts +0 -11
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -55
- package/dist/events.ts +0 -158
- package/dist/formValues.d.ts +0 -3
- package/dist/formValues.d.ts.map +0 -1
- package/dist/formValues.js +0 -156
- package/dist/formValues.ts +0 -371
- package/dist/helpers.d.ts +0 -15
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js +0 -113
- package/dist/helpers.ts +0 -219
- package/dist/main.mjs +0 -1
- package/dist/microcomponents.ts +0 -6
- package/dist/observables.d.ts +0 -11
- package/dist/observables.d.ts.map +0 -1
- package/dist/observables.js +0 -228
- package/dist/observables.ts +0 -449
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Web Components
|
|
3
|
+
*
|
|
4
|
+
* Defines micro component integration with native web components and the CustomElementRegistry.
|
|
5
|
+
*
|
|
6
|
+
* This module provides utilities for defining custom HTML elements using the native Web Components API.
|
|
7
|
+
*
|
|
8
|
+
* ---
|
|
9
|
+
*
|
|
10
|
+
* The {@link defineCE} function handles registration of custom elements with the CustomElementRegistry,
|
|
11
|
+
* automatically attaching the provided class as a DC instance ( micro component ) to the native web component created.
|
|
12
|
+
* This class and any DC instances added to the web component later will receive all web component native events.
|
|
13
|
+
* Only the class that defines the WC also defines its observed attributes, but all inner DCs get the changed event.
|
|
14
|
+
*
|
|
15
|
+
* The {@link getCE} function is just a wrapper for customElements.get()
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
*
|
|
19
|
+
* code:
|
|
20
|
+
* ```javascript
|
|
21
|
+
* // create a custom micro component class
|
|
22
|
+
* class MyComponent extends DC{
|
|
23
|
+
*
|
|
24
|
+
* constructor( target ){
|
|
25
|
+
* super( target );
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* defineCE( 'my-component', MyComponent );
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* afterwards you can use ...
|
|
34
|
+
* ```HTML
|
|
35
|
+
* <my-component></my-component>
|
|
36
|
+
* ```
|
|
37
|
+
* ... in your template.
|
|
38
|
+
*
|
|
39
|
+
* Or you can construct it programmatically:
|
|
40
|
+
* ```javascript
|
|
41
|
+
* const myComponentClass = getCE('my-component');
|
|
42
|
+
* const body = document.body;
|
|
43
|
+
* body.append( new myComponentClass() );
|
|
44
|
+
* ```
|
|
45
|
+
* ---
|
|
46
|
+
*/
|
|
47
|
+
import { type McHost } from './MC.js';
|
|
48
|
+
/**
|
|
49
|
+
Resolves the host element type for a given `extend` tag: the matching built-in
|
|
50
|
+
element type when extending one (e.g. `'button'` → `HTMLButtonElement`),
|
|
51
|
+
plain `HTMLElement` otherwise.
|
|
52
|
+
|
|
53
|
+
@example
|
|
54
|
+
```ts
|
|
55
|
+
type Btn = TargetOf<'button'>; // HTMLButtonElement
|
|
56
|
+
type Plain = TargetOf<'div'>; // HTMLElement
|
|
57
|
+
```
|
|
58
|
+
*/
|
|
59
|
+
export type TargetOf<E> = E extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[E] : HTMLElement;
|
|
60
|
+
/**
|
|
61
|
+
The type-level mirror of `kebabToPascal()` in helpers.ts: `'user-card'` →
|
|
62
|
+
`'UserCard'`. Lets {@link defineCE} type the `_mc` registry entry under the
|
|
63
|
+
exact key the runtime stores it at.
|
|
64
|
+
*/
|
|
65
|
+
export type McPascalCase<S extends string> = S extends `${infer Head}-${infer Rest}` ? `${Capitalize<Head>}${McPascalCase<Rest>}` : Capitalize<S>;
|
|
66
|
+
/**
|
|
67
|
+
The custom element constructor returned by {@link defineCE}. Constructing it
|
|
68
|
+
programmatically accepts an optional `data` payload, forwarded as the second
|
|
69
|
+
argument to the microcomponent class. The resulting element exposes its
|
|
70
|
+
microcomponent instance via `._mc`, keyed by the PascalCase form of the tag
|
|
71
|
+
name (`N`); with the default `N = string` no entry is claimed.
|
|
72
|
+
|
|
73
|
+
@template T - The microcomponent class hosted by the element.
|
|
74
|
+
@template D - The optional construction payload accepted by `new`.
|
|
75
|
+
@template E - The built-in tag being extended, if any (customized built-in elements).
|
|
76
|
+
@template N - The literal PascalCase registry key; `defineCE` fills in `McPascalCase<Tag>`.
|
|
77
|
+
*/
|
|
78
|
+
export type McElementConstructor<T extends object = object, D = unknown, E extends keyof HTMLElementTagNameMap | undefined = undefined, N extends string = string> = new (data?: D) => McHost<TargetOf<E>, string extends N ? Record<never, never> : Record<N, T>>;
|
|
79
|
+
declare global {
|
|
80
|
+
/**
|
|
81
|
+
Tag-name → constructor map for microcomponent custom elements — the Mc
|
|
82
|
+
analogue of `HTMLElementTagNameMap`. Empty by default; register an element
|
|
83
|
+
once, app-wide, via declaration merging and `getCE()` returns the typed
|
|
84
|
+
constructor for that tag string:
|
|
85
|
+
|
|
86
|
+
@example
|
|
87
|
+
```ts
|
|
88
|
+
class UserCard extends DC {}
|
|
89
|
+
defineCE('user-card', UserCard);
|
|
90
|
+
|
|
91
|
+
declare global {
|
|
92
|
+
interface McElementTagNameMap {
|
|
93
|
+
'user-card': McElementConstructor<UserCard, { initial: number }, undefined, 'UserCard'>;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const Ctor = getCE('user-card'); // typed — no cast
|
|
98
|
+
if (Ctor) {
|
|
99
|
+
const card = new Ctor({ initial: 1 }); // payload checked
|
|
100
|
+
card._mc.UserCard; // UserCard
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
*/
|
|
104
|
+
interface McElementTagNameMap {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
Defines a custom HTML element with optional observed attributes and micro component integration.
|
|
109
|
+
The class provided in DefinitionClass will be added to the ._mc hash object appended to the custom element instance.
|
|
110
|
+
Automatically assigns a "PascalCase" class name derived from the <kebab-case> tagName.
|
|
111
|
+
If the provided definition class extends McBase (indicating a DC or MC class extension), it wraps the constructor to register
|
|
112
|
+
the element instance with DC (DomComponent).
|
|
113
|
+
|
|
114
|
+
@param tagName - The HTML tag name for the custom element (must contain at least one hyphen, enforced at compile time).
|
|
115
|
+
@param DefinitionClass - The constructor function or class that defines the element's behavior. Its `target` parameter type follows `extend`; an optional second `data` parameter receives the payload passed on programmatic construction.
|
|
116
|
+
@param observedAttributes - An optional array of attribute names to observe for changes.
|
|
117
|
+
@param extend - An optional built-in HTML element tag name to extend, enabling customized built-in elements.
|
|
118
|
+
@returns The registered custom element constructor, typed to accept the `data` payload
|
|
119
|
+
and exposing the `_mc` entry under the PascalCase tag name — or `undefined` if the
|
|
120
|
+
tag name was already defined. Feed it (or an equivalent `McElementConstructor`) to
|
|
121
|
+
the global {@link McElementTagNameMap} to make `getCE()` return it typed by string.
|
|
122
|
+
|
|
123
|
+
@example define a custom component
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
javascript:
|
|
128
|
+
```javascript
|
|
129
|
+
class MyElement extends DC {
|
|
130
|
+
|
|
131
|
+
constructor( target ){
|
|
132
|
+
super(target);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// DOM web component event handler
|
|
136
|
+
onConnected() {
|
|
137
|
+
this.innerHTML = '<p>Hi!</p>';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// DOM standard event handler
|
|
141
|
+
onClick(){
|
|
142
|
+
this.trigger('something', { data: 'do something' } );
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// DOM custom event handler
|
|
146
|
+
oneSomething(ev){
|
|
147
|
+
// do only once! Subsequent clicks will not trigger this handler
|
|
148
|
+
console.log('something happens here:', ev.detail.data );
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
defineCE( 'my-element', MyElement );
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
afterwards you can use ...
|
|
156
|
+
html:
|
|
157
|
+
```HTML
|
|
158
|
+
<my-element></my-element>
|
|
159
|
+
```
|
|
160
|
+
... in your template.
|
|
161
|
+
|
|
162
|
+
Or you can construct it programmatically using {@link getCE}:
|
|
163
|
+
javascript:
|
|
164
|
+
```javascript
|
|
165
|
+
const MyElementClass = getCE('my-element');
|
|
166
|
+
const body = document.body;
|
|
167
|
+
body.append( new MyElementClass() );
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
@example Extending a built-in element (customized built-in element)
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
javascript:
|
|
175
|
+
```javascript
|
|
176
|
+
class MyButton extends DC {
|
|
177
|
+
constructor(target) {
|
|
178
|
+
super(target);
|
|
179
|
+
}
|
|
180
|
+
onConnected() {
|
|
181
|
+
this.textContent = 'Click me!';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
defineCE('my-button', MyButton, [], 'button');
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
afterwards you can use it in your template with the `is` attribute:
|
|
189
|
+
```HTML
|
|
190
|
+
<button is="my-button"></button>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
Or you can construct it programmatically using {@link getCE}:
|
|
195
|
+
javascript:
|
|
196
|
+
```javascript
|
|
197
|
+
const MyButtonClass = getCE('my-button');
|
|
198
|
+
const body = document.body;
|
|
199
|
+
body.append( new MyButtonClass() );
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Hints:
|
|
203
|
+
- Your micro component must extend DC, since it is a DOM element
|
|
204
|
+
- method names that look like event handlers are DOM - or custom event handlers ( 'onClick()', 'oneSomething()' )
|
|
205
|
+
- event handlers defined as methods will be assigned to the DOM automatically
|
|
206
|
+
*/
|
|
207
|
+
export declare function defineCE<Tag extends `${string}-${string}`, T extends object, D, E extends keyof HTMLElementTagNameMap | undefined = undefined>(tagName: Tag, DefinitionClass: new (target: TargetOf<E>, data?: D) => T, observedAttributes?: string[], extend?: E): McElementConstructor<T, D, E, McPascalCase<Tag>> | undefined;
|
|
208
|
+
export declare function defineCE<Tag extends `${string}-${string}`, T extends object, E extends keyof HTMLElementTagNameMap | undefined = undefined>(tagName: Tag, DefinitionClass: new (target: TargetOf<E>) => T, observedAttributes?: string[], extend?: E): McElementConstructor<T, undefined, E, McPascalCase<Tag>> | undefined;
|
|
209
|
+
export declare function defineCE<Tag extends `${string}-${string}`, T extends object, D, E extends keyof HTMLElementTagNameMap | undefined = undefined>(tagName: Tag, DefinitionClass: new (target: TargetOf<E>, data: D) => T, observedAttributes?: string[], extend?: E): McElementConstructor<T, D, E, McPascalCase<Tag>> | undefined;
|
|
210
|
+
/**
|
|
211
|
+
Retrieves a custom element constructor by tag name.
|
|
212
|
+
|
|
213
|
+
Tags registered on the global {@link McElementTagNameMap} (via declaration
|
|
214
|
+
merging) come back as their declared constructor type — payload and `_mc`
|
|
215
|
+
entry included; any other string falls back to the plain
|
|
216
|
+
`CustomElementConstructor`.
|
|
217
|
+
|
|
218
|
+
@example
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const MyElementClass = getCE('my-element');
|
|
222
|
+
if (MyElementClass) {
|
|
223
|
+
document.body.append(new MyElementClass());
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
@param tagName - The HTML tag name to look up.
|
|
228
|
+
@returns The constructor if defined, or undefined if not found.
|
|
229
|
+
*/
|
|
230
|
+
export declare function getCE<K extends keyof McElementTagNameMap & string>(tagName: K): McElementTagNameMap[K] | undefined;
|
|
231
|
+
export declare function getCE(tagName: string): CustomElementConstructor | undefined;
|
|
232
|
+
//# sourceMappingURL=elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../../src/core/elements.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Web Components
|
|
3
|
+
*
|
|
4
|
+
* Defines micro component integration with native web components and the CustomElementRegistry.
|
|
5
|
+
*
|
|
6
|
+
* This module provides utilities for defining custom HTML elements using the native Web Components API.
|
|
7
|
+
*
|
|
8
|
+
* ---
|
|
9
|
+
*
|
|
10
|
+
* The {@link defineCE} function handles registration of custom elements with the CustomElementRegistry,
|
|
11
|
+
* automatically attaching the provided class as a DC instance ( micro component ) to the native web component created.
|
|
12
|
+
* This class and any DC instances added to the web component later will receive all web component native events.
|
|
13
|
+
* Only the class that defines the WC also defines its observed attributes, but all inner DCs get the changed event.
|
|
14
|
+
*
|
|
15
|
+
* The {@link getCE} function is just a wrapper for customElements.get()
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
*
|
|
19
|
+
* code:
|
|
20
|
+
* ```javascript
|
|
21
|
+
* // create a custom micro component class
|
|
22
|
+
* class MyComponent extends DC{
|
|
23
|
+
*
|
|
24
|
+
* constructor( target ){
|
|
25
|
+
* super( target );
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* defineCE( 'my-component', MyComponent );
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* afterwards you can use ...
|
|
34
|
+
* ```HTML
|
|
35
|
+
* <my-component></my-component>
|
|
36
|
+
* ```
|
|
37
|
+
* ... in your template.
|
|
38
|
+
*
|
|
39
|
+
* Or you can construct it programmatically:
|
|
40
|
+
* ```javascript
|
|
41
|
+
* const myComponentClass = getCE('my-component');
|
|
42
|
+
* const body = document.body;
|
|
43
|
+
* body.append( new myComponentClass() );
|
|
44
|
+
* ```
|
|
45
|
+
* ---
|
|
46
|
+
*/
|
|
47
|
+
import { kebabToPascal } from '../utils/helpers.js';
|
|
48
|
+
import { McBase, DC } from './MC.js';
|
|
49
|
+
/**
|
|
50
|
+
Creates a named class constructor with the specified name.
|
|
51
|
+
@param name - The desired name for the class.
|
|
52
|
+
@param targetClass - The class constructor to which the name will be assigned.
|
|
53
|
+
@returns The class constructor with the name property set.
|
|
54
|
+
|
|
55
|
+
@example
|
|
56
|
+
```ts
|
|
57
|
+
const MyNamedClass = createNamedClass('MyNamedClass', class { });
|
|
58
|
+
console.log(MyNamedClass.name); // 'MyNamedClass'
|
|
59
|
+
```
|
|
60
|
+
*/
|
|
61
|
+
function createNamedClass(name, targetClass) {
|
|
62
|
+
return Object.defineProperty(targetClass, 'name', { value: name });
|
|
63
|
+
}
|
|
64
|
+
function Base(ElementClass) {
|
|
65
|
+
return class extends ElementClass {
|
|
66
|
+
constructor(...args) {
|
|
67
|
+
super(...args);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Implementation signature (not directly callable)
|
|
72
|
+
export function defineCE(tagName, DefinitionClass, observedAttributes = [], extend) {
|
|
73
|
+
if (customElements.get(tagName)) {
|
|
74
|
+
console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!tagName.includes('-')) {
|
|
78
|
+
throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');
|
|
79
|
+
}
|
|
80
|
+
let extendClass = HTMLElement;
|
|
81
|
+
if (extend) {
|
|
82
|
+
extendClass = document.createElement(extend).constructor;
|
|
83
|
+
}
|
|
84
|
+
const pascalCaseName = kebabToPascal(tagName);
|
|
85
|
+
// a class, but not a MC — the class itself is the element; no `._mc` is attached
|
|
86
|
+
if (!(DefinitionClass.prototype instanceof McBase)) {
|
|
87
|
+
customElements.define(tagName, DefinitionClass);
|
|
88
|
+
return DefinitionClass;
|
|
89
|
+
}
|
|
90
|
+
// a MC
|
|
91
|
+
const McElementClass = createNamedClass(pascalCaseName, class extends Base(extendClass) {
|
|
92
|
+
constructor(data) {
|
|
93
|
+
super();
|
|
94
|
+
DC.add(this, pascalCaseName, new DefinitionClass(this, data));
|
|
95
|
+
}
|
|
96
|
+
connectedCallback() {
|
|
97
|
+
this.dispatchEvent(new CustomEvent('_mcConnected'));
|
|
98
|
+
}
|
|
99
|
+
connectedMoveCallback() {
|
|
100
|
+
this.dispatchEvent(new CustomEvent('_mcConnectedMove'));
|
|
101
|
+
}
|
|
102
|
+
disconnectedCallback() {
|
|
103
|
+
this.dispatchEvent(new CustomEvent('_mcDisconnected'));
|
|
104
|
+
}
|
|
105
|
+
adoptedCallback() {
|
|
106
|
+
this.dispatchEvent(new CustomEvent('_mcAdopted'));
|
|
107
|
+
}
|
|
108
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
109
|
+
this.dispatchEvent(new CustomEvent('_mcAttributeChanged', { detail: { name, oldValue, newValue } }));
|
|
110
|
+
}
|
|
111
|
+
formResetCallback() {
|
|
112
|
+
this.dispatchEvent(new CustomEvent('_mcFormReset'));
|
|
113
|
+
}
|
|
114
|
+
static get observedAttributes() {
|
|
115
|
+
return [...observedAttributes];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
customElements.define(tagName, McElementClass, { extends: extend });
|
|
119
|
+
return McElementClass;
|
|
120
|
+
}
|
|
121
|
+
export function getCE(tagName) {
|
|
122
|
+
return customElements.get(tagName);
|
|
123
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@module
|
|
3
|
+
|
|
4
|
+
This module provides event utilities for interfacing **between microcomponents and external
|
|
5
|
+
frameworks or native DOM/JS environments**. It is not intended for communication between
|
|
6
|
+
frontend microcomponents themselves — for that purpose, use the inherited methods
|
|
7
|
+
( `.on()`, `.one()`, `.off()`, `.trigger()`) that exist when you extend `DC`.
|
|
8
|
+
|
|
9
|
+
Import this module when you need to exchange information with microcomponents from outside
|
|
10
|
+
the microcomponent system (e.g., vanilla JS, React via `useRef()`, or other frameworks).
|
|
11
|
+
|
|
12
|
+
The core feature is the ability to explicitly control event flow direction when using {@link trigger}:
|
|
13
|
+
- upward propagation to ancestor components ('u')
|
|
14
|
+
- local dispatch only ('l') [default]
|
|
15
|
+
- downward propagation to descendant components ('d').
|
|
16
|
+
|
|
17
|
+
@example
|
|
18
|
+
html:
|
|
19
|
+
```html
|
|
20
|
+
<div class="grandparent">
|
|
21
|
+
<div class="parent">
|
|
22
|
+
<div class="child">
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
javascript:
|
|
29
|
+
```javascript
|
|
30
|
+
import { on, one, trigger, off } from '@twobirds/microcomponents/events';
|
|
31
|
+
|
|
32
|
+
// Attach listeners (querySelector may return null — guard first)
|
|
33
|
+
const grandParent = document.querySelector('.grandparent');
|
|
34
|
+
const parent = document.querySelector('.parent');
|
|
35
|
+
const child = document.querySelector('.child');
|
|
36
|
+
if (!grandParent || !parent || !child) throw new Error('example markup missing');
|
|
37
|
+
|
|
38
|
+
const grandParentHandler = on(
|
|
39
|
+
grandParent,
|
|
40
|
+
'dataReady',
|
|
41
|
+
(ev) => console.log(ev.detail.data)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const parentHandler = on(
|
|
45
|
+
parent,
|
|
46
|
+
'dataReady',
|
|
47
|
+
(ev) => ev.detail.control.stop()
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// this event bubbles toward root from the innermost div ..
|
|
51
|
+
trigger( child, 'dataReady', { value: 42 }, 'u');
|
|
52
|
+
// ...but the 'dataReady' handler on grandParent will never be reached !!!
|
|
53
|
+
|
|
54
|
+
// Clean up handlers when done
|
|
55
|
+
off( parent, 'dataReady', parentHandler );
|
|
56
|
+
off( grandParent, 'dataReady', grandParentHandler );
|
|
57
|
+
```
|
|
58
|
+
*/
|
|
59
|
+
import type { BubbleDirections, McBubbleController, McEventHandler } from '../types/mcTypes.js';
|
|
60
|
+
/**
|
|
61
|
+
* Converts a standard event name to its microcomponent-prefixed variant.
|
|
62
|
+
*
|
|
63
|
+
* This utility is used internally to namespace custom events (e.g., 'Click' → '_mcClick').
|
|
64
|
+
*
|
|
65
|
+
* @param eventName - The original event name (e.g., 'click', 'update').
|
|
66
|
+
* @returns The microcomponent-prefixed event name.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* getMcEventName('update'); // '_mcUpdate'
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function getMcEventName(eventName: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* A query selector string used to match one or more DOM elements.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const selector: QuerySelectorString = '.my-component';
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export type QuerySelectorString = string;
|
|
83
|
+
/**
|
|
84
|
+
* Represents the target of an event operation — either a concrete element,
|
|
85
|
+
* a CSS selector string, or `undefined` (which is silently ignored).
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* // Pass an HTMLElement directly
|
|
90
|
+
* const el: TargetSelect = document.getElementById('root');
|
|
91
|
+
*
|
|
92
|
+
* // Or pass a selector string to match multiple elements
|
|
93
|
+
* const allCards: TargetSelect = '.card';
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export type TargetSelect = HTMLElement | QuerySelectorString | undefined | null;
|
|
97
|
+
/**
|
|
98
|
+
* Removes a previously attached event handler from the DOM node. See {@link on} and {@link one}.
|
|
99
|
+
*
|
|
100
|
+
* Uses internal microcomponent-prefixed naming for event handlers.
|
|
101
|
+
* This is primarily used to interface with external frameworks or vanilla JS environments.
|
|
102
|
+
* For communication between frontend microcomponents, use the `DC.off()` method instead.
|
|
103
|
+
*
|
|
104
|
+
* @param target - The DOM element from which to remove the listener.
|
|
105
|
+
* @param eventName - The name of the event (e.g., 'click', 'update').
|
|
106
|
+
* @param handler - The listener function or object to detach.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const handler = on(myElement, 'click', () => console.log('clicked'));
|
|
111
|
+
* off(myElement, 'click', handler); // removes the listener
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function off<D = unknown>(target: TargetSelect, eventName: string, handler: McEventHandler<D>): void;
|
|
115
|
+
export declare function off(target: TargetSelect, eventName: string, handler: EventListenerOrEventListenerObject): void;
|
|
116
|
+
/**
|
|
117
|
+
* Attaches a persistent event listener that will fire every time the specified event occurs.
|
|
118
|
+
*
|
|
119
|
+
* This is primarily used to interface with external frameworks or vanilla JS environments.
|
|
120
|
+
* For communication between frontend microcomponents, use the `DC.on()` method instead.
|
|
121
|
+
*
|
|
122
|
+
* The handler receives a `CustomEvent<McDetail<D>>`: the payload sits under
|
|
123
|
+
* `ev.detail.data`, the bubble-control handle under `ev.detail.control`.
|
|
124
|
+
*
|
|
125
|
+
* @param target - The DOM element to attach the listener to.
|
|
126
|
+
* @param eventName - The name of the event (e.g., 'click', 'update').
|
|
127
|
+
* @param handler - The callback function or object to invoke on each event.
|
|
128
|
+
* @param once - If true, remove the listener after first invocation.
|
|
129
|
+
* @returns The attached handler reference. Useful for later deletion with {@link off}.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const handler = on<{ value: number }>(myElement, 'update', (ev) => {
|
|
134
|
+
* console.log(ev.detail.data.value); // number
|
|
135
|
+
* });
|
|
136
|
+
* // to remove: off(myElement, 'update', handler);
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export declare function on<D = unknown>(target: TargetSelect, eventName: string, handler: McEventHandler<D>, once?: boolean): McEventHandler<D>;
|
|
140
|
+
export declare function on(target: TargetSelect, eventName: string, handler: EventListenerOrEventListenerObject, once?: boolean): EventListenerOrEventListenerObject;
|
|
141
|
+
/**
|
|
142
|
+
* Attaches an event listener that will fire only once.
|
|
143
|
+
*
|
|
144
|
+
* Internally calls {@link on} with the `once` flag set to true. The handler
|
|
145
|
+
* is automatically removed after its first invocation.
|
|
146
|
+
* This is primarily used to interface with external frameworks or vanilla JS environments.
|
|
147
|
+
* For communication between frontend microcomponents, use the `DC.one()` method instead.
|
|
148
|
+
*
|
|
149
|
+
* @param target - The DOM element to attach the listener to.
|
|
150
|
+
* @param eventName - The name of the event (e.g., 'click', 'update').
|
|
151
|
+
* @param handler - The callback function or object to invoke once.
|
|
152
|
+
* @returns The attached one-time handler reference. Useful for later deletion with {@link off}.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* one<{ ready: boolean }>(myElement, 'dataReady', (ev) => console.log('received:', ev.detail.data));
|
|
157
|
+
* // fires only once then detaches automatically
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export declare function one<D = unknown>(target: TargetSelect, eventName: string, handler: McEventHandler<D>): McEventHandler<D>;
|
|
161
|
+
export declare function one(target: TargetSelect, eventName: string, handler: EventListenerOrEventListenerObject): EventListenerOrEventListenerObject;
|
|
162
|
+
/**
|
|
163
|
+
* @hidden
|
|
164
|
+
* A controller object used to manage and potentially abort event bubbling.
|
|
165
|
+
*
|
|
166
|
+
* The `trigger()` function internally creates instance of this class,
|
|
167
|
+
* allowing the an eventual handler to call `ev.detail.control.stop()` to
|
|
168
|
+
* prevent further propagation in either direction (up/down).
|
|
169
|
+
*
|
|
170
|
+
* This is only used internally.
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* trigger(myElement, 'update', { value: 42 }, 'u');
|
|
174
|
+
*
|
|
175
|
+
* // inside a handler you can call ev.detail.control.stop() to halt propagation
|
|
176
|
+
* onUpdate(ev) {
|
|
177
|
+
* ev.detail.control.stop();
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare class BubbleController implements McBubbleController {
|
|
182
|
+
stopped: boolean;
|
|
183
|
+
constructor();
|
|
184
|
+
/**
|
|
185
|
+
* Signals that event bubbling should be halted.
|
|
186
|
+
*
|
|
187
|
+
* After calling this method, subsequent `trigger()` calls will abort
|
|
188
|
+
* before dispatching the event to any targets.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* trigger(myElement, 'update', { value: 42 }, 'u');
|
|
193
|
+
*
|
|
194
|
+
* // inside a handler you can call ev.detail.control.stop() to halt propagation
|
|
195
|
+
* onUpdate(ev) {
|
|
196
|
+
* ev.detail.control.stop();
|
|
197
|
+
* }
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
stop(): void;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Creates and dispatches a custom event on the specified DOM node.
|
|
204
|
+
*
|
|
205
|
+
* The event is namespaced with an `_mc` prefix by default, unless already prefixed.
|
|
206
|
+
* Supports bidirectional bubbling (up/down the DOM tree) based on the `bubble` parameter:
|
|
207
|
+
* - 'l': local dispatch only
|
|
208
|
+
* - 'u': bubble up towards ancestors
|
|
209
|
+
* - 'd': bubble down to descendants
|
|
210
|
+
*
|
|
211
|
+
* The dispatched event is a `CustomEvent<McDetail<D>>`: handlers find the payload
|
|
212
|
+
* under `ev.detail.data` and can call `ev.detail.control.stop()` to cancel bubbling.
|
|
213
|
+
*
|
|
214
|
+
* @param target - The DOM element on which to trigger the event, or a querySelectorAll(selector) selector string.
|
|
215
|
+
* @param event - The name of the event (will be prefixed if needed).
|
|
216
|
+
* @param data - Additional data payload attached to `event.detail.data`.
|
|
217
|
+
* @param bubble - Bubbling direction ('l', 'u', 'd' or combinations).
|
|
218
|
+
* @param controller - Optional controller for managing bubbling behavior.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* // Trigger a local event with data
|
|
223
|
+
* trigger(myElement, 'update', { value: 42 }, 'l');
|
|
224
|
+
*
|
|
225
|
+
* // Bubble up to ancestors
|
|
226
|
+
* trigger(myElement, 'dataReady', { ready: true }, 'u');
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export declare function trigger<D = unknown>(target: HTMLElement | string | undefined | null, event: string, data?: D, bubble?: BubbleDirections, // direction of bubbling
|
|
230
|
+
controller?: BubbleController): void;
|
|
231
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|