@praxisjs/decorators 1.4.1 → 1.5.1
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/CHANGELOG.md +30 -0
- package/dist/__tests__/component.test.js +2 -1
- package/dist/__tests__/component.test.js.map +1 -1
- package/dist/__tests__/events.test.js +4 -3
- package/dist/__tests__/events.test.js.map +1 -1
- package/dist/__tests__/lazy.test.js +17 -17
- package/dist/__tests__/lazy.test.js.map +1 -1
- package/dist/__tests__/properties.test.js +67 -8
- package/dist/__tests__/properties.test.js.map +1 -1
- package/dist/component/lazy.d.ts.map +1 -1
- package/dist/component/lazy.js +2 -2
- package/dist/component/lazy.js.map +1 -1
- package/dist/events/helper.d.ts +2 -2
- package/dist/events/helper.d.ts.map +1 -1
- package/dist/events/helper.js +3 -2
- package/dist/events/helper.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/properties/deep-state.js +2 -2
- package/dist/properties/deep-state.js.map +1 -1
- package/dist/properties/function-prop.d.ts +2 -0
- package/dist/properties/function-prop.d.ts.map +1 -0
- package/dist/properties/function-prop.js +28 -0
- package/dist/properties/function-prop.js.map +1 -0
- package/dist/properties/index.d.ts +1 -0
- package/dist/properties/index.d.ts.map +1 -1
- package/dist/properties/index.js +1 -0
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/prop.d.ts.map +1 -1
- package/dist/properties/prop.js +5 -4
- package/dist/properties/prop.js.map +1 -1
- package/dist/properties/state.js +2 -2
- package/dist/properties/state.js.map +1 -1
- package/dist/reactive-host.d.ts +7 -3
- package/dist/reactive-host.d.ts.map +1 -1
- package/dist/reactive-host.js +1 -1
- package/dist/reactive-host.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/component.test.ts +2 -1
- package/src/__tests__/events.test.ts +4 -3
- package/src/__tests__/lazy.test.ts +17 -17
- package/src/__tests__/properties.test.ts +89 -8
- package/src/component/lazy.ts +6 -3
- package/src/events/helper.ts +8 -4
- package/src/index.ts +2 -1
- package/src/properties/deep-state.ts +2 -2
- package/src/properties/function-prop.ts +37 -0
- package/src/properties/index.ts +1 -0
- package/src/properties/prop.ts +10 -4
- package/src/properties/state.ts +2 -2
- package/src/reactive-host.ts +7 -3
- package/tsconfig.json +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import { StatefulComponent } from "@praxisjs/core";
|
|
4
|
+
import { setComponentDefault } from "@praxisjs/core/internal";
|
|
4
5
|
|
|
5
6
|
import { createCommand } from "../events/command";
|
|
6
7
|
import { Emit } from "../events/emit";
|
|
@@ -65,14 +66,14 @@ describe("createCommand", () => {
|
|
|
65
66
|
// ── readProp ──────────────────────────────────────────────────────────────────
|
|
66
67
|
|
|
67
68
|
describe("readProp", () => {
|
|
68
|
-
it("returns value from
|
|
69
|
+
it("returns value from raw props when defined", () => {
|
|
69
70
|
const instance = new TestComponent({ myProp: "fromParent" });
|
|
70
71
|
expect(readProp(instance, "myProp")).toBe("fromParent");
|
|
71
72
|
});
|
|
72
73
|
|
|
73
|
-
it("falls back to
|
|
74
|
+
it("falls back to defaults when raw props do not define the prop", () => {
|
|
74
75
|
const instance = new TestComponent();
|
|
75
|
-
instance
|
|
76
|
+
setComponentDefault(instance, "myProp", "default");
|
|
76
77
|
expect(readProp(instance, "myProp")).toBe("default");
|
|
77
78
|
});
|
|
78
79
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { beforeEach, afterEach, describe, it, expect, vi } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { StatefulComponent } from "@praxisjs/core";
|
|
5
|
+
import { setComponentAnchor } from "@praxisjs/core/internal";
|
|
5
6
|
import { Lazy } from "../component/lazy";
|
|
6
7
|
import type { LazyOptions } from "../component/lazy";
|
|
7
8
|
|
|
@@ -55,7 +56,7 @@ describe("Lazy decorator", () => {
|
|
|
55
56
|
expect(resolveRender(instance)).toBeNull();
|
|
56
57
|
});
|
|
57
58
|
|
|
58
|
-
it("sets
|
|
59
|
+
it("sets lazy visibility to true when IntersectionObserver is not supported", () => {
|
|
59
60
|
// Remove IntersectionObserver to simulate unsupported environment
|
|
60
61
|
// @ts-expect-error – removing test stub
|
|
61
62
|
delete globalThis.IntersectionObserver;
|
|
@@ -68,7 +69,7 @@ describe("Lazy decorator", () => {
|
|
|
68
69
|
document.body.appendChild(parent);
|
|
69
70
|
const anchor = document.createComment("end");
|
|
70
71
|
parent.appendChild(anchor);
|
|
71
|
-
(instance
|
|
72
|
+
setComponentAnchor(instance, anchor);
|
|
72
73
|
|
|
73
74
|
instance.onMount?.();
|
|
74
75
|
// Without IntersectionObserver, component should immediately become visible
|
|
@@ -84,7 +85,7 @@ describe("Lazy decorator", () => {
|
|
|
84
85
|
document.body.appendChild(parent);
|
|
85
86
|
const anchor = document.createComment("end");
|
|
86
87
|
parent.appendChild(anchor);
|
|
87
|
-
(instance
|
|
88
|
+
setComponentAnchor(instance, anchor);
|
|
88
89
|
|
|
89
90
|
instance.onMount?.();
|
|
90
91
|
expect(parent.style.minHeight).toBe("300px");
|
|
@@ -99,7 +100,7 @@ describe("Lazy decorator", () => {
|
|
|
99
100
|
document.body.appendChild(parent);
|
|
100
101
|
const anchor = document.createComment("end");
|
|
101
102
|
parent.appendChild(anchor);
|
|
102
|
-
(instance
|
|
103
|
+
setComponentAnchor(instance, anchor);
|
|
103
104
|
|
|
104
105
|
instance.onMount?.();
|
|
105
106
|
expect(resolveRender(instance)).toBeNull();
|
|
@@ -115,12 +116,12 @@ describe("Lazy decorator", () => {
|
|
|
115
116
|
document.body.removeChild(parent);
|
|
116
117
|
});
|
|
117
118
|
|
|
118
|
-
it("does nothing when
|
|
119
|
+
it("does nothing when the anchor has no parent", () => {
|
|
119
120
|
const Wrapped = applyLazy(BaseComp as AnyConstructor);
|
|
120
121
|
const instance = new Wrapped();
|
|
121
122
|
|
|
122
123
|
const anchor = document.createComment("end");
|
|
123
|
-
(instance
|
|
124
|
+
setComponentAnchor(instance, anchor);
|
|
124
125
|
|
|
125
126
|
// Should not throw even though anchor has no parent
|
|
126
127
|
expect(() => instance.onMount?.()).not.toThrow();
|
|
@@ -134,7 +135,7 @@ describe("Lazy decorator", () => {
|
|
|
134
135
|
document.body.appendChild(parent);
|
|
135
136
|
const anchor = document.createComment("end");
|
|
136
137
|
parent.appendChild(anchor);
|
|
137
|
-
(instance
|
|
138
|
+
setComponentAnchor(instance, anchor);
|
|
138
139
|
|
|
139
140
|
instance.onMount?.();
|
|
140
141
|
instance.onUnmount?.();
|
|
@@ -142,10 +143,9 @@ describe("Lazy decorator", () => {
|
|
|
142
143
|
document.body.removeChild(parent);
|
|
143
144
|
});
|
|
144
145
|
|
|
145
|
-
it("onMount does nothing when
|
|
146
|
+
it("onMount does nothing when anchor is undefined", () => {
|
|
146
147
|
const Wrapped = applyLazy(BaseComp as AnyConstructor);
|
|
147
148
|
const instance = new Wrapped();
|
|
148
|
-
// _anchor is undefined by default
|
|
149
149
|
expect(() => instance.onMount?.()).not.toThrow();
|
|
150
150
|
});
|
|
151
151
|
|
|
@@ -157,7 +157,7 @@ describe("Lazy decorator", () => {
|
|
|
157
157
|
document.body.appendChild(parent);
|
|
158
158
|
const anchor = document.createComment("end");
|
|
159
159
|
parent.appendChild(anchor);
|
|
160
|
-
(instance
|
|
160
|
+
setComponentAnchor(instance, anchor);
|
|
161
161
|
|
|
162
162
|
instance.onMount?.();
|
|
163
163
|
expect(resolveRender(instance)).toBeNull(); // not yet visible
|
|
@@ -181,7 +181,7 @@ describe("Lazy decorator", () => {
|
|
|
181
181
|
document.body.appendChild(parent);
|
|
182
182
|
const anchor = document.createComment("end");
|
|
183
183
|
parent.appendChild(anchor);
|
|
184
|
-
(instance
|
|
184
|
+
setComponentAnchor(instance, anchor);
|
|
185
185
|
|
|
186
186
|
instance.onMount?.();
|
|
187
187
|
|
|
@@ -205,7 +205,7 @@ describe("Lazy decorator", () => {
|
|
|
205
205
|
document.body.appendChild(parent);
|
|
206
206
|
const anchor = document.createComment("end");
|
|
207
207
|
parent.appendChild(anchor);
|
|
208
|
-
(instance
|
|
208
|
+
setComponentAnchor(instance, anchor);
|
|
209
209
|
|
|
210
210
|
instance.onMount?.();
|
|
211
211
|
expect(parent.style.minHeight).toBe("150px");
|
|
@@ -233,7 +233,7 @@ describe("Lazy decorator", () => {
|
|
|
233
233
|
document.body.appendChild(parent);
|
|
234
234
|
const anchor = document.createComment("end");
|
|
235
235
|
parent.appendChild(anchor);
|
|
236
|
-
(instance
|
|
236
|
+
setComponentAnchor(instance, anchor);
|
|
237
237
|
|
|
238
238
|
instance.onMount?.();
|
|
239
239
|
expect(capturedInit?.root).toBe(rootEl);
|
|
@@ -260,7 +260,7 @@ describe("Lazy decorator", () => {
|
|
|
260
260
|
document.body.appendChild(parent);
|
|
261
261
|
const anchor = document.createComment("end");
|
|
262
262
|
parent.appendChild(anchor);
|
|
263
|
-
(instance
|
|
263
|
+
setComponentAnchor(instance, anchor);
|
|
264
264
|
|
|
265
265
|
instance.onMount?.();
|
|
266
266
|
expect(capturedInit?.root).toBeNull();
|
|
@@ -276,7 +276,7 @@ describe("Lazy decorator", () => {
|
|
|
276
276
|
document.body.appendChild(parent);
|
|
277
277
|
const anchor = document.createComment("end");
|
|
278
278
|
parent.appendChild(anchor);
|
|
279
|
-
(instance
|
|
279
|
+
setComponentAnchor(instance, anchor);
|
|
280
280
|
|
|
281
281
|
// First mount — become visible
|
|
282
282
|
instance.onMount?.();
|
|
@@ -286,10 +286,10 @@ describe("Lazy decorator", () => {
|
|
|
286
286
|
);
|
|
287
287
|
instance.onUnmount?.();
|
|
288
288
|
|
|
289
|
-
// Second mount —
|
|
289
|
+
// Second mount — lazy visibility is already true
|
|
290
290
|
instance.onMount?.();
|
|
291
291
|
|
|
292
|
-
// minHeight must NOT be re-applied because
|
|
292
|
+
// minHeight must NOT be re-applied because lazy visibility is true
|
|
293
293
|
expect(parent.style.minHeight).toBe("");
|
|
294
294
|
document.body.removeChild(parent);
|
|
295
295
|
});
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import { StatefulComponent } from "@praxisjs/core";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
computed,
|
|
6
|
+
isStateDirty,
|
|
7
|
+
setStateDirty,
|
|
8
|
+
signal,
|
|
9
|
+
} from "@praxisjs/core/internal";
|
|
5
10
|
|
|
6
11
|
import { createFieldDecorator } from "../create-field-decorator";
|
|
7
12
|
import { createGetterDecorator } from "../create-getter-decorator";
|
|
@@ -11,6 +16,7 @@ import { When } from "../functions/when";
|
|
|
11
16
|
import { Compose } from "../properties/compose";
|
|
12
17
|
import { Computed } from "../properties/computed";
|
|
13
18
|
import { History } from "../properties/history";
|
|
19
|
+
import { FunctionProp } from "../properties/function-prop";
|
|
14
20
|
import { Prop } from "../properties/prop";
|
|
15
21
|
import { State } from "../properties/state";
|
|
16
22
|
|
|
@@ -68,7 +74,7 @@ describe("State decorator", () => {
|
|
|
68
74
|
expect((instance as unknown as Record<string, unknown>).count).toBe(20);
|
|
69
75
|
});
|
|
70
76
|
|
|
71
|
-
it("sets
|
|
77
|
+
it("sets state dirty on write", () => {
|
|
72
78
|
const { ctx, run } = fieldCtx("value");
|
|
73
79
|
State()(undefined, ctx);
|
|
74
80
|
|
|
@@ -76,9 +82,9 @@ describe("State decorator", () => {
|
|
|
76
82
|
(instance as unknown as Record<string, unknown>).value = "hello";
|
|
77
83
|
run(instance);
|
|
78
84
|
|
|
79
|
-
instance
|
|
85
|
+
setStateDirty(instance, false);
|
|
80
86
|
(instance as unknown as Record<string, unknown>).value = "world";
|
|
81
|
-
expect(instance
|
|
87
|
+
expect(isStateDirty(instance)).toBe(true);
|
|
82
88
|
});
|
|
83
89
|
|
|
84
90
|
it("accepts null as initial value", () => {
|
|
@@ -115,7 +121,7 @@ describe("State decorator", () => {
|
|
|
115
121
|
// ── Prop ──────────────────────────────────────────────────────────────────────
|
|
116
122
|
|
|
117
123
|
describe("Prop decorator", () => {
|
|
118
|
-
it("reads from
|
|
124
|
+
it("reads from raw props when set by parent", () => {
|
|
119
125
|
const { ctx, run } = fieldCtx("label");
|
|
120
126
|
Prop()(undefined, ctx);
|
|
121
127
|
|
|
@@ -125,7 +131,7 @@ describe("Prop decorator", () => {
|
|
|
125
131
|
expect((instance as unknown as Record<string, unknown>).label).toBe("hello");
|
|
126
132
|
});
|
|
127
133
|
|
|
128
|
-
it("falls back to default value when not in
|
|
134
|
+
it("falls back to default value when not in raw props", () => {
|
|
129
135
|
const { ctx, run } = fieldCtx("size");
|
|
130
136
|
Prop()(undefined, ctx);
|
|
131
137
|
|
|
@@ -150,6 +156,81 @@ describe("Prop decorator", () => {
|
|
|
150
156
|
});
|
|
151
157
|
});
|
|
152
158
|
|
|
159
|
+
// ── FunctionProp ──────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
describe("FunctionProp decorator", () => {
|
|
162
|
+
it("reads function values from raw props without invoking them", () => {
|
|
163
|
+
const { ctx, run } = fieldCtx("filter");
|
|
164
|
+
FunctionProp()(undefined, ctx);
|
|
165
|
+
|
|
166
|
+
const filter = vi.fn((value: number) => value > 1);
|
|
167
|
+
const instance = new TestComponent({ filter });
|
|
168
|
+
run(instance);
|
|
169
|
+
|
|
170
|
+
const received = (instance as unknown as Record<string, unknown>).filter;
|
|
171
|
+
expect(received).toBe(filter);
|
|
172
|
+
expect(filter).not.toHaveBeenCalled();
|
|
173
|
+
expect((received as (value: number) => boolean)(2)).toBe(true);
|
|
174
|
+
expect(filter).toHaveBeenCalledWith(2);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("falls back to the default function when not in raw props", () => {
|
|
178
|
+
const { ctx, run } = fieldCtx("filter");
|
|
179
|
+
FunctionProp()(undefined, ctx);
|
|
180
|
+
|
|
181
|
+
const defaultFilter = vi.fn((value: number) => value % 2 === 0);
|
|
182
|
+
const instance = new TestComponent();
|
|
183
|
+
(instance as unknown as Record<string, unknown>).filter = defaultFilter;
|
|
184
|
+
run(instance);
|
|
185
|
+
|
|
186
|
+
const received = (instance as unknown as Record<string, unknown>).filter;
|
|
187
|
+
expect(received).toBe(defaultFilter);
|
|
188
|
+
expect((received as (value: number) => boolean)(4)).toBe(true);
|
|
189
|
+
expect(defaultFilter).toHaveBeenCalledWith(4);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("set() updates the default function used without a raw prop", () => {
|
|
193
|
+
const { ctx, run } = fieldCtx("filter");
|
|
194
|
+
FunctionProp()(undefined, ctx);
|
|
195
|
+
|
|
196
|
+
const instance = new TestComponent();
|
|
197
|
+
run(instance);
|
|
198
|
+
|
|
199
|
+
const nextFilter = (value: number) => value < 10;
|
|
200
|
+
(instance as unknown as Record<string, unknown>).filter = nextFilter;
|
|
201
|
+
|
|
202
|
+
expect((instance as unknown as Record<string, unknown>).filter).toBe(nextFilter);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("warns on a non-function raw prop in non-production", () => {
|
|
206
|
+
const { ctx, run } = fieldCtx("filter");
|
|
207
|
+
FunctionProp()(undefined, ctx);
|
|
208
|
+
|
|
209
|
+
const instance = new TestComponent({ filter: "not-a-function" });
|
|
210
|
+
run(instance);
|
|
211
|
+
|
|
212
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
213
|
+
expect((instance as unknown as Record<string, unknown>).filter).toBe("not-a-function");
|
|
214
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining("[FunctionProp]"));
|
|
215
|
+
warn.mockRestore();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("does not warn in production", () => {
|
|
219
|
+
const { ctx, run } = fieldCtx("filter");
|
|
220
|
+
FunctionProp()(undefined, ctx);
|
|
221
|
+
|
|
222
|
+
const instance = new TestComponent({ filter: "not-a-function" });
|
|
223
|
+
run(instance);
|
|
224
|
+
|
|
225
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
226
|
+
vi.stubEnv("NODE_ENV", "production");
|
|
227
|
+
expect((instance as unknown as Record<string, unknown>).filter).toBe("not-a-function");
|
|
228
|
+
expect(warn).not.toHaveBeenCalled();
|
|
229
|
+
vi.unstubAllEnvs();
|
|
230
|
+
warn.mockRestore();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
153
234
|
// ── Computed ──────────────────────────────────────────────────────────────────
|
|
154
235
|
|
|
155
236
|
describe("Computed decorator", () => {
|
|
@@ -832,7 +913,7 @@ describe("When decorator", () => {
|
|
|
832
913
|
// ── Prop (additional branches) ────────────────────────────────────────────────
|
|
833
914
|
|
|
834
915
|
describe("Prop decorator — additional branches", () => {
|
|
835
|
-
it("set() updates the default value (used when no
|
|
916
|
+
it("set() updates the default value (used when no raw props entry)", () => {
|
|
836
917
|
const { ctx, run } = fieldCtx("size");
|
|
837
918
|
Prop()(undefined, ctx);
|
|
838
919
|
|
|
@@ -840,7 +921,7 @@ describe("Prop decorator — additional branches", () => {
|
|
|
840
921
|
(instance as unknown as Record<string, unknown>).size = "sm";
|
|
841
922
|
run(instance);
|
|
842
923
|
|
|
843
|
-
// Setter path: updates
|
|
924
|
+
// Setter path: updates defaults.
|
|
844
925
|
(instance as unknown as Record<string, unknown>).size = "lg";
|
|
845
926
|
expect((instance as unknown as Record<string, unknown>).size).toBe("lg");
|
|
846
927
|
});
|
package/src/component/lazy.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getComponentAnchor,
|
|
3
|
+
type RootComponent,
|
|
4
|
+
signal,
|
|
5
|
+
} from "@praxisjs/core/internal";
|
|
2
6
|
|
|
3
7
|
import { ClassBehavior, createClassDecorator, type ClassEnhancement } from "../create-class-decorator";
|
|
4
8
|
|
|
@@ -27,8 +31,7 @@ class LazyBehavior extends ClassBehavior {
|
|
|
27
31
|
|
|
28
32
|
return {
|
|
29
33
|
onMount() {
|
|
30
|
-
const el =
|
|
31
|
-
(instance as { _anchor?: Comment })._anchor?.parentElement ?? null;
|
|
34
|
+
const el = getComponentAnchor(instance)?.parentElement ?? null;
|
|
32
35
|
if (!el) return;
|
|
33
36
|
|
|
34
37
|
if (!("IntersectionObserver" in window)) {
|
package/src/events/helper.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
getComponentDefault,
|
|
3
|
+
getComponentRawProp,
|
|
4
|
+
type RootComponent,
|
|
5
|
+
} from "@praxisjs/core/internal";
|
|
2
6
|
|
|
3
7
|
export function readProp(
|
|
4
|
-
instance:
|
|
8
|
+
instance: RootComponent<Record<string, unknown>>,
|
|
5
9
|
propName: string,
|
|
6
10
|
): unknown {
|
|
7
|
-
const fromParent = instance
|
|
11
|
+
const fromParent = getComponentRawProp(instance, propName);
|
|
8
12
|
if (fromParent !== undefined) return fromParent;
|
|
9
|
-
return instance
|
|
13
|
+
return getComponentDefault(instance, propName);
|
|
10
14
|
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export {
|
|
|
15
15
|
} from "./functions";
|
|
16
16
|
export {
|
|
17
17
|
Prop,
|
|
18
|
+
FunctionProp,
|
|
18
19
|
State,
|
|
19
20
|
Computed,
|
|
20
21
|
Persisted,
|
|
@@ -39,7 +40,7 @@ export {
|
|
|
39
40
|
type FieldBehavior,
|
|
40
41
|
type FieldBinding,
|
|
41
42
|
} from "./create-field-decorator";
|
|
42
|
-
export { type ReactiveHost } from "./reactive-host";
|
|
43
|
+
export { reactiveHostType, type ReactiveHost } from "./reactive-host";
|
|
43
44
|
export {
|
|
44
45
|
createClassDecorator,
|
|
45
46
|
ClassBehavior,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { signal } from "@praxisjs/core/internal";
|
|
1
|
+
import { markStateDirty, signal } from "@praxisjs/core/internal";
|
|
2
2
|
|
|
3
3
|
import { createFieldDecorator } from "../create-field-decorator";
|
|
4
4
|
|
|
@@ -37,7 +37,7 @@ export function DeepState() {
|
|
|
37
37
|
: current;
|
|
38
38
|
|
|
39
39
|
function notify() {
|
|
40
|
-
instance
|
|
40
|
+
markStateDirty(instance);
|
|
41
41
|
version.update((v) => v + 1);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getComponentDefault,
|
|
3
|
+
getComponentRawProp,
|
|
4
|
+
setComponentDefault,
|
|
5
|
+
} from "@praxisjs/core/internal";
|
|
6
|
+
|
|
7
|
+
import { createFieldDecorator } from "../create-field-decorator";
|
|
8
|
+
|
|
9
|
+
export function FunctionProp() {
|
|
10
|
+
return createFieldDecorator({
|
|
11
|
+
bind(instance, name, initialValue) {
|
|
12
|
+
setComponentDefault(instance, name, initialValue);
|
|
13
|
+
return {
|
|
14
|
+
descriptor: {
|
|
15
|
+
get() {
|
|
16
|
+
const fromParent = getComponentRawProp(instance, name);
|
|
17
|
+
if (fromParent !== undefined) {
|
|
18
|
+
if (
|
|
19
|
+
process.env.NODE_ENV !== "production" &&
|
|
20
|
+
typeof fromParent !== "function"
|
|
21
|
+
) {
|
|
22
|
+
console.warn(
|
|
23
|
+
`[FunctionProp] "${name}" received a non-function value (${typeof fromParent}). @FunctionProp() expects a function.`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return fromParent;
|
|
27
|
+
}
|
|
28
|
+
return getComponentDefault(instance, name);
|
|
29
|
+
},
|
|
30
|
+
set(value: unknown) {
|
|
31
|
+
setComponentDefault(instance, name, value);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
package/src/properties/index.ts
CHANGED
package/src/properties/prop.ts
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getComponentDefault,
|
|
3
|
+
getComponentRawProp,
|
|
4
|
+
setComponentDefault,
|
|
5
|
+
} from "@praxisjs/core/internal";
|
|
6
|
+
|
|
1
7
|
import { createFieldDecorator } from "../create-field-decorator";
|
|
2
8
|
|
|
3
9
|
export function Prop() {
|
|
4
10
|
return createFieldDecorator({
|
|
5
11
|
bind(instance, name, initialValue) {
|
|
6
|
-
instance
|
|
12
|
+
setComponentDefault(instance, name, initialValue);
|
|
7
13
|
return {
|
|
8
14
|
descriptor: {
|
|
9
15
|
get() {
|
|
10
|
-
const fromParent = (instance
|
|
16
|
+
const fromParent = getComponentRawProp(instance, name);
|
|
11
17
|
if (fromParent !== undefined) {
|
|
12
18
|
return typeof fromParent === "function"
|
|
13
19
|
? (fromParent as () => unknown)()
|
|
14
20
|
: fromParent;
|
|
15
21
|
}
|
|
16
|
-
return instance
|
|
22
|
+
return getComponentDefault(instance, name);
|
|
17
23
|
},
|
|
18
24
|
set(value: unknown) {
|
|
19
|
-
instance
|
|
25
|
+
setComponentDefault(instance, name, value);
|
|
20
26
|
},
|
|
21
27
|
},
|
|
22
28
|
};
|
package/src/properties/state.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { signal } from "@praxisjs/core/internal";
|
|
1
|
+
import { markStateDirty, signal } from "@praxisjs/core/internal";
|
|
2
2
|
|
|
3
3
|
import { createFieldDecorator } from "../create-field-decorator";
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ export function State() {
|
|
|
12
12
|
descriptor: {
|
|
13
13
|
get: () => sig(),
|
|
14
14
|
set: (value: unknown) => {
|
|
15
|
-
instance
|
|
15
|
+
markStateDirty(instance);
|
|
16
16
|
sig.set(value);
|
|
17
17
|
},
|
|
18
18
|
},
|
package/src/reactive-host.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { componentPropsType } from "@praxisjs/core/internal";
|
|
2
|
+
|
|
3
|
+
export const reactiveHostType: unique symbol = Symbol("praxis.reactiveHostType");
|
|
4
|
+
|
|
5
|
+
export type ReactiveHost =
|
|
6
|
+
| { readonly [componentPropsType]: object }
|
|
7
|
+
| { readonly [reactiveHostType]: true };
|