@sigx/lynx-runtime-main 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,111 @@
1
+ /**
2
+ * MT-side per-slot event registration state machine.
3
+ *
4
+ * Lynx native's `__AddEvent(el, eventType, eventName, value)` only stores ONE
5
+ * value per `(el, eventType, eventName)` slot — the second call wins. When
6
+ * sigx user code declares both a `main-thread-bind*` worklet AND a regular
7
+ * `bind*` BG handler on the same element, two ops arrive in the same patch
8
+ * batch (SET_WORKLET_EVENT + SET_EVENT). Calling `__AddEvent` eagerly per op
9
+ * means the second one silently overwrites the first.
10
+ *
11
+ * This module defers the `__AddEvent` call. Each op updates per-slot state
12
+ * (`worklet?`, `bgSign?`) and marks the slot dirty. After the entire op
13
+ * batch is processed (`flushDirtySlots` is called at the tail of `applyOps`),
14
+ * we issue ONE `__AddEvent` per dirty slot using whichever shape combines
15
+ * the present handlers — string sign, worklet ctx, or hybrid ctx.
16
+ *
17
+ * State persists across batches because re-renders may update only one of
18
+ * the two handlers (the BG event-registry already deduplicates SET_EVENT
19
+ * after the first registration, and `sentWorklets` deduplicates
20
+ * SET_WORKLET_EVENT by `_wkltId`).
21
+ */
22
+ import { elements } from './element-registry.js';
23
+ import { hybridCtx } from './hybrid-worklet.js';
24
+ /** elementId → typeName ('bindEvent:tap' etc.) → slot state */
25
+ const slotStates = new Map();
26
+ /** Set of `${elementId}|${typeName}` keys that need __AddEvent re-issuing. */
27
+ const dirtySlots = new Set();
28
+ function getOrCreateSlot(elId, type, name) {
29
+ let perEl = slotStates.get(elId);
30
+ if (!perEl) {
31
+ perEl = new Map();
32
+ slotStates.set(elId, perEl);
33
+ }
34
+ const typeName = `${type}:${name}`;
35
+ let slot = perEl.get(typeName);
36
+ if (!slot) {
37
+ slot = {};
38
+ perEl.set(typeName, slot);
39
+ }
40
+ return slot;
41
+ }
42
+ function markDirty(elId, type, name) {
43
+ dirtySlots.add(`${elId}|${type}:${name}`);
44
+ }
45
+ export function setSlotWorklet(elId, type, name, ctx) {
46
+ const slot = getOrCreateSlot(elId, type, name);
47
+ slot.worklet = ctx;
48
+ markDirty(elId, type, name);
49
+ }
50
+ export function setSlotBgSign(elId, type, name, sign) {
51
+ const slot = getOrCreateSlot(elId, type, name);
52
+ slot.bgSign = sign;
53
+ markDirty(elId, type, name);
54
+ }
55
+ /**
56
+ * Pick the right __AddEvent value given which handlers are present.
57
+ * Returns `undefined` to mean "unregister this slot".
58
+ */
59
+ function computeAddEventValue(slot) {
60
+ const { worklet, bgSign } = slot;
61
+ if (!worklet && !bgSign)
62
+ return undefined;
63
+ if (worklet && !bgSign) {
64
+ return { type: 'worklet', value: worklet };
65
+ }
66
+ if (!worklet && bgSign) {
67
+ return bgSign;
68
+ }
69
+ return { type: 'worklet', value: hybridCtx(worklet, bgSign) };
70
+ }
71
+ /**
72
+ * Commit __AddEvent for every slot that changed since the last flush.
73
+ * Called from `applyOps` after the op loop, before `__FlushElementTree()`.
74
+ */
75
+ export function flushDirtySlots() {
76
+ for (const key of dirtySlots) {
77
+ const sep = key.indexOf('|');
78
+ const elId = Number(key.slice(0, sep));
79
+ const typeName = key.slice(sep + 1);
80
+ const colon = typeName.indexOf(':');
81
+ const type = typeName.slice(0, colon);
82
+ const name = typeName.slice(colon + 1);
83
+ const el = elements.get(elId);
84
+ if (!el)
85
+ continue;
86
+ const slot = slotStates.get(elId)?.get(typeName);
87
+ if (!slot)
88
+ continue;
89
+ const value = computeAddEventValue(slot);
90
+ if (sameRef(value, slot.installed))
91
+ continue;
92
+ // Lynx PAPI: undefined as the 4th arg unregisters.
93
+ __AddEvent(el, type, name, value);
94
+ slot.installed = value;
95
+ }
96
+ dirtySlots.clear();
97
+ }
98
+ function sameRef(a, b) {
99
+ // Reference equality is enough for our usage:
100
+ // - undefined === undefined
101
+ // - bgSign string deduplicated by event-registry, so identity stable
102
+ // - worklet ctx is a fresh object per SET_WORKLET_EVENT op (never compared
103
+ // to itself across batches because the prev value would always differ),
104
+ // so this is mostly a defensive no-op for the first three branches.
105
+ return a === b;
106
+ }
107
+ /** Hot-reload / test reset hook — clears all slot state. */
108
+ export function resetSlotStates() {
109
+ slotStates.clear();
110
+ dirtySlots.clear();
111
+ }
@@ -13,7 +13,7 @@
13
13
  * just invokes it, then bridges to BG via the `Lynx.Sigx.PublishEvent`
14
14
  * channel that `bg-bridge.ts` listens on.
15
15
  */
16
- import type { WorkletPlaceholder } from './worklet-events';
16
+ import type { WorkletPlaceholder } from './worklet-events.js';
17
17
  export declare const HYBRID_WORKLET_ID = "__sigx_hybrid_dispatch__";
18
18
  /**
19
19
  * Install the hybrid worklet into upstream's worklet map. Must be called
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Hybrid worklet — combines a user worklet handler and a BG-side handler
3
+ * into a single registration that fits Lynx's one-handler-per-slot rule.
4
+ *
5
+ * Registered ONCE at MT init under the stable id `__sigx_hybrid_dispatch__`
6
+ * in upstream's `lynxWorkletImpl._workletMap`. When the slot machine sees a
7
+ * slot with both a worklet and a BG sign, it asks `hybridCtx(worklet, sign)`
8
+ * for the ctx to hand to `__AddEvent({ type: 'worklet', value })`.
9
+ *
10
+ * Lynx native dispatches via `runWorklet` → upstream's `transformWorklet`
11
+ * walks the ctx and `_c`. It detects nested `_wkltId` (our `realCtx`) and
12
+ * replaces it with the bound user-worklet callable. Our hybrid body then
13
+ * just invokes it, then bridges to BG via the `Lynx.Sigx.PublishEvent`
14
+ * channel that `bg-bridge.ts` listens on.
15
+ */
16
+ export const HYBRID_WORKLET_ID = '__sigx_hybrid_dispatch__';
17
+ function hybridDispatch(event) {
18
+ if (this._c.realCtx) {
19
+ try {
20
+ this._c.realCtx(event);
21
+ }
22
+ catch (e) {
23
+ console.log('[sigx-mt] hybrid worklet body threw:', String(e));
24
+ }
25
+ }
26
+ if (this._c.bgSign)
27
+ bridgeToBg(this._c.bgSign, event);
28
+ }
29
+ function bridgeToBg(sign, event) {
30
+ const lynxObj = globalThis.lynx;
31
+ if (!lynxObj) {
32
+ console.log('[sigx-mt] bridgeToBg: globalThis.lynx is undefined');
33
+ return;
34
+ }
35
+ const ctx = lynxObj.getJSContext?.();
36
+ if (!ctx) {
37
+ console.log('[sigx-mt] bridgeToBg: lynx.getJSContext() returned', typeof ctx);
38
+ return;
39
+ }
40
+ if (!ctx.dispatchEvent) {
41
+ console.log('[sigx-mt] bridgeToBg: jsContext has no dispatchEvent', Object.keys(ctx).join(','));
42
+ return;
43
+ }
44
+ let data;
45
+ try {
46
+ data = JSON.stringify({ sign, event });
47
+ }
48
+ catch (e) {
49
+ console.log('[sigx-mt] bridgeToBg: JSON.stringify failed', String(e));
50
+ return;
51
+ }
52
+ console.log('[sigx-mt] bridgeToBg: dispatching to BG, sign=', sign);
53
+ ctx.dispatchEvent({ type: 'Lynx.Sigx.PublishEvent', data });
54
+ }
55
+ /**
56
+ * Install the hybrid worklet into upstream's worklet map. Must be called
57
+ * AFTER the @lynx-js/react/worklet-runtime IIFE has populated
58
+ * globalThis.lynxWorkletImpl. Idempotent — safe to call across hot reloads.
59
+ */
60
+ export function installHybridWorklet() {
61
+ const impl = globalThis
62
+ .lynxWorkletImpl;
63
+ if (impl)
64
+ impl._workletMap[HYBRID_WORKLET_ID] = hybridDispatch;
65
+ }
66
+ /** Build the ctx for a hybrid registration. */
67
+ export function hybridCtx(realCtx, bgSign) {
68
+ return {
69
+ _wkltId: HYBRID_WORKLET_ID,
70
+ _workletType: 'main-thread',
71
+ _c: { realCtx, bgSign },
72
+ };
73
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import './entry-main';
2
- export { elements, pageUniqueId, setPageUniqueId } from './element-registry';
3
- export { applyOps, resetMainThreadState } from './ops-apply';
4
- export { MTElementWrapper } from './mt-element';
5
- export { invokeWorklet, type WorkletPlaceholder } from './worklet-events';
6
- export { setSlotWorklet, setSlotBgSign, flushDirtySlots, resetSlotStates, } from './event-slots';
7
- export { HYBRID_WORKLET_ID, hybridCtx, installHybridWorklet, } from './hybrid-worklet';
1
+ import './entry-main.js';
2
+ export { elements, pageUniqueId, setPageUniqueId } from './element-registry.js';
3
+ export { applyOps, resetMainThreadState } from './ops-apply.js';
4
+ export { MTElementWrapper } from './mt-element.js';
5
+ export { invokeWorklet, type WorkletPlaceholder } from './worklet-events.js';
6
+ export { setSlotWorklet, setSlotBgSign, flushDirtySlots, resetSlotStates, } from './event-slots.js';
7
+ export { HYBRID_WORKLET_ID, hybridCtx, installHybridWorklet, } from './hybrid-worklet.js';
8
8
  /**
9
9
  * Compatibility shim — upstream's worklet-runtime provides the canonical
10
10
  * `loadWorkletRuntime`, but @lynx-js/react/transform's LEPUS output imports
package/dist/index.js CHANGED
@@ -1,64 +1,23 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "./entry-main-CBM2DHsU.js";
2
- import { n as u, r as d, t as f } from "./hybrid-worklet-nTcCh-mA.js";
3
- //#region src/mt-element.ts
4
- var p = !1, m = class e {
5
- _el;
6
- constructor(e) {
7
- this._el = e;
8
- }
9
- flushElementTree() {
10
- p || (p = !0, Promise.resolve().then(() => {
11
- p = !1, __FlushElementTree();
12
- }));
13
- }
14
- setStyleProperties(e) {
15
- __SetInlineStyles(this._el, e), this.flushElementTree();
16
- }
17
- getComputedStyleProperty(e) {
18
- return typeof __GetComputedStyleByKey == "function" ? __GetComputedStyleByKey(this._el, e) : "";
19
- }
20
- getAttribute(e) {
21
- if (typeof __GetAttributeByName == "function") return __GetAttributeByName(this._el, e);
22
- }
23
- getAttributeNames() {
24
- return typeof __GetAttributeNames == "function" ? __GetAttributeNames(this._el) : [];
25
- }
26
- querySelector(t) {
27
- if (typeof __QuerySelector != "function") return null;
28
- let n = __QuerySelector(this._el, t, {});
29
- return n ? new e(n) : null;
30
- }
31
- querySelectorAll(t) {
32
- return typeof __QuerySelectorAll == "function" ? __QuerySelectorAll(this._el, t, {}).map((t) => new e(t)) : [];
33
- }
34
- invoke(e, t) {
35
- return new Promise((n, r) => {
36
- if (typeof __InvokeUIMethod != "function") {
37
- r(/* @__PURE__ */ Error("UI method invoke: __InvokeUIMethod not available"));
38
- return;
39
- }
40
- __InvokeUIMethod(this._el, e, t ?? {}, (e) => {
41
- e.code === 0 ? n(e.data) : r(/* @__PURE__ */ Error("UI method invoke: " + JSON.stringify(e)));
42
- }), this.flushElementTree();
43
- });
44
- }
45
- animate(e, t = {}) {
46
- let n = this._el;
47
- return typeof n.animate == "function" ? n.animate(e, t) : null;
48
- }
49
- setAttribute(e, t) {
50
- __SetAttribute(this._el, e, t), this.flushElementTree();
51
- }
52
- setStyleProperty(e, t) {
53
- __AddInlineStyle(this._el, e, t), this.flushElementTree();
54
- }
55
- };
56
- //#endregion
57
- //#region src/index.ts
58
- function h(e) {
59
- return !0;
1
+ /// <reference path="./shims.d.ts" />
2
+ // Side-effect import entry-main.ts registers globalThis.renderPage /
3
+ // processData / sigxPatchUpdate / sigxRunOnMT and side-effect imports
4
+ // @lynx-js/react/worklet-runtime which installs lynxWorkletImpl /
5
+ // registerWorkletInternal / runWorklet. Must run at module load time so
6
+ // the main-thread entry of the Lynx template has these globals.
7
+ import './entry-main.js';
8
+ export { elements, pageUniqueId, setPageUniqueId } from './element-registry.js';
9
+ export { applyOps, resetMainThreadState } from './ops-apply.js';
10
+ export { MTElementWrapper } from './mt-element.js';
11
+ export { invokeWorklet } from './worklet-events.js';
12
+ export { setSlotWorklet, setSlotBgSign, flushDirtySlots, resetSlotStates, } from './event-slots.js';
13
+ export { HYBRID_WORKLET_ID, hybridCtx, installHybridWorklet, } from './hybrid-worklet.js';
14
+ /**
15
+ * Compatibility shim — upstream's worklet-runtime provides the canonical
16
+ * `loadWorkletRuntime`, but @lynx-js/react/transform's LEPUS output imports
17
+ * it from `runtimePkg`. Our MT loader strips the import + gating before
18
+ * shipping registrations, so this re-export is only for the rare case where
19
+ * upstream's raw output is used unstripped (tests, future Phase 1c).
20
+ */
21
+ export function loadWorkletRuntime(_globDynamicComponentEntry) {
22
+ return true;
60
23
  }
61
- //#endregion
62
- export { f as HYBRID_WORKLET_ID, m as MTElementWrapper, c as applyOps, t as elements, o as flushDirtySlots, u as hybridCtx, d as installHybridWorklet, s as invokeWorklet, h as loadWorkletRuntime, r as pageUniqueId, i as resetMainThreadState, n as resetSlotStates, l as setPageUniqueId, e as setSlotBgSign, a as setSlotWorklet };
63
-
64
- //# sourceMappingURL=index.js.map
@@ -1,6 +1,19 @@
1
- import { r as e } from "./hybrid-worklet-nTcCh-mA.js";
2
- //#region src/install-hybrid-worklet.ts
3
- e();
4
- //#endregion
5
-
6
- //# sourceMappingURL=install-hybrid-worklet.js.map
1
+ /**
2
+ * Side-effect module that installs the hybrid worklet into upstream's
3
+ * `lynxWorkletImpl._workletMap`.
4
+ *
5
+ * Must be loaded AFTER `@lynx-js/react/worklet-runtime` (which populates
6
+ * `lynxWorkletImpl`) but BEFORE user code runs. The MT bootstrap preamble
7
+ * in `lynx-plugin/src/loaders/worklet-loader-mt.ts` lists it third in the
8
+ * import order:
9
+ *
10
+ * 1. @sigx/lynx-runtime-main/entry-main (sets SystemInfo + globals)
11
+ * 2. @lynx-js/react/worklet-runtime (installs lynxWorkletImpl)
12
+ * 3. @sigx/lynx-runtime-main/install-hybrid (this file)
13
+ * 4. user code (calls registerWorkletInternal)
14
+ *
15
+ * Splitting this out is necessary because vite would otherwise hoist any
16
+ * bare `import` statement above whatever sets up its prerequisites.
17
+ */
18
+ import { installHybridWorklet } from './hybrid-worklet.js';
19
+ installHybridWorklet();
@@ -0,0 +1,203 @@
1
+ /**
2
+ * MainThread element wrapper — provides a high-level API over raw PAPI
3
+ * element handles for use in main-thread event handlers.
4
+ *
5
+ * When a MainThreadRef's `.current` is set, it receives one of these
6
+ * wrappers so user code can call:
7
+ * - setStyleProperties({ transform: '...' })
8
+ * - getComputedStyleProperty('width')
9
+ * - animate(keyframes, options)
10
+ *
11
+ * These methods call Lynx PAPI directly on the main thread — no cross-thread
12
+ * round-trip, enabling zero-latency UI updates.
13
+ */
14
+ // ---------------------------------------------------------------------------
15
+ // MTElementWrapper
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Module-level latch that microtask-debounces `__FlushElementTree()` across
19
+ * every MTElementWrapper write within a single microtask. Mirrors the
20
+ * pattern in upstream `@lynx-js/react`'s `Element` class
21
+ * (`runtime/lib/worklet-runtime/api/element.js`):
22
+ *
23
+ * - First write in a microtask: schedule one Promise-microtask to flush.
24
+ * - Subsequent writes (same wrapper or any other) before the microtask
25
+ * fires: no-op (`willFlush` is already `true`).
26
+ * - Microtask runs: clear the latch, call the (animated-bridge-wrapped)
27
+ * `__FlushElementTree()` exactly once.
28
+ *
29
+ * Why the latch is module-level, not per-instance: a single tick often
30
+ * touches multiple element wrappers (e.g. `<Draggable>` writes its own
31
+ * transform AND issues `scrollBy` on the parent `<scroll-view>`). Two
32
+ * wrappers, two writes, but the native flush is a tree-wide operation —
33
+ * coalescing them into one is the whole point.
34
+ *
35
+ * Without this debounce, each of `setStyleProperties` / `setStyleProperty`
36
+ * / `setAttribute` / `invoke` was firing a synchronous
37
+ * `__FlushElementTree()`, paying the full layout pass per-call. The
38
+ * stutter showed up most obviously in the `<Draggable edgeScroll>` rAF
39
+ * tick (one transform write + one scrollBy invoke = 2 flushes/frame).
40
+ */
41
+ let willFlush = false;
42
+ export class MTElementWrapper {
43
+ /** The raw PAPI element handle. */
44
+ _el;
45
+ constructor(el) {
46
+ this._el = el;
47
+ }
48
+ /**
49
+ * Coalesce multiple element writes into a single `__FlushElementTree()`
50
+ * call at the end of the current microtask. See `willFlush` doc for the
51
+ * full rationale; mirrors `Element.flushElementTree` in upstream
52
+ * `@lynx-js/react`.
53
+ *
54
+ * `__FlushElementTree` itself is wrapped by `animated-bridge-mt` to
55
+ * apply pending `useAnimatedStyle` bindings before the native flush, so
56
+ * the debounce automatically coalesces SV-binding application too.
57
+ */
58
+ flushElementTree() {
59
+ if (willFlush)
60
+ return;
61
+ willFlush = true;
62
+ void Promise.resolve().then(() => {
63
+ willFlush = false;
64
+ __FlushElementTree();
65
+ });
66
+ }
67
+ /**
68
+ * Synchronously update inline styles on this element.
69
+ * This bypasses the BG→MT op queue — styles are applied immediately
70
+ * on the main thread, making it ideal for scroll-driven animations.
71
+ *
72
+ * The native `__FlushElementTree` call is microtask-debounced (see
73
+ * `flushElementTree`), so chaining multiple writes within one tick
74
+ * pays for a single flush instead of one per call.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * ref.current?.setStyleProperties({
79
+ * transform: `translateX(${offset}px)`,
80
+ * opacity: `${1 - ratio}`,
81
+ * });
82
+ * ```
83
+ */
84
+ setStyleProperties(styles) {
85
+ __SetInlineStyles(this._el, styles);
86
+ this.flushElementTree();
87
+ }
88
+ /**
89
+ * Get a computed style property value from this element.
90
+ *
91
+ * @param name - CSS property name in kebab-case (e.g. 'background-color')
92
+ * @returns The computed value as a string
93
+ */
94
+ getComputedStyleProperty(name) {
95
+ if (typeof __GetComputedStyleByKey === 'function') {
96
+ return __GetComputedStyleByKey(this._el, name);
97
+ }
98
+ return '';
99
+ }
100
+ /**
101
+ * Get a single attribute value by name. Returns the value as set via
102
+ * `setAttribute` (or by a parent component); does not resolve aliases.
103
+ */
104
+ getAttribute(name) {
105
+ if (typeof __GetAttributeByName === 'function') {
106
+ return __GetAttributeByName(this._el, name);
107
+ }
108
+ return undefined;
109
+ }
110
+ /**
111
+ * Get the list of attribute names currently set on this element.
112
+ */
113
+ getAttributeNames() {
114
+ if (typeof __GetAttributeNames === 'function') {
115
+ return __GetAttributeNames(this._el);
116
+ }
117
+ return [];
118
+ }
119
+ /**
120
+ * Find the first descendant element matching the CSS selector.
121
+ * Mirrors `Element.prototype.querySelector` from the DOM.
122
+ *
123
+ * Returns `null` when no match is found OR when the host runtime does not
124
+ * provide `__QuerySelector` (older Lynx SDKs).
125
+ */
126
+ querySelector(selector) {
127
+ if (typeof __QuerySelector !== 'function')
128
+ return null;
129
+ const ref = __QuerySelector(this._el, selector, {});
130
+ return ref ? new MTElementWrapper(ref) : null;
131
+ }
132
+ /**
133
+ * Find every descendant element matching the CSS selector. Returns an empty
134
+ * array when nothing matches OR when the host runtime does not provide
135
+ * `__QuerySelectorAll`.
136
+ */
137
+ querySelectorAll(selector) {
138
+ if (typeof __QuerySelectorAll !== 'function')
139
+ return [];
140
+ return __QuerySelectorAll(this._el, selector, {})
141
+ .map((el) => new MTElementWrapper(el));
142
+ }
143
+ /**
144
+ * Invoke a UI method exposed by the underlying native element (e.g.
145
+ * `scrollIntoView` on `<scroll-view>`, `scrollToIndex` on `<list>`).
146
+ *
147
+ * Resolves with the method's `data` payload on success (`code === 0`);
148
+ * rejects with an Error containing the JSON-stringified response otherwise.
149
+ */
150
+ invoke(methodName, params) {
151
+ return new Promise((resolve, reject) => {
152
+ if (typeof __InvokeUIMethod !== 'function') {
153
+ reject(new Error('UI method invoke: __InvokeUIMethod not available'));
154
+ return;
155
+ }
156
+ __InvokeUIMethod(this._el, methodName, params ?? {}, (res) => {
157
+ if (res.code === 0)
158
+ resolve(res.data);
159
+ else
160
+ reject(new Error('UI method invoke: ' + JSON.stringify(res)));
161
+ });
162
+ this.flushElementTree();
163
+ });
164
+ }
165
+ /**
166
+ * Start a keyframe animation on this element using the Lynx animation API.
167
+ *
168
+ * @param keyframes - Array of keyframe objects
169
+ * @param options - Animation configuration
170
+ * @returns Animation controller with play/pause/cancel methods
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * ref.current?.animate(
175
+ * [{ opacity: 0 }, { opacity: 1 }],
176
+ * { duration: 300, easing: 'ease-in-out' }
177
+ * );
178
+ * ```
179
+ */
180
+ animate(keyframes, options = {}) {
181
+ const el = this._el;
182
+ if (typeof el.animate === 'function') {
183
+ return el.animate(keyframes, options);
184
+ }
185
+ return null;
186
+ }
187
+ /**
188
+ * Set a single attribute on this element. Microtask-debounced flush —
189
+ * see `flushElementTree`.
190
+ */
191
+ setAttribute(key, value) {
192
+ __SetAttribute(this._el, key, value);
193
+ this.flushElementTree();
194
+ }
195
+ /**
196
+ * Set a single inline style property. Microtask-debounced flush — see
197
+ * `flushElementTree`.
198
+ */
199
+ setStyleProperty(name, value) {
200
+ __AddInlineStyle(this._el, name, value);
201
+ this.flushElementTree();
202
+ }
203
+ }