sygnal 2.8.0 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +117 -66
- package/dist/index.esm.js +117 -66
- package/dist/sygnal.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -3283,8 +3283,10 @@ class Component {
|
|
|
3283
3283
|
};
|
|
3284
3284
|
}
|
|
3285
3285
|
|
|
3286
|
+
const componentNumber = COMPONENT_COUNT++;
|
|
3287
|
+
|
|
3286
3288
|
this.addCalculated = this.createMemoizedAddCalculated();
|
|
3287
|
-
this.log = makeLog(name);
|
|
3289
|
+
this.log = makeLog(`${componentNumber} | ${name}`);
|
|
3288
3290
|
|
|
3289
3291
|
this.initIntent$();
|
|
3290
3292
|
this.initAction$();
|
|
@@ -3299,11 +3301,9 @@ class Component {
|
|
|
3299
3301
|
this.initVdom$();
|
|
3300
3302
|
this.initSinks();
|
|
3301
3303
|
|
|
3302
|
-
this.sinks.__index =
|
|
3304
|
+
this.sinks.__index = componentNumber;
|
|
3303
3305
|
|
|
3304
|
-
|
|
3305
|
-
console.log(`[${ this.name }] Instantiated (#${ this.sinks.__index })`);
|
|
3306
|
-
}
|
|
3306
|
+
this.log(`Instantiated`, true);
|
|
3307
3307
|
}
|
|
3308
3308
|
|
|
3309
3309
|
get debug() {
|
|
@@ -3358,7 +3358,7 @@ class Component {
|
|
|
3358
3358
|
const hydrate$ = initialApiData.map(data => ({ type: HYDRATE_ACTION, data }));
|
|
3359
3359
|
|
|
3360
3360
|
this.action$ = xs$1.merge(wrapped$, hydrate$)
|
|
3361
|
-
.compose(this.log(({ type }) =>
|
|
3361
|
+
.compose(this.log(({ type }) => `<${ type }> Action triggered`));
|
|
3362
3362
|
}
|
|
3363
3363
|
|
|
3364
3364
|
initResponse$() {
|
|
@@ -3408,7 +3408,7 @@ class Component {
|
|
|
3408
3408
|
console.log(`${ timestamp } ${ ip } ${ req.method } ${ req.url }`);
|
|
3409
3409
|
|
|
3410
3410
|
if (this.debug) {
|
|
3411
|
-
this.action$.setDebugListener({next: ({ type }) =>
|
|
3411
|
+
this.action$.setDebugListener({next: ({ type }) => this.log(`[${ this.name }] Action from ${ this.requestSourceName } request: <${ type }>`, true)});
|
|
3412
3412
|
}
|
|
3413
3413
|
|
|
3414
3414
|
if (actionType === 'function') {
|
|
@@ -3565,10 +3565,10 @@ class Component {
|
|
|
3565
3565
|
const wrapped$ = on$
|
|
3566
3566
|
.compose(this.log(data => {
|
|
3567
3567
|
if (isStateSink) {
|
|
3568
|
-
return
|
|
3568
|
+
return `<${ action }> State reducer added`
|
|
3569
3569
|
} else {
|
|
3570
3570
|
const extra = data && (data.type || data.command || data.name || data.key || (Array.isArray(data) && 'Array') || data);
|
|
3571
|
-
return
|
|
3571
|
+
return `<${ action }> Data sent to [${ sink }]: ${ JSON.stringify(extra).replaceAll('"', '') }`
|
|
3572
3572
|
}
|
|
3573
3573
|
}));
|
|
3574
3574
|
|
|
@@ -3691,6 +3691,7 @@ class Component {
|
|
|
3691
3691
|
|
|
3692
3692
|
this.vdom$ = renderParameters$
|
|
3693
3693
|
.map(this.view)
|
|
3694
|
+
.compose(this.log('View rendered'))
|
|
3694
3695
|
.map(vDom => vDom || { sel: 'div', data: {}, children: [] })
|
|
3695
3696
|
.compose(this.instantiateSubComponents.bind(this))
|
|
3696
3697
|
.filter(val => val !== undefined)
|
|
@@ -3731,6 +3732,7 @@ class Component {
|
|
|
3731
3732
|
// push the "next" action request into the action$ stream
|
|
3732
3733
|
rootAction$.shamefullySendNext({ type, data: _data });
|
|
3733
3734
|
}, delay);
|
|
3735
|
+
this.log(`<${ name }> Triggered a next() action: <${ type }> ${ delay }ms delay`, true);
|
|
3734
3736
|
};
|
|
3735
3737
|
|
|
3736
3738
|
let data = action.data;
|
|
@@ -3827,37 +3829,19 @@ class Component {
|
|
|
3827
3829
|
const enhancedState = state && state.isolateSource(state, { get: state => this.addCalculated(state) });
|
|
3828
3830
|
const stateStream = (enhancedState && enhancedState.stream) || xs$1.never();
|
|
3829
3831
|
|
|
3830
|
-
const objRepeatChecker = (a, b) => {
|
|
3831
|
-
const { state, sygnalFactory, __props, __children, __context, ...sanitized } = a;
|
|
3832
|
-
const keys = Object.keys(sanitized);
|
|
3833
|
-
if (keys.length === 0) {
|
|
3834
|
-
const { state, sygnalFactory, __props, __children, __context, ...sanitizedB } = b;
|
|
3835
|
-
return Object.keys(sanitizedB).length === 0
|
|
3836
|
-
}
|
|
3837
|
-
return keys.every(key => a[key] === b[key])
|
|
3838
|
-
};
|
|
3839
3832
|
|
|
3840
|
-
|
|
3841
|
-
if (a === b) return true
|
|
3842
|
-
if (a.length !== b.length) return false
|
|
3843
|
-
for (let i=0; i < a.length; i++) {
|
|
3844
|
-
if (a[i] !== b[i]) return false
|
|
3845
|
-
}
|
|
3846
|
-
return true
|
|
3847
|
-
};
|
|
3848
|
-
|
|
3849
|
-
renderParams.state = stateStream.compose(_default$5(objRepeatChecker));
|
|
3833
|
+
renderParams.state = stateStream.compose(_default$5(objIsEqual));
|
|
3850
3834
|
|
|
3851
3835
|
if (this.sources.props$) {
|
|
3852
|
-
renderParams.__props = this.sources.props$.compose(_default$5(
|
|
3836
|
+
renderParams.__props = this.sources.props$.compose(_default$5(objIsEqual));
|
|
3853
3837
|
}
|
|
3854
3838
|
|
|
3855
3839
|
if (this.sources.children$) {
|
|
3856
|
-
renderParams.__children = this.sources.children$.compose(_default$5(
|
|
3840
|
+
renderParams.__children = this.sources.children$.compose(_default$5(objIsEqual));
|
|
3857
3841
|
}
|
|
3858
3842
|
|
|
3859
3843
|
if (this.context$) {
|
|
3860
|
-
renderParams.__context = this.context$.compose(_default$5(
|
|
3844
|
+
renderParams.__context = this.context$.compose(_default$5(objIsEqual));
|
|
3861
3845
|
}
|
|
3862
3846
|
|
|
3863
3847
|
const names = [];
|
|
@@ -3869,11 +3853,15 @@ class Component {
|
|
|
3869
3853
|
});
|
|
3870
3854
|
|
|
3871
3855
|
const combined = xs$1.combine(...streams)
|
|
3856
|
+
.compose(_default$2(1))
|
|
3872
3857
|
// map the streams from an array back to an object with the render parameter names as the keys
|
|
3873
3858
|
.map(arr => {
|
|
3874
3859
|
const params = names.reduce((acc, name, index) => {
|
|
3875
3860
|
acc[name] = arr[index];
|
|
3876
3861
|
if (name === 'state') acc[this.stateSourceName] = arr[index];
|
|
3862
|
+
if (name === '__props') acc.props = arr[index];
|
|
3863
|
+
if (name === '__children') acc.children = arr[index];
|
|
3864
|
+
if (name === '__context') acc.context = arr[index];
|
|
3877
3865
|
return acc
|
|
3878
3866
|
}, {});
|
|
3879
3867
|
return params
|
|
@@ -3895,6 +3883,7 @@ class Component {
|
|
|
3895
3883
|
}
|
|
3896
3884
|
|
|
3897
3885
|
const sinkArrsByType = {};
|
|
3886
|
+
let newInstanceCount = 0;
|
|
3898
3887
|
|
|
3899
3888
|
const newComponents = entries.reduce((acc, [id, el]) => {
|
|
3900
3889
|
const data = el.data;
|
|
@@ -3934,6 +3923,8 @@ class Component {
|
|
|
3934
3923
|
instantiator = this.instantiateCustomComponent.bind(this);
|
|
3935
3924
|
}
|
|
3936
3925
|
|
|
3926
|
+
newInstanceCount++;
|
|
3927
|
+
|
|
3937
3928
|
const sink$ = instantiator(el, props$, children$);
|
|
3938
3929
|
|
|
3939
3930
|
sink$[this.DOMSourceName] = sink$[this.DOMSourceName] ? this.makeCoordinatedSubComponentDomSink(sink$[this.DOMSourceName]) : xs$1.never();
|
|
@@ -3953,18 +3944,18 @@ class Component {
|
|
|
3953
3944
|
|
|
3954
3945
|
this.newSubComponentSinks(mergedSinksByType);
|
|
3955
3946
|
|
|
3947
|
+
if (newInstanceCount > 0) this.log(`New sub components instantiated: ${ newInstanceCount }`, true);
|
|
3948
|
+
|
|
3956
3949
|
return newComponents
|
|
3957
3950
|
}, {})
|
|
3958
3951
|
}
|
|
3959
3952
|
|
|
3960
3953
|
makeCoordinatedSubComponentDomSink(domSink$) {
|
|
3961
3954
|
const remembered$ = domSink$.remember();
|
|
3962
|
-
const repeatChecker = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
3963
3955
|
|
|
3964
3956
|
const coordinated = this.sources[this.stateSourceName].stream
|
|
3965
|
-
.compose(_default$5(
|
|
3957
|
+
.compose(_default$5(objIsEqual))
|
|
3966
3958
|
.map(state => remembered$)
|
|
3967
|
-
.compose(_default$2(10))
|
|
3968
3959
|
.flatten()
|
|
3969
3960
|
.debug(_ => this.triggerSubComponentsRendered())
|
|
3970
3961
|
.remember();
|
|
@@ -4214,7 +4205,7 @@ class Component {
|
|
|
4214
4205
|
|
|
4215
4206
|
renderVdom(componentInstances$) {
|
|
4216
4207
|
return xs$1.combine(this.subComponentsRendered$, componentInstances$)
|
|
4217
|
-
.compose(_default$2(
|
|
4208
|
+
.compose(_default$2(1))
|
|
4218
4209
|
.map(([_, components]) => {
|
|
4219
4210
|
const componentNames = Object.keys(this.components);
|
|
4220
4211
|
|
|
@@ -4235,7 +4226,7 @@ class Component {
|
|
|
4235
4226
|
if (vdom$.length === 0) return xs$1.of(root)
|
|
4236
4227
|
|
|
4237
4228
|
return xs$1.combine(...vdom$)
|
|
4238
|
-
.compose(_default$2(
|
|
4229
|
+
.compose(_default$2(1))
|
|
4239
4230
|
.map(vdoms => {
|
|
4240
4231
|
const withIds = vdoms.reduce((acc, vdom, index) => {
|
|
4241
4232
|
acc[ids[index]] = vdom;
|
|
@@ -4249,7 +4240,6 @@ class Component {
|
|
|
4249
4240
|
.flatten()
|
|
4250
4241
|
.filter(val => !!val)
|
|
4251
4242
|
.remember()
|
|
4252
|
-
.compose(this.log('View Rendered'))
|
|
4253
4243
|
}
|
|
4254
4244
|
|
|
4255
4245
|
}
|
|
@@ -4273,21 +4263,28 @@ class Component {
|
|
|
4273
4263
|
* ONLY outputs if the global `DEBUG` variable is set to `true`
|
|
4274
4264
|
*/
|
|
4275
4265
|
function makeLog (context) {
|
|
4276
|
-
return function (msg) {
|
|
4266
|
+
return function (msg, immediate=false) {
|
|
4277
4267
|
const fixedMsg = (typeof msg === 'function') ? msg : _ => msg;
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4268
|
+
if (immediate) {
|
|
4269
|
+
if (this.debug) {
|
|
4270
|
+
console.log(`[${context}] ${fixedMsg(msg)}`);
|
|
4271
|
+
}
|
|
4272
|
+
return
|
|
4273
|
+
} else {
|
|
4274
|
+
return stream => {
|
|
4275
|
+
return stream.debug(msg => {
|
|
4276
|
+
if (this.debug) {
|
|
4277
|
+
console.log(`[${context}] ${fixedMsg(msg)}`);
|
|
4278
|
+
}
|
|
4279
|
+
})
|
|
4280
|
+
}
|
|
4284
4281
|
}
|
|
4285
4282
|
}
|
|
4286
4283
|
}
|
|
4287
4284
|
|
|
4288
4285
|
|
|
4289
4286
|
|
|
4290
|
-
function getComponents(currentElement, componentNames, depth=0, index=0) {
|
|
4287
|
+
function getComponents(currentElement, componentNames, depth=0, index=0, parentId) {
|
|
4291
4288
|
if (!currentElement) return {}
|
|
4292
4289
|
|
|
4293
4290
|
if (currentElement.data?.componentsProcessed) return {}
|
|
@@ -4302,9 +4299,10 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
|
|
|
4302
4299
|
const children = currentElement.children || [];
|
|
4303
4300
|
|
|
4304
4301
|
let found = {};
|
|
4305
|
-
|
|
4302
|
+
|
|
4303
|
+
let id = parentId;
|
|
4306
4304
|
if (isComponent) {
|
|
4307
|
-
|
|
4305
|
+
id = getComponentIdFromElement(currentElement, depth, index, parentId);
|
|
4308
4306
|
if (isCollection) {
|
|
4309
4307
|
if (!props.of) throw new Error(`Collection element missing required 'component' property`)
|
|
4310
4308
|
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`)
|
|
@@ -4327,7 +4325,7 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
|
|
|
4327
4325
|
}
|
|
4328
4326
|
|
|
4329
4327
|
if (children.length > 0) {
|
|
4330
|
-
children.map((child, i) => getComponents(child, componentNames, depth + 1, index + i))
|
|
4328
|
+
children.map((child, i) => getComponents(child, componentNames, depth + 1, index + i, id))
|
|
4331
4329
|
.forEach((child) => {
|
|
4332
4330
|
Object.entries(child).forEach(([id, el]) => found[id] = el);
|
|
4333
4331
|
});
|
|
@@ -4336,7 +4334,7 @@ function getComponents(currentElement, componentNames, depth=0, index=0) {
|
|
|
4336
4334
|
return found
|
|
4337
4335
|
}
|
|
4338
4336
|
|
|
4339
|
-
function injectComponents(currentElement, components, componentNames, depth=0, index=0) {
|
|
4337
|
+
function injectComponents(currentElement, components, componentNames, depth=0, index=0, parentId) {
|
|
4340
4338
|
if (!currentElement) return
|
|
4341
4339
|
if (currentElement.data?.componentsInjected) return currentElement
|
|
4342
4340
|
if (depth === 0 && currentElement.data) currentElement.data.componentsInjected = true;
|
|
@@ -4349,8 +4347,9 @@ function injectComponents(currentElement, components, componentNames, depth=0, i
|
|
|
4349
4347
|
(currentElement.data && currentElement.data.props) || {};
|
|
4350
4348
|
const children = currentElement.children || [];
|
|
4351
4349
|
|
|
4350
|
+
let id = parentId;
|
|
4352
4351
|
if (isComponent) {
|
|
4353
|
-
|
|
4352
|
+
id = getComponentIdFromElement(currentElement, depth, index, parentId);
|
|
4354
4353
|
const component = components[id];
|
|
4355
4354
|
if (isCollection) {
|
|
4356
4355
|
currentElement.sel = 'div';
|
|
@@ -4362,28 +4361,21 @@ function injectComponents(currentElement, components, componentNames, depth=0, i
|
|
|
4362
4361
|
return component
|
|
4363
4362
|
}
|
|
4364
4363
|
} else if (children.length > 0) {
|
|
4365
|
-
currentElement.children = children.map((child, i) => injectComponents(child, components, componentNames, depth + 1, index + i)).flat();
|
|
4364
|
+
currentElement.children = children.map((child, i) => injectComponents(child, components, componentNames, depth + 1, index + i, id)).flat();
|
|
4366
4365
|
return currentElement
|
|
4367
4366
|
} else {
|
|
4368
4367
|
return currentElement
|
|
4369
4368
|
}
|
|
4370
4369
|
}
|
|
4371
4370
|
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
const
|
|
4375
|
-
const
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
base = `${date}-${rand}`;
|
|
4381
|
-
selMap.set(sel, base);
|
|
4382
|
-
}
|
|
4383
|
-
const uid = `${base}-${depth}-${index}`;
|
|
4384
|
-
const props = (el.data && el.data.props) || {};
|
|
4385
|
-
const id = (props.id && JSON.stringify(props.id)) || uid;
|
|
4386
|
-
const fullId = `${ name }::${ id }`;
|
|
4371
|
+
function getComponentIdFromElement(el, depth, index, parentId) {
|
|
4372
|
+
const sel = el.sel;
|
|
4373
|
+
const name = typeof sel === 'string' ? sel : 'functionComponent';
|
|
4374
|
+
const uid = `${depth}:${index}`;
|
|
4375
|
+
const props = el.data?.props || {};
|
|
4376
|
+
const id = (props.id && JSON.stringify(props.id).replaceAll('"', '')) || uid;
|
|
4377
|
+
const parentString = parentId ? `${ parentId }|` : '';
|
|
4378
|
+
const fullId = `${ parentString }${ name }::${ id }`;
|
|
4387
4379
|
return fullId
|
|
4388
4380
|
}
|
|
4389
4381
|
|
|
@@ -4393,6 +4385,65 @@ function deepCopyVdom(obj) {
|
|
|
4393
4385
|
return { ...obj, children: Array.isArray(obj.children) ? obj.children.map(deepCopyVdom) : undefined, data: obj.data && { ...obj.data, componentsInjected: false } }
|
|
4394
4386
|
}
|
|
4395
4387
|
|
|
4388
|
+
function objIsEqual(objA, objB, maxDepth = 5, depth = 0) {
|
|
4389
|
+
const obj1 = sanitizeObject(objA);
|
|
4390
|
+
const obj2 = sanitizeObject(objB);
|
|
4391
|
+
// Base case: if the current depth exceeds maxDepth, return true
|
|
4392
|
+
if (depth > maxDepth) {
|
|
4393
|
+
return false;
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
// If both are the same object or are both exactly null or undefined
|
|
4397
|
+
if (obj1 === obj2) {
|
|
4398
|
+
return true;
|
|
4399
|
+
}
|
|
4400
|
+
|
|
4401
|
+
// If either is not an object (null, undefined, or primitive), directly compare
|
|
4402
|
+
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
|
|
4403
|
+
return false;
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
// Special handling for arrays
|
|
4407
|
+
if (Array.isArray(obj1) && Array.isArray(obj2)) {
|
|
4408
|
+
if (obj1.length !== obj2.length) {
|
|
4409
|
+
return false;
|
|
4410
|
+
}
|
|
4411
|
+
for (let i = 0; i < obj1.length; i++) {
|
|
4412
|
+
if (!isEqual(obj1[i], obj2[i], maxDepth, depth + 1)) {
|
|
4413
|
+
return false;
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
return true;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
// Get keys of both objects
|
|
4420
|
+
const keys1 = Object.keys(obj1);
|
|
4421
|
+
const keys2 = Object.keys(obj2);
|
|
4422
|
+
|
|
4423
|
+
// Check if the number of properties is different
|
|
4424
|
+
if (keys1.length !== keys2.length) {
|
|
4425
|
+
return false;
|
|
4426
|
+
}
|
|
4427
|
+
|
|
4428
|
+
// Recursively check each property
|
|
4429
|
+
for (const key of keys1) {
|
|
4430
|
+
if (!keys2.includes(key)) {
|
|
4431
|
+
return false;
|
|
4432
|
+
}
|
|
4433
|
+
if (!objIsEqual(obj1[key], obj2[key], maxDepth, depth + 1)) {
|
|
4434
|
+
return false;
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
return true;
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4441
|
+
function sanitizeObject(obj) {
|
|
4442
|
+
if (typeof obj !== 'object' || obj === null) return obj
|
|
4443
|
+
const {state, of, from, _reqId, _action, __props, __children, __context, ...sanitized} = obj;
|
|
4444
|
+
return sanitized
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4396
4447
|
function driverFromAsync(promiseReturningFunction, opts = {}) {
|
|
4397
4448
|
const {
|
|
4398
4449
|
selector: selectorProperty = 'category',
|