@fluffjs/fluff 0.1.12 → 0.1.14
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/package.json +1 -1
- package/runtime/FluffBase.d.ts +10 -0
- package/runtime/FluffBase.js +23 -1
- package/runtime/FluffElementImpl.d.ts +1 -0
- package/runtime/FluffElementImpl.js +3 -0
- package/runtime/MarkerController.d.ts +2 -0
- package/runtime/MarkerController.js +88 -7
- package/runtime/TextController.js +4 -0
- package/runtime/tests/TestInterpolationNestedPropertyComponentBase.d.ts +10 -0
- package/runtime/tests/TestInterpolationNestedPropertyComponentBase.js +27 -0
- package/runtime/tests/TestInterpolationNestedPropertyContainerClass.d.ts +4 -0
- package/runtime/tests/TestInterpolationNestedPropertyContainerClass.js +4 -0
- package/runtime/tests/TestPropertyBindingPipeChildComponent.d.ts +10 -0
- package/runtime/tests/TestPropertyBindingPipeChildComponent.js +19 -0
- package/runtime/tests/TestPropertyBindingPipeParentComponent.d.ts +9 -0
- package/runtime/tests/TestPropertyBindingPipeParentComponent.js +18 -0
- package/runtime/tests/createPropertyBindingPipeChildComponent.d.ts +2 -0
- package/runtime/tests/createPropertyBindingPipeChildComponent.js +5 -0
- package/runtime/tests/createPropertyBindingPipeParentComponent.d.ts +2 -0
- package/runtime/tests/createPropertyBindingPipeParentComponent.js +5 -0
- package/runtime/tests/createTestInterpolationNestedPropertyComponent.d.ts +2 -0
- package/runtime/tests/createTestInterpolationNestedPropertyComponent.js +5 -0
package/package.json
CHANGED
package/runtime/FluffBase.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ export interface BindingInfo {
|
|
|
12
12
|
t?: string;
|
|
13
13
|
d?: PropertyChain[];
|
|
14
14
|
s?: string;
|
|
15
|
+
p?: {
|
|
16
|
+
n: string;
|
|
17
|
+
a: number[];
|
|
18
|
+
}[];
|
|
15
19
|
}
|
|
16
20
|
export declare abstract class FluffBase extends HTMLElement {
|
|
17
21
|
static __e: ExpressionFn[];
|
|
@@ -27,6 +31,12 @@ export declare abstract class FluffBase extends HTMLElement {
|
|
|
27
31
|
protected __applyBindingWithScope(el: HTMLElement, binding: BindingInfo, scope: Scope, subscriptions?: Subscription[]): void;
|
|
28
32
|
protected __getCompiledExprFn(exprId: number): ExpressionFn;
|
|
29
33
|
protected __getCompiledHandlerFn(handlerId: number): HandlerFn;
|
|
34
|
+
protected __applyPipes(value: unknown, pipes: {
|
|
35
|
+
n: string;
|
|
36
|
+
a: number[];
|
|
37
|
+
}[], locals: Record<string, unknown>): unknown;
|
|
38
|
+
private __applyPipe;
|
|
39
|
+
protected __getPipeFn(_name: string): ((value: unknown, ...args: unknown[]) => unknown) | undefined;
|
|
30
40
|
protected __subscribeToExpressionInScope(deps: PropertyChain[] | undefined, scope: Scope, callback: () => void, subscriptions?: Subscription[]): void;
|
|
31
41
|
private __subscribeToPropertyChain;
|
|
32
42
|
private __subscribeToNestedChain;
|
package/runtime/FluffBase.js
CHANGED
|
@@ -74,6 +74,25 @@ export class FluffBase extends HTMLElement {
|
|
|
74
74
|
}
|
|
75
75
|
return fn;
|
|
76
76
|
}
|
|
77
|
+
__applyPipes(value, pipes, locals) {
|
|
78
|
+
let result = value;
|
|
79
|
+
for (const pipe of pipes) {
|
|
80
|
+
result = this.__applyPipe(pipe.n, result, pipe.a, locals);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
__applyPipe(name, value, argExprIds, locals) {
|
|
85
|
+
const pipeFn = this.__getPipeFn(name);
|
|
86
|
+
if (!pipeFn) {
|
|
87
|
+
console.warn(`Pipe "${name}" not found`);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
const args = argExprIds.map(id => this.__getCompiledExprFn(id)(this, locals));
|
|
91
|
+
return pipeFn(value, ...args);
|
|
92
|
+
}
|
|
93
|
+
__getPipeFn(_name) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
77
96
|
__subscribeToExpressionInScope(deps, scope, callback, subscriptions) {
|
|
78
97
|
if (!deps)
|
|
79
98
|
return;
|
|
@@ -222,7 +241,10 @@ export class FluffBase extends HTMLElement {
|
|
|
222
241
|
throw new Error(`Binding for ${binding.n} is missing exprId`);
|
|
223
242
|
}
|
|
224
243
|
const fn = this.__getCompiledExprFn(binding.e);
|
|
225
|
-
|
|
244
|
+
let value = fn(this, scope.locals);
|
|
245
|
+
if (binding.p && binding.p.length > 0) {
|
|
246
|
+
value = this.__applyPipes(value, binding.p, scope.locals);
|
|
247
|
+
}
|
|
226
248
|
this.__setChildProperty(el, binding.n, value);
|
|
227
249
|
}
|
|
228
250
|
catch (e) {
|
|
@@ -21,6 +21,7 @@ export declare abstract class FluffElement extends FluffBase {
|
|
|
21
21
|
protected __setupBindings(): void;
|
|
22
22
|
protected __addSubscription(sub: Subscription): void;
|
|
23
23
|
protected __pipe(name: string, value: unknown, ...args: unknown[]): unknown;
|
|
24
|
+
protected __getPipeFn(name: string): ((value: unknown, ...args: unknown[]) => unknown) | undefined;
|
|
24
25
|
protected __getShadowRoot(): ShadowRoot;
|
|
25
26
|
protected __setMarkerConfigs(configJson: string): void;
|
|
26
27
|
protected __initializeMarkers(MarkerManagerClass: new (host: FluffElement, shadowRoot: ShadowRoot) => MarkerManagerInterface): void;
|
|
@@ -31,6 +31,8 @@ export declare abstract class MarkerController {
|
|
|
31
31
|
protected getScope(): Scope;
|
|
32
32
|
protected collectLocalsFromScope(scope: Scope): Record<string, unknown>;
|
|
33
33
|
protected subscribeTo(deps: PropertyChain[], callback: () => void): void;
|
|
34
|
+
private subscribeToPropertyChain;
|
|
35
|
+
private subscribeToNestedChain;
|
|
34
36
|
protected getReactivePropFromScope(propName: string, scope: Scope): Property<unknown> | undefined;
|
|
35
37
|
protected createChildScope(locals: Record<string, unknown>): Scope;
|
|
36
38
|
protected clearContentBetweenMarkersWithCleanup(bindingsSubscriptions: Subscription[]): void;
|
|
@@ -82,14 +82,95 @@ export class MarkerController {
|
|
|
82
82
|
subscribeTo(deps, callback) {
|
|
83
83
|
const scope = this.getScope();
|
|
84
84
|
for (const dep of deps) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
continue;
|
|
88
|
-
const reactiveProp = this.getReactivePropFromScope(propName, scope);
|
|
89
|
-
if (reactiveProp) {
|
|
90
|
-
const sub = reactiveProp.onChange.subscribe(callback);
|
|
91
|
-
this.subscriptions.push(sub);
|
|
85
|
+
if (Array.isArray(dep)) {
|
|
86
|
+
this.subscribeToPropertyChain(dep, scope, callback);
|
|
92
87
|
}
|
|
88
|
+
else {
|
|
89
|
+
if (dep.startsWith('['))
|
|
90
|
+
continue;
|
|
91
|
+
const reactiveProp = this.getReactivePropFromScope(dep, scope);
|
|
92
|
+
if (reactiveProp) {
|
|
93
|
+
const sub = reactiveProp.onChange.subscribe(callback);
|
|
94
|
+
this.subscriptions.push(sub);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
subscribeToPropertyChain(chain, scope, callback) {
|
|
100
|
+
if (chain.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
const [first, ...rest] = chain;
|
|
103
|
+
if (first.startsWith('['))
|
|
104
|
+
return;
|
|
105
|
+
const reactiveProp = this.getReactivePropFromScope(first, scope);
|
|
106
|
+
if (reactiveProp) {
|
|
107
|
+
if (rest.length === 0) {
|
|
108
|
+
this.subscriptions.push(reactiveProp.onChange.subscribe(callback));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
let nestedSubs = [];
|
|
112
|
+
const resubscribeNested = () => {
|
|
113
|
+
for (const sub of nestedSubs) {
|
|
114
|
+
sub.unsubscribe();
|
|
115
|
+
}
|
|
116
|
+
nestedSubs = [];
|
|
117
|
+
const currentValue = reactiveProp.getValue();
|
|
118
|
+
if (currentValue !== null && currentValue !== undefined) {
|
|
119
|
+
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
120
|
+
nestedSubs.push(sub);
|
|
121
|
+
this.subscriptions.push(sub);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
callback();
|
|
125
|
+
};
|
|
126
|
+
this.subscriptions.push(reactiveProp.onChange.subscribe(resubscribeNested));
|
|
127
|
+
const currentValue = reactiveProp.getValue();
|
|
128
|
+
if (currentValue !== null && currentValue !== undefined) {
|
|
129
|
+
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
130
|
+
nestedSubs.push(sub);
|
|
131
|
+
this.subscriptions.push(sub);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
subscribeToNestedChain(obj, chain, callback, addSub) {
|
|
138
|
+
if (chain.length === 0 || obj === null || obj === undefined)
|
|
139
|
+
return;
|
|
140
|
+
const [first, ...rest] = chain;
|
|
141
|
+
const prop = Reflect.get(obj, first);
|
|
142
|
+
if (prop instanceof Property) {
|
|
143
|
+
if (rest.length === 0) {
|
|
144
|
+
addSub(prop.onChange.subscribe(callback));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
let nestedSubs = [];
|
|
148
|
+
const resubscribeNested = () => {
|
|
149
|
+
for (const sub of nestedSubs) {
|
|
150
|
+
sub.unsubscribe();
|
|
151
|
+
}
|
|
152
|
+
nestedSubs = [];
|
|
153
|
+
const currentValue = prop.getValue();
|
|
154
|
+
if (currentValue !== null && currentValue !== undefined) {
|
|
155
|
+
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
156
|
+
nestedSubs.push(sub);
|
|
157
|
+
addSub(sub);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
callback();
|
|
161
|
+
};
|
|
162
|
+
addSub(prop.onChange.subscribe(resubscribeNested));
|
|
163
|
+
const currentValue = prop.getValue();
|
|
164
|
+
if (currentValue !== null && currentValue !== undefined) {
|
|
165
|
+
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
166
|
+
nestedSubs.push(sub);
|
|
167
|
+
addSub(sub);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (rest.length > 0 && prop !== null && prop !== undefined) {
|
|
173
|
+
this.subscribeToNestedChain(prop, rest, callback, addSub);
|
|
93
174
|
}
|
|
94
175
|
}
|
|
95
176
|
getReactivePropFromScope(propName, scope) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Property } from '../utils/Property.js';
|
|
1
2
|
import { MarkerController } from './MarkerController.js';
|
|
2
3
|
export class TextController extends MarkerController {
|
|
3
4
|
config;
|
|
@@ -13,6 +14,9 @@ export class TextController extends MarkerController {
|
|
|
13
14
|
const pipes = this.config.pipes ?? [];
|
|
14
15
|
const update = () => {
|
|
15
16
|
let result = this.evaluateExpr(this.config.exprId);
|
|
17
|
+
if (result instanceof Property) {
|
|
18
|
+
result = result.getValue();
|
|
19
|
+
}
|
|
16
20
|
for (const pipe of pipes) {
|
|
17
21
|
result = this.applyPipe(pipe.name, result, pipe.argExprIds);
|
|
18
22
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
import { TestInterpolationNestedPropertyContainerClass } from './TestInterpolationNestedPropertyContainerClass.js';
|
|
4
|
+
export declare abstract class TestInterpolationNestedPropertyComponentBase extends FluffElement {
|
|
5
|
+
__hostClass: Property<TestInterpolationNestedPropertyContainerClass>;
|
|
6
|
+
get hostClass(): TestInterpolationNestedPropertyContainerClass;
|
|
7
|
+
set hostClass(val: TestInterpolationNestedPropertyContainerClass);
|
|
8
|
+
protected __render(): void;
|
|
9
|
+
protected __setupBindings(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
import { MarkerManager } from '../MarkerManager.js';
|
|
4
|
+
import { TestInterpolationNestedPropertyContainerClass } from './TestInterpolationNestedPropertyContainerClass.js';
|
|
5
|
+
export class TestInterpolationNestedPropertyComponentBase extends FluffElement {
|
|
6
|
+
__hostClass = new Property({ initialValue: new TestInterpolationNestedPropertyContainerClass(), propertyName: 'hostClass' });
|
|
7
|
+
get hostClass() {
|
|
8
|
+
const val = this.__hostClass.getValue();
|
|
9
|
+
if (!val) {
|
|
10
|
+
throw new Error('hostClass is null');
|
|
11
|
+
}
|
|
12
|
+
return val;
|
|
13
|
+
}
|
|
14
|
+
set hostClass(val) {
|
|
15
|
+
this.__hostClass.setValue(val);
|
|
16
|
+
}
|
|
17
|
+
__render() {
|
|
18
|
+
this.__getShadowRoot().innerHTML = '<!--fluff:text:0--><!--/fluff:text:0-->';
|
|
19
|
+
this.__setMarkerConfigs(JSON.stringify([
|
|
20
|
+
[0, { type: 'text', exprId: 0, deps: [['hostClass', 'childProp']], pipes: [] }]
|
|
21
|
+
]));
|
|
22
|
+
}
|
|
23
|
+
__setupBindings() {
|
|
24
|
+
this.__initializeMarkers(MarkerManager);
|
|
25
|
+
super.__setupBindings();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
export declare let testPropertyBindingPipeReceivedValue: unknown;
|
|
4
|
+
export declare function resetTestPropertyBindingPipeReceivedValue(): void;
|
|
5
|
+
export declare class TestPropertyBindingPipeChildComponent extends FluffElement {
|
|
6
|
+
__value: Property<unknown>;
|
|
7
|
+
get value(): unknown;
|
|
8
|
+
set value(val: unknown);
|
|
9
|
+
protected __render(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
export let testPropertyBindingPipeReceivedValue = undefined;
|
|
4
|
+
export function resetTestPropertyBindingPipeReceivedValue() {
|
|
5
|
+
testPropertyBindingPipeReceivedValue = undefined;
|
|
6
|
+
}
|
|
7
|
+
export class TestPropertyBindingPipeChildComponent extends FluffElement {
|
|
8
|
+
__value = new Property({ initialValue: undefined, propertyName: 'value' });
|
|
9
|
+
get value() {
|
|
10
|
+
return this.__value.getValue();
|
|
11
|
+
}
|
|
12
|
+
set value(val) {
|
|
13
|
+
this.__value.setValue(val);
|
|
14
|
+
testPropertyBindingPipeReceivedValue = val;
|
|
15
|
+
}
|
|
16
|
+
__render() {
|
|
17
|
+
this.__getShadowRoot().innerHTML = '<span>child</span>';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
export declare class TestPropertyBindingPipeParentComponent extends FluffElement {
|
|
4
|
+
__amount: Property<number>;
|
|
5
|
+
get amount(): number;
|
|
6
|
+
set amount(val: number);
|
|
7
|
+
__pipes: Record<string, (v: unknown, ...args: unknown[]) => unknown>;
|
|
8
|
+
protected __render(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Property } from '../../utils/Property.js';
|
|
2
|
+
import { FluffElement } from '../FluffElement.js';
|
|
3
|
+
export class TestPropertyBindingPipeParentComponent extends FluffElement {
|
|
4
|
+
__amount = new Property({ initialValue: 100, propertyName: 'amount' });
|
|
5
|
+
get amount() {
|
|
6
|
+
return this.__amount.getValue() ?? 0;
|
|
7
|
+
}
|
|
8
|
+
set amount(val) {
|
|
9
|
+
this.__amount.setValue(val);
|
|
10
|
+
}
|
|
11
|
+
__pipes = {
|
|
12
|
+
double: (v) => (typeof v === 'number' ? v * 2 : 0),
|
|
13
|
+
addSuffix: (v, suffix) => `${String(v)}${String(suffix)}`
|
|
14
|
+
};
|
|
15
|
+
__render() {
|
|
16
|
+
this.__getShadowRoot().innerHTML = '<test-child data-lid="l0"></test-child>';
|
|
17
|
+
}
|
|
18
|
+
}
|