@fluffjs/fluff 0.0.7 → 0.1.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/bundle.min.js +1 -0
- package/decorators/Component.d.ts +0 -1
- package/decorators/Component.js +0 -3
- package/decorators/HostBinding.d.ts +4 -0
- package/decorators/HostBinding.js +3 -10
- package/decorators/HostListener.d.ts +4 -0
- package/decorators/HostListener.js +3 -10
- package/decorators/Input.d.ts +1 -1
- package/decorators/Input.js +2 -16
- package/decorators/InputOutputHelper.d.ts +1 -0
- package/decorators/InputOutputHelper.js +18 -0
- package/decorators/MetadataArrayHelper.d.ts +4 -0
- package/decorators/MetadataArrayHelper.js +14 -0
- package/decorators/Output.d.ts +1 -1
- package/decorators/Output.js +2 -16
- package/decorators/ViewChild.d.ts +4 -0
- package/decorators/ViewChild.js +3 -10
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/interfaces/BreakMarkerConfig.d.ts +3 -0
- package/interfaces/BreakMarkerConfig.js +1 -0
- package/interfaces/FluffHostElement.d.ts +5 -0
- package/interfaces/FluffHostElement.js +1 -0
- package/interfaces/ForMarkerConfig.d.ts +8 -0
- package/interfaces/ForMarkerConfig.js +1 -0
- package/interfaces/IfMarkerConfig.d.ts +7 -0
- package/interfaces/IfMarkerConfig.js +1 -0
- package/interfaces/MarkerConfig.d.ts +6 -0
- package/interfaces/MarkerConfig.js +1 -0
- package/interfaces/PropertyChain.d.ts +1 -0
- package/interfaces/PropertyChain.js +1 -0
- package/interfaces/RenderContext.d.ts +3 -0
- package/interfaces/RenderContext.js +1 -0
- package/interfaces/SwitchMarkerConfig.d.ts +10 -0
- package/interfaces/SwitchMarkerConfig.js +1 -0
- package/interfaces/TextMarkerConfig.d.ts +9 -0
- package/interfaces/TextMarkerConfig.js +1 -0
- package/package.json +1 -1
- package/runtime/BreakController.d.ts +8 -0
- package/runtime/BreakController.js +13 -0
- package/runtime/FluffBase.d.ts +40 -0
- package/runtime/FluffBase.js +271 -0
- package/runtime/FluffElement.d.ts +5 -39
- package/runtime/FluffElement.js +3 -272
- package/runtime/FluffElementImpl.d.ts +49 -0
- package/runtime/FluffElementImpl.js +315 -0
- package/runtime/FluffMarkers.d.ts +8 -0
- package/runtime/FluffMarkers.js +8 -0
- package/runtime/ForController.d.ts +10 -0
- package/runtime/ForController.js +43 -0
- package/runtime/IfController.d.ts +10 -0
- package/runtime/IfController.js +46 -0
- package/runtime/MarkerConfigGuards.d.ts +15 -0
- package/runtime/MarkerConfigGuards.js +20 -0
- package/runtime/MarkerController.d.ts +46 -0
- package/runtime/MarkerController.js +235 -0
- package/runtime/MarkerManager.d.ts +16 -0
- package/runtime/MarkerManager.js +136 -0
- package/runtime/MarkerManagerInterface.d.ts +4 -0
- package/runtime/MarkerManagerInterface.js +1 -0
- package/runtime/ScopeRegistry.d.ts +9 -0
- package/runtime/ScopeRegistry.js +13 -0
- package/runtime/SwitchController.d.ts +9 -0
- package/runtime/SwitchController.js +42 -0
- package/runtime/TextController.d.ts +10 -0
- package/runtime/TextController.js +53 -0
- package/runtime/tests/DirectOutputChild.d.ts +10 -0
- package/runtime/tests/DirectOutputChild.js +14 -0
- package/runtime/tests/DirectOutputParent.d.ts +9 -0
- package/runtime/tests/DirectOutputParent.js +17 -0
- package/runtime/tests/TaskStats.d.ts +9 -0
- package/runtime/tests/TaskStats.js +1 -0
- package/runtime/tests/TestChildTasksListComponent.d.ts +8 -0
- package/runtime/tests/TestChildTasksListComponent.js +28 -0
- package/runtime/tests/TestForChildComponent.d.ts +6 -0
- package/runtime/tests/TestForChildComponent.js +10 -0
- package/runtime/tests/TestForComponent.d.ts +6 -0
- package/runtime/tests/TestForComponent.js +21 -0
- package/runtime/tests/TestForReinsertBindsInputParentComponent.d.ts +12 -0
- package/runtime/tests/TestForReinsertBindsInputParentComponent.js +57 -0
- package/runtime/tests/TestForTextMarkerCollisionNoTrackParentComponent.d.ts +8 -0
- package/runtime/tests/TestForTextMarkerCollisionNoTrackParentComponent.js +29 -0
- package/runtime/tests/TestForTextMarkerCollisionParentComponent.d.ts +9 -0
- package/runtime/tests/TestForTextMarkerCollisionParentComponent.js +46 -0
- package/runtime/tests/TestForUnsubscribeNestedParentComponent.d.ts +8 -0
- package/runtime/tests/TestForUnsubscribeNestedParentComponent.js +35 -0
- package/runtime/tests/TestGetterReactivityComponent.d.ts +9 -0
- package/runtime/tests/TestGetterReactivityComponent.js +27 -0
- package/runtime/tests/TestIfReinsertBindsInputChildComponent.d.ts +9 -0
- package/runtime/tests/TestIfReinsertBindsInputChildComponent.js +39 -0
- package/runtime/tests/TestIfReinsertBindsInputParentComponent.d.ts +12 -0
- package/runtime/tests/TestIfReinsertBindsInputParentComponent.js +54 -0
- package/runtime/tests/TestIfUnsubscribeNestedParentComponent.d.ts +8 -0
- package/runtime/tests/TestIfUnsubscribeNestedParentComponent.js +32 -0
- package/runtime/tests/TestLateDefineForChildComponent.d.ts +6 -0
- package/runtime/tests/TestLateDefineForChildComponent.js +10 -0
- package/runtime/tests/TestLateDefineForComponent.d.ts +9 -0
- package/runtime/tests/TestLateDefineForComponent.js +25 -0
- package/runtime/tests/TestNullInputTextComponent.d.ts +14 -0
- package/runtime/tests/TestNullInputTextComponent.js +37 -0
- package/runtime/tests/TestOutputBindingChildComponent.d.ts +10 -0
- package/runtime/tests/TestOutputBindingChildComponent.js +20 -0
- package/runtime/tests/TestOutputBindingParentComponent.d.ts +13 -0
- package/runtime/tests/TestOutputBindingParentComponent.js +38 -0
- package/runtime/tests/TestParentBindsTasksComponent.d.ts +7 -0
- package/runtime/tests/TestParentBindsTasksComponent.js +22 -0
- package/runtime/tests/TestSwitchReinsertBindsInputChildComponent.d.ts +9 -0
- package/runtime/tests/TestSwitchReinsertBindsInputChildComponent.js +39 -0
- package/runtime/tests/TestSwitchReinsertBindsInputParentComponent.d.ts +12 -0
- package/runtime/tests/TestSwitchReinsertBindsInputParentComponent.js +65 -0
- package/runtime/tests/TestSwitchUnsubscribeNestedParentComponent.d.ts +8 -0
- package/runtime/tests/TestSwitchUnsubscribeNestedParentComponent.js +42 -0
- package/runtime/tests/TestTemplateNestedMarkersComponent.d.ts +11 -0
- package/runtime/tests/TestTemplateNestedMarkersComponent.js +39 -0
- package/runtime/tests/TestUnsubscribeNestedChildComponent.d.ts +11 -0
- package/runtime/tests/TestUnsubscribeNestedChildComponent.js +43 -0
- package/runtime/tests/TestUnsubscribeNestedGrandchildComponent.d.ts +9 -0
- package/runtime/tests/TestUnsubscribeNestedGrandchildComponent.js +39 -0
- package/runtime/tests/TestUnsubscribeNestedParentBaseComponent.d.ts +8 -0
- package/runtime/tests/TestUnsubscribeNestedParentBaseComponent.js +33 -0
- package/utils/DomUtils.d.ts +3 -0
- package/utils/DomUtils.js +6 -0
- package/utils/Property.d.ts +8 -3
- package/utils/Property.js +26 -20
- package/utils/Publisher.d.ts +2 -1
- package/utils/Publisher.js +16 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElement.js';
|
|
2
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
3
|
+
export class TestParentBindsTasksComponent extends FluffElement {
|
|
4
|
+
tasksForChild = [1, 2, 3];
|
|
5
|
+
childList = [0];
|
|
6
|
+
__render() {
|
|
7
|
+
this.__getShadowRoot().innerHTML = `
|
|
8
|
+
<!--fluff:for:0-->
|
|
9
|
+
<!--/fluff:for:0-->
|
|
10
|
+
<template data-fluff-tpl="test-parent-binds-tasks-0">
|
|
11
|
+
<test-child-tasks-list x-fluff-component="" data-lid="l0"></test-child-tasks-list>
|
|
12
|
+
</template>
|
|
13
|
+
`;
|
|
14
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
15
|
+
[0, { type: 'for', iterator: 'child', iterableExprId: 0, deps: ['childList'], hasEmpty: false }]
|
|
16
|
+
]));
|
|
17
|
+
}
|
|
18
|
+
__setupBindings() {
|
|
19
|
+
this.__initializeMarkers(MarkerManager);
|
|
20
|
+
super.__setupBindings();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
2
|
+
import type { TaskStats } from './TaskStats.js';
|
|
3
|
+
export declare class TestSwitchReinsertBindsInputChildComponent extends FluffElement {
|
|
4
|
+
private readonly __stats;
|
|
5
|
+
get stats(): TaskStats;
|
|
6
|
+
set stats(value: TaskStats);
|
|
7
|
+
protected __render(): void;
|
|
8
|
+
protected __setupBindings(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
3
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
4
|
+
export class TestSwitchReinsertBindsInputChildComponent extends FluffElement {
|
|
5
|
+
__stats = new Property({
|
|
6
|
+
initialValue: {
|
|
7
|
+
total: 0,
|
|
8
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
9
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
10
|
+
overdue: 0,
|
|
11
|
+
dueToday: 0
|
|
12
|
+
},
|
|
13
|
+
propertyName: 'stats'
|
|
14
|
+
});
|
|
15
|
+
get stats() {
|
|
16
|
+
return this.__stats.getValue() ?? {
|
|
17
|
+
total: 0,
|
|
18
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
19
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
20
|
+
overdue: 0,
|
|
21
|
+
dueToday: 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
set stats(value) {
|
|
25
|
+
this.__stats.setValue(value);
|
|
26
|
+
}
|
|
27
|
+
__render() {
|
|
28
|
+
this.__getShadowRoot().innerHTML = `
|
|
29
|
+
<div class="total"><!--fluff:text:0--><!--/fluff:text:0--></div>
|
|
30
|
+
`;
|
|
31
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
32
|
+
[0, { type: 'text', exprId: 4, deps: ['stats'], pipes: [] }]
|
|
33
|
+
]));
|
|
34
|
+
}
|
|
35
|
+
__setupBindings() {
|
|
36
|
+
this.__initializeMarkers(MarkerManager);
|
|
37
|
+
super.__setupBindings();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
2
|
+
import type { TaskStats } from './TaskStats.js';
|
|
3
|
+
export declare class TestSwitchReinsertBindsInputParentComponent extends FluffElement {
|
|
4
|
+
private readonly __mode;
|
|
5
|
+
private readonly __stats;
|
|
6
|
+
get mode(): string;
|
|
7
|
+
set mode(value: string);
|
|
8
|
+
get stats(): TaskStats;
|
|
9
|
+
set stats(value: TaskStats);
|
|
10
|
+
protected __render(): void;
|
|
11
|
+
protected __setupBindings(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
3
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
4
|
+
export class TestSwitchReinsertBindsInputParentComponent extends FluffElement {
|
|
5
|
+
__mode = new Property({ initialValue: 'a', propertyName: 'mode' });
|
|
6
|
+
__stats = new Property({
|
|
7
|
+
initialValue: {
|
|
8
|
+
total: 8,
|
|
9
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 8 },
|
|
10
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
11
|
+
overdue: 0,
|
|
12
|
+
dueToday: 0
|
|
13
|
+
},
|
|
14
|
+
propertyName: 'stats'
|
|
15
|
+
});
|
|
16
|
+
get mode() {
|
|
17
|
+
return this.__mode.getValue() ?? 'a';
|
|
18
|
+
}
|
|
19
|
+
set mode(value) {
|
|
20
|
+
this.__mode.setValue(value);
|
|
21
|
+
}
|
|
22
|
+
get stats() {
|
|
23
|
+
return this.__stats.getValue() ?? {
|
|
24
|
+
total: 0,
|
|
25
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
26
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
27
|
+
overdue: 0,
|
|
28
|
+
dueToday: 0
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
set stats(value) {
|
|
32
|
+
this.__stats.setValue(value);
|
|
33
|
+
}
|
|
34
|
+
__render() {
|
|
35
|
+
this.__getShadowRoot().innerHTML = `
|
|
36
|
+
<!--fluff:switch:0-->
|
|
37
|
+
<!--/fluff:switch:0-->
|
|
38
|
+
<template data-fluff-case="test-switch-reinsert-binds-input-parent-0-0">
|
|
39
|
+
<test-switch-reinsert-binds-input-child x-fluff-component data-lid="l0"></test-switch-reinsert-binds-input-child>
|
|
40
|
+
</template>
|
|
41
|
+
<template data-fluff-case="test-switch-reinsert-binds-input-parent-0-1">
|
|
42
|
+
<test-switch-reinsert-binds-input-child x-fluff-component data-lid="l1"></test-switch-reinsert-binds-input-child>
|
|
43
|
+
</template>
|
|
44
|
+
`;
|
|
45
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
46
|
+
[
|
|
47
|
+
0, {
|
|
48
|
+
type: 'switch', expressionExprId: 0, deps: ['mode'], cases: [
|
|
49
|
+
{ valueExprId: 1, isDefault: false, fallthrough: false },
|
|
50
|
+
{ valueExprId: 2, isDefault: false, fallthrough: false }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
]));
|
|
55
|
+
const bindings = {
|
|
56
|
+
l0: [{ n: 'stats', b: 'property', e: 3, d: ['stats'] }],
|
|
57
|
+
l1: [{ n: 'stats', b: 'property', e: 3, d: ['stats'] }]
|
|
58
|
+
};
|
|
59
|
+
Reflect.set(this.constructor, '__bindings', bindings);
|
|
60
|
+
}
|
|
61
|
+
__setupBindings() {
|
|
62
|
+
this.__initializeMarkers(MarkerManager);
|
|
63
|
+
super.__setupBindings();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TestUnsubscribeNestedParentBaseComponent } from './TestUnsubscribeNestedParentBaseComponent.js';
|
|
2
|
+
export declare class TestSwitchUnsubscribeNestedParentComponent extends TestUnsubscribeNestedParentBaseComponent {
|
|
3
|
+
private readonly __mode;
|
|
4
|
+
get mode(): string;
|
|
5
|
+
set mode(value: string);
|
|
6
|
+
protected __render(): void;
|
|
7
|
+
protected __setupBindings(): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
3
|
+
import { TestUnsubscribeNestedParentBaseComponent } from './TestUnsubscribeNestedParentBaseComponent.js';
|
|
4
|
+
export class TestSwitchUnsubscribeNestedParentComponent extends TestUnsubscribeNestedParentBaseComponent {
|
|
5
|
+
__mode = new Property({ initialValue: 'a', propertyName: 'mode' });
|
|
6
|
+
get mode() {
|
|
7
|
+
return this.__mode.getValue() ?? 'a';
|
|
8
|
+
}
|
|
9
|
+
set mode(value) {
|
|
10
|
+
this.__mode.setValue(value);
|
|
11
|
+
}
|
|
12
|
+
__render() {
|
|
13
|
+
this.__getShadowRoot().innerHTML = `
|
|
14
|
+
<!--fluff:switch:0-->
|
|
15
|
+
<!--/fluff:switch:0-->
|
|
16
|
+
<template data-fluff-case="test-switch-unsubscribe-nested-parent-0-0">
|
|
17
|
+
<test-unsubscribe-nested-child x-fluff-component data-lid="l0"></test-unsubscribe-nested-child>
|
|
18
|
+
</template>
|
|
19
|
+
<template data-fluff-case="test-switch-unsubscribe-nested-parent-0-1">
|
|
20
|
+
<div class="placeholder">placeholder</div>
|
|
21
|
+
</template>
|
|
22
|
+
`;
|
|
23
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
24
|
+
[
|
|
25
|
+
0, {
|
|
26
|
+
type: 'switch', expressionExprId: 0, deps: ['mode'], cases: [
|
|
27
|
+
{ valueExprId: 1, isDefault: false, fallthrough: false },
|
|
28
|
+
{ valueExprId: 2, isDefault: false, fallthrough: false }
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
]));
|
|
33
|
+
const bindings = {
|
|
34
|
+
l0: [{ n: 'stats', b: 'property', e: 3, d: ['stats'] }]
|
|
35
|
+
};
|
|
36
|
+
Reflect.set(this.constructor, '__bindings', bindings);
|
|
37
|
+
}
|
|
38
|
+
__setupBindings() {
|
|
39
|
+
this.__initializeMarkers(MarkerManager);
|
|
40
|
+
super.__setupBindings();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElement.js';
|
|
2
|
+
export declare class TestTemplateNestedMarkersComponent extends FluffElement {
|
|
3
|
+
private readonly __show;
|
|
4
|
+
private readonly __text;
|
|
5
|
+
get show(): boolean;
|
|
6
|
+
set show(value: boolean);
|
|
7
|
+
get text(): string;
|
|
8
|
+
set text(value: string);
|
|
9
|
+
protected __render(): void;
|
|
10
|
+
protected __setupBindings(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
4
|
+
export class TestTemplateNestedMarkersComponent extends FluffElement {
|
|
5
|
+
__show = new Property(true);
|
|
6
|
+
__text = new Property('Hello');
|
|
7
|
+
get show() {
|
|
8
|
+
return this.__show.getValue() ?? false;
|
|
9
|
+
}
|
|
10
|
+
set show(value) {
|
|
11
|
+
this.__show.setValue(value);
|
|
12
|
+
}
|
|
13
|
+
get text() {
|
|
14
|
+
return this.__text.getValue() ?? '';
|
|
15
|
+
}
|
|
16
|
+
set text(value) {
|
|
17
|
+
this.__text.setValue(value);
|
|
18
|
+
}
|
|
19
|
+
__render() {
|
|
20
|
+
this.__getShadowRoot().innerHTML = `
|
|
21
|
+
<!--fluff:if:0-->
|
|
22
|
+
<!--/fluff:if:0-->
|
|
23
|
+
<template data-fluff-branch="test-template-nested-markers-0-0">
|
|
24
|
+
<div class="title"><!--fluff:text:1--><!--/fluff:text:1--></div>
|
|
25
|
+
</template>
|
|
26
|
+
<template data-fluff-branch="test-template-nested-markers-0-1">
|
|
27
|
+
<div class="fallback">Fallback</div>
|
|
28
|
+
</template>
|
|
29
|
+
`;
|
|
30
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
31
|
+
[0, { type: 'if', branches: [{ exprId: 0, deps: ['show'] }, { exprId: undefined, deps: [] }] }],
|
|
32
|
+
[1, { type: 'text', exprId: 1, deps: ['text'], pipes: [] }]
|
|
33
|
+
]));
|
|
34
|
+
}
|
|
35
|
+
__setupBindings() {
|
|
36
|
+
this.__initializeMarkers(MarkerManager);
|
|
37
|
+
super.__setupBindings();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
2
|
+
import type { TaskStats } from './TaskStats.js';
|
|
3
|
+
export declare class TestUnsubscribeNestedChildComponent extends FluffElement {
|
|
4
|
+
private readonly __stats;
|
|
5
|
+
private _statsSetCount;
|
|
6
|
+
get statsSetCount(): number;
|
|
7
|
+
get stats(): TaskStats;
|
|
8
|
+
set stats(value: TaskStats);
|
|
9
|
+
protected __render(): void;
|
|
10
|
+
protected __setupBindings(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
3
|
+
export class TestUnsubscribeNestedChildComponent extends FluffElement {
|
|
4
|
+
__stats = new Property({
|
|
5
|
+
initialValue: {
|
|
6
|
+
total: 0,
|
|
7
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
8
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
9
|
+
overdue: 0,
|
|
10
|
+
dueToday: 0
|
|
11
|
+
},
|
|
12
|
+
propertyName: 'stats'
|
|
13
|
+
});
|
|
14
|
+
_statsSetCount = 0;
|
|
15
|
+
get statsSetCount() {
|
|
16
|
+
return this._statsSetCount;
|
|
17
|
+
}
|
|
18
|
+
get stats() {
|
|
19
|
+
return this.__stats.getValue() ?? {
|
|
20
|
+
total: 0,
|
|
21
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
22
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
23
|
+
overdue: 0,
|
|
24
|
+
dueToday: 0
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
set stats(value) {
|
|
28
|
+
this._statsSetCount++;
|
|
29
|
+
this.__stats.setValue(value);
|
|
30
|
+
}
|
|
31
|
+
__render() {
|
|
32
|
+
this.__getShadowRoot().innerHTML = `
|
|
33
|
+
<test-unsubscribe-nested-grandchild x-fluff-component data-lid="l0"></test-unsubscribe-nested-grandchild>
|
|
34
|
+
`;
|
|
35
|
+
const bindings = {
|
|
36
|
+
l0: [{ n: 'stats', b: 'property', e: 4, d: ['stats'] }]
|
|
37
|
+
};
|
|
38
|
+
Reflect.set(this.constructor, '__bindings', bindings);
|
|
39
|
+
}
|
|
40
|
+
__setupBindings() {
|
|
41
|
+
super.__setupBindings();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
2
|
+
import type { TaskStats } from './TaskStats.js';
|
|
3
|
+
export declare class TestUnsubscribeNestedGrandchildComponent extends FluffElement {
|
|
4
|
+
private readonly __stats;
|
|
5
|
+
get stats(): TaskStats;
|
|
6
|
+
set stats(value: TaskStats);
|
|
7
|
+
protected __render(): void;
|
|
8
|
+
protected __setupBindings(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
3
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
4
|
+
export class TestUnsubscribeNestedGrandchildComponent extends FluffElement {
|
|
5
|
+
__stats = new Property({
|
|
6
|
+
initialValue: {
|
|
7
|
+
total: 0,
|
|
8
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
9
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
10
|
+
overdue: 0,
|
|
11
|
+
dueToday: 0
|
|
12
|
+
},
|
|
13
|
+
propertyName: 'stats'
|
|
14
|
+
});
|
|
15
|
+
get stats() {
|
|
16
|
+
return this.__stats.getValue() ?? {
|
|
17
|
+
total: 0,
|
|
18
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
19
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
20
|
+
overdue: 0,
|
|
21
|
+
dueToday: 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
set stats(value) {
|
|
25
|
+
this.__stats.setValue(value);
|
|
26
|
+
}
|
|
27
|
+
__render() {
|
|
28
|
+
this.__getShadowRoot().innerHTML = `
|
|
29
|
+
<div class="total"><!--fluff:text:0--><!--/fluff:text:0--></div>
|
|
30
|
+
`;
|
|
31
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
32
|
+
[0, { type: 'text', exprId: 5, deps: ['stats'], pipes: [] }]
|
|
33
|
+
]));
|
|
34
|
+
}
|
|
35
|
+
__setupBindings() {
|
|
36
|
+
this.__initializeMarkers(MarkerManager);
|
|
37
|
+
super.__setupBindings();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
2
|
+
import type { TaskStats } from './TaskStats.js';
|
|
3
|
+
export declare abstract class TestUnsubscribeNestedParentBaseComponent extends FluffElement {
|
|
4
|
+
private readonly __stats;
|
|
5
|
+
get stats(): TaskStats;
|
|
6
|
+
set stats(value: TaskStats);
|
|
7
|
+
setStatsTotal(total: number): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElementImpl.js';
|
|
3
|
+
export class TestUnsubscribeNestedParentBaseComponent extends FluffElement {
|
|
4
|
+
__stats = new Property({
|
|
5
|
+
initialValue: {
|
|
6
|
+
total: 8,
|
|
7
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 8 },
|
|
8
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
9
|
+
overdue: 0,
|
|
10
|
+
dueToday: 0
|
|
11
|
+
},
|
|
12
|
+
propertyName: 'stats'
|
|
13
|
+
});
|
|
14
|
+
get stats() {
|
|
15
|
+
return this.__stats.getValue() ?? {
|
|
16
|
+
total: 0,
|
|
17
|
+
byStatus: { 'todo': 0, 'in-progress': 0, 'done': 0 },
|
|
18
|
+
byPriority: { 'low': 0, 'medium': 0, 'high': 0, 'urgent': 0 },
|
|
19
|
+
overdue: 0,
|
|
20
|
+
dueToday: 0
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
set stats(value) {
|
|
24
|
+
this.__stats.setValue(value);
|
|
25
|
+
}
|
|
26
|
+
setStatsTotal(total) {
|
|
27
|
+
const current = this.stats;
|
|
28
|
+
this.stats = {
|
|
29
|
+
...current,
|
|
30
|
+
total
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
package/utils/Property.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Direction } from '../enums/Direction.js';
|
|
2
2
|
import type { Subscription } from '../interfaces/Subscription.js';
|
|
3
|
-
import { Publisher } from '
|
|
3
|
+
import { Publisher } from './Publisher.js';
|
|
4
4
|
export declare class Property<T> {
|
|
5
5
|
readonly onChange: Publisher<T>;
|
|
6
6
|
readonly onInboundChange: Publisher<T>;
|
|
@@ -8,9 +8,14 @@ export declare class Property<T> {
|
|
|
8
8
|
private value?;
|
|
9
9
|
private committed;
|
|
10
10
|
private _isChanging;
|
|
11
|
-
|
|
11
|
+
private readonly _propName?;
|
|
12
|
+
constructor(options: {
|
|
13
|
+
initialValue: T;
|
|
14
|
+
propertyName?: string;
|
|
15
|
+
} | T);
|
|
12
16
|
setValue(val: T, inbound?: boolean, commit?: boolean): void;
|
|
13
|
-
triggerChange(direction?: Direction):
|
|
17
|
+
triggerChange(direction?: Direction): void;
|
|
14
18
|
subscribe(direction: Direction, cb: (val: T) => void): Subscription;
|
|
15
19
|
getValue(): T | null;
|
|
20
|
+
private isOptionsObject;
|
|
16
21
|
}
|
package/utils/Property.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Direction } from '../enums/Direction.js';
|
|
2
|
-
import { Publisher } from '
|
|
2
|
+
import { Publisher } from './Publisher.js';
|
|
3
3
|
function safeStringify(obj) {
|
|
4
4
|
const seen = new WeakSet();
|
|
5
5
|
return JSON.stringify(obj, (_key, value) => {
|
|
@@ -19,12 +19,24 @@ export class Property {
|
|
|
19
19
|
value;
|
|
20
20
|
committed = true;
|
|
21
21
|
_isChanging = false;
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
_propName;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
if (this.isOptionsObject(options)) {
|
|
25
|
+
if (options.initialValue !== undefined) {
|
|
26
|
+
this.value = options.initialValue;
|
|
27
|
+
}
|
|
28
|
+
if (options.propertyName !== undefined) {
|
|
29
|
+
this._propName = options.propertyName;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.value = options;
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
setValue(val, inbound = false, commit = true) {
|
|
26
37
|
if (this._isChanging) {
|
|
27
|
-
|
|
38
|
+
console.error((this._propName ? this._propName + ': ' : '') + 'Binding loop detected: setValue called while change is in progress');
|
|
39
|
+
return;
|
|
28
40
|
}
|
|
29
41
|
const changed = val !== this.value && safeStringify(val) !== safeStringify(this.value);
|
|
30
42
|
if (!changed)
|
|
@@ -32,27 +44,18 @@ export class Property {
|
|
|
32
44
|
this._isChanging = true;
|
|
33
45
|
try {
|
|
34
46
|
this.value = val;
|
|
35
|
-
this.onChange.emit(val)
|
|
36
|
-
.catch((e) => {
|
|
37
|
-
console.error(e);
|
|
38
|
-
});
|
|
47
|
+
this.onChange.emit(val);
|
|
39
48
|
if (!commit) {
|
|
40
49
|
this.committed = false;
|
|
41
50
|
}
|
|
42
51
|
if (inbound) {
|
|
43
52
|
this.committed = true;
|
|
44
|
-
this.onInboundChange.emit(val)
|
|
45
|
-
.catch((e) => {
|
|
46
|
-
console.error(e);
|
|
47
|
-
});
|
|
53
|
+
this.onInboundChange.emit(val);
|
|
48
54
|
}
|
|
49
55
|
else if (commit || !this.committed) {
|
|
50
56
|
this.committed = true;
|
|
51
57
|
if (this.value !== undefined) {
|
|
52
|
-
this.onOutboundChange.emit(this.value)
|
|
53
|
-
.catch((e) => {
|
|
54
|
-
console.error(e);
|
|
55
|
-
});
|
|
58
|
+
this.onOutboundChange.emit(this.value);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
}
|
|
@@ -60,15 +63,15 @@ export class Property {
|
|
|
60
63
|
this._isChanging = false;
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
|
-
|
|
66
|
+
triggerChange(direction = Direction.Any) {
|
|
64
67
|
if (this.value === undefined)
|
|
65
68
|
return;
|
|
66
|
-
|
|
69
|
+
this.onChange.emit(this.value);
|
|
67
70
|
if (direction == Direction.Outbound) {
|
|
68
|
-
|
|
71
|
+
this.onOutboundChange.emit(this.value);
|
|
69
72
|
}
|
|
70
73
|
if (direction == Direction.Inbound) {
|
|
71
|
-
|
|
74
|
+
this.onOutboundChange.emit(this.value);
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
subscribe(direction, cb) {
|
|
@@ -94,4 +97,7 @@ export class Property {
|
|
|
94
97
|
}
|
|
95
98
|
return this.value;
|
|
96
99
|
}
|
|
100
|
+
isOptionsObject(options) {
|
|
101
|
+
return typeof options === 'object' && options !== null && ('initialValue' in options);
|
|
102
|
+
}
|
|
97
103
|
}
|
package/utils/Publisher.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import type { Subscription } from '../interfaces/Subscription.js';
|
|
|
2
2
|
type Callback<T> = (value: T) => void | Promise<void>;
|
|
3
3
|
export declare class Publisher<T> {
|
|
4
4
|
private readonly callbacks;
|
|
5
|
-
emit(value: T):
|
|
5
|
+
emit(value: T): void;
|
|
6
|
+
emitAsync(value: T): Promise<void>;
|
|
6
7
|
subscribe(callback: Callback<T>): Subscription;
|
|
7
8
|
subscribeOnce(callback: Callback<T>): Subscription;
|
|
8
9
|
}
|
package/utils/Publisher.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
export class Publisher {
|
|
2
2
|
callbacks = new Set();
|
|
3
|
-
|
|
3
|
+
emit(value) {
|
|
4
|
+
for (const callback of this.callbacks) {
|
|
5
|
+
try {
|
|
6
|
+
const result = callback(value);
|
|
7
|
+
if (result instanceof Promise) {
|
|
8
|
+
result.catch((e) => {
|
|
9
|
+
console.error(e);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
console.error(e);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async emitAsync(value) {
|
|
4
19
|
for (const callback of this.callbacks) {
|
|
5
20
|
try {
|
|
6
21
|
await callback(value);
|