sygnal 2.9.2 → 2.9.4
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/dist/index.cjs.js +92 -59
- package/dist/index.esm.js +92 -59
- package/dist/sygnal.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -3158,7 +3158,7 @@ const ABORT = '~#~#~ABORT~#~#~';
|
|
|
3158
3158
|
function component (opts) {
|
|
3159
3159
|
const { name, sources, isolateOpts, stateSourceName='STATE' } = opts;
|
|
3160
3160
|
|
|
3161
|
-
if (sources &&
|
|
3161
|
+
if (sources && !isObj(sources)) {
|
|
3162
3162
|
throw new Error('Sources must be a Cycle.js sources object:', name)
|
|
3163
3163
|
}
|
|
3164
3164
|
|
|
@@ -3176,7 +3176,7 @@ function component (opts) {
|
|
|
3176
3176
|
const currySources = typeof sources === 'undefined';
|
|
3177
3177
|
let returnFunction;
|
|
3178
3178
|
|
|
3179
|
-
if (
|
|
3179
|
+
if (isObj(fixedIsolateOpts)) {
|
|
3180
3180
|
const wrapped = (sources) => {
|
|
3181
3181
|
const fixedOpts = { ...opts, sources };
|
|
3182
3182
|
return (new Component(fixedOpts)).sinks
|
|
@@ -3240,7 +3240,7 @@ class Component {
|
|
|
3240
3240
|
// sinks
|
|
3241
3241
|
|
|
3242
3242
|
constructor({ name='NO NAME', sources, intent, request, model, context, response, view, children={}, components={}, initialState, calculated, storeCalculatedInState=true, DOMSourceName='DOM', stateSourceName='STATE', requestSourceName='HTTP', debug=false }) {
|
|
3243
|
-
if (!sources ||
|
|
3243
|
+
if (!sources || !isObj(sources)) throw new Error('Missing or invalid sources')
|
|
3244
3244
|
|
|
3245
3245
|
this.name = name;
|
|
3246
3246
|
this.sources = sources;
|
|
@@ -3320,7 +3320,7 @@ class Component {
|
|
|
3320
3320
|
|
|
3321
3321
|
this.intent$ = this.intent(this.sources);
|
|
3322
3322
|
|
|
3323
|
-
if (!(this.intent$ instanceof xs$1.Stream) && (
|
|
3323
|
+
if (!(this.intent$ instanceof xs$1.Stream) && (!isObj(this.intent$))) {
|
|
3324
3324
|
throw new Error('Intent must return either an action$ stream or map of event streams')
|
|
3325
3325
|
}
|
|
3326
3326
|
}
|
|
@@ -3364,7 +3364,7 @@ class Component {
|
|
|
3364
3364
|
initResponse$() {
|
|
3365
3365
|
if (typeof this.request == 'undefined') {
|
|
3366
3366
|
return
|
|
3367
|
-
} else if (
|
|
3367
|
+
} else if (!isObj(this.request)) {
|
|
3368
3368
|
throw new Error('The request parameter must be an object')
|
|
3369
3369
|
}
|
|
3370
3370
|
|
|
@@ -3469,29 +3469,16 @@ class Component {
|
|
|
3469
3469
|
this.context$ = xs$1.of({});
|
|
3470
3470
|
return
|
|
3471
3471
|
}
|
|
3472
|
-
const repeatChecker = (a, b) => {
|
|
3473
|
-
if (a === b) return true
|
|
3474
|
-
if (typeof a !== 'object' || typeof b !== 'object') {
|
|
3475
|
-
return a === b
|
|
3476
|
-
}
|
|
3477
|
-
const entriesA = Object.entries(a);
|
|
3478
|
-
const entriesB = Object.entries(b);
|
|
3479
|
-
if (entriesA.length === 0 && entriesB.length === 0) return true
|
|
3480
|
-
if (entriesA.length !== entriesB.length) return false
|
|
3481
|
-
return entriesA.every(([name, value]) => {
|
|
3482
|
-
return b[name] === value
|
|
3483
|
-
})
|
|
3484
|
-
};
|
|
3485
3472
|
|
|
3486
|
-
const state$ = this.sources[this.stateSourceName]?.stream.startWith({}).compose(_default$5(
|
|
3487
|
-
const parentContext$ = this.sources.__parentContext$.startWith({}).compose(_default$5(
|
|
3488
|
-
if (this.context &&
|
|
3473
|
+
const state$ = this.sources[this.stateSourceName]?.stream.startWith({}).compose(_default$5(objIsEqual)) || xs$1.never();
|
|
3474
|
+
const parentContext$ = this.sources.__parentContext$.startWith({}).compose(_default$5(objIsEqual)) || xs$1.of({});
|
|
3475
|
+
if (this.context && !isObj(this.context)) {
|
|
3489
3476
|
console.error(`[${this.name}] Context must be an object mapping names to values of functions: ignoring provided ${ typeof this.context }`);
|
|
3490
3477
|
}
|
|
3491
3478
|
this.context$ = xs$1.combine(state$, parentContext$)
|
|
3492
3479
|
.map(([_, parent]) => {
|
|
3493
|
-
const _parent =
|
|
3494
|
-
const context =
|
|
3480
|
+
const _parent = isObj(parent) ? parent : {};
|
|
3481
|
+
const context = isObj(this.context) ? this.context : {};
|
|
3495
3482
|
const state = this.currentState;
|
|
3496
3483
|
const values = Object.entries(context).reduce((acc, current) => {
|
|
3497
3484
|
const [name, value] = current;
|
|
@@ -3514,7 +3501,7 @@ class Component {
|
|
|
3514
3501
|
this.currentContext = newContext;
|
|
3515
3502
|
return newContext
|
|
3516
3503
|
})
|
|
3517
|
-
.compose(_default$5(
|
|
3504
|
+
.compose(_default$5(objIsEqual))
|
|
3518
3505
|
.startWith({});
|
|
3519
3506
|
this.context$.subscribe({ next: _ => _ });
|
|
3520
3507
|
}
|
|
@@ -3548,7 +3535,7 @@ class Component {
|
|
|
3548
3535
|
sinks = { [this.stateSourceName]: sinks };
|
|
3549
3536
|
}
|
|
3550
3537
|
|
|
3551
|
-
if (
|
|
3538
|
+
if (!isObj(sinks)) {
|
|
3552
3539
|
throw new Error(`Entry for each action must be an object: ${ this.name } ${ action }`)
|
|
3553
3540
|
}
|
|
3554
3541
|
|
|
@@ -3614,7 +3601,7 @@ class Component {
|
|
|
3614
3601
|
};
|
|
3615
3602
|
|
|
3616
3603
|
const out = this.response(selectable);
|
|
3617
|
-
if (
|
|
3604
|
+
if (!isObj(out)) {
|
|
3618
3605
|
throw new Error('The response function must return an object')
|
|
3619
3606
|
}
|
|
3620
3607
|
|
|
@@ -3726,7 +3713,7 @@ class Component {
|
|
|
3726
3713
|
const next = (type, data, delay=10) => {
|
|
3727
3714
|
if (typeof delay !== 'number') throw new Error(`[${ this.name } ] Invalid delay value provided to next() function in model action '${ name }'. Must be a number in ms.`)
|
|
3728
3715
|
const _reqId = action._reqId || (action.req && action.req.id);
|
|
3729
|
-
const _data = _reqId ? (
|
|
3716
|
+
const _data = _reqId ? (isObj(data) ? { ...data, _reqId, _action: name } : { data, _reqId, _action: name }) : data;
|
|
3730
3717
|
// put the "next" action request at the end of the event loop so the "current" action completes first
|
|
3731
3718
|
setTimeout(() => {
|
|
3732
3719
|
// push the "next" action request into the action$ stream
|
|
@@ -3751,7 +3738,7 @@ class Component {
|
|
|
3751
3738
|
const type = typeof reduced;
|
|
3752
3739
|
const _reqId = action._reqId || (action.req && action.req.id);
|
|
3753
3740
|
if (['string', 'number', 'boolean', 'function'].includes(type)) return reduced
|
|
3754
|
-
if (
|
|
3741
|
+
if (isObj(reduced)) return { ...reduced, _reqId, _action: name }
|
|
3755
3742
|
if (type == 'undefined') {
|
|
3756
3743
|
console.warn(`'undefined' value sent to ${ name }`);
|
|
3757
3744
|
return reduced
|
|
@@ -3775,11 +3762,11 @@ class Component {
|
|
|
3775
3762
|
let lastResult;
|
|
3776
3763
|
|
|
3777
3764
|
return function(state) {
|
|
3778
|
-
if (!this.calculated ||
|
|
3765
|
+
if (!this.calculated || !isObj(state) || Array.isArray(state)) return state
|
|
3779
3766
|
if (state === lastState) {
|
|
3780
3767
|
return lastResult
|
|
3781
3768
|
}
|
|
3782
|
-
if (
|
|
3769
|
+
if (!isObj(this.calculated)) throw new Error(`'calculated' parameter must be an object mapping calculated state field named to functions`)
|
|
3783
3770
|
const entries = Object.entries(this.calculated);
|
|
3784
3771
|
if (entries.length === 0) {
|
|
3785
3772
|
lastState = state;
|
|
@@ -3806,7 +3793,7 @@ class Component {
|
|
|
3806
3793
|
}
|
|
3807
3794
|
|
|
3808
3795
|
cleanupCalculated(incomingState) {
|
|
3809
|
-
if (!incomingState ||
|
|
3796
|
+
if (!incomingState || !isObj(incomingState) || Array.isArray(incomingState)) return incomingState
|
|
3810
3797
|
const state = this.storeCalculatedInState ? this.addCalculated(incomingState) : incomingState;
|
|
3811
3798
|
const { __props, __children, __context, ...sanitized } = state;
|
|
3812
3799
|
const copy = { ...sanitized };
|
|
@@ -3967,20 +3954,42 @@ class Component {
|
|
|
3967
3954
|
const data = el.data;
|
|
3968
3955
|
const props = data.props || {};
|
|
3969
3956
|
el.children || [];
|
|
3957
|
+
let filter = typeof props.filter === 'function' ? props.filter : _ => true;
|
|
3970
3958
|
|
|
3971
3959
|
const combined$ = xs$1.combine(this.sources[this.stateSourceName].stream.startWith(this.currentState), props$, children$)
|
|
3972
3960
|
.map(([state, __props, __children]) => {
|
|
3973
|
-
|
|
3961
|
+
if (__props.filter && typeof __props.filter === 'function') {
|
|
3962
|
+
filter = __props.filter;
|
|
3963
|
+
}
|
|
3964
|
+
return isObj(state) ? { ...this.addCalculated(state), __props, __children, __context: this.currentContext } : { value: state, __props, __children, __context: this.currentContext }
|
|
3974
3965
|
});
|
|
3975
3966
|
|
|
3976
|
-
const stateSource
|
|
3977
|
-
const stateField
|
|
3967
|
+
const stateSource = new state.StateSource(combined$);
|
|
3968
|
+
const stateField = props.from;
|
|
3969
|
+
const collectionOf = props.of;
|
|
3970
|
+
const idField = props.idfield || 'id';
|
|
3971
|
+
|
|
3978
3972
|
let lense;
|
|
3973
|
+
let factory;
|
|
3979
3974
|
|
|
3980
|
-
|
|
3975
|
+
if (typeof collectionOf === 'function') {
|
|
3976
|
+
if (collectionOf.isSygnalComponent) {
|
|
3977
|
+
factory = collectionOf;
|
|
3978
|
+
} else {
|
|
3979
|
+
const name = (typeof collectionOf.name === 'string') ? collectionOf.name : 'FUNCTION_COMPONENT';
|
|
3980
|
+
const view = collectionOf;
|
|
3981
|
+
const { model, intent, context, children, components, initialState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, debug } = collectionOf;
|
|
3982
|
+
const options = { name, view, model, intent, context, children, components, initialState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, debug };
|
|
3983
|
+
factory = component(options);
|
|
3984
|
+
}
|
|
3985
|
+
} else if (this.components[collectionOf]) {
|
|
3986
|
+
factory = this.components[collectionOf];
|
|
3987
|
+
} else {
|
|
3988
|
+
throw new Error(`[${this.name}] Invalid 'of' propery in collection: ${ collectionOf }`)
|
|
3989
|
+
}
|
|
3981
3990
|
|
|
3982
3991
|
const sanitizeItems = item => {
|
|
3983
|
-
if (
|
|
3992
|
+
if (isObj(item)) {
|
|
3984
3993
|
const { __props, __children, __context, ...sanitized } = item;
|
|
3985
3994
|
return sanitized
|
|
3986
3995
|
} else {
|
|
@@ -3992,8 +4001,8 @@ class Component {
|
|
|
3992
4001
|
get: state => {
|
|
3993
4002
|
const { __props, __children } = state;
|
|
3994
4003
|
if (!Array.isArray(state[stateField])) return []
|
|
3995
|
-
return state[stateField].map(item => {
|
|
3996
|
-
return
|
|
4004
|
+
return state[stateField].filter(filter).map((item, index) => {
|
|
4005
|
+
return (isObj(item)) ? { ...item, [idField]: item[idField] || index, __props, __children, __context: this.currentContext } : { value: item, [idField]: index, __props, __children, __context: this.currentContext }
|
|
3997
4006
|
})
|
|
3998
4007
|
},
|
|
3999
4008
|
set: (oldState, newState) => {
|
|
@@ -4001,6 +4010,15 @@ class Component {
|
|
|
4001
4010
|
console.warn(`Collection sub-component of ${ this.name } attempted to update state on a calculated field '${ stateField }': Update ignored`);
|
|
4002
4011
|
return oldState
|
|
4003
4012
|
}
|
|
4013
|
+
const updated = [];
|
|
4014
|
+
for (const oldItem of oldState[stateField].map((item, index) => ({ __primitive: true, value: item, [idField]: index }))) {
|
|
4015
|
+
if (!filter(oldItem)) {
|
|
4016
|
+
updated.push(oldItem.__primitive ? oldItem.value : oldItem);
|
|
4017
|
+
} else {
|
|
4018
|
+
const newItem = newState.find(newItem => newItem.id === oldItem.id);
|
|
4019
|
+
if (typeof newItem !== 'undefined') updated.push(oldItem.__primitive ? newItem.value : newItem);
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4004
4022
|
return { ...oldState, [stateField]: newState.map(sanitizeItems) }
|
|
4005
4023
|
}
|
|
4006
4024
|
};
|
|
@@ -4016,7 +4034,7 @@ class Component {
|
|
|
4016
4034
|
}
|
|
4017
4035
|
};
|
|
4018
4036
|
} else if (typeof stateField === 'string') {
|
|
4019
|
-
if (
|
|
4037
|
+
if (isObj(this.currentState)) {
|
|
4020
4038
|
if(!(this.currentState && stateField in this.currentState) && !(this.calculated && stateField in this.calculated)) {
|
|
4021
4039
|
console.error(`Collection component in ${ this.name } is attempting to use non-existent state property '${ stateField }': To fix this error, specify a valid array property on the state. Attempting to use parent component state.`);
|
|
4022
4040
|
lense = undefined;
|
|
@@ -4034,7 +4052,7 @@ class Component {
|
|
|
4034
4052
|
lense = fieldLense;
|
|
4035
4053
|
}
|
|
4036
4054
|
}
|
|
4037
|
-
} else if (
|
|
4055
|
+
} else if (isObj(stateField)) {
|
|
4038
4056
|
if (typeof stateField.get !== 'function') {
|
|
4039
4057
|
console.error(`Collection component in ${ this.name } has an invalid 'from' field: Expecting 'undefined', a string indicating an array property in the state, or an object with 'get' and 'set' functions for retrieving and setting child state from the current state. Attempting to use parent component state.`);
|
|
4040
4058
|
lense = undefined;
|
|
@@ -4058,7 +4076,7 @@ class Component {
|
|
|
4058
4076
|
|
|
4059
4077
|
const sources = { ...this.sources, [this.stateSourceName]: stateSource, props$, children$, __parentContext$: this.context$ };
|
|
4060
4078
|
const sink$ = collection(factory, lense, { container: null })(sources);
|
|
4061
|
-
if (
|
|
4079
|
+
if (!isObj(sink$)) {
|
|
4062
4080
|
throw new Error('Invalid sinks returned from component factory of collection element')
|
|
4063
4081
|
}
|
|
4064
4082
|
return sink$
|
|
@@ -4071,7 +4089,7 @@ class Component {
|
|
|
4071
4089
|
|
|
4072
4090
|
const combined$ = xs$1.combine(this.sources[this.stateSourceName].stream.startWith(this.currentState), props$, children$)
|
|
4073
4091
|
.map(([state, __props, __children]) => {
|
|
4074
|
-
return
|
|
4092
|
+
return isObj(state) ? { ...this.addCalculated(state), __props, __children, __context: this.currentContext } : { value: state, __props, __children, __context: this.currentContext }
|
|
4075
4093
|
});
|
|
4076
4094
|
|
|
4077
4095
|
const stateSource = new state.StateSource(combined$);
|
|
@@ -4081,14 +4099,14 @@ class Component {
|
|
|
4081
4099
|
const fieldLense = {
|
|
4082
4100
|
get: state => {
|
|
4083
4101
|
const { __props, __children } = state;
|
|
4084
|
-
return (
|
|
4102
|
+
return (isObj(state[stateField])) ? { ...state[stateField], __props, __children, __context: this.currentContext } : { value: state[stateField], __props, __children, __context: this.currentContext }
|
|
4085
4103
|
},
|
|
4086
4104
|
set: (oldState, newState) => {
|
|
4087
4105
|
if (this.calculated && stateField in this.calculated) {
|
|
4088
4106
|
console.warn(`Switchable sub-component of ${ this.name } attempted to update state on a calculated field '${ stateField }': Update ignored`);
|
|
4089
4107
|
return oldState
|
|
4090
4108
|
}
|
|
4091
|
-
if (
|
|
4109
|
+
if (!isObj(newState) || Array.isArray(newState)) return { ...oldState, [stateField]: newState }
|
|
4092
4110
|
const { __props, __children, __context, ...sanitized } = newState;
|
|
4093
4111
|
return { ...oldState, [stateField]: sanitized }
|
|
4094
4112
|
}
|
|
@@ -4097,7 +4115,7 @@ class Component {
|
|
|
4097
4115
|
const baseLense = {
|
|
4098
4116
|
get: state => state,
|
|
4099
4117
|
set: (oldState, newState) => {
|
|
4100
|
-
if (
|
|
4118
|
+
if (!isObj(newState) || Array.isArray(newState)) return newState
|
|
4101
4119
|
const { __props, __children, __context, ...sanitized } = newState;
|
|
4102
4120
|
return sanitized
|
|
4103
4121
|
}
|
|
@@ -4107,7 +4125,7 @@ class Component {
|
|
|
4107
4125
|
lense = baseLense;
|
|
4108
4126
|
} else if (typeof stateField === 'string') {
|
|
4109
4127
|
lense = fieldLense;
|
|
4110
|
-
} else if (
|
|
4128
|
+
} else if (isObj(stateField)) {
|
|
4111
4129
|
if (typeof stateField.get !== 'function') {
|
|
4112
4130
|
console.error(`Switchable component in ${ this.name } has an invalid 'state' field: Expecting 'undefined', a string indicating an array property in the state, or an object with 'get' and 'set' functions for retrieving and setting sub-component state from the current state. Attempting to use parent component state.`);
|
|
4113
4131
|
lense = baseLense;
|
|
@@ -4120,11 +4138,22 @@ class Component {
|
|
|
4120
4138
|
}
|
|
4121
4139
|
|
|
4122
4140
|
const switchableComponents = props.of;
|
|
4141
|
+
const keys = Object.keys(switchableComponents);
|
|
4142
|
+
keys.forEach(key => {
|
|
4143
|
+
const current = switchableComponents[key];
|
|
4144
|
+
if (!current.isSygnalComponent) {
|
|
4145
|
+
const name = (typeof current.name === 'string') ? current.name : 'FUNCTION_COMPONENT';
|
|
4146
|
+
const view = current;
|
|
4147
|
+
const { model, intent, context, children, components, initialState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, debug } = current;
|
|
4148
|
+
const options = { name, view, model, intent, context, children, components, initialState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, debug };
|
|
4149
|
+
switchableComponents[key] = component(options);
|
|
4150
|
+
}
|
|
4151
|
+
});
|
|
4123
4152
|
const sources = { ...this.sources, [this.stateSourceName]: stateSource, props$, children$, __parentContext$: this.context$ };
|
|
4124
4153
|
|
|
4125
4154
|
const sink$ = isolate(switchable(switchableComponents, props$.map(props => props.current)), { [this.stateSourceName]: lense })(sources);
|
|
4126
4155
|
|
|
4127
|
-
if (
|
|
4156
|
+
if (!isObj(sink$)) {
|
|
4128
4157
|
throw new Error('Invalid sinks returned from component factory of switchable element')
|
|
4129
4158
|
}
|
|
4130
4159
|
|
|
@@ -4139,13 +4168,13 @@ class Component {
|
|
|
4139
4168
|
|
|
4140
4169
|
const combined$ = xs$1.combine(this.sources[this.stateSourceName].stream.startWith(this.currentState), props$, children$)
|
|
4141
4170
|
.map(([state, __props, __children]) => {
|
|
4142
|
-
return
|
|
4171
|
+
return isObj(state) ? { ...this.addCalculated(state), __props, __children, __context: this.currentContext } : { value: state, __props, __children, __context: this.currentContext }
|
|
4143
4172
|
});
|
|
4144
4173
|
|
|
4145
4174
|
const stateSource = new state.StateSource(combined$);
|
|
4146
4175
|
const stateField = props.state;
|
|
4147
4176
|
|
|
4148
|
-
if (typeof props.sygnalFactory !== 'function' &&
|
|
4177
|
+
if (typeof props.sygnalFactory !== 'function' && isObj(props.sygnalOptions)) {
|
|
4149
4178
|
props.sygnalFactory = component(props.sygnalOptions);
|
|
4150
4179
|
}
|
|
4151
4180
|
|
|
@@ -4160,7 +4189,7 @@ class Component {
|
|
|
4160
4189
|
const fieldLense = {
|
|
4161
4190
|
get: state => {
|
|
4162
4191
|
const { __props, __children } = state;
|
|
4163
|
-
return
|
|
4192
|
+
return isObj(state[stateField]) ? { ...state[stateField], __props, __children, __context: this.currentContext } : { value: state[stateField], __props, __children, __context: this.currentContext }
|
|
4164
4193
|
},
|
|
4165
4194
|
set: (oldState, newState) => {
|
|
4166
4195
|
if (this.calculated && stateField in this.calculated) {
|
|
@@ -4174,7 +4203,7 @@ class Component {
|
|
|
4174
4203
|
const baseLense = {
|
|
4175
4204
|
get: state => state,
|
|
4176
4205
|
set: (oldState, newState) => {
|
|
4177
|
-
if (
|
|
4206
|
+
if (!isObj(newState) || Array.isArray(newState)) return newState
|
|
4178
4207
|
const { __props, __children, __context, ...sanitized } = newState;
|
|
4179
4208
|
return sanitized
|
|
4180
4209
|
}
|
|
@@ -4184,7 +4213,7 @@ class Component {
|
|
|
4184
4213
|
lense = baseLense;
|
|
4185
4214
|
} else if (typeof stateField === 'string') {
|
|
4186
4215
|
lense = fieldLense;
|
|
4187
|
-
} else if (
|
|
4216
|
+
} else if (isObj(stateField)) {
|
|
4188
4217
|
if (typeof stateField.get !== 'function') {
|
|
4189
4218
|
console.error(`Sub-component in ${ this.name } has an invalid 'state' field: Expecting 'undefined', a string indicating an array property in the state, or an object with 'get' and 'set' functions for retrieving and setting sub-component state from the current state. Attempting to use parent component state.`);
|
|
4190
4219
|
lense = baseLense;
|
|
@@ -4199,7 +4228,7 @@ class Component {
|
|
|
4199
4228
|
const sources = { ...this.sources, [this.stateSourceName]: stateSource, props$, children$, __parentContext$: this.context$ };
|
|
4200
4229
|
const sink$ = isolate(factory, { [this.stateSourceName]: lense })(sources);
|
|
4201
4230
|
|
|
4202
|
-
if (
|
|
4231
|
+
if (!isObj(sink$)) {
|
|
4203
4232
|
const name = componentName === 'sygnal-factory' ? 'custom element' : componentName;
|
|
4204
4233
|
throw new Error('Invalid sinks returned from component factory:', name)
|
|
4205
4234
|
}
|
|
@@ -4297,7 +4326,7 @@ function getComponents(currentElement, componentNames, depth=0, index=0, parentI
|
|
|
4297
4326
|
const sel = currentElement.sel;
|
|
4298
4327
|
const isCollection = sel && sel.toLowerCase() === 'collection';
|
|
4299
4328
|
const isSwitchable = sel && sel.toLowerCase() === 'switchable';
|
|
4300
|
-
const isComponent = sel && (['collection', 'switchable', 'sygnal-factory', ...componentNames].includes(sel)) || typeof currentElement.data?.props?.sygnalFactory === 'function' ||
|
|
4329
|
+
const isComponent = sel && (['collection', 'switchable', 'sygnal-factory', ...componentNames].includes(sel)) || typeof currentElement.data?.props?.sygnalFactory === 'function' || isObj(currentElement.data?.props?.sygnalOptions);
|
|
4301
4330
|
const props = (currentElement.data && currentElement.data.props) || {};
|
|
4302
4331
|
(currentElement.data && currentElement.data.attrs) || {};
|
|
4303
4332
|
const children = currentElement.children || [];
|
|
@@ -4308,15 +4337,15 @@ function getComponents(currentElement, componentNames, depth=0, index=0, parentI
|
|
|
4308
4337
|
if (isComponent) {
|
|
4309
4338
|
id = getComponentIdFromElement(currentElement, depth, index, parentId);
|
|
4310
4339
|
if (isCollection) {
|
|
4311
|
-
if (!props.of)
|
|
4340
|
+
if (!props.of) throw new Error(`Collection element missing required 'component' property`)
|
|
4312
4341
|
if (typeof props.of !== 'string' && typeof props.of !== 'function') throw new Error(`Invalid 'component' property of collection element: found ${ typeof props.of } requires string or component factory function`)
|
|
4313
4342
|
if (typeof props.of !== 'function' && !componentNames.includes(props.of)) throw new Error(`Specified component for collection not found: ${ props.of }`)
|
|
4314
4343
|
if (typeof props.from !== 'undefined' && !(typeof props.from === 'string' || Array.isArray(props.from) || typeof props.from.get === 'function')) console.warn(`No valid array found for collection ${ typeof props.of === 'string' ? props.of : 'function component' }: no collection components will be created`, props.from);
|
|
4315
4344
|
currentElement.data.isCollection = true;
|
|
4316
4345
|
currentElement.data.props ||= {};
|
|
4317
4346
|
} else if (isSwitchable) {
|
|
4318
|
-
if (!props.of)
|
|
4319
|
-
if (
|
|
4347
|
+
if (!props.of) throw new Error(`Switchable element missing required 'of' property`)
|
|
4348
|
+
if (!isObj(props.of)) throw new Error(`Invalid 'of' property of switchable element: found ${ typeof props.of } requires object mapping names to component factories`)
|
|
4320
4349
|
const switchableComponents = Object.values(props.of);
|
|
4321
4350
|
if (!switchableComponents.every(comp => typeof comp === 'function')) throw new Error(`One or more components provided to switchable element is not a valid component factory`)
|
|
4322
4351
|
if (!props.current || (typeof props.current !== 'string' && typeof props.current !== 'function')) throw new Error(`Missing or invalid 'current' property for switchable element: found '${ typeof props.current }' requires string or function`)
|
|
@@ -4345,7 +4374,7 @@ function injectComponents(currentElement, components, componentNames, depth=0, i
|
|
|
4345
4374
|
|
|
4346
4375
|
|
|
4347
4376
|
const sel = currentElement.sel || 'NO SELECTOR';
|
|
4348
|
-
const isComponent = ['collection', 'switchable', 'sygnal-factory', ...componentNames].includes(sel) || typeof currentElement.data?.props?.sygnalFactory === 'function' ||
|
|
4377
|
+
const isComponent = ['collection', 'switchable', 'sygnal-factory', ...componentNames].includes(sel) || typeof currentElement.data?.props?.sygnalFactory === 'function' || isObj(currentElement.data?.props?.sygnalOptions);
|
|
4349
4378
|
const isCollection = currentElement?.data?.isCollection;
|
|
4350
4379
|
const isSwitchable = currentElement?.data?.isSwitchable;
|
|
4351
4380
|
(currentElement.data && currentElement.data.props) || {};
|
|
@@ -4443,11 +4472,15 @@ function objIsEqual(objA, objB, maxDepth = 5, depth = 0) {
|
|
|
4443
4472
|
}
|
|
4444
4473
|
|
|
4445
4474
|
function sanitizeObject(obj) {
|
|
4446
|
-
if (
|
|
4475
|
+
if (!isObj(obj)) return obj
|
|
4447
4476
|
const {state, of, from, _reqId, _action, __props, __children, __context, ...sanitized} = obj;
|
|
4448
4477
|
return sanitized
|
|
4449
4478
|
}
|
|
4450
4479
|
|
|
4480
|
+
function isObj(obj) {
|
|
4481
|
+
return typeof obj === 'object' && obj !== null && !Array.isArray(obj)
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4451
4484
|
function driverFromAsync(promiseReturningFunction, opts = {}) {
|
|
4452
4485
|
const {
|
|
4453
4486
|
selector: selectorProperty = 'category',
|