rask-ui 0.3.4 → 0.4.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.
Files changed (65) hide show
  1. package/README.md +266 -96
  2. package/dist/batch.d.ts +7 -0
  3. package/dist/batch.d.ts.map +1 -0
  4. package/dist/batch.js +107 -0
  5. package/dist/component.d.ts +9 -1
  6. package/dist/component.d.ts.map +1 -1
  7. package/dist/component.js +42 -12
  8. package/dist/createComputed.d.ts +4 -0
  9. package/dist/createComputed.d.ts.map +1 -0
  10. package/dist/createComputed.js +41 -0
  11. package/dist/createEffect.d.ts +2 -0
  12. package/dist/createEffect.d.ts.map +1 -0
  13. package/dist/createEffect.js +25 -0
  14. package/dist/createState.d.ts +1 -0
  15. package/dist/createState.d.ts.map +1 -1
  16. package/dist/createState.js +1 -1
  17. package/dist/index.d.ts +4 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +11 -1
  20. package/dist/observation.d.ts +82 -6
  21. package/dist/observation.d.ts.map +1 -1
  22. package/dist/observation.js +171 -21
  23. package/dist/plugin.d.ts +8 -0
  24. package/dist/plugin.d.ts.map +1 -0
  25. package/dist/plugin.js +195 -0
  26. package/dist/scheduler.d.ts +4 -0
  27. package/dist/scheduler.d.ts.map +1 -0
  28. package/dist/scheduler.js +107 -0
  29. package/package.json +1 -1
  30. package/dist/createRef.d.ts +0 -5
  31. package/dist/createRef.d.ts.map +0 -1
  32. package/dist/createRef.js +0 -7
  33. package/dist/test-setup.d.ts +0 -16
  34. package/dist/test-setup.d.ts.map +0 -1
  35. package/dist/test-setup.js +0 -40
  36. package/dist/vdom/AbstractVNode.d.ts +0 -44
  37. package/dist/vdom/AbstractVNode.d.ts.map +0 -1
  38. package/dist/vdom/AbstractVNode.js +0 -256
  39. package/dist/vdom/ComponentVNode.d.ts +0 -48
  40. package/dist/vdom/ComponentVNode.d.ts.map +0 -1
  41. package/dist/vdom/ComponentVNode.js +0 -221
  42. package/dist/vdom/ElementVNode.d.ts +0 -27
  43. package/dist/vdom/ElementVNode.d.ts.map +0 -1
  44. package/dist/vdom/ElementVNode.js +0 -220
  45. package/dist/vdom/FragmentVNode.d.ts +0 -13
  46. package/dist/vdom/FragmentVNode.d.ts.map +0 -1
  47. package/dist/vdom/FragmentVNode.js +0 -49
  48. package/dist/vdom/RootVNode.d.ts +0 -25
  49. package/dist/vdom/RootVNode.d.ts.map +0 -1
  50. package/dist/vdom/RootVNode.js +0 -79
  51. package/dist/vdom/TextVNode.d.ts +0 -11
  52. package/dist/vdom/TextVNode.d.ts.map +0 -1
  53. package/dist/vdom/TextVNode.js +0 -35
  54. package/dist/vdom/dom-utils.d.ts +0 -14
  55. package/dist/vdom/dom-utils.d.ts.map +0 -1
  56. package/dist/vdom/dom-utils.js +0 -103
  57. package/dist/vdom/index.d.ts +0 -10
  58. package/dist/vdom/index.d.ts.map +0 -1
  59. package/dist/vdom/index.js +0 -26
  60. package/dist/vdom/types.d.ts +0 -20
  61. package/dist/vdom/types.d.ts.map +0 -1
  62. package/dist/vdom/types.js +0 -1
  63. package/dist/vdom/utils.d.ts +0 -6
  64. package/dist/vdom/utils.d.ts.map +0 -1
  65. package/dist/vdom/utils.js +0 -63
package/README.md CHANGED
@@ -4,13 +4,13 @@
4
4
  <img src="logo.png" alt="Logo" width="200">
5
5
  </p>
6
6
 
7
- A lightweight reactive component library that combines the simplicity of observable state management with the full power of a virtual DOM reconciler.
7
+ A lightweight reactive component library that combines the simplicity of observable state management with the full power of a virtual DOM reconciler. Ideal for single page applications, using web technology.
8
8
 
9
9
  ```bash
10
10
  npm install rask-ui
11
11
  ```
12
12
 
13
- ## The Problem with Modern UI Frameworks
13
+ ## The Itch with Modern UI Frameworks
14
14
 
15
15
  Modern UI frameworks present developers with a fundamental tradeoff between state management and UI expression:
16
16
 
@@ -42,9 +42,9 @@ function MyApp() {
42
42
  }
43
43
  ```
44
44
 
45
- Solid offers a simpler mental model with fine-grained reactivity. Updates don't happen by calling the component function again, but in "hidden" parts of expressions in the UI. However:
45
+ Solid offers a seamingly simpler mental model with fine-grained reactivity. Updates don't happen by calling the component function again, which resolves the mental strain of expressing state management, however:
46
46
 
47
- - Requires understanding special compiler transformations
47
+ - The code you write is compiled to balance DX vs requirements of the runtime
48
48
  - Special components for expressing dynamic UIs (`<Show>`, `<For>`, etc.)
49
49
  - Different signatures for accessing reactive values: `count()` VS `state.count`
50
50
 
@@ -60,13 +60,11 @@ function MyApp() {
60
60
 
61
61
  RASK gives you:
62
62
 
63
- - **Predictable observable state management** - No reconciler interference, just plain reactivity
64
- - **Full reconciler power** - Express complex UIs naturally with components
65
- - **No special syntax** - Access state properties directly, no function calls
66
- - **No compiler magic** - Plain JavaScript/TypeScript
67
- - **Simple mental model** - State updates trigger only affected components
63
+ - **Simple state management** - No reconciler interference with your state management
64
+ - **Full reconciler power** - Express complex UIs naturally with the language
65
+ - **No compiler magic** - Plain JavaScript/TypeScript, it runs as you write it
68
66
 
69
- Built on [Inferno JS](https://github.com/infernojs/inferno).
67
+ :fire: Built on [Inferno JS](https://github.com/infernojs/inferno).
70
68
 
71
69
  ## Getting Started
72
70
 
@@ -76,6 +74,19 @@ Built on [Inferno JS](https://github.com/infernojs/inferno).
76
74
  npm install rask-ui
77
75
  ```
78
76
 
77
+ ### Configuration
78
+
79
+ Configure TypeScript to use RASK's JSX runtime:
80
+
81
+ ```json
82
+ {
83
+ "compilerOptions": {
84
+ "jsx": "react-jsx",
85
+ "jsxImportSource": "rask-ui"
86
+ }
87
+ }
88
+ ```
89
+
79
90
  ### Basic Example
80
91
 
81
92
  ```tsx
@@ -182,9 +193,9 @@ function Parent() {
182
193
 
183
194
  When `state.count` changes in Parent, only Child re-renders because it accesses `props.value`.
184
195
 
185
- ### Important: Do Not Destructure Reactive Objects
196
+ ### One Rule To Accept
186
197
 
187
- **RASK follows the same rule as Solid.js**: Never destructure reactive objects (state, props, context values, async, query, mutation). Destructuring extracts plain values and breaks reactivity.
198
+ **RASK has observable primitives**: Never destructure reactive objects (state, props, context values, async, query, mutation). Destructuring extracts plain values and breaks reactivity.
188
199
 
189
200
  ```tsx
190
201
  // ❌ BAD - Destructuring breaks reactivity
@@ -234,6 +245,7 @@ Reactive objects are implemented using JavaScript Proxies. When you access a pro
234
245
  - `createQuery()` - Never destructure query objects
235
246
  - `createMutation()` - Never destructure mutation objects
236
247
  - `createView()` - Never destructure view objects
248
+ - `createComputed()` - Never destructure computed objects
237
249
 
238
250
  ## API Reference
239
251
 
@@ -300,24 +312,26 @@ Creates a view that merges multiple objects (reactive or plain) into a single ob
300
312
  ```tsx
301
313
  import { createView, createState } from "rask-ui";
302
314
 
303
- function Counter() {
315
+ function createCounter() {
304
316
  const state = createState({ count: 0, name: "Counter" });
305
- const helpers = {
306
- increment: () => state.count++,
307
- decrement: () => state.count--,
308
- reset: () => (state.count = 0),
309
- };
317
+ const increment = () => state.count++;
318
+ const decrement = () => state.count--;
319
+ const reset = () => (state.count = 0);
310
320
 
311
- const view = createView(state, helpers);
321
+ return createView(state, { increment, decrement, reset });
322
+ }
323
+
324
+ function Counter() {
325
+ const counter = createCounter();
312
326
 
313
327
  return () => (
314
328
  <div>
315
329
  <h1>
316
- {view.name}: {view.count}
330
+ {counter.name}: {counter.count}
317
331
  </h1>
318
- <button onClick={view.increment}>+</button>
319
- <button onClick={view.decrement}>-</button>
320
- <button onClick={view.reset}>Reset</button>
332
+ <button onClick={counter.increment}>+</button>
333
+ <button onClick={counter.decrement}>-</button>
334
+ <button onClick={counter.reset}>Reset</button>
321
335
  </div>
322
336
  );
323
337
  }
@@ -329,38 +343,6 @@ function Counter() {
329
343
 
330
344
  **Returns:** A view object with getters for all properties, maintaining reactivity
331
345
 
332
- **Use Cases:**
333
-
334
- 1. **Merge state with helper methods:**
335
-
336
- ```tsx
337
- const state = createState({ count: 0 });
338
- const helpers = { increment: () => state.count++ };
339
- const view = createView(state, helpers);
340
- // Access both: view.count, view.increment()
341
- ```
342
-
343
- 2. **Combine multiple reactive objects:**
344
-
345
- ```tsx
346
- const user = createState({ name: "Alice" });
347
- const settings = createState({ theme: "dark" });
348
- const view = createView(user, settings);
349
- // Access both: view.name, view.theme
350
- ```
351
-
352
- 3. **Override properties with computed values:**
353
- ```tsx
354
- const state = createState({ firstName: "John", lastName: "Doe" });
355
- const computed = {
356
- get fullName() {
357
- return `${state.firstName} ${state.lastName}`;
358
- },
359
- };
360
- const view = createView(state, computed);
361
- // view.fullName returns "John Doe" and updates when state changes
362
- ```
363
-
364
346
  **Notes:**
365
347
 
366
348
  - Reactivity is maintained through getters that reference the source objects
@@ -403,25 +385,171 @@ function Example() {
403
385
 
404
386
  Pass the ref to an element's `ref` prop. The `current` property will be set to the DOM element when mounted and `null` when unmounted.
405
387
 
406
- **Example with SVG:**
388
+ ---
389
+
390
+ ### Reactivity Primitives
391
+
392
+ #### `createEffect(callback)`
393
+
394
+ Creates an effect that automatically tracks reactive dependencies and re-runs whenever they change. The effect runs immediately on creation.
407
395
 
408
396
  ```tsx
409
- function Drawing() {
410
- const svgRef = createRef<SVGSVGElement>();
397
+ import { createEffect, createState } from "rask-ui";
411
398
 
412
- const getSize = () => {
413
- if (svgRef.current) {
414
- const bbox = svgRef.current.getBBox();
415
- console.log(`Width: ${bbox.width}, Height: ${bbox.height}`);
416
- }
399
+ function Timer() {
400
+ const state = createState({ count: 0, log: [] });
401
+
402
+ // Effect runs immediately and whenever state.count changes
403
+ createEffect(() => {
404
+ console.log("Count changed:", state.count);
405
+ state.log.push(`Count: ${state.count}`);
406
+ });
407
+
408
+ return () => (
409
+ <div>
410
+ <p>Count: {state.count}</p>
411
+ <button onClick={() => state.count++}>Increment</button>
412
+ <ul>
413
+ {state.log.map((entry, i) => (
414
+ <li key={i}>{entry}</li>
415
+ ))}
416
+ </ul>
417
+ </div>
418
+ );
419
+ }
420
+ ```
421
+
422
+ **Parameters:**
423
+
424
+ - `callback: () => void` - Function to run when dependencies change
425
+
426
+ **Features:**
427
+
428
+ - Runs immediately on creation
429
+ - Automatically tracks reactive dependencies accessed during execution
430
+ - Re-runs on microtask when dependencies change (prevents synchronous cascades)
431
+ - Automatically cleaned up when component unmounts
432
+ - Can be used for side effects like logging, syncing to localStorage, or updating derived state
433
+
434
+ **Notes:**
435
+
436
+ - Only call during component setup phase (not in render function)
437
+ - Effects are queued on microtask to avoid synchronous execution from prop changes
438
+ - Be careful with effects that modify state - can cause infinite loops if not careful
439
+
440
+ ---
441
+
442
+ #### `createComputed<T>(computed)`
443
+
444
+ Creates an object with computed properties that automatically track dependencies and cache results until dependencies change.
445
+
446
+ ```tsx
447
+ import { createComputed, createState } from "rask-ui";
448
+
449
+ function ShoppingCart() {
450
+ const state = createState({
451
+ items: [
452
+ { id: 1, name: "Apple", price: 1.5, quantity: 3 },
453
+ { id: 2, name: "Banana", price: 0.8, quantity: 5 },
454
+ ],
455
+ taxRate: 0.2,
456
+ });
457
+
458
+ const computed = createComputed({
459
+ subtotal: () =>
460
+ state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
461
+ tax: () => computed.subtotal * state.taxRate,
462
+ total: () => computed.subtotal + computed.tax,
463
+ itemCount: () => state.items.reduce((sum, item) => sum + item.quantity, 0),
464
+ });
465
+
466
+ return () => (
467
+ <div>
468
+ <h2>Cart ({computed.itemCount} items)</h2>
469
+ <ul>
470
+ {state.items.map((item) => (
471
+ <li key={item.id}>
472
+ {item.name}: ${item.price} x {item.quantity}
473
+ <button onClick={() => item.quantity++}>+</button>
474
+ <button onClick={() => item.quantity--}>-</button>
475
+ </li>
476
+ ))}
477
+ </ul>
478
+ <div>
479
+ <p>Subtotal: ${computed.subtotal.toFixed(2)}</p>
480
+ <p>
481
+ Tax ({state.taxRate * 100}%): ${computed.tax.toFixed(2)}
482
+ </p>
483
+ <p>
484
+ <strong>Total: ${computed.total.toFixed(2)}</strong>
485
+ </p>
486
+ </div>
487
+ </div>
488
+ );
489
+ }
490
+ ```
491
+
492
+ **Parameters:**
493
+
494
+ - `computed: T` - Object where each property is a function returning a computed value
495
+
496
+ **Returns:** Reactive object with cached computed properties
497
+
498
+ **Features:**
499
+
500
+ - **Lazy evaluation** - Computed values are only calculated when accessed
501
+ - **Automatic caching** - Results are cached until dependencies change
502
+ - **Dependency tracking** - Automatically tracks what state each computed depends on
503
+ - **Composable** - Computed properties can depend on other computed properties
504
+ - **Efficient** - Only recomputes when dirty (dependencies changed)
505
+ - **Automatic cleanup** - Cleaned up when component unmounts
506
+
507
+ **Notes:**
508
+
509
+ - Access computed properties directly (e.g., `computed.total`), don't call as functions
510
+ - Computed properties are getters, not functions
511
+ - **Do not destructure** - Breaks reactivity (see warning section above)
512
+ - Only call during component setup phase
513
+
514
+ ---
515
+
516
+ ### Automatic Batching
517
+
518
+ RASK automatically batches state updates to minimize re-renders. This happens transparently without any special syntax.
519
+
520
+ **How it works:**
521
+
522
+ - **User interactions** (clicks, inputs, keyboard, etc.) - State changes are batched and flushed synchronously at the end of the event
523
+ - **Other updates** (setTimeout, fetch callbacks, etc.) - State changes are batched and flushed on the next microtask
524
+
525
+ ```tsx
526
+ function BatchingExample() {
527
+ const state = createState({ count: 0, clicks: 0 });
528
+
529
+ const handleClick = () => {
530
+ // All three updates are batched into a single render
531
+ state.count++;
532
+ state.clicks++;
533
+ state.count++;
534
+ // UI updates once with count=2, clicks=1
535
+ };
536
+
537
+ const handleAsync = () => {
538
+ setTimeout(() => {
539
+ // These updates are also batched (async batch)
540
+ state.count++;
541
+ state.clicks++;
542
+ // UI updates once on next microtask
543
+ }, 100);
417
544
  };
418
545
 
419
546
  return () => (
420
547
  <div>
421
- <svg ref={svgRef} width="200" height="200">
422
- <circle cx="100" cy="100" r="50" />
423
- </svg>
424
- <button onClick={getSize}>Get SVG Size</button>
548
+ <p>
549
+ Count: {state.count}, Clicks: {state.clicks}
550
+ </p>
551
+ <button onClick={handleClick}>Sync Update</button>
552
+ <button onClick={handleAsync}>Async Update</button>
425
553
  </div>
426
554
  );
427
555
  }
@@ -543,13 +671,16 @@ import { createAsync } from "rask-ui";
543
671
  function UserProfile() {
544
672
  const user = createAsync(fetch("/api/user").then((r) => r.json()));
545
673
 
546
- return () => (
547
- <div>
548
- {user.isPending && <p>Loading...</p>}
549
- {user.error && <p>Error: {user.error}</p>}
550
- {user.value && <p>Hello, {user.value.name}!</p>}
551
- </div>
552
- );
674
+ return () => }
675
+ if (user.isPending) {
676
+ return <p>Loading...</p>
677
+ }
678
+
679
+ if (user.error) {
680
+ return <p>Error: {user.error}</p>
681
+ }
682
+
683
+ return <p>Hello, {user.value.name}!</p>
553
684
  }
554
685
  ```
555
686
 
@@ -580,16 +711,25 @@ import { createQuery } from "rask-ui";
580
711
 
581
712
  function Posts() {
582
713
  const posts = createQuery(() => fetch("/api/posts").then((r) => r.json()));
714
+ const renderPosts = () => {
715
+ if (posts.isPending) {
716
+ return <p>Loading...</p>;
717
+ }
718
+
719
+ if (posts.error) {
720
+ return <p>Error: {posts.error}</p>;
721
+ }
722
+
723
+ return posts.data.map((post) => (
724
+ <article key={post.id}>{post.title}</article>
725
+ ));
726
+ };
583
727
 
584
728
  return () => (
585
729
  <div>
586
730
  <button onClick={() => posts.fetch()}>Refresh</button>
587
731
  <button onClick={() => posts.fetch(true)}>Force Refresh</button>
588
-
589
- {posts.isPending && <p>Loading...</p>}
590
- {posts.error && <p>Error: {posts.error}</p>}
591
- {posts.data &&
592
- posts.data.map((post) => <article key={post.id}>{post.title}</article>)}
732
+ {renderPosts()}
593
733
  </div>
594
734
  );
595
735
  }
@@ -630,7 +770,7 @@ function CreatePost() {
630
770
  fetch("/api/posts", {
631
771
  method: "POST",
632
772
  body: JSON.stringify(data),
633
- }).then((r) => r.json())
773
+ }))
634
774
  );
635
775
 
636
776
  const handleSubmit = () => {
@@ -768,7 +908,9 @@ Keys prevent component recreation when list order changes.
768
908
 
769
909
  ### Computed Values
770
910
 
771
- Create computed values using functions in setup:
911
+ You can create computed values in two ways:
912
+
913
+ **1. Simple computed functions** - For basic derived values:
772
914
 
773
915
  ```tsx
774
916
  function ShoppingCart() {
@@ -799,6 +941,49 @@ function ShoppingCart() {
799
941
 
800
942
  Computed functions automatically track dependencies when called during render.
801
943
 
944
+ **2. Using `createComputed`** - For cached, efficient computed values with automatic dependency tracking:
945
+
946
+ ```tsx
947
+ function ShoppingCart() {
948
+ const state = createState({
949
+ items: [
950
+ { id: 1, price: 10, quantity: 2 },
951
+ { id: 2, price: 20, quantity: 1 },
952
+ ],
953
+ taxRate: 0.1,
954
+ });
955
+
956
+ const computed = createComputed({
957
+ subtotal: () =>
958
+ state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
959
+ tax: () => computed.subtotal * state.taxRate,
960
+ total: () => computed.subtotal + computed.tax,
961
+ });
962
+
963
+ return () => (
964
+ <div>
965
+ <ul>
966
+ {state.items.map((item) => (
967
+ <li key={item.id}>
968
+ ${item.price} x {item.quantity}
969
+ </li>
970
+ ))}
971
+ </ul>
972
+ <p>Subtotal: ${computed.subtotal}</p>
973
+ <p>Tax: ${computed.tax}</p>
974
+ <p>Total: ${computed.total}</p>
975
+ </div>
976
+ );
977
+ }
978
+ ```
979
+
980
+ Benefits of `createComputed`:
981
+
982
+ - **Cached** - Only recalculates when dependencies change
983
+ - **Lazy** - Only calculates when accessed
984
+ - **Composable** - Computed properties can depend on other computed properties
985
+ - **Efficient** - Better performance for expensive calculations
986
+
802
987
  ### Composition
803
988
 
804
989
  Compose complex logic by combining state and methods using `createView`:
@@ -945,21 +1130,6 @@ function TodoList() {
945
1130
  }
946
1131
  ```
947
1132
 
948
- ## Configuration
949
-
950
- ### JSX Setup
951
-
952
- Configure TypeScript to use RASK's JSX runtime:
953
-
954
- ```json
955
- {
956
- "compilerOptions": {
957
- "jsx": "react-jsx",
958
- "jsxImportSource": "rask-ui"
959
- }
960
- }
961
- ```
962
-
963
1133
  ## Performance
964
1134
 
965
1135
  RASK is designed for performance:
@@ -0,0 +1,7 @@
1
+ export type QueuedCallback = (() => void) & {
2
+ __queued: boolean;
3
+ };
4
+ export declare function queue(cb: QueuedCallback): void;
5
+ export declare function syncBatch(cb: () => void): void;
6
+ export declare function installEventBatching(target?: EventTarget): void;
7
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAwClE,wBAAgB,KAAK,CAAC,EAAE,EAAE,cAAc,QAYvC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAavC;AAED,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,WAAsB,QA4BlE"}
package/dist/batch.js ADDED
@@ -0,0 +1,107 @@
1
+ const INTERACTIVE_EVENTS = [
2
+ // DISCRETE
3
+ "beforeinput",
4
+ "input",
5
+ "change",
6
+ "compositionend",
7
+ "keydown",
8
+ "keyup",
9
+ "click",
10
+ "contextmenu",
11
+ "submit",
12
+ "reset",
13
+ // GESTURE START
14
+ "pointerdown",
15
+ "mousedown",
16
+ "touchstart",
17
+ // GESTURE END
18
+ "pointerup",
19
+ "mouseup",
20
+ "touchend",
21
+ "touchcancel",
22
+ ];
23
+ const asyncQueue = [];
24
+ const syncQueue = [];
25
+ let inInteractive = 0;
26
+ let asyncScheduled = false;
27
+ let inSyncBatch = 0;
28
+ function scheduleAsyncFlush() {
29
+ if (asyncScheduled)
30
+ return;
31
+ asyncScheduled = true;
32
+ queueMicrotask(flushAsyncQueue);
33
+ }
34
+ function flushAsyncQueue() {
35
+ asyncScheduled = false;
36
+ if (!asyncQueue.length)
37
+ return;
38
+ for (let i = 0; i < asyncQueue.length; i++) {
39
+ const cb = asyncQueue[i];
40
+ asyncQueue[i] = undefined;
41
+ cb();
42
+ cb.__queued = false;
43
+ }
44
+ asyncQueue.length = 0;
45
+ }
46
+ function flushSyncQueue() {
47
+ if (!syncQueue.length)
48
+ return;
49
+ for (let i = 0; i < syncQueue.length; i++) {
50
+ const cb = syncQueue[i];
51
+ syncQueue[i] = undefined;
52
+ cb();
53
+ cb.__queued = false;
54
+ }
55
+ syncQueue.length = 0;
56
+ }
57
+ export function queue(cb) {
58
+ cb.__queued = true;
59
+ if (inSyncBatch) {
60
+ syncQueue.push(cb);
61
+ return;
62
+ }
63
+ asyncQueue.push(cb);
64
+ if (!inInteractive) {
65
+ scheduleAsyncFlush();
66
+ }
67
+ }
68
+ export function syncBatch(cb) {
69
+ inSyncBatch++;
70
+ try {
71
+ cb();
72
+ // Only flush on successful completion
73
+ inSyncBatch--;
74
+ if (!inSyncBatch) {
75
+ flushSyncQueue();
76
+ }
77
+ }
78
+ catch (e) {
79
+ inSyncBatch--;
80
+ throw e; // Re-throw without flushing
81
+ }
82
+ }
83
+ export function installEventBatching(target = document) {
84
+ const captureOptions = {
85
+ capture: true,
86
+ passive: true,
87
+ };
88
+ const bubbleOptions = { passive: true };
89
+ const onCapture = () => {
90
+ inInteractive++;
91
+ scheduleAsyncFlush(); // backup in case of stopPropagation
92
+ };
93
+ const onBubble = () => {
94
+ if (--inInteractive === 0 && asyncQueue.length) {
95
+ // Flush inline once outermost interactive event finishes
96
+ flushAsyncQueue();
97
+ }
98
+ };
99
+ INTERACTIVE_EVENTS.forEach((type) => {
100
+ target.addEventListener(type, onCapture, captureOptions);
101
+ });
102
+ queueMicrotask(() => {
103
+ INTERACTIVE_EVENTS.forEach((type) => {
104
+ target.addEventListener(type, onBubble, bubbleOptions);
105
+ });
106
+ });
107
+ }
@@ -10,6 +10,10 @@ declare class RaskComponent<P extends Props<any>> extends Component<P & {
10
10
  private reactiveProps?;
11
11
  private observer;
12
12
  private isRendering;
13
+ effects: Array<{
14
+ isDirty: boolean;
15
+ run: () => void;
16
+ }>;
13
17
  contexts: Map<any, any>;
14
18
  getChildContext(): any;
15
19
  onMounts: Array<() => void>;
@@ -17,7 +21,11 @@ declare class RaskComponent<P extends Props<any>> extends Component<P & {
17
21
  private createReactiveProps;
18
22
  componentDidMount(): void;
19
23
  componentWillUnmount(): void;
20
- componentDidUpdate(): void;
24
+ /**
25
+ *
26
+ */
27
+ componentWillUpdate(nextProps: any): void;
28
+ componentWillReceiveProps(): void;
21
29
  shouldComponentUpdate(nextProps: Props<any>): boolean;
22
30
  render(): any;
23
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,EACL,SAAS,EACT,KAAK,EAEN,MAAM,SAAS,CAAC;AAMjB,wBAAgB,mBAAmB,uBAMlC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAMrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAMvC;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,IAClD,CAAC,MAAM,MAAM,KAAK,CAAC,GACnB,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC;AAEhC,cAAM,aAAa,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,CAAE,SAAQ,SAAS,CACzD,CAAC,GAAG;IAAE,WAAW,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAA;CAAE,CAC9C;IACC,OAAO,CAAC,QAAQ,CAAC,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,QAAQ,CAEb;IACH,OAAO,CAAC,WAAW,CAAS;IAC5B,QAAQ,gBAAa;IACrB,eAAe;IAUf,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACjC,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACnC,OAAO,CAAC,mBAAmB;IAgC3B,iBAAiB,IAAI,IAAI;IAGzB,oBAAoB,IAAI,IAAI;IAG5B,kBAAkB;IAUlB,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAerD,MAAM;CAyCP;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,SAO9D"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,EACL,SAAS,EACT,KAAK,EAEN,MAAM,SAAS,CAAC;AAQjB,wBAAgB,mBAAmB,uBAMlC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,QAMrC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,QAMvC;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,IAClD,CAAC,MAAM,MAAM,KAAK,CAAC,GACnB,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC;AAEhC,cAAM,aAAa,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,CAAE,SAAQ,SAAS,CACzD,CAAC,GAAG;IAAE,WAAW,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAA;CAAE,CAC9C;IACC,OAAO,CAAC,QAAQ,CAAC,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,QAAQ,CAEb;IACH,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAM;IAC3D,QAAQ,gBAAa;IACrB,eAAe;IAUf,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACjC,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACnC,OAAO,CAAC,mBAAmB;IA4D3B,iBAAiB,IAAI,IAAI;IAGzB,oBAAoB,IAAI,IAAI;IAG5B;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,GAAG;IAYlC,yBAAyB,IAAI,IAAI;IACjC,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAerD,MAAM;CAyCP;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,SAO9D"}