@promptctl/rich-js 0.18.1 → 0.20.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/README.md +11 -8
- package/dist/core/box.d.ts +3 -1
- package/dist/core/box.js +6 -13
- package/dist/core/cells.d.ts +61 -28
- package/dist/core/cells.js +171 -124
- package/dist/core/clock.d.ts +48 -0
- package/dist/core/clock.js +42 -0
- package/dist/core/color.d.ts +99 -18
- package/dist/core/color.js +334 -146
- package/dist/core/console.d.ts +38 -7
- package/dist/core/console.js +159 -90
- package/dist/core/easing.d.ts +86 -0
- package/dist/core/easing.js +171 -0
- package/dist/core/env.d.ts +16 -0
- package/dist/core/env.js +16 -0
- package/dist/core/export-html.js +1 -4
- package/dist/core/export-lines.d.ts +22 -13
- package/dist/core/export-lines.js +37 -19
- package/dist/core/export-svg.d.ts +49 -0
- package/dist/core/export-svg.js +213 -0
- package/dist/core/fnv1a.d.ts +10 -0
- package/dist/core/fnv1a.js +17 -0
- package/dist/core/highlighter.d.ts +2 -2
- package/dist/core/highlighter.js +113 -47
- package/dist/core/json.js +1 -1
- package/dist/core/markup.d.ts +28 -7
- package/dist/core/markup.js +235 -312
- package/dist/core/measure.d.ts +3 -3
- package/dist/core/measure.js +12 -7
- package/dist/core/memo.d.ts +19 -0
- package/dist/core/memo.js +34 -0
- package/dist/core/noise.d.ts +31 -0
- package/dist/core/noise.js +94 -0
- package/dist/core/osc8.d.ts +6 -6
- package/dist/core/osc8.js +9 -21
- package/dist/core/paint.d.ts +107 -0
- package/dist/core/paint.js +161 -0
- package/dist/core/place.d.ts +1 -1
- package/dist/core/place.js +4 -6
- package/dist/core/pretty.d.ts +126 -2
- package/dist/core/pretty.js +571 -105
- package/dist/core/protocol.d.ts +43 -3
- package/dist/core/protocol.js +23 -2
- package/dist/core/render.d.ts +33 -30
- package/dist/core/render.js +43 -83
- package/dist/core/segment.d.ts +6 -5
- package/dist/core/segment.js +11 -15
- package/dist/core/selection.d.ts +12 -0
- package/dist/core/selection.js +14 -0
- package/dist/core/strip.d.ts +116 -74
- package/dist/core/strip.js +266 -217
- package/dist/core/style.d.ts +27 -7
- package/dist/core/style.js +106 -41
- package/dist/core/text.d.ts +43 -16
- package/dist/core/text.js +180 -59
- package/dist/core/wrap.d.ts +5 -0
- package/dist/core/wrap.js +16 -3
- package/dist/host/app.d.ts +95 -17
- package/dist/host/app.js +201 -61
- package/dist/host/index.d.ts +4 -1
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +84 -0
- package/dist/host/input.js +498 -0
- package/dist/host/terminal-host.d.ts +15 -2
- package/dist/host/terminal-host.js +2 -0
- package/dist/index.d.ts +26 -14
- package/dist/index.js +17 -7
- package/dist/node/prompt.d.ts +13 -0
- package/dist/node/prompt.js +30 -9
- package/dist/node/save.d.ts +4 -3
- package/dist/node/save.js +6 -3
- package/dist/node/terminal-host.d.ts +10 -2
- package/dist/node/terminal-host.js +7 -0
- package/dist/node/traceback.d.ts +2 -1
- package/dist/node/traceback.js +3 -39
- package/dist/renderables/align.js +2 -9
- package/dist/renderables/columns.d.ts +45 -29
- package/dist/renderables/columns.js +142 -103
- package/dist/renderables/constrain.js +6 -12
- package/dist/renderables/effect.d.ts +113 -0
- package/dist/renderables/effect.js +182 -0
- package/dist/renderables/effects.d.ts +252 -0
- package/dist/renderables/effects.js +565 -0
- package/dist/renderables/embed.d.ts +94 -31
- package/dist/renderables/embed.js +141 -45
- package/dist/renderables/group.d.ts +6 -3
- package/dist/renderables/group.js +5 -0
- package/dist/renderables/layout.d.ts +6 -23
- package/dist/renderables/layout.js +24 -113
- package/dist/renderables/list-view.d.ts +42 -0
- package/dist/renderables/list-view.js +78 -0
- package/dist/renderables/live.d.ts +40 -16
- package/dist/renderables/live.js +96 -83
- package/dist/renderables/markdown.d.ts +16 -2
- package/dist/renderables/markdown.js +521 -118
- package/dist/renderables/padding.d.ts +22 -1
- package/dist/renderables/padding.js +30 -24
- package/dist/renderables/panel.d.ts +31 -33
- package/dist/renderables/panel.js +137 -141
- package/dist/renderables/progress.d.ts +110 -16
- package/dist/renderables/progress.js +212 -81
- package/dist/renderables/progressBar.d.ts +24 -4
- package/dist/renderables/progressBar.js +78 -23
- package/dist/renderables/prompt.d.ts +37 -15
- package/dist/renderables/prompt.js +125 -85
- package/dist/renderables/ratio.d.ts +123 -0
- package/dist/renderables/ratio.js +213 -0
- package/dist/renderables/rule.d.ts +3 -2
- package/dist/renderables/rule.js +50 -52
- package/dist/renderables/spinner.d.ts +28 -2
- package/dist/renderables/spinner.js +52 -19
- package/dist/renderables/status.d.ts +13 -7
- package/dist/renderables/status.js +15 -29
- package/dist/renderables/syntax.d.ts +37 -7
- package/dist/renderables/syntax.js +134 -83
- package/dist/renderables/table.d.ts +58 -20
- package/dist/renderables/table.js +373 -197
- package/dist/renderables/traceback.d.ts +5 -4
- package/dist/renderables/traceback.js +239 -68
- package/dist/renderables/tree.d.ts +10 -2
- package/dist/renderables/tree.js +61 -34
- package/dist/renderables/viewport.d.ts +30 -0
- package/dist/renderables/viewport.js +61 -7
- package/dist/template-bindings/color-funcs.d.ts +31 -9
- package/dist/template-bindings/color-funcs.js +40 -14
- package/dist/template-bindings/helpers.d.ts +4 -2
- package/dist/template-bindings/helpers.js +5 -20
- package/dist/template-bindings/index.d.ts +29 -17
- package/dist/template-bindings/index.js +36 -20
- package/dist/template-bindings/palette-funcs.d.ts +3 -1
- package/dist/template-bindings/palette-funcs.js +11 -7
- package/dist/template-bindings/style-funcs.js +4 -2
- package/dist/themes/buildPalette.d.ts +24 -3
- package/dist/themes/buildPalette.js +52 -8
- package/dist/themes/colorMath.d.ts +29 -17
- package/dist/themes/colorMath.js +74 -48
- package/dist/themes/colorRef.d.ts +2 -17
- package/dist/themes/colorRef.js +13 -31
- package/dist/themes/palette.d.ts +24 -0
- package/dist/themes/palette.js +46 -3
- package/dist/themes/ramp.d.ts +21 -34
- package/dist/themes/ramp.js +23 -42
- package/dist/themes/registry.js +39 -28
- package/dist/widgets/button.d.ts +2 -6
- package/dist/widgets/button.js +9 -40
- package/dist/widgets/checkbox.d.ts +2 -5
- package/dist/widgets/checkbox.js +9 -31
- package/dist/widgets/dropdown.d.ts +2 -5
- package/dist/widgets/dropdown.js +17 -51
- package/dist/widgets/event-router.d.ts +31 -40
- package/dist/widgets/event-router.js +52 -483
- package/dist/widgets/index.d.ts +2 -1
- package/dist/widgets/ink.d.ts +22 -0
- package/dist/widgets/ink.js +31 -0
- package/dist/widgets/slider.d.ts +2 -5
- package/dist/widgets/slider.js +11 -34
- package/dist/widgets/text-input.d.ts +19 -10
- package/dist/widgets/text-input.js +156 -147
- package/dist/widgets/themed-widget.d.ts +20 -0
- package/dist/widgets/themed-widget.js +89 -0
- package/dist/widgets/toggle.d.ts +2 -5
- package/dist/widgets/toggle.js +8 -31
- package/dist/widgets/types.d.ts +8 -25
- package/dist/widgets/types.js +8 -0
- package/dist/widgets/widget-app.d.ts +24 -7
- package/dist/widgets/widget-app.js +35 -18
- package/dist/widgets/widget-base.d.ts +2 -0
- package/dist/widgets/widget-base.js +9 -2
- package/package.json +31 -17
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemedWidget — a widget that draws every cell it owns from one theme's
|
|
3
|
+
* palette: the interactive widgets, as against `StaticItem`, which shows
|
|
4
|
+
* content it did not draw.
|
|
5
|
+
*
|
|
6
|
+
* [LAW:one-type-per-behavior] The theme, how it is swapped, what a disabled
|
|
7
|
+
* widget looks like, and the ground a padded row stands on are the same for
|
|
8
|
+
* every such widget, so they live here once.
|
|
9
|
+
*/
|
|
10
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
11
|
+
var useValue = arguments.length > 2;
|
|
12
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
13
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
14
|
+
}
|
|
15
|
+
return useValue ? value : void 0;
|
|
16
|
+
};
|
|
17
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
18
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
19
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
20
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
21
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
22
|
+
var _, done = false;
|
|
23
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
24
|
+
var context = {};
|
|
25
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
26
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
27
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
28
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
29
|
+
if (kind === "accessor") {
|
|
30
|
+
if (result === void 0) continue;
|
|
31
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
32
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
33
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
34
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
35
|
+
}
|
|
36
|
+
else if (_ = accept(result)) {
|
|
37
|
+
if (kind === "field") initializers.unshift(_);
|
|
38
|
+
else descriptor[key] = _;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
42
|
+
done = true;
|
|
43
|
+
};
|
|
44
|
+
import { observableRef, action } from "mobx";
|
|
45
|
+
import { Style } from "../core/style.js";
|
|
46
|
+
import { DEFAULT_TERMINAL_THEME } from "../themes/terminalThemes.js";
|
|
47
|
+
import { WidgetBase } from "./widget-base.js";
|
|
48
|
+
import { ink } from "./ink.js";
|
|
49
|
+
let ThemedWidget = (() => {
|
|
50
|
+
let _classSuper = WidgetBase;
|
|
51
|
+
let _instanceExtraInitializers = [];
|
|
52
|
+
let _theme_decorators;
|
|
53
|
+
let _theme_initializers = [];
|
|
54
|
+
let _theme_extraInitializers = [];
|
|
55
|
+
let _setTheme_decorators;
|
|
56
|
+
return class ThemedWidget extends _classSuper {
|
|
57
|
+
static {
|
|
58
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
59
|
+
_theme_decorators = [observableRef];
|
|
60
|
+
_setTheme_decorators = [action];
|
|
61
|
+
__esDecorate(this, null, _theme_decorators, { kind: "accessor", name: "theme", static: false, private: false, access: { has: obj => "theme" in obj, get: obj => obj.theme, set: (obj, value) => { obj.theme = value; } }, metadata: _metadata }, _theme_initializers, _theme_extraInitializers);
|
|
62
|
+
__esDecorate(this, null, _setTheme_decorators, { kind: "method", name: "setTheme", static: false, private: false, access: { has: obj => "setTheme" in obj, get: obj => obj.setTheme }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
63
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
64
|
+
}
|
|
65
|
+
#theme_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _theme_initializers, void 0));
|
|
66
|
+
// [LAW:types-are-the-program] @observableRef so setTheme() triggers a
|
|
67
|
+
// re-render: every draw reads its colours through this reference.
|
|
68
|
+
get theme() { return this.#theme_accessor_storage; }
|
|
69
|
+
set theme(value) { this.#theme_accessor_storage = value; }
|
|
70
|
+
constructor(theme) {
|
|
71
|
+
super();
|
|
72
|
+
__runInitializers(this, _theme_extraInitializers);
|
|
73
|
+
this.theme = theme ?? DEFAULT_TERMINAL_THEME;
|
|
74
|
+
}
|
|
75
|
+
setTheme(theme) {
|
|
76
|
+
this.theme = theme;
|
|
77
|
+
}
|
|
78
|
+
get ground() {
|
|
79
|
+
return new Style(ink(this.theme, "foreground", "background"));
|
|
80
|
+
}
|
|
81
|
+
// [LAW:one-source-of-truth] How every widget looks while disabled: the
|
|
82
|
+
// palette's de-emphasized text on its ground. WCAG sets no contrast floor for
|
|
83
|
+
// an inactive control, and this sits under the one for text on purpose.
|
|
84
|
+
get disabledInk() {
|
|
85
|
+
return ink(this.theme, "foreground-muted", "background");
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
})();
|
|
89
|
+
export { ThemedWidget };
|
package/dist/widgets/toggle.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { Segment } from "../core/segment.js";
|
|
14
14
|
import type { RenderOptions } from "../core/protocol.js";
|
|
15
15
|
import type { TerminalTheme } from "../core/color.js";
|
|
16
|
-
import {
|
|
16
|
+
import { ThemedWidget } from "./themed-widget.js";
|
|
17
17
|
import type { KeyEvent, WidgetMouseEvent } from "./types.js";
|
|
18
18
|
export type ToggleVariant = "default" | "primary" | "success" | "warning" | "danger";
|
|
19
19
|
export interface ToggleOptions {
|
|
@@ -24,15 +24,13 @@ export interface ToggleOptions {
|
|
|
24
24
|
theme?: TerminalTheme;
|
|
25
25
|
variant?: ToggleVariant;
|
|
26
26
|
}
|
|
27
|
-
export declare class Toggle extends
|
|
27
|
+
export declare class Toggle extends ThemedWidget {
|
|
28
28
|
readonly id: string;
|
|
29
29
|
readonly focusable = true;
|
|
30
30
|
accessor label: string;
|
|
31
31
|
accessor on: boolean;
|
|
32
32
|
accessor variant: ToggleVariant;
|
|
33
|
-
private accessor _theme;
|
|
34
33
|
constructor(options: ToggleOptions);
|
|
35
|
-
setTheme(theme: TerminalTheme): void;
|
|
36
34
|
handleKey(event: KeyEvent): void;
|
|
37
35
|
handleMouse(event: WidgetMouseEvent): void;
|
|
38
36
|
protected draw(_options: RenderOptions): Iterable<Segment>;
|
|
@@ -40,5 +38,4 @@ export declare class Toggle extends WidgetBase {
|
|
|
40
38
|
minimum: number;
|
|
41
39
|
maximum: number;
|
|
42
40
|
};
|
|
43
|
-
private resolvePalette;
|
|
44
41
|
}
|
package/dist/widgets/toggle.js
CHANGED
|
@@ -47,10 +47,9 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
47
47
|
import { observable, action, observableRef } from "mobx";
|
|
48
48
|
import { Segment } from "../core/segment.js";
|
|
49
49
|
import { Style } from "../core/style.js";
|
|
50
|
-
import { ColorSpec } from "../core/color.js";
|
|
51
50
|
import { cellLen } from "../core/cells.js";
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
51
|
+
import { ThemedWidget } from "./themed-widget.js";
|
|
52
|
+
import { ink } from "./ink.js";
|
|
54
53
|
// onFg uses on-${accent} (WCAG-correct contrast, picked once at palette
|
|
55
54
|
// build time) so the ON state stays readable on a full accent bg. Earlier
|
|
56
55
|
// versions used text-${accent} here, which is mostly-accent and clashed
|
|
@@ -64,7 +63,7 @@ const VARIANT_KEYS = {
|
|
|
64
63
|
danger: { onBg: "error", onFg: "on-error", offBg: "error-muted", offFg: "text-error" },
|
|
65
64
|
};
|
|
66
65
|
let Toggle = (() => {
|
|
67
|
-
let _classSuper =
|
|
66
|
+
let _classSuper = ThemedWidget;
|
|
68
67
|
let _instanceExtraInitializers = [];
|
|
69
68
|
let _label_decorators;
|
|
70
69
|
let _label_initializers = [];
|
|
@@ -75,10 +74,6 @@ let Toggle = (() => {
|
|
|
75
74
|
let _variant_decorators;
|
|
76
75
|
let _variant_initializers = [];
|
|
77
76
|
let _variant_extraInitializers = [];
|
|
78
|
-
let __theme_decorators;
|
|
79
|
-
let __theme_initializers = [];
|
|
80
|
-
let __theme_extraInitializers = [];
|
|
81
|
-
let _setTheme_decorators;
|
|
82
77
|
let _handleKey_decorators;
|
|
83
78
|
let _handleMouse_decorators;
|
|
84
79
|
return class Toggle extends _classSuper {
|
|
@@ -87,15 +82,11 @@ let Toggle = (() => {
|
|
|
87
82
|
_label_decorators = [observable];
|
|
88
83
|
_on_decorators = [observable];
|
|
89
84
|
_variant_decorators = [observableRef];
|
|
90
|
-
__theme_decorators = [observableRef];
|
|
91
|
-
_setTheme_decorators = [action];
|
|
92
85
|
_handleKey_decorators = [action];
|
|
93
86
|
_handleMouse_decorators = [action];
|
|
94
87
|
__esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
|
|
95
88
|
__esDecorate(this, null, _on_decorators, { kind: "accessor", name: "on", static: false, private: false, access: { has: obj => "on" in obj, get: obj => obj.on, set: (obj, value) => { obj.on = value; } }, metadata: _metadata }, _on_initializers, _on_extraInitializers);
|
|
96
89
|
__esDecorate(this, null, _variant_decorators, { kind: "accessor", name: "variant", static: false, private: false, access: { has: obj => "variant" in obj, get: obj => obj.variant, set: (obj, value) => { obj.variant = value; } }, metadata: _metadata }, _variant_initializers, _variant_extraInitializers);
|
|
97
|
-
__esDecorate(this, null, __theme_decorators, { kind: "accessor", name: "_theme", static: false, private: false, access: { has: obj => "_theme" in obj, get: obj => obj._theme, set: (obj, value) => { obj._theme = value; } }, metadata: _metadata }, __theme_initializers, __theme_extraInitializers);
|
|
98
|
-
__esDecorate(this, null, _setTheme_decorators, { kind: "method", name: "setTheme", static: false, private: false, access: { has: obj => "setTheme" in obj, get: obj => obj.setTheme }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
99
90
|
__esDecorate(this, null, _handleKey_decorators, { kind: "method", name: "handleKey", static: false, private: false, access: { has: obj => "handleKey" in obj, get: obj => obj.handleKey }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
100
91
|
__esDecorate(this, null, _handleMouse_decorators, { kind: "method", name: "handleMouse", static: false, private: false, access: { has: obj => "handleMouse" in obj, get: obj => obj.handleMouse }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
101
92
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
@@ -111,22 +102,15 @@ let Toggle = (() => {
|
|
|
111
102
|
#variant_accessor_storage = (__runInitializers(this, _on_extraInitializers), __runInitializers(this, _variant_initializers, void 0));
|
|
112
103
|
get variant() { return this.#variant_accessor_storage; }
|
|
113
104
|
set variant(value) { this.#variant_accessor_storage = value; }
|
|
114
|
-
#_theme_accessor_storage = (__runInitializers(this, _variant_extraInitializers), __runInitializers(this, __theme_initializers, void 0));
|
|
115
|
-
// [LAW:types-are-the-program] @observableRef so setTheme() triggers a
|
|
116
|
-
// re-render — see slider.ts.
|
|
117
|
-
get _theme() { return this.#_theme_accessor_storage; }
|
|
118
|
-
set _theme(value) { this.#_theme_accessor_storage = value; }
|
|
119
105
|
constructor(options) {
|
|
120
|
-
super();
|
|
121
|
-
__runInitializers(this,
|
|
106
|
+
super(options.theme);
|
|
107
|
+
__runInitializers(this, _variant_extraInitializers);
|
|
122
108
|
this.id = options.id ?? `toggle-${options.label.toLowerCase().replace(/\s+/g, "-")}`;
|
|
123
109
|
this.label = options.label;
|
|
124
110
|
this.on = options.on ?? false;
|
|
125
111
|
this.variant = options.variant ?? "default";
|
|
126
112
|
this.disabled = options.disabled ?? false;
|
|
127
|
-
this._theme = options.theme ?? DEFAULT_TERMINAL_THEME;
|
|
128
113
|
}
|
|
129
|
-
setTheme(theme) { this._theme = theme; }
|
|
130
114
|
// --- Event handlers ---
|
|
131
115
|
handleKey(event) {
|
|
132
116
|
if (this.disabled)
|
|
@@ -157,24 +141,17 @@ let Toggle = (() => {
|
|
|
157
141
|
const indicator = this.on ? "[ON] " : "[OFF]";
|
|
158
142
|
const text = `${indicator} ${this.label}`;
|
|
159
143
|
if (this.disabled) {
|
|
160
|
-
return [new Segment(text, new Style(
|
|
144
|
+
return [new Segment(text, new Style(this.disabledInk))];
|
|
161
145
|
}
|
|
162
146
|
const keys = VARIANT_KEYS[this.variant];
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
return [new Segment(text, new Style({ color: fg, bgcolor: bg, underline: this.focused }))];
|
|
147
|
+
const colors = this.on ? ink(this.theme, keys.onFg, keys.onBg) : ink(this.theme, keys.offFg, keys.offBg);
|
|
148
|
+
return [new Segment(text, new Style({ ...colors, underline: this.focused }))];
|
|
166
149
|
}
|
|
167
150
|
measure(_options) {
|
|
168
151
|
// [LAW:one-source-of-truth] cellLen — see button.ts.
|
|
169
152
|
const width = 5 + 1 + cellLen(this.label);
|
|
170
153
|
return { minimum: width, maximum: width };
|
|
171
154
|
}
|
|
172
|
-
// --- Palette resolution ---
|
|
173
|
-
resolvePalette(key) {
|
|
174
|
-
const rgba = this._theme.palette.get(key);
|
|
175
|
-
// [LAW:no-defensive-null-guards] palette must contain all keys; missing is a construction bug.
|
|
176
|
-
return ColorSpec.fromRgba(rgba);
|
|
177
|
-
}
|
|
178
155
|
};
|
|
179
156
|
})();
|
|
180
157
|
export { Toggle };
|
package/dist/widgets/types.d.ts
CHANGED
|
@@ -8,21 +8,15 @@
|
|
|
8
8
|
import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
|
|
9
9
|
import type { Segment } from "../core/segment.js";
|
|
10
10
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
character: string;
|
|
14
|
-
shift: boolean;
|
|
15
|
-
ctrl: boolean;
|
|
16
|
-
meta: boolean;
|
|
17
|
-
}
|
|
18
|
-
export declare class KeyEvent {
|
|
11
|
+
import type { KeyPress, ScreenMouseEvent } from "../host/input.js";
|
|
12
|
+
export declare class KeyEvent implements KeyPress {
|
|
19
13
|
readonly key: string;
|
|
20
14
|
readonly character: string;
|
|
21
15
|
readonly shift: boolean;
|
|
22
16
|
readonly ctrl: boolean;
|
|
23
17
|
readonly meta: boolean;
|
|
24
18
|
private _stopped;
|
|
25
|
-
constructor(init:
|
|
19
|
+
constructor(init: KeyPress);
|
|
26
20
|
get stopped(): boolean;
|
|
27
21
|
stop(): void;
|
|
28
22
|
}
|
|
@@ -30,21 +24,11 @@ export type KeyHandlerPriority = "high" | "normal";
|
|
|
30
24
|
export interface KeyHandlerOptions {
|
|
31
25
|
priority?: KeyHandlerPriority;
|
|
32
26
|
}
|
|
33
|
-
export type
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
type: Type;
|
|
39
|
-
x: number;
|
|
40
|
-
y: number;
|
|
41
|
-
button: number;
|
|
42
|
-
shift: boolean;
|
|
43
|
-
ctrl: boolean;
|
|
44
|
-
}
|
|
45
|
-
export interface WidgetMouseEvent extends MouseEventOf<"mouse_down" | "mouse_up" | "mouse_move"> {
|
|
46
|
-
over: boolean;
|
|
47
|
-
}
|
|
27
|
+
export type WidgetMouseEvent = Extract<ScreenMouseEvent, {
|
|
28
|
+
type: "mouse_down" | "mouse_up" | "mouse_move";
|
|
29
|
+
}> & {
|
|
30
|
+
readonly over: boolean;
|
|
31
|
+
};
|
|
48
32
|
export interface WidgetFocusEvent {
|
|
49
33
|
type: "focus" | "blur";
|
|
50
34
|
}
|
|
@@ -84,4 +68,3 @@ export interface FrameSource {
|
|
|
84
68
|
readonly frame: readonly (readonly Segment[])[];
|
|
85
69
|
refresh(): void;
|
|
86
70
|
}
|
|
87
|
-
export {};
|
package/dist/widgets/types.js
CHANGED
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
* producing Segment[] from current state. They have no knowledge of stdin,
|
|
6
6
|
* terminal escape sequences, or their host environment.
|
|
7
7
|
*/
|
|
8
|
+
// --- Event types ---
|
|
9
|
+
// [LAW:types-are-the-program] KeyEvent is a `KeyPress` the app heard, plus
|
|
10
|
+
// the say over who else hears it. It carries a single mutable signal
|
|
11
|
+
// (`stopped`) that participants in the dispatch chain set by calling
|
|
12
|
+
// `stop()`. Treating it as an interface would force every handler to
|
|
13
|
+
// shuttle a return value upward and the router to interpret it — the
|
|
14
|
+
// class collapses that into one self-describing value flowing through
|
|
15
|
+
// the chain.
|
|
8
16
|
export class KeyEvent {
|
|
9
17
|
key;
|
|
10
18
|
character;
|
|
@@ -20,12 +20,21 @@
|
|
|
20
20
|
*
|
|
21
21
|
* [LAW:locality-or-seam] `App` knows nothing of widgets — `host/` depends on
|
|
22
22
|
* `core/` alone — and this reaches it only through the seams it already has:
|
|
23
|
-
* the view is a renderable,
|
|
23
|
+
* the view is a renderable, `onPaint` hears the frame, and `onKey`/`onMouse`
|
|
24
|
+
* hear the input.
|
|
24
25
|
*/
|
|
25
26
|
import { Segment } from "../core/segment.js";
|
|
26
27
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
27
|
-
import { type AppOptions, type AppPhase } from "../host/app.js";
|
|
28
|
-
import type { FocusManager, FrameSource, KeyEvent, KeyHandlerOptions
|
|
28
|
+
import { type AppOptions, type AppPhase, type Wheel } from "../host/app.js";
|
|
29
|
+
import type { FocusManager, FrameSource, KeyEvent, KeyHandlerOptions } from "./types.js";
|
|
30
|
+
import type { AppMouseEvent } from "../host/app.js";
|
|
31
|
+
export interface WidgetAppOptions extends AppOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Whether a left-button press focuses the widget under it, before it hears the
|
|
34
|
+
* press. `true` unless given.
|
|
35
|
+
*/
|
|
36
|
+
readonly focusOnClick?: boolean;
|
|
37
|
+
}
|
|
29
38
|
export declare class WidgetApp implements FrameSource {
|
|
30
39
|
readonly focusManager: FocusManager;
|
|
31
40
|
private readonly focus;
|
|
@@ -33,7 +42,7 @@ export declare class WidgetApp implements FrameSource {
|
|
|
33
42
|
private readonly router;
|
|
34
43
|
private readonly reaction;
|
|
35
44
|
private drawn;
|
|
36
|
-
constructor(options:
|
|
45
|
+
constructor(options: WidgetAppOptions);
|
|
37
46
|
get phase(): AppPhase;
|
|
38
47
|
/** The rows on screen now, as painted: what a pointer event lands on. */
|
|
39
48
|
get frame(): readonly (readonly Segment[])[];
|
|
@@ -51,13 +60,21 @@ export declare class WidgetApp implements FrameSource {
|
|
|
51
60
|
*/
|
|
52
61
|
refresh(): void;
|
|
53
62
|
suspend(): Promise<void>;
|
|
63
|
+
/** Paint at the app's rate until the returned function is called, as `App.animate` does. */
|
|
64
|
+
animate(): Unsubscribe;
|
|
54
65
|
/**
|
|
55
|
-
* Hear every key. A `high` handler hears it before the focused widget, a
|
|
66
|
+
* Hear every key the app does not quit on. A `high` handler hears it before the focused widget, a
|
|
56
67
|
* `normal` one after it — and after Tab has moved focus — and a handler
|
|
57
68
|
* that calls `event.stop()` ends the key there.
|
|
58
69
|
*/
|
|
59
70
|
onKey(handler: (event: KeyEvent) => void, options?: KeyHandlerOptions): Unsubscribe;
|
|
60
|
-
/** Hear every pointer event, in terminal cells, before any widget does. */
|
|
61
|
-
onMouse(handler: (event:
|
|
71
|
+
/** Hear every pointer event but the vertical wheel, in terminal cells, before any widget does. */
|
|
72
|
+
onMouse(handler: (event: AppMouseEvent) => void): Unsubscribe;
|
|
73
|
+
/**
|
|
74
|
+
* Offer each wheel turn the viewport under the pointer did not move with to
|
|
75
|
+
* `handler`, as `App.onWheel` does: it returns whether it moved something,
|
|
76
|
+
* and a turn nothing moved with is passed outward.
|
|
77
|
+
*/
|
|
78
|
+
onWheel(handler: (wheel: Wheel) => boolean): Unsubscribe;
|
|
62
79
|
private compose;
|
|
63
80
|
}
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* [LAW:locality-or-seam] `App` knows nothing of widgets — `host/` depends on
|
|
22
22
|
* `core/` alone — and this reaches it only through the seams it already has:
|
|
23
|
-
* the view is a renderable,
|
|
23
|
+
* the view is a renderable, `onPaint` hears the frame, and `onKey`/`onMouse`
|
|
24
|
+
* hear the input.
|
|
24
25
|
*/
|
|
25
26
|
import { Reaction } from "mobx";
|
|
26
27
|
import { Segment } from "../core/segment.js";
|
|
@@ -40,16 +41,23 @@ export class WidgetApp {
|
|
|
40
41
|
// The widgets the view drew for the frame on screen, in document order.
|
|
41
42
|
drawn = [];
|
|
42
43
|
constructor(options) {
|
|
43
|
-
const { view } = options;
|
|
44
|
+
const { view, focusOnClick = true } = options;
|
|
44
45
|
this.reaction = new Reaction("WidgetApp", () => this.app.refresh());
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
this.app = new App({
|
|
47
|
+
...options,
|
|
48
|
+
view: (t) => ({ render: (renderOptions) => this.compose(() => view(t), renderOptions) }),
|
|
49
|
+
});
|
|
47
50
|
this.focus = new DefaultFocusManager(() => {
|
|
48
51
|
const owners = ownersOn(this.app.frame);
|
|
49
52
|
return this.drawn.filter((widget) => owners.has(widget));
|
|
50
53
|
});
|
|
51
54
|
this.focusManager = this.focus;
|
|
52
|
-
this.router = new EventRouter({ source: this,
|
|
55
|
+
this.router = new EventRouter({ source: this, focusOnClick });
|
|
56
|
+
// [LAW:single-enforcer] The app reads the terminal; the router routes
|
|
57
|
+
// what it hears, after the app's quit keys.
|
|
58
|
+
this.app.onKey((press) => this.router.key(press));
|
|
59
|
+
this.app.onMouse((event) => this.router.mouse(event));
|
|
60
|
+
this.app.onWheel((wheel) => this.router.wheel(wheel));
|
|
53
61
|
this.app.onPaint(() => {
|
|
54
62
|
this.focus.settle(this.drawn);
|
|
55
63
|
this.router.framePainted();
|
|
@@ -70,18 +78,14 @@ export class WidgetApp {
|
|
|
70
78
|
* until the app stops — `App.run`, with the input.
|
|
71
79
|
*/
|
|
72
80
|
async run() {
|
|
73
|
-
// App refuses a second run; this one must not end the
|
|
81
|
+
// App refuses a second run; this one must not end the state of the first.
|
|
74
82
|
if (this.app.phase !== "idle")
|
|
75
83
|
return this.app.run();
|
|
76
|
-
// Listening before the app starts, so a first frame that throws — and
|
|
77
|
-
// stops the host — is not followed by a subscription that restarts it.
|
|
78
|
-
this.router.start();
|
|
79
|
-
const running = this.app.run();
|
|
80
84
|
try {
|
|
81
|
-
await
|
|
85
|
+
await this.app.run();
|
|
82
86
|
}
|
|
83
87
|
finally {
|
|
84
|
-
this.router.
|
|
88
|
+
this.router.reset();
|
|
85
89
|
this.reaction.dispose();
|
|
86
90
|
}
|
|
87
91
|
}
|
|
@@ -102,18 +106,30 @@ export class WidgetApp {
|
|
|
102
106
|
suspend() {
|
|
103
107
|
return this.app.suspend();
|
|
104
108
|
}
|
|
109
|
+
/** Paint at the app's rate until the returned function is called, as `App.animate` does. */
|
|
110
|
+
animate() {
|
|
111
|
+
return this.app.animate();
|
|
112
|
+
}
|
|
105
113
|
/**
|
|
106
|
-
* Hear every key. A `high` handler hears it before the focused widget, a
|
|
114
|
+
* Hear every key the app does not quit on. A `high` handler hears it before the focused widget, a
|
|
107
115
|
* `normal` one after it — and after Tab has moved focus — and a handler
|
|
108
116
|
* that calls `event.stop()` ends the key there.
|
|
109
117
|
*/
|
|
110
118
|
onKey(handler, options) {
|
|
111
119
|
return this.router.onKey(handler, options);
|
|
112
120
|
}
|
|
113
|
-
/** Hear every pointer event, in terminal cells, before any widget does. */
|
|
121
|
+
/** Hear every pointer event but the vertical wheel, in terminal cells, before any widget does. */
|
|
114
122
|
onMouse(handler) {
|
|
115
123
|
return this.router.onMouse(handler);
|
|
116
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Offer each wheel turn the viewport under the pointer did not move with to
|
|
127
|
+
* `handler`, as `App.onWheel` does: it returns whether it moved something,
|
|
128
|
+
* and a turn nothing moved with is passed outward.
|
|
129
|
+
*/
|
|
130
|
+
onWheel(handler) {
|
|
131
|
+
return this.app.onWheel(handler);
|
|
132
|
+
}
|
|
117
133
|
compose(view, options) {
|
|
118
134
|
const drawn = new Set();
|
|
119
135
|
// [LAW:parse-dont-validate] An owner is any object; only a `WidgetBase`
|
|
@@ -176,12 +192,13 @@ function paintOverlay(lines, widget, options) {
|
|
|
176
192
|
const at = footprintOf(lines, widget);
|
|
177
193
|
if (!at)
|
|
178
194
|
return;
|
|
179
|
-
// An overlay floats over the frame; no region holds it
|
|
180
|
-
|
|
195
|
+
// An overlay floats over the frame; no region holds it, and the cells right
|
|
196
|
+
// of its column are all it can reach.
|
|
197
|
+
const width = Math.max(0, options.maxWidth - at.x);
|
|
198
|
+
const overlay = widget.renderOverlay({ ...options, maxWidth: width, height: undefined });
|
|
181
199
|
if (overlay === null)
|
|
182
200
|
return;
|
|
183
|
-
const
|
|
184
|
-
const rows = Segment.anchorLines(Segment.splitLines(overlay), widget, at.rows).map((line) => Segment.adjustLineLength(line, width, undefined, false));
|
|
201
|
+
const rows = Segment.anchorLines(Segment.splitLines(Segment.cropLines(overlay, width)), widget, at.rows);
|
|
185
202
|
paintLines(lines, rows, at.x, at.y + at.rows);
|
|
186
203
|
}
|
|
187
204
|
// Paint `rows` into `lines` with its top-left cell at (x, y), growing `lines`
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* makeObservable call and subclasses add observables the same way.
|
|
9
9
|
*/
|
|
10
10
|
import { Segment } from "../core/segment.js";
|
|
11
|
+
import { type Style } from "../core/style.js";
|
|
11
12
|
import type { RenderOptions } from "../core/protocol.js";
|
|
12
13
|
import type { InteractiveWidget, KeyEvent, WidgetMouseEvent, WidgetFocusEvent } from "./types.js";
|
|
13
14
|
import type { Unsubscribe } from "../core/subscription.js";
|
|
@@ -32,6 +33,7 @@ export declare abstract class WidgetBase implements InteractiveWidget {
|
|
|
32
33
|
protected emitChange(): void;
|
|
33
34
|
protected emitSubmit(): void;
|
|
34
35
|
render(options: RenderOptions): Iterable<Segment>;
|
|
36
|
+
protected get ground(): Style;
|
|
35
37
|
protected abstract draw(options: RenderOptions): Iterable<Segment>;
|
|
36
38
|
abstract measure(options: RenderOptions): {
|
|
37
39
|
minimum: number;
|
|
@@ -43,6 +43,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
43
43
|
};
|
|
44
44
|
import { observable, action } from "mobx";
|
|
45
45
|
import { Segment } from "../core/segment.js";
|
|
46
|
+
import { NULL_STYLE } from "../core/style.js";
|
|
46
47
|
let WidgetBase = (() => {
|
|
47
48
|
let _instanceExtraInitializers = [];
|
|
48
49
|
let _focused_decorators;
|
|
@@ -150,16 +151,22 @@ let WidgetBase = (() => {
|
|
|
150
151
|
// anchor, so stamping has to follow every text layout `draw` does.
|
|
151
152
|
// Every row is padded to the widest, so the widget owns its whole rectangle
|
|
152
153
|
// and a click past the end of a short row still reaches it; every row ends
|
|
153
|
-
// in a newline, so a blank last row survives the next `splitLines`.
|
|
154
|
+
// in a newline, so a blank last row survives the next `splitLines`. The
|
|
155
|
+
// padding stands on `ground`, whatever the widget draws its own cells on.
|
|
154
156
|
// Reporting itself before it draws is what puts a widget ahead of the
|
|
155
157
|
// widgets nested in it in document order — the order focus traverses.
|
|
156
158
|
render(options) {
|
|
157
159
|
options.onDraw?.(this);
|
|
158
160
|
const drawn = Segment.splitLines(this.draw(options));
|
|
159
161
|
const [width] = Segment.getShape(drawn);
|
|
160
|
-
const lines = Segment.anchorLines(drawn.map((line) => Segment.adjustLineLength(line, width)), this);
|
|
162
|
+
const lines = Segment.anchorLines(drawn.map((line) => Segment.adjustLineLength(line, width, this.ground)), this);
|
|
161
163
|
return lines.flatMap((line) => [...line, Segment.line()]);
|
|
162
164
|
}
|
|
165
|
+
// What a padded row stands on. None by default: the padding shows whatever
|
|
166
|
+
// the widget is drawn over, as the cells of content it did not draw do.
|
|
167
|
+
get ground() {
|
|
168
|
+
return NULL_STYLE;
|
|
169
|
+
}
|
|
163
170
|
};
|
|
164
171
|
})();
|
|
165
172
|
export { WidgetBase };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promptctl/rich-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Rich text and beautiful formatting in the terminal — a TypeScript port of Python's Rich",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,25 +61,27 @@
|
|
|
61
61
|
"build": "npm run clean && tsc",
|
|
62
62
|
"test": "vitest run",
|
|
63
63
|
"test:watch": "vitest",
|
|
64
|
+
"prelint": "node scripts/stage-repo-files.ts",
|
|
64
65
|
"lint": "tsc --noEmit && tsc -p tsconfig.scripts.json && tsc -p tsconfig.test.json",
|
|
65
66
|
"clean": "rm -rf dist",
|
|
66
|
-
"
|
|
67
|
-
"docs:
|
|
67
|
+
"predocs:dev": "node scripts/stage-repo-files.ts",
|
|
68
|
+
"docs:dev": "vitepress dev docs",
|
|
69
|
+
"predocs:build": "node scripts/stage-repo-files.ts",
|
|
70
|
+
"docs:build": "vitepress build docs",
|
|
68
71
|
"docs:preview": "vitepress preview docs",
|
|
69
|
-
"demo": "
|
|
70
|
-
"demo:build": "
|
|
71
|
-
"sessions": "
|
|
72
|
-
"strip": "
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"demo
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"demos:preview": "vite preview --config vite.config.demos.ts",
|
|
72
|
+
"demo": "node scripts/build-demos.ts && node dist-demo/examples/rich-explore/node.js",
|
|
73
|
+
"demo:build": "node scripts/build-demos.ts",
|
|
74
|
+
"sessions": "node scripts/build-demos.ts && node dist-demo/examples/claude-sessions/node.js",
|
|
75
|
+
"strip": "node scripts/build-demos.ts && node dist-demo/examples/rich-strip/main.js",
|
|
76
|
+
"effects-feel": "node scripts/build-demos.ts && node dist-demo/examples/effects-feel/index.js",
|
|
77
|
+
"viewport": "node scripts/build-demos.ts && node dist-demo/examples/rich-viewport/main.js",
|
|
78
|
+
"markup-plugins": "node scripts/build-demos.ts && node dist-demo/examples/rich-markup-plugins/main.js",
|
|
79
|
+
"demo-inputs": "node scripts/build-demos.ts && node dist-demo/examples/rich-config/main.js",
|
|
80
|
+
"demo:dropdown": "node scripts/build-demos.ts && node dist-demo/examples/dropdown-demo/main.js",
|
|
81
|
+
"dash": "node scripts/build-demos.ts && node dist-demo/examples/rich-dash/node.js",
|
|
82
|
+
"template-bindings": "node scripts/build-demos.ts && node dist-demo/examples/rich-template-bindings/main.js",
|
|
83
|
+
"themes-and-color-studio": "node scripts/build-demos.ts && node dist-demo/examples/themes-and-color-studio/node.js",
|
|
84
|
+
"terminal-host": "node scripts/build-demos.ts && node dist-demo/examples/terminal-host/main.js",
|
|
83
85
|
"test:demos": "playwright test"
|
|
84
86
|
},
|
|
85
87
|
"keywords": [
|
|
@@ -96,20 +98,32 @@
|
|
|
96
98
|
"cli"
|
|
97
99
|
],
|
|
98
100
|
"license": "MIT",
|
|
101
|
+
"devEngines": {
|
|
102
|
+
"runtime": { "name": "node", "version": "^22.18.0 || >=23.6.0", "onFail": "error" }
|
|
103
|
+
},
|
|
99
104
|
"engines": {
|
|
100
105
|
"node": ">=20"
|
|
101
106
|
},
|
|
102
107
|
"devDependencies": {
|
|
108
|
+
"@codemirror/commands": "^6.11.1",
|
|
109
|
+
"@codemirror/lang-javascript": "^6.2.5",
|
|
110
|
+
"@codemirror/language": "^6.12.4",
|
|
111
|
+
"@codemirror/state": "^6.7.6",
|
|
112
|
+
"@codemirror/view": "^6.43.13",
|
|
113
|
+
"@lezer/highlight": "^1.2.5",
|
|
103
114
|
"@playwright/test": "^1.63.0",
|
|
104
115
|
"@promptctl/go-template-js": "^0.10.0",
|
|
105
116
|
"@types/markdown-it": "^14.2.0",
|
|
106
117
|
"@types/node": "^26.5.1",
|
|
107
118
|
"@types/semver": "^7.8.0",
|
|
119
|
+
"@xterm/headless": "^6.0.0",
|
|
108
120
|
"markdown-it": "^14.3.2",
|
|
109
121
|
"markdown-it-container": "^4.0.0",
|
|
110
122
|
"mobx": "^7.0.3",
|
|
123
|
+
"node-inspect-extracted": "^3.3.3",
|
|
111
124
|
"semver": "^7.8.5",
|
|
112
125
|
"strip-ansi": "^7.2.0",
|
|
126
|
+
"sucrase": "^3.35.1",
|
|
113
127
|
"typescript": "^6.0.3",
|
|
114
128
|
"vite": "^8.3.0",
|
|
115
129
|
"vitepress": "^1.6.4",
|