sygnal 5.3.7 → 5.4.0
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 +53 -38
- package/dist/astro/client.cjs.js +18 -8106
- package/dist/astro/client.cjs.js.map +1 -0
- package/dist/astro/client.mjs +17 -8105
- package/dist/astro/client.mjs.map +1 -0
- package/dist/astro/index.cjs.js +768 -9
- package/dist/astro/index.cjs.js.map +1 -0
- package/dist/astro/index.mjs +768 -9
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/server.cjs.js +4 -1
- package/dist/astro/server.cjs.js.map +1 -0
- package/dist/astro/server.mjs +4 -1
- package/dist/astro/server.mjs.map +1 -0
- package/dist/diagnostics.cjs.js +1297 -0
- package/dist/diagnostics.cjs.js.map +1 -0
- package/dist/diagnostics.esm.js +1267 -0
- package/dist/diagnostics.esm.js.map +1 -0
- package/dist/index.cjs.js +2981 -1386
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +848 -111
- package/dist/index.esm.js +2997 -1411
- package/dist/index.esm.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs.js +15 -9
- package/dist/jsx-dev-runtime.cjs.js.map +1 -0
- package/dist/jsx-dev-runtime.esm.js +15 -9
- package/dist/jsx-dev-runtime.esm.js.map +1 -0
- package/dist/jsx-runtime.cjs.js +15 -9
- package/dist/jsx-runtime.cjs.js.map +1 -0
- package/dist/jsx-runtime.esm.js +15 -9
- package/dist/jsx-runtime.esm.js.map +1 -0
- package/dist/jsx.cjs.js +15 -9
- package/dist/jsx.cjs.js.map +1 -0
- package/dist/jsx.esm.js +15 -9
- package/dist/jsx.esm.js.map +1 -0
- package/dist/sygnal.min.js +2 -1
- package/dist/sygnal.min.js.map +1 -0
- package/dist/vike/+config.cjs.js +1 -0
- package/dist/vike/+config.cjs.js.map +1 -0
- package/dist/vike/+config.js +1 -0
- package/dist/vike/+config.js.map +1 -0
- package/dist/vike/ClientOnly.cjs.js +1 -0
- package/dist/vike/ClientOnly.cjs.js.map +1 -0
- package/dist/vike/ClientOnly.mjs +1 -0
- package/dist/vike/ClientOnly.mjs.map +1 -0
- package/dist/vike/onRenderClient.cjs.js +1 -0
- package/dist/vike/onRenderClient.cjs.js.map +1 -0
- package/dist/vike/onRenderClient.mjs +1 -0
- package/dist/vike/onRenderClient.mjs.map +1 -0
- package/dist/vike/onRenderHtml.cjs.js +1 -0
- package/dist/vike/onRenderHtml.cjs.js.map +1 -0
- package/dist/vike/onRenderHtml.mjs +1 -0
- package/dist/vike/onRenderHtml.mjs.map +1 -0
- package/dist/vite/plugin.cjs.js +670 -44
- package/dist/vite/plugin.cjs.js.map +1 -0
- package/dist/vite/plugin.mjs +670 -44
- package/dist/vite/plugin.mjs.map +1 -0
- package/llms.txt +250 -0
- package/package.json +15 -6
- package/src/astro/client.ts +13 -2
- package/src/astro/index.d.ts +24 -1
- package/src/astro/index.ts +40 -9
- package/src/astro/server.ts +3 -1
- package/src/collection.ts +5 -2
- package/src/component.ts +375 -330
- package/src/cycle/dom/MainDOMSource.ts +4 -0
- package/src/cycle/dom/classNameModule.ts +74 -0
- package/src/cycle/dom/controlledInputModule.ts +33 -0
- package/src/cycle/dom/enrichEventStream.ts +9 -3
- package/src/cycle/dom/makeDOMDriver.ts +1 -2
- package/src/cycle/dom/mockDOMSource.ts +62 -8
- package/src/cycle/dom/modules.ts +5 -1
- package/src/cycle/state/Collection.ts +13 -3
- package/src/cycle/state/StateSource.ts +1 -1
- package/src/cycle/state/pickCombine.ts +35 -1
- package/src/cycle/state/withState.ts +1 -1
- package/src/extra/devtools.ts +8 -0
- package/src/extra/diagnostics/checks/collections.ts +67 -0
- package/src/extra/diagnostics/checks/dom.ts +241 -0
- package/src/extra/diagnostics/checks/events.ts +68 -0
- package/src/extra/diagnostics/checks/index.ts +109 -0
- package/src/extra/diagnostics/checks/inspect.ts +319 -0
- package/src/extra/diagnostics/checks/props.ts +51 -0
- package/src/extra/diagnostics/checks/public.d.ts +211 -0
- package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
- package/src/extra/diagnostics/checks/shared.ts +119 -0
- package/src/extra/diagnostics/checks/state.ts +55 -0
- package/src/extra/diagnostics/checks/strict.ts +112 -0
- package/src/extra/diagnostics/checks/wiring.ts +65 -0
- package/src/extra/diagnostics/codes.ts +232 -0
- package/src/extra/diagnostics/index.ts +328 -0
- package/src/extra/diagnostics/legacy.ts +59 -0
- package/src/extra/driverFactories.ts +106 -58
- package/src/extra/eventDriver.ts +4 -0
- package/src/extra/flatten.ts +75 -0
- package/src/extra/reducers.ts +12 -5
- package/src/extra/run.ts +11 -0
- package/src/extra/testing.ts +890 -180
- package/src/extra/xstreamExtras.ts +269 -0
- package/src/index.d.ts +428 -17
- package/src/index.ts +7 -6
- package/src/pragma/index.ts +14 -9
- package/src/switchable.ts +10 -8
- package/src/vike/types.ts +21 -4
- package/src/vite/plugin.d.ts +95 -2
- package/src/vite/plugin.ts +720 -54
- package/dist/astro/astro/client.d.ts +0 -5
- package/dist/astro/astro/index.d.ts +0 -16
- package/dist/astro/astro/server.d.ts +0 -12
- package/dist/astro/client.d.ts +0 -5
- package/dist/astro/client.esm.js +0 -4665
- package/dist/astro/collection.d.ts +0 -12
- package/dist/astro/component.d.ts +0 -22
- package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/astro/cycle/dom/index.d.ts +0 -8
- package/dist/astro/cycle/dom/isolate.d.ts +0 -9
- package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/astro/cycle/dom/modules.d.ts +0 -5
- package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
- package/dist/astro/cycle/dom/thunk.d.ts +0 -11
- package/dist/astro/cycle/dom/utils.d.ts +0 -8
- package/dist/astro/cycle/isolate/index.d.ts +0 -42
- package/dist/astro/cycle/run/adapt.d.ts +0 -6
- package/dist/astro/cycle/run/index.d.ts +0 -36
- package/dist/astro/cycle/run/internals.d.ts +0 -8
- package/dist/astro/cycle/run/types.d.ts +0 -49
- package/dist/astro/cycle/state/Collection.d.ts +0 -29
- package/dist/astro/cycle/state/StateSource.d.ts +0 -20
- package/dist/astro/cycle/state/index.d.ts +0 -5
- package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
- package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
- package/dist/astro/cycle/state/types.d.ts +0 -18
- package/dist/astro/cycle/state/withState.d.ts +0 -17
- package/dist/astro/extra/classes.d.ts +0 -7
- package/dist/astro/extra/devtools.d.ts +0 -78
- package/dist/astro/extra/dragDriver.d.ts +0 -20
- package/dist/astro/extra/driverFactories.d.ts +0 -12
- package/dist/astro/extra/eventDriver.d.ts +0 -9
- package/dist/astro/extra/exactState.d.ts +0 -1
- package/dist/astro/extra/hmr.d.ts +0 -17
- package/dist/astro/extra/logDriver.d.ts +0 -2
- package/dist/astro/extra/processDrag.d.ts +0 -19
- package/dist/astro/extra/processForm.d.ts +0 -15
- package/dist/astro/extra/run.d.ts +0 -13
- package/dist/astro/extra/xstreamCompat.d.ts +0 -5
- package/dist/astro/index.d.ts +0 -19
- package/dist/astro/index.esm.js +0 -27
- package/dist/astro/jsx-dev-runtime.d.ts +0 -1
- package/dist/astro/jsx-runtime.d.ts +0 -4
- package/dist/astro/jsx.d.ts +0 -2
- package/dist/astro/pragma/fn.d.ts +0 -7
- package/dist/astro/pragma/index.d.ts +0 -7
- package/dist/astro/pragma/is.d.ts +0 -10
- package/dist/astro/server.d.ts +0 -12
- package/dist/astro/server.esm.js +0 -25
- package/dist/astro/switchable.d.ts +0 -7
- package/dist/collection.d.ts +0 -12
- package/dist/component.d.ts +0 -22
- package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/cycle/dom/index.d.ts +0 -8
- package/dist/cycle/dom/isolate.d.ts +0 -9
- package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/cycle/dom/modules.d.ts +0 -5
- package/dist/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/cycle/dom/styleModule.d.ts +0 -13
- package/dist/cycle/dom/thunk.d.ts +0 -11
- package/dist/cycle/dom/utils.d.ts +0 -8
- package/dist/cycle/isolate/index.d.ts +0 -42
- package/dist/cycle/run/adapt.d.ts +0 -6
- package/dist/cycle/run/index.d.ts +0 -36
- package/dist/cycle/run/internals.d.ts +0 -8
- package/dist/cycle/run/types.d.ts +0 -49
- package/dist/cycle/state/Collection.d.ts +0 -29
- package/dist/cycle/state/StateSource.d.ts +0 -20
- package/dist/cycle/state/index.d.ts +0 -5
- package/dist/cycle/state/pickCombine.d.ts +0 -3
- package/dist/cycle/state/pickMerge.d.ts +0 -3
- package/dist/cycle/state/types.d.ts +0 -18
- package/dist/cycle/state/withState.d.ts +0 -17
- package/dist/extra/classes.d.ts +0 -7
- package/dist/extra/devtools.d.ts +0 -78
- package/dist/extra/dragDriver.d.ts +0 -20
- package/dist/extra/driverFactories.d.ts +0 -12
- package/dist/extra/eventDriver.d.ts +0 -9
- package/dist/extra/exactState.d.ts +0 -1
- package/dist/extra/hmr.d.ts +0 -17
- package/dist/extra/logDriver.d.ts +0 -2
- package/dist/extra/processDrag.d.ts +0 -19
- package/dist/extra/processForm.d.ts +0 -15
- package/dist/extra/run.d.ts +0 -13
- package/dist/extra/xstreamCompat.d.ts +0 -5
- package/dist/jsx-dev-runtime.d.ts +0 -1
- package/dist/jsx-dev-runtime.js +0 -224
- package/dist/jsx-runtime.d.ts +0 -4
- package/dist/jsx-runtime.js +0 -224
- package/dist/jsx.d.ts +0 -2
- package/dist/pragma/fn.d.ts +0 -7
- package/dist/pragma/index.d.ts +0 -7
- package/dist/pragma/is.d.ts +0 -10
- package/dist/switchable.d.ts +0 -7
package/src/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { MainDOMSource } from './cycle/dom/MainDOMSource'
|
|
|
2
2
|
import type { EnrichedEventStream } from './cycle/dom/enrichEventStream'
|
|
3
3
|
import type { StateSource } from './cycle/state/index'
|
|
4
4
|
import xsDefault from 'xstream'
|
|
5
|
+
import type { InspectGraph } from './extra/diagnostics/checks/public'
|
|
5
6
|
import type { MemoryStream, Stream } from 'xstream'
|
|
6
7
|
|
|
7
8
|
export declare const ABORT: unique symbol
|
|
@@ -60,6 +61,72 @@ type StateOnlyReducer<STATE, RETURN = any> = (
|
|
|
60
61
|
|
|
61
62
|
export type Event<DATA = any> = { type: string; data: DATA }
|
|
62
63
|
|
|
64
|
+
// ── EVENTS registry ────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Registry of global EVENTS bus event names and their payload types.
|
|
68
|
+
*
|
|
69
|
+
* Empty by default, which keeps the EVENTS bus untyped (`any`). Augment it to
|
|
70
|
+
* type-check `EVENTS.select()`, `event()`, `emit()` and raw EVENTS sink returns:
|
|
71
|
+
*
|
|
72
|
+
* declare module 'sygnal' {
|
|
73
|
+
* interface SygnalEvents {
|
|
74
|
+
* DELETE_LANE: { laneId: string }
|
|
75
|
+
* RESET: void // no payload: event('RESET')
|
|
76
|
+
* }
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* Once the registry has at least one entry, unregistered event names are type errors.
|
|
80
|
+
* The augmenting file must be a module (have at least one import or export).
|
|
81
|
+
*/
|
|
82
|
+
export interface SygnalEvents {}
|
|
83
|
+
|
|
84
|
+
/** Valid event names: `string` while the registry is empty, otherwise the registered names. */
|
|
85
|
+
export type EventName = keyof SygnalEvents extends never ? string : keyof SygnalEvents & string
|
|
86
|
+
|
|
87
|
+
/** Payload type of a registered event (`any` while the registry is empty). */
|
|
88
|
+
export type EventPayload<TYPE extends string = string> = keyof SygnalEvents extends never
|
|
89
|
+
? any
|
|
90
|
+
: TYPE extends keyof SygnalEvents ? SygnalEvents[TYPE] : never
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* An event object as put on the EVENTS bus. While the registry is empty this is `Event<any>`;
|
|
94
|
+
* otherwise it is the union of `{ type, data }` for every registered event.
|
|
95
|
+
*/
|
|
96
|
+
export type RegisteredEvent = keyof SygnalEvents extends never
|
|
97
|
+
? Event<any>
|
|
98
|
+
: { [TYPE in keyof SygnalEvents & string]: { type: TYPE; data: SygnalEvents[TYPE] } }[keyof SygnalEvents & string]
|
|
99
|
+
|
|
100
|
+
/** The `{ type, data }` object produced by `event(type, ...)` / `emit(type, ...)`. */
|
|
101
|
+
export type EmittedEvent<TYPE extends string = string> = keyof SygnalEvents extends never
|
|
102
|
+
? { type: TYPE; data: any }
|
|
103
|
+
: { type: TYPE; data: EventPayload<TYPE> }
|
|
104
|
+
|
|
105
|
+
/** The `next()` function as seen by an event payload function. */
|
|
106
|
+
type EventNextFunction = (action: string, data?: any, delay?: number) => void
|
|
107
|
+
|
|
108
|
+
/** Payload function for `event()` / `emit()`: receives the reducer arguments, returns the event data. */
|
|
109
|
+
export type EventPayloadFunction<TYPE extends string = string, STATE = any, DATA = any> =
|
|
110
|
+
(state: STATE, data: DATA, next: EventNextFunction, props: any) => EventPayload<TYPE>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Remaining arguments of `event()` / `emit()` when the payload is a static value.
|
|
114
|
+
* The payload may be omitted when the registry is empty or the event's payload
|
|
115
|
+
* type accepts `undefined` (e.g. `void`).
|
|
116
|
+
*/
|
|
117
|
+
type StaticEventArgs<TYPE extends string> = keyof SygnalEvents extends never
|
|
118
|
+
? [payload?: any]
|
|
119
|
+
: undefined extends EventPayload<TYPE>
|
|
120
|
+
? [payload?: EventPayload<TYPE>]
|
|
121
|
+
: [payload: EventPayload<TYPE>]
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The sink function returned by `event()`. Use it as the value of an `EVENTS` key in a
|
|
125
|
+
* model entry: `ACTION: { STATE: ..., EVENTS: event('TYPE', fn) }`.
|
|
126
|
+
*/
|
|
127
|
+
export type EventSink<TYPE extends string = string, STATE = any, DATA = any> =
|
|
128
|
+
(state: STATE, data: DATA, next: any, props: any) => EmittedEvent<TYPE>
|
|
129
|
+
|
|
63
130
|
export type NonStateSinkReturns = {
|
|
64
131
|
EVENTS?: unknown;
|
|
65
132
|
LOG?: unknown;
|
|
@@ -67,7 +134,7 @@ export type NonStateSinkReturns = {
|
|
|
67
134
|
}
|
|
68
135
|
|
|
69
136
|
type ResolvedNonStateSinkReturns<SINK_RETURNS extends NonStateSinkReturns = {}> = {
|
|
70
|
-
EVENTS: SINK_RETURNS extends { EVENTS: infer EVENTS_RETURN } ? EVENTS_RETURN :
|
|
137
|
+
EVENTS: SINK_RETURNS extends { EVENTS: infer EVENTS_RETURN } ? EVENTS_RETURN : RegisteredEvent;
|
|
71
138
|
LOG: SINK_RETURNS extends { LOG: infer LOG_RETURN } ? LOG_RETURN : any;
|
|
72
139
|
PARENT: SINK_RETURNS extends { PARENT: infer PARENT_RETURN } ? PARENT_RETURN : any;
|
|
73
140
|
}
|
|
@@ -149,7 +216,43 @@ type ComponentModel<STATE, PROPS, DRIVERS, ACTIONS, CALCULATED, SINK_RETURNS ext
|
|
|
149
216
|
>
|
|
150
217
|
}
|
|
151
218
|
|
|
219
|
+
type TrimSpaces<S extends string> =
|
|
220
|
+
S extends ` ${infer REST}` ? TrimSpaces<REST>
|
|
221
|
+
: S extends `${infer REST} ` ? TrimSpaces<REST>
|
|
222
|
+
: S
|
|
223
|
+
|
|
224
|
+
/** Value type produced by a PARENT sink value (a reducer's return, minus ABORT/undefined). */
|
|
225
|
+
type ParentSinkValueReturn<VALUE> =
|
|
226
|
+
VALUE extends (...args: any[]) => infer RETURN ? Exclude<RETURN, ABORT | undefined | void> : never
|
|
227
|
+
|
|
228
|
+
type ParentPayloadFromEntry<ENTRY> =
|
|
229
|
+
ENTRY extends (...args: any[]) => any ? never
|
|
230
|
+
: ENTRY extends object
|
|
231
|
+
? 'PARENT' extends keyof ENTRY ? ParentSinkValueReturn<NonNullable<ENTRY['PARENT']>> : never
|
|
232
|
+
: never
|
|
233
|
+
|
|
234
|
+
type ParentPayloadsOfModel<MODEL> = {
|
|
235
|
+
[ACTION_KEY in keyof MODEL]-?: ACTION_KEY extends `${string}|${infer SINK}`
|
|
236
|
+
? TrimSpaces<SINK> extends 'PARENT' ? ParentSinkValueReturn<NonNullable<MODEL[ACTION_KEY]>> : never
|
|
237
|
+
: ParentPayloadFromEntry<NonNullable<MODEL[ACTION_KEY]>>
|
|
238
|
+
}[keyof MODEL]
|
|
239
|
+
|
|
240
|
+
type AnyIfNever<T> = [T] extends [never] ? any : T
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* The value type a component sends to its parent through the `PARENT` sink, inferred from the
|
|
244
|
+
* component's `model` (object-form `{ PARENT: fn }` entries and `'ACTION | PARENT'` shorthand).
|
|
245
|
+
* Falls back to `any` when it can't be inferred (no model, a `Component<...>` annotation without
|
|
246
|
+
* a `PARENT` entry in its `SINK_RETURNS`, or `PARENT: true` pass-through entries only).
|
|
247
|
+
*/
|
|
248
|
+
export type ParentPayloadOf<COMPONENT> =
|
|
249
|
+
COMPONENT extends { model?: infer MODEL }
|
|
250
|
+
? 0 extends (1 & MODEL) ? any : AnyIfNever<ParentPayloadsOfModel<NonNullable<MODEL>>>
|
|
251
|
+
: any
|
|
252
|
+
|
|
152
253
|
type ChildSource = {
|
|
254
|
+
/** Typed: the stream type is inferred from the child's PARENT sink (falls back to `any`). */
|
|
255
|
+
select<COMPONENT extends (...args: any[]) => any>(component: COMPONENT): Stream<ParentPayloadOf<COMPONENT>>;
|
|
153
256
|
select<T = any>(component: (...args: any[]) => any): Stream<T>;
|
|
154
257
|
select<T = any>(name: string): Stream<T>;
|
|
155
258
|
}
|
|
@@ -158,9 +261,11 @@ export type SygnalDOMSource = MainDOMSource & {
|
|
|
158
261
|
[eventName: string]: (selector: string) => EnrichedEventStream<globalThis.Event>
|
|
159
262
|
}
|
|
160
263
|
|
|
161
|
-
|
|
162
|
-
select<T = any>(type: string): Stream<T>;
|
|
163
|
-
}
|
|
264
|
+
type EventsSelect = keyof SygnalEvents extends never
|
|
265
|
+
? { select<T = any>(type: string): Stream<T>; }
|
|
266
|
+
: { select<TYPE extends keyof SygnalEvents & string>(type: TYPE): Stream<SygnalEvents[TYPE]>; }
|
|
267
|
+
|
|
268
|
+
export type EventsSource<EVENTS = any> = Stream<Event<EVENTS>> & EventsSelect
|
|
164
269
|
|
|
165
270
|
export type DefaultDrivers<STATE, EVENTS = any> = {
|
|
166
271
|
STATE: {
|
|
@@ -217,6 +322,42 @@ export type FixDrivers<DRIVERS> =
|
|
|
217
322
|
|
|
218
323
|
type CombinedSources<STATE, DRIVERS> = Sources<DefaultDrivers<STATE> & DRIVERS> & { dispose$: Stream<boolean> }
|
|
219
324
|
|
|
325
|
+
/**
|
|
326
|
+
* The sources object an intent function receives (DOM, STATE, EVENTS, CHILD, dispose$, plus
|
|
327
|
+
* any custom drivers). Use it to annotate an intent declared before its component:
|
|
328
|
+
*
|
|
329
|
+
* const intent = ({ DOM }: IntentSources<State>) => ({ INC: DOM.click('.inc') })
|
|
330
|
+
*/
|
|
331
|
+
export type IntentSources<STATE = any, DRIVERS = {}> = CombinedSources<STATE, FixDrivers<DRIVERS>>
|
|
332
|
+
|
|
333
|
+
type StreamPayload<STREAM> = STREAM extends Stream<infer T> ? T : any
|
|
334
|
+
|
|
335
|
+
type IntentReturnToActions<RETURN> = {
|
|
336
|
+
[ACTION_KEY in keyof RETURN & string]-?: StreamPayload<Exclude<RETURN[ACTION_KEY], undefined>>
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Derives the ACTIONS map (action name → payload type) from an intent function's type
|
|
341
|
+
* (or from its return object type): each key's `Stream<T>` becomes `T`.
|
|
342
|
+
*
|
|
343
|
+
* const intent = ({ DOM }: IntentSources<State>) => ({
|
|
344
|
+
* INC: DOM.click('.inc').mapTo(1), // Stream<number>
|
|
345
|
+
* NAME: DOM.input('.name').value(), // Stream<string>
|
|
346
|
+
* })
|
|
347
|
+
* const Counter: Component<State, {}, {}, ActionsOf<typeof intent>> = ...
|
|
348
|
+
* Counter.intent = intent
|
|
349
|
+
* Counter.model = { INC: (state, n) => ..., NAME: (state, name) => ... } // n: number, name: string
|
|
350
|
+
*
|
|
351
|
+
* With it, model keys not returned by the intent are type errors (the built-ins BOOTSTRAP,
|
|
352
|
+
* INITIALIZE, HYDRATE and DISPOSE stay allowed). Actions reached only through `next()` are
|
|
353
|
+
* added explicitly:
|
|
354
|
+
*
|
|
355
|
+
* type Actions = ActionsOf<typeof intent> & { SAVED: { id: string } }
|
|
356
|
+
*/
|
|
357
|
+
export type ActionsOf<INTENT> = INTENT extends (...args: any[]) => infer RETURN
|
|
358
|
+
? IntentReturnToActions<RETURN>
|
|
359
|
+
: IntentReturnToActions<INTENT>
|
|
360
|
+
|
|
220
361
|
interface ComponentIntent<STATE, DRIVERS, ACTIONS> {
|
|
221
362
|
(args: CombinedSources<STATE, DRIVERS>): Partial<IntentActions<ACTIONS>>
|
|
222
363
|
}
|
|
@@ -267,6 +408,12 @@ export type Component<
|
|
|
267
408
|
model?: ComponentModel<STATE, PROPS, FixDrivers<DRIVERS>, ACTIONS, CALCULATED, SINK_RETURNS, CONTEXT>;
|
|
268
409
|
intent?: ComponentIntent<STATE & CALCULATED, FixDrivers<DRIVERS>, ACTIONS>;
|
|
269
410
|
initialState?: STATE;
|
|
411
|
+
/**
|
|
412
|
+
* Give a sub-component its own state instead of the slice its parent passes in.
|
|
413
|
+
* Required to use `initialState` on a sub-component (otherwise SYG405). Without a
|
|
414
|
+
* `state` prop the state is local to the instance and never written to the parent.
|
|
415
|
+
*/
|
|
416
|
+
isolatedState?: boolean;
|
|
270
417
|
calculated?: Calculated<STATE, CALCULATED>;
|
|
271
418
|
storeCalculatedInState?: boolean;
|
|
272
419
|
context?: Context<STATE & CALCULATED, CONTEXT>;
|
|
@@ -294,12 +441,37 @@ export type RootComponent<
|
|
|
294
441
|
*/
|
|
295
442
|
type AnyComponent = ((...args: any[]) => any) & Record<string, any>
|
|
296
443
|
|
|
297
|
-
|
|
444
|
+
/** Keys of STATE whose value is an array (optional/nullable arrays included). */
|
|
445
|
+
export type ArrayKeysOf<STATE> = {
|
|
446
|
+
[KEY in keyof STATE]-?: NonNullable<STATE[KEY]> extends ReadonlyArray<any> ? KEY : never
|
|
447
|
+
}[keyof STATE] & string
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Valid `from` values for a Collection: any string or Lense while the parent STATE is unknown
|
|
451
|
+
* (`any`); otherwise an array-valued key of STATE or a Lense over STATE.
|
|
452
|
+
*/
|
|
453
|
+
export type CollectionFrom<STATE = any> = 0 extends (1 & STATE)
|
|
454
|
+
? string | Lense
|
|
455
|
+
: ArrayKeysOf<STATE> | Lense<STATE, any>
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Collection props. Pass the parent component's state type as STATE to type-check `from`:
|
|
459
|
+
*
|
|
460
|
+
* const TaskCollection = Collection<{}, LaneState> // instantiation expression
|
|
461
|
+
* <TaskCollection of={TaskCard} from="tasks" /> // 'tasks' must be an array key of LaneState
|
|
462
|
+
*/
|
|
463
|
+
export type CollectionProps<PROPS = any, STATE = any> = {
|
|
298
464
|
of: AnyComponent;
|
|
299
|
-
from:
|
|
465
|
+
from: CollectionFrom<STATE>;
|
|
300
466
|
filter?: Filter;
|
|
301
467
|
sort?: string | SortFunction | SortObject;
|
|
302
|
-
|
|
468
|
+
/**
|
|
469
|
+
* Item field used as the key that tracks each item (its component instance, isolation
|
|
470
|
+
* scope and DOM) across updates. Items are keyed by `id` by default; keys should be
|
|
471
|
+
* unique and stable (an item without the field is keyed by its index).
|
|
472
|
+
*/
|
|
473
|
+
idfield?: string;
|
|
474
|
+
} & Omit<PROPS, 'of' | 'from' | 'filter' | 'sort' | 'idfield'>
|
|
303
475
|
|
|
304
476
|
export type SwitchableProps<PROPS = any> = {
|
|
305
477
|
of: Record<string, AnyComponent>;
|
|
@@ -319,6 +491,16 @@ export type TransitionProps = {
|
|
|
319
491
|
children?: any;
|
|
320
492
|
}
|
|
321
493
|
|
|
494
|
+
export type SuspenseProps = {
|
|
495
|
+
/**
|
|
496
|
+
* Shown (wrapped in `<div data-sygnal-suspense="pending">`) while any child is not ready:
|
|
497
|
+
* a `lazy()` component still loading, or a component with an explicit READY model entry
|
|
498
|
+
* that hasn't emitted true. A string renders as text. Without it the children render as-is.
|
|
499
|
+
*/
|
|
500
|
+
fallback?: JSX.Element | string;
|
|
501
|
+
children?: any;
|
|
502
|
+
}
|
|
503
|
+
|
|
322
504
|
export type SlotProps = {
|
|
323
505
|
name?: string;
|
|
324
506
|
children?: any;
|
|
@@ -326,12 +508,93 @@ export type SlotProps = {
|
|
|
326
508
|
|
|
327
509
|
export type ClassesType = (string | string[] | { [className: string]: boolean | undefined })[]
|
|
328
510
|
|
|
511
|
+
/**
|
|
512
|
+
* Diagnostics mode.
|
|
513
|
+
* - 'off' — no checks, no collection (default in production)
|
|
514
|
+
* - 'collect' — collect diagnostics silently (read with getDiagnostics())
|
|
515
|
+
* - 'warn' — collect and print warn/error diagnostics to the console (default in Vite dev)
|
|
516
|
+
* - 'error' — collect and throw on warn/error diagnostics
|
|
517
|
+
*/
|
|
518
|
+
export type DiagnosticsMode = 'off' | 'collect' | 'warn' | 'error'
|
|
519
|
+
|
|
520
|
+
/** Stable diagnostic code, e.g. 'SYG101'. See https://sygnal.js.org/reference/errors */
|
|
521
|
+
export type DiagnosticCode = `SYG${number}`
|
|
522
|
+
|
|
523
|
+
export type DiagnosticSeverity = 'error' | 'warn' | 'info'
|
|
524
|
+
|
|
525
|
+
export type Diagnostic = {
|
|
526
|
+
code: DiagnosticCode;
|
|
527
|
+
severity: DiagnosticSeverity;
|
|
528
|
+
/** Name of the component the diagnostic is about */
|
|
529
|
+
component?: string;
|
|
530
|
+
/** What is wrong */
|
|
531
|
+
message: string;
|
|
532
|
+
/** How to fix it */
|
|
533
|
+
fix?: string;
|
|
534
|
+
/** Structured payload (check-specific) */
|
|
535
|
+
data?: any;
|
|
536
|
+
/** Link to the docs entry for this code */
|
|
537
|
+
docsUrl: string;
|
|
538
|
+
/** Fully formatted message: `[Sygnal SYG123] Component: message. fix docsUrl` */
|
|
539
|
+
text: string;
|
|
540
|
+
timestamp: number;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export type DiagnosticsOptions = {
|
|
544
|
+
mode?: DiagnosticsMode;
|
|
545
|
+
/** Codes to ignore entirely */
|
|
546
|
+
ignore?: DiagnosticCode[];
|
|
547
|
+
}
|
|
548
|
+
|
|
329
549
|
export type RunOptions = {
|
|
330
550
|
mountPoint?: string;
|
|
331
551
|
fragments?: boolean;
|
|
332
552
|
useDefaultDrivers?: boolean;
|
|
553
|
+
/**
|
|
554
|
+
* Runtime diagnostics. Takes precedence over `globalThis.__SYGNAL_DEV__`
|
|
555
|
+
* (set by the Sygnal Vite plugin in dev), which enables 'warn'. Default: 'off'.
|
|
556
|
+
*/
|
|
557
|
+
diagnostics?: DiagnosticsMode | DiagnosticsOptions;
|
|
333
558
|
}
|
|
334
559
|
|
|
560
|
+
/** All diagnostics collected so far (most recent last). */
|
|
561
|
+
export function getDiagnostics(): Diagnostic[]
|
|
562
|
+
|
|
563
|
+
/** Clear the collected diagnostics. */
|
|
564
|
+
export function clearDiagnostics(): void
|
|
565
|
+
|
|
566
|
+
/** Subscribe to diagnostics as they are reported. Returns an unsubscribe function. */
|
|
567
|
+
export function onDiagnostic(callback: (diagnostic: Diagnostic) => void): () => void
|
|
568
|
+
|
|
569
|
+
export type {
|
|
570
|
+
InspectGraph,
|
|
571
|
+
InspectComponent,
|
|
572
|
+
InspectAction,
|
|
573
|
+
InspectActionTrigger,
|
|
574
|
+
InspectChild,
|
|
575
|
+
InspectSelector,
|
|
576
|
+
InspectDiagnostic,
|
|
577
|
+
} from './extra/diagnostics/checks/public'
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* The Sygnal DevTools bridge (also `window.__SYGNAL_DEVTOOLS__` once run() has
|
|
581
|
+
* initialized it in a browser). Only the stable, documented members are typed.
|
|
582
|
+
*/
|
|
583
|
+
export interface SygnalDevTools {
|
|
584
|
+
/** true while the browser extension is connected */
|
|
585
|
+
readonly connected: boolean
|
|
586
|
+
/** Diagnostics collected so far (same as getDiagnostics()) */
|
|
587
|
+
getDiagnostics(): Diagnostic[]
|
|
588
|
+
/**
|
|
589
|
+
* The machine-readable app graph of the live components. Present only when the
|
|
590
|
+
* 'sygnal/diagnostics' dev entry is loaded (it attaches this method); needs diagnostics on.
|
|
591
|
+
*/
|
|
592
|
+
inspect?(): InspectGraph
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** The DevTools bridge singleton. */
|
|
596
|
+
export function getDevTools(): SygnalDevTools | undefined
|
|
597
|
+
|
|
335
598
|
export type SygnalSinks<STATE = any, DRIVERS = {}> = {
|
|
336
599
|
[SINK_NAME in keyof (DefaultDrivers<STATE> & FixDrivers<DRIVERS>) | string]?: Stream<any>
|
|
337
600
|
}
|
|
@@ -406,16 +669,52 @@ export function set<S = any>(
|
|
|
406
669
|
*/
|
|
407
670
|
export function toggle<S = any>(field: keyof S & string): (state: S) => S
|
|
408
671
|
|
|
672
|
+
type EmitEntry<TYPE extends string> = keyof SygnalEvents extends never
|
|
673
|
+
? { EVENTS: (state: any, actionData: any, next: Function, props: any) => { type: string; data: any } }
|
|
674
|
+
: { EVENTS: (state: any, actionData: any, next: Function, props: any) => EmittedEvent<TYPE> }
|
|
675
|
+
|
|
409
676
|
/**
|
|
410
677
|
* Create a model entry that emits an EVENTS bus event.
|
|
678
|
+
* Prefer `event()` inside the object form: `ACTION: { EVENTS: event('TYPE', fn) }`.
|
|
411
679
|
*
|
|
412
680
|
* `emit('DELETE_LANE', (state) => ({ laneId: state.id }))`
|
|
413
681
|
* `emit('REFRESH')`
|
|
682
|
+
*
|
|
683
|
+
* With a `SygnalEvents` registry, `type` and the payload are checked against it.
|
|
414
684
|
*/
|
|
415
|
-
export function emit(
|
|
416
|
-
type:
|
|
417
|
-
data
|
|
418
|
-
):
|
|
685
|
+
export function emit<TYPE extends EventName>(
|
|
686
|
+
type: TYPE,
|
|
687
|
+
data: (state: any, actionData: any, next: Function, props: any) => EventPayload<TYPE>
|
|
688
|
+
): EmitEntry<TYPE>
|
|
689
|
+
export function emit<TYPE extends EventName>(
|
|
690
|
+
type: TYPE,
|
|
691
|
+
...data: StaticEventArgs<TYPE>
|
|
692
|
+
): EmitEntry<TYPE>
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Create an EVENTS sink function that puts `{ type, data }` on the EVENTS bus.
|
|
696
|
+
* Use it as the `EVENTS` value inside an object-form model entry:
|
|
697
|
+
*
|
|
698
|
+
* DELETE: {
|
|
699
|
+
* STATE: (state) => ({ ...state, deleting: true }),
|
|
700
|
+
* EVENTS: event('DELETE_LANE', (state) => ({ laneId: state.id })),
|
|
701
|
+
* }
|
|
702
|
+
*
|
|
703
|
+
* The payload is either a function `(state, data, next, props) => payload` or a static value:
|
|
704
|
+
* `event('RESET')`, `event('SET_MODE', 'dark')`.
|
|
705
|
+
*
|
|
706
|
+
* With a `SygnalEvents` registry, `type` must be a registered name and the payload must match
|
|
707
|
+
* its type. When used inside a model, the payload function's `state` and `data` parameters are
|
|
708
|
+
* typed from the component.
|
|
709
|
+
*/
|
|
710
|
+
export function event<TYPE extends EventName, STATE = any, DATA = any>(
|
|
711
|
+
type: TYPE,
|
|
712
|
+
payload: EventPayloadFunction<TYPE, STATE, DATA>
|
|
713
|
+
): EventSink<TYPE, STATE, DATA>
|
|
714
|
+
export function event<TYPE extends EventName>(
|
|
715
|
+
type: TYPE,
|
|
716
|
+
...payload: StaticEventArgs<TYPE>
|
|
717
|
+
): EventSink<TYPE>
|
|
419
718
|
|
|
420
719
|
/**
|
|
421
720
|
* Any object with an events() method (e.g., DOM.select('form')).
|
|
@@ -552,18 +851,43 @@ export function collection(...args: any[]): any
|
|
|
552
851
|
export function switchable(...args: any[]): any
|
|
553
852
|
export function portal(...args: any[]): any
|
|
554
853
|
|
|
555
|
-
export function Collection<PROPS extends { [prop: string]: any }>(props: CollectionProps<PROPS>): JSX.Element
|
|
854
|
+
export function Collection<PROPS extends { [prop: string]: any }, STATE = any>(props: CollectionProps<PROPS, STATE>): JSX.Element
|
|
556
855
|
export function Switchable<PROPS extends { [prop: string]: any }>(props: SwitchableProps<PROPS>): JSX.Element
|
|
557
856
|
export function Portal(props: PortalProps): JSX.Element
|
|
558
857
|
export function Transition(props: TransitionProps): JSX.Element
|
|
858
|
+
export function Suspense(props: SuspenseProps): JSX.Element
|
|
559
859
|
export function Slot(props: SlotProps): JSX.Element
|
|
560
860
|
|
|
861
|
+
/**
|
|
862
|
+
* What `lazy()` returns: a sub-component used in JSX with its own props only
|
|
863
|
+
* (`<Chart title="Sales" />`; `state` is optional, as for any sub-component), that
|
|
864
|
+
* still carries the component statics (`model`, `intent`, …) once loaded.
|
|
865
|
+
*/
|
|
866
|
+
export type LazyComponent<PROPS = any> = ((
|
|
867
|
+
props: PROPS & { state?: any; children?: JSX.Element | JSX.Element[] }
|
|
868
|
+
) => JSX.Element) & Omit<Component<any, PROPS>, never>
|
|
869
|
+
|
|
561
870
|
export function lazy<PROPS = any>(
|
|
562
871
|
loadFn: () => Promise<{ default: Component<any, PROPS> } | Component<any, PROPS>>
|
|
563
|
-
):
|
|
872
|
+
): LazyComponent<PROPS>
|
|
873
|
+
|
|
874
|
+
/** Payload on `errors()` of a driverFromAsync source when a request fails */
|
|
875
|
+
export type AsyncDriverError<INCOMING = any> = {
|
|
876
|
+
/** The rejection reason (or what `post` threw) */
|
|
877
|
+
error: any;
|
|
878
|
+
/** The request that failed */
|
|
879
|
+
request: INCOMING;
|
|
880
|
+
/** The request's selector property (default 'category') is copied here */
|
|
881
|
+
[selectorProperty: string]: any;
|
|
882
|
+
}
|
|
564
883
|
|
|
565
884
|
export type AsyncDriverFromFunction<INCOMING = any, OUTGOING = any> = {
|
|
566
885
|
select: (selector?: string | ((value: OUTGOING) => boolean)) => Stream<OUTGOING>
|
|
886
|
+
/**
|
|
887
|
+
* Failed requests (rejected promise, rejected/throwing `post`). Filters like
|
|
888
|
+
* `select()`. Failures are only console.error'd while nothing listens here.
|
|
889
|
+
*/
|
|
890
|
+
errors: (selector?: string | ((error: AsyncDriverError<INCOMING>) => boolean)) => Stream<AsyncDriverError<INCOMING>>
|
|
567
891
|
}
|
|
568
892
|
|
|
569
893
|
export type DriverFromAsyncOptions<INCOMING = any, OUTGOING = any, RETURN = any> = {
|
|
@@ -629,13 +953,43 @@ export interface InstallPrompt {
|
|
|
629
953
|
|
|
630
954
|
export function createInstallPrompt(): InstallPrompt
|
|
631
955
|
|
|
956
|
+
export interface SimulatedEventInit {
|
|
957
|
+
/** Merged into `event.target` (value, checked, dataset, ...) */
|
|
958
|
+
target?: Record<string, any>;
|
|
959
|
+
/** Shorthand for target.value */
|
|
960
|
+
value?: any;
|
|
961
|
+
/** Shorthand for target.checked */
|
|
962
|
+
checked?: boolean;
|
|
963
|
+
/** Merged into target.dataset (values become strings, like the DOM) */
|
|
964
|
+
dataset?: Record<string, any>;
|
|
965
|
+
/** Alias for dataset */
|
|
966
|
+
data?: Record<string, any>;
|
|
967
|
+
/** Keyboard key (e.key) */
|
|
968
|
+
key?: string;
|
|
969
|
+
/**
|
|
970
|
+
* Don't fail when the selector matches no rendered element: wait up to 300ms for it, then
|
|
971
|
+
* drop the event with SYG103 (info). Not copied onto the event.
|
|
972
|
+
*/
|
|
973
|
+
allowMissing?: boolean;
|
|
974
|
+
/** Any other event properties are copied onto the event */
|
|
975
|
+
[prop: string]: any;
|
|
976
|
+
}
|
|
977
|
+
|
|
632
978
|
export interface RenderOptions {
|
|
633
979
|
/** Override initial state (defaults to component's .initialState) */
|
|
634
980
|
initialState?: any;
|
|
635
981
|
/** Mock DOM configuration — maps selectors to event streams */
|
|
636
982
|
mockConfig?: Record<string, any>;
|
|
637
|
-
/** Additional drivers beyond DOM, EVENTS, STATE, and LOG */
|
|
983
|
+
/** Additional drivers beyond DOM, EVENTS, STATE, and LOG (model sinks without a driver get a no-op one) */
|
|
638
984
|
drivers?: Record<string, any>;
|
|
985
|
+
/**
|
|
986
|
+
* Diagnostics mode while rendered. Default: 'collect' (error-severity messages still print),
|
|
987
|
+
* or the current mode when diagnostics are already on. Restored when the last instance is
|
|
988
|
+
* disposed. Dev checks require `import 'sygnal/diagnostics'` (the Vite plugin adds it under Vitest).
|
|
989
|
+
*/
|
|
990
|
+
diagnostics?: DiagnosticsMode;
|
|
991
|
+
/** Enable strict (canonical-form) runtime checks while rendered (requires 'sygnal/diagnostics') */
|
|
992
|
+
strict?: boolean;
|
|
639
993
|
}
|
|
640
994
|
|
|
641
995
|
export interface RenderResult {
|
|
@@ -649,14 +1003,68 @@ export interface RenderResult {
|
|
|
649
1003
|
sinks: Record<string, any>;
|
|
650
1004
|
/** All source objects by driver name */
|
|
651
1005
|
sources: Record<string, any>;
|
|
652
|
-
/** Push an action
|
|
1006
|
+
/** Push an action into the intent→model pipeline under its real name (all sinks of the entry run) */
|
|
653
1007
|
simulateAction: (actionName: string, data?: any) => void;
|
|
654
|
-
/**
|
|
1008
|
+
/**
|
|
1009
|
+
* Dispatch a synthetic DOM event through the mock DOM source so the component's real intent
|
|
1010
|
+
* streams fire (DOM.click('.x'), DOM.select('.x').events('click'), .value(), .data()).
|
|
1011
|
+
* Targets the first rendered element matching `selector` and bubbles within its isolation scope.
|
|
1012
|
+
* Selectors match the rendered tree like the real DOM: tag, .class, #id, [attr], [attr="v"]
|
|
1013
|
+
* (^= $= *= ~=), :first-child, :last-child, :only-child, :nth-child(an+b|odd|even),
|
|
1014
|
+
* :nth-last-child(), :first/last/only/nth-of-type, :not(), descendant ' ' and child '>'
|
|
1015
|
+
* combinators, ',' lists. Other syntax (:has(), '+', '~', pseudo-elements...) throws.
|
|
1016
|
+
* If nothing matches yet, the event waits (up to 300ms, re-checked on every render) for a
|
|
1017
|
+
* matching element, then targets the first one. If none renders, the test fails with an
|
|
1018
|
+
* error naming the selector: it rejects the pending next()/waitForState()/settle(), or is
|
|
1019
|
+
* thrown by the next t.* call or dispose() (or by simulateEvent itself when nothing is
|
|
1020
|
+
* pending and the tree is quiet). Pass `{ allowMissing: true }` to drop the event with SYG103
|
|
1021
|
+
* instead. It is never sent to every listener with that selector string. It also waits until
|
|
1022
|
+
* the listeners it reaches are subscribed (a just-mounted child subscribes a few ms late).
|
|
1023
|
+
* `'document'` / `'body'` go to the DOM.select('document' | 'body') listeners.
|
|
1024
|
+
* simulateAction/simulateEvent calls are delivered in call order; a waiting event holds the
|
|
1025
|
+
* calls after it. Reports SYG104 (selector only matches inside a child component).
|
|
1026
|
+
*/
|
|
1027
|
+
simulateEvent: (selector: string, eventType: string, eventInit?: SimulatedEventInit) => void;
|
|
1028
|
+
/** Resolves once the component is subscribed (earlier simulate* calls are buffered and replayed) */
|
|
1029
|
+
ready: () => Promise<void>;
|
|
1030
|
+
/**
|
|
1031
|
+
* Wait for a state that satisfies the predicate. Matches the recorded HISTORY too: a state
|
|
1032
|
+
* from before the call resolves it (e.g. `count === 0` right after a reset resolves at once
|
|
1033
|
+
* with the initial state). Resolves with the matching state once the whole tree (children
|
|
1034
|
+
* included) has rendered it. Use `next()` to wait for a new state.
|
|
1035
|
+
*/
|
|
655
1036
|
waitForState: (predicate: (state: any) => boolean, timeoutMs?: number) => Promise<any>;
|
|
1037
|
+
/**
|
|
1038
|
+
* Wait for the next state emitted AFTER this call that satisfies the predicate (default: any
|
|
1039
|
+
* state). Resolves with it once the whole tree (children included) has rendered it; rejects
|
|
1040
|
+
* after timeoutMs (default 2000).
|
|
1041
|
+
*/
|
|
1042
|
+
next: (predicate?: (state: any) => boolean, timeoutMs?: number) => Promise<any>;
|
|
1043
|
+
/**
|
|
1044
|
+
* Resolves once nothing is pending: the component is ready, no simulated input is waiting,
|
|
1045
|
+
* and nothing in the tree has rendered, reduced or changed state for 20ms (longer than
|
|
1046
|
+
* next()'s default delay). Rejects after timeoutMs (default 2000) if it never calms down.
|
|
1047
|
+
*/
|
|
1048
|
+
settle: (timeoutMs?: number) => Promise<void>;
|
|
656
1049
|
/** Collected state values — grows as new states are emitted */
|
|
657
1050
|
states: any[];
|
|
658
|
-
/**
|
|
1051
|
+
/** Live array of values emitted on a sink (EVENTS as {type, data}, PARENT unwrapped, custom drivers) */
|
|
1052
|
+
sinkValues: (sinkName: string) => any[];
|
|
1053
|
+
/** Live array of EVENTS sink emissions ({type, data}) */
|
|
1054
|
+
emitted: Array<{ type: string; data: any }>;
|
|
1055
|
+
/** Live array of diagnostics reported while rendered */
|
|
1056
|
+
diagnostics: Diagnostic[];
|
|
1057
|
+
/** Throws (with the formatted texts) if any warn/error diagnostics were collected */
|
|
1058
|
+
expectNoDiagnostics: () => void;
|
|
1059
|
+
/** Latest rendered VNode serialized to HTML ('' before the first render) */
|
|
1060
|
+
html: () => string;
|
|
1061
|
+
/** Tear down the component, clean up listeners and restore the diagnostics mode */
|
|
659
1062
|
dispose: () => void;
|
|
1063
|
+
/**
|
|
1064
|
+
* The app graph of the rendered tree (components, actions, selectors with the mock DOM's
|
|
1065
|
+
* match / isolation results, EVENTS, diagnostics). Throws unless 'sygnal/diagnostics' is loaded.
|
|
1066
|
+
*/
|
|
1067
|
+
inspect: () => InspectGraph;
|
|
660
1068
|
}
|
|
661
1069
|
|
|
662
1070
|
export function renderComponent(componentDef: any, options?: RenderOptions): RenderResult
|
|
@@ -688,6 +1096,9 @@ export { default as throttle } from 'xstream/extra/throttle.js'
|
|
|
688
1096
|
export { default as delay } from 'xstream/extra/delay.js'
|
|
689
1097
|
export { default as dropRepeats } from 'xstream/extra/dropRepeats.js'
|
|
690
1098
|
export { default as sampleCombine } from 'xstream/extra/sampleCombine.js'
|
|
1099
|
+
export { default as flattenConcurrently } from 'xstream/extra/flattenConcurrently.js'
|
|
1100
|
+
export { default as flattenSequentially } from 'xstream/extra/flattenSequentially.js'
|
|
1101
|
+
export { default as concat } from 'xstream/extra/concat.js'
|
|
691
1102
|
|
|
692
1103
|
export * from './cycle/dom/index'
|
|
693
1104
|
export type { MemoryStream, Stream }
|
package/src/index.ts
CHANGED
|
@@ -21,18 +21,19 @@ export { createElement } from './pragma/index'
|
|
|
21
21
|
export { createCommand } from './extra/command'
|
|
22
22
|
export { createRef, createRef$ } from './extra/ref'
|
|
23
23
|
export { renderComponent } from './extra/testing'
|
|
24
|
-
export { set, toggle, emit } from './extra/reducers'
|
|
24
|
+
export { set, toggle, emit, event } from './extra/reducers'
|
|
25
25
|
export { makeServiceWorkerDriver, onlineStatus$, createInstallPrompt } from './extra/pwa'
|
|
26
26
|
export { renderToString } from './extra/ssr'
|
|
27
27
|
export { default as xs } from './extra/xstreamCompat'
|
|
28
28
|
export { getDevTools } from './extra/devtools'
|
|
29
|
+
export { getDiagnostics, clearDiagnostics, onDiagnostic } from './extra/diagnostics/index'
|
|
29
30
|
|
|
30
31
|
// export dom helper functions (h, makeDOMDriver, etc.)
|
|
31
32
|
export * from './cycle/dom/index'
|
|
32
33
|
|
|
33
34
|
// export xstream and most used extra operators
|
|
34
|
-
|
|
35
|
-
export { default
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
export {
|
|
35
|
+
// ESM ports of xstream/extra/* (behaviour-identical). The CJS originals are not callable from
|
|
36
|
+
// the rollup CJS build or native Node ESM (their default export is `{ default: fn }` there),
|
|
37
|
+
// and ESM classes tree-shake when an app does not use them.
|
|
38
|
+
export { concat, debounce, throttle, delay, dropRepeats, sampleCombine } from './extra/xstreamExtras'
|
|
39
|
+
export { flattenConcurrently, flattenSequentially } from './extra/flatten'
|
package/src/pragma/index.ts
CHANGED
|
@@ -166,9 +166,12 @@ export const createElementWithModules = (modules: Record<string, any>) => {
|
|
|
166
166
|
return (sel: any, data: any, ...children: any[]) => {
|
|
167
167
|
if (typeof sel === 'undefined') {
|
|
168
168
|
sel = 'UNDEFINED'
|
|
169
|
-
|
|
169
|
+
// Pre-formatted (formatDiagnostic output) instead of diagnostics/legacy: the JSX
|
|
170
|
+
// runtime entries bundle this file standalone and must not carry a second diagnostics core.
|
|
171
|
+
console.error('[Sygnal SYG420] JSX: A JSX tag is undefined, so <UNDEFINED> is rendered instead. Import or define the component in this file. https://sygnal.js.org/reference/errors#syg420')
|
|
170
172
|
}
|
|
171
|
-
|
|
173
|
+
const isComponent = is.fun(sel)
|
|
174
|
+
if (isComponent) {
|
|
172
175
|
if ((sel as any).__sygnalFragment || sel.name === 'Fragment') {
|
|
173
176
|
return sel(data || {}, children)
|
|
174
177
|
}
|
|
@@ -178,13 +181,12 @@ export const createElementWithModules = (modules: Record<string, any>) => {
|
|
|
178
181
|
const view = sel
|
|
179
182
|
const { model, intent, hmrActions, context, peers, components, initialState, isolatedState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, onError, debug, preventInstantiation } = sel as any
|
|
180
183
|
if (preventInstantiation) {
|
|
181
|
-
|
|
182
|
-
const sanitized = data ? sanitizeData(data, modules) : {}
|
|
184
|
+
// children always stay an array here: Portal/Suspense/... read vnode.children
|
|
183
185
|
return considerSvg({
|
|
184
186
|
sel: name,
|
|
185
|
-
data:
|
|
186
|
-
children:
|
|
187
|
-
text,
|
|
187
|
+
data: data ? sanitizeData(data, modules) : {},
|
|
188
|
+
children: sanitizeChildren(children),
|
|
189
|
+
text: undefined,
|
|
188
190
|
elm: undefined,
|
|
189
191
|
key: data ? data.key : undefined
|
|
190
192
|
})
|
|
@@ -198,11 +200,14 @@ export const createElementWithModules = (modules: Record<string, any>) => {
|
|
|
198
200
|
data.sygnalFactory = factory
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
|
-
|
|
203
|
+
// B-011: a vnode is either text-only (`text`, no children) or has a children array,
|
|
204
|
+
// never both; snabbdom's diff mishandles a vnode with both. A component placeholder
|
|
205
|
+
// keeps an array so the component receives its text child via `children`.
|
|
206
|
+
const text = isComponent ? undefined : sanitizeText(children)
|
|
202
207
|
return considerSvg({
|
|
203
208
|
sel,
|
|
204
209
|
data: data ? sanitizeData(data, modules) : {},
|
|
205
|
-
children: typeof text !== 'undefined' ?
|
|
210
|
+
children: typeof text !== 'undefined' ? undefined : sanitizeChildren(children),
|
|
206
211
|
text,
|
|
207
212
|
elm: undefined,
|
|
208
213
|
key: data ? data.key : undefined
|