@wippy-fe/webcomponent-core 0.0.50 → 0.0.52
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 +8 -0
- package/dist/index.d.ts +21 -3
- package/dist/index.js +72 -4
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -199,3 +199,11 @@ class MyElement extends WippyElement {
|
|
|
199
199
|
onUnmount() { /* cleanup */ }
|
|
200
200
|
}
|
|
201
201
|
```
|
|
202
|
+
|
|
203
|
+
## Host-owned logical visibility
|
|
204
|
+
|
|
205
|
+
`data-wippy-visible="true" | "false"` is a host-owned logical activity contract. It is not CSS visibility, viewport intersection, document visibility, readiness, or interactivity. Hosts set it before inserting an element and update it in place when retained content changes ownership.
|
|
206
|
+
|
|
207
|
+
`element.hostVisible` is `true`, `false`, or `null`; `null` means no host manages the element. The initial value is readable in `onMount`, but is not a transition hook. Later connected changes call `onHostVisibilityChanged(next, previous)` and are available through `this.reactive.hostVisibility.subscribe(...)`.
|
|
208
|
+
|
|
209
|
+
`setWippyVisibility(element, visible)` is the host helper. It is re-exported here for component consumers; Web Host source imports the same dependency-free contract from `@wippy-fe/shared`. The helper suppresses duplicate writes and never remounts the element. The reserved attribute never reaches schema props or `onPropsChanged`. Components own any false-to-true refresh work and should make it cancellable; hosts must not reload a component just to change logical activity.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LayoutBusBound } from '@wippy-fe/shared';
|
|
2
|
-
export { BroadcastEnvelope, LayoutBusBound } from '@wippy-fe/shared';
|
|
2
|
+
export { BroadcastEnvelope, LayoutBusBound, WIPPY_VISIBILITY_ATTRIBUTE, readWippyVisibility, setWippyVisibility } from '@wippy-fe/shared';
|
|
3
3
|
export { define } from '@wippy-fe/proxy';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -25,6 +25,7 @@ export { define } from '@wippy-fe/proxy';
|
|
|
25
25
|
*/
|
|
26
26
|
type PropsListener<Props> = (props: Props, errors: readonly string[]) => void;
|
|
27
27
|
type ContentListener = (content: string | null) => void;
|
|
28
|
+
type HostVisibilityListener = (visible: boolean | null, previous: boolean | null) => void;
|
|
28
29
|
interface SubscribeOptions {
|
|
29
30
|
/** Cancel the subscription when the signal aborts. */
|
|
30
31
|
signal?: AbortSignal;
|
|
@@ -56,6 +57,11 @@ interface ContentSubscription {
|
|
|
56
57
|
/** See `PropsSubscription.subscribe` for the same ordering caveat. */
|
|
57
58
|
subscribe: (listener: ContentListener, options?: SubscribeOptions) => () => void;
|
|
58
59
|
}
|
|
60
|
+
/** Host-owned logical activity. `null` means the element is unmanaged. */
|
|
61
|
+
interface HostVisibilitySubscription {
|
|
62
|
+
readonly value: boolean | null;
|
|
63
|
+
subscribe: (listener: HostVisibilityListener, options?: SubscribeOptions) => () => void;
|
|
64
|
+
}
|
|
59
65
|
interface EventEmitterHandle<Events> {
|
|
60
66
|
/**
|
|
61
67
|
* Dispatch a typed `CustomEvent` (bubbles + composed, identical
|
|
@@ -72,6 +78,7 @@ interface EventEmitterHandle<Events> {
|
|
|
72
78
|
interface ReactiveAdapter<Props, Events> {
|
|
73
79
|
props: PropsSubscription<Props>;
|
|
74
80
|
events: EventEmitterHandle<Events>;
|
|
81
|
+
hostVisibility: HostVisibilitySubscription;
|
|
75
82
|
/**
|
|
76
83
|
* Present only when the element's `wippyConfig.contentTemplate` is set;
|
|
77
84
|
* `null` otherwise. Avoids fake `.value === null` semantics for elements
|
|
@@ -301,6 +308,7 @@ declare abstract class WippyElement<Props = Record<string, unknown>, Events = Re
|
|
|
301
308
|
private _lastContent;
|
|
302
309
|
/** Unsubscribe from host `@theme` broadcasts; set on connect, cleared on disconnect. */
|
|
303
310
|
private _themeUnsub;
|
|
311
|
+
private _hostVisible;
|
|
304
312
|
/**
|
|
305
313
|
* Phantom field to retain the `Events` type parameter so it shows up in
|
|
306
314
|
* type errors / `Reflect.get` shape. Adapter typing reads it indirectly
|
|
@@ -323,6 +331,11 @@ declare abstract class WippyElement<Props = Record<string, unknown>, Events = Re
|
|
|
323
331
|
*/
|
|
324
332
|
static get observedAttributes(): string[];
|
|
325
333
|
constructor();
|
|
334
|
+
/**
|
|
335
|
+
* Host-owned logical activity. `null` means no host manages this element.
|
|
336
|
+
* It is not CSS visibility or viewport intersection.
|
|
337
|
+
*/
|
|
338
|
+
get hostVisible(): boolean | null;
|
|
326
339
|
/**
|
|
327
340
|
* Panel-scoped `host` wrapper attached by the managed-layout shell's
|
|
328
341
|
* content resolvers (`ComponentResolver` / `WebComponentPackageLoader`).
|
|
@@ -377,7 +390,7 @@ declare abstract class WippyElement<Props = Record<string, unknown>, Events = Re
|
|
|
377
390
|
*/
|
|
378
391
|
private _applyTheme;
|
|
379
392
|
disconnectedCallback(): void;
|
|
380
|
-
attributeChangedCallback(
|
|
393
|
+
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
381
394
|
/** Called right after shadow DOM is attached, before CSS or container. */
|
|
382
395
|
protected onInit(_shadow: ShadowRoot): void;
|
|
383
396
|
/**
|
|
@@ -399,6 +412,11 @@ declare abstract class WippyElement<Props = Record<string, unknown>, Events = Re
|
|
|
399
412
|
protected abstract onUnmount(): void;
|
|
400
413
|
/** Called when observed attributes change. Override to update framework state. */
|
|
401
414
|
protected onPropsChanged(_props: Props, _errors: string[]): void;
|
|
415
|
+
/**
|
|
416
|
+
* Called when the host changes logical activity. `null` means unmanaged.
|
|
417
|
+
* This does not imply a DOM remount or a CSS/viewport visibility change.
|
|
418
|
+
*/
|
|
419
|
+
protected onHostVisibilityChanged(_visible: boolean | null, _previous: boolean | null): void;
|
|
402
420
|
/**
|
|
403
421
|
* Extract text from a child `<template data-type="...">` element.
|
|
404
422
|
* Uses `.content.textContent` since `<template>` stores content in a DocumentFragment.
|
|
@@ -469,4 +487,4 @@ declare function attrToCamel(attr: string): string;
|
|
|
469
487
|
*/
|
|
470
488
|
declare function parseProps(element: HTMLElement, schema: WippyPropsSchema): ParseResult;
|
|
471
489
|
|
|
472
|
-
export { type ContentListener, type ContentSubscription, type EventEmitterHandle, type HostCssKey, type ParseResult, type PropsListener, type PropsSubscription, type ReactiveAdapter, type SubscribeOptions, WippyElement, type WippyElementConfig, type WippyPropDefinition, type WippyPropsSchema, attrToCamel, getWippyHost, getWippyHostBus, getWippyPanelId, injectInlineCss, loadHostCss, parseProps };
|
|
490
|
+
export { type ContentListener, type ContentSubscription, type EventEmitterHandle, type HostCssKey, type HostVisibilityListener, type HostVisibilitySubscription, type ParseResult, type PropsListener, type PropsSubscription, type ReactiveAdapter, type SubscribeOptions, WippyElement, type WippyElementConfig, type WippyPropDefinition, type WippyPropsSchema, attrToCamel, getWippyHost, getWippyHostBus, getWippyPanelId, injectInlineCss, loadHostCss, parseProps };
|
package/dist/index.js
CHANGED
|
@@ -129,16 +129,20 @@ var ReactiveAdapterImpl = class {
|
|
|
129
129
|
__publicField(this, "_props");
|
|
130
130
|
__publicField(this, "_errors");
|
|
131
131
|
__publicField(this, "_content");
|
|
132
|
+
__publicField(this, "_hostVisibility");
|
|
132
133
|
__publicField(this, "_propsListeners", /* @__PURE__ */ new Set());
|
|
133
134
|
__publicField(this, "_contentListeners", /* @__PURE__ */ new Set());
|
|
135
|
+
__publicField(this, "_hostVisibilityListeners", /* @__PURE__ */ new Set());
|
|
134
136
|
__publicField(this, "_disposed", false);
|
|
135
137
|
__publicField(this, "_emitToDom");
|
|
136
138
|
__publicField(this, "props");
|
|
137
139
|
__publicField(this, "events");
|
|
138
140
|
__publicField(this, "content");
|
|
141
|
+
__publicField(this, "hostVisibility");
|
|
139
142
|
this._props = initial.props;
|
|
140
143
|
this._errors = initial.errors;
|
|
141
144
|
this._content = initial.content;
|
|
145
|
+
this._hostVisibility = initial.hostVisibility;
|
|
142
146
|
this._emitToDom = emitToDom;
|
|
143
147
|
const self = this;
|
|
144
148
|
this.props = {
|
|
@@ -167,6 +171,14 @@ var ReactiveAdapterImpl = class {
|
|
|
167
171
|
return self._subscribeContent(listener, options);
|
|
168
172
|
}
|
|
169
173
|
} : null;
|
|
174
|
+
this.hostVisibility = {
|
|
175
|
+
get value() {
|
|
176
|
+
return self._hostVisibility;
|
|
177
|
+
},
|
|
178
|
+
subscribe(listener, options) {
|
|
179
|
+
return self._subscribeHostVisibility(listener, options);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
170
182
|
}
|
|
171
183
|
/** @internal */
|
|
172
184
|
notifyProps(props, errors) {
|
|
@@ -186,12 +198,21 @@ var ReactiveAdapterImpl = class {
|
|
|
186
198
|
listener(content);
|
|
187
199
|
}
|
|
188
200
|
/** @internal */
|
|
201
|
+
notifyHostVisibility(visible, previous) {
|
|
202
|
+
if (this._disposed || visible === previous)
|
|
203
|
+
return;
|
|
204
|
+
this._hostVisibility = visible;
|
|
205
|
+
for (const listener of this._hostVisibilityListeners)
|
|
206
|
+
listener(visible, previous);
|
|
207
|
+
}
|
|
208
|
+
/** @internal */
|
|
189
209
|
dispose() {
|
|
190
210
|
if (this._disposed)
|
|
191
211
|
return;
|
|
192
212
|
this._disposed = true;
|
|
193
213
|
this._propsListeners.clear();
|
|
194
214
|
this._contentListeners.clear();
|
|
215
|
+
this._hostVisibilityListeners.clear();
|
|
195
216
|
}
|
|
196
217
|
_subscribeProps(listener, options) {
|
|
197
218
|
if (this._disposed || options?.signal?.aborted)
|
|
@@ -221,8 +242,25 @@ var ReactiveAdapterImpl = class {
|
|
|
221
242
|
options?.signal?.addEventListener("abort", unsub, { once: true });
|
|
222
243
|
return unsub;
|
|
223
244
|
}
|
|
245
|
+
_subscribeHostVisibility(listener, options) {
|
|
246
|
+
if (this._disposed || options?.signal?.aborted)
|
|
247
|
+
return () => {
|
|
248
|
+
};
|
|
249
|
+
this._hostVisibilityListeners.add(listener);
|
|
250
|
+
if (options?.immediate)
|
|
251
|
+
listener(this._hostVisibility, this._hostVisibility);
|
|
252
|
+
const unsub = () => {
|
|
253
|
+
this._hostVisibilityListeners.delete(listener);
|
|
254
|
+
options?.signal?.removeEventListener("abort", unsub);
|
|
255
|
+
};
|
|
256
|
+
options?.signal?.addEventListener("abort", unsub, { once: true });
|
|
257
|
+
return unsub;
|
|
258
|
+
}
|
|
224
259
|
};
|
|
225
260
|
|
|
261
|
+
// src/visibility.ts
|
|
262
|
+
import { readWippyVisibility, setWippyVisibility, WIPPY_VISIBILITY_ATTRIBUTE } from "@wippy-fe/shared";
|
|
263
|
+
|
|
226
264
|
// src/base-element.ts
|
|
227
265
|
var WippyElement = class extends HTMLElement {
|
|
228
266
|
constructor() {
|
|
@@ -253,7 +291,9 @@ var WippyElement = class extends HTMLElement {
|
|
|
253
291
|
__publicField(this, "_lastContent", null);
|
|
254
292
|
/** Unsubscribe from host `@theme` broadcasts; set on connect, cleared on disconnect. */
|
|
255
293
|
__publicField(this, "_themeUnsub", null);
|
|
294
|
+
__publicField(this, "_hostVisible", null);
|
|
256
295
|
this._internals = this.attachInternals();
|
|
296
|
+
this._hostVisible = readWippyVisibility(this);
|
|
257
297
|
}
|
|
258
298
|
/**
|
|
259
299
|
* Override to provide the component's configuration.
|
|
@@ -274,7 +314,14 @@ var WippyElement = class extends HTMLElement {
|
|
|
274
314
|
const config = this.wippyConfig;
|
|
275
315
|
const schemaAttrs = Object.keys(config.propsSchema.properties);
|
|
276
316
|
const extra = config.extraObservedAttributes ?? [];
|
|
277
|
-
return [...schemaAttrs, ...extra];
|
|
317
|
+
return [.../* @__PURE__ */ new Set([...schemaAttrs, ...extra, WIPPY_VISIBILITY_ATTRIBUTE])];
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Host-owned logical activity. `null` means no host manages this element.
|
|
321
|
+
* It is not CSS visibility or viewport intersection.
|
|
322
|
+
*/
|
|
323
|
+
get hostVisible() {
|
|
324
|
+
return this._hostVisible;
|
|
278
325
|
}
|
|
279
326
|
/**
|
|
280
327
|
* Panel-scoped `host` wrapper attached by the managed-layout shell's
|
|
@@ -347,7 +394,7 @@ var WippyElement = class extends HTMLElement {
|
|
|
347
394
|
if (hasContent && this._lastContent === null)
|
|
348
395
|
this._lastContent = content;
|
|
349
396
|
this._reactive = new ReactiveAdapterImpl(
|
|
350
|
-
{ props, errors, content, hasContent },
|
|
397
|
+
{ props, errors, content, hasContent, hostVisibility: this._hostVisible },
|
|
351
398
|
this.emitEvent.bind(this)
|
|
352
399
|
);
|
|
353
400
|
}
|
|
@@ -471,9 +518,21 @@ var WippyElement = class extends HTMLElement {
|
|
|
471
518
|
delete this.__wippyHost;
|
|
472
519
|
delete this.__wippyHostBus;
|
|
473
520
|
}
|
|
474
|
-
attributeChangedCallback(
|
|
521
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
475
522
|
if (oldVal === newVal)
|
|
476
523
|
return;
|
|
524
|
+
if (name === WIPPY_VISIBILITY_ATTRIBUTE) {
|
|
525
|
+
const previous = this._hostVisible;
|
|
526
|
+
const visible = readWippyVisibility(this);
|
|
527
|
+
if (visible === previous)
|
|
528
|
+
return;
|
|
529
|
+
this._hostVisible = visible;
|
|
530
|
+
if (this.isConnected && this._initialized) {
|
|
531
|
+
this._reactive?.notifyHostVisibility(visible, previous);
|
|
532
|
+
this.onHostVisibilityChanged(visible, previous);
|
|
533
|
+
}
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
477
536
|
const config = this.constructor.wippyConfig;
|
|
478
537
|
const { props, errors } = parseProps(this, config.propsSchema);
|
|
479
538
|
if (config.validateProps) {
|
|
@@ -499,6 +558,12 @@ var WippyElement = class extends HTMLElement {
|
|
|
499
558
|
/** Called when observed attributes change. Override to update framework state. */
|
|
500
559
|
onPropsChanged(_props, _errors) {
|
|
501
560
|
}
|
|
561
|
+
/**
|
|
562
|
+
* Called when the host changes logical activity. `null` means unmanaged.
|
|
563
|
+
* This does not imply a DOM remount or a CSS/viewport visibility change.
|
|
564
|
+
*/
|
|
565
|
+
onHostVisibilityChanged(_visible, _previous) {
|
|
566
|
+
}
|
|
502
567
|
/**
|
|
503
568
|
* Extract text from a child `<template data-type="...">` element.
|
|
504
569
|
* Uses `.content.textContent` since `<template>` stores content in a DocumentFragment.
|
|
@@ -520,6 +585,7 @@ function getWippyPanelId(el) {
|
|
|
520
585
|
return el.dataset.wippyPanelId ?? null;
|
|
521
586
|
}
|
|
522
587
|
export {
|
|
588
|
+
WIPPY_VISIBILITY_ATTRIBUTE,
|
|
523
589
|
WippyElement,
|
|
524
590
|
attrToCamel,
|
|
525
591
|
define,
|
|
@@ -528,6 +594,8 @@ export {
|
|
|
528
594
|
getWippyPanelId,
|
|
529
595
|
injectInlineCss,
|
|
530
596
|
loadHostCss,
|
|
531
|
-
parseProps
|
|
597
|
+
parseProps,
|
|
598
|
+
readWippyVisibility,
|
|
599
|
+
setWippyVisibility
|
|
532
600
|
};
|
|
533
601
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base-element.ts","../src/css-loader.ts","../src/host-scope.ts","../src/prop-parser.ts","../src/reactive-adapter.ts","../src/host-bus.ts"],"sourcesContent":["import type { ReactiveAdapter } from './reactive-adapter.ts'\r\nimport type { WippyElementConfig } from './types.ts'\r\nimport { addCollection } from '@iconify/vue'\r\nimport { addIcons, applyThemeMode, define, config as hostConfig, host as wippyHost, on as wippyOn } from '@wippy-fe/proxy'\r\nimport { injectCustomCss, injectInlineCss, loadHostCss } from './css-loader.ts'\r\nimport { getWippyHost } from './host-scope.ts'\r\nimport { parseProps } from './prop-parser.ts'\r\nimport { ReactiveAdapterImpl } from './reactive-adapter.ts'\r\n\r\n/**\r\n * Abstract base class for Wippy web components.\r\n *\r\n * Generic over `Props` — the parsed prop object type. This types `onMount`,\r\n * `onPropsChanged`, and `validateProps`. Defaults to `Record<string, unknown>`.\r\n *\r\n * Lifecycle order (first connect):\r\n * 1. shadow DOM attached\r\n * 2. `onInit(shadow)` — hook for early shadow DOM customization\r\n * 3. inline CSS injected\r\n * 4. host CSS loading started (async, non-blocking)\r\n * 5. container div created and appended\r\n * 6. icons registered\r\n * 7. props parsed from attributes + custom validation\r\n * 8. `onMount(shadow, container, props, errors)` — framework setup\r\n * 9. internals state → ready\r\n * 10. `onReady()` — post-mount hook\r\n * 11. `load` event emitted\r\n *\r\n * On reconnect (move-style DOM op: detach → reattach), the shadow root\r\n * persists across the cycle, so steps 1, 3, 4, 5 (CSS injection +\r\n * container creation) are skipped to avoid duplicating `<style>` and\r\n * container `<div>` siblings inside the persistent shadow. The stored\r\n * container is reused and `onMount` is re-invoked with `isRemount = true`\r\n * so framework adapters can decide between fresh-mount and remount paths.\r\n *\r\n * On error: `onError(error)` → internals state → error → `error` event\r\n * On disconnect: `onUnmount()` → `unload` event → internals cleared.\r\n * Note: `disconnectedCallback` does NOT clear the shadow root or the\r\n * stored container — they're reused on reconnect.\r\n */\r\nexport abstract class WippyElement<\r\n Props = Record<string, unknown>,\r\n Events = Record<string, unknown>,\r\n> extends HTMLElement {\r\n private _internals!: ElementInternals\r\n private _contentObserver: MutationObserver | null = null\r\n /** True after the first successful connectedCallback completes. */\r\n private _initialized: boolean = false\r\n /** Container div created on first connect; reused on subsequent connects. */\r\n private _container: HTMLElement | null = null\r\n /**\r\n * Opt-in reactive adapter. Lazy-allocated on first `this.reactive`\r\n * access, disposed on `disconnectedCallback`, re-allocated on next\r\n * access after reconnect. Subclasses that never touch `this.reactive`\r\n * pay zero allocation cost — `notifyProps`/`notifyContent` short-circuit\r\n * on the null guard.\r\n */\r\n private _reactive: ReactiveAdapterImpl<Props, Events> | null = null\r\n /**\r\n * Cached results of the most recent `parseProps` + `validateProps`\r\n * pass. Set by `connectedCallback` and `attributeChangedCallback`.\r\n * Read by `get reactive()` to avoid re-parsing on lazy allocation —\r\n * means `validateProps` only ever runs once per attribute change,\r\n * even for consumers that touch `this.reactive` inside `onMount`.\r\n */\r\n private _lastProps: Props | null = null\r\n private _lastErrors: readonly string[] = []\r\n private _lastContent: string | null = null\r\n /** Unsubscribe from host `@theme` broadcasts; set on connect, cleared on disconnect. */\r\n private _themeUnsub: (() => void) | null = null\r\n\r\n /**\r\n * Phantom field to retain the `Events` type parameter so it shows up in\r\n * type errors / `Reflect.get` shape. Adapter typing reads it indirectly\r\n * via the generic.\r\n * @internal\r\n */\r\n declare readonly _events: Events\r\n\r\n /**\r\n * Override to provide the component's configuration.\r\n * Must be static because `observedAttributes` reads it before construction.\r\n *\r\n * Specify the generic to get typed `validateProps`:\r\n * ```ts\r\n * static get wippyConfig(): WippyElementConfig<MyProps> { ... }\r\n * ```\r\n */\r\n static get wippyConfig(): WippyElementConfig {\r\n return { propsSchema: { properties: {} } }\r\n }\r\n\r\n /**\r\n * Derived from the props schema + any `extraObservedAttributes`.\r\n */\r\n static get observedAttributes(): string[] {\r\n const config = this.wippyConfig\r\n const schemaAttrs = Object.keys(config.propsSchema.properties)\r\n const extra = config.extraObservedAttributes ?? []\r\n return [...schemaAttrs, ...extra]\r\n }\r\n\r\n constructor() {\r\n super()\r\n this._internals = this.attachInternals()\r\n }\r\n\r\n /**\r\n * Panel-scoped `host` wrapper attached by the managed-layout shell's\r\n * content resolvers (`ComponentResolver` / `WebComponentPackageLoader`).\r\n *\r\n * Inside a managed-layout panel, this is a wrapper around the universal\r\n * `host` API where context-aware calls (`layout.broadcast / send / on`)\r\n * are routed through the panel-bound bus — so `sourcePanelId` is\r\n * attributed correctly without postMessage indirection. Layout\r\n * mutations and other host methods pass through unchanged.\r\n *\r\n * `null` outside a managed-layout context (compat shell, chat sidebar,\r\n * standalone playground). Subclass code that needs a host in those\r\n * cases can fall back to `import { host } from '@wippy-fe/proxy'`.\r\n */\r\n get host(): ReturnType<typeof getWippyHost> {\r\n return getWippyHost(this)\r\n }\r\n\r\n /**\r\n * Emit a CustomEvent that bubbles and crosses shadow DOM boundaries.\r\n */\r\n protected emitEvent(eventName: string, detail?: unknown): void {\r\n this.dispatchEvent(new CustomEvent(eventName, {\r\n bubbles: true,\r\n composed: true,\r\n detail,\r\n }))\r\n }\r\n\r\n /**\r\n * Opt-in reactive adapter — framework-agnostic. Subscribe to prop\r\n * changes, content changes, or emit typed events from a non-Vue\r\n * consumer without re-rolling reactivity.\r\n *\r\n * ```ts\r\n * class MyEl extends WippyElement<{ count: number }, { tick: { n: number } }> {\r\n * protected onMount() {\r\n * const ctrl = new AbortController()\r\n * this.reactive.props.subscribe(({ count }) => {\r\n * this.shadowRoot!.querySelector('.n')!.textContent = String(count)\r\n * }, { signal: ctrl.signal, immediate: true })\r\n * }\r\n * tick(n: number) { this.reactive.events.emit('tick', { n }) }\r\n * }\r\n * ```\r\n *\r\n * Allocation cost is zero unless this getter is touched. Disposed on\r\n * `disconnectedCallback`; a fresh adapter is allocated on the next\r\n * access after reconnect.\r\n */\r\n protected get reactive(): ReactiveAdapter<Props, Events> {\r\n if (!this._reactive) {\r\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const hasContent = !!config.contentTemplate\r\n // Reuse the cached parse result from the most recent\r\n // `connectedCallback` / `attributeChangedCallback` whenever we\r\n // have one; otherwise fall back to a fresh parse (this happens\r\n // when `reactive` is touched before the element is ever\r\n // connected — rare but legal).\r\n let props: Props\r\n let errors: readonly string[]\r\n if (this._lastProps !== null) {\r\n props = this._lastProps\r\n errors = this._lastErrors\r\n }\r\n else {\r\n const parsed = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n parsed.errors.push(...config.validateProps(parsed.props))\r\n }\r\n props = parsed.props as Props\r\n errors = parsed.errors\r\n this._lastProps = props\r\n this._lastErrors = errors\r\n }\r\n const content = hasContent\r\n ? (this._lastContent ?? this._extractContent(config.contentTemplate!))\r\n : null\r\n if (hasContent && this._lastContent === null)\r\n this._lastContent = content\r\n this._reactive = new ReactiveAdapterImpl<Props, Events>(\r\n { props, errors, content, hasContent },\r\n this.emitEvent.bind(this),\r\n )\r\n }\r\n return this._reactive\r\n }\r\n\r\n // ── Lifecycle ──────────────────────────────────────────────\r\n\r\n connectedCallback(): void {\r\n this._internals.states.add('loading')\r\n try {\r\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const isRemount = this._initialized\r\n\r\n // 1. Shadow DOM (guard against reconnect — attachShadow throws if called twice)\r\n const shadow = this.shadowRoot ?? this.attachShadow({ mode: config.shadowMode ?? 'open' })\r\n\r\n let container: HTMLElement\r\n if (!isRemount) {\r\n // 2. Early hook — customize shadow before CSS/container\r\n this.onInit(shadow)\r\n\r\n // 3. Inline CSS\r\n if (config.inlineCss) {\r\n injectInlineCss(shadow, config.inlineCss)\r\n }\r\n\r\n // 3b. Facade custom CSS (opt-out via `customCss`). Compose the child scopes\r\n // the same way a view.page does — global then children — and inject the\r\n // selector rules into the shadow root (custom properties already inherit).\r\n // The proxy `config` getter throws host-less, so guard the read.\r\n if (config.customCss !== false) {\r\n try {\r\n const theming = hostConfig?.theming\r\n const facadeCss = [theming?.global?.customCSS, theming?.children?.customCSS]\r\n .filter(Boolean)\r\n .join('\\n')\r\n if (facadeCss)\r\n injectCustomCss(shadow, facadeCss)\r\n }\r\n catch { /* host-less / no proxy config — skip */ }\r\n }\r\n\r\n // 4. Host CSS (async, non-blocking)\r\n if (config.hostCssKeys === undefined || config.hostCssKeys.length > 0) {\r\n loadHostCss(shadow, config.hostCssKeys)\r\n }\r\n\r\n // 5. Container\r\n container = document.createElement('div')\r\n const classes = config.containerClasses ?? []\r\n if (classes.length > 0) {\r\n container.classList.add(...classes)\r\n }\r\n shadow.appendChild(container)\r\n this._container = container\r\n\r\n // 6. Icons\r\n addIcons(addCollection)\r\n }\r\n else {\r\n // Reconnect path — reuse the existing shadow children + container.\r\n // Skip CSS/icon/container setup so we don't accumulate duplicate\r\n // `<style>` and container `<div>` siblings on every detach/reattach.\r\n // The framework adapter decides whether to remount on the existing\r\n // container or recreate its app instance.\r\n container = this._container!\r\n }\r\n\r\n // Mirror the forced theme onto the shadow container AND this host element\r\n // so the WC's own theme rules respond — class selectors don't cross the\r\n // shadow boundary (the `--p-*` tokens inherit across it via custom\r\n // properties, so token colors already follow without this). The container\r\n // class is matched by Tailwind `dark:` utilities and `.w-theme-dark &`\r\n // rules (both need an IN-shadow ancestor); the host-element class lets\r\n // `:host(.w-theme-*)` / `:host(:not(.w-theme-light))` selectors (the SCSS\r\n // dark mixin's OS-dark auto branch) reflect the forced mode.\r\n this._applyTheme()\r\n if (!this._themeUnsub)\r\n this._themeUnsub = wippyOn('@theme', (mode: 'auto' | 'light' | 'dark') => this._applyTheme(mode))\r\n\r\n // 7. Parse initial props + custom validation\r\n const { props, errors } = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n errors.push(...config.validateProps(props))\r\n }\r\n const typedProps = props as Props\r\n // Cache so a lazy `get reactive()` call from inside `onMount`\r\n // doesn't re-parse / re-validate.\r\n this._lastProps = typedProps\r\n this._lastErrors = errors\r\n\r\n // 7b. Extract children content (if contentTemplate configured)\r\n let initialContent: string | null = null\r\n if (config.contentTemplate) {\r\n initialContent = this._extractContent(config.contentTemplate)\r\n this._lastContent = initialContent\r\n this._contentObserver = new MutationObserver(() => {\r\n const content = this._extractContent(config.contentTemplate!)\r\n this._lastContent = content\r\n // Fan out to the reactive adapter first so subclass overrides of\r\n // `onContentChanged` that read `this.reactive.content.value` see\r\n // the new value. No-op when the adapter hasn't been allocated.\r\n this._reactive?.notifyContent(content)\r\n this.onContentChanged(content)\r\n })\r\n this._contentObserver.observe(this, {\r\n childList: true,\r\n characterData: true,\r\n subtree: true,\r\n })\r\n }\r\n\r\n // 8. Framework mount (first time) or remount (reconnect)\r\n this.onMount(shadow, container, typedProps, errors, initialContent, isRemount)\r\n\r\n // 9. Ready\r\n this._internals.states.delete('loading')\r\n this._internals.states.add('ready')\r\n\r\n // First-connect bookkeeping after a clean mount.\r\n if (!isRemount) {\r\n this._initialized = true\r\n }\r\n\r\n // 10. Post-mount hook\r\n this.onReady()\r\n\r\n // 11. Emit load\r\n this.emitEvent('load')\r\n }\r\n catch (error) {\r\n this.onError(error)\r\n this._internals.states.delete('loading')\r\n this._internals.states.add('error')\r\n this.emitEvent('error', {\r\n message: error instanceof Error ? error.message : String(error),\r\n error,\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Applies a forced theme mode to this host element AND the shadow container.\r\n * The container class drives in-shadow selectors (Tailwind `dark:` utilities,\r\n * `.w-theme-dark &`); the host-element class drives `:host(.w-theme-*)`\r\n * selectors. On `@theme` broadcasts the resolved `mode` is passed in directly\r\n * (don't re-read `getThemeMode()` — the proxy's config-vs-emit order isn't a\r\n * contract); on the initial connect it defaults to the host's current mode.\r\n * No-op for an older proxy without `getThemeMode` — `applyThemeMode` clamps\r\n * `undefined` to 'auto'.\r\n */\r\n private _applyTheme(mode: Parameters<typeof applyThemeMode>[0] = wippyHost.getThemeMode?.()): void {\r\n applyThemeMode(mode, this)\r\n if (this._container)\r\n applyThemeMode(mode, this._container)\r\n }\r\n\r\n disconnectedCallback(): void {\r\n if (this._themeUnsub) {\r\n this._themeUnsub()\r\n this._themeUnsub = null\r\n }\r\n // Clear the mirrored theme off this host element + container so a parked or\r\n // re-inserted element doesn't carry a stale forced theme — which, via the\r\n // document-level `.w-theme-*` token rules, would otherwise inherit onto any\r\n // slotted light-DOM children. connectedCallback re-applies on reconnect.\r\n applyThemeMode('auto', this)\r\n if (this._container)\r\n applyThemeMode('auto', this._container)\r\n if (this._contentObserver) {\r\n this._contentObserver.disconnect()\r\n this._contentObserver = null\r\n }\r\n this.onUnmount()\r\n this.emitEvent('unload')\r\n this._internals.states.clear()\r\n // Drop the reactive adapter so subscribers from this attachment are\r\n // cleared and a fresh adapter is allocated on the next `this.reactive`\r\n // access (i.e. after reconnect).\r\n this._reactive?.dispose()\r\n this._reactive = null\r\n // Clear cached parse state — `connectedCallback` re-populates on\r\n // reconnect; before then, a lazy `get reactive()` access should\r\n // re-parse from current attributes (rare path).\r\n this._lastProps = null\r\n this._lastErrors = []\r\n this._lastContent = null\r\n // Drop panel-context wires so a detached element held by a\r\n // consumer (or re-inserted into a different panel) doesn't carry\r\n // stale wires that would silently misattribute. The resolver\r\n // re-installs them on the next mount.\r\n delete (this as unknown as { __wippyHost?: unknown }).__wippyHost\r\n delete (this as unknown as { __wippyHostBus?: unknown }).__wippyHostBus\r\n }\r\n\r\n attributeChangedCallback(_name: string, oldVal: string | null, newVal: string | null): void {\r\n if (oldVal === newVal)\r\n return\r\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const { props, errors } = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n errors.push(...config.validateProps(props))\r\n }\r\n const typedProps = props as Props\r\n this._lastProps = typedProps\r\n this._lastErrors = errors\r\n // Fan out to the reactive adapter BEFORE the legacy hook so subclasses\r\n // that override `onPropsChanged` AND read `this.reactive.props.value`\r\n // inside it see consistent state. No-op when the adapter hasn't been\r\n // lazy-allocated.\r\n this._reactive?.notifyProps(typedProps, errors)\r\n this.onPropsChanged(typedProps, errors)\r\n }\r\n\r\n // ── Hooks ──────────────────────────────────────────────────\r\n\r\n /** Called right after shadow DOM is attached, before CSS or container. */\r\n protected onInit(_shadow: ShadowRoot): void {}\r\n\r\n /**\r\n * Called after shadow DOM, CSS, and container are ready. Mount your\r\n * framework here.\r\n *\r\n * Invoked on first connect AND on every subsequent reconnect (move-style\r\n * DOM op: detach → reattach). On reconnect the same `container` instance\r\n * is reused. Adapters that hold a framework app handle should either\r\n * detect `isRemount === true` and re-mount on the existing container, or\r\n * leave the previous app intact across the detach/reattach cycle.\r\n */\r\n protected abstract onMount(\r\n shadow: ShadowRoot,\r\n container: HTMLElement,\r\n initialProps: Props,\r\n initialErrors: string[],\r\n initialContent?: string | null,\r\n isRemount?: boolean,\r\n ): void\r\n\r\n /** Called after internals state is set to ready, before the `load` event. */\r\n protected onReady(): void {}\r\n\r\n /** Called when connectedCallback throws. Default logs to console. */\r\n protected onError(error: unknown): void {\r\n console.error(`${this.constructor.name} initialization failed:`, error)\r\n }\r\n\r\n /** Called during disconnectedCallback — clean up framework resources. */\r\n protected abstract onUnmount(): void\r\n\r\n /** Called when observed attributes change. Override to update framework state. */\r\n protected onPropsChanged(_props: Props, _errors: string[]): void {}\r\n\r\n /**\r\n * Extract text from a child `<template data-type=\"...\">` element.\r\n * Uses `.content.textContent` since `<template>` stores content in a DocumentFragment.\r\n */\r\n private _extractContent(dataType: string): string | null {\r\n const tpl = this.querySelector(`template[data-type=\"${dataType}\"]`) as HTMLTemplateElement | null\r\n return tpl?.content.textContent?.trim() ?? null\r\n }\r\n\r\n /** Called when child `<template>` content changes. Override to update framework state. */\r\n protected onContentChanged(_content: string | null): void {}\r\n}\r\n\r\nexport { define }\r\n","import type { HostCssKey } from './types.ts'\r\nimport { hostCss, loadCss } from '@wippy-fe/proxy'\r\n\r\nconst DEFAULT_HOST_CSS_KEYS: HostCssKey[] = [\r\n 'themeConfigUrl',\r\n 'primeVueCssUrl',\r\n 'markdownCssUrl',\r\n 'iframeCssUrl',\r\n]\r\n\r\n/**\r\n * Loads host CSS URLs into the shadow root as `<style>` elements.\r\n * Non-blocking — returns a promise but the component doesn't need to await it.\r\n */\r\nexport function loadHostCss(shadow: ShadowRoot, keys?: HostCssKey[]): Promise<void> {\r\n const cssKeys = keys ?? DEFAULT_HOST_CSS_KEYS\r\n // Filter out keys whose URL is missing (e.g. removed CSS like fontCssUrl).\r\n // Load each independently so one failure doesn't block the rest.\r\n const jobs = cssKeys.map(async (key) => {\r\n const url = hostCss[key]\r\n if (!url) {\r\n console.warn(`[wippy-fe/webcomponent-core] hostCss key \"${key}\" is undefined — skipping. Remove it from hostCssKeys if the CSS was removed.`)\r\n return null\r\n }\r\n try {\r\n return await loadCss(url)\r\n }\r\n catch (err) {\r\n console.warn(`[wippy-fe/webcomponent-core] Failed to load hostCss \"${key}\" (${url}):`, err)\r\n return null\r\n }\r\n })\r\n return Promise.all(jobs).then((cssChunks) => {\r\n for (const css of cssChunks) {\r\n if (!css)\r\n continue\r\n const style = document.createElement('style')\r\n style.textContent = css\r\n style.setAttribute('role', '@wippy-fe/host-css')\r\n shadow.appendChild(style)\r\n }\r\n })\r\n}\r\n\r\n/**\r\n * Injects inline CSS text into the shadow root.\r\n */\r\nexport function injectInlineCss(shadow: ShadowRoot, text: string): void {\r\n const style = document.createElement('style')\r\n style.textContent = text\r\n shadow.appendChild(style)\r\n}\r\n\r\n/**\r\n * Injects the host's facade custom CSS into the shadow root via an adopted\r\n * stylesheet, which cascades after the component's own `<style>`/`<link>` (and the\r\n * async `hostCssKeys` sheets) whenever they are added — so facade custom CSS wins,\r\n * matching the page pipeline. `@import` rules are dropped by adopted sheets, but the\r\n * font they load is already applied by the host document. Falls back to a trailing\r\n * `<style role=\"@wippy-fe/custom-css\">` where constructable stylesheets are\r\n * unavailable (e.g. jsdom).\r\n */\r\nexport function injectCustomCss(shadow: ShadowRoot, css: string): void {\r\n if (typeof CSSStyleSheet !== 'undefined' && 'replaceSync' in CSSStyleSheet.prototype) {\r\n const sheet = new CSSStyleSheet()\r\n sheet.replaceSync(css)\r\n shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet]\r\n return\r\n }\r\n const style = document.createElement('style')\r\n style.setAttribute('role', '@wippy-fe/custom-css')\r\n style.textContent = css\r\n shadow.appendChild(style)\r\n}\r\n","/**\n * Element-attached host wrapper reader for web components mounted as\n * `kind: 'component'` panels in the gen-2-chat managed-layout shell.\n *\n * The host stamps a panel-scoped wrapper as `__wippyHost` on each\n * element BEFORE it is appended to the DOM (see the host's\n * `panel-context-wires.ts` and `host-scope.ts`). Consumer web\n * components read it back via `getWippyHost(this)` in\n * `connectedCallback` and onwards.\n *\n * The wrapper is **constructed by the host** — this package only\n * exposes the reader. Outside a managed-layout host (raw mounts,\n * compat shells, tests without the connector) the property is absent\n * and `getWippyHost` returns `null`.\n */\n\n/**\n * Read the panel-scoped host wrapper attached to an element by the\n * managed-layout shell's content resolvers. Returns `null` outside a\n * managed-layout host (or before the element is connected).\n *\n * Subclass authors of `WippyElement` / `WippyVueElement` access this\n * via `this.host` / `useHost()` and rarely need to call this directly.\n * The helper is exposed for raw `HTMLElement` consumers.\n */\nexport function getWippyHost<H = unknown>(el: HTMLElement): H | null {\n return ((el as unknown) as { __wippyHost?: H }).__wippyHost ?? null\n}\n","import type { WippyPropDefinition, WippyPropsSchema } from './types.ts'\r\n\r\nexport interface ParseResult {\r\n props: Record<string, unknown>\r\n errors: string[]\r\n}\r\n\r\n/**\r\n * Converts a kebab-case attribute name to camelCase.\r\n * `allowed-types` → `allowedTypes`\r\n */\r\nexport function attrToCamel(attr: string): string {\r\n return attr.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\r\n}\r\n\r\n/**\r\n * Parses a single attribute value according to its schema definition.\r\n */\r\nfunction parseValue(attr: string, raw: string, def: WippyPropDefinition): { value: unknown, error?: string } {\r\n switch (def.type) {\r\n case 'string':\r\n return { value: raw }\r\n\r\n case 'number': {\r\n const n = Number.parseFloat(raw)\r\n if (Number.isNaN(n))\r\n return { value: undefined, error: `Invalid ${attr}: expected a number` }\r\n return { value: n }\r\n }\r\n\r\n case 'integer': {\r\n const n = Number.parseInt(raw, 10)\r\n if (Number.isNaN(n))\r\n return { value: undefined, error: `Invalid ${attr}: expected an integer` }\r\n return { value: n }\r\n }\r\n\r\n case 'boolean':\r\n // Presence of the attribute means true (HTML convention), explicit \"false\" means false\r\n return { value: raw !== 'false' }\r\n\r\n case 'array':\r\n case 'object': {\r\n try {\r\n const parsed = JSON.parse(raw)\r\n if (def.type === 'array' && !Array.isArray(parsed)) {\r\n return { value: undefined, error: `Invalid ${attr}: expected a JSON array` }\r\n }\r\n return { value: parsed }\r\n }\r\n catch {\r\n return { value: undefined, error: `Invalid ${attr}: must be valid JSON` }\r\n }\r\n }\r\n\r\n default:\r\n return { value: raw }\r\n }\r\n}\r\n\r\n/**\r\n * Parses all attributes on an element according to its props schema.\r\n * Returns `{ props, errors }` where errors is an array of human-readable messages.\r\n */\r\nexport function parseProps(element: HTMLElement, schema: WippyPropsSchema): ParseResult {\r\n const props: Record<string, unknown> = {}\r\n const errors: string[] = []\r\n\r\n for (const [attr, def] of Object.entries(schema.properties)) {\r\n const raw = element.getAttribute(attr)\r\n const camel = attrToCamel(attr)\r\n\r\n if (raw === null) {\r\n // Attribute not set — use default if available\r\n if (def.default !== undefined) {\r\n props[camel] = def.default\r\n }\r\n continue\r\n }\r\n\r\n const result = parseValue(attr, raw, def)\r\n if (result.error) {\r\n errors.push(result.error)\r\n }\r\n else {\r\n props[camel] = result.value\r\n }\r\n }\r\n\r\n return { props, errors }\r\n}\r\n","/**\n * Opt-in reactive adapter for `WippyElement`.\n *\n * Framework-agnostic primitive that lets non-Vue consumers subscribe to\n * prop / content updates and emit typed events on a web component without\n * pulling Vue (or any other reactivity library) into the core bundle.\n *\n * Access via `this.reactive` on a `WippyElement` subclass — the getter is\n * lazy, so subclasses that never touch it pay zero allocation cost. See\n * `base-element.ts:get reactive` for the bridge into the lifecycle.\n *\n * The `notifyProps` / `notifyContent` methods are package-visible: the\n * base element calls them from `attributeChangedCallback` and the content\n * MutationObserver callback respectively. They are NOT part of the public\n * API consumers should reach for.\n *\n * Cleanup: `dispose()` runs from `disconnectedCallback`. All listener\n * sets are cleared; subsequent notifyProps/notifyContent are no-ops; the\n * `events.emit` becomes a no-op too. A fresh adapter is allocated on the\n * next `this.reactive` access (i.e. after reconnect).\n */\n\nexport type PropsListener<Props> = (props: Props, errors: readonly string[]) => void\nexport type ContentListener = (content: string | null) => void\n\nexport interface SubscribeOptions {\n /** Cancel the subscription when the signal aborts. */\n signal?: AbortSignal\n /** Fire the listener once synchronously with the current value. */\n immediate?: boolean\n}\n\nexport interface PropsSubscription<Props> {\n /** Current parsed props. Always reflects the latest state. */\n readonly value: Props\n /** Current validation/parse errors. */\n readonly errors: readonly string[]\n /**\n * Register a listener that fires whenever props change. Returns an\n * unsubscribe function. Pass `options.signal` for AbortSignal-driven\n * cleanup (e.g. tied to an element's lifetime). Pass\n * `options.immediate: true` to fire once synchronously with the current\n * value — useful when the subscriber is set up mid-flight.\n *\n * Note: `notifyProps` runs BEFORE the subclass `onPropsChanged()` hook.\n * A subscriber added from inside `onPropsChanged()` therefore does NOT\n * receive the currently-firing change — only the next one. Use\n * `{ immediate: true }` to also see the current value.\n */\n subscribe: (listener: PropsListener<Props>, options?: SubscribeOptions) => () => void\n}\n\nexport interface ContentSubscription {\n /** Current `<template>` content text, or `null` if not set. */\n readonly value: string | null\n /** See `PropsSubscription.subscribe` for the same ordering caveat. */\n subscribe: (listener: ContentListener, options?: SubscribeOptions) => () => void\n}\n\nexport interface EventEmitterHandle<Events> {\n /**\n * Dispatch a typed `CustomEvent` (bubbles + composed, identical\n * semantics to the protected `emitEvent` helper). The key is constrained\n * to `keyof Events & string`, so consumers narrow `Events` to get\n * autocomplete + payload-type checks.\n *\n * No-op after the adapter is disposed (i.e. after the element is\n * detached). The element is the only event target — subscribers on\n * the element itself receive the event.\n */\n emit: <K extends keyof Events & string>(event: K, detail: Events[K]) => void\n}\n\nexport interface ReactiveAdapter<Props, Events> {\n props: PropsSubscription<Props>\n events: EventEmitterHandle<Events>\n /**\n * Present only when the element's `wippyConfig.contentTemplate` is set;\n * `null` otherwise. Avoids fake `.value === null` semantics for elements\n * that don't track children content.\n */\n content: ContentSubscription | null\n}\n\n/**\n * Concrete implementation used by `WippyElement`. The `notify*` methods\n * are intentionally exposed (not private) so the base-element can call\n * them; consumers should never reach for them.\n *\n * @internal\n */\nexport class ReactiveAdapterImpl<Props, Events> implements ReactiveAdapter<Props, Events> {\n private _props: Props\n private _errors: readonly string[]\n private _content: string | null\n private _propsListeners = new Set<PropsListener<Props>>()\n private _contentListeners = new Set<ContentListener>()\n private _disposed = false\n private _emitToDom: (eventName: string, detail?: unknown) => void\n\n readonly props: PropsSubscription<Props>\n readonly events: EventEmitterHandle<Events>\n readonly content: ContentSubscription | null\n\n constructor(\n initial: {\n props: Props\n errors: readonly string[]\n content: string | null\n hasContent: boolean\n },\n emitToDom: (eventName: string, detail?: unknown) => void,\n ) {\n this._props = initial.props\n this._errors = initial.errors\n this._content = initial.content\n this._emitToDom = emitToDom\n\n // Each getter / closure below runs with the surrounding object literal\n // as `this`, not the class instance — so we have to capture the\n // instance explicitly here.\n // eslint-disable-next-line ts/no-this-alias\n const self = this\n\n this.props = {\n get value() {\n return self._props\n },\n get errors() {\n return self._errors\n },\n subscribe(listener, options) {\n return self._subscribeProps(listener, options)\n },\n }\n\n this.events = {\n emit(event, detail) {\n if (self._disposed)\n return\n self._emitToDom(event as string, detail)\n },\n }\n\n this.content = initial.hasContent\n ? {\n get value() {\n return self._content\n },\n subscribe(listener, options) {\n return self._subscribeContent(listener, options)\n },\n }\n : null\n }\n\n /** @internal */\n notifyProps(props: Props, errors: readonly string[]): void {\n if (this._disposed)\n return\n this._props = props\n this._errors = errors\n for (const listener of this._propsListeners)\n listener(props, errors)\n }\n\n /** @internal */\n notifyContent(content: string | null): void {\n if (this._disposed)\n return\n this._content = content\n for (const listener of this._contentListeners)\n listener(content)\n }\n\n /** @internal */\n dispose(): void {\n if (this._disposed)\n return\n this._disposed = true\n this._propsListeners.clear()\n this._contentListeners.clear()\n }\n\n private _subscribeProps(listener: PropsListener<Props>, options?: SubscribeOptions): () => void {\n if (this._disposed || options?.signal?.aborted)\n return () => {}\n // Add to the set BEFORE firing `immediate` so a re-entrant\n // `notifyProps` triggered from inside the immediate callback can\n // find this listener and fire it for the synchronous change too.\n this._propsListeners.add(listener)\n if (options?.immediate)\n listener(this._props, this._errors)\n const unsub = () => {\n this._propsListeners.delete(listener)\n // Manual unsub must also detach the abort listener — otherwise it\n // accumulates on long-lived signals (e.g. an AbortController kept\n // around for the element's whole lifetime that fans out to many\n // subscriptions). `{ once: true }` only auto-removes when 'abort'\n // actually fires.\n options?.signal?.removeEventListener('abort', unsub)\n }\n options?.signal?.addEventListener('abort', unsub, { once: true })\n return unsub\n }\n\n private _subscribeContent(listener: ContentListener, options?: SubscribeOptions): () => void {\n if (this._disposed || options?.signal?.aborted)\n return () => {}\n this._contentListeners.add(listener)\n if (options?.immediate)\n listener(this._content)\n const unsub = () => {\n this._contentListeners.delete(listener)\n options?.signal?.removeEventListener('abort', unsub)\n }\n options?.signal?.addEventListener('abort', unsub, { once: true })\n return unsub\n }\n}\n","/**\n * Layout bus types shared between `@wippy-fe/webcomponent-core` and\n * `@wippy-fe/webcomponent-vue`. Mirror of the host-side\n * `LayoutBusBound` / `BroadcastEnvelope` shapes; structurally\n * compatible so a host-mounted web component can read its\n * `__wippyHostBus` property without importing host-private types.\n *\n * The host (gen-2-chat managed-layout shell) sets:\n * - `el.dataset.wippyPanelId` (string)\n * - `(el as { __wippyHostBus?: LayoutBusBound }).__wippyHostBus`\n * BEFORE the element is appended to the DOM. Web components see them\n * on first `connectedCallback` tick.\n *\n * Outside a managed-layout host, both are absent — read code MUST\n * tolerate `undefined`.\n *\n * The interface bodies live in `@wippy-fe/shared` so the host can\n * import them without dragging in this package's `@wippy-fe/proxy`\n * runtime dependency. Consumers continue to import from\n * `@wippy-fe/webcomponent-core` (this re-export) for backward compat.\n */\n\nimport type { LayoutBusBound } from '@wippy-fe/shared'\n\nexport type { BroadcastEnvelope, LayoutBusBound } from '@wippy-fe/shared'\n\n/**\n * Read the host bus attached to an element by `ComponentResolver` in\n * the managed-layout host. Returns `null` outside a managed-layout\n * host (or before the element is connected). Stable across element\n * remounts of the same panel — the resolver re-attaches a fresh bus\n * each time.\n */\nexport function getWippyHostBus(el: HTMLElement): LayoutBusBound | null {\n return (el as { __wippyHostBus?: LayoutBusBound }).__wippyHostBus ?? null\n}\n\n/**\n * Read the panelId attribute set by `ComponentResolver`. `null`\n * outside a managed-layout host.\n */\nexport function getWippyPanelId(el: HTMLElement): string | null {\n return el.dataset.wippyPanelId ?? null\n}\n"],"mappings":";;;;;AAEA,SAAS,qBAAqB;AAC9B,SAAS,UAAU,gBAAgB,QAAQ,UAAU,YAAY,QAAQ,WAAW,MAAM,eAAe;;;ACFzG,SAAS,SAAS,eAAe;AAEjC,IAAM,wBAAsC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,YAAY,QAAoB,MAAoC;AAClF,QAAM,UAAU,QAAQ;AAGxB,QAAM,OAAO,QAAQ,IAAI,OAAO,QAAQ;AACtC,UAAM,MAAM,QAAQ,GAAG;AACvB,QAAI,CAAC,KAAK;AACR,cAAQ,KAAK,6CAA6C,GAAG,oFAA+E;AAC5I,aAAO;AAAA,IACT;AACA,QAAI;AACF,aAAO,MAAM,QAAQ,GAAG;AAAA,IAC1B,SACO,KAAK;AACV,cAAQ,KAAK,wDAAwD,GAAG,MAAM,GAAG,MAAM,GAAG;AAC1F,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,SAAO,QAAQ,IAAI,IAAI,EAAE,KAAK,CAAC,cAAc;AAC3C,eAAW,OAAO,WAAW;AAC3B,UAAI,CAAC;AACH;AACF,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,cAAc;AACpB,YAAM,aAAa,QAAQ,oBAAoB;AAC/C,aAAO,YAAY,KAAK;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;AAKO,SAAS,gBAAgB,QAAoB,MAAoB;AACtE,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,cAAc;AACpB,SAAO,YAAY,KAAK;AAC1B;AAWO,SAAS,gBAAgB,QAAoB,KAAmB;AACrE,MAAI,OAAO,kBAAkB,eAAe,iBAAiB,cAAc,WAAW;AACpF,UAAM,QAAQ,IAAI,cAAc;AAChC,UAAM,YAAY,GAAG;AACrB,WAAO,qBAAqB,CAAC,GAAG,OAAO,oBAAoB,KAAK;AAChE;AAAA,EACF;AACA,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,aAAa,QAAQ,sBAAsB;AACjD,QAAM,cAAc;AACpB,SAAO,YAAY,KAAK;AAC1B;;;AChDO,SAAS,aAA0B,IAA2B;AACnE,SAAS,GAAuC,eAAe;AACjE;;;AChBO,SAAS,YAAY,MAAsB;AAChD,SAAO,KAAK,QAAQ,aAAa,CAAC,GAAG,MAAc,EAAE,YAAY,CAAC;AACpE;AAKA,SAAS,WAAW,MAAc,KAAa,KAA8D;AAC3G,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AACH,aAAO,EAAE,OAAO,IAAI;AAAA,IAEtB,KAAK,UAAU;AACb,YAAM,IAAI,OAAO,WAAW,GAAG;AAC/B,UAAI,OAAO,MAAM,CAAC;AAChB,eAAO,EAAE,OAAO,QAAW,OAAO,WAAW,IAAI,sBAAsB;AACzE,aAAO,EAAE,OAAO,EAAE;AAAA,IACpB;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,UAAI,OAAO,MAAM,CAAC;AAChB,eAAO,EAAE,OAAO,QAAW,OAAO,WAAW,IAAI,wBAAwB;AAC3E,aAAO,EAAE,OAAO,EAAE;AAAA,IACpB;AAAA,IAEA,KAAK;AAEH,aAAO,EAAE,OAAO,QAAQ,QAAQ;AAAA,IAElC,KAAK;AAAA,IACL,KAAK,UAAU;AACb,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAI,IAAI,SAAS,WAAW,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClD,iBAAO,EAAE,OAAO,QAAW,OAAO,WAAW,IAAI,0BAA0B;AAAA,QAC7E;AACA,eAAO,EAAE,OAAO,OAAO;AAAA,MACzB,QACM;AACJ,eAAO,EAAE,OAAO,QAAW,OAAO,WAAW,IAAI,uBAAuB;AAAA,MAC1E;AAAA,IACF;AAAA,IAEA;AACE,aAAO,EAAE,OAAO,IAAI;AAAA,EACxB;AACF;AAMO,SAAS,WAAW,SAAsB,QAAuC;AACtF,QAAM,QAAiC,CAAC;AACxC,QAAM,SAAmB,CAAC;AAE1B,aAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC3D,UAAM,MAAM,QAAQ,aAAa,IAAI;AACrC,UAAM,QAAQ,YAAY,IAAI;AAE9B,QAAI,QAAQ,MAAM;AAEhB,UAAI,IAAI,YAAY,QAAW;AAC7B,cAAM,KAAK,IAAI,IAAI;AAAA,MACrB;AACA;AAAA,IACF;AAEA,UAAM,SAAS,WAAW,MAAM,KAAK,GAAG;AACxC,QAAI,OAAO,OAAO;AAChB,aAAO,KAAK,OAAO,KAAK;AAAA,IAC1B,OACK;AACH,YAAM,KAAK,IAAI,OAAO;AAAA,IACxB;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,OAAO;AACzB;;;ACCO,IAAM,sBAAN,MAAmF;AAAA,EAaxF,YACE,SAMA,WACA;AApBF,wBAAQ;AACR,wBAAQ;AACR,wBAAQ;AACR,wBAAQ,mBAAkB,oBAAI,IAA0B;AACxD,wBAAQ,qBAAoB,oBAAI,IAAqB;AACrD,wBAAQ,aAAY;AACpB,wBAAQ;AAER,wBAAS;AACT,wBAAS;AACT,wBAAS;AAWP,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AACvB,SAAK,WAAW,QAAQ;AACxB,SAAK,aAAa;AAMlB,UAAM,OAAO;AAEb,SAAK,QAAQ;AAAA,MACX,IAAI,QAAQ;AACV,eAAO,KAAK;AAAA,MACd;AAAA,MACA,IAAI,SAAS;AACX,eAAO,KAAK;AAAA,MACd;AAAA,MACA,UAAU,UAAU,SAAS;AAC3B,eAAO,KAAK,gBAAgB,UAAU,OAAO;AAAA,MAC/C;AAAA,IACF;AAEA,SAAK,SAAS;AAAA,MACZ,KAAK,OAAO,QAAQ;AAClB,YAAI,KAAK;AACP;AACF,aAAK,WAAW,OAAiB,MAAM;AAAA,MACzC;AAAA,IACF;AAEA,SAAK,UAAU,QAAQ,aACnB;AAAA,MACE,IAAI,QAAQ;AACV,eAAO,KAAK;AAAA,MACd;AAAA,MACA,UAAU,UAAU,SAAS;AAC3B,eAAO,KAAK,kBAAkB,UAAU,OAAO;AAAA,MACjD;AAAA,IACF,IACA;AAAA,EACN;AAAA;AAAA,EAGA,YAAY,OAAc,QAAiC;AACzD,QAAI,KAAK;AACP;AACF,SAAK,SAAS;AACd,SAAK,UAAU;AACf,eAAW,YAAY,KAAK;AAC1B,eAAS,OAAO,MAAM;AAAA,EAC1B;AAAA;AAAA,EAGA,cAAc,SAA8B;AAC1C,QAAI,KAAK;AACP;AACF,SAAK,WAAW;AAChB,eAAW,YAAY,KAAK;AAC1B,eAAS,OAAO;AAAA,EACpB;AAAA;AAAA,EAGA,UAAgB;AACd,QAAI,KAAK;AACP;AACF,SAAK,YAAY;AACjB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,kBAAkB,MAAM;AAAA,EAC/B;AAAA,EAEQ,gBAAgB,UAAgC,SAAwC;AAC9F,QAAI,KAAK,aAAa,SAAS,QAAQ;AACrC,aAAO,MAAM;AAAA,MAAC;AAIhB,SAAK,gBAAgB,IAAI,QAAQ;AACjC,QAAI,SAAS;AACX,eAAS,KAAK,QAAQ,KAAK,OAAO;AACpC,UAAM,QAAQ,MAAM;AAClB,WAAK,gBAAgB,OAAO,QAAQ;AAMpC,eAAS,QAAQ,oBAAoB,SAAS,KAAK;AAAA,IACrD;AACA,aAAS,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAChE,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,UAA2B,SAAwC;AAC3F,QAAI,KAAK,aAAa,SAAS,QAAQ;AACrC,aAAO,MAAM;AAAA,MAAC;AAChB,SAAK,kBAAkB,IAAI,QAAQ;AACnC,QAAI,SAAS;AACX,eAAS,KAAK,QAAQ;AACxB,UAAM,QAAQ,MAAM;AAClB,WAAK,kBAAkB,OAAO,QAAQ;AACtC,eAAS,QAAQ,oBAAoB,SAAS,KAAK;AAAA,IACrD;AACA,aAAS,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAChE,WAAO;AAAA,EACT;AACF;;;AJnLO,IAAe,eAAf,cAGG,YAAY;AAAA,EA2DpB,cAAc;AACZ,UAAM;AA3DR,wBAAQ;AACR,wBAAQ,oBAA4C;AAEpD;AAAA,wBAAQ,gBAAwB;AAEhC;AAAA,wBAAQ,cAAiC;AAQzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAQ,aAAuD;AAQ/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAQ,cAA2B;AACnC,wBAAQ,eAAiC,CAAC;AAC1C,wBAAQ,gBAA8B;AAEtC;AAAA,wBAAQ,eAAmC;AAmCzC,SAAK,aAAa,KAAK,gBAAgB;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAjBA,WAAW,cAAkC;AAC3C,WAAO,EAAE,aAAa,EAAE,YAAY,CAAC,EAAE,EAAE;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,qBAA+B;AACxC,UAAM,SAAS,KAAK;AACpB,UAAM,cAAc,OAAO,KAAK,OAAO,YAAY,UAAU;AAC7D,UAAM,QAAQ,OAAO,2BAA2B,CAAC;AACjD,WAAO,CAAC,GAAG,aAAa,GAAG,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,IAAI,OAAwC;AAC1C,WAAO,aAAa,IAAI;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKU,UAAU,WAAmB,QAAwB;AAC7D,SAAK,cAAc,IAAI,YAAY,WAAW;AAAA,MAC5C,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,IACF,CAAC,CAAC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,IAAc,WAA2C;AACvD,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,SAAU,KAAK,YAAoC;AACzD,YAAM,aAAa,CAAC,CAAC,OAAO;AAM5B,UAAI;AACJ,UAAI;AACJ,UAAI,KAAK,eAAe,MAAM;AAC5B,gBAAQ,KAAK;AACb,iBAAS,KAAK;AAAA,MAChB,OACK;AACH,cAAM,SAAS,WAAW,MAAM,OAAO,WAAW;AAClD,YAAI,OAAO,eAAe;AACxB,iBAAO,OAAO,KAAK,GAAG,OAAO,cAAc,OAAO,KAAK,CAAC;AAAA,QAC1D;AACA,gBAAQ,OAAO;AACf,iBAAS,OAAO;AAChB,aAAK,aAAa;AAClB,aAAK,cAAc;AAAA,MACrB;AACA,YAAM,UAAU,aACX,KAAK,gBAAgB,KAAK,gBAAgB,OAAO,eAAgB,IAClE;AACJ,UAAI,cAAc,KAAK,iBAAiB;AACtC,aAAK,eAAe;AACtB,WAAK,YAAY,IAAI;AAAA,QACnB,EAAE,OAAO,QAAQ,SAAS,WAAW;AAAA,QACrC,KAAK,UAAU,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAIA,oBAA0B;AACxB,SAAK,WAAW,OAAO,IAAI,SAAS;AACpC,QAAI;AACF,YAAM,SAAU,KAAK,YAAoC;AACzD,YAAM,YAAY,KAAK;AAGvB,YAAM,SAAS,KAAK,cAAc,KAAK,aAAa,EAAE,MAAM,OAAO,cAAc,OAAO,CAAC;AAEzF,UAAI;AACJ,UAAI,CAAC,WAAW;AAEd,aAAK,OAAO,MAAM;AAGlB,YAAI,OAAO,WAAW;AACpB,0BAAgB,QAAQ,OAAO,SAAS;AAAA,QAC1C;AAMA,YAAI,OAAO,cAAc,OAAO;AAC9B,cAAI;AACF,kBAAM,UAAU,YAAY;AAC5B,kBAAM,YAAY,CAAC,SAAS,QAAQ,WAAW,SAAS,UAAU,SAAS,EACxE,OAAO,OAAO,EACd,KAAK,IAAI;AACZ,gBAAI;AACF,8BAAgB,QAAQ,SAAS;AAAA,UACrC,QACM;AAAA,UAA2C;AAAA,QACnD;AAGA,YAAI,OAAO,gBAAgB,UAAa,OAAO,YAAY,SAAS,GAAG;AACrE,sBAAY,QAAQ,OAAO,WAAW;AAAA,QACxC;AAGA,oBAAY,SAAS,cAAc,KAAK;AACxC,cAAM,UAAU,OAAO,oBAAoB,CAAC;AAC5C,YAAI,QAAQ,SAAS,GAAG;AACtB,oBAAU,UAAU,IAAI,GAAG,OAAO;AAAA,QACpC;AACA,eAAO,YAAY,SAAS;AAC5B,aAAK,aAAa;AAGlB,iBAAS,aAAa;AAAA,MACxB,OACK;AAMH,oBAAY,KAAK;AAAA,MACnB;AAUA,WAAK,YAAY;AACjB,UAAI,CAAC,KAAK;AACR,aAAK,cAAc,QAAQ,UAAU,CAAC,SAAoC,KAAK,YAAY,IAAI,CAAC;AAGlG,YAAM,EAAE,OAAO,OAAO,IAAI,WAAW,MAAM,OAAO,WAAW;AAC7D,UAAI,OAAO,eAAe;AACxB,eAAO,KAAK,GAAG,OAAO,cAAc,KAAK,CAAC;AAAA,MAC5C;AACA,YAAM,aAAa;AAGnB,WAAK,aAAa;AAClB,WAAK,cAAc;AAGnB,UAAI,iBAAgC;AACpC,UAAI,OAAO,iBAAiB;AAC1B,yBAAiB,KAAK,gBAAgB,OAAO,eAAe;AAC5D,aAAK,eAAe;AACpB,aAAK,mBAAmB,IAAI,iBAAiB,MAAM;AACjD,gBAAM,UAAU,KAAK,gBAAgB,OAAO,eAAgB;AAC5D,eAAK,eAAe;AAIpB,eAAK,WAAW,cAAc,OAAO;AACrC,eAAK,iBAAiB,OAAO;AAAA,QAC/B,CAAC;AACD,aAAK,iBAAiB,QAAQ,MAAM;AAAA,UAClC,WAAW;AAAA,UACX,eAAe;AAAA,UACf,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAGA,WAAK,QAAQ,QAAQ,WAAW,YAAY,QAAQ,gBAAgB,SAAS;AAG7E,WAAK,WAAW,OAAO,OAAO,SAAS;AACvC,WAAK,WAAW,OAAO,IAAI,OAAO;AAGlC,UAAI,CAAC,WAAW;AACd,aAAK,eAAe;AAAA,MACtB;AAGA,WAAK,QAAQ;AAGb,WAAK,UAAU,MAAM;AAAA,IACvB,SACO,OAAO;AACZ,WAAK,QAAQ,KAAK;AAClB,WAAK,WAAW,OAAO,OAAO,SAAS;AACvC,WAAK,WAAW,OAAO,IAAI,OAAO;AAClC,WAAK,UAAU,SAAS;AAAA,QACtB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,YAAY,OAA6C,UAAU,eAAe,GAAS;AACjG,mBAAe,MAAM,IAAI;AACzB,QAAI,KAAK;AACP,qBAAe,MAAM,KAAK,UAAU;AAAA,EACxC;AAAA,EAEA,uBAA6B;AAC3B,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY;AACjB,WAAK,cAAc;AAAA,IACrB;AAKA,mBAAe,QAAQ,IAAI;AAC3B,QAAI,KAAK;AACP,qBAAe,QAAQ,KAAK,UAAU;AACxC,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,WAAW;AACjC,WAAK,mBAAmB;AAAA,IAC1B;AACA,SAAK,UAAU;AACf,SAAK,UAAU,QAAQ;AACvB,SAAK,WAAW,OAAO,MAAM;AAI7B,SAAK,WAAW,QAAQ;AACxB,SAAK,YAAY;AAIjB,SAAK,aAAa;AAClB,SAAK,cAAc,CAAC;AACpB,SAAK,eAAe;AAKpB,WAAQ,KAA8C;AACtD,WAAQ,KAAiD;AAAA,EAC3D;AAAA,EAEA,yBAAyB,OAAe,QAAuB,QAA6B;AAC1F,QAAI,WAAW;AACb;AACF,UAAM,SAAU,KAAK,YAAoC;AACzD,UAAM,EAAE,OAAO,OAAO,IAAI,WAAW,MAAM,OAAO,WAAW;AAC7D,QAAI,OAAO,eAAe;AACxB,aAAO,KAAK,GAAG,OAAO,cAAc,KAAK,CAAC;AAAA,IAC5C;AACA,UAAM,aAAa;AACnB,SAAK,aAAa;AAClB,SAAK,cAAc;AAKnB,SAAK,WAAW,YAAY,YAAY,MAAM;AAC9C,SAAK,eAAe,YAAY,MAAM;AAAA,EACxC;AAAA;AAAA;AAAA,EAKU,OAAO,SAA2B;AAAA,EAAC;AAAA;AAAA,EAsBnC,UAAgB;AAAA,EAAC;AAAA;AAAA,EAGjB,QAAQ,OAAsB;AACtC,YAAQ,MAAM,GAAG,KAAK,YAAY,IAAI,2BAA2B,KAAK;AAAA,EACxE;AAAA;AAAA,EAMU,eAAe,QAAe,SAAyB;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1D,gBAAgB,UAAiC;AACvD,UAAM,MAAM,KAAK,cAAc,uBAAuB,QAAQ,IAAI;AAClE,WAAO,KAAK,QAAQ,aAAa,KAAK,KAAK;AAAA,EAC7C;AAAA;AAAA,EAGU,iBAAiB,UAA+B;AAAA,EAAC;AAC7D;;;AKpaO,SAAS,gBAAgB,IAAwC;AACtE,SAAQ,GAA2C,kBAAkB;AACvE;AAMO,SAAS,gBAAgB,IAAgC;AAC9D,SAAO,GAAG,QAAQ,gBAAgB;AACpC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/base-element.ts","../src/css-loader.ts","../src/host-scope.ts","../src/prop-parser.ts","../src/reactive-adapter.ts","../src/visibility.ts","../src/host-bus.ts"],"sourcesContent":["import type { ReactiveAdapter } from './reactive-adapter.ts'\r\nimport type { WippyElementConfig } from './types.ts'\r\nimport { addCollection } from '@iconify/vue'\r\nimport { addIcons, applyThemeMode, define, config as hostConfig, host as wippyHost, on as wippyOn } from '@wippy-fe/proxy'\r\nimport { injectCustomCss, injectInlineCss, loadHostCss } from './css-loader.ts'\r\nimport { getWippyHost } from './host-scope.ts'\r\nimport { parseProps } from './prop-parser.ts'\r\nimport { ReactiveAdapterImpl } from './reactive-adapter.ts'\nimport { readWippyVisibility, WIPPY_VISIBILITY_ATTRIBUTE } from './visibility.ts'\n\r\n/**\r\n * Abstract base class for Wippy web components.\r\n *\r\n * Generic over `Props` — the parsed prop object type. This types `onMount`,\r\n * `onPropsChanged`, and `validateProps`. Defaults to `Record<string, unknown>`.\r\n *\r\n * Lifecycle order (first connect):\r\n * 1. shadow DOM attached\r\n * 2. `onInit(shadow)` — hook for early shadow DOM customization\r\n * 3. inline CSS injected\r\n * 4. host CSS loading started (async, non-blocking)\r\n * 5. container div created and appended\r\n * 6. icons registered\r\n * 7. props parsed from attributes + custom validation\r\n * 8. `onMount(shadow, container, props, errors)` — framework setup\r\n * 9. internals state → ready\r\n * 10. `onReady()` — post-mount hook\r\n * 11. `load` event emitted\r\n *\r\n * On reconnect (move-style DOM op: detach → reattach), the shadow root\r\n * persists across the cycle, so steps 1, 3, 4, 5 (CSS injection +\r\n * container creation) are skipped to avoid duplicating `<style>` and\r\n * container `<div>` siblings inside the persistent shadow. The stored\r\n * container is reused and `onMount` is re-invoked with `isRemount = true`\r\n * so framework adapters can decide between fresh-mount and remount paths.\r\n *\r\n * On error: `onError(error)` → internals state → error → `error` event\r\n * On disconnect: `onUnmount()` → `unload` event → internals cleared.\r\n * Note: `disconnectedCallback` does NOT clear the shadow root or the\r\n * stored container — they're reused on reconnect.\r\n */\r\nexport abstract class WippyElement<\r\n Props = Record<string, unknown>,\r\n Events = Record<string, unknown>,\r\n> extends HTMLElement {\r\n private _internals!: ElementInternals\r\n private _contentObserver: MutationObserver | null = null\r\n /** True after the first successful connectedCallback completes. */\r\n private _initialized: boolean = false\r\n /** Container div created on first connect; reused on subsequent connects. */\r\n private _container: HTMLElement | null = null\r\n /**\r\n * Opt-in reactive adapter. Lazy-allocated on first `this.reactive`\r\n * access, disposed on `disconnectedCallback`, re-allocated on next\r\n * access after reconnect. Subclasses that never touch `this.reactive`\r\n * pay zero allocation cost — `notifyProps`/`notifyContent` short-circuit\r\n * on the null guard.\r\n */\r\n private _reactive: ReactiveAdapterImpl<Props, Events> | null = null\r\n /**\r\n * Cached results of the most recent `parseProps` + `validateProps`\r\n * pass. Set by `connectedCallback` and `attributeChangedCallback`.\r\n * Read by `get reactive()` to avoid re-parsing on lazy allocation —\r\n * means `validateProps` only ever runs once per attribute change,\r\n * even for consumers that touch `this.reactive` inside `onMount`.\r\n */\r\n private _lastProps: Props | null = null\r\n private _lastErrors: readonly string[] = []\r\n private _lastContent: string | null = null\r\n /** Unsubscribe from host `@theme` broadcasts; set on connect, cleared on disconnect. */\r\n private _themeUnsub: (() => void) | null = null\n private _hostVisible: boolean | null = null\n\r\n /**\r\n * Phantom field to retain the `Events` type parameter so it shows up in\r\n * type errors / `Reflect.get` shape. Adapter typing reads it indirectly\r\n * via the generic.\r\n * @internal\r\n */\r\n declare readonly _events: Events\r\n\r\n /**\r\n * Override to provide the component's configuration.\r\n * Must be static because `observedAttributes` reads it before construction.\r\n *\r\n * Specify the generic to get typed `validateProps`:\r\n * ```ts\r\n * static get wippyConfig(): WippyElementConfig<MyProps> { ... }\r\n * ```\r\n */\r\n static get wippyConfig(): WippyElementConfig {\r\n return { propsSchema: { properties: {} } }\r\n }\r\n\r\n /**\r\n * Derived from the props schema + any `extraObservedAttributes`.\r\n */\r\n static get observedAttributes(): string[] {\n const config = this.wippyConfig\r\n const schemaAttrs = Object.keys(config.propsSchema.properties)\r\n const extra = config.extraObservedAttributes ?? []\r\n return [...new Set([...schemaAttrs, ...extra, WIPPY_VISIBILITY_ATTRIBUTE])]\n }\r\n\r\n constructor() {\n super()\n this._internals = this.attachInternals()\n this._hostVisible = readWippyVisibility(this)\n }\n\n /**\n * Host-owned logical activity. `null` means no host manages this element.\n * It is not CSS visibility or viewport intersection.\n */\n get hostVisible(): boolean | null {\n return this._hostVisible\n }\n\r\n /**\r\n * Panel-scoped `host` wrapper attached by the managed-layout shell's\r\n * content resolvers (`ComponentResolver` / `WebComponentPackageLoader`).\r\n *\r\n * Inside a managed-layout panel, this is a wrapper around the universal\r\n * `host` API where context-aware calls (`layout.broadcast / send / on`)\r\n * are routed through the panel-bound bus — so `sourcePanelId` is\r\n * attributed correctly without postMessage indirection. Layout\r\n * mutations and other host methods pass through unchanged.\r\n *\r\n * `null` outside a managed-layout context (compat shell, chat sidebar,\r\n * standalone playground). Subclass code that needs a host in those\r\n * cases can fall back to `import { host } from '@wippy-fe/proxy'`.\r\n */\r\n get host(): ReturnType<typeof getWippyHost> {\r\n return getWippyHost(this)\r\n }\r\n\r\n /**\r\n * Emit a CustomEvent that bubbles and crosses shadow DOM boundaries.\r\n */\r\n protected emitEvent(eventName: string, detail?: unknown): void {\r\n this.dispatchEvent(new CustomEvent(eventName, {\r\n bubbles: true,\r\n composed: true,\r\n detail,\r\n }))\r\n }\r\n\r\n /**\r\n * Opt-in reactive adapter — framework-agnostic. Subscribe to prop\r\n * changes, content changes, or emit typed events from a non-Vue\r\n * consumer without re-rolling reactivity.\r\n *\r\n * ```ts\r\n * class MyEl extends WippyElement<{ count: number }, { tick: { n: number } }> {\r\n * protected onMount() {\r\n * const ctrl = new AbortController()\r\n * this.reactive.props.subscribe(({ count }) => {\r\n * this.shadowRoot!.querySelector('.n')!.textContent = String(count)\r\n * }, { signal: ctrl.signal, immediate: true })\r\n * }\r\n * tick(n: number) { this.reactive.events.emit('tick', { n }) }\r\n * }\r\n * ```\r\n *\r\n * Allocation cost is zero unless this getter is touched. Disposed on\r\n * `disconnectedCallback`; a fresh adapter is allocated on the next\r\n * access after reconnect.\r\n */\r\n protected get reactive(): ReactiveAdapter<Props, Events> {\r\n if (!this._reactive) {\r\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const hasContent = !!config.contentTemplate\r\n // Reuse the cached parse result from the most recent\r\n // `connectedCallback` / `attributeChangedCallback` whenever we\r\n // have one; otherwise fall back to a fresh parse (this happens\r\n // when `reactive` is touched before the element is ever\r\n // connected — rare but legal).\r\n let props: Props\r\n let errors: readonly string[]\r\n if (this._lastProps !== null) {\r\n props = this._lastProps\r\n errors = this._lastErrors\r\n }\r\n else {\r\n const parsed = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n parsed.errors.push(...config.validateProps(parsed.props))\r\n }\r\n props = parsed.props as Props\r\n errors = parsed.errors\r\n this._lastProps = props\r\n this._lastErrors = errors\r\n }\r\n const content = hasContent\r\n ? (this._lastContent ?? this._extractContent(config.contentTemplate!))\r\n : null\r\n if (hasContent && this._lastContent === null)\r\n this._lastContent = content\r\n this._reactive = new ReactiveAdapterImpl<Props, Events>(\n { props, errors, content, hasContent, hostVisibility: this._hostVisible },\n this.emitEvent.bind(this),\r\n )\r\n }\r\n return this._reactive\r\n }\r\n\r\n // ── Lifecycle ──────────────────────────────────────────────\r\n\r\n connectedCallback(): void {\r\n this._internals.states.add('loading')\r\n try {\r\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const isRemount = this._initialized\r\n\r\n // 1. Shadow DOM (guard against reconnect — attachShadow throws if called twice)\r\n const shadow = this.shadowRoot ?? this.attachShadow({ mode: config.shadowMode ?? 'open' })\r\n\r\n let container: HTMLElement\r\n if (!isRemount) {\r\n // 2. Early hook — customize shadow before CSS/container\r\n this.onInit(shadow)\r\n\r\n // 3. Inline CSS\r\n if (config.inlineCss) {\r\n injectInlineCss(shadow, config.inlineCss)\r\n }\r\n\r\n // 3b. Facade custom CSS (opt-out via `customCss`). Compose the child scopes\r\n // the same way a view.page does — global then children — and inject the\r\n // selector rules into the shadow root (custom properties already inherit).\r\n // The proxy `config` getter throws host-less, so guard the read.\r\n if (config.customCss !== false) {\r\n try {\r\n const theming = hostConfig?.theming\r\n const facadeCss = [theming?.global?.customCSS, theming?.children?.customCSS]\r\n .filter(Boolean)\r\n .join('\\n')\r\n if (facadeCss)\r\n injectCustomCss(shadow, facadeCss)\r\n }\r\n catch { /* host-less / no proxy config — skip */ }\r\n }\r\n\r\n // 4. Host CSS (async, non-blocking)\r\n if (config.hostCssKeys === undefined || config.hostCssKeys.length > 0) {\r\n loadHostCss(shadow, config.hostCssKeys)\r\n }\r\n\r\n // 5. Container\r\n container = document.createElement('div')\r\n const classes = config.containerClasses ?? []\r\n if (classes.length > 0) {\r\n container.classList.add(...classes)\r\n }\r\n shadow.appendChild(container)\r\n this._container = container\r\n\r\n // 6. Icons\r\n addIcons(addCollection)\r\n }\r\n else {\r\n // Reconnect path — reuse the existing shadow children + container.\r\n // Skip CSS/icon/container setup so we don't accumulate duplicate\r\n // `<style>` and container `<div>` siblings on every detach/reattach.\r\n // The framework adapter decides whether to remount on the existing\r\n // container or recreate its app instance.\r\n container = this._container!\r\n }\r\n\r\n // Mirror the forced theme onto the shadow container AND this host element\r\n // so the WC's own theme rules respond — class selectors don't cross the\r\n // shadow boundary (the `--p-*` tokens inherit across it via custom\r\n // properties, so token colors already follow without this). The container\r\n // class is matched by Tailwind `dark:` utilities and `.w-theme-dark &`\r\n // rules (both need an IN-shadow ancestor); the host-element class lets\r\n // `:host(.w-theme-*)` / `:host(:not(.w-theme-light))` selectors (the SCSS\r\n // dark mixin's OS-dark auto branch) reflect the forced mode.\r\n this._applyTheme()\r\n if (!this._themeUnsub)\r\n this._themeUnsub = wippyOn('@theme', (mode: 'auto' | 'light' | 'dark') => this._applyTheme(mode))\r\n\r\n // 7. Parse initial props + custom validation\r\n const { props, errors } = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n errors.push(...config.validateProps(props))\r\n }\r\n const typedProps = props as Props\r\n // Cache so a lazy `get reactive()` call from inside `onMount`\r\n // doesn't re-parse / re-validate.\r\n this._lastProps = typedProps\r\n this._lastErrors = errors\r\n\r\n // 7b. Extract children content (if contentTemplate configured)\r\n let initialContent: string | null = null\r\n if (config.contentTemplate) {\r\n initialContent = this._extractContent(config.contentTemplate)\r\n this._lastContent = initialContent\r\n this._contentObserver = new MutationObserver(() => {\r\n const content = this._extractContent(config.contentTemplate!)\r\n this._lastContent = content\r\n // Fan out to the reactive adapter first so subclass overrides of\r\n // `onContentChanged` that read `this.reactive.content.value` see\r\n // the new value. No-op when the adapter hasn't been allocated.\r\n this._reactive?.notifyContent(content)\r\n this.onContentChanged(content)\r\n })\r\n this._contentObserver.observe(this, {\r\n childList: true,\r\n characterData: true,\r\n subtree: true,\r\n })\r\n }\r\n\r\n // 8. Framework mount (first time) or remount (reconnect)\r\n this.onMount(shadow, container, typedProps, errors, initialContent, isRemount)\r\n\r\n // 9. Ready\r\n this._internals.states.delete('loading')\r\n this._internals.states.add('ready')\r\n\r\n // First-connect bookkeeping after a clean mount.\r\n if (!isRemount) {\r\n this._initialized = true\r\n }\r\n\r\n // 10. Post-mount hook\r\n this.onReady()\r\n\r\n // 11. Emit load\r\n this.emitEvent('load')\r\n }\r\n catch (error) {\r\n this.onError(error)\r\n this._internals.states.delete('loading')\r\n this._internals.states.add('error')\r\n this.emitEvent('error', {\r\n message: error instanceof Error ? error.message : String(error),\r\n error,\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Applies a forced theme mode to this host element AND the shadow container.\r\n * The container class drives in-shadow selectors (Tailwind `dark:` utilities,\r\n * `.w-theme-dark &`); the host-element class drives `:host(.w-theme-*)`\r\n * selectors. On `@theme` broadcasts the resolved `mode` is passed in directly\r\n * (don't re-read `getThemeMode()` — the proxy's config-vs-emit order isn't a\r\n * contract); on the initial connect it defaults to the host's current mode.\r\n * No-op for an older proxy without `getThemeMode` — `applyThemeMode` clamps\r\n * `undefined` to 'auto'.\r\n */\r\n private _applyTheme(mode: Parameters<typeof applyThemeMode>[0] = wippyHost.getThemeMode?.()): void {\r\n applyThemeMode(mode, this)\r\n if (this._container)\r\n applyThemeMode(mode, this._container)\r\n }\r\n\r\n disconnectedCallback(): void {\r\n if (this._themeUnsub) {\r\n this._themeUnsub()\r\n this._themeUnsub = null\r\n }\r\n // Clear the mirrored theme off this host element + container so a parked or\r\n // re-inserted element doesn't carry a stale forced theme — which, via the\r\n // document-level `.w-theme-*` token rules, would otherwise inherit onto any\r\n // slotted light-DOM children. connectedCallback re-applies on reconnect.\r\n applyThemeMode('auto', this)\r\n if (this._container)\r\n applyThemeMode('auto', this._container)\r\n if (this._contentObserver) {\r\n this._contentObserver.disconnect()\r\n this._contentObserver = null\r\n }\r\n this.onUnmount()\r\n this.emitEvent('unload')\r\n this._internals.states.clear()\r\n // Drop the reactive adapter so subscribers from this attachment are\r\n // cleared and a fresh adapter is allocated on the next `this.reactive`\r\n // access (i.e. after reconnect).\r\n this._reactive?.dispose()\r\n this._reactive = null\r\n // Clear cached parse state — `connectedCallback` re-populates on\r\n // reconnect; before then, a lazy `get reactive()` access should\r\n // re-parse from current attributes (rare path).\r\n this._lastProps = null\r\n this._lastErrors = []\r\n this._lastContent = null\r\n // Drop panel-context wires so a detached element held by a\r\n // consumer (or re-inserted into a different panel) doesn't carry\r\n // stale wires that would silently misattribute. The resolver\r\n // re-installs them on the next mount.\r\n delete (this as unknown as { __wippyHost?: unknown }).__wippyHost\r\n delete (this as unknown as { __wippyHostBus?: unknown }).__wippyHostBus\r\n }\r\n\r\n attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void {\n if (oldVal === newVal)\n return\n if (name === WIPPY_VISIBILITY_ATTRIBUTE) {\n const previous = this._hostVisible\n const visible = readWippyVisibility(this)\n if (visible === previous)\n return\n this._hostVisible = visible\n // Visibility is host lifecycle, never a component prop. Keep it out of\n // parseProps / onPropsChanged so hosts can retain an element while\n // changing logical ownership without triggering prop side effects.\n // An initial host attribute is applied before connection so onMount can\n // read it, but it is not a lifecycle transition. Subscribers and hooks\n // begin only after this attachment has mounted successfully.\n if (this.isConnected && this._initialized) {\n this._reactive?.notifyHostVisibility(visible, previous)\n this.onHostVisibilityChanged(visible, previous)\n }\n return\n }\n const config = (this.constructor as typeof WippyElement).wippyConfig\r\n const { props, errors } = parseProps(this, config.propsSchema)\r\n if (config.validateProps) {\r\n errors.push(...config.validateProps(props))\r\n }\r\n const typedProps = props as Props\r\n this._lastProps = typedProps\r\n this._lastErrors = errors\r\n // Fan out to the reactive adapter BEFORE the legacy hook so subclasses\r\n // that override `onPropsChanged` AND read `this.reactive.props.value`\r\n // inside it see consistent state. No-op when the adapter hasn't been\r\n // lazy-allocated.\r\n this._reactive?.notifyProps(typedProps, errors)\r\n this.onPropsChanged(typedProps, errors)\r\n }\r\n\r\n // ── Hooks ──────────────────────────────────────────────────\r\n\r\n /** Called right after shadow DOM is attached, before CSS or container. */\r\n protected onInit(_shadow: ShadowRoot): void {}\r\n\r\n /**\r\n * Called after shadow DOM, CSS, and container are ready. Mount your\r\n * framework here.\r\n *\r\n * Invoked on first connect AND on every subsequent reconnect (move-style\r\n * DOM op: detach → reattach). On reconnect the same `container` instance\r\n * is reused. Adapters that hold a framework app handle should either\r\n * detect `isRemount === true` and re-mount on the existing container, or\r\n * leave the previous app intact across the detach/reattach cycle.\r\n */\r\n protected abstract onMount(\r\n shadow: ShadowRoot,\r\n container: HTMLElement,\r\n initialProps: Props,\r\n initialErrors: string[],\r\n initialContent?: string | null,\r\n isRemount?: boolean,\r\n ): void\r\n\r\n /** Called after internals state is set to ready, before the `load` event. */\r\n protected onReady(): void {}\r\n\r\n /** Called when connectedCallback throws. Default logs to console. */\r\n protected onError(error: unknown): void {\r\n console.error(`${this.constructor.name} initialization failed:`, error)\r\n }\r\n\r\n /** Called during disconnectedCallback — clean up framework resources. */\r\n protected abstract onUnmount(): void\r\n\r\n /** Called when observed attributes change. Override to update framework state. */\n protected onPropsChanged(_props: Props, _errors: string[]): void {}\n\n /**\n * Called when the host changes logical activity. `null` means unmanaged.\n * This does not imply a DOM remount or a CSS/viewport visibility change.\n */\n protected onHostVisibilityChanged(_visible: boolean | null, _previous: boolean | null): void {}\n\r\n /**\r\n * Extract text from a child `<template data-type=\"...\">` element.\r\n * Uses `.content.textContent` since `<template>` stores content in a DocumentFragment.\r\n */\r\n private _extractContent(dataType: string): string | null {\r\n const tpl = this.querySelector(`template[data-type=\"${dataType}\"]`) as HTMLTemplateElement | null\r\n return tpl?.content.textContent?.trim() ?? null\r\n }\r\n\r\n /** Called when child `<template>` content changes. Override to update framework state. */\r\n protected onContentChanged(_content: string | null): void {}\r\n}\r\n\r\nexport { define }\r\n","import type { HostCssKey } from './types.ts'\r\nimport { hostCss, loadCss } from '@wippy-fe/proxy'\r\n\r\nconst DEFAULT_HOST_CSS_KEYS: HostCssKey[] = [\r\n 'themeConfigUrl',\r\n 'primeVueCssUrl',\r\n 'markdownCssUrl',\r\n 'iframeCssUrl',\r\n]\r\n\r\n/**\r\n * Loads host CSS URLs into the shadow root as `<style>` elements.\r\n * Non-blocking — returns a promise but the component doesn't need to await it.\r\n */\r\nexport function loadHostCss(shadow: ShadowRoot, keys?: HostCssKey[]): Promise<void> {\r\n const cssKeys = keys ?? DEFAULT_HOST_CSS_KEYS\r\n // Filter out keys whose URL is missing (e.g. removed CSS like fontCssUrl).\r\n // Load each independently so one failure doesn't block the rest.\r\n const jobs = cssKeys.map(async (key) => {\r\n const url = hostCss[key]\r\n if (!url) {\r\n console.warn(`[wippy-fe/webcomponent-core] hostCss key \"${key}\" is undefined — skipping. Remove it from hostCssKeys if the CSS was removed.`)\r\n return null\r\n }\r\n try {\r\n return await loadCss(url)\r\n }\r\n catch (err) {\r\n console.warn(`[wippy-fe/webcomponent-core] Failed to load hostCss \"${key}\" (${url}):`, err)\r\n return null\r\n }\r\n })\r\n return Promise.all(jobs).then((cssChunks) => {\r\n for (const css of cssChunks) {\r\n if (!css)\r\n continue\r\n const style = document.createElement('style')\r\n style.textContent = css\r\n style.setAttribute('role', '@wippy-fe/host-css')\r\n shadow.appendChild(style)\r\n }\r\n })\r\n}\r\n\r\n/**\r\n * Injects inline CSS text into the shadow root.\r\n */\r\nexport function injectInlineCss(shadow: ShadowRoot, text: string): void {\r\n const style = document.createElement('style')\r\n style.textContent = text\r\n shadow.appendChild(style)\r\n}\r\n\r\n/**\r\n * Injects the host's facade custom CSS into the shadow root via an adopted\r\n * stylesheet, which cascades after the component's own `<style>`/`<link>` (and the\r\n * async `hostCssKeys` sheets) whenever they are added — so facade custom CSS wins,\r\n * matching the page pipeline. `@import` rules are dropped by adopted sheets, but the\r\n * font they load is already applied by the host document. Falls back to a trailing\r\n * `<style role=\"@wippy-fe/custom-css\">` where constructable stylesheets are\r\n * unavailable (e.g. jsdom).\r\n */\r\nexport function injectCustomCss(shadow: ShadowRoot, css: string): void {\r\n if (typeof CSSStyleSheet !== 'undefined' && 'replaceSync' in CSSStyleSheet.prototype) {\r\n const sheet = new CSSStyleSheet()\r\n sheet.replaceSync(css)\r\n shadow.adoptedStyleSheets = [...shadow.adoptedStyleSheets, sheet]\r\n return\r\n }\r\n const style = document.createElement('style')\r\n style.setAttribute('role', '@wippy-fe/custom-css')\r\n style.textContent = css\r\n shadow.appendChild(style)\r\n}\r\n","/**\n * Element-attached host wrapper reader for web components mounted as\n * `kind: 'component'` panels in the gen-2-chat managed-layout shell.\n *\n * The host stamps a panel-scoped wrapper as `__wippyHost` on each\n * element BEFORE it is appended to the DOM (see the host's\n * `panel-context-wires.ts` and `host-scope.ts`). Consumer web\n * components read it back via `getWippyHost(this)` in\n * `connectedCallback` and onwards.\n *\n * The wrapper is **constructed by the host** — this package only\n * exposes the reader. Outside a managed-layout host (raw mounts,\n * compat shells, tests without the connector) the property is absent\n * and `getWippyHost` returns `null`.\n */\n\n/**\n * Read the panel-scoped host wrapper attached to an element by the\n * managed-layout shell's content resolvers. Returns `null` outside a\n * managed-layout host (or before the element is connected).\n *\n * Subclass authors of `WippyElement` / `WippyVueElement` access this\n * via `this.host` / `useHost()` and rarely need to call this directly.\n * The helper is exposed for raw `HTMLElement` consumers.\n */\nexport function getWippyHost<H = unknown>(el: HTMLElement): H | null {\n return ((el as unknown) as { __wippyHost?: H }).__wippyHost ?? null\n}\n","import type { WippyPropDefinition, WippyPropsSchema } from './types.ts'\r\n\r\nexport interface ParseResult {\r\n props: Record<string, unknown>\r\n errors: string[]\r\n}\r\n\r\n/**\r\n * Converts a kebab-case attribute name to camelCase.\r\n * `allowed-types` → `allowedTypes`\r\n */\r\nexport function attrToCamel(attr: string): string {\r\n return attr.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\r\n}\r\n\r\n/**\r\n * Parses a single attribute value according to its schema definition.\r\n */\r\nfunction parseValue(attr: string, raw: string, def: WippyPropDefinition): { value: unknown, error?: string } {\r\n switch (def.type) {\r\n case 'string':\r\n return { value: raw }\r\n\r\n case 'number': {\r\n const n = Number.parseFloat(raw)\r\n if (Number.isNaN(n))\r\n return { value: undefined, error: `Invalid ${attr}: expected a number` }\r\n return { value: n }\r\n }\r\n\r\n case 'integer': {\r\n const n = Number.parseInt(raw, 10)\r\n if (Number.isNaN(n))\r\n return { value: undefined, error: `Invalid ${attr}: expected an integer` }\r\n return { value: n }\r\n }\r\n\r\n case 'boolean':\r\n // Presence of the attribute means true (HTML convention), explicit \"false\" means false\r\n return { value: raw !== 'false' }\r\n\r\n case 'array':\r\n case 'object': {\r\n try {\r\n const parsed = JSON.parse(raw)\r\n if (def.type === 'array' && !Array.isArray(parsed)) {\r\n return { value: undefined, error: `Invalid ${attr}: expected a JSON array` }\r\n }\r\n return { value: parsed }\r\n }\r\n catch {\r\n return { value: undefined, error: `Invalid ${attr}: must be valid JSON` }\r\n }\r\n }\r\n\r\n default:\r\n return { value: raw }\r\n }\r\n}\r\n\r\n/**\r\n * Parses all attributes on an element according to its props schema.\r\n * Returns `{ props, errors }` where errors is an array of human-readable messages.\r\n */\r\nexport function parseProps(element: HTMLElement, schema: WippyPropsSchema): ParseResult {\r\n const props: Record<string, unknown> = {}\r\n const errors: string[] = []\r\n\r\n for (const [attr, def] of Object.entries(schema.properties)) {\r\n const raw = element.getAttribute(attr)\r\n const camel = attrToCamel(attr)\r\n\r\n if (raw === null) {\r\n // Attribute not set — use default if available\r\n if (def.default !== undefined) {\r\n props[camel] = def.default\r\n }\r\n continue\r\n }\r\n\r\n const result = parseValue(attr, raw, def)\r\n if (result.error) {\r\n errors.push(result.error)\r\n }\r\n else {\r\n props[camel] = result.value\r\n }\r\n }\r\n\r\n return { props, errors }\r\n}\r\n","/**\n * Opt-in reactive adapter for `WippyElement`.\n *\n * Framework-agnostic primitive that lets non-Vue consumers subscribe to\n * prop / content updates and emit typed events on a web component without\n * pulling Vue (or any other reactivity library) into the core bundle.\n *\n * Access via `this.reactive` on a `WippyElement` subclass — the getter is\n * lazy, so subclasses that never touch it pay zero allocation cost. See\n * `base-element.ts:get reactive` for the bridge into the lifecycle.\n *\n * The `notifyProps` / `notifyContent` methods are package-visible: the\n * base element calls them from `attributeChangedCallback` and the content\n * MutationObserver callback respectively. They are NOT part of the public\n * API consumers should reach for.\n *\n * Cleanup: `dispose()` runs from `disconnectedCallback`. All listener\n * sets are cleared; subsequent notifyProps/notifyContent are no-ops; the\n * `events.emit` becomes a no-op too. A fresh adapter is allocated on the\n * next `this.reactive` access (i.e. after reconnect).\n */\n\nexport type PropsListener<Props> = (props: Props, errors: readonly string[]) => void\nexport type ContentListener = (content: string | null) => void\nexport type HostVisibilityListener = (visible: boolean | null, previous: boolean | null) => void\n\nexport interface SubscribeOptions {\n /** Cancel the subscription when the signal aborts. */\n signal?: AbortSignal\n /** Fire the listener once synchronously with the current value. */\n immediate?: boolean\n}\n\nexport interface PropsSubscription<Props> {\n /** Current parsed props. Always reflects the latest state. */\n readonly value: Props\n /** Current validation/parse errors. */\n readonly errors: readonly string[]\n /**\n * Register a listener that fires whenever props change. Returns an\n * unsubscribe function. Pass `options.signal` for AbortSignal-driven\n * cleanup (e.g. tied to an element's lifetime). Pass\n * `options.immediate: true` to fire once synchronously with the current\n * value — useful when the subscriber is set up mid-flight.\n *\n * Note: `notifyProps` runs BEFORE the subclass `onPropsChanged()` hook.\n * A subscriber added from inside `onPropsChanged()` therefore does NOT\n * receive the currently-firing change — only the next one. Use\n * `{ immediate: true }` to also see the current value.\n */\n subscribe: (listener: PropsListener<Props>, options?: SubscribeOptions) => () => void\n}\n\nexport interface ContentSubscription {\n /** Current `<template>` content text, or `null` if not set. */\n readonly value: string | null\n /** See `PropsSubscription.subscribe` for the same ordering caveat. */\n subscribe: (listener: ContentListener, options?: SubscribeOptions) => () => void\n}\n\n/** Host-owned logical activity. `null` means the element is unmanaged. */\nexport interface HostVisibilitySubscription {\n readonly value: boolean | null\n subscribe: (listener: HostVisibilityListener, options?: SubscribeOptions) => () => void\n}\n\nexport interface EventEmitterHandle<Events> {\n /**\n * Dispatch a typed `CustomEvent` (bubbles + composed, identical\n * semantics to the protected `emitEvent` helper). The key is constrained\n * to `keyof Events & string`, so consumers narrow `Events` to get\n * autocomplete + payload-type checks.\n *\n * No-op after the adapter is disposed (i.e. after the element is\n * detached). The element is the only event target — subscribers on\n * the element itself receive the event.\n */\n emit: <K extends keyof Events & string>(event: K, detail: Events[K]) => void\n}\n\nexport interface ReactiveAdapter<Props, Events> {\n props: PropsSubscription<Props>\n events: EventEmitterHandle<Events>\n hostVisibility: HostVisibilitySubscription\n /**\n * Present only when the element's `wippyConfig.contentTemplate` is set;\n * `null` otherwise. Avoids fake `.value === null` semantics for elements\n * that don't track children content.\n */\n content: ContentSubscription | null\n}\n\n/**\n * Concrete implementation used by `WippyElement`. The `notify*` methods\n * are intentionally exposed (not private) so the base-element can call\n * them; consumers should never reach for them.\n *\n * @internal\n */\nexport class ReactiveAdapterImpl<Props, Events> implements ReactiveAdapter<Props, Events> {\n private _props: Props\n private _errors: readonly string[]\n private _content: string | null\n private _hostVisibility: boolean | null\n private _propsListeners = new Set<PropsListener<Props>>()\n private _contentListeners = new Set<ContentListener>()\n private _hostVisibilityListeners = new Set<HostVisibilityListener>()\n private _disposed = false\n private _emitToDom: (eventName: string, detail?: unknown) => void\n\n readonly props: PropsSubscription<Props>\n readonly events: EventEmitterHandle<Events>\n readonly content: ContentSubscription | null\n readonly hostVisibility: HostVisibilitySubscription\n\n constructor(\n initial: {\n props: Props\n errors: readonly string[]\n content: string | null\n hasContent: boolean\n hostVisibility: boolean | null\n },\n emitToDom: (eventName: string, detail?: unknown) => void,\n ) {\n this._props = initial.props\n this._errors = initial.errors\n this._content = initial.content\n this._hostVisibility = initial.hostVisibility\n this._emitToDom = emitToDom\n\n // Each getter / closure below runs with the surrounding object literal\n // as `this`, not the class instance — so we have to capture the\n // instance explicitly here.\n // eslint-disable-next-line ts/no-this-alias\n const self = this\n\n this.props = {\n get value() {\n return self._props\n },\n get errors() {\n return self._errors\n },\n subscribe(listener, options) {\n return self._subscribeProps(listener, options)\n },\n }\n\n this.events = {\n emit(event, detail) {\n if (self._disposed)\n return\n self._emitToDom(event as string, detail)\n },\n }\n\n this.content = initial.hasContent\n ? {\n get value() {\n return self._content\n },\n subscribe(listener, options) {\n return self._subscribeContent(listener, options)\n },\n }\n : null\n\n this.hostVisibility = {\n get value() {\n return self._hostVisibility\n },\n subscribe(listener, options) {\n return self._subscribeHostVisibility(listener, options)\n },\n }\n }\n\n /** @internal */\n notifyProps(props: Props, errors: readonly string[]): void {\n if (this._disposed)\n return\n this._props = props\n this._errors = errors\n for (const listener of this._propsListeners)\n listener(props, errors)\n }\n\n /** @internal */\n notifyContent(content: string | null): void {\n if (this._disposed)\n return\n this._content = content\n for (const listener of this._contentListeners)\n listener(content)\n }\n\n /** @internal */\n notifyHostVisibility(visible: boolean | null, previous: boolean | null): void {\n if (this._disposed || visible === previous)\n return\n this._hostVisibility = visible\n for (const listener of this._hostVisibilityListeners)\n listener(visible, previous)\n }\n\n /** @internal */\n dispose(): void {\n if (this._disposed)\n return\n this._disposed = true\n this._propsListeners.clear()\n this._contentListeners.clear()\n this._hostVisibilityListeners.clear()\n }\n\n private _subscribeProps(listener: PropsListener<Props>, options?: SubscribeOptions): () => void {\n if (this._disposed || options?.signal?.aborted)\n return () => {}\n // Add to the set BEFORE firing `immediate` so a re-entrant\n // `notifyProps` triggered from inside the immediate callback can\n // find this listener and fire it for the synchronous change too.\n this._propsListeners.add(listener)\n if (options?.immediate)\n listener(this._props, this._errors)\n const unsub = () => {\n this._propsListeners.delete(listener)\n // Manual unsub must also detach the abort listener — otherwise it\n // accumulates on long-lived signals (e.g. an AbortController kept\n // around for the element's whole lifetime that fans out to many\n // subscriptions). `{ once: true }` only auto-removes when 'abort'\n // actually fires.\n options?.signal?.removeEventListener('abort', unsub)\n }\n options?.signal?.addEventListener('abort', unsub, { once: true })\n return unsub\n }\n\n private _subscribeContent(listener: ContentListener, options?: SubscribeOptions): () => void {\n if (this._disposed || options?.signal?.aborted)\n return () => {}\n this._contentListeners.add(listener)\n if (options?.immediate)\n listener(this._content)\n const unsub = () => {\n this._contentListeners.delete(listener)\n options?.signal?.removeEventListener('abort', unsub)\n }\n options?.signal?.addEventListener('abort', unsub, { once: true })\n return unsub\n }\n\n private _subscribeHostVisibility(listener: HostVisibilityListener, options?: SubscribeOptions): () => void {\n if (this._disposed || options?.signal?.aborted)\n return () => {}\n this._hostVisibilityListeners.add(listener)\n if (options?.immediate)\n listener(this._hostVisibility, this._hostVisibility)\n const unsub = () => {\n this._hostVisibilityListeners.delete(listener)\n options?.signal?.removeEventListener('abort', unsub)\n }\n options?.signal?.addEventListener('abort', unsub, { once: true })\n return unsub\n }\n}\n","export { readWippyVisibility, setWippyVisibility, WIPPY_VISIBILITY_ATTRIBUTE } from '@wippy-fe/shared'\n","/**\n * Layout bus types shared between `@wippy-fe/webcomponent-core` and\n * `@wippy-fe/webcomponent-vue`. Mirror of the host-side\n * `LayoutBusBound` / `BroadcastEnvelope` shapes; structurally\n * compatible so a host-mounted web component can read its\n * `__wippyHostBus` property without importing host-private types.\n *\n * The host (gen-2-chat managed-layout shell) sets:\n * - `el.dataset.wippyPanelId` (string)\n * - `(el as { __wippyHostBus?: LayoutBusBound }).__wippyHostBus`\n * BEFORE the element is appended to the DOM. Web components see them\n * on first `connectedCallback` tick.\n *\n * Outside a managed-layout host, both are absent — read code MUST\n * tolerate `undefined`.\n *\n * The interface bodies live in `@wippy-fe/shared` so the host can\n * import them without dragging in this package's `@wippy-fe/proxy`\n * runtime dependency. Consumers continue to import from\n * `@wippy-fe/webcomponent-core` (this re-export) for backward compat.\n */\n\nimport type { LayoutBusBound } from '@wippy-fe/shared'\n\nexport type { BroadcastEnvelope, LayoutBusBound } from '@wippy-fe/shared'\n\n/**\n * Read the host bus attached to an element by `ComponentResolver` in\n * the managed-layout host. Returns `null` outside a managed-layout\n * host (or before the element is connected). Stable across element\n * remounts of the same panel — the resolver re-attaches a fresh bus\n * each time.\n */\nexport function getWippyHostBus(el: HTMLElement): LayoutBusBound | null {\n return (el as { __wippyHostBus?: LayoutBusBound }).__wippyHostBus ?? null\n}\n\n/**\n * Read the panelId attribute set by `ComponentResolver`. `null`\n * outside a managed-layout host.\n */\nexport function getWippyPanelId(el: HTMLElement): string | null {\n return el.dataset.wippyPanelId ?? null\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wippy-fe/webcomponent-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.52",
|
|
4
4
|
"description": "Framework-agnostic base class for Wippy web components - shadow DOM, CSS loading, schema-driven prop parsing, and lifecycle management.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -17,12 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"package.json",
|
|
20
|
+
"README.md",
|
|
20
21
|
"dist/"
|
|
21
22
|
],
|
|
22
23
|
"peerDependencies": {
|
|
24
|
+
"@wippy-fe/proxy": ">=0.0.49 <0.0.53",
|
|
23
25
|
"@iconify/vue": "^5.0.0",
|
|
24
|
-
"@wippy-fe/shared": "^0.0.
|
|
25
|
-
"@wippy-fe/proxy": "^0.0.50"
|
|
26
|
+
"@wippy-fe/shared": "^0.0.52"
|
|
26
27
|
},
|
|
27
28
|
"scripts": {
|
|
28
29
|
"build": "tsup",
|