rask-ui 0.28.3 → 0.29.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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/dist/component.d.ts +4 -3
  3. package/dist/component.d.ts.map +1 -1
  4. package/dist/component.js +37 -57
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +0 -1
  8. package/dist/render.js +2 -2
  9. package/dist/scheduler.d.ts +2 -3
  10. package/dist/scheduler.d.ts.map +1 -1
  11. package/dist/scheduler.js +31 -104
  12. package/dist/tests/batch.test.js +202 -12
  13. package/dist/tests/createContext.test.js +50 -37
  14. package/dist/tests/error.test.js +25 -12
  15. package/dist/tests/renderCount.test.d.ts +2 -0
  16. package/dist/tests/renderCount.test.d.ts.map +1 -0
  17. package/dist/tests/renderCount.test.js +95 -0
  18. package/dist/tests/scopeEnforcement.test.d.ts +2 -0
  19. package/dist/tests/scopeEnforcement.test.d.ts.map +1 -0
  20. package/dist/tests/scopeEnforcement.test.js +157 -0
  21. package/dist/tests/useAction.test.d.ts +2 -0
  22. package/dist/tests/useAction.test.d.ts.map +1 -0
  23. package/dist/tests/useAction.test.js +132 -0
  24. package/dist/tests/useAsync.test.d.ts +2 -0
  25. package/dist/tests/useAsync.test.d.ts.map +1 -0
  26. package/dist/tests/useAsync.test.js +499 -0
  27. package/dist/tests/useDerived.test.d.ts +2 -0
  28. package/dist/tests/useDerived.test.d.ts.map +1 -0
  29. package/dist/tests/useDerived.test.js +407 -0
  30. package/dist/tests/useEffect.test.d.ts +2 -0
  31. package/dist/tests/useEffect.test.d.ts.map +1 -0
  32. package/dist/tests/useEffect.test.js +600 -0
  33. package/dist/tests/useLookup.test.d.ts +2 -0
  34. package/dist/tests/useLookup.test.d.ts.map +1 -0
  35. package/dist/tests/useLookup.test.js +299 -0
  36. package/dist/tests/useRef.test.d.ts +2 -0
  37. package/dist/tests/useRef.test.d.ts.map +1 -0
  38. package/dist/tests/useRef.test.js +189 -0
  39. package/dist/tests/useState.test.d.ts +2 -0
  40. package/dist/tests/useState.test.d.ts.map +1 -0
  41. package/dist/tests/useState.test.js +178 -0
  42. package/dist/tests/useSuspend.test.d.ts +2 -0
  43. package/dist/tests/useSuspend.test.d.ts.map +1 -0
  44. package/dist/tests/useSuspend.test.js +752 -0
  45. package/dist/tests/useView.test.d.ts +2 -0
  46. package/dist/tests/useView.test.d.ts.map +1 -0
  47. package/dist/tests/useView.test.js +305 -0
  48. package/dist/useAsync.d.ts.map +1 -1
  49. package/dist/useAsync.js +12 -11
  50. package/dist/useDerived.d.ts +1 -1
  51. package/dist/useDerived.d.ts.map +1 -1
  52. package/dist/useDerived.js +9 -63
  53. package/dist/useEffect.d.ts.map +1 -1
  54. package/dist/useEffect.js +4 -19
  55. package/dist/useLookup.d.ts.map +1 -1
  56. package/dist/useLookup.js +9 -14
  57. package/dist/useRef.d.ts.map +1 -1
  58. package/dist/useRef.js +4 -8
  59. package/dist/useRouter.d.ts.map +1 -1
  60. package/dist/useRouter.js +4 -8
  61. package/dist/useState.d.ts +0 -1
  62. package/dist/useState.d.ts.map +1 -1
  63. package/dist/useState.js +2 -100
  64. package/dist/useSuspend.d.ts.map +1 -1
  65. package/package.json +1 -1
@@ -1,21 +1,21 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "./jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "rask-ui/jsx-runtime";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { createContext } from "../createContext";
4
4
  import { render } from "../";
5
5
  describe("createContext", () => {
6
- it("should create a context object", () => {
7
- const context = createContext();
8
- expect(context).toHaveProperty("inject");
9
- expect(context).toHaveProperty("get");
6
+ it("should create a context with use and inject methods", () => {
7
+ const MyContext = createContext(() => ({ value: "test" }));
8
+ expect(typeof MyContext.use).toBe("function");
9
+ expect(typeof MyContext.inject).toBe("function");
10
10
  });
11
11
  it("should allow setting and getting context values", () => {
12
- const ThemeContext = createContext();
12
+ const ThemeContext = createContext(() => ({ theme: "dark" }));
13
13
  function Parent() {
14
- ThemeContext.inject({ theme: "dark" });
14
+ ThemeContext.inject();
15
15
  return () => _jsx(Child, {});
16
16
  }
17
17
  function Child() {
18
- const theme = ThemeContext.get();
18
+ const theme = ThemeContext.use();
19
19
  return () => _jsx("div", { children: theme.theme });
20
20
  }
21
21
  const container = document.createElement("div");
@@ -25,16 +25,16 @@ describe("createContext", () => {
25
25
  document.body.removeChild(container);
26
26
  });
27
27
  it("should traverse parent components to find context", () => {
28
- const ThemeContext = createContext();
28
+ const ThemeContext = createContext(() => ({ theme: "light" }));
29
29
  function GrandParent() {
30
- ThemeContext.inject({ theme: "light" });
30
+ ThemeContext.inject();
31
31
  return () => _jsx(Parent, {});
32
32
  }
33
33
  function Parent() {
34
34
  return () => _jsx(Child, {});
35
35
  }
36
36
  function Child() {
37
- const theme = ThemeContext.get();
37
+ const theme = ThemeContext.use();
38
38
  return () => _jsx("div", { children: theme.theme });
39
39
  }
40
40
  const container = document.createElement("div");
@@ -44,11 +44,11 @@ describe("createContext", () => {
44
44
  document.body.removeChild(container);
45
45
  });
46
46
  it("should throw error when context is not found", () => {
47
- const ThemeContext = createContext();
47
+ const ThemeContext = createContext(() => ({ theme: "dark" }));
48
48
  function Child() {
49
49
  expect(() => {
50
- ThemeContext.get();
51
- }).toThrow("There is no parent context");
50
+ ThemeContext.use();
51
+ }).toThrow("No context available");
52
52
  return () => _jsx("div", { children: "Child" });
53
53
  }
54
54
  const container = document.createElement("div");
@@ -57,33 +57,33 @@ describe("createContext", () => {
57
57
  document.body.removeChild(container);
58
58
  });
59
59
  it("should throw error when setting context outside component", () => {
60
- const ThemeContext = createContext();
60
+ const ThemeContext = createContext(() => ({ theme: "dark" }));
61
61
  expect(() => {
62
- ThemeContext.inject({ theme: "dark" });
63
- }).toThrow("No current component");
62
+ ThemeContext.inject();
63
+ }).toThrow("Only use useInjectContext in component setup");
64
64
  });
65
65
  it("should throw error when getting context outside component", () => {
66
- const ThemeContext = createContext();
66
+ const ThemeContext = createContext(() => ({ theme: "dark" }));
67
67
  expect(() => {
68
- ThemeContext.get();
69
- }).toThrow("No current component");
68
+ ThemeContext.use();
69
+ }).toThrow("Only use useContext in component setup");
70
70
  });
71
71
  it("should allow overriding context in nested components", () => {
72
- const ThemeContext = createContext();
72
+ const ThemeContext = createContext((theme) => ({ theme }));
73
73
  function GrandParent() {
74
- ThemeContext.inject({ theme: "light" });
74
+ ThemeContext.inject("light");
75
75
  return () => (_jsxs("div", { children: [_jsx(Parent, {}), _jsx(ChildOfGrandParent, {})] }));
76
76
  }
77
77
  function Parent() {
78
- ThemeContext.inject({ theme: "dark" });
78
+ ThemeContext.inject("dark");
79
79
  return () => _jsx(ChildOfParent, {});
80
80
  }
81
81
  function ChildOfParent() {
82
- const theme = ThemeContext.get();
82
+ const theme = ThemeContext.use();
83
83
  return () => _jsx("div", { class: "child-of-parent", children: theme.theme });
84
84
  }
85
85
  function ChildOfGrandParent() {
86
- const theme = ThemeContext.get();
86
+ const theme = ThemeContext.use();
87
87
  return () => _jsx("div", { class: "child-of-grandparent", children: theme.theme });
88
88
  }
89
89
  const container = document.createElement("div");
@@ -96,16 +96,16 @@ describe("createContext", () => {
96
96
  document.body.removeChild(container);
97
97
  });
98
98
  it("should support multiple different contexts", () => {
99
- const ThemeContext = createContext();
100
- const UserContext = createContext();
99
+ const ThemeContext = createContext(() => ({ theme: "dark" }));
100
+ const UserContext = createContext(() => ({ name: "Alice" }));
101
101
  function Parent() {
102
- ThemeContext.inject({ theme: "dark" });
103
- UserContext.inject({ name: "Alice" });
102
+ ThemeContext.inject();
103
+ UserContext.inject();
104
104
  return () => _jsx(Child, {});
105
105
  }
106
106
  function Child() {
107
- const theme = ThemeContext.get();
108
- const user = UserContext.get();
107
+ const theme = ThemeContext.use();
108
+ const user = UserContext.use();
109
109
  return () => _jsx("div", { children: `${theme.theme} - ${user.name}` });
110
110
  }
111
111
  const container = document.createElement("div");
@@ -115,16 +115,16 @@ describe("createContext", () => {
115
115
  document.body.removeChild(container);
116
116
  });
117
117
  it("should handle context values of different types", () => {
118
- const NumberContext = createContext();
119
- const ArrayContext = createContext();
118
+ const NumberContext = createContext(() => 42);
119
+ const ArrayContext = createContext(() => ["a", "b", "c"]);
120
120
  function Parent() {
121
- NumberContext.inject(42);
122
- ArrayContext.inject(["a", "b", "c"]);
121
+ NumberContext.inject();
122
+ ArrayContext.inject();
123
123
  return () => _jsx(Child, {});
124
124
  }
125
125
  function Child() {
126
- const num = NumberContext.get();
127
- const arr = ArrayContext.get();
126
+ const num = NumberContext.use();
127
+ const arr = ArrayContext.use();
128
128
  return () => _jsx("div", { children: `${num} - ${arr.join(",")}` });
129
129
  }
130
130
  const container = document.createElement("div");
@@ -133,4 +133,17 @@ describe("createContext", () => {
133
133
  expect(container.textContent).toContain("42 - a,b,c");
134
134
  document.body.removeChild(container);
135
135
  });
136
+ it("should allow using context in the root component that injects it", () => {
137
+ const ThemeContext = createContext(() => ({ theme: "root-theme" }));
138
+ function RootComponent() {
139
+ ThemeContext.inject();
140
+ const theme = ThemeContext.use();
141
+ return () => _jsx("div", { children: theme.theme });
142
+ }
143
+ const container = document.createElement("div");
144
+ document.body.appendChild(container);
145
+ render(_jsx(RootComponent, {}), container);
146
+ expect(container.textContent).toContain("root-theme");
147
+ document.body.removeChild(container);
148
+ });
136
149
  });
@@ -1,14 +1,15 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "./jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "rask-ui/jsx-runtime";
2
2
  import { describe, it, expect } from "vitest";
3
- import { ErrorBoundary } from "../error";
3
+ import { useCatchError } from "../useCatchError";
4
4
  import { render } from "../";
5
- describe("ErrorBoundary", () => {
5
+ describe("useCatchError", () => {
6
6
  it("should render children when no error occurs", async () => {
7
7
  function SafeChild() {
8
8
  return () => _jsx("div", { children: "Safe content" });
9
9
  }
10
10
  function TestComponent() {
11
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Error: ", String(error)] }), children: _jsx(SafeChild, {}) }));
11
+ const errorState = useCatchError();
12
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", String(errorState.error)] })) : (_jsx(SafeChild, {}));
12
13
  }
13
14
  const container = document.createElement("div");
14
15
  document.body.appendChild(container);
@@ -26,7 +27,8 @@ describe("ErrorBoundary", () => {
26
27
  };
27
28
  }
28
29
  function TestComponent() {
29
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Error: ", String(error)] }), children: _jsx(ThrowingChild, {}) }));
30
+ const errorState = useCatchError();
31
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", String(errorState.error)] })) : (_jsx(ThrowingChild, {}));
30
32
  }
31
33
  const container = document.createElement("div");
32
34
  document.body.appendChild(container);
@@ -44,7 +46,8 @@ describe("ErrorBoundary", () => {
44
46
  };
45
47
  }
46
48
  function TestComponent() {
47
- return () => (_jsx(ErrorBoundary, { error: (error) => (_jsxs("div", { class: "error-ui", children: [_jsx("h1", { children: "Oops!" }), _jsx("p", { children: String(error) })] })), children: _jsx(ThrowingChild, {}) }));
49
+ const errorState = useCatchError();
50
+ return () => errorState.error ? (_jsxs("div", { class: "error-ui", children: [_jsx("h1", { children: "Oops!" }), _jsx("p", { children: String(errorState.error) })] })) : (_jsx(ThrowingChild, {}));
48
51
  }
49
52
  const container = document.createElement("div");
50
53
  document.body.appendChild(container);
@@ -64,7 +67,8 @@ describe("ErrorBoundary", () => {
64
67
  return () => _jsx("div", { children: "Child 2" });
65
68
  }
66
69
  function TestComponent() {
67
- return () => (_jsxs(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Error: ", String(error)] }), children: [_jsx(SafeChild1, {}), _jsx(SafeChild2, {})] }));
70
+ const errorState = useCatchError();
71
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", String(errorState.error)] })) : (_jsxs(_Fragment, { children: [_jsx(SafeChild1, {}), _jsx(SafeChild2, {})] }));
68
72
  }
69
73
  const container = document.createElement("div");
70
74
  document.body.appendChild(container);
@@ -85,7 +89,8 @@ describe("ErrorBoundary", () => {
85
89
  return () => _jsx(DeepChild, {});
86
90
  }
87
91
  function TestComponent() {
88
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Caught: ", String(error)] }), children: _jsx(MiddleChild, {}) }));
92
+ const errorState = useCatchError();
93
+ return () => errorState.error ? (_jsxs("div", { children: ["Caught: ", String(errorState.error)] })) : (_jsx(MiddleChild, {}));
89
94
  }
90
95
  const container = document.createElement("div");
91
96
  document.body.appendChild(container);
@@ -102,8 +107,13 @@ describe("ErrorBoundary", () => {
102
107
  return _jsx("div", {});
103
108
  };
104
109
  }
110
+ function InnerBoundary() {
111
+ const errorState = useCatchError();
112
+ return () => errorState.error ? (_jsxs("div", { children: ["Inner: ", String(errorState.error)] })) : (_jsx(ThrowingChild, {}));
113
+ }
105
114
  function TestComponent() {
106
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Outer: ", String(error)] }), children: _jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Inner: ", String(error)] }), children: _jsx(ThrowingChild, {}) }) }));
115
+ const errorState = useCatchError();
116
+ return () => errorState.error ? (_jsxs("div", { children: ["Outer: ", String(errorState.error)] })) : (_jsx(InnerBoundary, {}));
107
117
  }
108
118
  const container = document.createElement("div");
109
119
  document.body.appendChild(container);
@@ -122,7 +132,8 @@ describe("ErrorBoundary", () => {
122
132
  };
123
133
  }
124
134
  function TestComponent() {
125
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Error: ", String(error)] }), children: _jsx(ThrowingChild, {}) }));
135
+ const errorState = useCatchError();
136
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", String(errorState.error)] })) : (_jsx(ThrowingChild, {}));
126
137
  }
127
138
  const container = document.createElement("div");
128
139
  document.body.appendChild(container);
@@ -139,7 +150,8 @@ describe("ErrorBoundary", () => {
139
150
  };
140
151
  }
141
152
  function TestComponent() {
142
- return () => (_jsx(ErrorBoundary, { error: (error) => (_jsxs("div", { children: ["Error: ", error.message, " (Code: ", error.code, ")"] })), children: _jsx(ThrowingChild, {}) }));
153
+ const errorState = useCatchError();
154
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", errorState.error.message, " (Code:", " ", errorState.error.code, ")"] })) : (_jsx(ThrowingChild, {}));
143
155
  }
144
156
  const container = document.createElement("div");
145
157
  document.body.appendChild(container);
@@ -156,7 +168,8 @@ describe("ErrorBoundary", () => {
156
168
  return () => _jsx("div", { children: "Safe content" });
157
169
  }
158
170
  function TestComponent() {
159
- return () => (_jsx(ErrorBoundary, { error: (error) => _jsxs("div", { children: ["Error: ", String(error)] }), children: _jsx(SafeChild, {}) }));
171
+ const errorState = useCatchError();
172
+ return () => errorState.error ? (_jsxs("div", { children: ["Error: ", String(errorState.error)] })) : (_jsx(SafeChild, {}));
160
173
  }
161
174
  const container = document.createElement("div");
162
175
  document.body.appendChild(container);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=renderCount.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderCount.test.d.ts","sourceRoot":"","sources":["../../src/tests/renderCount.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,95 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "rask-ui/jsx-runtime";
2
+ import { describe, it, expect } from "vitest";
3
+ import { useState } from "../useState";
4
+ import { render } from "../";
5
+ describe("Child render count test", () => {
6
+ it("should track how many times Child renders when count changes", async () => {
7
+ let childRenderCount = 0;
8
+ let state;
9
+ function Child(props) {
10
+ return () => {
11
+ childRenderCount++;
12
+ return (_jsxs("div", { children: ["State count: ", props.state.count, ", Props count: ", props.count] }));
13
+ };
14
+ }
15
+ function MyComp() {
16
+ state = useState({
17
+ count: 0,
18
+ });
19
+ return () => (_jsx("div", { children: _jsx(Child, { state: state, count: state.count }) }));
20
+ }
21
+ const container = document.createElement("div");
22
+ render(_jsx(MyComp, {}), container);
23
+ // Initial render
24
+ expect(childRenderCount).toBe(1);
25
+ expect(container.textContent).toBe("State count: 0, Props count: 0");
26
+ // Simulate click to increment count
27
+ state.count++;
28
+ await new Promise((resolve) => setTimeout(resolve, 10));
29
+ // After first increment
30
+ expect(childRenderCount).toBe(2);
31
+ expect(container.textContent).toBe("State count: 1, Props count: 1");
32
+ state.count++;
33
+ await new Promise((resolve) => setTimeout(resolve, 10));
34
+ // After second increment
35
+ expect(childRenderCount).toBe(3);
36
+ expect(container.textContent).toBe("State count: 2, Props count: 2");
37
+ });
38
+ it("should show Child renders only once when only state prop changes", async () => {
39
+ let childRenderCount = 0;
40
+ let state;
41
+ function Child(props) {
42
+ childRenderCount++;
43
+ return () => _jsxs("div", { children: ["State count: ", props.state.count] });
44
+ }
45
+ function MyComp() {
46
+ state = useState({
47
+ count: 0,
48
+ });
49
+ return () => (_jsx("div", { children: _jsx(Child, { state: state }) }));
50
+ }
51
+ const container = document.createElement("div");
52
+ render(_jsx(MyComp, {}), container);
53
+ // Initial render
54
+ expect(childRenderCount).toBe(1);
55
+ expect(container.textContent).toBe("State count: 0");
56
+ // Simulate click to increment count
57
+ state.count++;
58
+ await new Promise((resolve) => setTimeout(resolve, 10));
59
+ // Child shouldn't re-render because state object reference didn't change
60
+ expect(childRenderCount).toBe(1);
61
+ expect(container.textContent).toBe("State count: 1");
62
+ });
63
+ it("should show Child renders when primitive prop changes", async () => {
64
+ let childRenderCount = 0;
65
+ let state;
66
+ function Child(props) {
67
+ return () => {
68
+ childRenderCount++;
69
+ return _jsxs("div", { children: ["Props count: ", props.count] });
70
+ };
71
+ }
72
+ function MyComp() {
73
+ state = useState({
74
+ count: 0,
75
+ });
76
+ return () => (_jsx("div", { children: _jsx(Child, { count: state.count }) }));
77
+ }
78
+ const container = document.createElement("div");
79
+ render(_jsx(MyComp, {}), container);
80
+ // Initial render
81
+ expect(childRenderCount).toBe(1);
82
+ expect(container.textContent).toBe("Props count: 0");
83
+ // Simulate click to increment count
84
+ state.count++;
85
+ await new Promise((resolve) => setTimeout(resolve, 10));
86
+ // Child re-renders because count prop changed
87
+ expect(childRenderCount).toBe(2);
88
+ expect(container.textContent).toBe("Props count: 1");
89
+ // Another click
90
+ state.count++;
91
+ await new Promise((resolve) => setTimeout(resolve, 10));
92
+ expect(childRenderCount).toBe(3);
93
+ expect(container.textContent).toBe("Props count: 2");
94
+ });
95
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scopeEnforcement.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeEnforcement.test.d.ts","sourceRoot":"","sources":["../../src/tests/scopeEnforcement.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,157 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "rask-ui/jsx-runtime";
2
+ import { describe, it, expect } from "vitest";
3
+ import { useState } from "../useState";
4
+ import { useEffect } from "../useEffect";
5
+ import { useDerived } from "../useDerived";
6
+ import { render } from "../index";
7
+ describe("Scope Enforcement", () => {
8
+ describe("useState", () => {
9
+ it("should allow useState in global scope", () => {
10
+ expect(() => {
11
+ const state = useState({ count: 0 });
12
+ }).not.toThrow();
13
+ });
14
+ it("should allow useState in component setup", () => {
15
+ function Component() {
16
+ const state = useState({ count: 0 });
17
+ return () => _jsx("div", { children: state.count });
18
+ }
19
+ const container = document.createElement("div");
20
+ expect(() => {
21
+ render(_jsx(Component, {}), container);
22
+ }).not.toThrow();
23
+ });
24
+ it("should throw when useState is called during render", () => {
25
+ function Component() {
26
+ const state = useState({ count: 0 });
27
+ return () => {
28
+ // This should throw - useState in render scope
29
+ expect(() => {
30
+ useState({ nested: 1 });
31
+ }).toThrow("useState cannot be called during render");
32
+ return _jsx("div", { children: state.count });
33
+ };
34
+ }
35
+ const container = document.createElement("div");
36
+ render(_jsx(Component, {}), container);
37
+ });
38
+ });
39
+ describe("useEffect", () => {
40
+ it("should throw when useEffect is called outside component setup", () => {
41
+ expect(() => {
42
+ useEffect(() => {
43
+ // Effect logic
44
+ });
45
+ }).toThrow("Only use useEffect in component setup");
46
+ });
47
+ it("should allow useEffect in component setup", () => {
48
+ function Component() {
49
+ const state = useState({ count: 0 });
50
+ let effectRan = false;
51
+ useEffect(() => {
52
+ effectRan = true;
53
+ state.count;
54
+ });
55
+ expect(effectRan).toBe(true);
56
+ return () => _jsx("div", { children: state.count });
57
+ }
58
+ const container = document.createElement("div");
59
+ expect(() => {
60
+ render(_jsx(Component, {}), container);
61
+ }).not.toThrow();
62
+ });
63
+ it("should throw when useEffect is called during render", () => {
64
+ function Component() {
65
+ const state = useState({ count: 0 });
66
+ return () => {
67
+ // This should throw - useEffect in render scope
68
+ expect(() => {
69
+ useEffect(() => {
70
+ state.count;
71
+ });
72
+ }).toThrow("Only use useEffect in component setup");
73
+ return _jsx("div", { children: state.count });
74
+ };
75
+ }
76
+ const container = document.createElement("div");
77
+ render(_jsx(Component, {}), container);
78
+ });
79
+ });
80
+ describe("useDerived", () => {
81
+ it("should throw when useDerived is called outside component setup", () => {
82
+ expect(() => {
83
+ useDerived({
84
+ doubled: () => 2 * 2,
85
+ });
86
+ }).toThrow("Only use useDerived in component setup");
87
+ });
88
+ it("should allow useDerived in component setup", () => {
89
+ function Component() {
90
+ const state = useState({ count: 5 });
91
+ const computed = useDerived({
92
+ doubled: () => state.count * 2,
93
+ });
94
+ return () => _jsx("div", { children: computed.doubled });
95
+ }
96
+ const container = document.createElement("div");
97
+ expect(() => {
98
+ render(_jsx(Component, {}), container);
99
+ }).not.toThrow();
100
+ });
101
+ it("should throw when useDerived is called during render", () => {
102
+ function Component() {
103
+ const state = useState({ count: 0 });
104
+ return () => {
105
+ // This should throw - useDerived in render scope
106
+ expect(() => {
107
+ useDerived({
108
+ doubled: () => state.count * 2,
109
+ });
110
+ }).toThrow("Only use useDerived in component setup");
111
+ return _jsx("div", { children: state.count });
112
+ };
113
+ }
114
+ const container = document.createElement("div");
115
+ render(_jsx(Component, {}), container);
116
+ });
117
+ });
118
+ describe("Mixed scenarios", () => {
119
+ it("should allow all reactive primitives in setup but not in render", () => {
120
+ function Component() {
121
+ // All of these should work in setup
122
+ const state = useState({ count: 0 });
123
+ const computed = useDerived({
124
+ doubled: () => state.count * 2,
125
+ });
126
+ useEffect(() => {
127
+ state.count;
128
+ });
129
+ return () => {
130
+ // None of these should work in render
131
+ expect(() => useState({ bad: 1 })).toThrow();
132
+ expect(() => useEffect(() => { })).toThrow();
133
+ expect(() => useDerived({ bad: () => 1 })).toThrow();
134
+ return _jsx("div", { children: computed.doubled });
135
+ };
136
+ }
137
+ const container = document.createElement("div");
138
+ render(_jsx(Component, {}), container);
139
+ });
140
+ it("should properly enforce scope in nested renders", () => {
141
+ function Child() {
142
+ const childState = useState({ value: "child" });
143
+ return () => _jsx("div", { children: childState.value });
144
+ }
145
+ function Parent() {
146
+ const parentState = useState({ value: "parent" });
147
+ return () => {
148
+ // This should fail in render
149
+ expect(() => useState({ bad: 1 })).toThrow();
150
+ return (_jsxs("div", { children: [parentState.value, _jsx(Child, {})] }));
151
+ };
152
+ }
153
+ const container = document.createElement("div");
154
+ render(_jsx(Parent, {}), container);
155
+ });
156
+ });
157
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useAction.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAction.test.d.ts","sourceRoot":"","sources":["../../src/tests/useAction.test.ts"],"names":[],"mappings":""}