@moku-labs/game 0.0.1 → 0.0.2
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 +424 -37
- package/dist/assets.d.mts +161 -0
- package/dist/assets.mjs +4729 -0
- package/dist/component-DGg5DqKK.mjs +44 -0
- package/dist/control.d.mts +162 -0
- package/dist/control.mjs +758 -0
- package/dist/define-sFoO3y6X.d.mts +263 -0
- package/dist/headless-CvamCUcR.mjs +186 -0
- package/dist/headless-KaSWcd0s.d.mts +181 -0
- package/dist/index.d.mts +1204 -50
- package/dist/index.mjs +20978 -2010
- package/dist/inspect.d.mts +109 -0
- package/dist/inspect.mjs +519 -0
- package/dist/jsx-dev-runtime.d.mts +2 -0
- package/dist/jsx-dev-runtime.mjs +2 -0
- package/dist/jsx-runtime.d.mts +2 -0
- package/dist/jsx-runtime.mjs +2 -0
- package/dist/memory-CvgdnsQO.mjs +259 -0
- package/dist/registry-DlpRCibU.mjs +384 -0
- package/dist/runtime-DRlwxkIv.mjs +182 -0
- package/dist/runtime-DiOTkDZz.d.mts +77 -0
- package/dist/session-DmAxY6Ll.mjs +145 -0
- package/dist/testing.d.mts +23 -111
- package/dist/testing.mjs +12 -289
- package/dist/types-BxkNNYul.d.mts +2840 -0
- package/dist/types-CTPS9GBu.d.mts +742 -0
- package/dist/types-DD-QrG_z.d.mts +588 -0
- package/dist/types-DWILGrPn.d.mts +622 -0
- package/dist/types-DYLnSgMI.d.mts +570 -0
- package/dist/types-JNc_UQBo.d.mts +2896 -0
- package/dist/types-yg_ywtT-.d.mts +1859 -0
- package/dist/visual-BDUHSRvf.mjs +734 -0
- package/package.json +26 -4
- package/dist/registry-DWV5C0Mf.mjs +0 -666
- package/dist/types-BfsmUzLC.d.mts +0 -1908
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
import { k as Api, lt as Require, t as Api$1 } from "./types-JNc_UQBo.mjs";
|
|
2
|
+
import { D as AnyComponent, N as Entity, t as Api$3, u as Api$2 } from "./types-BxkNNYul.mjs";
|
|
3
|
+
import { o as Events, t as Api$4 } from "./types-DWILGrPn.mjs";
|
|
4
|
+
import { F as Events$1, H as InputApi, I as I18nApi, L as Message, c as UiNode, i as Finding, n as ElementChange, o as JsxState, r as ElementMotion, v as StylesState } from "./types-yg_ywtT-.mjs";
|
|
5
|
+
import { Log } from "@moku-labs/common/browser";
|
|
6
|
+
import { PluginCtx } from "@moku-labs/core";
|
|
7
|
+
import { Node, Yoga } from "yoga-layout/load";
|
|
8
|
+
|
|
9
|
+
//#region src/plugins/text/types.d.ts
|
|
10
|
+
declare namespace types_d_exports$1 {
|
|
11
|
+
export { AdvanceTable, BundleLoaded, BundleUnloaded, Config$1 as Config, Deps$1 as Deps, DrawnLabel, IconRun, KernelSlice$1 as KernelSlice, LayoutOptions, Line, LocaleChanged, Point, Run, SeenText, Size, State$1 as State, TextAlign, TextApi, TextBind, TextCtx, TextLayout, TextRun, TextShadow, TextStyle, TextStyleInput, TextStyles, TextValue, TextWrap, Warn };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A point in reference units: where a label sits, and which point of the block sits there.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const anchor: Point = { x: 0.5, y: 0.5 };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
type Point = {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The size of a measured block, in reference pixels.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const size: Size = { width: 57.6, height: 38.4 };
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
type Size = {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Which numeric component field a label shows. The component is named, not imported: a HUD is
|
|
39
|
+
* written before the game's components are in scope.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const bind: TextBind = { component: "Counter", field: "value" };
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
type TextBind = {
|
|
47
|
+
component: string;
|
|
48
|
+
field: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* What the `Text` component holds. `resolved` is engine-owned: a game writes `content`, `style`,
|
|
52
|
+
* `bind` and `anchor`, and reads `resolved`.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const value: TextValue = {
|
|
57
|
+
* content: "+5", style: "body", bind: undefined, anchor: { x: 0.5, y: 0.5 }, resolved: "+5"
|
|
58
|
+
* };
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
type TextValue = {
|
|
62
|
+
content: string | Message;
|
|
63
|
+
style: string;
|
|
64
|
+
bind: TextBind | undefined;
|
|
65
|
+
anchor: Point;
|
|
66
|
+
resolved: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Where the lines of a block sit inside the widest of them.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* const align: TextAlign = "center";
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
type TextAlign = "left" | "center" | "right";
|
|
77
|
+
/**
|
|
78
|
+
* The wrap width of a style in reference pixels, or `"none"` for one line per `\n` segment.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const wrap: TextWrap = 480;
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
type TextWrap = number | "none";
|
|
86
|
+
/**
|
|
87
|
+
* The drop shadow of a style as the plugin stores it: a copy of every glyph run in `color`, at
|
|
88
|
+
* `alpha`, moved by `dx` and `dy` reference pixels.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const shadow: TextShadow = { color: 0x5b3a1e, dx: 0, dy: 4, alpha: 1 };
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
type TextShadow = {
|
|
96
|
+
color: number;
|
|
97
|
+
dx: number;
|
|
98
|
+
dy: number;
|
|
99
|
+
alpha: number;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* One style as a game writes it: the font and the size are required, the rest has defaults.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* // A popup title: cream display glyphs over a brown shadow 4 px down.
|
|
107
|
+
* const title: TextStyleInput = {
|
|
108
|
+
* font: "ui.font-display", size: 56, fill: 0xfff3d6, shadow: { color: 0x5b3a1e, dx: 0, dy: 4 }
|
|
109
|
+
* };
|
|
110
|
+
*
|
|
111
|
+
* defineTextStyles({ "popup.title": title }).map["popup.title"]?.shadow;
|
|
112
|
+
* // { color: 0x5b3a1e, dx: 0, dy: 4, alpha: 1 }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
type TextStyleInput = {
|
|
116
|
+
font: string;
|
|
117
|
+
bold?: string;
|
|
118
|
+
italic?: string;
|
|
119
|
+
size: number;
|
|
120
|
+
fill: number; /** The outline colour. Drawn only when `strokeWidth` is above 0. */
|
|
121
|
+
stroke?: number;
|
|
122
|
+
/**
|
|
123
|
+
* The outline width in reference px: 8 copies of each glyph run on a circle this wide (12 from 6
|
|
124
|
+
* on), tinted `stroke`. 0 draws none. It never changes what `measure` answers.
|
|
125
|
+
*/
|
|
126
|
+
strokeWidth?: number;
|
|
127
|
+
letterSpacing?: number;
|
|
128
|
+
align?: TextAlign;
|
|
129
|
+
wrap?: TextWrap;
|
|
130
|
+
digits?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* A drop shadow under every glyph run, in reference px at the style size. `alpha` is 1 when
|
|
133
|
+
* left out. It never changes what `measure` answers.
|
|
134
|
+
*/
|
|
135
|
+
shadow?: {
|
|
136
|
+
color: number;
|
|
137
|
+
dx: number;
|
|
138
|
+
dy: number;
|
|
139
|
+
alpha?: number;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* One style as the plugin stores it: every field filled, `bold` and `italic` only when the game
|
|
144
|
+
* shipped those MSDF fonts, `shadow` only when the style has one.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const style: TextStyle = {
|
|
149
|
+
* font: "ui.font-body", bold: undefined, italic: undefined, size: 32, fill: 0xffffff,
|
|
150
|
+
* stroke: 0x000000, strokeWidth: 0, letterSpacing: 0, align: "left", wrap: "none",
|
|
151
|
+
* digits: false, shadow: undefined
|
|
152
|
+
* };
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
type TextStyle = {
|
|
156
|
+
font: string;
|
|
157
|
+
bold: string | undefined;
|
|
158
|
+
italic: string | undefined;
|
|
159
|
+
size: number;
|
|
160
|
+
fill: number;
|
|
161
|
+
stroke: number;
|
|
162
|
+
strokeWidth: number;
|
|
163
|
+
letterSpacing: number;
|
|
164
|
+
align: TextAlign;
|
|
165
|
+
wrap: TextWrap;
|
|
166
|
+
digits: boolean;
|
|
167
|
+
shadow: TextShadow | undefined;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* What `defineTextStyles` returns and a feature registers under its `textStyles` key. Structural
|
|
171
|
+
* on purpose: `flow` carries the map, `text` reads it.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const styles: TextStyles = { kind: "textStyles", map: { "hud.title": bodyStyle } };
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
type TextStyles = {
|
|
179
|
+
readonly kind: "textStyles";
|
|
180
|
+
readonly map: Record<string, TextStyle>;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* The advances of one font at the size the `.fnt` was exported with. Widths scale by
|
|
184
|
+
* `style.size / size`; kerning pairs are ignored.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* const table: AdvanceTable = { size: 32, lineHeight: 40, advances: new Map([["1", 18]]) };
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
type AdvanceTable = {
|
|
192
|
+
size: number;
|
|
193
|
+
lineHeight: number;
|
|
194
|
+
advances: Map<string, number>;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* One run of glyphs: the text and the flags every glyph in it shares.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const run: TextRun = { kind: "text", text: "+5", bold: true, italic: false, color: 0xffe082 };
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
type TextRun = {
|
|
205
|
+
kind: "text";
|
|
206
|
+
text: string;
|
|
207
|
+
bold: boolean;
|
|
208
|
+
italic: boolean;
|
|
209
|
+
color: number | undefined;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* One inline icon: an asset key drawn square at the line height.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* const run: IconRun = { kind: "icon", key: "hud.coin" };
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
type IconRun = {
|
|
220
|
+
kind: "icon";
|
|
221
|
+
key: string;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* A piece of a line: glyphs or one inline icon.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* const runs: Run[] = [{ kind: "icon", key: "hud.coin" }];
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
type Run = TextRun | IconRun;
|
|
232
|
+
/**
|
|
233
|
+
* One laid-out line and how wide it is.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* const line: Line = { runs: [{ kind: "icon", key: "hud.coin" }], width: 38.4 };
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
type Line = {
|
|
241
|
+
runs: Run[];
|
|
242
|
+
width: number;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* A laid-out block: its lines and the size `measure` answers with.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const layout: TextLayout = { lines: [], width: 0, height: 0 };
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
type TextLayout = {
|
|
253
|
+
lines: Line[];
|
|
254
|
+
width: number;
|
|
255
|
+
height: number;
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* What one label container was last filled from: the style object and the laid-out block. An
|
|
259
|
+
* update with the same style object, the same anchor and the same lines and runs writes the new
|
|
260
|
+
* text and positions into the objects already there.
|
|
261
|
+
*/
|
|
262
|
+
type DrawnLabel = {
|
|
263
|
+
style: TextStyle;
|
|
264
|
+
layout: TextLayout;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* A dev warning that is written once per key. Pure modules take it as an argument, so nothing
|
|
268
|
+
* below the plugin context reaches the log itself.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```ts
|
|
272
|
+
* const warn: Warn = (key, message) => seen.has(key) || log.warn(message);
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
type Warn = (key: string, message: string, data?: Record<string, unknown>) => void;
|
|
276
|
+
/**
|
|
277
|
+
* What the pure layout needs next to the runs, the style and the tables.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* const options: LayoutOptions = { missingGlyph: "□", warn: () => undefined };
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
type LayoutOptions = {
|
|
285
|
+
missingGlyph: string;
|
|
286
|
+
warn: Warn;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* What was resolved for one entity last, so the frame step knows whether anything moved.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```ts
|
|
293
|
+
* const seen: SeenText = { content: "+5", style: "body", bind: undefined, locale: "ru" };
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
type SeenText = {
|
|
297
|
+
content: unknown;
|
|
298
|
+
style: string;
|
|
299
|
+
bind: string | undefined;
|
|
300
|
+
locale: string;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* text plugin config.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```ts
|
|
307
|
+
* createApp({ pluginConfigs: { text: { fonts: { body: "ui.body", digits: "ui.digits" } } } });
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
type Config$1 = {
|
|
311
|
+
/** The two fonts every game ships in its boot bundle. They back the built-in styles. */fonts: {
|
|
312
|
+
body: string;
|
|
313
|
+
digits: string;
|
|
314
|
+
}; /** Drawn and measured for a character the font does not have. */
|
|
315
|
+
missingGlyph: string;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* text plugin state.
|
|
319
|
+
*/
|
|
320
|
+
type State$1 = {
|
|
321
|
+
/** Built-in styles first, then the styles of every feature in feature order. */styles: Map<string, TextStyle>; /** Style name to the feature that brought it, for the duplicate error. */
|
|
322
|
+
styleOwner: Map<string, string>; /** The config fonts plus every `font`, `bold` and `italic` of every style. */
|
|
323
|
+
fontKeys: Set<string>; /** The parsed advance table per font key, filled when `assets` has the font. */
|
|
324
|
+
tables: Map<string, AdvanceTable>; /** The font keys handed to `renderer.sync.fonts.install`. */
|
|
325
|
+
installed: Set<string>; /** What was resolved for an entity last. */
|
|
326
|
+
seen: Map<Entity, SeenText>; /** `bind.component` to its world type; `undefined` after the one warning. */
|
|
327
|
+
bindTypes: Map<string, AnyComponent | undefined>; /** The measured size of every live label, for `ui`. */
|
|
328
|
+
measured: Map<Entity, Size>; /** Layout per `style + resolved`, oldest dropped first. */
|
|
329
|
+
cache: Map<string, TextLayout>; /** What every live label container was last filled from, by container. */
|
|
330
|
+
drawn: WeakMap<object, DrawnLabel>; /** Entities to re-resolve in the next layout phase. */
|
|
331
|
+
dirty: Set<Entity>; /** Warning keys already written, so a style, a tag, a glyph or a font warns once. */
|
|
332
|
+
warned: Set<string>; /** The system, the two world hooks and the display adapter. */
|
|
333
|
+
removers: Array<() => void>;
|
|
334
|
+
};
|
|
335
|
+
/**
|
|
336
|
+
* text plugin API, `app.text`. Two questions: how big a piece of text is, and which styles the
|
|
337
|
+
* game registered. Everything else happens in the frame.
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* ```ts
|
|
341
|
+
* app.text.measure("120", "digits"); // { width: 57.6, height: 38.4 }
|
|
342
|
+
* app.text.styles(); // ["body", "digits"]
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
type TextApi = {
|
|
346
|
+
/**
|
|
347
|
+
* The size of a piece of text in reference pixels, from the advance table of the style's font.
|
|
348
|
+
* A `Message` is formatted in the current locale first. Never touches a canvas, so the answer
|
|
349
|
+
* is the same in a browser and in plain Bun. Cached per style and resolved string.
|
|
350
|
+
*
|
|
351
|
+
* @param content - A plain string, or what `tr` returned.
|
|
352
|
+
* @param style - A registered style name. An unknown one warns once and measures as `body`.
|
|
353
|
+
* @returns The width and height of the block.
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* // `ui.layout` asks once per invalidation, from the Yoga measure function of a text element.
|
|
357
|
+
* const text = ctx.require(textPlugin);
|
|
358
|
+
*
|
|
359
|
+
* text.measure("120", "digits"); // { width: 57.6, height: 38.4 } on the 0.6 em fallback
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
measure(content: string | Message, style: string): Size;
|
|
363
|
+
/**
|
|
364
|
+
* The registered style names: the two built-ins first, then the styles of every feature in
|
|
365
|
+
* feature order.
|
|
366
|
+
*
|
|
367
|
+
* @returns A frozen list of style names.
|
|
368
|
+
* @example
|
|
369
|
+
* ```ts
|
|
370
|
+
* // A dev overlay lists what a game may write in a `style` prop.
|
|
371
|
+
* app.text.styles(); // ["body", "digits", "hud.digits"]
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
styles(): readonly string[];
|
|
375
|
+
};
|
|
376
|
+
/**
|
|
377
|
+
* Resolved dependency APIs.
|
|
378
|
+
*/
|
|
379
|
+
type Deps$1 = {
|
|
380
|
+
time: Api;
|
|
381
|
+
flow: Api$1;
|
|
382
|
+
world: Api$2;
|
|
383
|
+
renderer: Api$3;
|
|
384
|
+
assets: Api$4;
|
|
385
|
+
i18n: I18nApi;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* What the kernel context offers before the deps are attached.
|
|
389
|
+
*
|
|
390
|
+
* `text` owns no event, so `emit` is the kernel's and never called here.
|
|
391
|
+
*/
|
|
392
|
+
type KernelSlice$1 = PluginCtx<Config$1, State$1> & {
|
|
393
|
+
readonly global: object;
|
|
394
|
+
readonly log: Log.LogApi;
|
|
395
|
+
readonly require: Require;
|
|
396
|
+
};
|
|
397
|
+
/**
|
|
398
|
+
* Domain context shared by the files of the plugin: the kernel slice plus the resolved deps.
|
|
399
|
+
*/
|
|
400
|
+
type TextCtx = KernelSlice$1 & {
|
|
401
|
+
readonly deps: Deps$1;
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* Payload of the `assets:bundle-loaded` hook: a bundle landed, so a font may be readable now.
|
|
405
|
+
*/
|
|
406
|
+
type BundleLoaded = Events["assets:bundle-loaded"];
|
|
407
|
+
/**
|
|
408
|
+
* Payload of the `assets:bundle-unloaded` hook: `keys` names the assets that left.
|
|
409
|
+
*/
|
|
410
|
+
type BundleUnloaded = Events["assets:bundle-unloaded"];
|
|
411
|
+
/**
|
|
412
|
+
* Payload of the `i18n:locale-changed` hook: every message has to be resolved again.
|
|
413
|
+
*/
|
|
414
|
+
type LocaleChanged = Events$1["i18n:locale-changed"];
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/plugins/ui/layout/types.d.ts
|
|
417
|
+
/**
|
|
418
|
+
* layout module state. `nodes` is attach minus detach: Yoga 3.2.1 has no instance counter.
|
|
419
|
+
*/
|
|
420
|
+
type LayoutState = {
|
|
421
|
+
yoga: Yoga | undefined;
|
|
422
|
+
byEntity: Map<Entity, Node>;
|
|
423
|
+
nodes: number;
|
|
424
|
+
measured: number;
|
|
425
|
+
solves: number;
|
|
426
|
+
scrolling: Entity | undefined;
|
|
427
|
+
scrollStart: {
|
|
428
|
+
pointerY: number;
|
|
429
|
+
offset: number;
|
|
430
|
+
};
|
|
431
|
+
order: number;
|
|
432
|
+
cleanups: Array<() => void>;
|
|
433
|
+
};
|
|
434
|
+
declare namespace types_d_exports {
|
|
435
|
+
export { Config, Deps, ElementChange, ElementMotion, Finding, FocusRing, KernelSlice, State, UiApi, UiCtx, UiNode };
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* The look of the keyboard focus ring: a dashed ring with a solid halo under it, drawn around the
|
|
439
|
+
* focused control. Colours are `0xRRGGBB`, lengths reference units.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* // A dashed ink ring with a cream halo, 9 u outside the control.
|
|
444
|
+
* const ring: FocusRing = {
|
|
445
|
+
* stroke: 0x3a2212, strokeWidth: 4, dash: 10, offset: 9, halo: 0xfff3d6, haloWidth: 12
|
|
446
|
+
* };
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
449
|
+
type FocusRing = {
|
|
450
|
+
/** The colour of the dashed ring. */stroke: number; /** The stroke width of the dashed ring. */
|
|
451
|
+
strokeWidth: number; /** The dash length of the ring, with gaps of half a dash; 0 draws it solid. */
|
|
452
|
+
dash: number; /** How far outside the control's rect the ring runs, on every side. */
|
|
453
|
+
offset: number; /** The colour of the solid halo drawn under the ring. */
|
|
454
|
+
halo: number; /** The stroke width of the halo, centred on the same path as the ring. */
|
|
455
|
+
haloWidth: number;
|
|
456
|
+
};
|
|
457
|
+
/**
|
|
458
|
+
* ui plugin config.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* ```ts
|
|
462
|
+
* createApp({ pluginConfigs: { ui: { tapTargetPt: 48, breakpoints: { tall: 2, wide: 1.5 } } } });
|
|
463
|
+
* // A game with a white focus ring on a dark board.
|
|
464
|
+
* createApp({
|
|
465
|
+
* pluginConfigs: {
|
|
466
|
+
* ui: {
|
|
467
|
+
* focusRing: {
|
|
468
|
+
* stroke: 0xffffff, strokeWidth: 4, dash: 10, offset: 9, halo: 0x000000, haloWidth: 12
|
|
469
|
+
* }
|
|
470
|
+
* }
|
|
471
|
+
* }
|
|
472
|
+
* });
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
475
|
+
type Config = {
|
|
476
|
+
/** Smallest tap target `lint()` accepts, in CSS px (points). */tapTargetPt: number; /** `when` flags: `tall` when height / width is at least `tall`, `wide` the other way round. */
|
|
477
|
+
breakpoints: {
|
|
478
|
+
tall: number;
|
|
479
|
+
wide: number;
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* The ring drawn around the control the keyboard focused. Shallow merge: a game that sets
|
|
483
|
+
* `focusRing` gives all six fields.
|
|
484
|
+
*/
|
|
485
|
+
focusRing: FocusRing;
|
|
486
|
+
};
|
|
487
|
+
/**
|
|
488
|
+
* ui plugin state: one branch per module.
|
|
489
|
+
*/
|
|
490
|
+
type State = {
|
|
491
|
+
jsx: JsxState;
|
|
492
|
+
styles: StylesState;
|
|
493
|
+
layout: LayoutState;
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* Resolved dependency APIs. `anim` is not here: its edge is validation only, and its work
|
|
497
|
+
* reaches `ui` through the tween driver behind every `ViewHandle`.
|
|
498
|
+
*/
|
|
499
|
+
type Deps = {
|
|
500
|
+
time: Api;
|
|
501
|
+
flow: Api$1;
|
|
502
|
+
world: Api$2;
|
|
503
|
+
renderer: Api$3;
|
|
504
|
+
input: InputApi;
|
|
505
|
+
i18n: I18nApi;
|
|
506
|
+
text: TextApi;
|
|
507
|
+
};
|
|
508
|
+
/**
|
|
509
|
+
* What the kernel context offers before the deps are attached.
|
|
510
|
+
*
|
|
511
|
+
* `ui` owns no event, so `emit` is the kernel's and never called here.
|
|
512
|
+
*/
|
|
513
|
+
type KernelSlice = PluginCtx<Config, State> & {
|
|
514
|
+
readonly global: object;
|
|
515
|
+
readonly log: Log.LogApi;
|
|
516
|
+
readonly require: Require;
|
|
517
|
+
};
|
|
518
|
+
/**
|
|
519
|
+
* Domain context shared by the three modules: the kernel slice plus the resolved deps.
|
|
520
|
+
*/
|
|
521
|
+
type UiCtx = KernelSlice & {
|
|
522
|
+
readonly deps: Deps;
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* ui plugin API, `app.ui`. The screen is one more projection, so the three members read it the
|
|
526
|
+
* way a test reads the board: a snapshot, a key lookup and a list of findings.
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```ts
|
|
530
|
+
* // A headless scenario taps the claim button of the reward popup.
|
|
531
|
+
* app.ui.tree().type; // "row", the root element of the HUD
|
|
532
|
+
* app.input.tap(app.ui.find("claim") ?? 0);
|
|
533
|
+
* app.ui.lint(); // []
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
type UiApi = {
|
|
537
|
+
/**
|
|
538
|
+
* The live screen as plain data: every root in layer order, every element in child order, with
|
|
539
|
+
* its rect in root coordinates, its resolved style and its seven state flags. A rect is natural:
|
|
540
|
+
* under a `fit: "contain"` element it is the rect before that scale, and the fitted element
|
|
541
|
+
* adds `fitScale`. Works headless.
|
|
542
|
+
*
|
|
543
|
+
* @returns The root node; several roots come back under one `screen` node.
|
|
544
|
+
* @example
|
|
545
|
+
* ```ts
|
|
546
|
+
* // A snapshot test reads the HUD without a browser.
|
|
547
|
+
* app.ui.tree().children.map(child => child.key); // ["coins", "settings", "order"]
|
|
548
|
+
* // On an iPhone SE the board slot is drawn at 0.8 of its 970 u.
|
|
549
|
+
* app.ui.tree().children[3]?.fitScale; // 0.8
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
tree(): UiNode;
|
|
553
|
+
/**
|
|
554
|
+
* The entity of a keyed element, so a test can tap it and `anim` can aim at it. Popup roots
|
|
555
|
+
* come first, then the projection roots in layer order.
|
|
556
|
+
*
|
|
557
|
+
* @param key - The `key` prop of the element.
|
|
558
|
+
* @returns The entity, or `undefined` for an unknown or exiting element.
|
|
559
|
+
* @example
|
|
560
|
+
* ```ts
|
|
561
|
+
* // A headless scenario answers the gate through the button of the popup.
|
|
562
|
+
* app.input.tap(app.ui.find("claim") ?? 0); // true
|
|
563
|
+
* app.ui.find("nothing"); // undefined
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
566
|
+
find(key: string): Entity | undefined;
|
|
567
|
+
/**
|
|
568
|
+
* Reads the live screen against the five rules: a tap target under `tapTargetPt` at the size
|
|
569
|
+
* it is drawn (a `fit: "contain"` on it or above it shrinks it), a text that does not fit its
|
|
570
|
+
* box in some registered locale, an absolute element with no `reason`, a clipping element
|
|
571
|
+
* (`scroll`, `overflow: "hidden"`) whose style names a nine-slice it never draws, and a root
|
|
572
|
+
* element whose style sets a `zIndex` it ignores. Never throws; empty when nothing is mounted.
|
|
573
|
+
*
|
|
574
|
+
* @returns One finding per rule and element.
|
|
575
|
+
* @example
|
|
576
|
+
* ```ts
|
|
577
|
+
* // A game test keeps the board honest on an iPhone SE: a 140 u cell in the 0.8 slot.
|
|
578
|
+
* app.ui.lint(); // [{ rule: "tap-target", key: "cell", detail: "39 x 39 pt" }]
|
|
579
|
+
* // A list styled with a nine-slice: the clip keeps it from drawing.
|
|
580
|
+
* app.ui.lint(); // [{ rule: "nine-slice-clipped", key: "orders", detail: "scroll" }]
|
|
581
|
+
* // A screen root that asks to be drawn over the others: the layer decides that.
|
|
582
|
+
* app.ui.lint(); // [{ rule: "z-index-on-root", key: "board", detail: "zIndex 2" }]
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
lint(): readonly Finding[];
|
|
586
|
+
};
|
|
587
|
+
//#endregion
|
|
588
|
+
export { Config$1 as a, TextApi as c, TextValue as d, types_d_exports$1 as f, types_d_exports as i, TextStyleInput as l, State as n, Point as o, UiApi as r, State$1 as s, Config as t, TextStyles as u };
|