@tur-ng/std 0.0.7 → 0.0.9

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 (2) hide show
  1. package/package.json +4 -1
  2. package/src/index.d.ts +54 -37
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tur-ng/std",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "types": "src/index.d.ts",
6
6
  "files": [
@@ -14,5 +14,8 @@
14
14
  "type": "git",
15
15
  "url": "git+https://github.com/hpp2334/tur.git",
16
16
  "directory": "js/packages/tur-std"
17
+ },
18
+ "dependencies": {
19
+ "@tur-ng/core": "0.0.7"
17
20
  }
18
21
  }
package/src/index.d.ts CHANGED
@@ -18,13 +18,17 @@
18
18
  * substrate may import directly from `tur:core`.
19
19
  */
20
20
 
21
+ /// <reference types="@tur-ng/core" />
22
+
21
23
  declare module "tur:std" {
22
24
  // Re-export the reactive core (source/derive/mutate/get/set/view/mount,
23
25
  // Element/Source/Derived/Mutation/Readable/Val, ReadonlyStoreCtx/StoreCtx).
24
26
  export * from "tur:core";
25
27
 
26
- // Core meta-types used by the prop interfaces below.
27
- import type { Element, Mutation, Readable, Val } from "tur:core";
28
+ // Core meta-types used by the prop interfaces below. (`export *` alone
29
+ // re-exports but does not bind names locally every core type used in
30
+ // this module body must also appear here.)
31
+ import type { Derived, Element, Mutation, Readable, Val } from "tur:core";
28
32
 
29
33
  // ---------------------------------------------------------------------------
30
34
  // Value types — Color / LinearGradient / Brush / SpanData
@@ -87,9 +91,10 @@ declare module "tur:std" {
87
91
  }
88
92
 
89
93
  /** Engine-owned reactive atom holding the live canvas size
90
- * (`{width, height}` in CSS pixels). Updated each frame from the resize
91
- * handler; import from `tur:std`. Read-only to app code typed as a
92
- * `Derived` so `set(viewportSize$, …)` is rejected at compile time. */
94
+ * (`{width, height}` in CSS pixels). Published by the engine on every
95
+ * resize (readable through any store of the instance); import from
96
+ * `tur:std`. Read-only to app code typed as a `Derived` so
97
+ * `set(viewportSize$, …)` is rejected at compile time. */
93
98
  export const viewportSize$: Derived<ViewportSize>;
94
99
 
95
100
  /** OS cursor keywords (CSS cursor names). Mirrors `tur_engine::core::platform::Cursor`. */
@@ -583,43 +588,55 @@ declare module "tur:std" {
583
588
  }
584
589
 
585
590
  // ---------------------------------------------------------------------------
586
- // Async task primitives — `sleep` (a timer primitive) + `launch` (a
587
- // cancellable generator coroutine driver). These replace the old
588
- // `setTimeout` / `setInterval` globals.
591
+ // Async task primitives — the `Task<T>` handle, `sleep`, `CancelError`,
592
+ // and `isCancelError`. These replace the old `setTimeout` /
593
+ // `setInterval` globals (and the former `launch` generator driver):
594
+ // async composition is plain `async`/`await` + `.then`, cancellation is
595
+ // per-operation via the Task handle.
589
596
  // ---------------------------------------------------------------------------
590
597
 
591
- /** Resolve after `ms` milliseconds (engine time). The engine's frame loop
592
- * wakes precisely at the deadline. Use bare (`sleep(ms).then(...)`) or
593
- * inside a `launch` coroutine via `yield sleep(ms)`. */
594
- export function sleep(ms: number): Promise<void>;
595
-
596
- /** A cancellable coroutine task returned by `launch`. `cancel()` stops the
597
- * generator from resuming after its current `yield`. Any in-flight
598
- * `sleep` resolves harmlessly and is ignored. */
599
- export interface Task {
598
+ /** The handle every async engine API returns: `sleep`, `request`,
599
+ * `requestStream`, `clipboard.readText`/`writeText`,
600
+ * `filePicker.pick`/`saveFile`,
601
+ *
602
+ * - `promise` settles with the operation's result.
603
+ * - `cancel()` stops the operation where stoppable (a pending `sleep`
604
+ * timer is really cleared; an unpolled HTTP request is never sent;
605
+ * an in-flight one is discarded; a stream is wire-aborted) and
606
+ * **rejects `promise` with a `CancelError`**. Idempotent; a no-op
607
+ * for the promise once settled (op-specific abort still runs — e.g.
608
+ * cancelling a stream mid-consumption).
609
+ *
610
+ * Debounce idiom (the no-op rejection handler IS the cancelled
611
+ * branch):
612
+ * ```ts
613
+ * t?.cancel(); t = sleep(300);
614
+ * t.promise.then(show, () => {});
615
+ * ```
616
+ *
617
+ * Loop stop idiom: cancel the awaited sleep; the `await` throws
618
+ * `CancelError`; `catch (e) { if (isCancelError(e)) return; throw e; }`
619
+ * exits the loop. */
620
+ export interface Task<T> {
621
+ readonly promise: Promise<T>;
600
622
  cancel(): void;
601
623
  }
602
624
 
603
- /** Run a zero-arg generator function as a cancellable coroutine. The
604
- * generator must `yield` Promises (typically `sleep(ms)`); each resolved
605
- * promise resumes the generator, passing the resolved value back as the
606
- * `yield` result. Returns a `Task` whose `cancel()` halts further
607
- * resumption.
608
- *
609
- * Rejections: when a yielded promise rejects, the rejection reason is
610
- * thrown into the generator at the `yield` point so a `try/catch`
611
- * around `yield` catches it (the same ergonomics as `await`). An uncaught
612
- * rejection stops the coroutine. This makes `launch` safe to use with
613
- * fallible Promises (`clipboard.readText`, `http`, `fetch`), not just
614
- * `sleep`.
615
- *
616
- * Unlike `async`/`await`, generators can be externally stepped/abandoned,
617
- * which is what makes real cancellation possible. Use the debounce
618
- * pattern: `task?.cancel(); task = launch(function* () { yield sleep(ms);
619
- * ... });`. */
620
- export function launch<T>(
621
- gen: () => Generator<Promise<unknown>, T, unknown>,
622
- ): Task;
625
+ /** The rejection reason produced by `Task.cancel()` an `Error` whose
626
+ * `name` is `"CancelError"`. Test with `isCancelError` (or
627
+ * `e.name === "CancelError"`). */
628
+ export interface CancelError extends Error {
629
+ name: "CancelError";
630
+ }
631
+
632
+ /** `true` when `reason` is the rejection produced by `Task.cancel()`. */
633
+ export function isCancelError(reason: unknown): reason is CancelError;
634
+
635
+ /** Sleep for `ms` milliseconds (engine time) the engine's frame loop
636
+ * wakes precisely at the deadline. Returns a `Task<void>`: await
637
+ * `sleep(ms).promise`, and `cancel()` to clear the timer (the promise
638
+ * then rejects with a `CancelError`). */
639
+ export function sleep(ms: number): Task<void>;
623
640
 
624
641
  // ---------------------------------------------------------------------------
625
642
  // Element factories