rask-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +263 -0
  2. package/dist/component.d.ts +21 -0
  3. package/dist/component.d.ts.map +1 -0
  4. package/dist/component.js +128 -0
  5. package/dist/context.d.ts +5 -0
  6. package/dist/context.d.ts.map +1 -0
  7. package/dist/context.js +29 -0
  8. package/dist/createAsync.d.ts +16 -0
  9. package/dist/createAsync.d.ts.map +1 -0
  10. package/dist/createAsync.js +24 -0
  11. package/dist/createAsyncState.d.ts +16 -0
  12. package/dist/createAsyncState.d.ts.map +1 -0
  13. package/dist/createAsyncState.js +24 -0
  14. package/dist/createContext.d.ts +5 -0
  15. package/dist/createContext.d.ts.map +1 -0
  16. package/dist/createContext.js +29 -0
  17. package/dist/createMutation.d.ts +20 -0
  18. package/dist/createMutation.d.ts.map +1 -0
  19. package/dist/createMutation.js +53 -0
  20. package/dist/createQuery.d.ts +19 -0
  21. package/dist/createQuery.d.ts.map +1 -0
  22. package/dist/createQuery.js +57 -0
  23. package/dist/createRef.d.ts +5 -0
  24. package/dist/createRef.d.ts.map +1 -0
  25. package/dist/createRef.js +7 -0
  26. package/dist/createState.d.ts +2 -0
  27. package/dist/createState.d.ts.map +1 -0
  28. package/dist/createState.js +52 -0
  29. package/dist/error.d.ts +5 -0
  30. package/dist/error.d.ts.map +1 -0
  31. package/dist/error.js +7 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +9 -0
  35. package/dist/jsx-dev-runtime.d.ts +4 -0
  36. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  37. package/dist/jsx-dev-runtime.js +5 -0
  38. package/dist/jsx-runtime.d.ts +15 -0
  39. package/dist/jsx-runtime.d.ts.map +1 -0
  40. package/dist/jsx-runtime.js +19 -0
  41. package/dist/jsx.d.ts +257 -0
  42. package/dist/jsx.d.ts.map +1 -0
  43. package/dist/jsx.js +42 -0
  44. package/dist/observation.d.ts +17 -0
  45. package/dist/observation.d.ts.map +1 -0
  46. package/dist/observation.js +50 -0
  47. package/dist/render.d.ts +7 -0
  48. package/dist/render.d.ts.map +1 -0
  49. package/dist/render.js +65 -0
  50. package/dist/suspense.d.ts +25 -0
  51. package/dist/suspense.d.ts.map +1 -0
  52. package/dist/suspense.js +97 -0
  53. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # RASK
2
+
3
+ A lightweight reactive component library built on [Snabbdom](https://github.com/snabbdom/snabbdom) with MobX-inspired reactivity.
4
+
5
+ ## Component and Element Lifecycle
6
+
7
+ ### Overview
8
+
9
+ RASK uses a **host-based architecture** where each component creates a host DOM element (`<component>` tag with `display: contents`) and manages its own virtual DOM independently. Components track their direct children for efficient cleanup detection.
10
+
11
+ ### Component Lifecycle Phases
12
+
13
+ #### 1. Component Creation
14
+
15
+ ```tsx
16
+ function MyComponent(props) {
17
+ // Setup Phase - runs ONCE per component instance
18
+ const state = createState({ count: 0 });
19
+ const ref = createRef();
20
+
21
+ onMount(() => console.log('Mounted!'));
22
+ onCleanup(() => console.log('Cleaning up!'));
23
+
24
+ // Return render function
25
+ return () => <div ref={ref}>{state.count}</div>;
26
+ }
27
+ ```
28
+
29
+ **What happens:**
30
+ - `createComponentInstance()` creates a new component instance
31
+ - Component function executes (setup phase)
32
+ - `createState()` creates reactive state
33
+ - `onMount()` and `onCleanup()` register lifecycle callbacks
34
+ - Render function is stored on the instance
35
+ - Instance is wrapped with an observer for reactivity
36
+
37
+ #### 2. Initial Render
38
+
39
+ ```
40
+ render(<MyComponent />, container)
41
+
42
+ jsxToVNode() - Convert JSX to VNode
43
+
44
+ renderComponent() - Create component instance
45
+
46
+ observer(() => { /* render function */ })
47
+
48
+ Initial render (hostElement = null)
49
+
50
+ Store child VNodes for host element creation
51
+
52
+ Create host <component> VNode with children
53
+
54
+ patch() - Superfine creates DOM
55
+
56
+ setupComponentInstances() - Walk VNode tree
57
+
58
+ Set instance.hostElement from vnode.node
59
+
60
+ Store instance on element.__componentInstance
61
+
62
+ Find parent component via DOM traversal
63
+
64
+ Add to parent.children Set
65
+
66
+ Run onMount() callbacks
67
+ ```
68
+
69
+ **Key steps:**
70
+ 1. **JSX to VNode**: JSX is converted to Superfine VNodes
71
+ 2. **Component Instance Creation**: Each component gets a unique instance
72
+ 3. **Observer Setup**: Render function is wrapped to track state dependencies
73
+ 4. **Initial Render**: Observer runs but hostElement is null, so child VNodes are stored
74
+ 5. **Host Element Creation**: A `<component>` VNode is created with the children
75
+ 6. **Superfine Patch**: Superfine creates actual DOM elements
76
+ 7. **Instance Setup**: VNode tree is walked to set `hostElement` from `vnode.node`
77
+ 8. **Parent-Child Tracking**: Each instance finds its parent and registers as a child
78
+ 9. **Mount Callbacks**: `onMount()` callbacks run after DOM is ready
79
+
80
+ #### 3. State Changes and Re-renders
81
+
82
+ ```
83
+ state.count++ (or props change)
84
+
85
+ Observer notified (reactive dependency)
86
+
87
+ observer() callback executes
88
+
89
+ Render function executes
90
+
91
+ jsx() - Convert new JSX to VNodes
92
+
93
+ patch(hostNode, newVNode)
94
+
95
+ Snabbdom updates DOM
96
+ ```
97
+
98
+ **Key steps:**
99
+ 1. **State Change**: Setting a state property notifies observers
100
+ 2. **Observer Execution**: The component's observer callback runs
101
+ 3. **Re-render**: Render function executes, accessing state (tracks dependencies)
102
+ 4. **JSX to VNode**: New JSX is converted to VNodes
103
+ 5. **Patch**: Snabbdom updates the host element's children
104
+
105
+ #### 4. Component Cleanup
106
+
107
+ **Cleanup happens in two scenarios:**
108
+
109
+ ##### A. Parent Re-renders and Removes Child
110
+
111
+ ```
112
+ Parent re-renders
113
+
114
+ patch(parentHost, newVNode)
115
+
116
+ Snabbdom removes child <component> from DOM
117
+
118
+ Destroy hook called
119
+
120
+ Run cleanupCallbacks
121
+ ```
122
+
123
+ **Key steps:**
124
+ 1. **Detection**: Snabbdom's destroy hook is called when element is removed
125
+ 2. **Callbacks**: `onCleanup()` callbacks execute (clear timers, subscriptions, etc.)
126
+
127
+ ### Element Lifecycle (Regular DOM Elements)
128
+
129
+ Regular DOM elements (div, span, etc.) follow Snabbdom's patching lifecycle:
130
+
131
+ ```
132
+ JSX: <div>Hello</div>
133
+
134
+ jsx() creates VNode
135
+
136
+ patch() creates or updates DOM
137
+
138
+ vnode.elm contains DOM element
139
+ ```
140
+
141
+ **Key points:**
142
+ - Regular elements don't create component instances
143
+ - They're managed entirely by Snabbdom's patch algorithm
144
+ - No special cleanup needed (browser handles DOM removal)
145
+
146
+ ### Parent-Child Relationship Tracking
147
+
148
+ Components track their parent via the component stack during initialization:
149
+
150
+ ```
151
+ componentStack.unshift(instance)
152
+ const render = component(instance.reactiveProps)
153
+ ```
154
+
155
+ **Key points:**
156
+ - Parent-child relationships tracked through component stack
157
+ - Used for context propagation
158
+ - Cleanup handled by Snabbdom's destroy hooks
159
+
160
+ ### Complete Lifecycle Example
161
+
162
+ ```tsx
163
+ function Counter() {
164
+ // SETUP PHASE (once)
165
+ const state = createState({ count: 0 });
166
+
167
+ onMount(() => {
168
+ console.log('Counter mounted');
169
+ });
170
+
171
+ onCleanup(() => {
172
+ console.log('Counter cleaning up');
173
+ });
174
+
175
+ // RENDER PHASE (every update)
176
+ return () => (
177
+ <div>
178
+ <p>Count: {state.count}</p>
179
+ <button onClick={() => state.count++}>+</button>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ // Mount
185
+ render(<Counter />, document.getElementById('app'));
186
+ // Logs: "Counter mounted"
187
+
188
+ // User clicks button
189
+ // → state.count++ triggers observer
190
+ // → Render function executes
191
+ // → DOM updates via patch()
192
+
193
+ // Component removed (parent re-renders without it)
194
+ // → Snabbdom destroy hook called
195
+ // → Logs: "Counter cleaning up"
196
+ ```
197
+
198
+ ## Key Architectural Decisions
199
+
200
+ ### 1. Host-Based Architecture
201
+ - Each component has a host `<component>` element (display: contents)
202
+ - Components render independently to their own host
203
+ - No parent-child instance relationships for rendering
204
+ - Isolation enables fine-grained updates
205
+
206
+ ### 2. Lifecycle Management
207
+ - Snabbdom hooks manage component lifecycle
208
+ - Insert hook runs onMount callbacks
209
+ - Destroy hook runs onCleanup callbacks
210
+ - Parent-child tracking for context propagation
211
+
212
+ ### 3. Observer Pattern for Reactivity
213
+ - Render functions wrapped with observer
214
+ - Automatically tracks state/props access
215
+ - Re-renders only when observed properties change
216
+ - No manual subscriptions needed
217
+
218
+ ### 4. Context Traversal
219
+ - Context walks component tree via parent references
220
+ - Set during component initialization
221
+ - Natural hierarchical lookup
222
+ - Works with host element architecture
223
+
224
+ ### 5. Hook-Based Cleanup
225
+ - Cleanup callbacks run via Snabbdom destroy hooks
226
+ - Synchronous and predictable
227
+ - No manual tracking required
228
+ - Integrated with virtual DOM lifecycle
229
+
230
+ ### 6. Thunk-Based Components
231
+
232
+ Components use Snabbdom's thunk feature for optimization:
233
+
234
+ ```tsx
235
+ const thunkNode = thunk("component", props.key, component, [props, children]);
236
+ ```
237
+
238
+ **How it works:**
239
+ - Components wrapped as thunks with custom hooks
240
+ - Init hook: Creates component instance and runs setup
241
+ - Prepatch hook: Updates reactive props before render
242
+ - Postpatch hook: Syncs props after patch
243
+ - Insert hook: Runs onMount callbacks
244
+ - Destroy hook: Runs onCleanup callbacks
245
+
246
+ **Benefits:**
247
+ - Leverages Snabbdom's thunk optimization
248
+ - Props changes trigger reactive updates
249
+ - Lifecycle hooks integrated with virtual DOM
250
+ - Efficient component reconciliation
251
+
252
+ ## API Reference
253
+
254
+ See main [README](../../README.md) for full API details:
255
+ - `createState(initialState)` - Create reactive state
256
+ - `onMount(callback)` - Register mount callback
257
+ - `onCleanup(callback)` - Register cleanup callback
258
+ - `createContext()` - Create context for data sharing
259
+ - `createAsync(promise)` - Handle async operations
260
+ - `createQuery(fetcher)` - Create query with refetch
261
+ - `createMutation(mutator)` - Create mutation handler
262
+ - `ErrorBoundary` - Error boundary component
263
+ - `render(jsx, container)` - Mount component to DOM
@@ -0,0 +1,21 @@
1
+ import { type VNode } from "snabbdom";
2
+ import { Observer } from "./observation";
3
+ import { ChildNode } from "./render";
4
+ export type Component<P> = ((props: P) => () => VNode) | (() => () => VNode);
5
+ export type ComponentInstance = {
6
+ parent: ComponentInstance | null;
7
+ component: Component<any>;
8
+ contexts: Map<object, object> | null;
9
+ onMounts: Array<() => void>;
10
+ onCleanups: Array<() => void>;
11
+ hostNode?: VNode;
12
+ observer: Observer;
13
+ reactiveProps: object;
14
+ error: unknown;
15
+ notifyError(error: unknown): void;
16
+ };
17
+ export declare function getCurrentComponent(): ComponentInstance;
18
+ export declare function onMount(cb: () => void): void;
19
+ export declare function onCleanup(cb: () => void): void;
20
+ export declare function createComponent(component: Component<any>, props: Record<string, unknown>, children: ChildNode[] | ChildNode): import("snabbdom").Thunk;
21
+ //# sourceMappingURL=component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,KAAK,EAAkB,MAAM,UAAU,CAAC;AAE7D,OAAO,EAAsB,QAAQ,EAAU,MAAM,eAAe,CAAC;AACrE,OAAO,EAAc,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,CAAC,GAAG,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;AAE7E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC5B,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC,CAAC;AAIF,wBAAgB,mBAAmB,sBAElC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAQrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAQvC;AAwGD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,4BAOlC"}
@@ -0,0 +1,128 @@
1
+ import { thunk } from "snabbdom";
2
+ import { getCurrentObserver, Observer, Signal } from "./observation";
3
+ import { jsx, patch } from "./render";
4
+ import { createState } from "./createState";
5
+ const componentStack = [];
6
+ export function getCurrentComponent() {
7
+ return componentStack[0] || null;
8
+ }
9
+ export function onMount(cb) {
10
+ const current = componentStack[0];
11
+ if (!current) {
12
+ throw new Error("Only use onMount in component setup");
13
+ }
14
+ current.onMounts.push(cb);
15
+ }
16
+ export function onCleanup(cb) {
17
+ const current = componentStack[0];
18
+ if (!current) {
19
+ throw new Error("Only use onCleanup in component setup");
20
+ }
21
+ current.onCleanups.push(cb);
22
+ }
23
+ const hook = {
24
+ insert(vnode) {
25
+ componentStack.shift();
26
+ vnode.data.componentInstance.onMounts.forEach((cb) => cb());
27
+ },
28
+ destroy(vnode) {
29
+ componentStack.shift();
30
+ vnode.data.componentInstance.onCleanups.forEach((cb) => cb());
31
+ },
32
+ prepatch(oldVnode, thunk) {
33
+ copyToThunk(oldVnode, thunk);
34
+ componentStack.unshift(thunk.data.componentInstance);
35
+ },
36
+ postpatch(_, newNode) {
37
+ const componentInstance = newNode.data.componentInstance;
38
+ componentStack.shift();
39
+ const props = newNode.data.args[0];
40
+ const children = newNode.data.args[1];
41
+ for (const key in props) {
42
+ componentInstance.reactiveProps[key] = props[key];
43
+ }
44
+ componentInstance.reactiveProps.children = children;
45
+ },
46
+ init(thunk) {
47
+ const component = thunk.data.fn;
48
+ const args = thunk.data.args;
49
+ let errorSignal;
50
+ let error;
51
+ const executeRender = () => {
52
+ const stopObserving = instance.observer.observe();
53
+ let renderResult = null;
54
+ try {
55
+ renderResult = render();
56
+ }
57
+ catch (error) {
58
+ instance.notifyError(error);
59
+ }
60
+ finally {
61
+ stopObserving();
62
+ }
63
+ return jsx("component", {
64
+ hook: {
65
+ insert: hook.insert,
66
+ destroy: hook.destroy,
67
+ },
68
+ "data-name": component.name,
69
+ }, Array.isArray(renderResult) ? renderResult : [renderResult]);
70
+ };
71
+ const instance = {
72
+ parent: getCurrentComponent(),
73
+ component,
74
+ contexts: null,
75
+ onMounts: [],
76
+ onCleanups: [],
77
+ observer: new Observer(() => {
78
+ const renderResult = executeRender();
79
+ instance.hostNode = patch(instance.hostNode, renderResult);
80
+ }),
81
+ reactiveProps: createState({
82
+ ...args[0],
83
+ children: args[1],
84
+ }),
85
+ get error() {
86
+ if (!errorSignal) {
87
+ errorSignal = new Signal();
88
+ }
89
+ const observer = getCurrentObserver();
90
+ if (observer) {
91
+ observer.subscribeSignal(errorSignal);
92
+ }
93
+ return error;
94
+ },
95
+ notifyError(childError) {
96
+ if (errorSignal) {
97
+ error = childError;
98
+ errorSignal.notify();
99
+ }
100
+ else if (instance.parent) {
101
+ instance.parent.notifyError(childError);
102
+ }
103
+ else {
104
+ throw childError;
105
+ }
106
+ },
107
+ };
108
+ componentStack.unshift(instance);
109
+ const render = component(instance.reactiveProps);
110
+ const renderResult = executeRender();
111
+ renderResult.data.componentInstance = instance;
112
+ copyToThunk(renderResult, thunk);
113
+ instance.hostNode = thunk;
114
+ },
115
+ };
116
+ export function createComponent(component, props, children) {
117
+ const thunkNode = thunk("component", props.key, component, [props, children]);
118
+ Object.assign(thunkNode.data.hook, hook);
119
+ return thunkNode;
120
+ }
121
+ function copyToThunk(vnode, thunk) {
122
+ vnode.data.fn = thunk.data.fn;
123
+ vnode.data.args = thunk.data.args;
124
+ thunk.data = vnode.data;
125
+ thunk.children = vnode.children;
126
+ thunk.text = vnode.text;
127
+ thunk.elm = vnode.elm;
128
+ }
@@ -0,0 +1,5 @@
1
+ export declare function createContext<T extends object>(): {
2
+ set(value: T): void;
3
+ get(): T;
4
+ };
5
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM;eAE/B,CAAC;WAaL,CAAC;EAmBX"}
@@ -0,0 +1,29 @@
1
+ import { getCurrentComponent } from "./component";
2
+ export function createContext() {
3
+ const context = {
4
+ set(value) {
5
+ const currentComponent = getCurrentComponent();
6
+ if (!currentComponent) {
7
+ throw new Error("You can not set context out component setup");
8
+ }
9
+ if (!currentComponent.contexts) {
10
+ currentComponent.contexts = new Map();
11
+ }
12
+ currentComponent.contexts.set(context, value);
13
+ },
14
+ get() {
15
+ let currentComponent = getCurrentComponent();
16
+ if (!currentComponent) {
17
+ throw new Error("You can not set context out component setup");
18
+ }
19
+ while (currentComponent) {
20
+ if (currentComponent.contexts?.has(context)) {
21
+ return currentComponent.contexts.get(context);
22
+ }
23
+ currentComponent = currentComponent.parent;
24
+ }
25
+ throw new Error("Could not find context in parent components");
26
+ },
27
+ };
28
+ return context;
29
+ }
@@ -0,0 +1,16 @@
1
+ type AsyncState<T> = {
2
+ isPending: true;
3
+ value: null;
4
+ error: null;
5
+ } | {
6
+ isPending: false;
7
+ value: T;
8
+ error: null;
9
+ } | {
10
+ isPending: false;
11
+ value: null;
12
+ error: string;
13
+ };
14
+ export declare function createAsync<T>(promise: Promise<T>): AsyncState<T>;
15
+ export {};
16
+ //# sourceMappingURL=createAsync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAsync.d.ts","sourceRoot":"","sources":["../src/createAsync.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,CAAC,CAAC,IACb;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,iBAwBjD"}
@@ -0,0 +1,24 @@
1
+ import { createState } from "./createState";
2
+ export function createAsync(promise) {
3
+ const state = createState({
4
+ isPending: true,
5
+ error: null,
6
+ value: null,
7
+ });
8
+ promise
9
+ .then((value) => {
10
+ Object.assign(state, {
11
+ value,
12
+ error: null,
13
+ isPending: false,
14
+ });
15
+ })
16
+ .catch((error) => {
17
+ Object.assign(state, {
18
+ value: null,
19
+ error: String(error),
20
+ isPending: false,
21
+ });
22
+ });
23
+ return state;
24
+ }
@@ -0,0 +1,16 @@
1
+ type AsyncState<T> = {
2
+ isPending: true;
3
+ value: null;
4
+ error: null;
5
+ } | {
6
+ isPending: false;
7
+ value: T;
8
+ error: null;
9
+ } | {
10
+ isPending: false;
11
+ value: null;
12
+ error: string;
13
+ };
14
+ export declare function createAsyncState<T>(promise: Promise<T>): AsyncState<T>;
15
+ export {};
16
+ //# sourceMappingURL=createAsyncState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAsyncState.d.ts","sourceRoot":"","sources":["../src/createAsyncState.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,CAAC,CAAC,IACb;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,iBAwBtD"}
@@ -0,0 +1,24 @@
1
+ import { createState } from "./createState";
2
+ export function createAsyncState(promise) {
3
+ const state = createState({
4
+ isPending: true,
5
+ error: null,
6
+ value: null,
7
+ });
8
+ promise
9
+ .then((value) => {
10
+ Object.assign(state, {
11
+ value,
12
+ error: null,
13
+ isPending: false,
14
+ });
15
+ })
16
+ .catch((error) => {
17
+ Object.assign(state, {
18
+ value: null,
19
+ error: String(error),
20
+ isPending: false,
21
+ });
22
+ });
23
+ return state;
24
+ }
@@ -0,0 +1,5 @@
1
+ export declare function createContext<T extends object>(): {
2
+ set(value: T): void;
3
+ get(): T;
4
+ };
5
+ //# sourceMappingURL=createContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createContext.d.ts","sourceRoot":"","sources":["../src/createContext.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM;eAE/B,CAAC;WAaL,CAAC;EAmBX"}
@@ -0,0 +1,29 @@
1
+ import { getCurrentComponent } from "./component";
2
+ export function createContext() {
3
+ const context = {
4
+ set(value) {
5
+ const currentComponent = getCurrentComponent();
6
+ if (!currentComponent) {
7
+ throw new Error("You can not set context out component setup");
8
+ }
9
+ if (!currentComponent.contexts) {
10
+ currentComponent.contexts = new Map();
11
+ }
12
+ currentComponent.contexts.set(context, value);
13
+ },
14
+ get() {
15
+ let currentComponent = getCurrentComponent();
16
+ if (!currentComponent) {
17
+ throw new Error("You can not set context out component setup");
18
+ }
19
+ while (currentComponent) {
20
+ if (currentComponent.contexts?.has(context)) {
21
+ return currentComponent.contexts.get(context);
22
+ }
23
+ currentComponent = currentComponent.parent;
24
+ }
25
+ throw new Error("Could not find context in parent components");
26
+ },
27
+ };
28
+ return context;
29
+ }
@@ -0,0 +1,20 @@
1
+ type MutationState<T> = {
2
+ isPending: true;
3
+ params: T;
4
+ error: null;
5
+ } | {
6
+ isPending: false;
7
+ params: null;
8
+ error: null;
9
+ } | {
10
+ isPending: false;
11
+ params: null;
12
+ error: string;
13
+ };
14
+ export type Mutation<T> = MutationState<T> & {
15
+ mutate(): void;
16
+ mutate(params: T): void;
17
+ };
18
+ export declare function createMutation<T>(mutator: (params: T) => Promise<T>): Mutation<T>;
19
+ export {};
20
+ //# sourceMappingURL=createMutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMutation.d.ts","sourceRoot":"","sources":["../src/createMutation.ts"],"names":[],"mappings":"AAEA,KAAK,aAAa,CAAC,CAAC,IAChB;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG;IAC3C,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,EAC9B,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACjC,QAAQ,CAAC,CAAC,CAAC,CA0Db"}
@@ -0,0 +1,53 @@
1
+ import { createState } from "./createState";
2
+ export function createMutation(mutator) {
3
+ const state = createState({
4
+ isPending: false,
5
+ params: null,
6
+ error: null,
7
+ });
8
+ const assign = (newState) => {
9
+ Object.assign(state, newState);
10
+ };
11
+ let currentAbortController;
12
+ return {
13
+ get isPending() {
14
+ return state.isPending;
15
+ },
16
+ get params() {
17
+ return state.params;
18
+ },
19
+ get error() {
20
+ return state.error;
21
+ },
22
+ mutate(params) {
23
+ currentAbortController?.abort();
24
+ const abortController = (currentAbortController = new AbortController());
25
+ assign({
26
+ isPending: true,
27
+ params,
28
+ error: null,
29
+ });
30
+ mutator(params)
31
+ .then(() => {
32
+ if (abortController.signal.aborted) {
33
+ return;
34
+ }
35
+ assign({
36
+ isPending: false,
37
+ params: null,
38
+ error: null,
39
+ });
40
+ })
41
+ .catch((error) => {
42
+ if (abortController.signal.aborted) {
43
+ return;
44
+ }
45
+ assign({
46
+ isPending: false,
47
+ params: null,
48
+ error: String(error),
49
+ });
50
+ });
51
+ },
52
+ };
53
+ }
@@ -0,0 +1,19 @@
1
+ type QueryState<T> = {
2
+ isPending: true;
3
+ data: T | null;
4
+ error: null;
5
+ } | {
6
+ isPending: false;
7
+ data: T;
8
+ error: null;
9
+ } | {
10
+ isPending: false;
11
+ data: null;
12
+ error: string;
13
+ };
14
+ export type Query<T> = QueryState<T> & {
15
+ fetch(force?: boolean): void;
16
+ };
17
+ export declare function createQuery<T>(fetcher: () => Promise<T>): Query<T>;
18
+ export {};
19
+ //# sourceMappingURL=createQuery.d.ts.map