@twobirds/microcomponents 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/MC.min.js +1 -1
  2. package/dist/autoload.min.js +1 -1
  3. package/dist/cli/index.js +18 -22
  4. package/dist/cli/inliner.d.ts +8 -5
  5. package/dist/cli/inliner.d.ts.map +1 -1
  6. package/dist/core/MC.d.ts +98 -50
  7. package/dist/core/MC.d.ts.map +1 -1
  8. package/dist/core/elements.js +134 -76
  9. package/dist/core/index.d.ts +5 -4
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/docs/api-external.d.ts +101 -0
  12. package/dist/docs/api-external.d.ts.map +1 -0
  13. package/dist/docs/cli.d.ts +115 -0
  14. package/dist/docs/cli.d.ts.map +1 -0
  15. package/dist/docs/concepts.d.ts +42 -0
  16. package/dist/docs/concepts.d.ts.map +1 -0
  17. package/dist/docs/installation.d.ts +74 -0
  18. package/dist/docs/installation.d.ts.map +1 -0
  19. package/dist/docs/mcp.d.ts +45 -0
  20. package/dist/docs/mcp.d.ts.map +1 -0
  21. package/dist/elements.min.js +1 -1
  22. package/dist/formValues.min.js +1 -1
  23. package/dist/mcp/api.json +325 -29
  24. package/dist/mcp/concepts/event-system.md +1 -1
  25. package/dist/mcp/index.js +13 -6
  26. package/dist/microcomponents.js +145 -82
  27. package/dist/microcomponents.min.js +1 -1
  28. package/dist/observables.min.js +1 -1
  29. package/dist/state/formValues.d.ts +3 -3
  30. package/dist/state/formValues.js +139 -81
  31. package/dist/state/index.d.ts +3 -0
  32. package/dist/state/index.d.ts.map +1 -1
  33. package/dist/state/observables.d.ts +2 -2
  34. package/dist/state/observables.js +136 -78
  35. package/dist/types/index.d.ts +1 -0
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/utils/helpers.d.ts +12 -0
  38. package/dist/utils/helpers.d.ts.map +1 -1
  39. package/package.json +7 -3
package/dist/mcp/api.json CHANGED
@@ -1,75 +1,82 @@
1
1
  {
2
- "libraryVersion": "0.10.0",
3
- "exportedCount": 41,
2
+ "libraryVersion": "0.10.2",
3
+ "exportedCount": 57,
4
4
  "entries": {
5
5
  "MC": {
6
6
  "name": "MC",
7
7
  "kind": "class",
8
+ "group": "MicroComponents",
8
9
  "file": "src/core/MC.ts",
9
10
  "signatures": [
10
11
  "class MC<TTarget extends object = object> extends McBase<TTarget> {"
11
12
  ],
12
- "description": "A general-purpose base microcomponent that does not require a DOM target.\n\nInherits from `McBase`, but is primarily used as a lightweight container or\nfor logic not directly tied to DOM elements."
13
+ "description": "A general-purpose base microcomponent that does not require a DOM target.\n\nInherits from `McBase`, but is primarily used as a lightweight container or\nfor logic not directly tied to DOM elements.\n\n`static assets` work here too: a server-side `MC` fetches its companion files\n(`.json`, `.html`, `.css`) with `loadAssets()` and reads them through the\nMcBase.assets getter — await `MC._assetsPromise` before reading. There is\nno DOM attach and no `Init` lifecycle; those are `DC`-only."
13
14
  },
14
15
  "DC": {
15
16
  "name": "DC",
16
17
  "kind": "class",
18
+ "group": "MicroComponents",
17
19
  "file": "src/core/MC.ts",
18
20
  "signatures": [
19
21
  "class DC< T extends HTMLElement = HTMLElement, EM extends Record<string, unknown> = Record<never, never>, > extends McBase<T> implements McController<T> {"
20
22
  ],
21
- "description": "A DOM-centric microcomponent that operates on a specific HTML element.\n\nExtends McBase and associates itself with an actual DOM node via the\n`_target` reference. Provides methods for event handling, DOM traversal,\nand interaction with sibling or ancestor microcomponents.\n\n\n## Static Configuration Properties\n\nDC classes support three static properties that configure custom elements\nbefore any instance is constructed:\n\n### `static tag?: string`\n\nReplaces the default target element with a semantic HTML element, or removes it entirely.\n\n- **Non-empty string** (e.g., `'header'`) — the original custom element is replaced\nwith the specified built-in element. The original tag name is added as a CSS class.\n- **Empty string `''`** — the target element is removed from the DOM entirely.\nUseful for components that only inject global styles or act as style containers.\n\nProduces `<header class=\"shop-header\">` instead of `<shop-header>`.\n\nThe element self-destructs; only side effects (e.g., injected styles) remain.\n\n### `static assets: string[]`\n\nDeclares companion files for auto-loading by convention. Asset names are camelCase\nand translated into file extensions: `'targetHtml'` → `.target.html`, `'json'` → `.json`.\n\nThe path is derived from the custom element tag segments, and the basename is the\nlast segment. For `<cart-container-checkout>`, assets load from `/cart/container/checkout.*`.\n\nWhen assets finish loading, an `'assets'` event fires so that `oneAssets(ev)` can\nprocess them. Everything ending in `Json` arrives parsed; all other files arrive as text.\n\n*One-time global styles**: Assets named `'css'` and `'targetCss'` inject CSS into the\nglobal document scope via `injectCSS(document, ...)`. Because these are idempotent\nglobal side effects, they are processed only once — after the first instance loads them,\nthe entries are removed from both `static assets` and `static _assets`. Subsequent\ninstances skip loading and re-processing them entirely.\n\n*CSS file roles**:\n\n- `.css` — design tokens only (CSS custom-property presets). Injected into the document\nscope once, like `targetCss`.\n- `.target.css` — layout rules for the light DOM. Also document-scoped and one-time.\n- `.shadow.css` — layout rules for the shadow DOM. Injected per instance into the\ncomponent's own shadow root, so each instance gets its own copy.\n\nEvery declared asset — CSS, HTML, JSON — is inlined into `static _assets` at build time by\nthe load-assets plugin, so a bundled build performs no fetches at all.\n\nIn a bundled build the plain `.css` files are additionally concatenated into a single\n`bundle.css` by the bundling script. That file is a convenience listing of the available\nvariables: copy the ones you want to change into your own stylesheet and override them\nthere. It is not required at runtime, and it cannot drift from the inlined presets — both\nare read from the same source files.\n\nThe runtime decides whether an asset still needs fetching with `!ctor._assets[key]`, so an\ninlined entry must never be an empty string: that would trigger a re-fetch of a file that\ndoes not exist in a bundled build.\n\n`configJson` arrives already parsed into an object.\n\n### `static attributes?: object`\n\nSets HTML attributes on every instance automatically.\n\nEvery `<product-card>` carries `role=\"listitem\"`.\n\n### Combined usage\n\nAll three can be combined in one class:\n\nProduces `<section role=\"list\" aria-label=\"products\">`.\n\n\n## Event Handler Conventions\n\nMethods whose names start with `on` or `one` are automatically wired as event listeners\non the target element. The prefix determines persistence:\n\n- **`on<EventName>`** — persistent listener (fires every time)\n- **`one<EventName>`** — one-time listener (fires once, then detaches)\n\n### Web Component Lifecycle Events\n\nWhen a DC is registered via defineCE, the custom element dispatches these\ninternal events that can be caught with handler methods:\n\n| Method | When it fires |\n|--------|---------------|\n| `onConnected()` | Element was inserted into the DOM (`connectedCallback`) |\n| `onDisconnected()` | Element was removed from the DOM (`disconnectedCallback`) |\n| `onAdopted()` | Element was moved to a new document (`adoptedCallback`) |\n| `onAttributeChanged()` | An observed attribute changed (`attributeChangedCallback`) |\n| `oneInit()` | Constructor finished; all synchronous setup complete (microtask) |\n| `oneAssets()` | Constructor finished; all assets loaded and available; ev contains assets object |\n\n\n## Construction Patterns\n\n### Template usage (declarative)\n\n```ts\nclass MyElement extends DC {}\ndefineCE('my-element', MyElement);\n```\n\nThe registered element is then used in HTML as `<my-element></my-element>`.\n\n### Programmatic construction with data\n\nWhen constructing programmatically via getCE, pass only the `data` payload —\nthe target element is created automatically by the custom element constructor.\n\n### Data from HTML attributes\n\nUsed in HTML as `<my-element my-data='{\"name\":\"John\"}'></my-element>`.\n\n\n## Plugin Extension Points\n\nThe prototype of `DC` (inherited from McBase) is extended at runtime by optional\nplugins. See the McBase documentation for details on State.observePlugin and\nState.formValuePlugin.\n\n`trigger()` checks the payload against the registered `CartUpdate` shape, and the `on()`\nhandler receives a fully typed `ev`.",
23
+ "description": "A DOM-centric microcomponent that operates on a specific HTML element.\n\nExtends McBase and associates itself with an actual DOM node via the\n`_target` reference. Provides methods for event handling, DOM traversal,\nand interaction with sibling or ancestor microcomponents.\n\n\n## Static Configuration Properties\n\nDC classes support three static properties that configure custom elements\nbefore any instance is constructed:\n\n### `static tag?: string`\n\nReplaces the default target element with a semantic HTML element, or removes it entirely.\n\n- **Non-empty string** (e.g., `'header'`) — the original custom element is replaced\n with the specified built-in element. The original tag name is added as a CSS class.\n- **Empty string `''`** — the target element is removed from the DOM entirely.\n Useful for components that only inject global styles or act as style containers.\n\nProduces `<header class=\"shop-header\">` instead of `<shop-header>`.\n\nThe element self-destructs; only side effects (e.g., injected styles) remain.\n\n### `static assets: string[]`\n\nDeclares companion files for auto-loading by convention. Asset names are camelCase\nand translated into file extensions: `'targetHtml'` → `.target.html`, `'json'` → `.json`.\n\nThe path is derived from the custom element tag segments, and the basename is the\nlast segment. For `<cart-container-checkout>`, assets load from `/cart/container/checkout.*`.\n\n*Assets are loaded before `oneInit()` fires.** The constructor applies them to the\ntarget, then dispatches the `Init` lifecycle event — synchronously in a bundled build\n(assets inlined), after the fetch resolves in a dev/autoload build. Inside `oneInit()`\nthe loaded assets are read through the DC.assets getter. Everything ending in\n`Json` arrives parsed; all other files arrive as text.\n\n*Auto-attached assets**: `.css`, `.target.css`, `.shadow.css`, `.target.html` and\n`.shadow.html` are attached automatically by `processAssets()` — CSS is injected into\nthe document or shadow scope, HTML is set as `target.innerHTML` / `shadowRoot.innerHTML`,\nand native event handlers in the template (`<button click=\"this|go\">`) are wired.\n\n*Plain `.html` is NOT auto-attached.** It is a template held in DC.assets for\ncomponents created programmatically with a `data` parameter: in `oneInit()` you compile\nthe target markup from template + data with `parse()`.\n\n*One-time global styles**: Assets named `'css'` and `'targetCss'` inject CSS into the\nglobal document scope via `injectCSS(document, ...)`. Because these are idempotent\nglobal side effects, they are processed only once — after the first instance loads them,\nthe entries are dropped from `static _assets`. Subsequent instances skip re-processing\nthem entirely.\n\n*CSS file roles**:\n\n- `.css` — design tokens only (CSS custom-property presets). Injected into the document\n scope once, like `targetCss`.\n- `.target.css` — layout rules for the light DOM. Also document-scoped and one-time.\n- `.shadow.css` — layout rules for the shadow DOM. Injected per instance into the\n component's own shadow root, so each instance gets its own copy.\n\nEvery declared asset — CSS, HTML, JSON — is inlined into `static _assets` at build time by\nthe bundler, which replaces the `static assets` declaration with `static _assets` (the\n`static assets` line is deleted from the bundled `.js`) and collapses each inlined\n`.[shadow/target].css` / `.html` to a single line, so a bundled build performs no fetches.\n\nIn a bundled build the plain `.css` files are additionally concatenated into a single\n`bundle.css` by the bundling script. That file is a convenience listing of the available\nvariables: copy the ones you want to change into your own stylesheet and override them\nthere. It is not required at runtime, and it cannot drift from the inlined presets — both\nare read from the same source files.\n\nThe runtime decides whether an asset still needs fetching with `!ctor._assets[key]`, so an\ninlined entry must never be an empty string: that would trigger a re-fetch of a file that\ndoes not exist in a bundled build.\n\n`configJson` arrives already parsed into an object.\n\n`user-card.html` holds the `{name}` template; `parse()` fills it from `data`.\n\n### `static attributes?: object`\n\nSets HTML attributes on every instance automatically.\n\nEvery `<product-card>` carries `role=\"listitem\"`.\n\n### Combined usage\n\nAll three can be combined in one class:\n\nProduces `<section role=\"list\" aria-label=\"products\">`.\n\n\n## Event Handler Conventions\n\nMethods whose names start with `on` or `one` are automatically wired as event listeners\non the target element. The prefix determines persistence:\n\n- **`on<EventName>`** — persistent listener (fires every time)\n- **`one<EventName>`** — one-time listener (fires once, then detaches)\n\n### Web Component Lifecycle Events\n\nWhen a DC is registered via defineCE, the custom element dispatches these\ninternal events that can be caught with handler methods:\n\n| Method | When it fires |\n|--------|---------------|\n| `onConnected()` | Element was inserted into the DOM (`connectedCallback`) |\n| `onDisconnected()` | Element was removed from the DOM (`disconnectedCallback`) |\n| `onAdopted()` | Element was moved to a new document (`adoptedCallback`) |\n| `onAttributeChanged()` | An observed attribute changed (`attributeChangedCallback`) |\n| `oneInit()` | Constructor finished and declared assets loaded; read them via `this.assets` |\n\n\n## Construction Patterns\n\n### Template usage (declarative)\n\n```ts\nclass MyElement extends DC {}\ndefineCE('my-element', MyElement);\n```\n\nThe registered element is then used in HTML as `<my-element></my-element>`.\n\n### Programmatic construction with data\n\nWhen constructing programmatically via getCE, pass only the `data` payload —\nthe target element is created automatically by the custom element constructor.\n\n### Data from HTML attributes\n\nUsed in HTML as `<my-element my-data='{\"name\":\"John\"}'></my-element>`.\n\n\n## Plugin Extension Points\n\nThe prototype of `DC` (inherited from McBase) is extended at runtime by optional\nplugins. See the McBase documentation for details on State.observePlugin and\nState.formValuePlugin.\n\n`trigger()` checks the payload against the registered `CartUpdate` shape, and the `on()`\nhandler receives a fully typed `ev`.",
22
24
  "examples": [
23
25
  {
24
26
  "title": "static tag — replace with semantic element",
25
- "code": "class ShopHeader extends DC {\nstatic tag = 'header';\n}\ndefineCE('shop-header', ShopHeader);"
27
+ "code": "class ShopHeader extends DC {\n\tstatic tag = 'header';\n}\ndefineCE('shop-header', ShopHeader);"
26
28
  },
27
29
  {
28
30
  "title": "static tag — remove element entirely",
29
- "code": "class GlobalStyles extends DC {\nstatic tag = '';\n}\ndefineCE('global-styles', GlobalStyles);"
31
+ "code": "class GlobalStyles extends DC {\n\tstatic tag = '';\n}\ndefineCE('global-styles', GlobalStyles);"
30
32
  },
31
33
  {
32
- "title": "static assets with autoload",
33
- "code": "class CartCheckout extends DC {\nstatic assets = ['targetHtml', 'targetCss', 'configJson'];\n\noneAssets(ev) {\nconst { configJson } = ev.detail.data;\nconsole.log(configJson);\n}\n}\ndefineCE('cart-checkout', CartCheckout);"
34
+ "title": "static assets read in oneInit",
35
+ "code": "class CartCheckout extends DC {\n\tstatic assets = ['targetHtml', 'targetCss', 'configJson'];\n\n\toneInit() {\n\t\tconst { configJson } = this.assets;\n\t\tconsole.log(configJson);\n\t}\n}\ndefineCE('cart-checkout', CartCheckout);"
36
+ },
37
+ {
38
+ "title": "plain .html template compiled with data",
39
+ "code": "class UserCard extends DC {\n\tstatic assets = ['html', 'targetCss'];\n\n\tconstructor(target: HTMLElement, data: { name: string }) {\n\t\tsuper(target);\n\t\tthis.data = data;\n\t}\n\n\toneInit() {\n\t\tthis.target.innerHTML = parse(this.assets.html, this.data);\n\t}\n}\ndefineCE('user-card', UserCard);"
34
40
  },
35
41
  {
36
42
  "title": "static attributes",
37
- "code": "class ProductCard extends DC {\nstatic attributes = { role: 'listitem' };\n}\ndefineCE('product-card', ProductCard);"
43
+ "code": "class ProductCard extends DC {\n\tstatic attributes = { role: 'listitem' };\n}\ndefineCE('product-card', ProductCard);"
38
44
  },
39
45
  {
40
46
  "title": "All static properties together",
41
- "code": "class ShopCatalog extends DC {\nstatic tag = 'section';\nstatic attributes = { role: 'list', 'aria-label': 'products' };\nstatic assets = ['targetHtml', 'targetCss'];\n}\ndefineCE('shop-catalog', ShopCatalog);"
47
+ "code": "class ShopCatalog extends DC {\n\tstatic tag = 'section';\n\tstatic attributes = { role: 'list', 'aria-label': 'products' };\n\tstatic assets = ['targetHtml', 'targetCss'];\n}\ndefineCE('shop-catalog', ShopCatalog);"
42
48
  },
43
49
  {
44
50
  "title": "Event handlers in action",
45
- "code": "class MyElement extends DC {\nonConnected() {\nconsole.log('entered the DOM');\n}\n\nonDisconnected() {\nconsole.log('left the DOM');\n}\n\nonClick() {\nthis.trigger('something', 'payload');\n}\n\noneSomething(ev) {\nconsole.log('first time only:', ev.detail.data);\n}\n}\ndefineCE('my-element', MyElement);"
51
+ "code": "class MyElement extends DC {\n\tonConnected() {\n\t\tconsole.log('entered the DOM');\n\t}\n\n\tonDisconnected() {\n\t\tconsole.log('left the DOM');\n\t}\n\n\tonClick() {\n\t\tthis.trigger('something', 'payload');\n\t}\n\n\toneSomething(ev) {\n\t\tconsole.log('first time only:', ev.detail.data);\n\t}\n}\ndefineCE('my-element', MyElement);"
46
52
  },
47
53
  {
48
54
  "title": "Programmatic construction",
49
- "code": "class MyElement extends DC {\ndata = {};\n\nconstructor(target, data) {\nsuper(target);\nthis.data = data;\n}\n}\ndefineCE('my-element', MyElement);\n\nconst Ctor = getCE('my-element');\ndocument.body.append(new Ctor({ name: 'John' }));"
55
+ "code": "class MyElement extends DC {\n\tdata = {};\n\n\tconstructor(target, data) {\n\t\tsuper(target);\n\t\tthis.data = data;\n\t}\n}\ndefineCE('my-element', MyElement);\n\nconst Ctor = getCE('my-element');\ndocument.body.append(new Ctor({ name: 'John' }));"
50
56
  },
51
57
  {
52
58
  "title": "Reading data from an attribute",
53
- "code": "class MyElement extends DC {\ndata = {};\n\nconstructor(target) {\nsuper(target);\nthis.data = JSON.parse(target.getAttribute('my-data'));\n}\n}\ndefineCE('my-element', MyElement);"
59
+ "code": "class MyElement extends DC {\n\tdata = {};\n\n\tconstructor(target) {\n\t\tsuper(target);\n\t\tthis.data = JSON.parse(target.getAttribute('my-data'));\n\t}\n}\ndefineCE('my-element', MyElement);"
54
60
  },
55
61
  {
56
62
  "title": "Typed event map",
57
- "code": "class Cart extends DC<HTMLFormElement, { CartUpdate: { count: number } }> {\ncheckout() {\nthis.trigger('CartUpdate', { count: 2 }, 'u');\nthis.on('CartUpdate', (ev) => ev.detail.data.count);\n}\n}"
63
+ "code": "class Cart extends DC<HTMLFormElement, { CartUpdate: { count: number } }> {\n\tcheckout() {\n\t\tthis.trigger('CartUpdate', { count: 2 }, 'u');\n\t\tthis.on('CartUpdate', (ev) => ev.detail.data.count);\n\t}\n}"
58
64
  }
59
65
  ]
60
66
  },
61
67
  "McBase": {
62
68
  "name": "McBase",
63
69
  "kind": "class",
70
+ "group": "MicroComponents",
64
71
  "file": "src/core/MC.ts",
65
72
  "signatures": [
66
73
  "class McBase<TTarget extends object = object> {"
67
74
  ],
68
- "description": "The base class for all microcomponents — shared root of both MC and DC.\n\nHolds a `WeakRef` to the target (a DOM element for `DC`, or any plain object for `MC`)\nto avoid circular references. For `DC` subclasses it also bootstraps two automatic\nbehaviours:\n\n1. **Event listener auto-attachment** — methods whose names start with `on` or `one`\n(e.g. `onClick`, `oneInit`) are wired to the target element via on / one.\n2. **\"Init\" lifecycle event** — dispatched asynchronously in a microtask so that all\nsynchronous constructor work finishes first.\n\nBoth mechanisms run only when the instance is a `DC` (checked with `instanceof DC`).\nPlain `MC` instances skip them entirely, keeping server-side usage lightweight.\n\n### Plugin extension points\n\nThe prototype of `McBase` is the attachment point for optional plugins that curry\nadditional instance methods onto every microcomponent. Two built-in plugins modify\nthis class at runtime:\n\n- **State.observePlugin** — adds `notify()`, `subscribe()`, and `bind()` so that\nobservable properties can be controlled directly on the component instance with\nfluent chaining. Call `observePlugin(DC)` once at module level to activate.\n\n- **State.formValuePlugin** — adds `formValues()` for two-way binding between DOM\nform controls and an observable property. Also pulls in all methods from\nState.observePlugin, so you can chain `.subscribe()` and `.bind()` after\n`.formValues()`. Call `formValuePlugin(DC)` once at module level to activate.\n\nBoth plugins are idempotent — calling them multiple times has no side effects. They\nwork by assigning methods onto `McBase.prototype` (reached via\n`Object.getPrototypeOf(Class.prototype)`) and use TypeScript module augmentation\n(`declare module`) so the added signatures appear in type-checking automatically.\n\n`observePlugin(DC)` adds `notify()`, `subscribe()`, `bind()` to `McBase.prototype`;\n`formValuePlugin(DC)` adds `formValues()` and re-runs `observePlugin`. `oneInit()`\nruns once after the constructor.",
75
+ "description": "The base class for all microcomponents — shared root of both MC and DC.\n\nHolds a `WeakRef` to the target (a DOM element for `DC`, or any plain object for `MC`)\nto avoid circular references. It starts loading any `static assets` for `MC` and `DC`\nalike (shared per class through `_assetsPromise`), read through the McBase.assets\ngetter. For `DC` subclasses it bootstraps one automatic behaviour:\n\n1. **Event listener auto-attachment** — methods whose names start with `on` or `one`\n (e.g. `onClick`, `oneInit`) are wired to the target element via on / one.\n\nThe **\"Init\" lifecycle event** and the DOM attach of auto-attached assets are dispatched\nby the DC constructor — after the declared assets are in place — so that\n`oneInit()` runs once the instance is fully constructed and its assets are loaded. Plain\n`MC` instances fetch their assets server-side with no DOM attach and no `Init` lifecycle,\nkeeping server-side usage lightweight.\n\n### Plugin extension points\n\nThe prototype of `McBase` is the attachment point for optional plugins that curry\nadditional instance methods onto every microcomponent. Two built-in plugins modify\nthis class at runtime:\n\n- **State.observePlugin** — adds `notify()`, `subscribe()`, and `bind()` so that\n observable properties can be controlled directly on the component instance with\n fluent chaining. Call `observePlugin(DC)` once at module level to activate.\n\n- **State.formValuePlugin** — adds `formValues()` for two-way binding between DOM\n form controls and an observable property. Also pulls in all methods from\n State.observePlugin, so you can chain `.subscribe()` and `.bind()` after\n `.formValues()`. Call `formValuePlugin(DC)` once at module level to activate.\n\nBoth plugins are idempotent — calling them multiple times has no side effects. They\nwork by assigning methods onto `McBase.prototype` (reached via\n`Object.getPrototypeOf(Class.prototype)`) and use TypeScript module augmentation\n(`declare module`) so the added signatures appear in type-checking automatically.\n\n`observePlugin(DC)` adds `notify()`, `subscribe()`, `bind()` to `McBase.prototype`;\n`formValuePlugin(DC)` adds `formValues()` and re-runs `observePlugin`. `oneInit()`\nruns once after the constructor.",
69
76
  "examples": [
70
77
  {
71
78
  "title": "Extending with plugins at runtime",
72
- "code": "import { DC, observePlugin, formValuePlugin } from '@twobirds/microcomponents';\n\nobservePlugin(DC);\nformValuePlugin(DC);\n\nclass MyForm extends DC {\ndata = { name: '' };\n\noneInit() {\nthis\n.formValues(this.target, 'data')\n.subscribe('data', (v) => console.log(v))\n.bind('data', this.target);\n}\n}"
79
+ "code": "import { DC, observePlugin, formValuePlugin } from '@twobirds/microcomponents';\n\nobservePlugin(DC);\nformValuePlugin(DC);\n\nclass MyForm extends DC {\n\tdata = { name: '' };\n\n\toneInit() {\n\t\tthis\n\t\t.formValues(this.target, 'data')\n\t\t.subscribe('data', (v) => console.log(v))\n\t\t.bind('data', this.target);\n\t}\n}"
73
80
  }
74
81
  ]
75
82
  },
@@ -84,7 +91,7 @@
84
91
  "export 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",
85
92
  "export function defineCE< Tag extends `${string}-${string}`, T extends object, D = unknown, E extends keyof HTMLElementTagNameMap | undefined = undefined, >( tagName: Tag, DefinitionClass: new (target: TargetOf<E>, data?: D) => T, observedAttributes: string[] = [], extend?: E"
86
93
  ],
87
- "description": "### Examples\n\n#### Define custom element in registry\n\n```ts\nclass MyElement extends DC {}\ndefineCE('my-element', MyElement);\n```\n\nThe registered element is then used in HTML as `<my-element></my-element>`.\n\n#### Define custom element in registry with observed attributes\n\n```ts\nclass MyElement extends DC {\nonAttributeChanged(ev){\nconst newValue = ev.detail.data.newValue;\n}\n}\ndefineCE('my-element', MyElement, ['observed']);\n```\n\nUsed in HTML as `<my-element observed></my-element>`. When the `observed` attribute\nchanges, `attributeChanged` is triggered, which calls `onAttributeChanged` with the\nchange data in the payload.\n\nDefines a custom HTML element with optional observed attributes and micro component integration.\nThe class provided in DefinitionClass will be added to the ._mc hash object appended to the custom element instance.\nAutomatically assigns a \"PascalCase\" class name derived from the <kebab-case> tagName.\nIf the provided definition class extends McBase (indicating a DC or MC class extension), it wraps the constructor to register\nthe element instance with DC (DomComponent)."
94
+ "description": "### Examples\n\n#### Define custom element in registry\n\n```ts\nclass MyElement extends DC {}\ndefineCE('my-element', MyElement);\n```\n\nThe registered element is then used in HTML as `<my-element></my-element>`.\n\n#### Define custom element in registry with observed attributes\n\n```ts\nclass MyElement extends DC {\n\tonAttributeChanged(ev){\n\t\tconst newValue = ev.detail.data.newValue;\n\t}\n}\ndefineCE('my-element', MyElement, ['observed']);\n```\n\nUsed in HTML as `<my-element observed></my-element>`. When the `observed` attribute\nchanges, `attributeChanged` is triggered, which calls `onAttributeChanged` with the\nchange data in the payload.\n\nDefines a custom HTML element with optional observed attributes and micro component integration.\nThe class provided in DefinitionClass will be added to the ._mc hash object appended to the custom element instance.\nAutomatically assigns a \"PascalCase\" class name derived from the <kebab-case> tagName.\nIf the provided definition class extends McBase (indicating a DC or MC class extension), it wraps the constructor to register\nthe element instance with DC (DomComponent)."
88
95
  },
89
96
  "getCE": {
90
97
  "name": "getCE",
@@ -100,7 +107,7 @@
100
107
  "examples": [
101
108
  {
102
109
  "title": "",
103
- "code": "const MyElementClass = getCE('my-element');\nif (MyElementClass) {\ndocument.body.append(new MyElementClass());\n}"
110
+ "code": "const MyElementClass = getCE('my-element');\nif (MyElementClass) {\n\tdocument.body.append(new MyElementClass());\n}"
104
111
  }
105
112
  ]
106
113
  },
@@ -172,13 +179,14 @@
172
179
  "examples": [
173
180
  {
174
181
  "title": "",
175
- "code": "declare global {\ninterface McRegistry {\ncart: Cart;\n}\n}\n\nconst el = document.querySelector('form');\nif (el && isMcHost(el)) {\nel._mc.trigger('Ping');\n}\nif (el && isMcHost(el, 'cart')) {\nel._mc.cart.addItem(item);\n}"
182
+ "code": "declare global {\n interface McRegistry {\n cart: Cart;\n }\n}\n\nconst el = document.querySelector('form');\nif (el && isMcHost(el)) {\n el._mc.trigger('Ping');\n}\nif (el && isMcHost(el, 'cart')) {\n el._mc.cart.addItem(item);\n}"
176
183
  }
177
184
  ]
178
185
  },
179
186
  "observe": {
180
187
  "name": "observe",
181
188
  "kind": "function",
189
+ "group": "State",
182
190
  "file": "src/state/observables.ts",
183
191
  "signatures": [
184
192
  "export function observe<T extends object, K extends keyof T>( target: T, propertyName: K ): ObservedKey<T, K>;",
@@ -194,17 +202,18 @@
194
202
  },
195
203
  {
196
204
  "title": "Declarative usage — typed class field with double cast:",
197
- "code": "class Counter {\nclicks: Observable<number> = 0 as unknown as Observable<number>;\n\nconstructor() {\nobserve(this, 'clicks');\n}\n\nbump() {\nthis.clicks++;\n}\n}"
205
+ "code": "class Counter {\n\tclicks: Observable<number> = 0 as unknown as Observable<number>;\n\n\tconstructor() {\n\t\tobserve(this, 'clicks');\n\t}\n\n\tbump() {\n\t\tthis.clicks++;\n\t}\n}"
198
206
  },
199
207
  {
200
208
  "title": "Schema-first usage — divergent read/write types via hand-declared interface:",
201
- "code": "interface CounterState {\nget count(): Observable<number>;\nset count(v: number);\n}\n\nconst state = observe<CounterState>({ count: 0 });\nstate.count.subscribe((v) => console.log(v));\nstate.count = 5;"
209
+ "code": "interface CounterState {\n\tget count(): Observable<number>;\n\tset count(v: number);\n}\n\nconst state = observe<CounterState>({ count: 0 });\nstate.count.subscribe((v) => console.log(v));\nstate.count = 5;"
202
210
  }
203
211
  ]
204
212
  },
205
213
  "observePlugin": {
206
214
  "name": "observePlugin",
207
215
  "kind": "function",
216
+ "group": "State",
208
217
  "file": "src/state/observables.ts",
209
218
  "signatures": [
210
219
  "export function observePlugin(Class: any) {"
@@ -213,13 +222,14 @@
213
222
  "examples": [
214
223
  {
215
224
  "title": "",
216
- "code": "class Counter extends DC {\ndata = { clicks: 1 };\n\noneAssets() {\nthis\n.subscribe('data', (v) => console.log('data →', v))\n.bind('data', this.target);\n}\n}"
225
+ "code": "class Counter extends DC {\n\tdata = { clicks: 1 };\n\n\toneInit() {\n\t\tthis\n\t\t.subscribe('data', (v) => console.log('data →', v))\n\t\t.bind('data', this.target);\n\t}\n}"
217
226
  }
218
227
  ]
219
228
  },
220
229
  "isAlreadyObserved": {
221
230
  "name": "isAlreadyObserved",
222
231
  "kind": "function",
232
+ "group": "State",
223
233
  "file": "src/state/observables.ts",
224
234
  "signatures": [
225
235
  "export function isAlreadyObserved(value: unknown): boolean {"
@@ -235,6 +245,7 @@
235
245
  "Observable": {
236
246
  "name": "Observable",
237
247
  "kind": "type alias",
248
+ "group": "State",
238
249
  "file": "src/state/observables.ts",
239
250
  "signatures": [
240
251
  "export type Observable<T = unknown> = T & {"
@@ -250,6 +261,7 @@
250
261
  "Callback": {
251
262
  "name": "Callback",
252
263
  "kind": "type alias",
264
+ "group": "State",
253
265
  "file": "src/state/observables.ts",
254
266
  "signatures": [
255
267
  "export type Callback<T = unknown> = (value: T) => void;"
@@ -265,11 +277,12 @@
265
277
  "Observed": {
266
278
  "name": "Observed",
267
279
  "kind": "type alias",
280
+ "group": "State",
268
281
  "file": "src/state/observables.ts",
269
282
  "signatures": [
270
283
  "export type Observed<T> = { [K in keyof T]: Observable<T[K]> };"
271
284
  ],
272
- "description": "Every property of `T` mapped to an observable of its value.\n\nKNOWN LIMIT: the runtime property *setter* accepts a plain value\n(`state.count = 5` re-wraps it), but this mapped type cannot say so — mapped\ntypes cannot declare divergent read/write (get/set) types, so the wrapper type\ngoverns writes too and plain assignment to a primitive observable is rejected.\nTracked upstream as https://github.com/microsoft/TypeScript/issues/43826\n(variant accessors for mapped types); when it lands, the write type here\nbecomes `T[K] | Observable<T[K]>` and the limit disappears.\n\nUntil then, use one of the supported write paths:\n- the `observed` variant, a single container whose `.value` gives \ntyped reads and writes today (`state.value.count = 5`, deep\nwrites included) — the limitation never applies;\n- `state.count++` (compiles today; TS does not re-check the `++` write-back);\n- the schema-first `observe<S>()` overload with a hand-declared get/set\ninterface, where the divergence IS expressible (and plain `=` becomes\nlegal) — see Unobserved.\n\nEvery property is mapped to an observable: `State` is\n`{ count: Observable<number>, name: Observable<string> }`.",
285
+ "description": "Every property of `T` mapped to an observable of its value.\n\nKNOWN LIMIT: the runtime property *setter* accepts a plain value\n(`state.count = 5` re-wraps it), but this mapped type cannot say so — mapped\ntypes cannot declare divergent read/write (get/set) types, so the wrapper type\ngoverns writes too and plain assignment to a primitive observable is rejected.\nTracked upstream as https://github.com/microsoft/TypeScript/issues/43826\n(variant accessors for mapped types); when it lands, the write type here\nbecomes `T[K] | Observable<T[K]>` and the limit disappears.\n\nUntil then, use one of the supported write paths:\n- the `observed` variant, a single container whose `.value` gives \n typed reads and writes today (`state.value.count = 5`, deep\n writes included) — the limitation never applies;\n- `state.count++` (compiles today; TS does not re-check the `++` write-back);\n- the schema-first `observe<S>()` overload with a hand-declared get/set\n interface, where the divergence IS expressible (and plain `=` becomes\n legal) — see Unobserved.\n\nEvery property is mapped to an observable: `State` is\n`{ count: Observable<number>, name: Observable<string> }`.",
273
286
  "examples": [
274
287
  {
275
288
  "title": "",
@@ -280,6 +293,7 @@
280
293
  "ObservedKey": {
281
294
  "name": "ObservedKey",
282
295
  "kind": "type alias",
296
+ "group": "State",
283
297
  "file": "src/state/observables.ts",
284
298
  "signatures": [
285
299
  "export type ObservedKey<T, K extends keyof T> = {"
@@ -295,6 +309,7 @@
295
309
  "Unobserved": {
296
310
  "name": "Unobserved",
297
311
  "kind": "type alias",
312
+ "group": "State",
298
313
  "file": "src/state/observables.ts",
299
314
  "signatures": [
300
315
  "export type Unobserved<S> = {"
@@ -303,13 +318,14 @@
303
318
  "examples": [
304
319
  {
305
320
  "title": "",
306
- "code": "interface CounterState {\nget count(): Observable<number>;\nset count(v: number);\n}\ntype Seed = Unobserved<CounterState>;\nconst state = observe<CounterState>({ count: 0 });"
321
+ "code": "interface CounterState {\n\tget count(): Observable<number>;\n\tset count(v: number);\n}\ntype Seed = Unobserved<CounterState>;\nconst state = observe<CounterState>({ count: 0 });"
307
322
  }
308
323
  ]
309
324
  },
310
325
  "formValues": {
311
326
  "name": "formValues",
312
327
  "kind": "function",
328
+ "group": "State",
313
329
  "file": "src/state/formValues.ts",
314
330
  "signatures": [
315
331
  "export function formValues<T extends object>( targetObject: T, propertyName: keyof T & string, dom: HTMLElement | ShadowRoot ) {"
@@ -322,13 +338,14 @@
322
338
  },
323
339
  {
324
340
  "title": "Subscribe to form changes inside a component",
325
- "code": "import { DC, defineCE, formValues } from '@twobirds/microcomponents';\n\nclass MyForm extends DC {\nstatic assets = ['targetHtml'];\n\noneAssets() {\nformValues(this, 'formData', this.target);\nthis.formData.subscribe((data) => console.log('form changed:', data));\n}\n}\n\ndefineCE('my-form', MyForm);"
341
+ "code": "import { DC, defineCE, formValues } from '@twobirds/microcomponents';\n\nclass MyForm extends DC {\n\tstatic assets = ['targetHtml'];\n\n\toneInit() {\n\t\tformValues(this, 'formData', this.target);\n\t\tthis.formData.subscribe((data) => console.log('form changed:', data));\n\t}\n}\n\ndefineCE('my-form', MyForm);"
326
342
  }
327
343
  ]
328
344
  },
329
345
  "formValuePlugin": {
330
346
  "name": "formValuePlugin",
331
347
  "kind": "function",
348
+ "group": "State",
332
349
  "file": "src/state/formValues.ts",
333
350
  "signatures": [
334
351
  "export function formValuePlugin(Class: any) {"
@@ -337,13 +354,14 @@
337
354
  "examples": [
338
355
  {
339
356
  "title": "",
340
- "code": "import { DC, defineCE, formValuePlugin } from '@twobirds/microcomponents';\n\nformValuePlugin(DC);\n\nclass CheckoutForm extends DC {\nstatic assets = ['targetHtml'];\n\noneAssets() {\nthis\n.formValues(this.target, 'formData')\n.subscribe('formData', (data) => console.log(data))\n.bind('formData', this.target);\n}\n}\n\ndefineCE('checkout-form', CheckoutForm);"
357
+ "code": "import { DC, defineCE, formValuePlugin } from '@twobirds/microcomponents';\n\nformValuePlugin(DC);\n\nclass CheckoutForm extends DC {\n\tstatic assets = ['targetHtml'];\n\n\toneInit() {\n\t\tthis\n\t\t\t.formValues(this.target, 'formData')\n\t\t\t.subscribe('formData', (data) => console.log(data))\n\t\t\t.bind('formData', this.target);\n\t}\n}\n\ndefineCE('checkout-form', CheckoutForm);"
341
358
  }
342
359
  ]
343
360
  },
344
361
  "getMcEventName": {
345
362
  "name": "getMcEventName",
346
363
  "kind": "function",
364
+ "group": "Events",
347
365
  "file": "src/utils/events.ts",
348
366
  "signatures": [
349
367
  "export function getMcEventName(eventName: string): string {"
@@ -359,6 +377,7 @@
359
377
  "trueEventName": {
360
378
  "name": "trueEventName",
361
379
  "kind": "function",
380
+ "group": "Events",
362
381
  "file": "src/utils/events.ts",
363
382
  "signatures": [
364
383
  "export function trueEventName(target: HTMLElement, eventName: string): string {"
@@ -374,6 +393,7 @@
374
393
  "off": {
375
394
  "name": "off",
376
395
  "kind": "function",
396
+ "group": "Events",
377
397
  "file": "src/utils/events.ts",
378
398
  "signatures": [
379
399
  "export function off<D = unknown>( target: TargetSelect, eventName: string, handler: McEventHandler<D> ): void;",
@@ -391,6 +411,7 @@
391
411
  "on": {
392
412
  "name": "on",
393
413
  "kind": "function",
414
+ "group": "Events",
394
415
  "file": "src/utils/events.ts",
395
416
  "signatures": [
396
417
  "export function on<D = unknown>( target: TargetSelect, eventName: string, handler: McEventHandler<D>, once?: boolean ): McEventHandler<D>;",
@@ -401,13 +422,14 @@
401
422
  "examples": [
402
423
  {
403
424
  "title": "",
404
- "code": "const handler = on<{ value: number }>(myElement, 'update', (ev) => {\nconsole.log(ev.detail.data.value);\n});\noff(myElement, 'update', handler);"
425
+ "code": "const handler = on<{ value: number }>(myElement, 'update', (ev) => {\n console.log(ev.detail.data.value);\n});\noff(myElement, 'update', handler);"
405
426
  }
406
427
  ]
407
428
  },
408
429
  "one": {
409
430
  "name": "one",
410
431
  "kind": "function",
432
+ "group": "Events",
411
433
  "file": "src/utils/events.ts",
412
434
  "signatures": [
413
435
  "export function one<D = unknown>( target: TargetSelect, eventName: string, handler: McEventHandler<D> ): McEventHandler<D>;",
@@ -425,6 +447,7 @@
425
447
  "trigger": {
426
448
  "name": "trigger",
427
449
  "kind": "function",
450
+ "group": "Events",
428
451
  "file": "src/utils/events.ts",
429
452
  "signatures": [
430
453
  "export function trigger<D = unknown>( target: HTMLElement | string | undefined | null, event: string, data: D = {} as D, bubble: BubbleDirections = 'l', // direction of bubbling controller?: BubbleController ) {"
@@ -440,6 +463,7 @@
440
463
  "BubbleController": {
441
464
  "name": "BubbleController",
442
465
  "kind": "class",
466
+ "group": "Events",
443
467
  "file": "src/utils/events.ts",
444
468
  "signatures": [
445
469
  "export class BubbleController implements McBubbleController {"
@@ -452,9 +476,268 @@
452
476
  }
453
477
  ]
454
478
  },
479
+ "autoload": {
480
+ "name": "autoload",
481
+ "kind": "function",
482
+ "group": "Autoload",
483
+ "file": "src/utils/autoload.ts",
484
+ "signatures": [
485
+ "export function autoload(enable: boolean = true): boolean {"
486
+ ],
487
+ "description": "/**\n The internal `loadingDCs` set, exposed for external inspection.\n\n This property is attached to the `autoload()` function itself and contains\n the names of microcomponent classes currently being loaded (or queued to load)."
488
+ },
489
+ "isBrowser": {
490
+ "name": "isBrowser",
491
+ "kind": "function",
492
+ "group": "Helpers",
493
+ "file": "src/utils/helpers.ts",
494
+ "signatures": [
495
+ "export function isBrowser(): boolean {"
496
+ ],
497
+ "description": "Determines whether the current runtime environment is a web browser.\n\nThis function works by attempting to access `this` within an anonymous function\nand checking if it refers to the global `window` object. It returns `true`\nwhen executed in a browser context, and `false` otherwise (e.g., Node.js).\n\nNote: While modern environments typically provide more reliable detection mechanisms,\nthis fallback remains compatible across older runtimes where other detection techniques\nmay be unreliable.",
498
+ "examples": [
499
+ {
500
+ "title": "",
501
+ "code": "if (isBrowser()) {\n console.log('Running in a browser');\n}"
502
+ }
503
+ ]
504
+ },
505
+ "isNativeObject": {
506
+ "name": "isNativeObject",
507
+ "kind": "function",
508
+ "group": "Helpers",
509
+ "file": "src/utils/helpers.ts",
510
+ "signatures": [
511
+ "export function isNativeObject(value: unknown): value is Record<string, unknown> {"
512
+ ],
513
+ "description": "Checks if a value is a native JavaScript object (created via {} or new Object()).",
514
+ "examples": [
515
+ {
516
+ "title": "",
517
+ "code": "console.log(isNativeObject({}));\nconsole.log(isNativeObject(new Object()));\nconsole.log(isNativeObject([]));\nconsole.log(isNativeObject(null));"
518
+ }
519
+ ]
520
+ },
521
+ "sortObject": {
522
+ "name": "sortObject",
523
+ "kind": "function",
524
+ "group": "Helpers",
525
+ "file": "src/utils/helpers.ts",
526
+ "signatures": [
527
+ "export function sortObject<T extends Record<string, unknown>>(source: T): T {"
528
+ ],
529
+ "description": "Recursively sorts all keys in an object alphabetically, preserving nested structure.",
530
+ "examples": [
531
+ {
532
+ "title": "",
533
+ "code": "const obj = { z: 1, a: { y: 2, b: 3 } };\nconsole.log(JSON.stringify(sortObject(obj)));"
534
+ }
535
+ ]
536
+ },
537
+ "flattenObject": {
538
+ "name": "flattenObject",
539
+ "kind": "function",
540
+ "group": "Helpers",
541
+ "file": "src/utils/helpers.ts",
542
+ "signatures": [
543
+ "export function flattenObject(source: object, doSort: boolean = true): Record<string, unknown> {"
544
+ ],
545
+ "description": "Flattens a nested object into a single-level object with dot-separated keys.\nOptionally sorts the resulting flat keys alphabetically (default: true).",
546
+ "examples": [
547
+ {
548
+ "title": "",
549
+ "code": "const obj = { user: { name: 'Alice', age: 30 } };\nconsole.log(JSON.stringify(flattenObject(obj)));"
550
+ }
551
+ ]
552
+ },
553
+ "deepEqual": {
554
+ "name": "deepEqual",
555
+ "kind": "function",
556
+ "group": "Helpers",
557
+ "file": "src/utils/helpers.ts",
558
+ "signatures": [
559
+ "export function deepEqual(a: unknown, b: unknown): boolean {"
560
+ ],
561
+ "description": "Structural deep-equality using SameValueZero for primitives.\n\nSee https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero.\n\nNote: `Map`/`Set` are not structurally compared.",
562
+ "examples": [
563
+ {
564
+ "title": "",
565
+ "code": "console.log(deepEqual({ a: 1 }, { a: 1 }));\nconsole.log(deepEqual({ a: { b: 2 } }, { a: {} }));\nconsole.log(deepEqual({ a: NaN }, { a: NaN }));\nconsole.log(deepEqual({ a: NaN }, { a: null }));"
566
+ }
567
+ ]
568
+ },
569
+ "nameSpace": {
570
+ "name": "nameSpace",
571
+ "kind": "function",
572
+ "group": "Helpers",
573
+ "file": "src/utils/helpers.ts",
574
+ "signatures": [
575
+ "export function nameSpace(ns: string | string[], obj: object = {}): unknown {"
576
+ ],
577
+ "description": "Retrieves a nested value from an object using a namespace path (dot-separated).",
578
+ "examples": [
579
+ {
580
+ "title": "",
581
+ "code": "const data = { user: { profile: { name: 'Alice' } } };\nconsole.log(nameSpace('user.profile.name', data));\nconsole.log(nameSpace(['user', 'profile'], data));"
582
+ }
583
+ ]
584
+ },
585
+ "parse": {
586
+ "name": "parse",
587
+ "kind": "function",
588
+ "group": "Helpers",
589
+ "file": "src/utils/helpers.ts",
590
+ "signatures": [
591
+ "export function parse<T = string | object | unknown[]>( template: T, parseThis: object, ...rest: unknown[] ): T {"
592
+ ],
593
+ "description": "Parses a template string or object, replacing placeholders in the form of {key.path} with\ncorresponding values from the provided data object using namespace resolution.\nAlso recursively processes objects and arrays within the input.",
594
+ "examples": [
595
+ {
596
+ "title": "",
597
+ "code": "const data = { user: { name: 'Alice' } };\nconsole.log(parse('Hello {user.name}!', data));\nconsole.log(parse(['Hi {user.name}', 'Bye {user.name}'], data));"
598
+ }
599
+ ]
600
+ },
601
+ "kebabToPascal": {
602
+ "name": "kebabToPascal",
603
+ "kind": "function",
604
+ "group": "Helpers",
605
+ "file": "src/utils/helpers.ts",
606
+ "signatures": [
607
+ "export function kebabToPascal(str: string) {"
608
+ ],
609
+ "description": "Converts a kebab-case string to PascalCase.\nExample: 'my-component-name' -> 'MyComponentName'",
610
+ "examples": [
611
+ {
612
+ "title": "",
613
+ "code": "console.log(kebabToPascal('my-element'));"
614
+ }
615
+ ]
616
+ },
617
+ "debounce": {
618
+ "name": "debounce",
619
+ "kind": "function",
620
+ "group": "Helpers",
621
+ "file": "src/utils/helpers.ts",
622
+ "signatures": [
623
+ "export function debounce<A extends unknown[]>( func: (...args: A) => unknown, milliseconds: number ): (...args: A) => void {"
624
+ ],
625
+ "description": "Creates a debounced version of a function that delays execution until after the specified\nnumber of milliseconds have elapsed since the last time this function was invoked.\nUseful for rate-limiting expensive operations like event handlers or API calls.",
626
+ "examples": [
627
+ {
628
+ "title": "",
629
+ "code": "const log = debounce(() => console.log('called'), 300);\nlog();\nlog();"
630
+ }
631
+ ]
632
+ },
633
+ "htmlToElements": {
634
+ "name": "htmlToElements",
635
+ "kind": "function",
636
+ "group": "Helpers",
637
+ "file": "src/utils/helpers.ts",
638
+ "signatures": [
639
+ "export function htmlToElements(html: string): HTMLElement[] {"
640
+ ],
641
+ "description": "Parses an HTML string and returns an array of DOM elements.\nHandles self-closing tags (XHTML style) by converting them to full closing tags first.",
642
+ "examples": [
643
+ {
644
+ "title": "",
645
+ "code": "const elems = htmlToElements('<div>Hello</div><span>World</span>');\nconsole.log(elems.map((el) => el.tagName));"
646
+ }
647
+ ]
648
+ },
649
+ "copyGettersSetters": {
650
+ "name": "copyGettersSetters",
651
+ "kind": "function",
652
+ "group": "Helpers",
653
+ "file": "src/utils/helpers.ts",
654
+ "signatures": [
655
+ "export function copyGettersSetters(source: object, target: object): void {"
656
+ ],
657
+ "description": "Copies all getter and setter properties from a source object to a target object.\nDoes not copy methods or regular data properties—only accessor properties (get/set).",
658
+ "examples": [
659
+ {
660
+ "title": "",
661
+ "code": "const src = { get name() { return 'Alice'; } };\nconst tgt = {};\ncopyGettersSetters(src, tgt);\nconsole.log(tgt.name);"
662
+ }
663
+ ]
664
+ },
665
+ "injectCSS": {
666
+ "name": "injectCSS",
667
+ "kind": "function",
668
+ "group": "Helpers",
669
+ "file": "src/utils/helpers.ts",
670
+ "signatures": [
671
+ "export function injectCSS(target: Document | ShadowRoot, css: string): CSSStyleSheet {"
672
+ ],
673
+ "description": "Injects a CSS string into the given scope (document or shadow root) as an adopted stylesheet.\nEnables css-in-js so that every custom element is self-contained and importable.\n\nWhen 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.\nWhen targeting **shadowRoot**: use `:host` for the custom element itself, standard selectors (`.inner`, `#id`) for internal structure, and `::slotted()` for projected light-DOM content.\n\nStyles can also be added using a compound innerHTML statement: `shadow.innerHTML = \\`<style>${style}</style>${template}\\``",
674
+ "examples": [
675
+ {
676
+ "title": "Inject global styles into the document:",
677
+ "code": "import { injectCSS } from '@twobirds/mc/utils/helpers';\ninjectCSS(document, 'body { display: block; }');"
678
+ },
679
+ {
680
+ "title": "Inject global styles for a micro component into the document:",
681
+ "code": "import { injectCSS } from '@twobirds/mc/utils/helpers';\ninjectCSS(document, 'my-microcomponent { display: block; }');"
682
+ },
683
+ {
684
+ "title": "Inject scoped styles into a shadow root:",
685
+ "code": "const shadow = element.attachShadow({ mode: 'open' });\ninjectCSS(shadow, ':host { color: var(--text); } .inner { padding: 8px; }');"
686
+ }
687
+ ]
688
+ },
689
+ "processAssets": {
690
+ "name": "processAssets",
691
+ "kind": "function",
692
+ "group": "Helpers",
693
+ "file": "src/utils/helpers.ts",
694
+ "signatures": [
695
+ "export function processAssets(instance: McController, assets: Record<string, string>): void {"
696
+ ],
697
+ "description": "Processes a record of asset strings and applies them to the given target element.\nSupports injecting CSS into document or shadow root, and setting innerHTML for\nboth target and shadow DOM. Automatically attaches a shadow root if any key starts\nwith `'shadow'`.\n\nRecognized keys: `'css'`, `'targetCss'` (document-level styles), `'shadowCss'`\n(shadow-root styles), `'shadowHtml'` (shadow innerHTML), `'targetHtml'` (target innerHTML).",
698
+ "examples": [
699
+ {
700
+ "title": "",
701
+ "code": "processAssets(this, {\n css: 'body { margin: 0; }',\n shadowCss: ':host { display: block; }',\n shadowHtml: '<slot></slot>'\n});"
702
+ }
703
+ ]
704
+ },
705
+ "loadAssets": {
706
+ "name": "loadAssets",
707
+ "kind": "function",
708
+ "group": "Helpers",
709
+ "file": "src/utils/helpers.ts",
710
+ "signatures": [
711
+ "export function loadAssets(name: string, assets: string[]): Promise<Array<any>> {"
712
+ ],
713
+ "description": "Loads companion asset files (CSS, HTML) for a given component basename from the server.\n\nEach entry in `assets` encodes an optional variant and extension in camelCase, e.g. `'shadowCss'` → `{name}.shadow.css`,\n`'targetHtml'` → `{name}.target.html`. Plain entries like `'css'` or `'html'` resolve to\n`{name}.css` / `{name}.html`.\n\nIn bundled mode the Vite plugin replaces this call with an inline array literal, so `.then()`\nfires synchronously — no async overhead.",
714
+ "examples": [
715
+ {
716
+ "title": "",
717
+ "code": "export const MyComponent = loadAssets('my-component', ['shadowCss', 'shadowHtml']).then(([shadowCss, shadowHtml]) => {\n class _MyComponent extends DC { ... }\n defineCE('my-component', _MyComponent);\n return _MyComponent;\n});"
718
+ }
719
+ ]
720
+ },
721
+ "bindTemplateEvents": {
722
+ "name": "bindTemplateEvents",
723
+ "kind": "function",
724
+ "group": "Helpers",
725
+ "file": "src/utils/helpers.ts",
726
+ "signatures": [
727
+ "export function bindTemplateEvents( rootElement: HTMLElement | ShadowRoot, instance: McController ): void {"
728
+ ],
729
+ "description": "Binds declarative event attributes in a template fragment to microcomponent triggers.\n\nScans all elements under `root` for attributes whose names correspond to native DOM\nevents (e.g. `click`, `submit`, `change`). The attribute value encodes the target and\nhandler method in the form `target|methodName`:\n\n- `this|myHandler` — triggers locally on the component attached to this element.\n- `other-comp|submit` — resolves elements via `querySelectorAll('other-comp')` and\n triggers the event on each matched host's `_mc`.\n\nAn optional sibling `payload` attribute supplies the data argument for `trigger()`.\nAfter binding, both the event attribute and the payload attribute are removed from the DOM.",
730
+ "examples": [
731
+ {
732
+ "title": "",
733
+ "code": "<button click='this|onSubmit|{\"action\":\"go\"}'>Submit</button>\n<input change=\"|cart-form|refresh\">"
734
+ }
735
+ ]
736
+ },
455
737
  "McBubbleController": {
456
738
  "name": "McBubbleController",
457
739
  "kind": "interface",
740
+ "group": "Types",
458
741
  "file": "src/types/mcTypes.ts",
459
742
  "signatures": [
460
743
  "export interface McBubbleController {"
@@ -464,6 +747,7 @@
464
747
  "BubbleDirection": {
465
748
  "name": "BubbleDirection",
466
749
  "kind": "type alias",
750
+ "group": "Types",
467
751
  "file": "src/types/mcTypes.ts",
468
752
  "signatures": [
469
753
  "export type BubbleDirection = 'l' | 'u' | 'd';"
@@ -473,6 +757,7 @@
473
757
  "BubbleDirections": {
474
758
  "name": "BubbleDirections",
475
759
  "kind": "type alias",
760
+ "group": "Types",
476
761
  "file": "src/types/mcTypes.ts",
477
762
  "signatures": [
478
763
  "export type BubbleDirections = | BubbleDirection | `${BubbleDirection}${BubbleDirection}` | `${BubbleDirection}${BubbleDirection}${BubbleDirection}`;"
@@ -482,6 +767,7 @@
482
767
  "McDetail": {
483
768
  "name": "McDetail",
484
769
  "kind": "interface",
770
+ "group": "Types",
485
771
  "file": "src/types/mcTypes.ts",
486
772
  "signatures": [
487
773
  "export interface McDetail<D = unknown> {"
@@ -491,6 +777,7 @@
491
777
  "McEventHandler": {
492
778
  "name": "McEventHandler",
493
779
  "kind": "type alias",
780
+ "group": "Types",
494
781
  "file": "src/types/mcTypes.ts",
495
782
  "signatures": [
496
783
  "export type McEventHandler<D = unknown> = (ev: McEvent<D>) => void;"
@@ -500,6 +787,7 @@
500
787
  "McEvent": {
501
788
  "name": "McEvent",
502
789
  "kind": "type alias",
790
+ "group": "Types",
503
791
  "file": "src/types/mcTypes.ts",
504
792
  "signatures": [
505
793
  "export type McEvent<D = unknown> = CustomEvent<McDetail<D>>;"
@@ -508,13 +796,14 @@
508
796
  "examples": [
509
797
  {
510
798
  "title": "",
511
- "code": "cart.on('CartUpdate', (ev: McEvent<{ count: number }>) => {\nconsole.log(ev.detail.data.count);\nev.detail.control.stop();\n});"
799
+ "code": "cart.on('CartUpdate', (ev: McEvent<{ count: number }>) => {\n console.log(ev.detail.data.count);\n ev.detail.control.stop();\n});"
512
800
  }
513
801
  ]
514
802
  },
515
803
  "McPayloadOf": {
516
804
  "name": "McPayloadOf",
517
805
  "kind": "type alias",
806
+ "group": "Types",
518
807
  "file": "src/types/mcTypes.ts",
519
808
  "signatures": [
520
809
  "export type McPayloadOf<EM, K extends string, D = unknown> = K extends keyof EM ? EM[K] : D;"
@@ -524,6 +813,7 @@
524
813
  "McController": {
525
814
  "name": "McController",
526
815
  "kind": "interface",
816
+ "group": "Types",
527
817
  "file": "src/types/mcTypes.ts",
528
818
  "signatures": [
529
819
  "export interface McController<T extends HTMLElement = HTMLElement> {"
@@ -533,6 +823,7 @@
533
823
  "McNativeEventHandlers": {
534
824
  "name": "McNativeEventHandlers",
535
825
  "kind": "type alias",
826
+ "group": "Types",
536
827
  "file": "src/types/mcTypes.ts",
537
828
  "signatures": [
538
829
  "export type McNativeEventHandlers = {"
@@ -541,13 +832,14 @@
541
832
  "examples": [
542
833
  {
543
834
  "title": "",
544
- "code": "class Panel extends DC implements McNativeEventHandlers {\nonClick(ev: MouseEvent) {}\n}"
835
+ "code": "class Panel extends DC implements McNativeEventHandlers {\n onClick(ev: MouseEvent) {}\n}"
545
836
  }
546
837
  ]
547
838
  },
548
839
  "McHost": {
549
840
  "name": "McHost",
550
841
  "kind": "type alias",
842
+ "group": "Types",
551
843
  "file": "src/types/mcTypes.ts",
552
844
  "signatures": [
553
845
  "export type McHost< T extends HTMLElement = HTMLElement, R extends Record<string, unknown> = Record<never, never>, > = T & {"
@@ -563,6 +855,7 @@
563
855
  "McHostOf": {
564
856
  "name": "McHostOf",
565
857
  "kind": "type alias",
858
+ "group": "Types",
566
859
  "file": "src/types/mcTypes.ts",
567
860
  "signatures": [
568
861
  "export type McHostOf<T extends HTMLElement> = T extends { _mc: McController<infer U> } ? U : T;"
@@ -572,6 +865,7 @@
572
865
  "McEntriesOf": {
573
866
  "name": "McEntriesOf",
574
867
  "kind": "type alias",
868
+ "group": "Types",
575
869
  "file": "src/types/mcTypes.ts",
576
870
  "signatures": [
577
871
  "export type McEntriesOf<T> = T extends { _mc: infer M } ? {"
@@ -581,6 +875,7 @@
581
875
  "McMerged": {
582
876
  "name": "McMerged",
583
877
  "kind": "type alias",
878
+ "group": "Types",
584
879
  "file": "src/types/mcTypes.ts",
585
880
  "signatures": [
586
881
  "export type McMerged<A, B> = A & B extends infer U ? { [K in keyof U]: U[K] } : never;"
@@ -590,6 +885,7 @@
590
885
  "McRemoved": {
591
886
  "name": "McRemoved",
592
887
  "kind": "type alias",
888
+ "group": "Types",
593
889
  "file": "src/types/mcTypes.ts",
594
890
  "signatures": [
595
891
  "export type McRemoved<T extends HTMLElement, K extends string> = T extends { _mc: McController } ? { _mc: Record<K, never> } : unknown;"