rask-ui 0.6.0 → 0.8.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/README.md +115 -88
- package/dist/createState.d.ts.map +1 -1
- package/dist/createState.js +14 -3
- package/dist/createTask.d.ts +30 -0
- package/dist/createTask.d.ts.map +1 -0
- package/dist/createTask.js +76 -0
- package/dist/createView.d.ts.map +1 -1
- package/dist/createView.js +35 -3
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/inspect.d.ts +13 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +7 -0
- package/dist/plugin.d.ts +2 -7
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +12 -4
- package/logo.png +0 -0
- package/package.json +3 -2
- package/swc-plugin/src/lib.rs +26 -0
- package/swc-plugin/target/wasm32-wasip1/release/deps/libswc_plugin_rask_component.rlib +0 -0
- package/swc-plugin/target/wasm32-wasip1/release/deps/swc_plugin_rask_component.d +3 -3
- package/swc-plugin/target/wasm32-wasip1/release/deps/swc_plugin_rask_component.wasm +0 -0
- package/swc-plugin/target/wasm32-wasip1/release/libswc_plugin_rask_component.d +1 -1
- package/swc-plugin/target/wasm32-wasip1/release/libswc_plugin_rask_component.rlib +0 -0
- package/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.d +1 -1
- package/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.wasm +0 -0
package/README.md
CHANGED
|
@@ -10,6 +10,29 @@ A lightweight reactive component library that combines the simplicity of observa
|
|
|
10
10
|
npm install rask-ui
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📢 Open For Feedback
|
|
16
|
+
|
|
17
|
+
**RASK is feature-complete and ready for community feedback!**
|
|
18
|
+
|
|
19
|
+
The core implementation is finished, including:
|
|
20
|
+
- ✅ Inferno-based reconciler for powerful UI expression
|
|
21
|
+
- ✅ JSX transformation plugin (Inferno JSX + stateful components)
|
|
22
|
+
- ✅ Reactive primitives for simple state management
|
|
23
|
+
|
|
24
|
+
**Before the official release, we need your input:**
|
|
25
|
+
- Would a library like this be valuable for your projects?
|
|
26
|
+
- Is the API clear and intuitive?
|
|
27
|
+
- Is the documentation helpful and complete?
|
|
28
|
+
- Does the approach resonate with you?
|
|
29
|
+
|
|
30
|
+
**[Share your feedback by creating an issue →](https://github.com/christianalfoni/rask/issues/new)**
|
|
31
|
+
|
|
32
|
+
Your feedback will directly shape the final release. All perspectives welcome!
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
13
36
|
## The Itch with Modern UI Frameworks
|
|
14
37
|
|
|
15
38
|
Modern UI frameworks present developers with a fundamental tradeoff between state management and UI expression:
|
|
@@ -195,7 +218,7 @@ When `state.count` changes in Parent, only Child re-renders because it accesses
|
|
|
195
218
|
|
|
196
219
|
### One Rule To Accept
|
|
197
220
|
|
|
198
|
-
**RASK has observable primitives**: Never destructure reactive objects (state, props, context values,
|
|
221
|
+
**RASK has observable primitives**: Never destructure reactive objects (state, props, context values, tasks). Destructuring extracts plain values and breaks reactivity.
|
|
199
222
|
|
|
200
223
|
```tsx
|
|
201
224
|
// ❌ BAD - Destructuring breaks reactivity
|
|
@@ -241,9 +264,7 @@ Reactive objects are implemented using JavaScript Proxies. When you access a pro
|
|
|
241
264
|
- `createState()` - Never destructure state objects
|
|
242
265
|
- Props - Never destructure component props
|
|
243
266
|
- `createContext().get()` - Never destructure context values
|
|
244
|
-
- `
|
|
245
|
-
- `createQuery()` - Never destructure query objects
|
|
246
|
-
- `createMutation()` - Never destructure mutation objects
|
|
267
|
+
- `createTask()` - Never destructure task objects
|
|
247
268
|
- `createView()` - Never destructure view objects
|
|
248
269
|
- `createComputed()` - Never destructure computed objects
|
|
249
270
|
|
|
@@ -661,58 +682,38 @@ function Child() {
|
|
|
661
682
|
|
|
662
683
|
### Async Data Management
|
|
663
684
|
|
|
664
|
-
#### `
|
|
685
|
+
#### `createTask<T, P>(task)`
|
|
665
686
|
|
|
666
|
-
Creates reactive
|
|
687
|
+
Creates a low-level reactive primitive for managing async operations with loading, error, and result states. This is a generic primitive that gives you full control over async state management without prescribing patterns.
|
|
667
688
|
|
|
668
689
|
```tsx
|
|
669
|
-
import {
|
|
690
|
+
import { createTask } from "rask-ui";
|
|
670
691
|
|
|
692
|
+
// Simple task without parameters - auto-runs on creation
|
|
671
693
|
function UserProfile() {
|
|
672
|
-
const user =
|
|
694
|
+
const user = createTask(() => fetch("/api/user").then((r) => r.json()));
|
|
673
695
|
|
|
674
|
-
return () =>
|
|
675
|
-
if (user.
|
|
676
|
-
return <p>Loading...</p
|
|
696
|
+
return () => {
|
|
697
|
+
if (user.isRunning) {
|
|
698
|
+
return <p>Loading...</p>;
|
|
677
699
|
}
|
|
678
700
|
|
|
679
701
|
if (user.error) {
|
|
680
|
-
return <p>Error: {user.error}</p
|
|
702
|
+
return <p>Error: {user.error}</p>;
|
|
681
703
|
}
|
|
682
704
|
|
|
683
|
-
return <p>Hello, {user.
|
|
705
|
+
return <p>Hello, {user.result.name}!</p>;
|
|
706
|
+
};
|
|
684
707
|
}
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
**Parameters:**
|
|
688
|
-
|
|
689
|
-
- `promise: Promise<T>` - The promise to track
|
|
690
|
-
|
|
691
|
-
**Returns:** Reactive object with:
|
|
692
|
-
|
|
693
|
-
- `isPending: boolean` - True while promise is pending
|
|
694
|
-
- `value: T | null` - Resolved value (null while pending or on error)
|
|
695
|
-
- `error: string | null` - Error message (null while pending or on success)
|
|
696
|
-
|
|
697
|
-
**States:**
|
|
698
|
-
|
|
699
|
-
- `{ isPending: true, value: null, error: null }` - Loading
|
|
700
|
-
- `{ isPending: false, value: T, error: null }` - Success
|
|
701
|
-
- `{ isPending: false, value: null, error: string }` - Error
|
|
702
|
-
|
|
703
|
-
---
|
|
704
|
-
|
|
705
|
-
#### `createQuery<T>(fetcher)`
|
|
706
|
-
|
|
707
|
-
Creates a query with refetch capability and request cancellation.
|
|
708
|
-
|
|
709
|
-
```tsx
|
|
710
|
-
import { createQuery } from "rask-ui";
|
|
711
708
|
|
|
709
|
+
// Task with parameters - control when to run
|
|
712
710
|
function Posts() {
|
|
713
|
-
const posts =
|
|
711
|
+
const posts = createTask((page: number) =>
|
|
712
|
+
fetch(`/api/posts?page=${page}`).then((r) => r.json())
|
|
713
|
+
);
|
|
714
|
+
|
|
714
715
|
const renderPosts = () => {
|
|
715
|
-
if (posts.
|
|
716
|
+
if (posts.isRunning) {
|
|
716
717
|
return <p>Loading...</p>;
|
|
717
718
|
}
|
|
718
719
|
|
|
@@ -720,61 +721,37 @@ function Posts() {
|
|
|
720
721
|
return <p>Error: {posts.error}</p>;
|
|
721
722
|
}
|
|
722
723
|
|
|
723
|
-
|
|
724
|
+
if (!posts.result) {
|
|
725
|
+
return <p>No posts loaded</p>;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return posts.result.map((post) => (
|
|
724
729
|
<article key={post.id}>{post.title}</article>
|
|
725
730
|
));
|
|
726
731
|
};
|
|
727
732
|
|
|
728
733
|
return () => (
|
|
729
734
|
<div>
|
|
730
|
-
<button onClick={() => posts.
|
|
731
|
-
<button onClick={() => posts.
|
|
735
|
+
<button onClick={() => posts.run(1)}>Load Page 1</button>
|
|
736
|
+
<button onClick={() => posts.rerun(1)}>Reload Page 1</button>
|
|
732
737
|
{renderPosts()}
|
|
733
738
|
</div>
|
|
734
739
|
);
|
|
735
740
|
}
|
|
736
|
-
```
|
|
737
|
-
|
|
738
|
-
**Parameters:**
|
|
739
|
-
|
|
740
|
-
- `fetcher: () => Promise<T>` - Function that returns a promise
|
|
741
|
-
|
|
742
|
-
**Returns:** Query object with:
|
|
743
|
-
|
|
744
|
-
- `isPending: boolean` - True while fetching
|
|
745
|
-
- `data: T | null` - Fetched data
|
|
746
|
-
- `error: string | null` - Error message
|
|
747
|
-
- `fetch(force?: boolean)` - Refetch data
|
|
748
|
-
- `force: false` (default) - Keep existing data while refetching
|
|
749
|
-
- `force: true` - Clear data before refetching
|
|
750
|
-
|
|
751
|
-
**Features:**
|
|
752
|
-
|
|
753
|
-
- Automatic request cancellation on refetch
|
|
754
|
-
- Keeps old data by default during refetch
|
|
755
|
-
- Automatically fetches on creation
|
|
756
|
-
|
|
757
|
-
---
|
|
758
|
-
|
|
759
|
-
#### `createMutation<T>(mutator)`
|
|
760
|
-
|
|
761
|
-
Creates a mutation for data updates with pending and error states.
|
|
762
|
-
|
|
763
|
-
```tsx
|
|
764
|
-
import { createMutation } from "rask-ui";
|
|
765
741
|
|
|
742
|
+
// Mutation-style usage
|
|
766
743
|
function CreatePost() {
|
|
767
744
|
const state = createState({ title: "", body: "" });
|
|
768
745
|
|
|
769
|
-
const create =
|
|
746
|
+
const create = createTask((data: { title: string; body: string }) =>
|
|
770
747
|
fetch("/api/posts", {
|
|
771
748
|
method: "POST",
|
|
772
749
|
body: JSON.stringify(data),
|
|
773
|
-
}))
|
|
750
|
+
}).then((r) => r.json())
|
|
774
751
|
);
|
|
775
752
|
|
|
776
753
|
const handleSubmit = () => {
|
|
777
|
-
create.
|
|
754
|
+
create.run({ title: state.title, body: state.body });
|
|
778
755
|
};
|
|
779
756
|
|
|
780
757
|
return () => (
|
|
@@ -787,8 +764,8 @@ function CreatePost() {
|
|
|
787
764
|
value={state.body}
|
|
788
765
|
onInput={(e) => (state.body = e.target.value)}
|
|
789
766
|
/>
|
|
790
|
-
<button disabled={create.
|
|
791
|
-
{create.
|
|
767
|
+
<button disabled={create.isRunning}>
|
|
768
|
+
{create.isRunning ? "Creating..." : "Create"}
|
|
792
769
|
</button>
|
|
793
770
|
{create.error && <p>Error: {create.error}</p>}
|
|
794
771
|
</form>
|
|
@@ -796,22 +773,72 @@ function CreatePost() {
|
|
|
796
773
|
}
|
|
797
774
|
```
|
|
798
775
|
|
|
799
|
-
**
|
|
776
|
+
**Type Signatures:**
|
|
777
|
+
|
|
778
|
+
```tsx
|
|
779
|
+
// Task without parameters - auto-runs on creation
|
|
780
|
+
createTask<T>(task: () => Promise<T>): Task<T, never> & {
|
|
781
|
+
run(): Promise<T>;
|
|
782
|
+
rerun(): Promise<T>;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Task with parameters - manual control
|
|
786
|
+
createTask<T, P>(task: (params: P) => Promise<T>): Task<T, P> & {
|
|
787
|
+
run(params: P): Promise<T>;
|
|
788
|
+
rerun(params: P): Promise<T>;
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
**Returns:** Task object with reactive state and methods:
|
|
800
793
|
|
|
801
|
-
|
|
794
|
+
**State Properties:**
|
|
795
|
+
- `isRunning: boolean` - True while task is executing
|
|
796
|
+
- `result: T | null` - Result of successful execution (null if not yet run, running, or error)
|
|
797
|
+
- `error: string | null` - Error message from failed execution (null if successful or running)
|
|
798
|
+
- `params: P | null` - Current parameters while running (null when idle)
|
|
802
799
|
|
|
803
|
-
**
|
|
800
|
+
**Methods:**
|
|
801
|
+
- `run(params?: P): Promise<T>` - Execute the task, clearing previous result
|
|
802
|
+
- `rerun(params?: P): Promise<T>` - Re-execute the task, keeping previous result until new one arrives
|
|
804
803
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
804
|
+
**State Transitions:**
|
|
805
|
+
|
|
806
|
+
Initial state (no params):
|
|
807
|
+
```tsx
|
|
808
|
+
{ isRunning: false, params: null, result: null, error: null }
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
While running:
|
|
812
|
+
```tsx
|
|
813
|
+
{ isRunning: true, result: T | null, params: P, error: null }
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
Success:
|
|
817
|
+
```tsx
|
|
818
|
+
{ isRunning: false, params: null, result: T, error: null }
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
Error:
|
|
822
|
+
```tsx
|
|
823
|
+
{ isRunning: false, params: null, result: null, error: string }
|
|
824
|
+
```
|
|
809
825
|
|
|
810
826
|
**Features:**
|
|
811
827
|
|
|
812
|
-
- Automatic
|
|
813
|
-
-
|
|
814
|
-
-
|
|
828
|
+
- **Automatic cancellation** - Previous executions are cancelled when a new one starts
|
|
829
|
+
- **Flexible control** - Use `run()` to clear old data or `rerun()` to keep it during loading
|
|
830
|
+
- **Type-safe** - Full TypeScript inference for parameters and results
|
|
831
|
+
- **Auto-run support** - Tasks without parameters run automatically on creation
|
|
832
|
+
- **Generic primitive** - Build your own patterns on top (queries, mutations, etc.)
|
|
833
|
+
|
|
834
|
+
**Usage Patterns:**
|
|
835
|
+
|
|
836
|
+
Use `createTask` as a building block for various async patterns:
|
|
837
|
+
- **Queries**: Tasks that fetch data and can be refetched
|
|
838
|
+
- **Mutations**: Tasks that modify server state
|
|
839
|
+
- **Polling**: Tasks that run periodically
|
|
840
|
+
- **Debounced searches**: Tasks that run based on user input
|
|
841
|
+
- **File uploads**: Tasks that track upload progress
|
|
815
842
|
|
|
816
843
|
---
|
|
817
844
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createState.d.ts","sourceRoot":"","sources":["../src/createState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createState.d.ts","sourceRoot":"","sources":["../src/createState.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEzD;AAGD,eAAO,MAAM,YAAY,eAAoB,CAAC"}
|
package/dist/createState.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { INSPECT_MARKER } from "./inspect";
|
|
1
2
|
import { getCurrentObserver, Signal } from "./observation";
|
|
2
3
|
/**
|
|
3
4
|
* Creates a reactive state object that tracks property access and notifies observers on changes.
|
|
@@ -28,7 +29,7 @@ export function createState(state) {
|
|
|
28
29
|
}
|
|
29
30
|
const proxyCache = new WeakMap();
|
|
30
31
|
export const PROXY_MARKER = Symbol("isProxy");
|
|
31
|
-
function getProxy(value) {
|
|
32
|
+
function getProxy(value, notifyInspector, path) {
|
|
32
33
|
// Check if already a proxy to avoid double-wrapping
|
|
33
34
|
if (PROXY_MARKER in value) {
|
|
34
35
|
return value;
|
|
@@ -47,7 +48,7 @@ function getProxy(value) {
|
|
|
47
48
|
},
|
|
48
49
|
get(target, key) {
|
|
49
50
|
// Mark this as a proxy to prevent double-wrapping
|
|
50
|
-
if (key === PROXY_MARKER) {
|
|
51
|
+
if (key === PROXY_MARKER || key === INSPECT_MARKER) {
|
|
51
52
|
return true;
|
|
52
53
|
}
|
|
53
54
|
const value = Reflect.get(target, key);
|
|
@@ -61,11 +62,16 @@ function getProxy(value) {
|
|
|
61
62
|
}
|
|
62
63
|
if (Array.isArray(value) ||
|
|
63
64
|
(typeof value === "object" && value !== null)) {
|
|
64
|
-
return getProxy(value);
|
|
65
|
+
return getProxy(value, notifyInspector, notifyInspector ? (path ? path.concat(key) : [key]) : undefined);
|
|
65
66
|
}
|
|
66
67
|
return value;
|
|
67
68
|
},
|
|
68
69
|
set(target, key, newValue) {
|
|
70
|
+
if (key === INSPECT_MARKER) {
|
|
71
|
+
notifyInspector = newValue.fn;
|
|
72
|
+
path = newValue.path;
|
|
73
|
+
return Reflect.set(target, key, newValue);
|
|
74
|
+
}
|
|
69
75
|
if (typeof key === "symbol") {
|
|
70
76
|
return Reflect.set(target, key, newValue);
|
|
71
77
|
}
|
|
@@ -76,6 +82,11 @@ function getProxy(value) {
|
|
|
76
82
|
const signal = signals[key];
|
|
77
83
|
signal?.notify();
|
|
78
84
|
}
|
|
85
|
+
notifyInspector?.({
|
|
86
|
+
type: "mutation",
|
|
87
|
+
path: path ? path.concat(key) : [key],
|
|
88
|
+
value: newValue,
|
|
89
|
+
});
|
|
79
90
|
return setResult;
|
|
80
91
|
},
|
|
81
92
|
deleteProperty(target, key) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type Task<T, P> = {
|
|
2
|
+
isRunning: false;
|
|
3
|
+
params: null;
|
|
4
|
+
result: null;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
isRunning: true;
|
|
8
|
+
result: T | null;
|
|
9
|
+
params: P;
|
|
10
|
+
error: null;
|
|
11
|
+
} | {
|
|
12
|
+
isRunning: false;
|
|
13
|
+
params: null;
|
|
14
|
+
result: T;
|
|
15
|
+
error: null;
|
|
16
|
+
} | {
|
|
17
|
+
isRunning: false;
|
|
18
|
+
params: null;
|
|
19
|
+
result: null;
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function createTask<T>(task: () => Promise<T>): Task<T, never> & {
|
|
23
|
+
run(): Promise<T>;
|
|
24
|
+
rerun(): Promise<T>;
|
|
25
|
+
};
|
|
26
|
+
export declare function createTask<T, P>(task: (params: P) => Promise<T>): Task<T, P> & {
|
|
27
|
+
run(params: P): Promise<T>;
|
|
28
|
+
rerun(params: P): Promise<T>;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=createTask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTask.d.ts","sourceRoot":"","sources":["../src/createTask.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,IACjB;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IACjB,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG;IACtE,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AACF,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC9B,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IACd,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9B,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createState } from "./createState";
|
|
2
|
+
export function createTask(task) {
|
|
3
|
+
const state = createState({
|
|
4
|
+
isRunning: false,
|
|
5
|
+
result: null,
|
|
6
|
+
error: null,
|
|
7
|
+
params: null,
|
|
8
|
+
});
|
|
9
|
+
const assign = (newState) => {
|
|
10
|
+
Object.assign(state, newState);
|
|
11
|
+
};
|
|
12
|
+
let currentAbortController;
|
|
13
|
+
const fetch = (params) => {
|
|
14
|
+
currentAbortController?.abort();
|
|
15
|
+
const abortController = (currentAbortController = new AbortController());
|
|
16
|
+
const promise = task(params);
|
|
17
|
+
promise
|
|
18
|
+
.then((result) => {
|
|
19
|
+
if (abortController.signal.aborted) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
assign({
|
|
23
|
+
isRunning: false,
|
|
24
|
+
result,
|
|
25
|
+
error: null,
|
|
26
|
+
params: null,
|
|
27
|
+
});
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
if (abortController.signal.aborted) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
assign({
|
|
34
|
+
isRunning: false,
|
|
35
|
+
result: null,
|
|
36
|
+
error: String(error),
|
|
37
|
+
params: null,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
return promise;
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
get isRunning() {
|
|
44
|
+
return state.isRunning;
|
|
45
|
+
},
|
|
46
|
+
get result() {
|
|
47
|
+
return state.result;
|
|
48
|
+
},
|
|
49
|
+
get error() {
|
|
50
|
+
return state.error;
|
|
51
|
+
},
|
|
52
|
+
get params() {
|
|
53
|
+
return state.params;
|
|
54
|
+
},
|
|
55
|
+
run(params) {
|
|
56
|
+
const promise = fetch(params);
|
|
57
|
+
assign({
|
|
58
|
+
isRunning: true,
|
|
59
|
+
result: null,
|
|
60
|
+
error: null,
|
|
61
|
+
params: (params || null),
|
|
62
|
+
});
|
|
63
|
+
return promise;
|
|
64
|
+
},
|
|
65
|
+
rerun(params) {
|
|
66
|
+
const promise = fetch(params);
|
|
67
|
+
assign({
|
|
68
|
+
isRunning: true,
|
|
69
|
+
result: state.result,
|
|
70
|
+
error: null,
|
|
71
|
+
params: (params || null),
|
|
72
|
+
});
|
|
73
|
+
return promise;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
package/dist/createView.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"AAGA,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAEjD,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,QAAQ,CAC1D,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CACrB,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,CAAC,SAAS;IACtD,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,GACzB,EAAE,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACpD,GAAG,IAAI,EAAE,CAAC,GACT,SAAS,CAAC,CAAC,CAAC,CA4Dd"}
|
package/dist/createView.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { INSPECT_MARKER } from "./inspect";
|
|
1
2
|
/**
|
|
2
3
|
* Creates a view that merges multiple objects (reactive or not) into a single object while
|
|
3
4
|
* maintaining reactivity through getters. Properties from later arguments override earlier ones.
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
export function createView(...args) {
|
|
45
46
|
const result = {};
|
|
46
47
|
const seen = new Set();
|
|
48
|
+
let notifyInspector;
|
|
47
49
|
for (let i = args.length - 1; i >= 0; i--) {
|
|
48
50
|
const src = args[i];
|
|
49
51
|
// mimic Object.assign: only enumerable own property keys
|
|
@@ -57,12 +59,42 @@ export function createView(...args) {
|
|
|
57
59
|
Object.defineProperty(result, key, {
|
|
58
60
|
enumerable: true,
|
|
59
61
|
configurable: true,
|
|
60
|
-
get: () =>
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
get: () => {
|
|
63
|
+
const value = src[key];
|
|
64
|
+
if (!notifyInspector) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (value?.[INSPECT_MARKER]) {
|
|
68
|
+
value[INSPECT_MARKER] = {
|
|
69
|
+
fn: notifyInspector.fn,
|
|
70
|
+
path: notifyInspector.path.concat(key),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
else if (typeof value === "function") {
|
|
74
|
+
return (...params) => {
|
|
75
|
+
notifyInspector.fn({
|
|
76
|
+
type: "action",
|
|
77
|
+
path: notifyInspector.path.concat(key),
|
|
78
|
+
params,
|
|
79
|
+
});
|
|
80
|
+
return value(...params);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
},
|
|
63
85
|
});
|
|
64
86
|
seen.add(key);
|
|
65
87
|
}
|
|
66
88
|
}
|
|
89
|
+
Object.defineProperty(result, INSPECT_MARKER, {
|
|
90
|
+
enumerable: false,
|
|
91
|
+
configurable: false,
|
|
92
|
+
get() {
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
set: (value) => {
|
|
96
|
+
notifyInspector = value;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
67
99
|
return result;
|
|
68
100
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,14 +2,13 @@ export { render } from "./render";
|
|
|
2
2
|
export { createCleanup, createMountEffect, RaskComponent } from "./component";
|
|
3
3
|
export { createContext } from "./createContext";
|
|
4
4
|
export { createState } from "./createState";
|
|
5
|
-
export {
|
|
5
|
+
export { createTask } from "./createTask";
|
|
6
6
|
export { ErrorBoundary } from "./error";
|
|
7
|
-
export { createQuery } from "./createQuery";
|
|
8
|
-
export { createMutation } from "./createMutation";
|
|
9
7
|
export { createRef } from "inferno";
|
|
10
8
|
export { createView } from "./createView";
|
|
11
9
|
export { createEffect } from "./createEffect";
|
|
12
10
|
export { createComputed } from "./createComputed";
|
|
13
11
|
export { syncBatch } from "./batch";
|
|
14
|
-
export {
|
|
12
|
+
export { inspect } from "./inspect";
|
|
13
|
+
export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, Component, } from "inferno";
|
|
15
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,13 @@ export { render } from "./render";
|
|
|
2
2
|
export { createCleanup, createMountEffect, RaskComponent } from "./component";
|
|
3
3
|
export { createContext } from "./createContext";
|
|
4
4
|
export { createState } from "./createState";
|
|
5
|
-
export {
|
|
5
|
+
export { createTask } from "./createTask";
|
|
6
6
|
export { ErrorBoundary } from "./error";
|
|
7
|
-
export { createQuery } from "./createQuery";
|
|
8
|
-
export { createMutation } from "./createMutation";
|
|
9
7
|
export { createRef } from "inferno";
|
|
10
8
|
export { createView } from "./createView";
|
|
11
9
|
export { createEffect } from "./createEffect";
|
|
12
10
|
export { createComputed } from "./createComputed";
|
|
13
11
|
export { syncBatch } from "./batch";
|
|
12
|
+
export { inspect } from "./inspect";
|
|
14
13
|
// Re-export Inferno JSX runtime functions so users don't need to install Inferno directly
|
|
15
|
-
export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, } from "inferno";
|
|
14
|
+
export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, Component, } from "inferno";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const INSPECT_MARKER: unique symbol;
|
|
2
|
+
export type InspectEvent = {
|
|
3
|
+
type: "mutation";
|
|
4
|
+
path: string[];
|
|
5
|
+
value: any;
|
|
6
|
+
} | {
|
|
7
|
+
type: "action";
|
|
8
|
+
path: string[];
|
|
9
|
+
params: any[];
|
|
10
|
+
};
|
|
11
|
+
export type InspectorCallback = (event: InspectEvent) => void;
|
|
12
|
+
export declare function inspect(root: any, cb: InspectorCallback): void;
|
|
13
|
+
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../src/inspect.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,eAAoB,CAAC;AAEhD,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,GAAG,CAAC;CACZ,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,GAAG,EAAE,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAE9D,wBAAgB,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,iBAAiB,QAKvD"}
|
package/dist/inspect.js
ADDED
package/dist/plugin.d.ts
CHANGED
|
@@ -6,12 +6,7 @@ export interface RaskPluginOptions {
|
|
|
6
6
|
*/
|
|
7
7
|
transformComponents?: boolean;
|
|
8
8
|
/**
|
|
9
|
-
* Import source for Inferno
|
|
10
|
-
* @default true (imports from rask-ui)
|
|
11
|
-
*/
|
|
12
|
-
imports?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Import source for RaskComponent
|
|
9
|
+
* Import source for Inferno JSX runtime functions
|
|
15
10
|
* @default "rask-ui"
|
|
16
11
|
*/
|
|
17
12
|
importSource?: string;
|
|
@@ -24,5 +19,5 @@ export interface RaskPluginOptions {
|
|
|
24
19
|
/**
|
|
25
20
|
* Vite plugin for transforming JSX to Inferno and function components to RaskComponent classes
|
|
26
21
|
*/
|
|
27
|
-
export
|
|
22
|
+
export default function raskPlugin(options?: RaskPluginOptions): Plugin;
|
|
28
23
|
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAMnC,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAMnC,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAsF1E"}
|
package/dist/plugin.js
CHANGED
|
@@ -7,8 +7,8 @@ const require = createRequire(import.meta.url);
|
|
|
7
7
|
/**
|
|
8
8
|
* Vite plugin for transforming JSX to Inferno and function components to RaskComponent classes
|
|
9
9
|
*/
|
|
10
|
-
export function raskPlugin(options = {}) {
|
|
11
|
-
const { transformComponents = true,
|
|
10
|
+
export default function raskPlugin(options = {}) {
|
|
11
|
+
const { transformComponents = true, importSource = 'rask-ui', defineAllArguments = false, } = options;
|
|
12
12
|
// Resolve the path to swc-plugin-inferno WASM file
|
|
13
13
|
const infernoPluginPath = require.resolve('swc-plugin-inferno/swc_plugin_inferno.wasm');
|
|
14
14
|
// Resolve the path to our RaskComponent plugin
|
|
@@ -16,9 +16,17 @@ export function raskPlugin(options = {}) {
|
|
|
16
16
|
return {
|
|
17
17
|
name: 'rask-plugin',
|
|
18
18
|
enforce: 'pre',
|
|
19
|
-
config() {
|
|
19
|
+
config(config, { mode }) {
|
|
20
20
|
return {
|
|
21
21
|
esbuild: false, // Disable esbuild to use SWC
|
|
22
|
+
resolve: {
|
|
23
|
+
alias: {
|
|
24
|
+
// In development mode, use Inferno's development build to avoid the warning
|
|
25
|
+
...(mode === 'development' && {
|
|
26
|
+
inferno: 'inferno/dist/index.dev.mjs',
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
22
30
|
};
|
|
23
31
|
},
|
|
24
32
|
async transform(code, id) {
|
|
@@ -33,7 +41,7 @@ export function raskPlugin(options = {}) {
|
|
|
33
41
|
[
|
|
34
42
|
infernoPluginPath,
|
|
35
43
|
{
|
|
36
|
-
|
|
44
|
+
importSource,
|
|
37
45
|
defineAllArguments,
|
|
38
46
|
},
|
|
39
47
|
],
|
package/logo.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rask-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -25,10 +25,11 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
27
|
"swc-plugin",
|
|
28
|
+
"logo.png",
|
|
28
29
|
"README.md"
|
|
29
30
|
],
|
|
30
31
|
"scripts": {
|
|
31
|
-
"build": "npm run build:plugin && tsc && cp ../../README.md .",
|
|
32
|
+
"build": "npm run build:plugin && tsc && cp ../../README.md . && cp ../../logo.png .",
|
|
32
33
|
"build:plugin": "cd swc-plugin && cargo build --release --target wasm32-wasip1",
|
|
33
34
|
"dev": "tsc --watch",
|
|
34
35
|
"test": "vitest",
|
package/swc-plugin/src/lib.rs
CHANGED
|
@@ -181,6 +181,29 @@ impl RaskComponentTransform {
|
|
|
181
181
|
})
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/// Rewrite imports from "inferno" to the configured import source
|
|
185
|
+
fn rewrite_inferno_imports(&mut self, module: &mut Module) {
|
|
186
|
+
let import_source = self
|
|
187
|
+
.config
|
|
188
|
+
.import_source
|
|
189
|
+
.as_ref()
|
|
190
|
+
.map(|s| s.as_str())
|
|
191
|
+
.unwrap_or("rask-ui");
|
|
192
|
+
|
|
193
|
+
for item in &mut module.body {
|
|
194
|
+
if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = item {
|
|
195
|
+
if &*import.src.value == "inferno" {
|
|
196
|
+
// Rewrite the import source from "inferno" to the configured source
|
|
197
|
+
import.src = Box::new(Str {
|
|
198
|
+
span: Default::default(),
|
|
199
|
+
value: Wtf8Atom::from(import_source),
|
|
200
|
+
raw: None,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
184
207
|
/// Inject the RaskComponent import at the top of the module
|
|
185
208
|
fn inject_runtime(&mut self, module: &mut Module) {
|
|
186
209
|
if self.import_rask_component.is_none() {
|
|
@@ -245,6 +268,9 @@ impl VisitMut for RaskComponentTransform {
|
|
|
245
268
|
// First visit all items to transform them
|
|
246
269
|
module.visit_mut_children_with(self);
|
|
247
270
|
|
|
271
|
+
// Rewrite any "inferno" imports to use the configured import source
|
|
272
|
+
self.rewrite_inferno_imports(module);
|
|
273
|
+
|
|
248
274
|
// Then inject imports if needed
|
|
249
275
|
self.inject_runtime(module);
|
|
250
276
|
}
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/Users/christianalfoni/Development/
|
|
1
|
+
/Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/target/wasm32-wasip1/release/deps/swc_plugin_rask_component.d: src/lib.rs
|
|
2
2
|
|
|
3
|
-
/Users/christianalfoni/Development/
|
|
3
|
+
/Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/target/wasm32-wasip1/release/deps/swc_plugin_rask_component.wasm: src/lib.rs
|
|
4
4
|
|
|
5
|
-
/Users/christianalfoni/Development/
|
|
5
|
+
/Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/target/wasm32-wasip1/release/deps/libswc_plugin_rask_component.rlib: src/lib.rs
|
|
6
6
|
|
|
7
7
|
src/lib.rs:
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/Users/christianalfoni/Development/
|
|
1
|
+
/Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/target/wasm32-wasip1/release/libswc_plugin_rask_component.rlib: /Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/src/lib.rs
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/Users/christianalfoni/Development/
|
|
1
|
+
/Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.wasm: /Users/christianalfoni/Development/rask-ui/packages/core/swc-plugin/src/lib.rs
|
|
Binary file
|