@textui/core 0.1.0 → 0.3.0

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.
Files changed (70) hide show
  1. package/README.md +17 -20
  2. package/dist/app/app.d.ts +64 -0
  3. package/dist/app/app.d.ts.map +1 -1
  4. package/dist/app/app.js +202 -1
  5. package/dist/core/focus.d.ts.map +1 -1
  6. package/dist/core/focus.js +12 -1
  7. package/dist/core/store.d.ts.map +1 -1
  8. package/dist/core/store.js +2 -10
  9. package/dist/jsx/intrinsics.d.ts +18 -0
  10. package/dist/jsx/intrinsics.d.ts.map +1 -1
  11. package/dist/render/layout.js +10 -2
  12. package/dist/runtime/bindings.d.ts.map +1 -1
  13. package/dist/runtime/bindings.js +31 -4
  14. package/dist/runtime/hooks.d.ts +14 -2
  15. package/dist/runtime/hooks.d.ts.map +1 -1
  16. package/dist/runtime/hooks.js +15 -4
  17. package/dist/themes/builtin.d.ts +2 -0
  18. package/dist/themes/builtin.d.ts.map +1 -1
  19. package/dist/themes/builtin.js +64 -1
  20. package/dist/themes/dividers.d.ts +14 -0
  21. package/dist/themes/dividers.d.ts.map +1 -0
  22. package/dist/themes/dividers.js +42 -0
  23. package/dist/themes/glyphs.d.ts.map +1 -1
  24. package/dist/themes/glyphs.js +4 -0
  25. package/dist/themes/index.d.ts +1 -0
  26. package/dist/themes/index.d.ts.map +1 -1
  27. package/dist/themes/index.js +1 -0
  28. package/dist/themes/registry.d.ts.map +1 -1
  29. package/dist/themes/registry.js +31 -1
  30. package/dist/types/app.d.ts +15 -0
  31. package/dist/types/app.d.ts.map +1 -1
  32. package/dist/types/command.d.ts +18 -1
  33. package/dist/types/command.d.ts.map +1 -1
  34. package/dist/types/input.d.ts +9 -0
  35. package/dist/types/input.d.ts.map +1 -1
  36. package/dist/types/markdown.d.ts +36 -1
  37. package/dist/types/markdown.d.ts.map +1 -1
  38. package/dist/types/style.d.ts +28 -1
  39. package/dist/types/style.d.ts.map +1 -1
  40. package/dist/types/terminal.d.ts +9 -0
  41. package/dist/types/terminal.d.ts.map +1 -1
  42. package/dist/types/theme.d.ts +26 -1
  43. package/dist/types/theme.d.ts.map +1 -1
  44. package/dist/util/markdown.d.ts.map +1 -1
  45. package/dist/util/markdown.js +172 -2
  46. package/dist/util/paths.d.ts +9 -3
  47. package/dist/util/paths.d.ts.map +1 -1
  48. package/dist/util/paths.js +11 -16
  49. package/package.json +5 -5
  50. package/src/app/app.ts +198 -1
  51. package/src/core/focus.ts +12 -1
  52. package/src/core/store.ts +2 -7
  53. package/src/jsx/intrinsics.ts +18 -0
  54. package/src/render/layout.ts +7 -2
  55. package/src/runtime/bindings.ts +29 -3
  56. package/src/runtime/hooks.ts +15 -4
  57. package/src/themes/builtin.ts +65 -1
  58. package/src/themes/dividers.ts +48 -0
  59. package/src/themes/glyphs.ts +4 -0
  60. package/src/themes/index.ts +1 -0
  61. package/src/themes/registry.ts +30 -2
  62. package/src/types/app.ts +13 -0
  63. package/src/types/command.ts +18 -1
  64. package/src/types/input.ts +9 -0
  65. package/src/types/markdown.ts +38 -2
  66. package/src/types/style.ts +33 -1
  67. package/src/types/terminal.ts +9 -0
  68. package/src/types/theme.ts +29 -1
  69. package/src/util/markdown.ts +202 -3
  70. package/src/util/paths.ts +12 -15
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # @textui/core
2
2
 
3
- The runtime: a reactive store, typed registries, a cell-diffing renderer, hooks,
4
- and the four host primitives. Everything else in TextUI sits on this.
3
+ [![npm](https://img.shields.io/npm/v/@textui/core?label=%40textui%2Fcore)](https://www.npmjs.com/package/@textui/core) [![license](https://img.shields.io/npm/l/@textui/core)](https://github.com/softov/textui/blob/main/LICENSE)
4
+
5
+ The runtime: a reactive store, typed registries, a cell-diffing renderer, hooks, and the four host primitives. Everything else in TextUI sits on this.
5
6
 
6
7
  ```bash
7
8
  npm install @textui/core
@@ -9,10 +10,7 @@ npm install @textui/core
9
10
 
10
11
  ## The one idea
11
12
 
12
- **JSX compiles to data.** `<Row gap={1}/>` and `{ component: 'Row', gap: 1 }` are
13
- the same value, and the runtime mounts either. A screen can be written in
14
- TypeScript, loaded from JSON, generated, edited or sent over a wire without the
15
- runtime changing.
13
+ **JSX compiles to data.** `<Row gap={1}/>` and `{ component: 'Row', gap: 1 }` are the same value, and the runtime mounts either. A screen can be written in TypeScript, loaded from JSON, generated, edited or sent over a wire without the runtime changing.
16
14
 
17
15
  ```ts
18
16
  import { h, renderToString } from '@textui/core';
@@ -23,18 +21,13 @@ console.log(renderToString(
23
21
  ));
24
22
  ```
25
23
 
26
- Capitalized spellings of the primitives exist for JSX - `Box`, `Text`, `Canvas`
27
- are the strings themselves, so `<Box/>` and `<box/>` produce the identical node.
24
+ Capitalized spellings of the primitives exist for JSX - `Box`, `Text`, `Canvas` are the strings themselves, so `<Box/>` and `<box/>` produce the identical node.
28
25
 
29
26
  ## What is in here, and what is not
30
27
 
31
- The four primitives - `box`, `text`, `canvas`, `spacer` - are here because the
32
- layout engine and the painter are the things that reason about them. The
33
- eighty-seven components built out of them are [`@textui/widgets`](https://github.com/softov/textui/tree/main/packages/widgets),
34
- a separate package that depends on this one.
28
+ The four primitives - `box`, `text`, `canvas`, `spacer` - are here because the layout engine and the painter are the things that reason about them. The eighty-seven components built out of them are [`@textui/widgets`](https://www.npmjs.com/package/@textui/widgets), a separate package that depends on this one.
35
29
 
36
- That split is not tidiness. An imported component travels on its own node, so a
37
- screen written in JSX resolves without a registry at all:
30
+ That split is not tidiness. An imported component travels on its own node, so a screen written in JSX resolves without a registry at all:
38
31
 
39
32
  ```ts
40
33
  import { Badge } from '@textui/widgets';
@@ -42,9 +35,7 @@ import { Badge } from '@textui/widgets';
42
35
  renderToString(h(Badge, { label: 'ok' }), { width: 20 }); // registry empty
43
36
  ```
44
37
 
45
- The registry is for the case JSX cannot cover - a component named by a string,
46
- in JSON, a template renderer, or an extension. `render` takes those through its
47
- `components` option.
38
+ The registry is for the case JSX cannot cover - a component named by a string, in JSON, a template renderer, or an extension. `render` takes those through its `components` option.
48
39
 
49
40
  ## The parts
50
41
 
@@ -58,10 +49,16 @@ in JSON, a template renderer, or an extension. `render` takes those through its
58
49
 
59
50
  ## Runtime
60
51
 
61
- No dependencies, and no `node:` imports - this package never touches a
62
- filesystem or a process. It runs on Node 22+ and on Bun, and would run in a
63
- browser against a virtual terminal.
52
+ No dependencies, and no `node:` imports - this package never touches a filesystem or a process. It runs on Node 22+ and on Bun, and would run in a browser against a virtual terminal.
64
53
 
65
54
  ## Documentation
66
55
 
67
56
  <https://softov.github.io/textui/>
57
+
58
+ <!-- family -->
59
+
60
+ ---
61
+
62
+ Part of **[TextUI](https://github.com/softov/textui)** - [documentation](https://softov.github.io/textui/) - [getting started](https://softov.github.io/textui/getting-started.html)
63
+
64
+ [`@textui/kit`](https://www.npmjs.com/package/@textui/kit) one install · **`@textui/core`** the runtime · [`@textui/widgets`](https://www.npmjs.com/package/@textui/widgets) the catalog · [`@textui/terminal`](https://www.npmjs.com/package/@textui/terminal) adapters and input · [`@textui/testing`](https://www.npmjs.com/package/@textui/testing) the harness · [`@textui/cli`](https://www.npmjs.com/package/@textui/cli) the CLI
package/dist/app/app.d.ts CHANGED
@@ -60,6 +60,27 @@ export declare class App implements TextUIApp {
60
60
  private resolvedTheme;
61
61
  private bag;
62
62
  private hovered;
63
+ /**
64
+ * Whoever took the last button down, until it comes back up.
65
+ *
66
+ * Mouse dispatch is a hit test, so without this a drag stops the moment the
67
+ * pointer leaves the box it started in - which is precisely when a drag
68
+ * becomes interesting. A selection dragged off the bottom of a field, a
69
+ * slider dragged past its own track and a splitter dragged across the pane
70
+ * it is resizing are all the pointer being somewhere the handler is not.
71
+ */
72
+ private captured;
73
+ /**
74
+ * Everything under the pointer, innermost outwards.
75
+ *
76
+ * A chain rather than one node, because hover is inherited the way it is in
77
+ * a browser: a row lights up when the pointer is over the label inside it,
78
+ * and the label is what the hit test finds. Hover used to be a focus id
79
+ * compared against `props.id`, which meant only a focusable node could ever
80
+ * be hovered - so a tool call row, a list row and every other box that is
81
+ * clicked rather than focused had a `hover` style nothing could trigger.
82
+ */
83
+ private hoveredChain;
63
84
  /** Focus registrations created from `focusable` props, by focus id. */
64
85
  private declaredFocus;
65
86
  private lastFrame;
@@ -73,6 +94,13 @@ export declare class App implements TextUIApp {
73
94
  get running(): boolean;
74
95
  private publishEnvironment;
75
96
  setTheme(id: string): void;
97
+ /**
98
+ * Ask the terminal for the theme's caret, when the theme states one.
99
+ *
100
+ * A theme that says nothing leaves the terminal's own setting alone, which
101
+ * is why this is not called with a default.
102
+ */
103
+ private applyCursorShape;
76
104
  setShell(id: string): void;
77
105
  activeShell(): string;
78
106
  setCapabilityOverrides(overrides: CapabilityOverrides): void;
@@ -92,6 +120,34 @@ export declare class App implements TextUIApp {
92
120
  setRoot(node: ComponentNode): void;
93
121
  private requestRender;
94
122
  flush(): void;
123
+ /**
124
+ * Render until there is nothing left to render.
125
+ *
126
+ * `flush` forces one frame; this is the other question - *has it finished?* -
127
+ * and there was no way to ask it. What a program wanting one true frame did
128
+ * instead was guess: every example that writes a still ended with a sleep
129
+ * loop of four milliseconds times a number somebody tried until the picture
130
+ * looked right. Eight, mostly. Four in one, twelve in another. A number too
131
+ * small does not fail; it writes a half-drawn frame.
132
+ *
133
+ * A frame settles in more than one pass by design - an effect may mark
134
+ * something dirty, and a measurement changing runs the layout again - so the
135
+ * answer is a loop rather than a flag. Each turn yields to the task queue
136
+ * first, because what has not run yet cannot have marked anything.
137
+ *
138
+ * It returns as soon as a pass finds nothing pending, so an application that
139
+ * animates settles *between* its frames - which is what makes a still of one
140
+ * possible at all, and why the answer is not "has it stopped moving".
141
+ *
142
+ * `false` is the other thing: passes that kept producing work until the
143
+ * limit ran out, which is a render loop that does not converge - an effect
144
+ * with no dependency list setting the state it reads. Worth reporting rather
145
+ * than hanging on, and worth a number rather than a promise a caller can
146
+ * wait on for ever.
147
+ */
148
+ settled(options?: {
149
+ limit?: number;
150
+ }): Promise<boolean>;
95
151
  /**
96
152
  * The tree the frame renders: the shell, always, when one is registered.
97
153
  *
@@ -166,6 +222,14 @@ export declare class App implements TextUIApp {
166
222
  */
167
223
  private handleKey;
168
224
  private handleMouse;
225
+ /**
226
+ * Who the pointer is over now, and who it has just left.
227
+ *
228
+ * `onHover` is called on the way in and the way out, once each - a handler
229
+ * that fires on every pixel of movement is a handler nobody can use for
230
+ * anything but a repaint.
231
+ */
232
+ private updateHover;
169
233
  /** Innermost box under the pointer first, then outward. */
170
234
  private dispatchMouse;
171
235
  private handleResize;
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app/app.ts"],"names":[],"mappings":"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"}
package/dist/app/app.js CHANGED
@@ -76,6 +76,27 @@ export class App {
76
76
  resolvedTheme;
77
77
  bag = createBag();
78
78
  hovered = null;
79
+ /**
80
+ * Whoever took the last button down, until it comes back up.
81
+ *
82
+ * Mouse dispatch is a hit test, so without this a drag stops the moment the
83
+ * pointer leaves the box it started in - which is precisely when a drag
84
+ * becomes interesting. A selection dragged off the bottom of a field, a
85
+ * slider dragged past its own track and a splitter dragged across the pane
86
+ * it is resizing are all the pointer being somewhere the handler is not.
87
+ */
88
+ captured = null;
89
+ /**
90
+ * Everything under the pointer, innermost outwards.
91
+ *
92
+ * A chain rather than one node, because hover is inherited the way it is in
93
+ * a browser: a row lights up when the pointer is over the label inside it,
94
+ * and the label is what the hit test finds. Hover used to be a focus id
95
+ * compared against `props.id`, which meant only a focusable node could ever
96
+ * be hovered - so a tool call row, a list row and every other box that is
97
+ * clicked rather than focused had a `hover` style nothing could trigger.
98
+ */
99
+ hoveredChain = new Set();
79
100
  /** Focus registrations created from `focusable` props, by focus id. */
80
101
  declaredFocus = new Map();
81
102
  lastFrame = null;
@@ -209,10 +230,22 @@ export class App {
209
230
  }
210
231
  this.themeId = id;
211
232
  this.resolvedTheme = this.themes.resolve(id, this.terminal.capabilities());
233
+ this.applyCursorShape();
212
234
  this.store.set('$/modus/theme', id);
213
235
  this.buffer_.invalidate();
214
236
  this.requestRender(true);
215
237
  }
238
+ /**
239
+ * Ask the terminal for the theme's caret, when the theme states one.
240
+ *
241
+ * A theme that says nothing leaves the terminal's own setting alone, which
242
+ * is why this is not called with a default.
243
+ */
244
+ applyCursorShape() {
245
+ const shape = this.resolvedTheme.cursor;
246
+ if (shape)
247
+ this.terminal.setCursorShape?.(shape);
248
+ }
216
249
  setShell(id) {
217
250
  if (!this.shells.get(id)) {
218
251
  throw new Error(`[textui] no shell registered as "${id}"`);
@@ -222,6 +255,20 @@ export class App {
222
255
  const shell = this.shells.get(id);
223
256
  if (shell?.theme && this.themes.get(shell.theme))
224
257
  this.setTheme(shell.theme);
258
+ // `root` reaches the screen two ways, and this is the moment it changes
259
+ // which. With no shell registered at boot it was never opened into `main` -
260
+ // `rootNode` wraps it directly, which is the path an application built out
261
+ // of primitives takes. A shell arriving afterwards makes `rootNode` return
262
+ // the shell instead, and the application's entire content was simply gone:
263
+ // a framed, themed, empty screen.
264
+ //
265
+ // `setRoot` has always handled both paths, and says why - "setting one and
266
+ // not the other works in exactly half of the programs that can exist". This
267
+ // is the other half of the same sentence. Opening the same key twice
268
+ // replaces the mount rather than stacking one, so no guard is needed.
269
+ if (this.options.root) {
270
+ this.surfaces.open({ surface: 'main', key: ROOT_KEY, target: this.options.root });
271
+ }
225
272
  this.buffer_.invalidate();
226
273
  this.requestRender(true);
227
274
  }
@@ -231,6 +278,7 @@ export class App {
231
278
  setCapabilityOverrides(overrides) {
232
279
  this.terminal.setCapabilityOverrides(overrides);
233
280
  this.resolvedTheme = this.themes.resolve(this.themeId, this.terminal.capabilities());
281
+ this.applyCursorShape();
234
282
  this.publishEnvironment();
235
283
  this.buffer_.invalidate();
236
284
  this.requestRender(true);
@@ -270,6 +318,9 @@ export class App {
270
318
  enhancedKeys: caps.kittyKeyboard,
271
319
  ...this.options.session,
272
320
  });
321
+ // After `acquire`, never before: with no session there is nothing to put
322
+ // the shape back, so an early call is dropped rather than leaked.
323
+ this.applyCursorShape();
273
324
  this.bag.add(this.terminal.onInput((event) => this.handleInput(event)));
274
325
  this.bag.add(this.terminal.onResize((size) => this.handleResize(size)));
275
326
  this.running_ = true;
@@ -364,6 +415,44 @@ export class App {
364
415
  this.frameScheduled = false;
365
416
  this.renderFrame();
366
417
  }
418
+ /**
419
+ * Render until there is nothing left to render.
420
+ *
421
+ * `flush` forces one frame; this is the other question - *has it finished?* -
422
+ * and there was no way to ask it. What a program wanting one true frame did
423
+ * instead was guess: every example that writes a still ended with a sleep
424
+ * loop of four milliseconds times a number somebody tried until the picture
425
+ * looked right. Eight, mostly. Four in one, twelve in another. A number too
426
+ * small does not fail; it writes a half-drawn frame.
427
+ *
428
+ * A frame settles in more than one pass by design - an effect may mark
429
+ * something dirty, and a measurement changing runs the layout again - so the
430
+ * answer is a loop rather than a flag. Each turn yields to the task queue
431
+ * first, because what has not run yet cannot have marked anything.
432
+ *
433
+ * It returns as soon as a pass finds nothing pending, so an application that
434
+ * animates settles *between* its frames - which is what makes a still of one
435
+ * possible at all, and why the answer is not "has it stopped moving".
436
+ *
437
+ * `false` is the other thing: passes that kept producing work until the
438
+ * limit ran out, which is a render loop that does not converge - an effect
439
+ * with no dependency list setting the state it reads. Worth reporting rather
440
+ * than hanging on, and worth a number rather than a promise a caller can
441
+ * wait on for ever.
442
+ */
443
+ async settled(options = {}) {
444
+ const limit = options.limit ?? 100;
445
+ for (let i = 0; i < limit; i++) {
446
+ // Deliberately not `unref`'d: this timer is what keeps the process alive
447
+ // while a still is being rendered, and one that lets it exit would leave
448
+ // the await unresolved and the frame unwritten.
449
+ await new Promise((resolve) => setTimeout(resolve, 0));
450
+ if (!this.frameScheduled && !this.isDirty())
451
+ return true;
452
+ this.flush();
453
+ }
454
+ return false;
455
+ }
367
456
  /**
368
457
  * The tree the frame renders: the shell, always, when one is registered.
369
458
  *
@@ -546,7 +635,7 @@ export class App {
546
635
  const focusedId = this.focus.focused();
547
636
  return {
548
637
  focused: focusedId === id || focusedId === `${instance.id}:focus`,
549
- hovered: this.hovered === id,
638
+ hovered: this.hovered === id || this.hoveredChain.has(instance),
550
639
  active: false,
551
640
  selected: instance.props.selected === true,
552
641
  disabled: instance.props.disabled === true,
@@ -811,6 +900,27 @@ export class App {
811
900
  this.requestRender();
812
901
  return;
813
902
  }
903
+ /*
904
+ * A modal takes escape before any keybinding does.
905
+ *
906
+ * `dismissOnEscape` was unreachable in any application with a global
907
+ * escape binding, which most have: the binding matched first, the layer
908
+ * stayed open, and the key went to whatever "go back" means behind it.
909
+ * What that looks like is a confirm dialog you cannot leave, over a screen
910
+ * that has navigated somewhere else while you were reading it.
911
+ *
912
+ * The test is `trapFocus`, not `dismissOnEscape` alone. A layer that traps
913
+ * focus has claimed the keyboard, so nothing behind it should be acting on
914
+ * keys; a toast or a tooltip has not, and those keep the old order so that
915
+ * escape still reaches the application while one happens to be up.
916
+ */
917
+ if (event.name === 'escape') {
918
+ const top = this.layers.topmostDismissible();
919
+ if (top && top.trapFocus) {
920
+ this.layers.close(top.id, 'escape');
921
+ return;
922
+ }
923
+ }
814
924
  if (this.keybindings.handle(event) !== 'unhandled') {
815
925
  this.requestRender();
816
926
  return;
@@ -831,14 +941,43 @@ export class App {
831
941
  this.requestRender();
832
942
  }
833
943
  handleMouse(event) {
944
+ // The rest of the gesture belongs to whoever took the button down,
945
+ // wherever the pointer has got to since - and it is delivered whether or
946
+ // not the handler claims it, because during a drag there is nothing else
947
+ // it could be for.
948
+ if (this.captured && (event.action === 'drag' || event.action === 'up')) {
949
+ const target = this.captured;
950
+ if (event.action === 'up')
951
+ this.captured = null;
952
+ if (target.mounted) {
953
+ const onMouse = target.props.onMouse;
954
+ if (typeof onMouse === 'function') {
955
+ onMouse(event);
956
+ this.requestRender();
957
+ return;
958
+ }
959
+ }
960
+ // Unmounted mid-drag, or it stopped taking the pointer: the gesture has
961
+ // nowhere to go, so let the hit test have it back.
962
+ this.captured = null;
963
+ }
834
964
  const hit = this.focus.at(event.x, event.y);
835
965
  if (event.action === 'move') {
966
+ const moved = this.updateHover(event);
836
967
  if (hit !== this.hovered) {
837
968
  this.hovered = hit;
838
969
  this.requestRender();
839
970
  }
971
+ else if (moved) {
972
+ this.requestRender();
973
+ }
840
974
  return;
841
975
  }
976
+ // A new press ends the last one, claimed or not: an `up` that never
977
+ // arrived - a terminal that lost focus mid-drag - must not leave a capture
978
+ // that eats the next gesture.
979
+ if (event.action === 'down')
980
+ this.captured = null;
842
981
  if (event.action === 'down' && hit)
843
982
  this.focus.focus(hit);
844
983
  if (this.root) {
@@ -846,6 +985,46 @@ export class App {
846
985
  }
847
986
  this.requestRender();
848
987
  }
988
+ /**
989
+ * Who the pointer is over now, and who it has just left.
990
+ *
991
+ * `onHover` is called on the way in and the way out, once each - a handler
992
+ * that fires on every pixel of movement is a handler nobody can use for
993
+ * anything but a repaint.
994
+ */
995
+ updateHover(event) {
996
+ const next = new Set();
997
+ if (this.root)
998
+ collectHover(this.root, event.x, event.y, next);
999
+ let changed = next.size !== this.hoveredChain.size;
1000
+ if (!changed) {
1001
+ for (const instance of next) {
1002
+ if (!this.hoveredChain.has(instance)) {
1003
+ changed = true;
1004
+ break;
1005
+ }
1006
+ }
1007
+ }
1008
+ if (!changed)
1009
+ return false;
1010
+ const previous = this.hoveredChain;
1011
+ this.hoveredChain = next;
1012
+ for (const instance of previous) {
1013
+ if (next.has(instance) || !instance.mounted)
1014
+ continue;
1015
+ const onHover = instance.props.onHover;
1016
+ if (typeof onHover === 'function')
1017
+ onHover(false);
1018
+ }
1019
+ for (const instance of next) {
1020
+ if (previous.has(instance))
1021
+ continue;
1022
+ const onHover = instance.props.onHover;
1023
+ if (typeof onHover === 'function')
1024
+ onHover(true);
1025
+ }
1026
+ return true;
1027
+ }
849
1028
  /** Innermost box under the pointer first, then outward. */
850
1029
  dispatchMouse(instance, event) {
851
1030
  for (let i = instance.children.length - 1; i >= 0; i--) {
@@ -861,6 +1040,9 @@ export class App {
861
1040
  return false;
862
1041
  const onMouse = instance.props.onMouse;
863
1042
  if (typeof onMouse === 'function' && onMouse(event) === true) {
1043
+ // Taking the button down is what claims the drag that follows it.
1044
+ if (event.action === 'down')
1045
+ this.captured = instance;
864
1046
  return true;
865
1047
  }
866
1048
  if (event.action === 'down' && event.button === 'left') {
@@ -978,3 +1160,22 @@ export const WRITER_KEY = serviceKey('textui.writer');
978
1160
  export function createApp(options = {}) {
979
1161
  return new App(options);
980
1162
  }
1163
+ /**
1164
+ * Every box containing the point, from the root down.
1165
+ *
1166
+ * The whole chain rather than the innermost one: a row is hovered when the
1167
+ * pointer is over the text inside it, and the text is what a hit test finds.
1168
+ * Only boxes with a laid-out rect count - a component that produced no box
1169
+ * occupies no space, so there is nothing to be over.
1170
+ */
1171
+ function collectHover(instance, x, y, into) {
1172
+ const box = instance.box;
1173
+ if (box) {
1174
+ const { x: bx, y: by, width, height } = box.rect;
1175
+ if (x < bx || x >= bx + width || y < by || y >= by + height)
1176
+ return;
1177
+ into.add(instance);
1178
+ }
1179
+ for (const child of instance.children)
1180
+ collectHover(child, x, y, into);
1181
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/core/focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAClE,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AASzD,8EAA8E;AAC9E,eAAO,MAAM,YAAY,eAAe,CAAC;AAEzC;;;;;;;GAOG;AACH,qBAAa,KAAM,YAAW,YAAY;IAQ5B,OAAO,CAAC,QAAQ;IAP5B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,KAAK,CAAuC;IACpD,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,OAAO,CAAuB;gBAElB,QAAQ,GAAE,MAAM,IAAe;IAOnD,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU;IAQrD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAe/B,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAgCjC,WAAW,IAAI,MAAM,GAAG,IAAI;IAK5B,qDAAqD;IACrD,OAAO,CAAC,aAAa;IAQrB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAM/B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU;IAiC/C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAgB1D,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAa1B,IAAI,IAAI,IAAI;IAQZ,OAAO,IAAI,MAAM,GAAG,IAAI;IAIxB,KAAK,IAAI,MAAM,EAAE;IAOjB,kEAAkE;IAClE,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAsBjC,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI;IAe9C;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAwCvB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBvC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAiClC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;CAItC;AAED,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,KAAK,CAExD"}
1
+ {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/core/focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAClE,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AASzD,8EAA8E;AAC9E,eAAO,MAAM,YAAY,eAAe,CAAC;AAEzC;;;;;;;GAOG;AACH,qBAAa,KAAM,YAAW,YAAY;IAQ5B,OAAO,CAAC,QAAQ;IAP5B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,KAAK,CAAuC;IACpD,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,OAAO,CAAuB;gBAElB,QAAQ,GAAE,MAAM,IAAe;IAOnD,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU;IAQrD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAe/B,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAgCjC,WAAW,IAAI,MAAM,GAAG,IAAI;IAK5B,qDAAqD;IACrD,OAAO,CAAC,aAAa;IAQrB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAM/B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU;IA4C/C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAgB1D,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAa1B,IAAI,IAAI,IAAI;IAQZ,OAAO,IAAI,MAAM,GAAG,IAAI;IAIxB,KAAK,IAAI,MAAM,EAAE;IAOjB,kEAAkE;IAClE,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAsBjC,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI;IAe9C;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAwCvB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBvC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAiClC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;CAItC;AAED,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,KAAK,CAExD"}
@@ -111,7 +111,18 @@ export class Focus {
111
111
  // the screen this is for - pushed over whatever had focus, which the push
112
112
  // unmounted, leaving none - and a dialog, which opens while its opener
113
113
  // still holds focus and whose own controls say which of them wants it.
114
- if (!existing && options.disabled !== true && this.current === null) {
114
+ //
115
+ // And only onto something a person could have tabbed to. A `global`
116
+ // handler registers as a focusable - that is how a layer reads escape
117
+ // without holding focus - and it is `skipTab`, so it is not a place focus
118
+ // can land. Handed it anyway, focus sat on a node that consumes nothing:
119
+ // the keys fell through to whatever was behind, and every real control's
120
+ // own `autoFocus` stood down, because it claims focus only when the scope
121
+ // does not already hold it. A question with a text field in it was
122
+ // therefore unanswerable - the field was drawn, `required` beside it, and
123
+ // what was typed at it went into the composer underneath.
124
+ const focusable = options.disabled !== true && options.skipTab !== true && options.global !== true;
125
+ if (!existing && focusable && this.current === null) {
115
126
  const scopeId = options.scopeId ?? GLOBAL_SCOPE;
116
127
  if (this.scopes.get(scopeId)?.autoFocus === true && this.stack.includes(scopeId)) {
117
128
  this.focus(options.id);
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/core/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/core/store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { toDisposable } from '../util/disposable.js';
2
- import { ancestorKeys, hasWildcard, isDescendantKey, matchKey, pathKey, PathError, } from '../util/paths.js';
2
+ import { hasWildcard, isDescendantKey, keysTouch, matchKey, pathKey, PathError, } from '../util/paths.js';
3
3
  /**
4
4
  * The store is one tree, and it is the only place state lives. A component
5
5
  * that keeps a copy in its own state has created a second answer to a question
@@ -184,15 +184,7 @@ export class Store {
184
184
  subMatches(sub, changedKey) {
185
185
  if (sub.wildcard)
186
186
  return matchKey(changedKey, sub.key, sub.subtree);
187
- if (sub.key === changedKey)
188
- return true;
189
- // A write below an exact subscription still changes that object's contents.
190
- if (isDescendantKey(changedKey, sub.key))
191
- return true;
192
- // A write above it may have replaced the subtree the subscriber reads.
193
- if (isDescendantKey(sub.key, changedKey))
194
- return true;
195
- return sub.subtree && ancestorKeys(changedKey).includes(sub.key);
187
+ return keysTouch(changedKey, sub.key);
196
188
  }
197
189
  // ---------------------------------------------------------- subscriptions
198
190
  subscribe(path, fn, options = {}) {
@@ -38,8 +38,26 @@ export interface BaseProps extends Style {
38
38
  onKey?(event: KeyEvent): boolean | void;
39
39
  onFocus?(): void;
40
40
  onBlur?(): void;
41
+ /**
42
+ * Every mouse action on this node, innermost first.
43
+ *
44
+ * Returning `true` stops it going any further - and on a `down`, **claims
45
+ * the rest of the gesture**: the `drag`s and the `up` that follow come here
46
+ * whatever they are over, until the button comes back up. Dispatch is
47
+ * otherwise a hit test, so without that a drag would stop at the edge of the
48
+ * node it started in, which is where a drag starts being worth having.
49
+ */
41
50
  onMouse?(event: MouseEvent): boolean | void;
51
+ /** The left button going down - a third of a gesture. `onMouse` for the rest. */
42
52
  onClick?: Action | ((event: MouseEvent) => void);
53
+ /**
54
+ * The pointer entered or left this node. Called once each way, not per cell.
55
+ *
56
+ * Hover is inherited the way it is in a browser: a row is hovered while the
57
+ * pointer is over the label inside it, because the label is what a hit test
58
+ * finds. A `style` with a `hover` overlay needs nothing else - this is for
59
+ * the cases where something other than a colour has to happen.
60
+ */
43
61
  onHover?(hovering: boolean): void;
44
62
  /** OSC 8 link target, where the terminal supports hyperlinks. */
45
63
  link?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/jsx/intrinsics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/jsx/intrinsics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,WAAW,SAAU,SAAQ,KAAK;IACtC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB,wEAAwE;IACxE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,KAAK,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;IACxC,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,MAAM,CAAC,IAAI,IAAI,CAAC;IAChB;;;;;;;;OAQG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAAC;IAC5C,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC;IACjD;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAElC,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,WAAW,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACzC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC1C,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IACtD,sDAAsD;IACtD,SAAS,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -387,8 +387,16 @@ function layoutBox(box, rect) {
387
387
  box.rect = { ...box.rect, width: 0, height: 0 };
388
388
  return;
389
389
  }
390
- const flow = box.children.filter((c) => !isAbsolute(c) && !isHidden(c));
391
- const absolute = box.children.filter((c) => isAbsolute(c) && !isHidden(c));
390
+ const flow = [];
391
+ const absolute = [];
392
+ for (const child of box.children) {
393
+ if (isHidden(child))
394
+ continue;
395
+ if (isAbsolute(child))
396
+ absolute.push(child);
397
+ else
398
+ flow.push(child);
399
+ }
392
400
  if (flow.length > 0)
393
401
  layoutFlow(box, flow);
394
402
  for (const child of absolute)
@@ -1 +1 @@
1
- {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/runtime/bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAAE,WAAW,EAAE,aAAa,EACnC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvD;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,gCAAgC;IAChC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,gCAAgC;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,oEAAoE;IACpE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAsCD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,SAAS,GAC7D,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,SAAS,CAW/C;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAkBzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,aAAa,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAezB;AAOD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,OAAO,GACT,CAAC,IAAI;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAMrD"}
1
+ {"version":3,"file":"bindings.d.ts","sourceRoot":"","sources":["../../src/runtime/bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAAE,WAAW,EAAE,aAAa,EACnC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvD;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,gCAAgC;IAChC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,gCAAgC;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,oEAAoE;IACpE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAsCD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,SAAS,GAC7D,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,SAAS,CAW/C;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CA4CzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,aAAa,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAezB;AAOD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,OAAO,GACT,CAAC,IAAI;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAMrD"}