@geastack/core 0.1.41 → 0.1.43
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/README.md +36 -9
- package/events.cpp +11 -0
- package/gea_app_entry.cpp +4 -0
- package/gea_sources.mjs +12 -2
- package/gea_sources.sh +6 -1
- package/include/canvas.h +1 -0
- package/include/display.h +1 -0
- package/include/event_listener_options.h +26 -0
- package/include/events.h +109 -5
- package/include/gea/embedded.h +1 -0
- package/include/graphics/font.h +11 -0
- package/include/native_identity.h +65 -0
- package/include/platform/asset_bundle.h +71 -0
- package/include/platform/esp_now.h +113 -0
- package/include/platform/magnetometer.h +60 -0
- package/include/platform/uart.h +58 -0
- package/include/runtime.h +14 -0
- package/index.d.ts +183 -8
- package/package.json +5 -2
- package/runtime/host.ts +95 -0
- package/runtime-surface.ts +7 -0
- package/runtime.cpp +145 -16
- package/scripts/build-gea-vite-geatsc.mjs +27 -3
- package/scripts/gea-file-asset-bundle.mjs +82 -0
- package/scripts/gea-native-style-plugin.mjs +3 -1
- package/scripts/gea-vite-plugin-resolution.mjs +49 -0
- package/scripts/generate-gea-embedded-assets.mjs +20 -3
- package/scripts/generate-gea-embedded-fonts.mjs +25 -4
- package/scripts/tests/gea-vite-plugin-resolution.test.mjs +46 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <array>
|
|
3
|
+
#include <cstddef>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
|
|
6
|
+
namespace gea::platform::espnow {
|
|
7
|
+
struct Datagram {
|
|
8
|
+
std::array<std::uint8_t, 6> source{};
|
|
9
|
+
std::array<std::uint8_t, 1470> bytes{};
|
|
10
|
+
std::size_t size = 0;
|
|
11
|
+
std::int64_t receivedUs = 0;
|
|
12
|
+
int rssi = 0;
|
|
13
|
+
// Raw 32-bit receive clock in microseconds, not the esp_timer epoch. The
|
|
14
|
+
// SDK qualifies its precision only without modem/light sleep. Zero is a
|
|
15
|
+
// valid timestamp; absence of RX metadata is represented separately.
|
|
16
|
+
std::uint32_t radioTimestampUs = 0;
|
|
17
|
+
bool radioTimestampValid = false;
|
|
18
|
+
};
|
|
19
|
+
struct Statistics {
|
|
20
|
+
std::uint32_t sent = 0, failed = 0, received = 0, dropped = 0;
|
|
21
|
+
std::uint32_t maximumSendUs = 0;
|
|
22
|
+
// Last completed datagram, published before canSend() becomes true. The
|
|
23
|
+
// single sending task may read these after canSend() for its prior send.
|
|
24
|
+
std::uint64_t lastSendStartedUs = 0, lastSendCompletedUs = 0;
|
|
25
|
+
std::uint32_t lastSendRate = 0, lastSendStatus = 0;
|
|
26
|
+
// Optional diagnostic copy of the SDK callback's 24-byte Action MAC header.
|
|
27
|
+
// Validity is separate: zero fields are valid values, and Retry=0 does not
|
|
28
|
+
// prove that the hardware made only one transmission attempt.
|
|
29
|
+
std::uint16_t lastSendFrameControl = 0, lastSendDuration = 0,
|
|
30
|
+
lastSendSequenceControl = 0;
|
|
31
|
+
bool lastSendMacValid = false;
|
|
32
|
+
};
|
|
33
|
+
} // namespace gea::platform::espnow
|
|
34
|
+
extern "C" {
|
|
35
|
+
bool gea_espnow_open(int channel, int rate) __attribute__((weak));
|
|
36
|
+
void gea_espnow_close() __attribute__((weak));
|
|
37
|
+
bool gea_espnow_is_open() __attribute__((weak));
|
|
38
|
+
bool gea_espnow_can_send() __attribute__((weak));
|
|
39
|
+
bool gea_espnow_capture_tx_header(bool enabled) __attribute__((weak));
|
|
40
|
+
bool gea_espnow_set_max_tx_power(int quarterDbm) __attribute__((weak));
|
|
41
|
+
int gea_espnow_get_max_tx_power() __attribute__((weak));
|
|
42
|
+
bool gea_espnow_peer(const std::uint8_t *mac, const std::uint8_t *key)
|
|
43
|
+
__attribute__((weak));
|
|
44
|
+
int gea_espnow_send(const std::uint8_t *mac, const void *data, std::size_t size)
|
|
45
|
+
__attribute__((weak));
|
|
46
|
+
bool gea_espnow_receive(gea::platform::espnow::Datagram *)
|
|
47
|
+
__attribute__((weak));
|
|
48
|
+
void gea_espnow_wake() __attribute__((weak));
|
|
49
|
+
void gea_espnow_wait(unsigned ms) __attribute__((weak));
|
|
50
|
+
void gea_espnow_statistics(gea::platform::espnow::Statistics *)
|
|
51
|
+
__attribute__((weak));
|
|
52
|
+
}
|
|
53
|
+
namespace gea::platform::espnow {
|
|
54
|
+
class EspNow {
|
|
55
|
+
public:
|
|
56
|
+
// Channel zero borrows the running Wi-Fi radio without changing its channel.
|
|
57
|
+
// Otherwise claims an idle radio. Rate is 24/36/54 Mbps (OFDM), 65 (HT20
|
|
58
|
+
// MCS7), or 115 on ESP32-S31 (HE20 MCS9 short GI, nominal 114.7 Mbps).
|
|
59
|
+
// Unsupported rates/protocols fail; a borrowed radio is never reconfigured.
|
|
60
|
+
static bool open(int channel, int rate = 54) {
|
|
61
|
+
return gea_espnow_open && gea_espnow_open(channel, rate);
|
|
62
|
+
}
|
|
63
|
+
static bool isOpen() { return gea_espnow_is_open && gea_espnow_is_open(); }
|
|
64
|
+
static bool canSend() { return gea_espnow_can_send && gea_espnow_can_send(); }
|
|
65
|
+
// Native diagnostics only; default off and reset on radio close/open.
|
|
66
|
+
// Enable only on an owned radio. Copies metadata, never changes the frame.
|
|
67
|
+
static bool captureTxHeader(bool enabled) {
|
|
68
|
+
return gea_espnow_capture_tx_header &&
|
|
69
|
+
gea_espnow_capture_tx_header(enabled);
|
|
70
|
+
}
|
|
71
|
+
// Quarter-dBm cap, 8..84. Only an owned radio may be changed; the SDK
|
|
72
|
+
// quantizes the request. Read back the actual cap, or -1 if unavailable.
|
|
73
|
+
static bool setMaxTxPower(int quarterDbm) {
|
|
74
|
+
return gea_espnow_set_max_tx_power &&
|
|
75
|
+
gea_espnow_set_max_tx_power(quarterDbm);
|
|
76
|
+
}
|
|
77
|
+
static int getMaxTxPower() {
|
|
78
|
+
return gea_espnow_get_max_tx_power ? gea_espnow_get_max_tx_power() : -1;
|
|
79
|
+
}
|
|
80
|
+
static void close() {
|
|
81
|
+
if (gea_espnow_close)
|
|
82
|
+
gea_espnow_close();
|
|
83
|
+
}
|
|
84
|
+
static bool addPeer(const std::uint8_t *mac,
|
|
85
|
+
const std::uint8_t *key = nullptr) {
|
|
86
|
+
return gea_espnow_peer && gea_espnow_peer(mac, key);
|
|
87
|
+
}
|
|
88
|
+
// Copies one datagram; length on admission, zero when busy, -1 on error.
|
|
89
|
+
// MAC completion is NOT an application acknowledgement.
|
|
90
|
+
static int send(const std::uint8_t *mac, const void *bytes,
|
|
91
|
+
std::size_t size) {
|
|
92
|
+
return gea_espnow_send ? gea_espnow_send(mac, bytes, size) : -1;
|
|
93
|
+
}
|
|
94
|
+
static bool receive(Datagram &packet) {
|
|
95
|
+
return gea_espnow_receive && gea_espnow_receive(&packet);
|
|
96
|
+
}
|
|
97
|
+
// One native consumer. Wakes for RX or TX completion; never call from the UI.
|
|
98
|
+
static void wake() {
|
|
99
|
+
if (gea_espnow_wake)
|
|
100
|
+
gea_espnow_wake();
|
|
101
|
+
}
|
|
102
|
+
static void wait(unsigned ms) {
|
|
103
|
+
if (gea_espnow_wait)
|
|
104
|
+
gea_espnow_wait(ms);
|
|
105
|
+
}
|
|
106
|
+
static Statistics statistics() {
|
|
107
|
+
Statistics s{};
|
|
108
|
+
if (gea_espnow_statistics)
|
|
109
|
+
gea_espnow_statistics(&s);
|
|
110
|
+
return s;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
} // namespace gea::platform::espnow
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
|
|
7
|
+
namespace gea::platform::sensors {
|
|
8
|
+
struct MagnetometerReading {
|
|
9
|
+
// Compensated whole microtesla. BMM150 overflow sentinels are preserved;
|
|
10
|
+
// saturatedAxes identifies axes that must not be used as field strength.
|
|
11
|
+
std::int16_t x = 0, y = 0, z = 0;
|
|
12
|
+
bool valid = false;
|
|
13
|
+
std::uint8_t saturatedAxes = 0; // X=1, Y=2, Z=4.
|
|
14
|
+
std::uint64_t timestampUs = 0;
|
|
15
|
+
};
|
|
16
|
+
} // namespace gea::platform::sensors
|
|
17
|
+
|
|
18
|
+
extern "C" {
|
|
19
|
+
bool gea_magnetometer_open() __attribute__((weak));
|
|
20
|
+
void gea_magnetometer_close() __attribute__((weak));
|
|
21
|
+
unsigned gea_magnetometer_count() __attribute__((weak));
|
|
22
|
+
bool gea_magnetometer_read(unsigned,
|
|
23
|
+
gea::platform::sensors::MagnetometerReading *)
|
|
24
|
+
__attribute__((weak));
|
|
25
|
+
bool gea_magnetometer_read_all(gea::platform::sensors::MagnetometerReading *,
|
|
26
|
+
std::size_t) __attribute__((weak));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
namespace gea::platform::sensors {
|
|
30
|
+
class Magnetometer {
|
|
31
|
+
public:
|
|
32
|
+
// Idempotent. No bus or pins are claimed until open is called.
|
|
33
|
+
static bool open() {
|
|
34
|
+
return gea_magnetometer_open && gea_magnetometer_open();
|
|
35
|
+
}
|
|
36
|
+
static void close() {
|
|
37
|
+
if (gea_magnetometer_close)
|
|
38
|
+
gea_magnetometer_close();
|
|
39
|
+
}
|
|
40
|
+
static unsigned count() {
|
|
41
|
+
return gea_magnetometer_count ? gea_magnetometer_count() : 0;
|
|
42
|
+
}
|
|
43
|
+
static bool read(unsigned index, MagnetometerReading &sample) {
|
|
44
|
+
sample = {};
|
|
45
|
+
return gea_magnetometer_read && gea_magnetometer_read(index, &sample);
|
|
46
|
+
}
|
|
47
|
+
// Reads the board's sensors back-to-back under one driver lock, with a
|
|
48
|
+
// shared completion timestamp. This is not hardware-triggered sampling.
|
|
49
|
+
// False if capacity is insufficient or any sensor failed; inspect valid
|
|
50
|
+
// on individual readings. The output is cleared even when unsupported.
|
|
51
|
+
static bool readAll(MagnetometerReading *samples, std::size_t capacity) {
|
|
52
|
+
if (!samples)
|
|
53
|
+
return false;
|
|
54
|
+
for (std::size_t i = 0; i < capacity; ++i)
|
|
55
|
+
samples[i] = {};
|
|
56
|
+
return gea_magnetometer_read_all &&
|
|
57
|
+
gea_magnetometer_read_all(samples, capacity);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
} // namespace gea::platform::sensors
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstddef>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
|
|
6
|
+
// Target-owned implementation. Unsupported platforms report unavailable.
|
|
7
|
+
extern "C" {
|
|
8
|
+
bool gea_uart_open(int port, int tx, int rx, int baud, int rxBytes, int txBytes)
|
|
9
|
+
__attribute__((weak));
|
|
10
|
+
bool gea_uart_is_open(int port) __attribute__((weak));
|
|
11
|
+
void gea_uart_close(int port) __attribute__((weak));
|
|
12
|
+
int gea_uart_read(int port, void *bytes, std::size_t capacity)
|
|
13
|
+
__attribute__((weak));
|
|
14
|
+
int gea_uart_write(int port, const void *bytes, std::size_t length)
|
|
15
|
+
__attribute__((weak));
|
|
16
|
+
int gea_uart_available(int port) __attribute__((weak));
|
|
17
|
+
int gea_uart_writable(int port) __attribute__((weak));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
namespace gea::platform::uart {
|
|
21
|
+
struct Config {
|
|
22
|
+
int tx;
|
|
23
|
+
int rx;
|
|
24
|
+
int baudRate;
|
|
25
|
+
int rxBufferSize = 4096;
|
|
26
|
+
int txBufferSize = 4096;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class Uart {
|
|
30
|
+
public:
|
|
31
|
+
static bool open(int port, const Config &config) {
|
|
32
|
+
return gea_uart_open &&
|
|
33
|
+
gea_uart_open(port, config.tx, config.rx, config.baudRate,
|
|
34
|
+
config.rxBufferSize, config.txBufferSize);
|
|
35
|
+
}
|
|
36
|
+
static bool isOpen(int port) {
|
|
37
|
+
return gea_uart_is_open && gea_uart_is_open(port);
|
|
38
|
+
}
|
|
39
|
+
static void close(int port) {
|
|
40
|
+
if (gea_uart_close)
|
|
41
|
+
gea_uart_close(port);
|
|
42
|
+
}
|
|
43
|
+
// Nonblocking. -1 means unavailable/closed/error; 0 means no progress.
|
|
44
|
+
static int read(int port, void *bytes, std::size_t capacity) {
|
|
45
|
+
return gea_uart_read ? gea_uart_read(port, bytes, capacity) : -1;
|
|
46
|
+
}
|
|
47
|
+
// Enqueues the complete buffer, or returns 0 if it cannot fit yet.
|
|
48
|
+
static int write(int port, const void *bytes, std::size_t length) {
|
|
49
|
+
return gea_uart_write ? gea_uart_write(port, bytes, length) : -1;
|
|
50
|
+
}
|
|
51
|
+
static int available(int port) {
|
|
52
|
+
return gea_uart_available ? gea_uart_available(port) : -1;
|
|
53
|
+
}
|
|
54
|
+
static int writable(int port) {
|
|
55
|
+
return gea_uart_writable ? gea_uart_writable(port) : -1;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
} // namespace gea::platform::uart
|
package/include/runtime.h
CHANGED
|
@@ -67,6 +67,20 @@ public:
|
|
|
67
67
|
// calls it, so a target that does not care never sees a difference.
|
|
68
68
|
static bool boot(const RuntimeOptions &options);
|
|
69
69
|
|
|
70
|
+
// Pause UI event/frame callbacks at a safe event-loop boundary. A request
|
|
71
|
+
// made before boot is retained; uiPaused() becomes true only after boot and
|
|
72
|
+
// the current callback/frame (including its locks) have returned. Calls do
|
|
73
|
+
// not wait and may be made from another task. uiPaused() acknowledges the
|
|
74
|
+
// current request, so callers that need quiescence must wait for it.
|
|
75
|
+
//
|
|
76
|
+
// Paused input is discarded and gestures are reset. Resuming requests a fresh
|
|
77
|
+
// frame. Platform tickers, device control, native services and previously
|
|
78
|
+
// submitted display DMA keep running; this does not suspend any task. A
|
|
79
|
+
// headless build has no UI loop, so a pause is acknowledged immediately.
|
|
80
|
+
static void requestUiPause(bool paused);
|
|
81
|
+
static bool uiPauseRequested();
|
|
82
|
+
static bool uiPaused();
|
|
83
|
+
|
|
70
84
|
// Hands the runtime a block of internal RAM to hold for the display and free
|
|
71
85
|
// immediately before Display::init(). For an app whose native boot hook has
|
|
72
86
|
// a phase that must not see less RAM than it actually has, followed by one
|
package/index.d.ts
CHANGED
|
@@ -103,9 +103,20 @@ export interface GeaIntrinsicElements {
|
|
|
103
103
|
'virtual-list': NativeVirtualListProps
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
export interface WindowEventListenerOptions {
|
|
107
|
+
capture?: boolean
|
|
108
|
+
once?: boolean
|
|
109
|
+
}
|
|
110
|
+
export interface GeaWindowEventMap extends GeaEventMap {
|
|
111
|
+
blur: Event
|
|
112
|
+
resize: Event
|
|
113
|
+
}
|
|
114
|
+
/** Native app-window event authority. No global input posting or browser Window privileges. */
|
|
106
115
|
export interface GeaWindow {
|
|
107
116
|
readonly innerWidth: number
|
|
108
117
|
readonly innerHeight: number
|
|
118
|
+
addEventListener<K extends keyof GeaWindowEventMap>(type: K, listener: (event: GeaWindowEventMap[K]) => void, options?: boolean | WindowEventListenerOptions): void
|
|
119
|
+
removeEventListener<K extends keyof GeaWindowEventMap>(type: K, listener: (event: GeaWindowEventMap[K]) => void, options?: boolean | WindowEventListenerOptions): void
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
declare global {
|
|
@@ -140,6 +151,10 @@ declare global {
|
|
|
140
151
|
/** @gea-host-no-property-writes */
|
|
141
152
|
function requestAnimationFrame(callback: (timestampMs: int) => void): number
|
|
142
153
|
|
|
154
|
+
// Shares the native Promise-job FIFO; app replacement retires pending jobs.
|
|
155
|
+
/** @gea-host-no-property-writes */
|
|
156
|
+
function queueMicrotask(callback: () => void): void
|
|
157
|
+
|
|
143
158
|
// Native one-shot / repeating timers (gea::host::setTimeout/setInterval,
|
|
144
159
|
// engine/../host/include/host/timers.h), NOT Node's `NodeJS.Timeout` (there is
|
|
145
160
|
// no `dom` or `node` lib here, so without this declaration a `setTimeout`
|
|
@@ -339,6 +354,7 @@ export interface DataAttributes {
|
|
|
339
354
|
}
|
|
340
355
|
|
|
341
356
|
export interface Event {
|
|
357
|
+
readonly defaultPrevented: boolean
|
|
342
358
|
readonly type: string
|
|
343
359
|
readonly target: EventTarget
|
|
344
360
|
readonly currentTarget: EventTarget
|
|
@@ -354,12 +370,30 @@ export interface EventTarget {
|
|
|
354
370
|
addEventListener(type: string, listener: (event: Event) => void): void
|
|
355
371
|
}
|
|
356
372
|
|
|
373
|
+
/** Live child collection; iterable and bracket protocols are not published yet. */
|
|
374
|
+
export interface NodeList {
|
|
375
|
+
readonly length: number
|
|
376
|
+
item(index: number): Node | null
|
|
377
|
+
}
|
|
378
|
+
|
|
357
379
|
export interface Node extends EventTarget {
|
|
358
|
-
|
|
380
|
+
/** True only for a live allocation in the current mounted document subtree. */
|
|
381
|
+
readonly isConnected: boolean
|
|
382
|
+
readonly nodeType: number
|
|
383
|
+
readonly parentNode: Node | null
|
|
384
|
+
/** The current first child, including text/comments; null when empty. */
|
|
385
|
+
readonly firstChild: Node | null
|
|
386
|
+
readonly childNodes: NodeList
|
|
359
387
|
appendChild(child: Node): void
|
|
388
|
+
/** Move a live node before a direct child; null appends. Return the inserted node. */
|
|
389
|
+
insertBefore(child: Node, reference: Node | null): Node
|
|
390
|
+
/** Detach a direct live child and return that same allocation, without retiring it. */
|
|
391
|
+
removeChild(child: Node): Node
|
|
360
392
|
remove(): void
|
|
361
393
|
}
|
|
362
394
|
|
|
395
|
+
export interface FocusOptions { preventScroll?: boolean }
|
|
396
|
+
|
|
363
397
|
export interface ScrollIntoViewOptions {
|
|
364
398
|
behavior?: 'auto' | 'instant' | 'smooth'
|
|
365
399
|
block?: 'start' | 'center' | 'end' | 'nearest'
|
|
@@ -374,6 +408,12 @@ export interface DOMTokenList {
|
|
|
374
408
|
}
|
|
375
409
|
|
|
376
410
|
export interface Element extends Node {
|
|
411
|
+
readonly lastElementChild: Element | null
|
|
412
|
+
/** Bounded native selector grammar; malformed/unsupported selectors refuse. */
|
|
413
|
+
matches(selector: string): boolean
|
|
414
|
+
closest<E extends Element = Element>(selector: string): E | null
|
|
415
|
+
querySelector(selector: string): Element | null
|
|
416
|
+
querySelectorAll(selector: string): readonly Element[]
|
|
377
417
|
className?: string
|
|
378
418
|
readonly children: readonly Element[]
|
|
379
419
|
scrollLeft?: number
|
|
@@ -395,10 +435,24 @@ export interface Element extends Node {
|
|
|
395
435
|
// `blur()` clears it again (and does nothing when this element was not the
|
|
396
436
|
// one focused). Backed by `NodeHandle::focus()`/`blur()` over
|
|
397
437
|
// `Tree::setActiveInput` (engine/ui/node.cpp).
|
|
398
|
-
focus(): void
|
|
438
|
+
focus(options?: FocusOptions): void
|
|
399
439
|
blur(): void
|
|
400
440
|
}
|
|
401
441
|
|
|
442
|
+
/** Minimal native text input backed by a live NodeHandle allocation.
|
|
443
|
+
* Value uses the native value attribute; HTML dirty-value/defaultValue semantics
|
|
444
|
+
* and checked/type/selection APIs are not declared by this carrier. */
|
|
445
|
+
export interface InputElement extends Element {
|
|
446
|
+
disabled: boolean
|
|
447
|
+
value: string
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** Native button attributes backed by the live node allocation. */
|
|
451
|
+
export interface ButtonElement extends Element {
|
|
452
|
+
disabled: boolean
|
|
453
|
+
value: string
|
|
454
|
+
}
|
|
455
|
+
|
|
402
456
|
export interface VirtualListElement extends Element {
|
|
403
457
|
scrollTop: number
|
|
404
458
|
/**
|
|
@@ -412,15 +466,22 @@ export interface VirtualListElement extends Element {
|
|
|
412
466
|
}
|
|
413
467
|
|
|
414
468
|
export interface Document {
|
|
469
|
+
addEventListener<K extends keyof GeaEventMap>(type: K, listener: (event: GeaEventMap[K]) => void, options?: boolean | WindowEventListenerOptions): void
|
|
470
|
+
removeEventListener<K extends keyof GeaEventMap>(type: K, listener: (event: GeaEventMap[K]) => void, options?: boolean | WindowEventListenerOptions): void
|
|
415
471
|
readonly body: Element
|
|
472
|
+
/** Actual connected native focus, null when no owned responder is focused. */
|
|
473
|
+
readonly activeElement: Element | null
|
|
416
474
|
getElementById(id: string): Element | null
|
|
417
475
|
querySelector(selector: string): Element | null
|
|
418
476
|
querySelectorAll(selector: string): readonly Element[]
|
|
477
|
+
createElement(tag: 'input'): InputElement
|
|
478
|
+
createElement(tag: 'button'): ButtonElement
|
|
419
479
|
createElement(tag: 'audio'): HTMLAudioElement
|
|
420
480
|
createElement(tag: 'video'): HTMLVideoElement
|
|
421
481
|
createElement(tag: 'virtual-list'): VirtualListElement
|
|
422
482
|
createElement(tag: string): Element
|
|
423
483
|
createTextNode(text: string): Node
|
|
484
|
+
createComment(text: string): Node
|
|
424
485
|
createDocumentFragment(): Node
|
|
425
486
|
}
|
|
426
487
|
|
|
@@ -435,6 +496,10 @@ export interface PointerEvent extends Event {
|
|
|
435
496
|
// finger is 2, etc. (web convention, mirrored by the device touch runtime).
|
|
436
497
|
// Multi-touch handlers route gestures by this id.
|
|
437
498
|
readonly pointerId: number
|
|
499
|
+
/** Changed button: primary 0, auxiliary 1, secondary 2; -1 for no known edge. */
|
|
500
|
+
readonly button: number
|
|
501
|
+
/** Held-button bitmask for the producing pointer gesture; zero when released/unknown. */
|
|
502
|
+
readonly buttons: number
|
|
438
503
|
readonly x: number
|
|
439
504
|
readonly y: number
|
|
440
505
|
readonly clientX: number
|
|
@@ -502,7 +567,7 @@ export interface RotaryEvent extends Event {
|
|
|
502
567
|
* `KeyEvent`; `input` carries an `InputEvent`. Both are dispatched off-tree by
|
|
503
568
|
* the runtime (`dispatch_key_input`, and `virtual_keyboard.cpp`'s synthetic
|
|
504
569
|
* pair). Hardware button releases dispatch `keyup` with the same KeyEvent.
|
|
505
|
-
* `pointercancel`
|
|
570
|
+
* Native cancellation names its event `pointercancel`; `touchcancel` is a listener alias.
|
|
506
571
|
*/
|
|
507
572
|
export interface GeaEventMap {
|
|
508
573
|
click: PressEvent
|
|
@@ -512,7 +577,12 @@ export interface GeaEventMap {
|
|
|
512
577
|
pointerdown: PointerEvent
|
|
513
578
|
pointermove: PointerEvent
|
|
514
579
|
pointerup: PointerEvent
|
|
580
|
+
pointercancel: PointerEvent
|
|
581
|
+
touchcancel: PointerEvent
|
|
515
582
|
input: InputEvent
|
|
583
|
+
focusin: Event
|
|
584
|
+
focusout: Event
|
|
585
|
+
change: InputEvent
|
|
516
586
|
keydown: KeyEvent
|
|
517
587
|
keyup: KeyEvent
|
|
518
588
|
rotary: RotaryEvent
|
|
@@ -524,6 +594,15 @@ export type PointerEventHandler = (event: PointerEvent) => void
|
|
|
524
594
|
export type RotaryEventHandler = (event: RotaryEvent) => void
|
|
525
595
|
|
|
526
596
|
export interface NativeTouchEventAttributes {
|
|
597
|
+
/** Bare JSX spellings use the same native listener publication as onX. */
|
|
598
|
+
touchstart?: TouchEventHandler
|
|
599
|
+
touchend?: TouchEventHandler
|
|
600
|
+
touchmove?: TouchEventHandler
|
|
601
|
+
touchcancel?: PointerEventHandler
|
|
602
|
+
pointerdown?: PointerEventHandler
|
|
603
|
+
pointermove?: PointerEventHandler
|
|
604
|
+
pointerup?: PointerEventHandler
|
|
605
|
+
pointercancel?: PointerEventHandler
|
|
527
606
|
onTouchStart?: TouchEventHandler
|
|
528
607
|
onTouchEnd?: TouchEventHandler
|
|
529
608
|
onTouchMove?: TouchEventHandler
|
|
@@ -538,9 +617,18 @@ export interface NativeTouchEventAttributes {
|
|
|
538
617
|
onPointerDown?: PointerEventHandler
|
|
539
618
|
onPointerMove?: PointerEventHandler
|
|
540
619
|
onPointerUp?: PointerEventHandler
|
|
620
|
+
onPointerCancel?: PointerEventHandler
|
|
541
621
|
}
|
|
542
622
|
|
|
543
623
|
export interface NativeEventAttributes extends NativeTouchEventAttributes {
|
|
624
|
+
click?: PressHandler
|
|
625
|
+
input?: (event: InputEvent) => void
|
|
626
|
+
/** Committed user value change; distinct from intermediate input. */
|
|
627
|
+
change?: (event: InputEvent) => void
|
|
628
|
+
onChange?: (event: InputEvent) => void
|
|
629
|
+
keydown?: (event: KeyEvent) => void
|
|
630
|
+
keyup?: (event: KeyEvent) => void
|
|
631
|
+
scroll?: (event: Event) => void
|
|
544
632
|
/** Text services and app-owned editors may dispatch input on ordinary views. */
|
|
545
633
|
onInput?: (event: InputEvent) => void
|
|
546
634
|
onClick?: PressHandler
|
|
@@ -551,6 +639,7 @@ export interface NativeEventAttributes extends NativeTouchEventAttributes {
|
|
|
551
639
|
}
|
|
552
640
|
|
|
553
641
|
export interface InputEventTarget extends Element {
|
|
642
|
+
disabled: boolean
|
|
554
643
|
value: string
|
|
555
644
|
}
|
|
556
645
|
|
|
@@ -559,9 +648,19 @@ export interface InputEvent {
|
|
|
559
648
|
currentTarget: InputEventTarget
|
|
560
649
|
}
|
|
561
650
|
|
|
562
|
-
export interface KeyEvent {
|
|
563
|
-
|
|
564
|
-
|
|
651
|
+
export interface KeyEvent extends Event {
|
|
652
|
+
readonly target: Element
|
|
653
|
+
readonly currentTarget: Element
|
|
654
|
+
readonly keyCode: number
|
|
655
|
+
readonly which: number
|
|
656
|
+
readonly key: string
|
|
657
|
+
readonly code: string
|
|
658
|
+
readonly altKey: boolean
|
|
659
|
+
readonly ctrlKey: boolean
|
|
660
|
+
readonly metaKey: boolean
|
|
661
|
+
readonly shiftKey: boolean
|
|
662
|
+
readonly repeat: boolean
|
|
663
|
+
readonly isComposing: boolean
|
|
565
664
|
}
|
|
566
665
|
|
|
567
666
|
export interface ViewProps extends DataAttributes {
|
|
@@ -1322,6 +1421,59 @@ export interface GpioController {
|
|
|
1322
1421
|
|
|
1323
1422
|
export declare const Gpio: GpioController
|
|
1324
1423
|
|
|
1424
|
+
export interface UartOptions {
|
|
1425
|
+
tx: number
|
|
1426
|
+
rx: number
|
|
1427
|
+
baudRate: number
|
|
1428
|
+
/** Receive/transmit queue bytes. Defaults to 4096 each. */
|
|
1429
|
+
rxBufferSize?: number
|
|
1430
|
+
txBufferSize?: number
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
/** Hardware UART, 8 data bits, no parity, one stop bit (8N1). */
|
|
1434
|
+
export interface UartController {
|
|
1435
|
+
/** Claims a free controller and pins. False on conflict/invalid configuration. */
|
|
1436
|
+
open(port: number, options: UartOptions): boolean
|
|
1437
|
+
isOpen(port: number): boolean
|
|
1438
|
+
close(port: number): void
|
|
1439
|
+
/** Nonblocking read into the supplied view; returns bytes read, or -1 on error. */
|
|
1440
|
+
read(port: number, buffer: Uint8Array): number
|
|
1441
|
+
/** Nonblocking whole-buffer enqueue; 0 means backpressure, -1 means error. */
|
|
1442
|
+
write(port: number, buffer: Uint8Array): number
|
|
1443
|
+
/** Queued readable bytes, or -1 when unavailable. */
|
|
1444
|
+
available(port: number): number
|
|
1445
|
+
/** Writable queue capacity, or -1 when unavailable. */
|
|
1446
|
+
writable(port: number): number
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
export declare const Uart: UartController
|
|
1450
|
+
|
|
1451
|
+
/** ESP-NOW v2 datagrams; addresses are six-byte MACs. Unsupported targets return false/-1. */
|
|
1452
|
+
export interface EspNowController {
|
|
1453
|
+
/** Integer quarter-dBm cap, 8..84; fails on closed/borrowed radios. The SDK quantizes it. */
|
|
1454
|
+
setMaxTxPower(quarterDbm: number): boolean
|
|
1455
|
+
/** Actual cap in quarter-dBm, or -1 when unavailable. */
|
|
1456
|
+
getMaxTxPower(): number
|
|
1457
|
+
/**
|
|
1458
|
+
* Channel 0 borrows running Wi-Fi. Other channels claim an idle radio.
|
|
1459
|
+
* Default 54; rates 24/36/54 use OFDM, 65 uses HT20 MCS7.
|
|
1460
|
+
* ESP32-S31 also accepts 115 for HE20 MCS9 short GI (nominal 114.7 Mbps).
|
|
1461
|
+
* Unsupported rates/protocols return false without changing a borrowed radio.
|
|
1462
|
+
*/
|
|
1463
|
+
open(channel: number, rateMbps?: number): boolean
|
|
1464
|
+
isOpen(): boolean
|
|
1465
|
+
/** True when the previous radio send has completed. */
|
|
1466
|
+
canSend(): boolean
|
|
1467
|
+
close(): void
|
|
1468
|
+
/** Optional key is a 16-byte LMK; omit only for unencrypted traffic. */
|
|
1469
|
+
addPeer(address: Uint8Array, key?: Uint8Array): boolean
|
|
1470
|
+
/** Whole datagram admission: bytes, 0 when busy, -1 for invalid/unavailable. */
|
|
1471
|
+
send(address: Uint8Array, bytes: Uint8Array): number
|
|
1472
|
+
/** source must be 6 bytes, buffer at least 1470. Returns received length, 0, or -1. */
|
|
1473
|
+
receive(source: Uint8Array, buffer: Uint8Array): number
|
|
1474
|
+
}
|
|
1475
|
+
export declare const EspNow: EspNowController
|
|
1476
|
+
|
|
1325
1477
|
export interface LedController {
|
|
1326
1478
|
// A WS2812/NeoPixel strand on one pin — what "the onboard LED" is on most
|
|
1327
1479
|
// modern ESP32 modules.
|
|
@@ -1523,6 +1675,29 @@ export interface AccelerometerController {
|
|
|
1523
1675
|
|
|
1524
1676
|
export declare const Accelerometer: AccelerometerController
|
|
1525
1677
|
|
|
1678
|
+
export interface MagnetometerReading {
|
|
1679
|
+
/** Compensated whole microtesla; saturated axes retain their sensor sentinel. */
|
|
1680
|
+
x: number
|
|
1681
|
+
y: number
|
|
1682
|
+
z: number
|
|
1683
|
+
/** False for an unavailable sensor or failed I2C read. */
|
|
1684
|
+
valid: boolean
|
|
1685
|
+
/** Saturated-axis bits: X=1, Y=2, Z=4. Those values are not field strength. */
|
|
1686
|
+
saturatedAxes: number
|
|
1687
|
+
timestampUs: number
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
export interface MagnetometerController {
|
|
1691
|
+
/** Initializes the board's sensors. Idempotent; false when unavailable. */
|
|
1692
|
+
open(): boolean
|
|
1693
|
+
close(): void
|
|
1694
|
+
/** Number of board-defined sensors, whether open or closed. */
|
|
1695
|
+
count(): number
|
|
1696
|
+
/** Mosaico indexes: 0=right (0x11), 1=left (0x12). */
|
|
1697
|
+
read(index: number): MagnetometerReading
|
|
1698
|
+
}
|
|
1699
|
+
export declare const Magnetometer: MagnetometerController
|
|
1700
|
+
|
|
1526
1701
|
export type CameraFacing = 'front' | 'back' | 'external'
|
|
1527
1702
|
export type CameraFlashMode = 'off' | 'on' | 'auto' | 'torch'
|
|
1528
1703
|
|
|
@@ -1787,7 +1962,7 @@ export interface InputElementProps {
|
|
|
1787
1962
|
keyup?: (keyCode: number) => void
|
|
1788
1963
|
}
|
|
1789
1964
|
|
|
1790
|
-
export interface NativeInputElementProps extends InputElementProps, DataAttributes {
|
|
1965
|
+
export interface NativeInputElementProps extends Omit<InputElementProps, 'input' | 'keydown' | 'keyup'>, NativeEventAttributes, DataAttributes {
|
|
1791
1966
|
id?: string
|
|
1792
1967
|
ref?: GeaElement | null
|
|
1793
1968
|
}
|
|
@@ -1802,7 +1977,7 @@ export interface TextAreaElementProps {
|
|
|
1802
1977
|
onBlur?: () => void
|
|
1803
1978
|
}
|
|
1804
1979
|
|
|
1805
|
-
export interface NativeTextAreaElementProps extends TextAreaElementProps, DataAttributes {
|
|
1980
|
+
export interface NativeTextAreaElementProps extends TextAreaElementProps, NativeEventAttributes, DataAttributes {
|
|
1806
1981
|
id?: string
|
|
1807
1982
|
disabled?: boolean
|
|
1808
1983
|
readOnly?: boolean
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geastack/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"description": "GeaStack app API, reactivity headers, runtime sources, and type declarations.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -66,8 +66,11 @@
|
|
|
66
66
|
"@geajs/core": "1.5.1",
|
|
67
67
|
"@geajs/vite-plugin": "1.5.0",
|
|
68
68
|
"@geastack/compiler": "^1.0.29",
|
|
69
|
-
"@geastack/geatsc-plugin-gea": "
|
|
69
|
+
"@geastack/geatsc-plugin-gea": "0.1.24",
|
|
70
70
|
"opentype.js": "^2.0.0",
|
|
71
71
|
"vite": "^8.0.0"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"jsdom": "^26.1.0"
|
|
72
75
|
}
|
|
73
76
|
}
|