@textui/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +11 -0
- package/dist/app/app.d.ts +200 -0
- package/dist/app/app.d.ts.map +1 -0
- package/dist/app/app.js +980 -0
- package/dist/core/animation.d.ts +34 -0
- package/dist/core/animation.d.ts.map +1 -0
- package/dist/core/animation.js +125 -0
- package/dist/core/clipboard.d.ts +29 -0
- package/dist/core/clipboard.d.ts.map +1 -0
- package/dist/core/clipboard.js +30 -0
- package/dist/core/commands.d.ts +42 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +146 -0
- package/dist/core/components.d.ts +27 -0
- package/dist/core/components.d.ts.map +1 -0
- package/dist/core/components.js +78 -0
- package/dist/core/events.d.ts +23 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +77 -0
- package/dist/core/focus.d.ts +69 -0
- package/dist/core/focus.d.ts.map +1 -0
- package/dist/core/focus.js +336 -0
- package/dist/core/i18n.d.ts +27 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/i18n.js +88 -0
- package/dist/core/keybindings.d.ts +53 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +163 -0
- package/dist/core/layers.d.ts +28 -0
- package/dist/core/layers.d.ts.map +1 -0
- package/dist/core/layers.js +84 -0
- package/dist/core/manifest.d.ts +22 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +85 -0
- package/dist/core/navigation.d.ts +47 -0
- package/dist/core/navigation.d.ts.map +1 -0
- package/dist/core/navigation.js +110 -0
- package/dist/core/resources.d.ts +115 -0
- package/dist/core/resources.d.ts.map +1 -0
- package/dist/core/resources.js +321 -0
- package/dist/core/services.d.ts +21 -0
- package/dist/core/services.d.ts.map +1 -0
- package/dist/core/services.js +63 -0
- package/dist/core/store.d.ts +60 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +593 -0
- package/dist/core/surfaces.d.ts +81 -0
- package/dist/core/surfaces.d.ts.map +1 -0
- package/dist/core/surfaces.js +237 -0
- package/dist/core/syntax.d.ts +49 -0
- package/dist/core/syntax.d.ts.map +1 -0
- package/dist/core/syntax.js +172 -0
- package/dist/core/when.d.ts +15 -0
- package/dist/core/when.d.ts.map +1 -0
- package/dist/core/when.js +224 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/jsx/factory.d.ts +27 -0
- package/dist/jsx/factory.d.ts.map +1 -0
- package/dist/jsx/factory.js +102 -0
- package/dist/jsx/intrinsics.d.ts +96 -0
- package/dist/jsx/intrinsics.d.ts.map +1 -0
- package/dist/jsx/intrinsics.js +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +13 -0
- package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-dev-runtime.js +12 -0
- package/dist/jsx/jsx-runtime.d.ts +42 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-runtime.js +16 -0
- package/dist/render/buffer.d.ts +77 -0
- package/dist/render/buffer.d.ts.map +1 -0
- package/dist/render/buffer.js +275 -0
- package/dist/render/color.d.ts +35 -0
- package/dist/render/color.d.ts.map +1 -0
- package/dist/render/color.js +160 -0
- package/dist/render/diff.d.ts +37 -0
- package/dist/render/diff.d.ts.map +1 -0
- package/dist/render/diff.js +66 -0
- package/dist/render/layout.d.ts +72 -0
- package/dist/render/layout.d.ts.map +1 -0
- package/dist/render/layout.js +633 -0
- package/dist/render/static.d.ts +63 -0
- package/dist/render/static.d.ts.map +1 -0
- package/dist/render/static.js +209 -0
- package/dist/runtime/bindings.d.ts +46 -0
- package/dist/runtime/bindings.d.ts.map +1 -0
- package/dist/runtime/bindings.js +116 -0
- package/dist/runtime/hooks.d.ts +284 -0
- package/dist/runtime/hooks.d.ts.map +1 -0
- package/dist/runtime/hooks.js +846 -0
- package/dist/runtime/instance.d.ts +106 -0
- package/dist/runtime/instance.d.ts.map +1 -0
- package/dist/runtime/instance.js +181 -0
- package/dist/runtime/paint.d.ts +27 -0
- package/dist/runtime/paint.d.ts.map +1 -0
- package/dist/runtime/paint.js +567 -0
- package/dist/runtime/reconcile.d.ts +23 -0
- package/dist/runtime/reconcile.d.ts.map +1 -0
- package/dist/runtime/reconcile.js +260 -0
- package/dist/runtime/runtime.d.ts +42 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +1 -0
- package/dist/runtime/style.d.ts +55 -0
- package/dist/runtime/style.d.ts.map +1 -0
- package/dist/runtime/style.js +143 -0
- package/dist/themes/borders.d.ts +10 -0
- package/dist/themes/borders.d.ts.map +1 -0
- package/dist/themes/borders.js +88 -0
- package/dist/themes/builtin.d.ts +31 -0
- package/dist/themes/builtin.d.ts.map +1 -0
- package/dist/themes/builtin.js +291 -0
- package/dist/themes/glyphs.d.ts +15 -0
- package/dist/themes/glyphs.d.ts.map +1 -0
- package/dist/themes/glyphs.js +97 -0
- package/dist/themes/index.d.ts +5 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +4 -0
- package/dist/themes/registry.d.ts +20 -0
- package/dist/themes/registry.d.ts.map +1 -0
- package/dist/themes/registry.js +204 -0
- package/dist/types/adapter.d.ts +38 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/adapter.js +1 -0
- package/dist/types/animation.d.ts +31 -0
- package/dist/types/animation.d.ts.map +1 -0
- package/dist/types/animation.js +1 -0
- package/dist/types/app.d.ts +148 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +1 -0
- package/dist/types/async.d.ts +30 -0
- package/dist/types/async.d.ts.map +1 -0
- package/dist/types/async.js +1 -0
- package/dist/types/capabilities.d.ts +44 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +33 -0
- package/dist/types/cells.d.ts +72 -0
- package/dist/types/cells.d.ts.map +1 -0
- package/dist/types/cells.js +10 -0
- package/dist/types/command.d.ts +127 -0
- package/dist/types/command.d.ts.map +1 -0
- package/dist/types/command.js +1 -0
- package/dist/types/component-registry.d.ts +77 -0
- package/dist/types/component-registry.d.ts.map +1 -0
- package/dist/types/component-registry.js +1 -0
- package/dist/types/disposable.d.ts +8 -0
- package/dist/types/disposable.d.ts.map +1 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/focus.d.ts +72 -0
- package/dist/types/focus.d.ts.map +1 -0
- package/dist/types/focus.js +1 -0
- package/dist/types/geometry.d.ts +28 -0
- package/dist/types/geometry.d.ts.map +1 -0
- package/dist/types/geometry.js +14 -0
- package/dist/types/graph.d.ts +129 -0
- package/dist/types/graph.d.ts.map +1 -0
- package/dist/types/graph.js +31 -0
- package/dist/types/i18n.d.ts +23 -0
- package/dist/types/i18n.d.ts.map +1 -0
- package/dist/types/i18n.js +1 -0
- package/dist/types/index.d.ts +32 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +31 -0
- package/dist/types/input.d.ts +65 -0
- package/dist/types/input.d.ts.map +1 -0
- package/dist/types/input.js +1 -0
- package/dist/types/keybinding.d.ts +49 -0
- package/dist/types/keybinding.d.ts.map +1 -0
- package/dist/types/keybinding.js +1 -0
- package/dist/types/layer.d.ts +54 -0
- package/dist/types/layer.d.ts.map +1 -0
- package/dist/types/layer.js +1 -0
- package/dist/types/manifest.d.ts +114 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +1 -0
- package/dist/types/markdown.d.ts +58 -0
- package/dist/types/markdown.d.ts.map +1 -0
- package/dist/types/markdown.js +1 -0
- package/dist/types/navigation.d.ts +40 -0
- package/dist/types/navigation.d.ts.map +1 -0
- package/dist/types/navigation.js +1 -0
- package/dist/types/render.d.ts +72 -0
- package/dist/types/render.d.ts.map +1 -0
- package/dist/types/render.js +1 -0
- package/dist/types/resource.d.ts +170 -0
- package/dist/types/resource.d.ts.map +1 -0
- package/dist/types/resource.js +1 -0
- package/dist/types/services.d.ts +24 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +3 -0
- package/dist/types/shell.d.ts +32 -0
- package/dist/types/shell.d.ts.map +1 -0
- package/dist/types/shell.js +1 -0
- package/dist/types/store.d.ts +124 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/store.js +1 -0
- package/dist/types/stream.d.ts +18 -0
- package/dist/types/stream.d.ts.map +1 -0
- package/dist/types/stream.js +1 -0
- package/dist/types/style.d.ts +166 -0
- package/dist/types/style.d.ts.map +1 -0
- package/dist/types/style.js +1 -0
- package/dist/types/surface.d.ts +97 -0
- package/dist/types/surface.d.ts.map +1 -0
- package/dist/types/surface.js +1 -0
- package/dist/types/syntax.d.ts +68 -0
- package/dist/types/syntax.d.ts.map +1 -0
- package/dist/types/syntax.js +5 -0
- package/dist/types/terminal.d.ts +52 -0
- package/dist/types/terminal.d.ts.map +1 -0
- package/dist/types/terminal.js +1 -0
- package/dist/types/theme.d.ts +117 -0
- package/dist/types/theme.d.ts.map +1 -0
- package/dist/types/theme.js +1 -0
- package/dist/types/when.d.ts +19 -0
- package/dist/types/when.d.ts.map +1 -0
- package/dist/types/when.js +1 -0
- package/dist/ui/primitives.d.ts +56 -0
- package/dist/ui/primitives.d.ts.map +1 -0
- package/dist/ui/primitives.js +108 -0
- package/dist/ui/screen.d.ts +23 -0
- package/dist/ui/screen.d.ts.map +1 -0
- package/dist/ui/screen.js +18 -0
- package/dist/util/disposable.d.ts +6 -0
- package/dist/util/disposable.d.ts.map +1 -0
- package/dist/util/disposable.js +49 -0
- package/dist/util/markdown.d.ts +24 -0
- package/dist/util/markdown.d.ts.map +1 -0
- package/dist/util/markdown.js +220 -0
- package/dist/util/paths.d.ts +47 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +134 -0
- package/dist/util/stream.d.ts +32 -0
- package/dist/util/stream.d.ts.map +1 -0
- package/dist/util/stream.js +206 -0
- package/dist/util/text.d.ts +65 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +419 -0
- package/package.json +70 -0
- package/src/adapters/index.ts +11 -0
- package/src/app/app.ts +1096 -0
- package/src/core/animation.ts +144 -0
- package/src/core/clipboard.ts +40 -0
- package/src/core/commands.ts +169 -0
- package/src/core/components.ts +91 -0
- package/src/core/events.ts +95 -0
- package/src/core/focus.ts +358 -0
- package/src/core/i18n.ts +107 -0
- package/src/core/keybindings.ts +184 -0
- package/src/core/layers.ts +94 -0
- package/src/core/manifest.ts +84 -0
- package/src/core/navigation.ts +135 -0
- package/src/core/resources.ts +362 -0
- package/src/core/services.ts +69 -0
- package/src/core/store.ts +640 -0
- package/src/core/surfaces.ts +292 -0
- package/src/core/syntax.ts +200 -0
- package/src/core/when.ts +238 -0
- package/src/index.ts +76 -0
- package/src/jsx/factory.ts +124 -0
- package/src/jsx/intrinsics.ts +99 -0
- package/src/jsx/jsx-dev-runtime.ts +23 -0
- package/src/jsx/jsx-runtime.ts +76 -0
- package/src/render/buffer.ts +318 -0
- package/src/render/color.ts +180 -0
- package/src/render/diff.ts +99 -0
- package/src/render/layout.ts +764 -0
- package/src/render/static.ts +290 -0
- package/src/runtime/bindings.ts +150 -0
- package/src/runtime/hooks.ts +1057 -0
- package/src/runtime/instance.ts +284 -0
- package/src/runtime/paint.ts +737 -0
- package/src/runtime/reconcile.ts +335 -0
- package/src/runtime/runtime.ts +47 -0
- package/src/runtime/style.ts +205 -0
- package/src/themes/borders.ts +95 -0
- package/src/themes/builtin.ts +301 -0
- package/src/themes/glyphs.ts +101 -0
- package/src/themes/index.ts +4 -0
- package/src/themes/registry.ts +224 -0
- package/src/types/adapter.ts +41 -0
- package/src/types/animation.ts +34 -0
- package/src/types/app.ts +149 -0
- package/src/types/async.ts +35 -0
- package/src/types/capabilities.ts +79 -0
- package/src/types/cells.ts +79 -0
- package/src/types/command.ts +139 -0
- package/src/types/component-registry.ts +82 -0
- package/src/types/disposable.ts +8 -0
- package/src/types/focus.ts +77 -0
- package/src/types/geometry.ts +50 -0
- package/src/types/graph.ts +174 -0
- package/src/types/i18n.ts +25 -0
- package/src/types/index.ts +31 -0
- package/src/types/input.ts +81 -0
- package/src/types/keybinding.ts +51 -0
- package/src/types/layer.ts +46 -0
- package/src/types/manifest.ts +101 -0
- package/src/types/markdown.ts +47 -0
- package/src/types/navigation.ts +42 -0
- package/src/types/render.ts +86 -0
- package/src/types/resource.ts +185 -0
- package/src/types/services.ts +28 -0
- package/src/types/shell.ts +30 -0
- package/src/types/store.ts +148 -0
- package/src/types/stream.ts +24 -0
- package/src/types/style.ts +205 -0
- package/src/types/surface.ts +119 -0
- package/src/types/syntax.ts +93 -0
- package/src/types/terminal.ts +58 -0
- package/src/types/theme.ts +121 -0
- package/src/types/when.ts +21 -0
- package/src/ui/primitives.ts +118 -0
- package/src/ui/screen.ts +41 -0
- package/src/util/disposable.ts +49 -0
- package/src/util/markdown.ts +225 -0
- package/src/util/paths.ts +138 -0
- package/src/util/stream.ts +213 -0
- package/src/util/text.ts +428 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/render/static.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAwB,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAoBrC;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,OAAO,IAAI,IAAI,CAAC;CACjB;AAaD,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,mBAAwB,GAAG;IACtE,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB,CA0EA;AAYD,wBAAgB,UAAU,CACxB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CA2EpB;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAO7F"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { Buffer } from './buffer.js';
|
|
2
|
+
import { layout, resolveEdges } from './layout.js';
|
|
3
|
+
import { buildBoxes, paintTree } from '../runtime/paint.js';
|
|
4
|
+
import { collectEffects, disposeTree, renderTree } from '../runtime/reconcile.js';
|
|
5
|
+
import { flushMeasures } from '../runtime/hooks.js';
|
|
6
|
+
import { NO_INTERACTION } from '../runtime/style.js';
|
|
7
|
+
import { createStore } from '../core/store.js';
|
|
8
|
+
import { createEvents } from '../core/events.js';
|
|
9
|
+
import { createWhen } from '../core/when.js';
|
|
10
|
+
import { createComponents } from '../core/components.js';
|
|
11
|
+
import { createServices } from '../core/services.js';
|
|
12
|
+
import { createFocus } from '../core/focus.js';
|
|
13
|
+
import { createLayers } from '../core/layers.js';
|
|
14
|
+
import { createAnimation } from '../core/animation.js';
|
|
15
|
+
import { createI18n } from '../core/i18n.js';
|
|
16
|
+
import { createThemes } from '../themes/registry.js';
|
|
17
|
+
import { PRIMITIVES } from '../ui/primitives.js';
|
|
18
|
+
import { FULL_CAPABILITIES } from '../types/capabilities.js';
|
|
19
|
+
import { ZERO_EDGES } from '../types/geometry.js';
|
|
20
|
+
const DEFAULT_CAPABILITIES = {
|
|
21
|
+
...FULL_CAPABILITIES,
|
|
22
|
+
mouse: false,
|
|
23
|
+
wheel: false,
|
|
24
|
+
focusEvents: false,
|
|
25
|
+
paste: false,
|
|
26
|
+
altScreen: false,
|
|
27
|
+
synchronizedOutput: false,
|
|
28
|
+
kittyKeyboard: false,
|
|
29
|
+
};
|
|
30
|
+
export function createStaticRuntime(options = {}) {
|
|
31
|
+
const store = createStore();
|
|
32
|
+
const events = createEvents();
|
|
33
|
+
const when = createWhen(store);
|
|
34
|
+
const components = createComponents();
|
|
35
|
+
const services = createServices();
|
|
36
|
+
const focus = createFocus();
|
|
37
|
+
const layers = createLayers();
|
|
38
|
+
const animation = createAnimation({ manual: true, enabled: false });
|
|
39
|
+
const i18n = createI18n(options.locale ?? 'en');
|
|
40
|
+
const themes = createThemes(options.themes);
|
|
41
|
+
// The four primitives, and nothing else by default.
|
|
42
|
+
//
|
|
43
|
+
// This registered the whole catalog until it didn't: some eighty entries a
|
|
44
|
+
// screen made of `box` and `text` never looked at, and that JSX never
|
|
45
|
+
// needed either, since an imported component travels on its own node.
|
|
46
|
+
// Naming a component in data is the case a registry is for, and that case
|
|
47
|
+
// asks for it through `components`.
|
|
48
|
+
components.registerMany(PRIMITIVES);
|
|
49
|
+
if (options.components)
|
|
50
|
+
components.registerMany(options.components);
|
|
51
|
+
const capabilities = {
|
|
52
|
+
...DEFAULT_CAPABILITIES,
|
|
53
|
+
...options.capabilities,
|
|
54
|
+
};
|
|
55
|
+
let size = { width: options.width ?? 80, height: 24 };
|
|
56
|
+
const onError = options.onError ?? ((err, context) => {
|
|
57
|
+
console.error(`[textui] ${context}`, err);
|
|
58
|
+
});
|
|
59
|
+
store.onError = onError;
|
|
60
|
+
events.onError = onError;
|
|
61
|
+
if (options.initialState) {
|
|
62
|
+
store.batch(() => {
|
|
63
|
+
for (const [path, value] of Object.entries(options.initialState)) {
|
|
64
|
+
store.set((path.startsWith('$/') ? path : `$/${path}`), value);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
store.set('$/modus/capabilities', capabilities);
|
|
69
|
+
store.set('$/modus/size', size);
|
|
70
|
+
const runtime = {
|
|
71
|
+
store, events, when, components, services, focus, layers, animation, i18n,
|
|
72
|
+
theme: () => themes.resolve(options.theme ?? 'dark', capabilities),
|
|
73
|
+
capabilities: () => capabilities,
|
|
74
|
+
size: () => size,
|
|
75
|
+
execute: (id) => {
|
|
76
|
+
throw new Error(`[textui] command "${id}" cannot run under the static renderer`);
|
|
77
|
+
},
|
|
78
|
+
emit: (path, payload) => events.emit(path, payload),
|
|
79
|
+
requestRender: () => { },
|
|
80
|
+
app: () => null,
|
|
81
|
+
onError,
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
runtime,
|
|
85
|
+
setSize(width, height) {
|
|
86
|
+
size = { width, height };
|
|
87
|
+
store.set('$/modus/size', size);
|
|
88
|
+
},
|
|
89
|
+
dispose() {
|
|
90
|
+
animation.dispose();
|
|
91
|
+
layers.dispose();
|
|
92
|
+
events.dispose();
|
|
93
|
+
store.dispose();
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function rootBoxFor(children) {
|
|
98
|
+
return {
|
|
99
|
+
style: { direction: 'column' },
|
|
100
|
+
borderEdges: ZERO_EDGES,
|
|
101
|
+
children,
|
|
102
|
+
rect: { x: 0, y: 0, width: 0, height: 0 },
|
|
103
|
+
content: { x: 0, y: 0, width: 0, height: 0 },
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function renderOnce(node, options = {}) {
|
|
107
|
+
const width = options.width ?? 80;
|
|
108
|
+
const { runtime, setSize, dispose: disposeRuntime } = createStaticRuntime(options);
|
|
109
|
+
// Measure against a generous height first when the caller wants `auto`, so
|
|
110
|
+
// nothing is clipped before we know how tall the content actually is.
|
|
111
|
+
const measureHeight = options.height === 'auto' || options.height === undefined
|
|
112
|
+
? 4096
|
|
113
|
+
: options.height;
|
|
114
|
+
setSize(width, measureHeight);
|
|
115
|
+
const env = {
|
|
116
|
+
theme: runtime.theme(),
|
|
117
|
+
capabilities: runtime.capabilities(),
|
|
118
|
+
stateOf: () => NO_INTERACTION,
|
|
119
|
+
};
|
|
120
|
+
let root = null;
|
|
121
|
+
const maxPasses = options.maxPasses ?? 8;
|
|
122
|
+
for (let pass = 0; pass < maxPasses; pass++) {
|
|
123
|
+
root = renderTree(runtime, root, node);
|
|
124
|
+
const effects = collectEffects(root);
|
|
125
|
+
if (effects.length === 0)
|
|
126
|
+
break;
|
|
127
|
+
for (const effect of effects)
|
|
128
|
+
effect();
|
|
129
|
+
if (!hasDirty(root))
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
let instance = root;
|
|
133
|
+
let boxes = buildBoxes(instance, env);
|
|
134
|
+
let rootBox = rootBoxFor(boxes);
|
|
135
|
+
layout(rootBox, { x: 0, y: 0, width, height: measureHeight });
|
|
136
|
+
// A measured component only knows its size once it has been laid out. Give
|
|
137
|
+
// it that, then render again - otherwise the static renderer is the one
|
|
138
|
+
// place where a viewport draws nothing.
|
|
139
|
+
for (let pass = 0; pass < maxPasses && flushMeasures(); pass++) {
|
|
140
|
+
instance = renderTree(runtime, instance, node);
|
|
141
|
+
for (const effect of collectEffects(instance))
|
|
142
|
+
effect();
|
|
143
|
+
boxes = buildBoxes(instance, env);
|
|
144
|
+
rootBox = rootBoxFor(boxes);
|
|
145
|
+
layout(rootBox, { x: 0, y: 0, width, height: measureHeight });
|
|
146
|
+
}
|
|
147
|
+
const used = contentHeight(rootBox);
|
|
148
|
+
const height = options.height === 'auto' || options.height === undefined
|
|
149
|
+
? Math.max(1, used)
|
|
150
|
+
: options.height;
|
|
151
|
+
// Lay out again at the real height so `flex` and `justify` see the truth.
|
|
152
|
+
if (height !== measureHeight) {
|
|
153
|
+
setSize(width, height);
|
|
154
|
+
layout(rootBox, { x: 0, y: 0, width, height });
|
|
155
|
+
for (let pass = 0; pass < maxPasses && flushMeasures(); pass++) {
|
|
156
|
+
instance = renderTree(runtime, instance, node);
|
|
157
|
+
for (const effect of collectEffects(instance))
|
|
158
|
+
effect();
|
|
159
|
+
rootBox = rootBoxFor(buildBoxes(instance, env));
|
|
160
|
+
layout(rootBox, { x: 0, y: 0, width, height });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const buffer = new Buffer(width, height);
|
|
164
|
+
paintTree(buffer, instance, env, { x: 0, y: 0, width, height });
|
|
165
|
+
return {
|
|
166
|
+
buffer,
|
|
167
|
+
text: buffer.toText(),
|
|
168
|
+
root: instance,
|
|
169
|
+
runtime,
|
|
170
|
+
dispose() {
|
|
171
|
+
disposeTree(instance);
|
|
172
|
+
disposeRuntime();
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/** Render to plain text. The shortest path from a component to a string. */
|
|
177
|
+
export function renderToString(node, options = {}) {
|
|
178
|
+
const result = renderOnce(node, options);
|
|
179
|
+
try {
|
|
180
|
+
return result.text;
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
result.dispose();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function contentHeight(box) {
|
|
187
|
+
let bottom = 0;
|
|
188
|
+
const walk = (b) => {
|
|
189
|
+
if (b.rect.width > 0 && b.rect.height > 0) {
|
|
190
|
+
// Plus the margin below it, which is space the box needs even though
|
|
191
|
+
// nothing paints there. Measuring to the bottom edge alone reports a
|
|
192
|
+
// height the layout cannot reproduce: laid out again inside it, the
|
|
193
|
+
// margin has to come out of the box, and the box loses the rows.
|
|
194
|
+
// `<box margin={2} border="single">` measured 5 and then drew one row
|
|
195
|
+
// of a three-row box.
|
|
196
|
+
bottom = Math.max(bottom, b.rect.y + b.rect.height + resolveEdges(b.style.margin).bottom);
|
|
197
|
+
}
|
|
198
|
+
for (const child of b.children)
|
|
199
|
+
walk(child);
|
|
200
|
+
};
|
|
201
|
+
for (const child of box.children)
|
|
202
|
+
walk(child);
|
|
203
|
+
return bottom;
|
|
204
|
+
}
|
|
205
|
+
function hasDirty(instance) {
|
|
206
|
+
if (instance.dirty)
|
|
207
|
+
return true;
|
|
208
|
+
return instance.children.some(hasDirty);
|
|
209
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Action, BindingPath, ComponentNode } from '../types/graph.js';
|
|
2
|
+
import type { ReactiveStore } from '../types/store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prop values arrive as literals, bindings (`{ path }`) or function calls
|
|
5
|
+
* (`{ call }`). Resolving them is what makes a node written as data behave
|
|
6
|
+
* exactly like one written in JSX.
|
|
7
|
+
*
|
|
8
|
+
* Every path read during a resolve is recorded, so the caller can subscribe to
|
|
9
|
+
* precisely the paths this subtree depends on and re-render on nothing else.
|
|
10
|
+
*/
|
|
11
|
+
export interface ResolveContext {
|
|
12
|
+
store: ReactiveStore;
|
|
13
|
+
/** Relative paths resolve against this. */
|
|
14
|
+
dataContext?: BindingPath;
|
|
15
|
+
/** Run a registered command. */
|
|
16
|
+
execute(id: string, args?: Record<string, unknown>): unknown;
|
|
17
|
+
/** Publish on an event path. */
|
|
18
|
+
emit(path: string, payload?: unknown): void;
|
|
19
|
+
/** Collected during the resolve; the caller subscribes to these. */
|
|
20
|
+
reads: Set<string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Turn an action into something callable. Actions stay data right up to the
|
|
24
|
+
* moment they are invoked, which is what lets the same button work whether it
|
|
25
|
+
* was written in JSX with a closure or loaded from JSON naming a command.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveAction(ctx: ResolveContext, action: Action | ((...args: unknown[]) => unknown) | undefined): ((...args: unknown[]) => unknown) | undefined;
|
|
28
|
+
/** Resolve one prop value, leaving nodes and closures alone. */
|
|
29
|
+
export declare function resolveValue(ctx: ResolveContext, value: unknown): unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve every prop on a node. `component`, `id`, `key` and `$meta` are
|
|
32
|
+
* structural and pass through untouched.
|
|
33
|
+
*
|
|
34
|
+
* A prop named `onSomething` whose value is an action becomes a callable, so a
|
|
35
|
+
* node loaded from JSON can say `{ onPress: { functionCall: { call: 'x' } } }`
|
|
36
|
+
* and the component receives the same shape it would get from JSX. Without
|
|
37
|
+
* this, actions-as-data would only work on the handful of props the runtime
|
|
38
|
+
* knew about by name.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveProps(ctx: ResolveContext, node: ComponentNode): Record<string, unknown>;
|
|
41
|
+
/** True when the value is a templated child list: one instance per item. */
|
|
42
|
+
export declare function isTemplateChildren(v: unknown): v is {
|
|
43
|
+
template: ComponentNode;
|
|
44
|
+
path: BindingPath;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=bindings.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { isAction, isComponentNode, isDataBinding, isFunctionCall } from '../types/graph.js';
|
|
2
|
+
import { resolvePath } from '../util/paths.js';
|
|
3
|
+
/** `#/a/b` means: the value AT this path is itself a path. One extra hop. */
|
|
4
|
+
function readPath(ctx, raw) {
|
|
5
|
+
let path = raw;
|
|
6
|
+
// `{{ /other/path }}` substitutes another path's value into this one first.
|
|
7
|
+
if (path.includes('{{')) {
|
|
8
|
+
path = path.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_m, inner) => {
|
|
9
|
+
const resolved = resolvePath(inner.trim(), ctx.dataContext);
|
|
10
|
+
ctx.reads.add(resolved);
|
|
11
|
+
return String(ctx.store.get(resolved) ?? '');
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (path.startsWith('#/')) {
|
|
15
|
+
const indirect = resolvePath(path.slice(1), ctx.dataContext);
|
|
16
|
+
ctx.reads.add(indirect);
|
|
17
|
+
const target = ctx.store.get(indirect);
|
|
18
|
+
if (typeof target !== 'string')
|
|
19
|
+
return undefined;
|
|
20
|
+
const final = resolvePath(target, ctx.dataContext);
|
|
21
|
+
ctx.reads.add(final);
|
|
22
|
+
return ctx.store.get(final);
|
|
23
|
+
}
|
|
24
|
+
const resolved = resolvePath(path, ctx.dataContext);
|
|
25
|
+
ctx.reads.add(resolved);
|
|
26
|
+
return ctx.store.get(resolved);
|
|
27
|
+
}
|
|
28
|
+
function resolveCall(ctx, call) {
|
|
29
|
+
const args = {};
|
|
30
|
+
for (const [k, v] of Object.entries(call.args ?? {})) {
|
|
31
|
+
args[k] = resolveValue(ctx, v);
|
|
32
|
+
}
|
|
33
|
+
return ctx.execute(call.call, args);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Turn an action into something callable. Actions stay data right up to the
|
|
37
|
+
* moment they are invoked, which is what lets the same button work whether it
|
|
38
|
+
* was written in JSX with a closure or loaded from JSON naming a command.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveAction(ctx, action) {
|
|
41
|
+
if (action === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
if (typeof action === 'function')
|
|
44
|
+
return action;
|
|
45
|
+
if ('handler' in action)
|
|
46
|
+
return action.handler;
|
|
47
|
+
if ('functionCall' in action) {
|
|
48
|
+
return () => resolveCall(ctx, action.functionCall);
|
|
49
|
+
}
|
|
50
|
+
if ('emit' in action) {
|
|
51
|
+
return () => ctx.emit(action.emit.path, resolveValue(ctx, action.emit.payload));
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
/** Resolve one prop value, leaving nodes and closures alone. */
|
|
56
|
+
export function resolveValue(ctx, value) {
|
|
57
|
+
if (value === null || value === undefined)
|
|
58
|
+
return value;
|
|
59
|
+
if (typeof value !== 'object')
|
|
60
|
+
return value;
|
|
61
|
+
if (typeof value === 'function')
|
|
62
|
+
return value;
|
|
63
|
+
if (isDataBinding(value))
|
|
64
|
+
return readPath(ctx, value.path);
|
|
65
|
+
if (isFunctionCall(value))
|
|
66
|
+
return resolveCall(ctx, value);
|
|
67
|
+
// Nodes and templated child lists stay as they are; the reconciler owns them.
|
|
68
|
+
if (isComponentNode(value))
|
|
69
|
+
return value;
|
|
70
|
+
if (isAction(value))
|
|
71
|
+
return value;
|
|
72
|
+
if (Array.isArray(value))
|
|
73
|
+
return value.map((v) => resolveValue(ctx, v));
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const [k, v] of Object.entries(value)) {
|
|
76
|
+
out[k] = resolveValue(ctx, v);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolve every prop on a node. `component`, `id`, `key` and `$meta` are
|
|
82
|
+
* structural and pass through untouched.
|
|
83
|
+
*
|
|
84
|
+
* A prop named `onSomething` whose value is an action becomes a callable, so a
|
|
85
|
+
* node loaded from JSON can say `{ onPress: { functionCall: { call: 'x' } } }`
|
|
86
|
+
* and the component receives the same shape it would get from JSX. Without
|
|
87
|
+
* this, actions-as-data would only work on the handful of props the runtime
|
|
88
|
+
* knew about by name.
|
|
89
|
+
*/
|
|
90
|
+
export function resolveProps(ctx, node) {
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [k, v] of Object.entries(node)) {
|
|
93
|
+
if (k === 'component' || k === '$meta' || k === 'key')
|
|
94
|
+
continue;
|
|
95
|
+
if (k === 'children') {
|
|
96
|
+
out.children = v;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (isHandlerProp(k) && isAction(v)) {
|
|
100
|
+
out[k] = resolveAction(ctx, v);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
out[k] = resolveValue(ctx, v);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
/** `onPress`, `onSelect`, `onChange` - but not `once` or `only`. */
|
|
108
|
+
function isHandlerProp(key) {
|
|
109
|
+
return key.length > 2 && key.startsWith('on') && key[2] === key[2]?.toUpperCase();
|
|
110
|
+
}
|
|
111
|
+
/** True when the value is a templated child list: one instance per item. */
|
|
112
|
+
export function isTemplateChildren(v) {
|
|
113
|
+
return (typeof v === 'object' && v !== null &&
|
|
114
|
+
'template' in v && 'path' in v &&
|
|
115
|
+
isComponentNode(v.template));
|
|
116
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import type { BindingPath, EventPath } from '../types/graph.js';
|
|
2
|
+
import type { Disposable } from '../types/disposable.js';
|
|
3
|
+
import type { ResolvedTheme } from '../types/theme.js';
|
|
4
|
+
import type { TerminalCapabilities } from '../types/capabilities.js';
|
|
5
|
+
import type { Rect, Size } from '../types/geometry.js';
|
|
6
|
+
import type { ServiceKey } from '../types/services.js';
|
|
7
|
+
import type { KeyEvent } from '../types/input.js';
|
|
8
|
+
import type { CommandDefinition } from '../types/command.js';
|
|
9
|
+
import type { FocusDirection } from '../types/focus.js';
|
|
10
|
+
import type { TaskFn, TaskState } from '../types/async.js';
|
|
11
|
+
import type { StreamSource } from '../types/stream.js';
|
|
12
|
+
import type { TextUIApp } from '../types/app.js';
|
|
13
|
+
import type { I18n } from '../types/i18n.js';
|
|
14
|
+
import type { Navigator } from '../types/navigation.js';
|
|
15
|
+
import type { Resource } from '../types/resource.js';
|
|
16
|
+
import type { SyntaxQuery, SyntaxRegistry, SyntaxToken } from '../types/syntax.js';
|
|
17
|
+
import type { RenderOutput } from '../types/render.js';
|
|
18
|
+
import type { Instance } from './instance.js';
|
|
19
|
+
import type { Runtime } from './runtime.js';
|
|
20
|
+
export declare function setCurrentInstance(instance: Instance | null): void;
|
|
21
|
+
export declare function currentInstance(): Instance;
|
|
22
|
+
export declare function useRuntime(): Runtime;
|
|
23
|
+
export type SetState<T> = (next: T | ((prev: T) => T)) => void;
|
|
24
|
+
export declare function useState<T>(initial: T | (() => T)): [T, SetState<T>];
|
|
25
|
+
export declare function useReducer<S, A>(reducer: (state: S, action: A) => S, initial: S): [S, (action: A) => void];
|
|
26
|
+
export declare function useRef<T>(initial: T): {
|
|
27
|
+
current: T;
|
|
28
|
+
};
|
|
29
|
+
export declare function useMemo<T>(factory: () => T, deps: unknown[]): T;
|
|
30
|
+
export declare function useCallback<T extends (...args: never[]) => unknown>(fn: T, deps: unknown[]): T;
|
|
31
|
+
/**
|
|
32
|
+
* Runs after the frame is painted. The returned function runs before the next
|
|
33
|
+
* run and on unmount - so a subscription set up here is torn down exactly once.
|
|
34
|
+
*/
|
|
35
|
+
export declare function useEffect(effect: () => void | (() => void), deps?: unknown[]): void;
|
|
36
|
+
/** Same contract as `useEffect`, but flushed before the frame is painted. */
|
|
37
|
+
export declare function useLayoutEffect(effect: () => void | (() => void), deps?: unknown[]): void;
|
|
38
|
+
export interface Context<T> {
|
|
39
|
+
id: string;
|
|
40
|
+
defaultValue: T;
|
|
41
|
+
Provider: (props: {
|
|
42
|
+
value: T;
|
|
43
|
+
children?: unknown;
|
|
44
|
+
}) => RenderOutput;
|
|
45
|
+
}
|
|
46
|
+
export declare function createContext<T>(name: string, defaultValue: T): Context<T>;
|
|
47
|
+
export declare function useContext<T>(context: Context<T>): T;
|
|
48
|
+
/**
|
|
49
|
+
* Store-backed state, in the shape of `useState`.
|
|
50
|
+
*
|
|
51
|
+
* The second argument is an initial value, and it behaves like one: if the
|
|
52
|
+
* path is empty the first time a component asks for it, it is written. That is
|
|
53
|
+
* what makes the hook safe to read like state - every other reader of the same
|
|
54
|
+
* path sees the same thing, immediately, rather than each one privately
|
|
55
|
+
* imagining its own default.
|
|
56
|
+
*
|
|
57
|
+
* The store stays authoritative. Copying a value out into `useState` and
|
|
58
|
+
* editing the copy creates a second answer to a question the store already
|
|
59
|
+
* answers; this hook is the way to avoid needing to.
|
|
60
|
+
*
|
|
61
|
+
* For a reader that must not write - a component displaying a path that
|
|
62
|
+
* something else owns - use `useStoreValue`, whose second argument is a
|
|
63
|
+
* display fallback and nothing more.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useStore<T = unknown>(path: BindingPath, initial?: T): [T | undefined, (value: T) => void];
|
|
66
|
+
/**
|
|
67
|
+
* Read a store path without ever writing it.
|
|
68
|
+
*
|
|
69
|
+
* `fallback` is what this reader shows while the path is empty. It is not an
|
|
70
|
+
* initial value and it is not shared: another component reading the same path
|
|
71
|
+
* still sees nothing.
|
|
72
|
+
*/
|
|
73
|
+
export declare function useStoreValue<T = unknown>(path: BindingPath, fallback?: T): T | undefined;
|
|
74
|
+
/** Subscribe to a whole subtree - a namespace, a collection, a scope. */
|
|
75
|
+
export declare function useStoreSubtree<T = unknown>(path: BindingPath): T | undefined;
|
|
76
|
+
export declare function useCollection<T = unknown>(path: BindingPath): import("../index.js").CollectionOps<T>;
|
|
77
|
+
export declare function useEvent(path: EventPath, handler: (payload: unknown) => void, options?: {
|
|
78
|
+
subtree?: boolean;
|
|
79
|
+
}): void;
|
|
80
|
+
export declare function useEmit(): (path: EventPath, payload?: unknown) => void;
|
|
81
|
+
export declare function useApp(): TextUIApp;
|
|
82
|
+
export declare function useTheme(): ResolvedTheme;
|
|
83
|
+
export declare function useCapabilities(): TerminalCapabilities;
|
|
84
|
+
/** Terminal size, re-rendering on resize. */
|
|
85
|
+
export declare function useSize(): Size;
|
|
86
|
+
/**
|
|
87
|
+
* Adapt to the space this component was actually given, not to the terminal.
|
|
88
|
+
* A sidebar and the main area are different widths on the same screen.
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* The content rect this component was last laid out into.
|
|
92
|
+
*
|
|
93
|
+
* A component that fills the space it is given cannot size itself from its
|
|
94
|
+
* content - a file viewer that renders one row per line makes every pane
|
|
95
|
+
* around it move when a different file is opened. Measuring inverts that: the
|
|
96
|
+
* layout decides the size, and the component renders exactly what fits.
|
|
97
|
+
*
|
|
98
|
+
* The value is the previous frame's, and asking for it schedules another pass
|
|
99
|
+
* when it changed, so the first frame after a resize is one frame behind and
|
|
100
|
+
* every frame after it is exact.
|
|
101
|
+
*/
|
|
102
|
+
export declare function useMeasure(): Rect;
|
|
103
|
+
/**
|
|
104
|
+
* How big the content is, when it is bigger than the box holding it.
|
|
105
|
+
*
|
|
106
|
+
* `null` when everything fits. The layout has always recorded this - the
|
|
107
|
+
* comment where it does says "so a scroll container knows how far it can go" -
|
|
108
|
+
* but nothing read it, so no scroll container knew, and every one of them
|
|
109
|
+
* scrolled for ever past its own last line.
|
|
110
|
+
*
|
|
111
|
+
* Reported for the nearest *scroll container* at or below this component's own
|
|
112
|
+
* box - a viewport is a row holding the scrolling part beside a scrollbar, and
|
|
113
|
+
* the row is not the part that scrolls.
|
|
114
|
+
*/
|
|
115
|
+
export declare function useScrollExtent(): Size | null;
|
|
116
|
+
/**
|
|
117
|
+
* Publish every watcher's laid-out rect. Returns true when one changed, which
|
|
118
|
+
* means the frame is not final and the caller should render again.
|
|
119
|
+
*/
|
|
120
|
+
export declare function flushMeasures(): boolean;
|
|
121
|
+
export declare function useBreakpoint(width: number, breakpoints?: {
|
|
122
|
+
compact?: number;
|
|
123
|
+
minimal?: number;
|
|
124
|
+
}): 'full' | 'compact' | 'minimal';
|
|
125
|
+
export declare function useI18n(): I18n;
|
|
126
|
+
export declare function useService<T>(key: ServiceKey<T>): T | undefined;
|
|
127
|
+
export declare function useRequiredService<T>(key: ServiceKey<T>): T;
|
|
128
|
+
export interface UseFocusOptions {
|
|
129
|
+
id?: string;
|
|
130
|
+
disabled?: boolean;
|
|
131
|
+
skipTab?: boolean;
|
|
132
|
+
autoFocus?: boolean;
|
|
133
|
+
order?: number;
|
|
134
|
+
scopeId?: string;
|
|
135
|
+
onFocus?(): void;
|
|
136
|
+
onBlur?(): void;
|
|
137
|
+
}
|
|
138
|
+
export interface FocusHandle {
|
|
139
|
+
id: string;
|
|
140
|
+
focused: boolean;
|
|
141
|
+
focus(): void;
|
|
142
|
+
blur(): void;
|
|
143
|
+
move(direction: FocusDirection): void;
|
|
144
|
+
}
|
|
145
|
+
/** The focus scope this instance sits inside, if any. */
|
|
146
|
+
export declare function focusScopeOf(instance: Instance): string | undefined;
|
|
147
|
+
export declare function useFocus(options?: UseFocusOptions): FocusHandle;
|
|
148
|
+
/** A focus scope. Modals trap; a sidebar does not. */
|
|
149
|
+
export declare function useFocusScope(options?: {
|
|
150
|
+
id?: string;
|
|
151
|
+
trap?: boolean;
|
|
152
|
+
restore?: boolean;
|
|
153
|
+
autoFocus?: boolean;
|
|
154
|
+
active?: boolean;
|
|
155
|
+
}): string;
|
|
156
|
+
/**
|
|
157
|
+
* Keyboard input. Scoped to focus by default - a handler that fires while
|
|
158
|
+
* something else is focused is nearly always a bug, so `global` has to be
|
|
159
|
+
* asked for.
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* A key that is not this control's to take.
|
|
163
|
+
*
|
|
164
|
+
* A list handles `pagedown`, and `ctrl+pagedown` is an application saying
|
|
165
|
+
* "next file" over the top of it - one is navigation inside the control, the
|
|
166
|
+
* other is a chord aimed past it. A control that switches on `event.name`
|
|
167
|
+
* alone takes both, and the application's binding then works everywhere except
|
|
168
|
+
* in the pane a person is actually looking at.
|
|
169
|
+
*/
|
|
170
|
+
export declare function chorded(event: KeyEvent): boolean;
|
|
171
|
+
export declare function useInput(handler: (event: KeyEvent) => boolean | void, options?: {
|
|
172
|
+
focusId?: string;
|
|
173
|
+
global?: boolean;
|
|
174
|
+
enabled?: boolean;
|
|
175
|
+
}): void;
|
|
176
|
+
/**
|
|
177
|
+
* The screen this is drawn inside: which one, and what it was given.
|
|
178
|
+
*
|
|
179
|
+
* Reads the published entry rather than props, so a control eight levels down
|
|
180
|
+
* can ask which task it is showing without every box between it and the screen
|
|
181
|
+
* forwarding an id it does not care about.
|
|
182
|
+
*/
|
|
183
|
+
/**
|
|
184
|
+
* Keys, by the name they are written under everywhere else.
|
|
185
|
+
*
|
|
186
|
+
* `useInput` hands you a `KeyEvent` and leaves you to compare its fields,
|
|
187
|
+
* which is four lines of `event.ctrl && event.name === 's'` per key and a bug
|
|
188
|
+
* the first time somebody forgets that shift is implied by an uppercase
|
|
189
|
+
* letter. The keybinding registry already had the answer - one canonical
|
|
190
|
+
* spelling per stroke - so this reads the same strings.
|
|
191
|
+
*
|
|
192
|
+
* useKeymap({
|
|
193
|
+
* '+': () => setCount((c) => c + 1),
|
|
194
|
+
* '-': () => setCount((c) => c - 1),
|
|
195
|
+
* space: () => setRunning((r) => !r),
|
|
196
|
+
* 'ctrl+s': save,
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* Global by default, unlike `useInput`. A component that lists the keys it
|
|
200
|
+
* wants almost never also wants them to stop working the moment focus lands
|
|
201
|
+
* somewhere else - and the screens where that is wrong have a focusable to
|
|
202
|
+
* name, so they can say `{ global: false }` and mean it.
|
|
203
|
+
*
|
|
204
|
+
* A handler that returns nothing has handled the key. Return `false` to let
|
|
205
|
+
* it carry on to whatever is behind.
|
|
206
|
+
*/
|
|
207
|
+
export declare function useKeymap(map: Record<string, (event: KeyEvent) => boolean | void>, options?: {
|
|
208
|
+
focusId?: string;
|
|
209
|
+
global?: boolean;
|
|
210
|
+
enabled?: boolean;
|
|
211
|
+
}): void;
|
|
212
|
+
export declare function useScreen<P = Record<string, unknown>>(): {
|
|
213
|
+
id: string | null;
|
|
214
|
+
params: P;
|
|
215
|
+
};
|
|
216
|
+
/** The stack, for a component that moves between screens. */
|
|
217
|
+
export declare function useNavigate(): Navigator;
|
|
218
|
+
export declare function useCommand(def: Omit<CommandDefinition, 'scopeId'>, deps?: unknown[]): void;
|
|
219
|
+
export declare function useExecute(): (id: string, args?: Record<string, unknown>) => unknown;
|
|
220
|
+
export interface TaskHandle<T> extends TaskState<T> {
|
|
221
|
+
run(...args: unknown[]): Promise<T | undefined>;
|
|
222
|
+
cancel(): void;
|
|
223
|
+
reset(): void;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* An async unit of work with a lifecycle a component can render: idle,
|
|
227
|
+
* running, success, error, cancelled - plus progress and cancellation.
|
|
228
|
+
*/
|
|
229
|
+
export declare function useTask<T>(fn: TaskFn<T>, deps?: unknown[]): TaskHandle<T>;
|
|
230
|
+
/** A task that runs on mount and can be refreshed. */
|
|
231
|
+
export declare function useResource<T>(fn: TaskFn<T>, deps?: unknown[]): TaskHandle<T> & {
|
|
232
|
+
refresh(): void;
|
|
233
|
+
};
|
|
234
|
+
/** Read a resource through the registry, by URI. */
|
|
235
|
+
export declare function useResourceUri(uri: string | null): {
|
|
236
|
+
resource: Resource | null;
|
|
237
|
+
content: string | Uint8Array | null;
|
|
238
|
+
status: TaskState['status'];
|
|
239
|
+
error: unknown;
|
|
240
|
+
refresh(): void;
|
|
241
|
+
};
|
|
242
|
+
/** The highlighter registry, or undefined outside an application. */
|
|
243
|
+
export declare function useSyntax(): SyntaxRegistry | undefined;
|
|
244
|
+
/**
|
|
245
|
+
* Tokenise text for display, memoised on the text and the query.
|
|
246
|
+
*
|
|
247
|
+
* Nothing registered for this kind means one plain token per line, which is
|
|
248
|
+
* exactly what an uncoloured viewer wants - so a caller never branches on
|
|
249
|
+
* whether highlighting exists.
|
|
250
|
+
*/
|
|
251
|
+
export declare function useHighlight(text: string, query?: SyntaxQuery): SyntaxToken[][];
|
|
252
|
+
export interface ClipboardHandle {
|
|
253
|
+
/** What is on the clipboard now. Reading it here means a menu row that
|
|
254
|
+
* offers "Paste" redraws when there is something to paste. */
|
|
255
|
+
text: string;
|
|
256
|
+
read(): string;
|
|
257
|
+
write(text: string): void;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The clipboard, as a hook.
|
|
261
|
+
*
|
|
262
|
+
* `write` puts the text on the system clipboard as well, when the terminal
|
|
263
|
+
* can take it. Nothing reads the system clipboard back - see
|
|
264
|
+
* `core/clipboard.ts` for why - so a paste is whatever this application last
|
|
265
|
+
* copied, plus whatever the terminal delivers as a bracketed paste.
|
|
266
|
+
*/
|
|
267
|
+
export declare function useClipboard(): ClipboardHandle;
|
|
268
|
+
/** The most recent `limit` values from any stream source. */
|
|
269
|
+
export declare function useStream<T>(source: StreamSource<T> | null, options?: {
|
|
270
|
+
limit?: number;
|
|
271
|
+
}): T[];
|
|
272
|
+
/** A frame ticker, throttled and globally disableable by the driver. */
|
|
273
|
+
export declare function useTicker(onTick: (frame: number, elapsedMs: number) => void, options?: {
|
|
274
|
+
fps?: number;
|
|
275
|
+
enabled?: boolean;
|
|
276
|
+
}): void;
|
|
277
|
+
/** A frame counter, for spinners and marquees. Frozen when animation is off. */
|
|
278
|
+
export declare function useFrame(fps?: number): number;
|
|
279
|
+
/** A value that eases towards its target. Snaps when animation is off. */
|
|
280
|
+
export declare function useTween(target: number, durationMs?: number): number;
|
|
281
|
+
export declare function useInterval(fn: () => void, ms: number, enabled?: boolean): void;
|
|
282
|
+
/** Register a disposable for the lifetime of this component. */
|
|
283
|
+
export declare function useDisposable(factory: () => Disposable, deps?: unknown[]): void;
|
|
284
|
+
//# sourceMappingURL=hooks.d.ts.map
|