sygnal 5.1.1 → 5.1.3

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 CHANGED
@@ -21,12 +21,13 @@ A reactive component framework with pure functions, zero side effects, and autom
21
21
  **Scaffold a new project:**
22
22
 
23
23
  ```bash
24
- npx degit tpresley/sygnal-template my-app
24
+ npm create sygnal-app my-app
25
25
  cd my-app
26
- npm install
27
26
  npm run dev
28
27
  ```
29
28
 
29
+ Choose from Vite (SPA), Vike (SSR), or Astro templates during setup.
30
+
30
31
  **Or add to an existing project:**
31
32
 
32
33
  ```bash
@@ -386,6 +387,25 @@ import Counter from '../components/Counter.jsx'
386
387
  <Counter client:load />
387
388
  ```
388
389
 
390
+ ### Vike Integration
391
+
392
+ File-based routing with SSR, client-side navigation, and automatic hydration:
393
+
394
+ ```javascript
395
+ // vite.config.js
396
+ import sygnal from 'sygnal/vite'
397
+ import vike from 'vike/plugin'
398
+ export default defineConfig({ plugins: [sygnal({ disableHmr: true }), vike()] })
399
+ ```
400
+
401
+ ```javascript
402
+ // pages/+config.js
403
+ import vikeSygnal from 'sygnal/config'
404
+ export default { extends: [vikeSygnal] }
405
+ ```
406
+
407
+ Pages are standard Sygnal components in `pages/*/+Page.jsx`. Supports layouts, data fetching, and SPA mode.
408
+
389
409
  ### TypeScript
390
410
 
391
411
  Full type definitions included:
@@ -443,6 +463,7 @@ h('div', [h('h1', 'Hello'), h('button.btn', 'Click')])
443
463
  |---------|-------------|
444
464
  | [Getting Started](./examples/getting-started) | Interactive guide with live demos (Astro) |
445
465
  | [Kanban Board](./examples/kanban) | Drag-and-drop with Collections and cross-component communication |
466
+ | [Vike SSR](./examples/vike) | File-based routing with SSR, layouts, and data fetching |
446
467
  | [Advanced Features](./examples/advanced-feature-tests) | Portals, slots, disposal, suspense, lazy loading |
447
468
  | [TypeScript 2048](./examples/ts-example-2048) | Full game in TypeScript |
448
469
  | [AI Discussion Panel](./examples/ai-panel-spa) | Complex SPA with custom drivers |
@@ -5462,7 +5462,18 @@ function wrapDOMSource(domSource) {
5462
5462
  }
5463
5463
  });
5464
5464
  }
5465
- const ABORT = Symbol('ABORT');
5465
+ const ABORT = Symbol.for('sygnal.ABORT');
5466
+ /**
5467
+ * Check if a value is the ABORT sentinel.
5468
+ * Uses Symbol.for() identity first, then falls back to description check
5469
+ * in case bundlers (e.g. Vite) create duplicate module instances with
5470
+ * separate Symbol.for() registries.
5471
+ */
5472
+ function isAbort(value) {
5473
+ if (value === ABORT)
5474
+ return true;
5475
+ return typeof value === 'symbol' && value.description === 'sygnal.ABORT';
5476
+ }
5466
5477
  function normalizeCalculatedEntry(field, entry) {
5467
5478
  if (typeof entry === 'function') {
5468
5479
  return { fn: entry, deps: null };
@@ -6184,7 +6195,7 @@ class Component {
6184
6195
  const enhancedState = this.addCalculated(_state);
6185
6196
  props.state = enhancedState;
6186
6197
  const newState = reducer(enhancedState, data, next, props);
6187
- if (newState === ABORT)
6198
+ if (isAbort(newState))
6188
6199
  return _state;
6189
6200
  return this.cleanupCalculated(newState);
6190
6201
  }
@@ -6213,7 +6224,7 @@ class Component {
6213
6224
  return ABORT;
6214
6225
  }
6215
6226
  }
6216
- }).filter((result) => result !== ABORT);
6227
+ }).filter((result) => !isAbort(result));
6217
6228
  }
6218
6229
  else if (reducer === undefined || reducer === true) {
6219
6230
  returnStream$ = filtered$.map(({ data }) => data);
@@ -5460,7 +5460,18 @@ function wrapDOMSource(domSource) {
5460
5460
  }
5461
5461
  });
5462
5462
  }
5463
- const ABORT = Symbol('ABORT');
5463
+ const ABORT = Symbol.for('sygnal.ABORT');
5464
+ /**
5465
+ * Check if a value is the ABORT sentinel.
5466
+ * Uses Symbol.for() identity first, then falls back to description check
5467
+ * in case bundlers (e.g. Vite) create duplicate module instances with
5468
+ * separate Symbol.for() registries.
5469
+ */
5470
+ function isAbort(value) {
5471
+ if (value === ABORT)
5472
+ return true;
5473
+ return typeof value === 'symbol' && value.description === 'sygnal.ABORT';
5474
+ }
5464
5475
  function normalizeCalculatedEntry(field, entry) {
5465
5476
  if (typeof entry === 'function') {
5466
5477
  return { fn: entry, deps: null };
@@ -6182,7 +6193,7 @@ class Component {
6182
6193
  const enhancedState = this.addCalculated(_state);
6183
6194
  props.state = enhancedState;
6184
6195
  const newState = reducer(enhancedState, data, next, props);
6185
- if (newState === ABORT)
6196
+ if (isAbort(newState))
6186
6197
  return _state;
6187
6198
  return this.cleanupCalculated(newState);
6188
6199
  }
@@ -6211,7 +6222,7 @@ class Component {
6211
6222
  return ABORT;
6212
6223
  }
6213
6224
  }
6214
- }).filter((result) => result !== ABORT);
6225
+ }).filter((result) => !isAbort(result));
6215
6226
  }
6216
6227
  else if (reducer === undefined || reducer === true) {
6217
6228
  returnStream$ = filtered$.map(({ data }) => data);
@@ -1,10 +1,12 @@
1
- import { Stream, MemoryStream } from 'xstream';
1
+ import { MemoryStream } from 'xstream';
2
2
  import { EventsFnOptions } from './DOMSource';
3
+ import { EnrichedEventStream } from './enrichEventStream';
3
4
  export declare class DocumentDOMSource {
4
5
  private _name;
5
- constructor(_name: string);
6
+ private _selector;
7
+ constructor(_name: string, selector?: string);
6
8
  select(selector: string): DocumentDOMSource;
7
- elements(): MemoryStream<Array<Document>>;
8
- element(): MemoryStream<Document>;
9
- events<K extends keyof DocumentEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): Stream<DocumentEventMap[K]>;
9
+ elements(): MemoryStream<Array<Document | Element>>;
10
+ element(): MemoryStream<Document | Element | null>;
11
+ events<K extends keyof DocumentEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<DocumentEventMap[K]>;
10
12
  }
@@ -3,6 +3,7 @@ import { EventsFnOptions } from './DOMSource';
3
3
  import { DocumentDOMSource } from './DocumentDOMSource';
4
4
  import { BodyDOMSource } from './BodyDOMSource';
5
5
  import { VNode } from './snabbdom';
6
+ import { EnrichedEventStream } from './enrichEventStream';
6
7
  import { Scope, IsolateSink } from './isolate';
7
8
  import { IsolateModule } from './IsolateModule';
8
9
  import { EventDelegator } from './EventDelegator';
@@ -24,7 +25,7 @@ export declare class MainDOMSource {
24
25
  get namespace(): Array<Scope>;
25
26
  select<T extends keyof SpecialSelector>(selector: T): SpecialSelector[T];
26
27
  select(selector: string): MainDOMSource;
27
- events<K extends keyof HTMLElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): Stream<HTMLElementEventMap[K]>;
28
+ events<K extends keyof HTMLElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<HTMLElementEventMap[K]>;
28
29
  dispose(): void;
29
30
  isolateSource: (source: MainDOMSource, scope: string) => MainDOMSource;
30
31
  isolateSink: IsolateSink<VNode>;
@@ -0,0 +1,24 @@
1
+ import { Stream } from 'xstream';
2
+ export interface EnrichedEventStream<T = Event> extends Stream<T> {
3
+ value(): EnrichedEventStream<string>;
4
+ value<R>(fn: (val: string) => R): EnrichedEventStream<R>;
5
+ checked(): EnrichedEventStream<boolean>;
6
+ checked<R>(fn: (val: boolean) => R): EnrichedEventStream<R>;
7
+ data(name: string): EnrichedEventStream<string | undefined>;
8
+ data<R>(name: string, fn: (val: string | undefined) => R): EnrichedEventStream<R>;
9
+ target(): EnrichedEventStream<EventTarget | null>;
10
+ target<R>(fn: (el: EventTarget | null) => R): EnrichedEventStream<R>;
11
+ key(): EnrichedEventStream<string>;
12
+ key<R>(fn: (key: string) => R): EnrichedEventStream<R>;
13
+ }
14
+ /**
15
+ * Adds chainable convenience methods to a DOM event stream.
16
+ *
17
+ * DOM.select('.input').events('input').value()
18
+ * DOM.input('.input').value()
19
+ * DOM.select('.item').events('click').data('id')
20
+ * DOM.click('.item').data('id', Number)
21
+ * DOM.change('.checkbox').checked()
22
+ * DOM.keydown('.field').key()
23
+ */
24
+ export declare function enrichEventStream(stream$: any): any;
@@ -514,6 +514,12 @@ function vnodeToHtml(vnode) {
514
514
  if (VOID_ELEMENTS.has(tag)) {
515
515
  return html;
516
516
  }
517
+ // If innerHTML is set via props, use it as raw content (no escaping)
518
+ if (vnode.data?.props?.innerHTML != null) {
519
+ html += String(vnode.data.props.innerHTML);
520
+ html += `</${tag}>`;
521
+ return html;
522
+ }
517
523
  // Children — snabbdom uses `text` for single text children (even when
518
524
  // `children` holds a text element object). Prioritize `text` when set.
519
525
  if (vnode.text != null) {
@@ -510,6 +510,12 @@ function vnodeToHtml(vnode) {
510
510
  if (VOID_ELEMENTS.has(tag)) {
511
511
  return html;
512
512
  }
513
+ // If innerHTML is set via props, use it as raw content (no escaping)
514
+ if (vnode.data?.props?.innerHTML != null) {
515
+ html += String(vnode.data.props.innerHTML);
516
+ html += `</${tag}>`;
517
+ return html;
518
+ }
513
519
  // Children — snabbdom uses `text` for single text children (even when
514
520
  // `children` holds a text element object). Prioritize `text` when set.
515
521
  if (vnode.text != null) {
@@ -1,10 +1,12 @@
1
- import { Stream, MemoryStream } from 'xstream';
1
+ import { MemoryStream } from 'xstream';
2
2
  import { EventsFnOptions } from './DOMSource';
3
+ import { EnrichedEventStream } from './enrichEventStream';
3
4
  export declare class DocumentDOMSource {
4
5
  private _name;
5
- constructor(_name: string);
6
+ private _selector;
7
+ constructor(_name: string, selector?: string);
6
8
  select(selector: string): DocumentDOMSource;
7
- elements(): MemoryStream<Array<Document>>;
8
- element(): MemoryStream<Document>;
9
- events<K extends keyof DocumentEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): Stream<DocumentEventMap[K]>;
9
+ elements(): MemoryStream<Array<Document | Element>>;
10
+ element(): MemoryStream<Document | Element | null>;
11
+ events<K extends keyof DocumentEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<DocumentEventMap[K]>;
10
12
  }
@@ -3,6 +3,7 @@ import { EventsFnOptions } from './DOMSource';
3
3
  import { DocumentDOMSource } from './DocumentDOMSource';
4
4
  import { BodyDOMSource } from './BodyDOMSource';
5
5
  import { VNode } from './snabbdom';
6
+ import { EnrichedEventStream } from './enrichEventStream';
6
7
  import { Scope, IsolateSink } from './isolate';
7
8
  import { IsolateModule } from './IsolateModule';
8
9
  import { EventDelegator } from './EventDelegator';
@@ -24,7 +25,7 @@ export declare class MainDOMSource {
24
25
  get namespace(): Array<Scope>;
25
26
  select<T extends keyof SpecialSelector>(selector: T): SpecialSelector[T];
26
27
  select(selector: string): MainDOMSource;
27
- events<K extends keyof HTMLElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): Stream<HTMLElementEventMap[K]>;
28
+ events<K extends keyof HTMLElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<HTMLElementEventMap[K]>;
28
29
  dispose(): void;
29
30
  isolateSource: (source: MainDOMSource, scope: string) => MainDOMSource;
30
31
  isolateSink: IsolateSink<VNode>;
@@ -0,0 +1,24 @@
1
+ import { Stream } from 'xstream';
2
+ export interface EnrichedEventStream<T = Event> extends Stream<T> {
3
+ value(): EnrichedEventStream<string>;
4
+ value<R>(fn: (val: string) => R): EnrichedEventStream<R>;
5
+ checked(): EnrichedEventStream<boolean>;
6
+ checked<R>(fn: (val: boolean) => R): EnrichedEventStream<R>;
7
+ data(name: string): EnrichedEventStream<string | undefined>;
8
+ data<R>(name: string, fn: (val: string | undefined) => R): EnrichedEventStream<R>;
9
+ target(): EnrichedEventStream<EventTarget | null>;
10
+ target<R>(fn: (el: EventTarget | null) => R): EnrichedEventStream<R>;
11
+ key(): EnrichedEventStream<string>;
12
+ key<R>(fn: (key: string) => R): EnrichedEventStream<R>;
13
+ }
14
+ /**
15
+ * Adds chainable convenience methods to a DOM event stream.
16
+ *
17
+ * DOM.select('.input').events('input').value()
18
+ * DOM.input('.input').value()
19
+ * DOM.select('.item').events('click').data('id')
20
+ * DOM.click('.item').data('id', Number)
21
+ * DOM.change('.checkbox').checked()
22
+ * DOM.keydown('.field').key()
23
+ */
24
+ export declare function enrichEventStream(stream$: any): any;
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var xs$1 = require('xstream');
4
- var dropRepeats$2 = require('xstream/extra/dropRepeats');
5
- var concat$1 = require('xstream/extra/concat');
4
+ var dropRepeatsModule = require('xstream/extra/dropRepeats.js');
5
+ var concat$1 = require('xstream/extra/concat.js');
6
6
  var h = require('snabbdom/build/h');
7
7
  var init$1 = require('snabbdom/build/init');
8
8
  var tovnode = require('snabbdom/build/tovnode');
@@ -12,14 +12,10 @@ var _class = require('snabbdom/build/modules/class');
12
12
  var props = require('snabbdom/build/modules/props');
13
13
  var attributes = require('snabbdom/build/modules/attributes');
14
14
  var dataset = require('snabbdom/build/modules/dataset');
15
- var sampleCombine = require('xstream/extra/sampleCombine');
15
+ var sampleCombine = require('xstream/extra/sampleCombine.js');
16
16
  var delayModule = require('xstream/extra/delay.js');
17
- var concatModule = require('xstream/extra/concat.js');
18
17
  var debounceModule = require('xstream/extra/debounce.js');
19
- var dropRepeatsModule = require('xstream/extra/dropRepeats.js');
20
- var debounce$1 = require('xstream/extra/debounce');
21
- var throttle = require('xstream/extra/throttle');
22
- var delay$1 = require('xstream/extra/delay');
18
+ var throttle_js = require('xstream/extra/throttle.js');
23
19
 
24
20
  function _interopNamespaceDefault(e) {
25
21
  var n = Object.create(null);
@@ -39,11 +35,10 @@ function _interopNamespaceDefault(e) {
39
35
  }
40
36
 
41
37
  var xs__namespace = /*#__PURE__*/_interopNamespaceDefault(xs$1);
42
- var dropRepeats__namespace = /*#__PURE__*/_interopNamespaceDefault(dropRepeats$2);
38
+ var dropRepeatsModule__namespace = /*#__PURE__*/_interopNamespaceDefault(dropRepeatsModule);
39
+ var concat__namespace = /*#__PURE__*/_interopNamespaceDefault(concat$1);
43
40
  var delayModule__namespace = /*#__PURE__*/_interopNamespaceDefault(delayModule);
44
- var concatModule__namespace = /*#__PURE__*/_interopNamespaceDefault(concatModule);
45
41
  var debounceModule__namespace = /*#__PURE__*/_interopNamespaceDefault(debounceModule);
46
- var dropRepeatsModule__namespace = /*#__PURE__*/_interopNamespaceDefault(dropRepeatsModule);
47
42
 
48
43
  function getGlobal() {
49
44
  let globalObj;
@@ -231,7 +226,7 @@ class StateSource {
231
226
  this.isolateSink = isolateSink;
232
227
  this._stream = stream
233
228
  .filter(s => typeof s !== 'undefined')
234
- .compose(dropRepeats$2())
229
+ .compose(dropRepeatsModule())
235
230
  .remember();
236
231
  this._name = name;
237
232
  this.stream = adapt(this._stream);
@@ -2080,7 +2075,7 @@ const Stream = xs__namespace.Stream ||
2080
2075
  (xs__namespace.default && xs__namespace.default.Stream) ||
2081
2076
  (xs && xs.Stream);
2082
2077
 
2083
- const dropRepeats$1 = resolveInteropDefault(dropRepeats__namespace);
2078
+ const dropRepeats$1 = resolveInteropDefault(dropRepeatsModule__namespace);
2084
2079
  function switchable(factories, name$, initial, opts = {}) {
2085
2080
  const { switched = ['DOM'], stateSourceName = 'STATE' } = opts;
2086
2081
  const nameType = typeof name$;
@@ -2183,7 +2178,7 @@ function makeCommandSource(cmd) {
2183
2178
  }
2184
2179
 
2185
2180
  const delay = resolveInteropDefault(delayModule__namespace);
2186
- const concat = resolveInteropDefault(concatModule__namespace);
2181
+ const concat = resolveInteropDefault(concat__namespace);
2187
2182
  const debounce = resolveInteropDefault(debounceModule__namespace);
2188
2183
  const dropRepeats = resolveInteropDefault(dropRepeatsModule__namespace);
2189
2184
  const ENVIRONMENT = (typeof window != 'undefined' && window) || (typeof process !== 'undefined' && process.env) || {};
@@ -2205,7 +2200,18 @@ function wrapDOMSource(domSource) {
2205
2200
  }
2206
2201
  });
2207
2202
  }
2208
- const ABORT = Symbol('ABORT');
2203
+ const ABORT = Symbol.for('sygnal.ABORT');
2204
+ /**
2205
+ * Check if a value is the ABORT sentinel.
2206
+ * Uses Symbol.for() identity first, then falls back to description check
2207
+ * in case bundlers (e.g. Vite) create duplicate module instances with
2208
+ * separate Symbol.for() registries.
2209
+ */
2210
+ function isAbort(value) {
2211
+ if (value === ABORT)
2212
+ return true;
2213
+ return typeof value === 'symbol' && value.description === 'sygnal.ABORT';
2214
+ }
2209
2215
  function normalizeCalculatedEntry(field, entry) {
2210
2216
  if (typeof entry === 'function') {
2211
2217
  return { fn: entry, deps: null };
@@ -2927,7 +2933,7 @@ class Component {
2927
2933
  const enhancedState = this.addCalculated(_state);
2928
2934
  props.state = enhancedState;
2929
2935
  const newState = reducer(enhancedState, data, next, props);
2930
- if (newState === ABORT)
2936
+ if (isAbort(newState))
2931
2937
  return _state;
2932
2938
  return this.cleanupCalculated(newState);
2933
2939
  }
@@ -2956,7 +2962,7 @@ class Component {
2956
2962
  return ABORT;
2957
2963
  }
2958
2964
  }
2959
- }).filter((result) => result !== ABORT);
2965
+ }).filter((result) => !isAbort(result));
2960
2966
  }
2961
2967
  else if (reducer === undefined || reducer === true) {
2962
2968
  returnStream$ = filtered$.map(({ data }) => data);
@@ -6326,6 +6332,12 @@ function vnodeToHtml(vnode) {
6326
6332
  if (VOID_ELEMENTS.has(tag)) {
6327
6333
  return html;
6328
6334
  }
6335
+ // If innerHTML is set via props, use it as raw content (no escaping)
6336
+ if (vnode.data?.props?.innerHTML != null) {
6337
+ html += String(vnode.data.props.innerHTML);
6338
+ html += `</${tag}>`;
6339
+ return html;
6340
+ }
6329
6341
  // Children — snabbdom uses `text` for single text children (even when
6330
6342
  // `children` holds a text element object). Prioritize `text` when set.
6331
6343
  if (vnode.text != null) {
@@ -6457,15 +6469,15 @@ function buildAttributes(data, selectorId, selectorClasses) {
6457
6469
  return result;
6458
6470
  }
6459
6471
 
6460
- exports.dropRepeats = dropRepeats$2;
6472
+ exports.dropRepeats = dropRepeatsModule;
6461
6473
  Object.defineProperty(exports, 'h', {
6462
6474
  enumerable: true,
6463
6475
  get: function () { return h.h; }
6464
6476
  });
6465
6477
  exports.sampleCombine = sampleCombine;
6466
- exports.debounce = debounce$1;
6467
- exports.throttle = throttle;
6468
- exports.delay = delay$1;
6478
+ exports.delay = delayModule;
6479
+ exports.debounce = debounceModule;
6480
+ exports.throttle = throttle_js;
6469
6481
  exports.ABORT = ABORT;
6470
6482
  exports.Collection = Collection;
6471
6483
  exports.MainDOMSource = MainDOMSource;
package/dist/index.d.ts CHANGED
@@ -614,11 +614,11 @@ export function renderToString(componentDef: any, options?: RenderToStringOption
614
614
 
615
615
  export const xs: typeof xsDefault
616
616
 
617
- export { default as debounce } from 'xstream/extra/debounce'
618
- export { default as throttle } from 'xstream/extra/throttle'
619
- export { default as delay } from 'xstream/extra/delay'
620
- export { default as dropRepeats } from 'xstream/extra/dropRepeats'
621
- export { default as sampleCombine } from 'xstream/extra/sampleCombine'
617
+ export { default as debounce } from 'xstream/extra/debounce.js'
618
+ export { default as throttle } from 'xstream/extra/throttle.js'
619
+ export { default as delay } from 'xstream/extra/delay.js'
620
+ export { default as dropRepeats } from 'xstream/extra/dropRepeats.js'
621
+ export { default as sampleCombine } from 'xstream/extra/sampleCombine.js'
622
622
 
623
623
  export * from './cycle/dom/index'
624
624
  export type { MemoryStream, Stream }
package/dist/index.esm.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as xs$1 from 'xstream';
2
2
  import xs__default, { Stream as Stream$1, NO } from 'xstream';
3
- import * as dropRepeats$2 from 'xstream/extra/dropRepeats';
4
- import dropRepeats__default from 'xstream/extra/dropRepeats';
5
- export { default as dropRepeats } from 'xstream/extra/dropRepeats';
6
- import concat$1 from 'xstream/extra/concat';
3
+ import * as dropRepeatsModule from 'xstream/extra/dropRepeats.js';
4
+ import dropRepeatsModule__default from 'xstream/extra/dropRepeats.js';
5
+ export { default as dropRepeats } from 'xstream/extra/dropRepeats.js';
6
+ import * as concat$1 from 'xstream/extra/concat.js';
7
+ import concat__default from 'xstream/extra/concat.js';
7
8
  import { h } from 'snabbdom/build/h';
8
9
  export { h } from 'snabbdom/build/h';
9
10
  import { init as init$1 } from 'snabbdom/build/init';
@@ -14,15 +15,13 @@ import { classModule } from 'snabbdom/build/modules/class';
14
15
  import { propsModule } from 'snabbdom/build/modules/props';
15
16
  import { attributesModule } from 'snabbdom/build/modules/attributes';
16
17
  import { datasetModule } from 'snabbdom/build/modules/dataset';
17
- import sampleCombine from 'xstream/extra/sampleCombine';
18
- export { default as sampleCombine } from 'xstream/extra/sampleCombine';
18
+ import sampleCombine from 'xstream/extra/sampleCombine.js';
19
+ export { default as sampleCombine } from 'xstream/extra/sampleCombine.js';
19
20
  import * as delayModule from 'xstream/extra/delay.js';
20
- import * as concatModule from 'xstream/extra/concat.js';
21
+ export { default as delay } from 'xstream/extra/delay.js';
21
22
  import * as debounceModule from 'xstream/extra/debounce.js';
22
- import * as dropRepeatsModule from 'xstream/extra/dropRepeats.js';
23
- export { default as debounce } from 'xstream/extra/debounce';
24
- export { default as throttle } from 'xstream/extra/throttle';
25
- export { default as delay } from 'xstream/extra/delay';
23
+ export { default as debounce } from 'xstream/extra/debounce.js';
24
+ export { default as throttle } from 'xstream/extra/throttle.js';
26
25
 
27
26
  function getGlobal() {
28
27
  let globalObj;
@@ -210,7 +209,7 @@ class StateSource {
210
209
  this.isolateSink = isolateSink;
211
210
  this._stream = stream
212
211
  .filter(s => typeof s !== 'undefined')
213
- .compose(dropRepeats__default())
212
+ .compose(dropRepeatsModule__default())
214
213
  .remember();
215
214
  this._name = name;
216
215
  this.stream = adapt(this._stream);
@@ -592,7 +591,7 @@ function withState(main, name = 'state') {
592
591
  innerSources[name] = new StateSource(state$, name);
593
592
  const sinks = main(innerSources);
594
593
  if (sinks[name]) {
595
- const stream$ = concat$1(xs__default.fromObservable(sinks[name]), xs__default.never());
594
+ const stream$ = concat__default(xs__default.fromObservable(sinks[name]), xs__default.never());
596
595
  stream$.subscribe({
597
596
  next: i => queueMicrotask(() => reducerMimic$._n(i)),
598
597
  error: err => queueMicrotask(() => reducerMimic$._e(err)),
@@ -1905,7 +1904,7 @@ function makeDOMDriver(container, options = {}) {
1905
1904
  })
1906
1905
  .compose(dropCompletion))
1907
1906
  .flatten();
1908
- const rootElement$ = concat$1(domReady$, mutationConfirmed$)
1907
+ const rootElement$ = concat__default(domReady$, mutationConfirmed$)
1909
1908
  .endWhen(sanitation$)
1910
1909
  .compose(sampleCombine(elementAfterPatch$))
1911
1910
  .map(arr => arr[1])
@@ -2059,7 +2058,7 @@ const Stream = xs$1.Stream ||
2059
2058
  (xs$1.default && xs$1.default.Stream) ||
2060
2059
  (xs && xs.Stream);
2061
2060
 
2062
- const dropRepeats$1 = resolveInteropDefault(dropRepeats$2);
2061
+ const dropRepeats$1 = resolveInteropDefault(dropRepeatsModule);
2063
2062
  function switchable(factories, name$, initial, opts = {}) {
2064
2063
  const { switched = ['DOM'], stateSourceName = 'STATE' } = opts;
2065
2064
  const nameType = typeof name$;
@@ -2162,7 +2161,7 @@ function makeCommandSource(cmd) {
2162
2161
  }
2163
2162
 
2164
2163
  const delay = resolveInteropDefault(delayModule);
2165
- const concat = resolveInteropDefault(concatModule);
2164
+ const concat = resolveInteropDefault(concat$1);
2166
2165
  const debounce = resolveInteropDefault(debounceModule);
2167
2166
  const dropRepeats = resolveInteropDefault(dropRepeatsModule);
2168
2167
  const ENVIRONMENT = (typeof window != 'undefined' && window) || (typeof process !== 'undefined' && process.env) || {};
@@ -2184,7 +2183,18 @@ function wrapDOMSource(domSource) {
2184
2183
  }
2185
2184
  });
2186
2185
  }
2187
- const ABORT = Symbol('ABORT');
2186
+ const ABORT = Symbol.for('sygnal.ABORT');
2187
+ /**
2188
+ * Check if a value is the ABORT sentinel.
2189
+ * Uses Symbol.for() identity first, then falls back to description check
2190
+ * in case bundlers (e.g. Vite) create duplicate module instances with
2191
+ * separate Symbol.for() registries.
2192
+ */
2193
+ function isAbort(value) {
2194
+ if (value === ABORT)
2195
+ return true;
2196
+ return typeof value === 'symbol' && value.description === 'sygnal.ABORT';
2197
+ }
2188
2198
  function normalizeCalculatedEntry(field, entry) {
2189
2199
  if (typeof entry === 'function') {
2190
2200
  return { fn: entry, deps: null };
@@ -2906,7 +2916,7 @@ class Component {
2906
2916
  const enhancedState = this.addCalculated(_state);
2907
2917
  props.state = enhancedState;
2908
2918
  const newState = reducer(enhancedState, data, next, props);
2909
- if (newState === ABORT)
2919
+ if (isAbort(newState))
2910
2920
  return _state;
2911
2921
  return this.cleanupCalculated(newState);
2912
2922
  }
@@ -2935,7 +2945,7 @@ class Component {
2935
2945
  return ABORT;
2936
2946
  }
2937
2947
  }
2938
- }).filter((result) => result !== ABORT);
2948
+ }).filter((result) => !isAbort(result));
2939
2949
  }
2940
2950
  else if (reducer === undefined || reducer === true) {
2941
2951
  returnStream$ = filtered$.map(({ data }) => data);
@@ -6305,6 +6315,12 @@ function vnodeToHtml(vnode) {
6305
6315
  if (VOID_ELEMENTS.has(tag)) {
6306
6316
  return html;
6307
6317
  }
6318
+ // If innerHTML is set via props, use it as raw content (no escaping)
6319
+ if (vnode.data?.props?.innerHTML != null) {
6320
+ html += String(vnode.data.props.innerHTML);
6321
+ html += `</${tag}>`;
6322
+ return html;
6323
+ }
6308
6324
  // Children — snabbdom uses `text` for single text children (even when
6309
6325
  // `children` holds a text element object). Prioritize `text` when set.
6310
6326
  if (vnode.text != null) {