@solidrt/core 0.0.35 → 0.0.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/core",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "license": "MIT",
5
5
  "author": "Antoine van Wel",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "colord": "^2.9.3"
28
28
  },
29
29
  "devDependencies": {
30
- "@solidrt/flux-types": "0.0.35"
30
+ "@solidrt/flux-types": "0.0.36"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@solidjs/signals": "2.0.0-beta.20",
package/src/core.ts CHANGED
@@ -64,16 +64,27 @@ export interface BoundingBox {
64
64
  }
65
65
 
66
66
  /**
67
- * Returns the node's window-relative bounding box from the most recently
68
- * computed layout, or `null` if the node has no layout or has not been laid out
69
- * yet. This is a snapshot read, not reactive: call it inside `onLayout` (or an
70
- * event handler) to get values for the current frame. Phase 1 composes only
71
- * translations; x/y are wrong when a rotate/scale sits anywhere above the node.
67
+ * Returns the node's bounding box from the most recently computed layout,
68
+ * relative to its nearest positioning context (an ancestor with an explicit
69
+ * `position="relative"`, falling back to the window), or `null` if the node
70
+ * has no layout or has not been laid out yet. This is a snapshot read, not
71
+ * reactive: call it inside `onLayout` (or an event handler) to get values for
72
+ * the current frame. Transforms anywhere in the chain (including the node's
73
+ * own) compose fully; the box is the axis-aligned bounds of the transformed
74
+ * quad.
72
75
  */
73
76
  export function getBoundingBox(node: { id: number }): BoundingBox | null {
74
77
  return tree.getBoundingBox(node.id)
75
78
  }
76
79
 
80
+ /**
81
+ * Like getBoundingBox, but always window-relative (getBoundingClientRect
82
+ * semantics), the frame pointer event clientX/clientY are reported in.
83
+ */
84
+ export function getBoundingBoxViewport(node: { id: number }): BoundingBox | null {
85
+ return tree.getBoundingBoxViewport(node.id)
86
+ }
87
+
77
88
  /**
78
89
  * Measures the rendered size of `text` in layout pixels under the given font
79
90
  * options (family, size, weight, style, maxLines), without adding it to the
package/src/index.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  export * from "./renderer"
2
- export { setFocus, getFocusedNodeId, measureText, getBoundingBox } from "./core"
2
+ export { setFocus, getFocusedNodeId, measureText, getBoundingBox, getBoundingBoxViewport } from "./core"
3
3
  export type { BoundingBox } from "./core"
4
4
  export { parseColor, mixColors, brightness, createLinearGradient, createRadialGradient } from "./color"
5
5
  export type { Gradient, GradientStop } from "./color"
6
6
  export { onFrame, onLayout, onResize, onWindowFocus, onWindowBlur } from "./window"
7
- export { setPointerCapture, releasePointerCapture } from "./window"
8
7
  export { windowSize, safeArea, displayScale, windowFocused, keyboardHeight } from "./window"
9
8
  export { env } from "./environment"
10
9
  export type { InputDevices, SystemTheme, Orientation } from "./environment"
@@ -67,14 +67,19 @@ declare module "srt:apps" {
67
67
  export type AppVersion = { id: string; size: number; current: boolean }
68
68
  /** One file in a listing: a relative path and its size in bytes. */
69
69
  export type AppFile = { path: string; size: number }
70
+ /**
71
+ * One fetch-cache entry: the cached (resolved) url, the response content
72
+ * type (lowercased, parameters stripped; absent when the response had
73
+ * none) and the entry's size on disk.
74
+ */
75
+ export type AppCacheEntry = { url: string; type?: string; size: number }
70
76
  /**
71
77
  * Usage details for one installed app: total bytes of its stored versions
72
- * (assets shared between versions via hardlinks count in each) and of its
73
- * data sandbox, plus the stored versions (current first, then newest first)
74
- * and three file listings, each sorted by path. `assets` is the current
75
- * version's manifest claim (declared sizes); `files` and `data` are disk
76
- * walks of the current version dir and the data sandbox - the truth, so a
77
- * divergence from the manifest is visible.
78
+ * (assets shared between versions via hardlinks count in each), of its
79
+ * data sandbox and of its fetch cache, plus the stored versions (current
80
+ * first, then newest first) and three listings: `files` and `data` are
81
+ * disk walks of the current version dir and the data sandbox (sorted by
82
+ * path), `cache` is the fetch cache's entries (sorted by url).
78
83
  */
79
84
  export type AppInfo = {
80
85
  id: string
@@ -82,10 +87,11 @@ declare module "srt:apps" {
82
87
  version: string
83
88
  installSize: number
84
89
  dataSize: number
90
+ cacheSize: number
85
91
  versions: AppVersion[]
86
- assets: AppFile[]
87
92
  files: AppFile[]
88
93
  data: AppFile[]
94
+ cache: AppCacheEntry[]
89
95
  }
90
96
  /** Usage details for an installed app. Throws when the app is not installed. */
91
97
  export function info(id: string): AppInfo
@@ -100,6 +106,22 @@ declare module "srt:apps" {
100
106
  * the app is not installed.
101
107
  */
102
108
  export function remove(id: string): void
109
+ /**
110
+ * Delete the app's fetch cache. Clearing a missing or empty cache is a
111
+ * no-op; the id does not need to be installed, so a removed app's
112
+ * leftover cache is still clearable.
113
+ */
114
+ export function clearCache(id: string): void
115
+ /**
116
+ * Build identity of this runtime, for the launcher's settings screen. Not
117
+ * app-specific, but surfaced here since the launcher already imports this
118
+ * module. `version` is the release version (git describe; "0.0.0-dev" in a
119
+ * plain build), `profile` is "debug" or "release", `platform` is the OS
120
+ * (std::env::consts::OS, e.g. "linux", "android", "windows", "macos").
121
+ */
122
+ export const version: string
123
+ export const profile: string
124
+ export const platform: string
103
125
  }
104
126
 
105
127
  // Frame draw (lattice runner). renderFrame() synchronously renders the current
package/src/window.ts CHANGED
@@ -5,27 +5,17 @@ import { on, once } from "srt:events"
5
5
  import { getEventHandler, getFocusedNodeId, setFocus } from "./core"
6
6
  import { scanForOrphans } from "./renderer"
7
7
 
8
- // ------ Pointer capture -----------------
9
-
10
- // Active pointer captures, pointerId -> nodeId. While a pointer is captured, its
11
- // move/up events dispatch straight to the captured node (bypassing hit testing),
12
- // so a drag keeps working when the pointer drifts off the element. Modeled on the
13
- // web setPointerCapture; capture auto-releases on pointerUp.
14
- let pointerCaptures = new Map<number, number>()
15
-
16
- /**
17
- * Routes all further move/up events for `pointerId` to `nodeId` until release,
18
- * regardless of what is under the pointer. Call from a pointerdown handler to own
19
- * a drag (e.g. a slider). Auto-releases on the matching pointerup.
20
- */
21
- export function setPointerCapture(nodeId: number, pointerId: number) {
22
- pointerCaptures.set(pointerId, nodeId)
23
- }
24
-
25
- /** Ends a capture early. Not needed for the common case (pointerup releases it). */
26
- export function releasePointerCapture(pointerId: number) {
27
- pointerCaptures.delete(pointerId)
28
- }
8
+ // ------ Pointer routing -----------------
9
+
10
+ // Hit path frozen at pointerDown, pointerId -> targets. While a pointer has an
11
+ // active down, its moves and up dispatch along this path (same leaf-to-root
12
+ // bubble) no matter where the pointer currently is, so every node under the
13
+ // original down observes the whole gesture: a drag keeps working off-element,
14
+ // and an ancestor recognizer (a scroller's pan) sees the moves it needs to
15
+ // take over mid-gesture via the arena. There is no exclusive pointer capture;
16
+ // gesture ownership is claim-based, above this layer. Enter/leave stay
17
+ // hover-driven, and moves with no active down follow the live hit path.
18
+ let downPaths = new Map<number, number[]>()
29
19
 
30
20
  // ------ Animation frames ----------------
31
21
 
@@ -244,6 +234,7 @@ export function attachWindow(_nodeId: number) {
244
234
  unsubDown = on(
245
235
  "pointerDown",
246
236
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
237
+ downPaths.set(e.pointerId, targets)
247
238
  bubble(targets, "onPointerDown", e)
248
239
  // Outside-tap blur. Read focus AFTER per-node handlers so a tap that
249
240
  // moves focus to a new node is not immediately blurred again.
@@ -255,28 +246,15 @@ export function attachWindow(_nodeId: number) {
255
246
  )
256
247
 
257
248
  unsubUp = on("pointerUp", ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
258
- let captured = pointerCaptures.get(e.pointerId)
259
- if (captured != null) {
260
- // Deliver to the captured node, then release (web auto-release on up).
261
- e.stopPropagation = () => {}
262
- getEventHandler(captured, "onPointerUp")?.(e)
263
- pointerCaptures.delete(e.pointerId)
264
- return
265
- }
266
- bubble(targets, "onPointerUp", e)
249
+ let frozen = downPaths.get(e.pointerId)
250
+ downPaths.delete(e.pointerId)
251
+ bubble(frozen ?? targets, "onPointerUp", e)
267
252
  })
268
253
 
269
254
  unsubMove = on(
270
255
  "pointerMove",
271
256
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
272
- let captured = pointerCaptures.get(e.pointerId)
273
- if (captured != null) {
274
- // Captured drags get moves anywhere over the window, bypassing hit test.
275
- e.stopPropagation = () => {}
276
- getEventHandler(captured, "onPointerMove")?.(e)
277
- return
278
- }
279
- bubble(targets, "onPointerMove", e)
257
+ bubble(downPaths.get(e.pointerId) ?? targets, "onPointerMove", e)
280
258
  },
281
259
  )
282
260