ReviewOS

stacks/stx

fix(native): make shared component reactive props and emitted events host-independent

#2086
Closed glennmichael123 opened this 8 days ago ·
8 days ago

Problem

Ordinary shared components cannot reliably initialize or communicate on native. The goal is one STX component source across browser and native, with platform differences handled by the runtime.

Audited at v0.2.546, commit 0013ce66e38399bb23c86b5b666ac0792825bf1b.

Reproduced evidence

Compiling screens with the actual shared-library Button, TextInput, Select, and Dialog components, then executing each bundle in a DOM-free VM with a native bridge, throws:

ReferenceError: MutationObserver is not defined

A plain signal-driven button/text screen works in the same harness. A shared Card also initializes.

Separately, a custom child with const emit = defineEmits(['change']) and a button calling emit('change', 'saved'), listened to by its parent, reports:

TypeError: target.dispatchEvent is not a function

Sources:

Requested change

Make prop subscriptions and component event delivery host-independent. Preserve browser behavior, typed prop values, component event ownership/bubbling semantics, and cleanup. A no-op MutationObserver shim would only hide the failure, not deliver reactive props.

Acceptance

  • The same shared-library component files initialize on browser and native.
  • Parent prop changes reach child useReactiveProp signals.
  • Child emits reach the correct parent with the correct payload.
  • useModel/two-way bindings work in both directions without feedback loops.
  • Hide/show, repeated instances, and teardown do not duplicate or leak subscriptions.
  • Tests explicitly exercise shared components, not native primitive replacements.

Priority and validation

First in the portability audit sequence. Foundational for controls, forms, and overlays. Existing native suite: 360 passed; selected browser/component tests: 58 passed. These new probes expose coverage gaps despite those passing suites. No simulator validation was performed during this audit.

8 days ago

Fixed on main in dd9d16b, 7fb6668, 79ec7bc, 7a2eca5, f82d175 and c41a2fe; verification follow-up 07835f3. Version: these commits follow v0.2.582 and are not yet in a numbered release.

Prop observation and emitted events now use the host adapter. Coverage includes actual shared Button, TextInput, Select, Dialog initialization, typed parent updates, independent instances, two-way models, conditional remounts, teardown, multiple listeners, and event cancellation/propagation.

Regression tests: packages/stx/test/native/shared-component-props.test.ts, component-events.test.ts, native-host.test.ts, and the browser host-boundary/model suites. The native/model/runtime-parse run passed 462 tests; combined browser/component checks passed 2,013 tests. CI on 36a98d2 passed lint, typecheck, test and publish-commit: https://github.com/stacksjs/stx/actions/runs/39264397388

This closes the prop/event transport gap, not the remaining DOM-dependent overlay behavior tracked in #2089. No simulator/device visual-parity claim is made.

Sign in to comment on this issue.