@solidrt/core 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/core",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "license": "MIT",
5
5
  "author": "Antoine van Wel",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  "colord": "^2.9.3"
21
21
  },
22
22
  "devDependencies": {
23
- "@solidrt/flux-types": "0.0.7"
23
+ "@solidrt/flux-types": "0.0.9"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@solidjs/signals": "2.0.0-beta.14",
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./renderer"
2
2
  export { setFocus, getFocusedNodeId, measureText, getBoundingBox } from "./core"
3
3
  export type { BoundingBox } from "./core"
4
- export { onFrame, createPacedClock, onLayout, onResize, onWindowFocus, onWindowBlur } from "./window"
4
+ export { onFrame, onLayout, onResize, onWindowFocus, onWindowBlur } from "./window"
5
5
  export { createTexture, decodeImage } from "./gpu"
6
6
  export type { DecodedImage } from "./gpu"
7
7
  export type {
package/src/types.d.ts CHANGED
@@ -3,6 +3,15 @@
3
3
  import type { JSX as SolidJSX } from "@solidjs/signals"
4
4
 
5
5
  declare global {
6
+ function requestAnimationFrame(callback: (time: number) => void): number
7
+ function cancelAnimationFrame(id: number): void
8
+
9
+ // UI event bus (lattice). on/once return an unsubscribe function.
10
+ let srt: {
11
+ on(event: string, callback: (data: any) => void): () => void
12
+ once(event: string, callback: (data: any) => void): () => void
13
+ }
14
+
6
15
  let ffi: {
7
16
  createRoot(id: number): void
8
17
  createNode(id: number, kind: string): void
package/src/window.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { onCleanup, onSettled, flush, createSignal } from "@solidjs/signals"
1
+ import { onCleanup, onSettled, flush } from "@solidjs/signals"
2
2
  import { getEventHandler, getFocusedNodeId, setFocus } from "./core"
3
3
 
4
4
  // ------ Animation frames ----------------
@@ -11,10 +11,12 @@ let animationFrames = new Map<number, Function>()
11
11
  let refreshRate = 60
12
12
 
13
13
  /**
14
- * Calls `fn` before every frame is painted, with the raw runtime signals: `tick`
15
- * is the unsmoothed wall-clock time in ms sampled at present, `frame` is the
16
- * present count, and `rate` is the current refresh rate in Hz. No pacing is
17
- * applied; see createPacedClock for an opt-in smooth clock.
14
+ * Calls `fn` before every frame is painted: `tick` is the time in ms, `frame` is
15
+ * the present count, and `rate` is the current refresh rate in Hz. `tick` is paced
16
+ * by the runtime (one refresh period per present, slow-corrected toward the wall
17
+ * clock) so animations driven off it stay smooth even when swap-return times
18
+ * jitter. For raw, continuous wall-clock time (e.g. measuring code), use
19
+ * performance.now() instead.
18
20
  * Returns a cleanup function; also auto-cleans within a reactive scope.
19
21
  */
20
22
  export function onFrame(fn: (tick: number, frame: number, rate: number) => void) {
@@ -34,26 +36,6 @@ export function onFrame(fn: (tick: number, frame: number, rate: number) => void)
34
36
  return cleanup
35
37
  }
36
38
 
37
- /**
38
- * Opt-in smooth clock built on the raw onFrame signals. Paces by present count
39
- * (one refresh period per frame) and slowly corrects toward the raw wall-clock
40
- * tick, so it stays smooth while keeping up and tracks real time when the
41
- * framerate drops. `gain` (0..1) trades convergence speed for jitter. Returns an
42
- * accessor for the paced time in milliseconds.
43
- */
44
- export function createPacedClock(opts?: { gain?: number }) {
45
- let gain = opts?.gain ?? 0.05
46
- let [time, setTime] = createSignal(0)
47
- let clock = 0
48
- onFrame((tick, _frame, rate) => {
49
- let period = 1000 / rate
50
- clock += period
51
- clock += (tick - clock) * gain
52
- setTime(clock)
53
- })
54
- return time
55
- }
56
-
57
39
  // ------ Resize ----------------
58
40
 
59
41
  interface SafeArea {
@@ -71,7 +53,7 @@ interface ResizeEvent {
71
53
  }
72
54
 
73
55
  export function onResize(fn: (data: ResizeEvent) => void) {
74
- let unsubscribe = Flux.on("resize", fn)
56
+ let unsubscribe = srt.on("resize", fn)
75
57
  onCleanup(unsubscribe)
76
58
  return unsubscribe
77
59
  }
@@ -81,19 +63,19 @@ export function onResize(fn: (data: ResizeEvent) => void) {
81
63
  // by a re-layout pass before painting (one extra pass; cascades beyond that
82
64
  // paint stale).
83
65
  export function onLayout(fn: () => void) {
84
- let unsubscribe = Flux.on("postLayout", fn)
66
+ let unsubscribe = srt.on("postLayout", fn)
85
67
  onCleanup(unsubscribe)
86
68
  return unsubscribe
87
69
  }
88
70
 
89
71
  export function onWindowFocus(fn: () => void) {
90
- let unsubscribe = Flux.on("windowFocus", fn)
72
+ let unsubscribe = srt.on("windowFocus", fn)
91
73
  onCleanup(unsubscribe)
92
74
  return unsubscribe
93
75
  }
94
76
 
95
77
  export function onWindowBlur(fn: () => void) {
96
- let unsubscribe = Flux.on("windowBlur", fn)
78
+ let unsubscribe = srt.on("windowBlur", fn)
97
79
  onCleanup(unsubscribe)
98
80
  return unsubscribe
99
81
  }
@@ -127,15 +109,15 @@ export function attachWindow(_nodeId: number) {
127
109
 
128
110
  onSettled(() => {
129
111
  // Sticky event: a late subscriber still receives the current rate.
130
- unsubRefreshRate = Flux.on("displayRefreshRate", ({ hz }: { hz: number }) => {
112
+ unsubRefreshRate = srt.on("displayRefreshRate", ({ hz }: { hz: number }) => {
131
113
  if (hz > 0) refreshRate = hz
132
114
  })
133
115
 
134
- unsubscribe = Flux.on("render", ({ time, frame }: { time: number; frame: number }) => {
116
+ unsubscribe = srt.on("render", ({ time, frame }: { time: number; frame: number }) => {
135
117
  runFrame(time * 1000, frame)
136
118
  })
137
119
 
138
- unsubDown = Flux.on(
120
+ unsubDown = srt.on(
139
121
  "pointerDown",
140
122
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
141
123
  for (let nodeId of targets) {
@@ -150,13 +132,13 @@ export function attachWindow(_nodeId: number) {
150
132
  },
151
133
  )
152
134
 
153
- unsubUp = Flux.on("pointerUp", ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
135
+ unsubUp = srt.on("pointerUp", ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
154
136
  for (let nodeId of targets) {
155
137
  getEventHandler(nodeId, "onPointerUp")?.(e)
156
138
  }
157
139
  })
158
140
 
159
- unsubMove = Flux.on(
141
+ unsubMove = srt.on(
160
142
  "pointerMove",
161
143
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
162
144
  for (let nodeId of targets) {
@@ -165,7 +147,7 @@ export function attachWindow(_nodeId: number) {
165
147
  },
166
148
  )
167
149
 
168
- unsubEnter = Flux.on(
150
+ unsubEnter = srt.on(
169
151
  "pointerEnter",
170
152
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
171
153
  for (let nodeId of targets) {
@@ -174,7 +156,7 @@ export function attachWindow(_nodeId: number) {
174
156
  },
175
157
  )
176
158
 
177
- unsubLeave = Flux.on(
159
+ unsubLeave = srt.on(
178
160
  "pointerLeave",
179
161
  ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
180
162
  for (let nodeId of targets) {
@@ -183,27 +165,27 @@ export function attachWindow(_nodeId: number) {
183
165
  },
184
166
  )
185
167
 
186
- unsubWheel = Flux.on("wheel", ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
168
+ unsubWheel = srt.on("wheel", ({ targets, ...e }: { targets: number[]; [k: string]: any }) => {
187
169
  for (let nodeId of targets) {
188
170
  getEventHandler(nodeId, "onWheel")?.(e)
189
171
  }
190
172
  })
191
173
 
192
- unsubKeyDown = Flux.on("keydown", (e: any) => {
174
+ unsubKeyDown = srt.on("keydown", (e: any) => {
193
175
  let id = getFocusedNodeId()
194
176
  if (id != null) {
195
177
  getEventHandler(id, "onKeyDown")?.(e)
196
178
  }
197
179
  })
198
180
 
199
- unsubKeyUp = Flux.on("keyup", (e: any) => {
181
+ unsubKeyUp = srt.on("keyup", (e: any) => {
200
182
  let id = getFocusedNodeId()
201
183
  if (id != null) {
202
184
  getEventHandler(id, "onKeyUp")?.(e)
203
185
  }
204
186
  })
205
187
 
206
- unsubTextInput = Flux.on("textInput", (e: any) => {
188
+ unsubTextInput = srt.on("textInput", (e: any) => {
207
189
  let id = getFocusedNodeId()
208
190
  if (id != null) {
209
191
  getEventHandler(id, "onTextInput")?.(e)
@@ -212,7 +194,7 @@ export function attachWindow(_nodeId: number) {
212
194
 
213
195
  // When the user dismisses the on-screen keyboard (swipe down, "Done",
214
196
  // back button), blur the focused node so the app's UI state catches up.
215
- unsubKeyboardVisibility = Flux.on("keyboardVisibility", ({ shown }: { shown: boolean }) => {
197
+ unsubKeyboardVisibility = srt.on("keyboardVisibility", ({ shown }: { shown: boolean }) => {
216
198
  if (!shown) setFocus(null)
217
199
  })
218
200
 
@@ -223,7 +205,7 @@ export function attachWindow(_nodeId: number) {
223
205
  // synchronously here, while we are still inside this onSettled callback
224
206
  // where flush() is illegal (not reentrant). Defer runFrame to a microtask
225
207
  // so the first frame always runs after this callback returns.
226
- unsubFirstResize = Flux.once("resize", () => {
208
+ unsubFirstResize = srt.once("resize", () => {
227
209
  queueMicrotask(() => runFrame(0, 0))
228
210
  })
229
211
  })