lecodes-sdk 2.0.7 → 2.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/dist/global.d.ts +6 -0
- package/dist/types/g2/Scene2D.d.ts +4 -0
- package/dist/types/gl/Light.d.ts +36 -1
- package/dist/types/gl/Scene.d.ts +4 -0
- package/dist/types/inject.d.ts +2 -1
- package/dist/types/runtime/rpc.d.ts +2 -0
- package/dist/types/server/context.d.ts +4 -0
- package/dist/types/server/db/defineDb.d.ts +1 -1
- package/dist/types/server/db/fields.d.ts +25 -1
- package/dist/types/server/db/marci/query.d.ts +39 -2
- package/dist/types/server/db/types.d.ts +13 -7
- package/dist/types/server/files/db.d.ts +39 -0
- package/dist/types/server/files/models.d.ts +131 -0
- package/dist/types/server/inject.d.ts +1 -0
- package/dist/types/ui/NativeView.d.ts +3 -0
- package/dist/types/ui/UI.d.ts +1 -0
- package/dist/types/ui/UILayer.d.ts +25 -0
- package/dist/types/ui/UIModal.d.ts +20 -16
- package/dist/types/ui/UIPopover.d.ts +5 -3
- package/dist/types/ui/UIVideo.d.ts +3 -0
- package/dist/types/ui/UIWidget.d.ts +25 -24
- package/dist/types/ui/presentable.d.ts +10 -0
- package/dist/types/ui/transitions.d.ts +2 -1
- package/dist/types/ui/tree.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types.json +1 -1
- package/package.json +3 -2
- package/prompts/3d-scene-files.md +3 -3
- package/prompts/3d-scene.md +1 -1
- package/prompts/dist/3d-app.md +4 -4
- package/src/bridges/gl.d.ts +5 -0
- package/src/bridges/tree.d.ts +24 -12
- package/src/chisel.ts +1 -1
- package/src/compile/libraryImports.ts +9 -0
- package/src/compile/serverTypes.ts +6 -0
- package/src/g2/Scene2D.ts +10 -0
- package/src/gl/Light.ts +78 -2
- package/src/gl/Material.ts +3 -0
- package/src/gl/Scene.ts +11 -1
- package/src/inject.ts +2 -0
- package/src/runtime/rpc.ts +15 -3
- package/src/server/context.ts +4 -0
- package/src/server/db/defineDb.ts +62 -9
- package/src/server/db/fields.ts +21 -1
- package/src/server/db/httpTransport.ts +9 -1
- package/src/server/db/marci/query.ts +71 -4
- package/src/server/db/types.ts +16 -5
- package/src/server/files/db.ts +182 -0
- package/src/server/files/host.ts +496 -0
- package/src/server/files/models.ts +116 -0
- package/src/server/host.ts +17 -4
- package/src/server/inject.ts +1 -0
- package/src/server/runtime.ts +41 -0
- package/src/server/validate.ts +5 -0
- package/src/ui/NativeView.ts +11 -0
- package/src/ui/UI.ts +1 -0
- package/src/ui/UIBottomSheet.ts +8 -7
- package/src/ui/UILayer.ts +88 -0
- package/src/ui/UIModal.ts +59 -43
- package/src/ui/UINode.ts +9 -1
- package/src/ui/UIPopover.ts +23 -9
- package/src/ui/UIVideo.ts +11 -0
- package/src/ui/UIWidget.ts +70 -44
- package/src/ui/presentable.ts +11 -1
- package/src/ui/transitions.ts +36 -7
- package/src/ui/tree.ts +4 -0
- package/src/version.ts +1 -1
- package/tests/helpers/fakeTree.ts +7 -3
package/dist/global.d.ts
CHANGED
|
@@ -124,6 +124,7 @@ declare global {
|
|
|
124
124
|
const UIImage: typeof SDK.UIImage
|
|
125
125
|
const UIInput: typeof SDK.UIInput
|
|
126
126
|
const UIModal: typeof SDK.UIModal
|
|
127
|
+
const UIOverlay: typeof SDK.UIOverlay
|
|
127
128
|
const UIPager: typeof SDK.UIPager
|
|
128
129
|
const UIPopover: typeof SDK.UIPopover
|
|
129
130
|
const UIRow: typeof SDK.UIRow
|
|
@@ -480,6 +481,8 @@ declare global {
|
|
|
480
481
|
type StepHandler = SDK.StepHandler
|
|
481
482
|
type StepWarpOptions = SDK.StepWarpOptions
|
|
482
483
|
type StopOptions = SDK.StopOptions
|
|
484
|
+
type StoredFile = SDK.StoredFile
|
|
485
|
+
type StoredImage = SDK.StoredImage
|
|
483
486
|
type System<K extends string, S extends SystemHost = Scene, E extends EventMap = {}> = SDK.System<K, S, E>
|
|
484
487
|
type SystemHost = SDK.SystemHost
|
|
485
488
|
type TabDef = SDK.TabDef
|
|
@@ -554,6 +557,7 @@ declare global {
|
|
|
554
557
|
type UIVideoStyle = SDK.UIVideoStyle
|
|
555
558
|
type UIVirtualizedList<T = unknown> = SDK.UIVirtualizedList<T>
|
|
556
559
|
type UIWidget = SDK.UIWidget
|
|
560
|
+
type UIWidgetContent = SDK.UIWidgetContent
|
|
557
561
|
type UIWidgetStyle = SDK.UIWidgetStyle
|
|
558
562
|
type Unit = SDK.Unit
|
|
559
563
|
type UnlitMaterialDef = SDK.UnlitMaterialDef
|
|
@@ -580,6 +584,8 @@ declare global {
|
|
|
580
584
|
const request: typeof SERVER.request
|
|
581
585
|
const t: typeof SERVER.t
|
|
582
586
|
type ApiError = SERVER.ApiError
|
|
587
|
+
type StoredFile = SERVER.StoredFile
|
|
588
|
+
type StoredImage = SERVER.StoredImage
|
|
583
589
|
}
|
|
584
590
|
|
|
585
591
|
export {}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ColorInput } from "../core/color";
|
|
2
2
|
import { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from "../core/Aspect";
|
|
3
3
|
import { Presentable, type DismissOptions, type PresentOptions } from "../ui/presentable";
|
|
4
|
+
import { type UIWidgetContent } from "../ui/UILayer";
|
|
4
5
|
import { type Vec2Like } from "../math/vec";
|
|
5
6
|
import type { ClickEvent, TouchStartEvent } from "../runtime/touch";
|
|
6
7
|
import { Camera2D } from "./Camera2D";
|
|
@@ -67,6 +68,9 @@ export declare class Scene2D implements Presentable {
|
|
|
67
68
|
/** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the
|
|
68
69
|
* rename; removed with the release that recompiles them. */
|
|
69
70
|
onBackPressed(callback: () => void): this;
|
|
71
|
+
/** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is
|
|
72
|
+
* presented; touches outside a widget's box reach the scene. */
|
|
73
|
+
setContent(content: UIWidgetContent): this;
|
|
70
74
|
/** Make this the active scene — shows it as the current destination (replaces a screen /
|
|
71
75
|
* another scene; only the active scene renders). */
|
|
72
76
|
open(options?: PresentOptions): this;
|
package/dist/types/gl/Light.d.ts
CHANGED
|
@@ -73,6 +73,23 @@ export type PointOptions = {
|
|
|
73
73
|
*/
|
|
74
74
|
bakeArea?: readonly [number, number];
|
|
75
75
|
};
|
|
76
|
+
export type SpotOptions = {
|
|
77
|
+
/**
|
|
78
|
+
* Luminous power in lumens, as a point light's. The cone does not change the brightness: widen it and the
|
|
79
|
+
* same lumens light a larger patch at the same level. On its axis a spot is 4x brighter than a point light of
|
|
80
|
+
* the same lumens (its light is not spread over the whole sphere). Default 1000.
|
|
81
|
+
*/
|
|
82
|
+
intensity?: number;
|
|
83
|
+
color?: ColorInput;
|
|
84
|
+
/** Metres of influence along the cone, the performance knob as for a point light. Default 10. */
|
|
85
|
+
range?: number;
|
|
86
|
+
/** The cone's full angle in degrees, up to 180: past it the light contributes nothing. Default 45. */
|
|
87
|
+
angle?: number;
|
|
88
|
+
/** The full angle in degrees of the cone's fully lit core; the light fades from it out to `angle`. Default 0.75 x `angle`. */
|
|
89
|
+
innerAngle?: number;
|
|
90
|
+
/** A spot's shadow is one 2D shadow map (a point light's is a cubemap); off by default. */
|
|
91
|
+
castShadows?: boolean;
|
|
92
|
+
};
|
|
76
93
|
export declare class Light extends Node {
|
|
77
94
|
private _intensity;
|
|
78
95
|
/** Tween `intensity` / `color` (a flash, a sunrise) and the transform — see {@link Node.animateTo}. */
|
|
@@ -94,7 +111,25 @@ export declare class Light extends Node {
|
|
|
94
111
|
static point(options?: PointOptions): Light;
|
|
95
112
|
/** Whether this host can create point lights at all. */
|
|
96
113
|
static get supportsPoint(): boolean;
|
|
97
|
-
|
|
114
|
+
_innerAngle: number;
|
|
115
|
+
/**
|
|
116
|
+
* A spot light — a flashlight, a headlight, a stage light. It shines along the node's forward (-Z): position
|
|
117
|
+
* it like any node and aim it with `lookAt`. Real time only: the lightmap bake takes no spot lights, so a spot
|
|
118
|
+
* lights the baked statics live too.
|
|
119
|
+
*
|
|
120
|
+
* Feature-detected like `Light.point`: on a host without it the node exists and lights nothing
|
|
121
|
+
* (`Light.supportsSpot`).
|
|
122
|
+
*/
|
|
123
|
+
static spot(options?: SpotOptions): Light;
|
|
124
|
+
/** Whether this host can create spot lights. */
|
|
125
|
+
static get supportsSpot(): boolean;
|
|
126
|
+
/** A spot's full cone angle in degrees — live (a flashlight's focus). */
|
|
127
|
+
get angle(): number;
|
|
128
|
+
set angle(value: number);
|
|
129
|
+
/** A spot's fully lit core, full angle in degrees — live. Setting `angle` scales it along. */
|
|
130
|
+
get innerAngle(): number;
|
|
131
|
+
set innerAngle(value: number);
|
|
132
|
+
/** Live intensity (sun: lux, point / spot: lumens) — animate a flash without rebuilding the light. */
|
|
98
133
|
get intensity(): number;
|
|
99
134
|
set intensity(value: number);
|
|
100
135
|
_holdDark(dark: boolean): void;
|
package/dist/types/gl/Scene.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ColorInput } from "../core/color";
|
|
2
2
|
import { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from "../core/Aspect";
|
|
3
3
|
import { Presentable, type DismissOptions, type PresentOptions } from "../ui/presentable";
|
|
4
|
+
import { type UIWidgetContent } from "../ui/UILayer";
|
|
4
5
|
import type { ClickEvent, TouchStartEvent } from "../runtime/touch";
|
|
5
6
|
import type { FetchResponse } from "../runtime/fetch";
|
|
6
7
|
import { Camera } from "./Camera";
|
|
@@ -247,6 +248,9 @@ export declare class Scene implements Presentable {
|
|
|
247
248
|
/** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the
|
|
248
249
|
* rename; removed with the release that recompiles them. */
|
|
249
250
|
onBackPressed(callback: () => void): this;
|
|
251
|
+
/** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is
|
|
252
|
+
* presented; touches outside a widget's box reach the scene. `scene.setContent([hud])`. */
|
|
253
|
+
setContent(content: UIWidgetContent): this;
|
|
250
254
|
/** Make this the active scene — shows it as the current destination (replaces a screen /
|
|
251
255
|
* another scene; only the active scene renders). The runtime activates the engine as part of
|
|
252
256
|
* presenting the destination. */
|
package/dist/types/inject.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export { WebSocket } from "./runtime/net";
|
|
|
23
23
|
export { Net, NetPlayer, Replicated, NetEntity, type NetMessage, type NetRole, type NetStatus, type NetEvents, type NetLaunch, type NetInput, type NetKind, type NetTransform, type NetCorrection } from "./net";
|
|
24
24
|
export { __rpc, __channel, __serverOnly, RpcError } from "./runtime/rpc";
|
|
25
25
|
export type { ChannelSubscription } from "./server/channel";
|
|
26
|
+
export type { StoredFile, StoredImage } from "./server/files/models";
|
|
26
27
|
export { AudioPlayer, VideoPlayer } from "./runtime/media";
|
|
27
28
|
export { Sound, type SoundOptions } from "./audio/Sound";
|
|
28
29
|
export { Voice, type VoiceEvents } from "./audio/Voice";
|
|
@@ -54,7 +55,7 @@ export { defineScene2d, Scene2dHandle } from "./g2/defineScene2d";
|
|
|
54
55
|
export type { Scene2dDef, Scene2dNodeDef, Scene2dEnv, SpriteSourceDef, TilemapSourceDef, Camera2dNodeDef, LoadedScene2d } from "./g2/defineScene2d";
|
|
55
56
|
export { cells, encodeCells, type CellsData } from "./g2/cells";
|
|
56
57
|
export { CameraFollow } from "./g2/scenarios2d";
|
|
57
|
-
export { UIScreen, type UIScreenStyle, UIRow, UIColumn, UIBox, type UIContainerStyle, UIText, type UITextStyle, UIButton, type UIButtonStyle, UIImage, type UIImageStyle, UIVideo, type UIVideoStyle, UIInput, UITextArea, type UIInputStyle, UIScrollable, type UIScrollableStyle, UIPager, type UIPagerStyle, UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle, UIWidget, type UIWidgetStyle, UIModal, type UIModalStyle, UIBottomSheet, type UIBottomSheetStyle, UIPopover, type UIPopoverStyle, UISpacer, type UISpacerStyle, UIVirtualizedList, Router, NativeView, type UINativeViewStyle, registerFont, __uiMap, __UIColumn, __UIRow, __UIBox, __UIButton, __UIScreen, __UIScrollable, __UIWidget, } from "./ui/UI";
|
|
58
|
+
export { UIScreen, type UIScreenStyle, UIRow, UIColumn, UIBox, type UIContainerStyle, UIText, type UITextStyle, UIButton, type UIButtonStyle, UIImage, type UIImageStyle, UIVideo, type UIVideoStyle, UIInput, UITextArea, type UIInputStyle, UIScrollable, type UIScrollableStyle, UIPager, type UIPagerStyle, UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle, UIWidget, type UIWidgetStyle, UIOverlay, type UIWidgetContent, UIModal, type UIModalStyle, UIBottomSheet, type UIBottomSheetStyle, UIPopover, type UIPopoverStyle, UISpacer, type UISpacerStyle, UIVirtualizedList, Router, NativeView, type UINativeViewStyle, registerFont, __uiMap, __UIColumn, __UIRow, __UIBox, __UIButton, __UIScreen, __UIScrollable, __UIWidget, } from "./ui/UI";
|
|
58
59
|
export { Presentable } from "./ui/UI";
|
|
59
60
|
export type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from "./ui/UI";
|
|
60
61
|
export type { UINode, UINodeChild } from "./ui/UINode";
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Wire (implemented by the runner):
|
|
11
11
|
* POST <serverUrl>/api/<id> body {"args":[…]}, `authorization: Bearer <session>` when known
|
|
12
|
+
* — with a `File` among the arguments: multipart, the field `args` is
|
|
13
|
+
* that JSON with `{"$file": <i>}` where the file stood, `file<i>` the files
|
|
12
14
|
* → 200 {"ok":true,"result":…,"session"?:"…"} | {"ok":false,"status":n,"message":"…","session"?:"…"}
|
|
13
15
|
* WS <serverUrl>/ws the channel socket — its frames are ./wire.ts
|
|
14
16
|
*
|
|
@@ -14,6 +14,10 @@ export type RequestContext = {
|
|
|
14
14
|
sessionToken?: string;
|
|
15
15
|
/** Set by the auth runtime after resolving the token — read via `db.auth`, not here. */
|
|
16
16
|
auth?: unknown;
|
|
17
|
+
/** The files a multipart call carried, as the receiving process left them (./files/host.ts `Upload`). */
|
|
18
|
+
uploads?: unknown[];
|
|
19
|
+
/** What `/files/<id>/<name>` is appended to in a stored file's url: the backend's own base, as this request reached it. */
|
|
20
|
+
filesBase?: string;
|
|
17
21
|
};
|
|
18
22
|
type Provider = () => RequestContext | undefined;
|
|
19
23
|
/** Host hook (runner / test harness): install the current-request provider. */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `defineDb(models, { transport })` or provided by the host through `setDbTransport()` — user code
|
|
8
8
|
* never sees a connection string.
|
|
9
9
|
*/
|
|
10
|
-
import type
|
|
10
|
+
import { type FieldDef } from "./fields";
|
|
11
11
|
import { type MarciTransport } from "./marci/query";
|
|
12
12
|
import type { Db, Fields, Model, Schema, ValidateRefs } from "./types";
|
|
13
13
|
export declare const model: <F extends Fields>(fields: F) => Model<F>;
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* mutated), so `const s = t.string(); { a: s, b: s.optional() }` behaves as expected.
|
|
7
7
|
*/
|
|
8
8
|
import type { JsonValue } from "./marci/query";
|
|
9
|
+
import type { StoredFile, StoredImage } from "../files/models";
|
|
9
10
|
export type ScalarKind = "string" | "int" | "float" | "bool" | "date" | "uuid" | "";
|
|
10
|
-
export type FieldKind = "scalar" | "json" | "enum" | "struct" | "one" | "many" | "list";
|
|
11
|
+
export type FieldKind = "scalar" | "json" | "enum" | "struct" | "one" | "many" | "list" | "file";
|
|
11
12
|
export type OnDelete = "cascade" | "setNull" | "restrict";
|
|
12
13
|
/** Phantom metadata — the type-level twin of `FieldDef`. */
|
|
13
14
|
export type FieldMeta = {
|
|
@@ -58,6 +59,10 @@ export type FieldDef = {
|
|
|
58
59
|
fields?: Record<string, Field<any, any>>;
|
|
59
60
|
/** one / many / list */
|
|
60
61
|
model?: string;
|
|
62
|
+
/** file: a picture (`t.image()`) — `max` is the most its longer side may be, px. */
|
|
63
|
+
image?: {
|
|
64
|
+
max: number;
|
|
65
|
+
};
|
|
61
66
|
/** many: the field on the related model that holds the reference (`@bind`); resolved by defineDb when omitted. */
|
|
62
67
|
back?: string;
|
|
63
68
|
};
|
|
@@ -136,6 +141,25 @@ export declare const t: {
|
|
|
136
141
|
kind: "many";
|
|
137
142
|
model: N;
|
|
138
143
|
}>>;
|
|
144
|
+
/**
|
|
145
|
+
* A stored file: written as a `File` (an upload — an endpoint's parameter), read as
|
|
146
|
+
* `{ url, name, type, size, width?, height? }`. `.optional()` = may be empty, `.array()` = an ordered
|
|
147
|
+
* list of files. It is deleted with its row — or when the field is given another file, or `null`.
|
|
148
|
+
*/
|
|
149
|
+
file: () => Field<StoredFile, Meta<{
|
|
150
|
+
kind: "file";
|
|
151
|
+
}>>;
|
|
152
|
+
/**
|
|
153
|
+
* A stored PICTURE — a `t.file()` that takes images only and keeps them fit to show: turned the way
|
|
154
|
+
* the camera meant, without its metadata (a photo's place and time), as WebP, and no larger than
|
|
155
|
+
* `max` px on its longer side (2048 when not said; a picture is never enlarged).
|
|
156
|
+
* Read as a `StoredFile` whose `width` and `height` are always there. A GIF is kept as it is.
|
|
157
|
+
*/
|
|
158
|
+
image: (options?: {
|
|
159
|
+
max?: number;
|
|
160
|
+
}) => Field<StoredImage, Meta<{
|
|
161
|
+
kind: "file";
|
|
162
|
+
}>>;
|
|
139
163
|
/** Ordered relation list stored inline (`@list`) — hand-arranged collections, duplicates allowed. */
|
|
140
164
|
list: <N extends string>(model: N) => Field<never, Meta<{
|
|
141
165
|
kind: "list";
|
|
@@ -197,6 +197,15 @@ export type MarciOp = {
|
|
|
197
197
|
query?: any;
|
|
198
198
|
data?: any;
|
|
199
199
|
id?: any;
|
|
200
|
+
journal?: JournalArgs;
|
|
201
|
+
};
|
|
202
|
+
/** The arguments of a journal action (`$journalOpen` / `$journalRead` / `$journalDrop`). `wait` is in seconds. */
|
|
203
|
+
export type JournalArgs = {
|
|
204
|
+
name: string;
|
|
205
|
+
on?: readonly JournalOp[];
|
|
206
|
+
after?: number;
|
|
207
|
+
limit?: number;
|
|
208
|
+
wait?: number;
|
|
200
209
|
};
|
|
201
210
|
export type MarciTransport = {
|
|
202
211
|
exec(op: MarciOp): Promise<any>;
|
|
@@ -291,13 +300,41 @@ export interface Query<T extends ModelTypes, Sel = T["scalars"]> extends Promise
|
|
|
291
300
|
/** @deprecated use `.select(query).first()` (removed in the next minor). */
|
|
292
301
|
findFirst<Q extends T["query"] = {}>(query?: Q): Op<Rows<T, Q> | null>;
|
|
293
302
|
}
|
|
294
|
-
/**
|
|
303
|
+
/** What a journal can record. Only deletes so far. */
|
|
304
|
+
export type JournalOp = "delete";
|
|
305
|
+
/** One recorded change. `row` is the row as it last was: its id and every scalar field. */
|
|
306
|
+
export type JournalEntry<T extends ModelTypes, O extends JournalOp = JournalOp> = {
|
|
307
|
+
seq: number;
|
|
308
|
+
op: O;
|
|
309
|
+
row: Rows<T, T["scalars"]>;
|
|
310
|
+
};
|
|
311
|
+
export type JournalOptions<O extends JournalOp> = {
|
|
312
|
+
/** The operations to record. A journal that exists with other ones is an error, not a redefinition. */
|
|
313
|
+
on: O | readonly O[];
|
|
314
|
+
/** `false`: the loop ends when the journal is read through. By default it waits for the next entry. */
|
|
315
|
+
wait?: boolean;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* A named, durable log of a model's changes. It starts recording when it is first asked for and keeps
|
|
319
|
+
* every entry until the loop that reads it has moved past it — an entry whose loop body threw, or that
|
|
320
|
+
* was never reached, is delivered again to the next reader of the same name.
|
|
321
|
+
*/
|
|
322
|
+
export interface Journal<T extends ModelTypes, O extends JournalOp = JournalOp> extends AsyncIterable<JournalEntry<T, O>> {
|
|
323
|
+
/** Drops the journal with whatever it still holds; the model's writes stop paying for it. */
|
|
324
|
+
drop(): Promise<void>;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* `db.<model>`: the root query, plus `reindex()` for models with a `@custom` (vector / full-text) index and
|
|
328
|
+
* `$journal(name, { on })` — the journal of this model's changes under that name, created on first use.
|
|
329
|
+
*/
|
|
295
330
|
export type Collection<T extends ModelTypes> = Query<T> & (T["reindex"] extends true ? {
|
|
296
331
|
reindex(): Op<{
|
|
297
332
|
ok: boolean;
|
|
298
333
|
indexed: number;
|
|
299
334
|
}>;
|
|
300
|
-
} : {})
|
|
335
|
+
} : {}) & {
|
|
336
|
+
$journal<O extends JournalOp>(name: string, options: JournalOptions<O>): Journal<T, O>;
|
|
337
|
+
};
|
|
301
338
|
/** One field of a model, in slot order: `n` name, `k` key | body | one | many, `m` the relation's target model. */
|
|
302
339
|
export type FieldDesc = {
|
|
303
340
|
n: string;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Field, FieldMeta } from "./fields";
|
|
10
10
|
import type { IdentityPublicFields, SessionPublicFields } from "../auth/models";
|
|
11
|
+
import type { StoredFile, UploadedFile as File } from "../files/models";
|
|
11
12
|
import type { CompareNumValue, CompareRefListValue, CompareRefValue, CompareStrValue, CompareValue, CustomSearchValue, FullTextSearch, JsonCondition, JsonPathWhere, Op, PrimitiveListUpdate, Query as MarciQuery, RefListUpdate, RefListUpdateOrdered, RefUpdate, RefUpdateStruct, Rows, Sub, UpdateNumValue, VectorSearch, WhereValue } from "./marci/query";
|
|
12
13
|
export type Fields = Record<string, Field<any, any>>;
|
|
13
14
|
export type Model<F extends Fields = Fields> = {
|
|
@@ -48,7 +49,12 @@ export type Row<S, N extends keyof S> = Id<S, N> & {
|
|
|
48
49
|
type StructRow<S, F extends Fields> = {
|
|
49
50
|
[K in keyof F]: FieldRow<S, F[K]>;
|
|
50
51
|
};
|
|
52
|
+
/** What a query without a selection returns besides the id: the scalars, and the files. */
|
|
51
53
|
type ScalarKeys<F extends Fields> = {
|
|
54
|
+
[K in keyof F]: MetaOf<F[K]>["kind"] extends "scalar" | "enum" | "json" | "file" ? K : never;
|
|
55
|
+
}[keyof F];
|
|
56
|
+
/** The fields a row is ordered and aggregated by. */
|
|
57
|
+
type ValueKeys<F extends Fields> = {
|
|
52
58
|
[K in keyof F]: MetaOf<F[K]>["kind"] extends "scalar" | "enum" | "json" ? K : never;
|
|
53
59
|
}[keyof F];
|
|
54
60
|
type NumKeys<F extends Fields> = {
|
|
@@ -60,9 +66,9 @@ export type Scalars<S, N extends keyof S> = Pick<Row<S, N>, (ScalarKeys<FieldsOf
|
|
|
60
66
|
export type ScalarSelect<S, N extends keyof S> = {
|
|
61
67
|
[K in (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>]: true;
|
|
62
68
|
};
|
|
63
|
-
type FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M["kind"] extends "many" | "list" ? Id<S, ModelName<S, Fld>>[] : M["kind"] extends "struct" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : Nullable<M, Arr<M, TsOf<Fld>>>;
|
|
69
|
+
type FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M["kind"] extends "many" | "list" ? Id<S, ModelName<S, Fld>>[] : M["kind"] extends "struct" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : M["kind"] extends "file" ? Nullable<M, Arr<M, File>> : Nullable<M, Arr<M, TsOf<Fld>>>;
|
|
64
70
|
type RequiredKeys<F extends Fields> = {
|
|
65
|
-
[K in keyof F]: K extends IdKeys<F> ? never : MetaOf<F[K]>["optional"] extends true ? never : MetaOf<F[K]>["hasDefault"] extends true ? never : MetaOf<F[K]>["kind"] extends "many" | "list" ? never : K;
|
|
71
|
+
[K in keyof F]: K extends IdKeys<F> ? never : MetaOf<F[K]>["optional"] extends true ? never : MetaOf<F[K]>["hasDefault"] extends true ? never : MetaOf<F[K]>["kind"] extends "many" | "list" ? never : MetaOf<F[K]>["kind"] extends "file" ? (MetaOf<F[K]>["array"] extends true ? never : K) : K;
|
|
66
72
|
}[keyof F];
|
|
67
73
|
type Simplify<T> = {
|
|
68
74
|
[K in keyof T]: T[K];
|
|
@@ -74,7 +80,7 @@ type InsertOf<S, F extends Fields> = Simplify<{
|
|
|
74
80
|
}>;
|
|
75
81
|
export type Insert<S, N extends keyof S> = InsertOf<S, FieldsOf<S[N]>>;
|
|
76
82
|
type StructInsert<S, F extends Fields> = InsertOf<S, F>;
|
|
77
|
-
type FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M["kind"] extends "many" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M["kind"] extends "list" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M["array"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;
|
|
83
|
+
type FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M["kind"] extends "many" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M["kind"] extends "list" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M["kind"] extends "file" ? Nullable<M, Arr<M, File | StoredFile>> : M["array"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;
|
|
78
84
|
type UpdateOf<S, F extends Fields> = {
|
|
79
85
|
[K in Exclude<keyof F, IdKeys<F>>]?: FieldUpdate<S, F[K]>;
|
|
80
86
|
};
|
|
@@ -87,7 +93,7 @@ type StructSelect<S, F extends Fields> = {
|
|
|
87
93
|
[K in keyof F]?: FieldSelect<S, F[K]>;
|
|
88
94
|
};
|
|
89
95
|
type ScalarWhere<T, M extends FieldMeta> = Nullable<M, CompareValue<T>> | (IsNum<M> extends true ? CompareNumValue<T> : M["scalar"] extends "string" ? CompareStrValue<T> : never);
|
|
90
|
-
type FieldWhere<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? CompareRefValue<Where<S, ModelName<S, Fld>> | null> : M["kind"] extends "many" | "list" ? CompareRefListValue<Where<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? CompareRefValue<WhereValue<StructWhereFields<S, StructFieldsOf<Fld>>> | null> : M["kind"] extends "json" ? JsonPathWhere | JsonCondition : M["array"] extends true ? TsOf<Fld>[] : ScalarWhere<TsOf<Fld>, M> | CustomSearchValue<FullTextSearch> | CustomSearchValue<VectorSearch>;
|
|
96
|
+
type FieldWhere<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? CompareRefValue<Where<S, ModelName<S, Fld>> | null> : M["kind"] extends "many" | "list" ? CompareRefListValue<Where<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? CompareRefValue<WhereValue<StructWhereFields<S, StructFieldsOf<Fld>>> | null> : M["kind"] extends "json" ? JsonPathWhere | JsonCondition : M["kind"] extends "file" ? never : M["array"] extends true ? TsOf<Fld>[] : ScalarWhere<TsOf<Fld>, M> | CustomSearchValue<FullTextSearch> | CustomSearchValue<VectorSearch>;
|
|
91
97
|
type WhereFieldsOf<S, F extends Fields> = {
|
|
92
98
|
[K in keyof F]?: FieldWhere<S, F[K]>;
|
|
93
99
|
};
|
|
@@ -96,7 +102,7 @@ type IdWhere<S, N extends keyof S> = {
|
|
|
96
102
|
};
|
|
97
103
|
export type Where<S, N extends keyof S> = WhereValue<WhereFieldsOf<S, FieldsOf<S[N]>> & IdWhere<S, N>>;
|
|
98
104
|
type StructWhereFields<S, F extends Fields> = WhereFieldsOf<S, F>;
|
|
99
|
-
type OrderKeys<S, N extends keyof S> = (
|
|
105
|
+
type OrderKeys<S, N extends keyof S> = (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>;
|
|
100
106
|
/** ONE field and its direction: the engine sorts by a single field, so a second key is a type error. */
|
|
101
107
|
export type Order<S, N extends keyof S> = {
|
|
102
108
|
[K in OrderKeys<S, N>]: {
|
|
@@ -118,8 +124,8 @@ export type AggregateQuery<S, N extends keyof S> = {
|
|
|
118
124
|
$count?: true;
|
|
119
125
|
$sum?: NumKeys<FieldsOf<S[N]>> & string;
|
|
120
126
|
$avg?: NumKeys<FieldsOf<S[N]>> & string;
|
|
121
|
-
$min?: (
|
|
122
|
-
$max?: (
|
|
127
|
+
$min?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;
|
|
128
|
+
$max?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;
|
|
123
129
|
};
|
|
124
130
|
/** The per-model type bag marcidb's generic `Query<T>` is parametrised by (what its codegen emits as `UserTypes`). */
|
|
125
131
|
export type Types<S, N extends keyof S> = {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The db layer's half of stored files (./models.ts): what turns a file FIELD — a value in a row — into
|
|
3
|
+
* operations on the platform's `File` model, and back.
|
|
4
|
+
*
|
|
5
|
+
* read the field is selected as the reverse relation it is (the `File` rows that point at the
|
|
6
|
+
* row, in order) and comes back as a `StoredFile`, or a list of them
|
|
7
|
+
* insert the row is inserted without the field; each upload's `File` row is then pointed at it
|
|
8
|
+
* (`ref` to the insert's id) — one transaction
|
|
9
|
+
* update the row's files that are no longer listed are deleted, the uploads are pointed at it —
|
|
10
|
+
* one transaction with the update itself
|
|
11
|
+
*
|
|
12
|
+
* An upload written to a `t.image()` field is first made a picture fit to show (the host's work,
|
|
13
|
+
* ./host.ts): that is why a plan is awaited. What it became — its type, its size — goes to its row
|
|
14
|
+
* in the operation that attaches it.
|
|
15
|
+
*
|
|
16
|
+
* A file is written from the FILE's side (its reference to the owner): that is the side the database
|
|
17
|
+
* cascades over. Only an upload of the current request is ever attached: a `StoredFile` the app hands
|
|
18
|
+
* back means "keep this one", and one of another row is not moved — a client that knows the url of
|
|
19
|
+
* someone else's file cannot take it.
|
|
20
|
+
*/
|
|
21
|
+
import type { MarciOp } from "../db/marci/query";
|
|
22
|
+
import { type FileField } from "./models";
|
|
23
|
+
type Plan = {
|
|
24
|
+
op: MarciOp;
|
|
25
|
+
after: MarciOp[];
|
|
26
|
+
};
|
|
27
|
+
export type FileLayer = {
|
|
28
|
+
/** The operation as the database runs it, and the ones that follow it in the same transaction.
|
|
29
|
+
* `index` is the operation's place in that transaction (what `ref` counts from). */
|
|
30
|
+
plan(op: MarciOp, index: number): Promise<Plan>;
|
|
31
|
+
/** The database's answer to a planned operation, as the project reads it. */
|
|
32
|
+
result(op: MarciOp, value: any): any;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* `fields`: the schema's `t.file()` fields. `relations`: model → relation field → its target model.
|
|
36
|
+
* `scalars`: model → what a query without a selection returns (file fields included).
|
|
37
|
+
*/
|
|
38
|
+
export declare const createFileLayer: (fields: FileField[], relations: Record<string, Record<string, string>>, scalars: Record<string, string[]>) => FileLayer;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stored files: `t.file()` on a model.
|
|
3
|
+
*
|
|
4
|
+
* A project never declares where a file lives. A model that has a `t.file()` field makes the db carry
|
|
5
|
+
* one more model, the PLATFORM's `File` — a row per stored file: what it is (name, type, size, an
|
|
6
|
+
* image's dimensions) and whose it is. The owner is a reference FROM the file TO its row, with
|
|
7
|
+
* `onDelete("cascade")`, one optional reference per `t.file()` field of the schema (`postImage`,
|
|
8
|
+
* `userAvatar`): deleting a post — by name, or because its author was deleted — deletes its files in
|
|
9
|
+
* the same transaction, by the database's own rule. The field on the owner is the reverse side of
|
|
10
|
+
* that reference.
|
|
11
|
+
*
|
|
12
|
+
* The bytes are the host's (./host.ts): a file on disk named by the row's id. They go only because
|
|
13
|
+
* the row went — the host reads the deletions from marcidb's journal of this model.
|
|
14
|
+
*
|
|
15
|
+
* What a project sees is a VALUE: it writes a `File` (an upload, an endpoint's parameter) and reads a
|
|
16
|
+
* `StoredFile`. The url is computed when the row is read, never stored.
|
|
17
|
+
*/
|
|
18
|
+
import { type Field } from "../db/fields";
|
|
19
|
+
export declare const FILE_MODEL = "File";
|
|
20
|
+
/** A stored file as a project reads it. */
|
|
21
|
+
export type StoredFile = {
|
|
22
|
+
/** Where the bytes are served from. Public, not guessable; it never changes for this file. */
|
|
23
|
+
url: string;
|
|
24
|
+
name: string;
|
|
25
|
+
/** The media type: `image/jpeg`, `video/mp4`, `application/pdf`. */
|
|
26
|
+
type: string;
|
|
27
|
+
/** Bytes. */
|
|
28
|
+
size: number;
|
|
29
|
+
/** An image's dimensions in pixels (absent for anything else). */
|
|
30
|
+
width?: number;
|
|
31
|
+
height?: number;
|
|
32
|
+
};
|
|
33
|
+
/** A stored picture (`t.image()`): its size is always known. */
|
|
34
|
+
export type StoredImage = StoredFile & {
|
|
35
|
+
width: number;
|
|
36
|
+
height: number;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* A file as an endpoint receives it — the app's `File` (a picked file, a photo), uploaded with the
|
|
40
|
+
* call. Written to a `t.file()` field, it is stored; an endpoint that writes it nowhere drops it.
|
|
41
|
+
*/
|
|
42
|
+
export type UploadedFile = {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly size: number;
|
|
45
|
+
readonly type: string;
|
|
46
|
+
};
|
|
47
|
+
/** One `t.file()` field of the schema; `image` = it is a `t.image()`, with its rule. */
|
|
48
|
+
export type FileField = {
|
|
49
|
+
model: string;
|
|
50
|
+
key: string;
|
|
51
|
+
array: boolean;
|
|
52
|
+
owner: string;
|
|
53
|
+
image?: ImageRule;
|
|
54
|
+
};
|
|
55
|
+
export type ImageRule = {
|
|
56
|
+
max: number;
|
|
57
|
+
};
|
|
58
|
+
/** What a file became when it was made fit for an image field: the facts its row carries from then on. */
|
|
59
|
+
export type ImageFacts = {
|
|
60
|
+
name: string;
|
|
61
|
+
type: string;
|
|
62
|
+
size: number;
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
};
|
|
66
|
+
/** The reference on `File` that says "I am this field of that row": `Post.image` → `postImage`. */
|
|
67
|
+
export declare const fileOwnerKey: (model: string, key: string) => string;
|
|
68
|
+
/** What a data browser may show of a file (the rest is the platform's bookkeeping). */
|
|
69
|
+
export declare const filePublicFields: () => {
|
|
70
|
+
name: Field<string, import("../db/fields").Meta<{
|
|
71
|
+
kind: "scalar";
|
|
72
|
+
scalar: "string";
|
|
73
|
+
}>>;
|
|
74
|
+
type: Field<string, import("../db/fields").Meta<{
|
|
75
|
+
kind: "scalar";
|
|
76
|
+
scalar: "string";
|
|
77
|
+
}>>;
|
|
78
|
+
size: Field<number, import("../db/fields").Meta<{
|
|
79
|
+
kind: "scalar";
|
|
80
|
+
scalar: "int";
|
|
81
|
+
}>>;
|
|
82
|
+
width: Field<number, {
|
|
83
|
+
kind: "scalar";
|
|
84
|
+
scalar: "int";
|
|
85
|
+
optional: true;
|
|
86
|
+
hasDefault: false;
|
|
87
|
+
array: false;
|
|
88
|
+
isId: false;
|
|
89
|
+
model: "";
|
|
90
|
+
}>;
|
|
91
|
+
height: Field<number, {
|
|
92
|
+
kind: "scalar";
|
|
93
|
+
scalar: "int";
|
|
94
|
+
optional: true;
|
|
95
|
+
hasDefault: false;
|
|
96
|
+
array: false;
|
|
97
|
+
isId: false;
|
|
98
|
+
model: "";
|
|
99
|
+
}>;
|
|
100
|
+
createdAt: Field<number, {
|
|
101
|
+
kind: "scalar";
|
|
102
|
+
scalar: "date";
|
|
103
|
+
optional: false;
|
|
104
|
+
hasDefault: true;
|
|
105
|
+
array: false;
|
|
106
|
+
isId: false;
|
|
107
|
+
model: "";
|
|
108
|
+
}>;
|
|
109
|
+
};
|
|
110
|
+
/** The whole `File` of a schema with these `t.file()` fields. */
|
|
111
|
+
export declare const fileFields: (fields: FileField[]) => Record<string, Field<any, any>>;
|
|
112
|
+
/**
|
|
113
|
+
* What the host (./host.ts) gives the db layer of a bundle — a global, because the bundle carries its
|
|
114
|
+
* own copy of this module. Absent (a unit test without a host): nothing is an upload, urls are relative.
|
|
115
|
+
*/
|
|
116
|
+
export type FilesSeam = {
|
|
117
|
+
/** The id of the `File` row behind an upload of the current request; undefined for anything else —
|
|
118
|
+
* a value the app sent as JSON is never an upload, whatever it looks like. */
|
|
119
|
+
uploaded(value: unknown): string | undefined;
|
|
120
|
+
url(id: string, name: string): string;
|
|
121
|
+
/** Make the upload `id` fit for a `t.image()` field (its bytes are rewritten in place) and say what
|
|
122
|
+
* it is now. Throws an `ApiError` for what is no picture. */
|
|
123
|
+
image(id: string, rule: ImageRule): Promise<ImageFacts>;
|
|
124
|
+
/** A write that may have removed rows of `File` went through the db (a delete, a rewritten file field): their bytes are due. */
|
|
125
|
+
dirty: boolean;
|
|
126
|
+
};
|
|
127
|
+
export declare const filesSeam: () => FilesSeam | undefined;
|
|
128
|
+
export declare const setFilesSeam: (value: FilesSeam | null) => void;
|
|
129
|
+
/** The row a `StoredFile` the app handed back stands for (by its url); undefined for anything else. */
|
|
130
|
+
export declare const storedFileId: (value: unknown) => string | undefined;
|
|
131
|
+
export declare const fileUrl: (id: string, name: string) => string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type UIWidgetContent } from "./UILayer";
|
|
1
2
|
import { type DismissOptions, type PresentOptions } from "./presentable";
|
|
2
3
|
import { type BaseStyle, type DrawableStyle, type ElementStyle, type UIElementBase } from "./UINode";
|
|
3
4
|
export type UINativeViewStyle = ElementStyle & DrawableStyle;
|
|
@@ -26,6 +27,8 @@ export interface NativeView extends UIElementBase<UINativeViewStyle, DrawableSty
|
|
|
26
27
|
/** Subscribe to an event the native view emits (`map.on("markerTap", cb)`). */
|
|
27
28
|
on(event: string, callback: (data?: any) => void): this;
|
|
28
29
|
off(event: string, callback: (data?: any) => void): this;
|
|
30
|
+
/** The UI over the view when presented: widgets over it (`Presentable.setContent`). */
|
|
31
|
+
setContent(content: UIWidgetContent): this;
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
34
|
* Create an instance of a host-registered platform view. `NativeView.isSupported(name)` reports
|
package/dist/types/ui/UI.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { UIImage, type UIImageStyle } from './UIImage';
|
|
|
7
7
|
export { UIVideo, type UIVideoStyle } from './UIVideo';
|
|
8
8
|
export { UIInput, UITextArea, type UIInputStyle } from './UIInput';
|
|
9
9
|
export { UIWidget, type UIWidgetStyle } from './UIWidget';
|
|
10
|
+
export { UIOverlay, type UIWidgetContent } from './UILayer';
|
|
10
11
|
export { UIModal, type UIModalStyle } from './UIModal';
|
|
11
12
|
export { UIBottomSheet, type UIBottomSheetStyle } from './UIBottomSheet';
|
|
12
13
|
export { UIPopover, type UIPopoverStyle, type UIPopoverAnchor } from './UIPopover';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UIWidget } from "./UIWidget";
|
|
2
|
+
export type UIWidgetContent = (UIWidget | null | undefined | false)[] | (() => (UIWidget | null | undefined | false)[]);
|
|
3
|
+
/**
|
|
4
|
+
* The app layer: the widgets above EVERY destination, always shown — a global loader, a mini-player
|
|
5
|
+
* that follows the user across screens, a toast with actions. Widgets that belong to a place go in
|
|
6
|
+
* that place instead: a dialog among its screen's children (`UIScreen(..., dialog)`), a HUD in
|
|
7
|
+
* `scene.setContent([hud])`. A widget shown with `show()` while it has no parent lands here.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* UIOverlay.append(miniPlayer)
|
|
11
|
+
* miniPlayer.hide() // display: none — still here, ready for show()
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const UIOverlay: Readonly<{
|
|
15
|
+
/** Add widgets at the end (on top). */
|
|
16
|
+
append(...widgets: (UIWidget | null | undefined | false)[]): void;
|
|
17
|
+
/** Insert widgets at `index` (0 = the bottom of the layer). */
|
|
18
|
+
insert(index: number, ...widgets: (UIWidget | null | undefined | false)[]): void;
|
|
19
|
+
/** Take widgets out of the layer (they stay valid; a dropped one is freed). */
|
|
20
|
+
remove(...widgets: (UIWidget | null | undefined | false)[]): void;
|
|
21
|
+
/** Replace the layer's widgets — a list, or a function for reactive content. */
|
|
22
|
+
setContent(content: UIWidgetContent): void;
|
|
23
|
+
/** The layer's widgets, bottom to top (a snapshot read from the runtime). */
|
|
24
|
+
readonly children: UIWidget[];
|
|
25
|
+
}>;
|