@promptctl/rich-js 0.24.1 → 0.25.1
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 +7 -0
- package/dist/core/anchor.d.ts +5 -0
- package/dist/core/anchor.js +11 -4
- package/dist/core/animation.d.ts +175 -10
- package/dist/core/animation.js +283 -15
- package/dist/core/ansi.js +2 -2
- package/dist/core/box.d.ts +7 -7
- package/dist/core/cells.d.ts +23 -13
- package/dist/core/cells.js +58 -48
- package/dist/core/clock.d.ts +2 -2
- package/dist/core/clock.js +6 -4
- package/dist/core/color.d.ts +27 -10
- package/dist/core/color.js +24 -33
- package/dist/core/console.d.ts +28 -17
- package/dist/core/console.js +44 -39
- package/dist/core/easing.d.ts +30 -0
- package/dist/core/easing.js +65 -20
- package/dist/core/emoji.d.ts +1 -1
- package/dist/core/emoji.js +1 -2
- package/dist/core/export-html.js +2 -1
- package/dist/core/export-lines.js +3 -3
- package/dist/core/highlighter.d.ts +9 -8
- package/dist/core/highlighter.js +3 -2
- package/dist/core/json.js +2 -2
- package/dist/core/markup.js +16 -12
- package/dist/core/measure.js +2 -2
- package/dist/core/memo.d.ts +11 -2
- package/dist/core/memo.js +16 -0
- package/dist/core/oklch.js +17 -6
- package/dist/core/osc8.d.ts +1 -1
- package/dist/core/osc8.js +4 -5
- package/dist/core/paint.d.ts +2 -1
- package/dist/core/paint.js +4 -3
- package/dist/core/pattern.d.ts +21 -0
- package/dist/core/pattern.js +21 -0
- package/dist/core/pretty.js +9 -10
- package/dist/core/protocol.d.ts +100 -39
- package/dist/core/protocol.js +167 -21
- package/dist/core/render.d.ts +15 -2
- package/dist/core/render.js +25 -5
- package/dist/core/segment.d.ts +13 -5
- package/dist/core/segment.js +23 -9
- package/dist/core/spinnerData.d.ts +1 -1
- package/dist/core/state.d.ts +53 -0
- package/dist/core/state.js +82 -0
- package/dist/core/strip.d.ts +98 -29
- package/dist/core/strip.js +211 -150
- package/dist/core/style.d.ts +47 -14
- package/dist/core/style.js +57 -28
- package/dist/core/text.d.ts +5 -8
- package/dist/core/text.js +116 -124
- package/dist/core/timeline.d.ts +30 -5
- package/dist/core/timeline.js +43 -7
- package/dist/core/tween.d.ts +1 -1
- package/dist/core/tween.js +5 -3
- package/dist/core/view.d.ts +92 -0
- package/dist/core/view.js +83 -0
- package/dist/host/app.d.ts +49 -21
- package/dist/host/app.js +71 -37
- package/dist/host/input.js +3 -4
- package/dist/index.d.ts +24 -12
- package/dist/index.js +9 -4
- package/dist/node/traceback.js +4 -3
- package/dist/renderables/align.d.ts +2 -3
- package/dist/renderables/align.js +0 -3
- package/dist/renderables/change.d.ts +42 -0
- package/dist/renderables/change.js +112 -0
- package/dist/renderables/columns.d.ts +3 -4
- package/dist/renderables/columns.js +2 -7
- package/dist/renderables/constrain.d.ts +2 -3
- package/dist/renderables/constrain.js +0 -3
- package/dist/renderables/effect.d.ts +158 -63
- package/dist/renderables/effect.js +378 -155
- package/dist/renderables/effects.d.ts +122 -11
- package/dist/renderables/effects.js +238 -94
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +16 -8
- package/dist/renderables/flexStrip.d.ts +2 -3
- package/dist/renderables/flexStrip.js +0 -4
- package/dist/renderables/frames.d.ts +35 -54
- package/dist/renderables/frames.js +43 -58
- package/dist/renderables/glyph-effect.d.ts +158 -0
- package/dist/renderables/glyph-effect.js +237 -0
- package/dist/renderables/glyph-effects.d.ts +147 -0
- package/dist/renderables/glyph-effects.js +283 -0
- package/dist/renderables/group.d.ts +3 -4
- package/dist/renderables/group.js +0 -3
- package/dist/renderables/layout.d.ts +12 -12
- package/dist/renderables/layout.js +40 -46
- package/dist/renderables/lifecycle.d.ts +77 -0
- package/dist/renderables/lifecycle.js +132 -0
- package/dist/renderables/list-view.d.ts +4 -5
- package/dist/renderables/list-view.js +9 -13
- package/dist/renderables/live.d.ts +36 -21
- package/dist/renderables/live.js +88 -41
- package/dist/renderables/markdown-parse.d.ts +4 -4
- package/dist/renderables/markdown-parse.js +52 -46
- package/dist/renderables/markdown-url.js +11 -11
- package/dist/renderables/padding.d.ts +4 -5
- package/dist/renderables/padding.js +0 -3
- package/dist/renderables/panel.d.ts +14 -16
- package/dist/renderables/panel.js +6 -14
- package/dist/renderables/progress.d.ts +83 -34
- package/dist/renderables/progress.js +182 -95
- package/dist/renderables/progressBar.d.ts +22 -12
- package/dist/renderables/progressBar.js +32 -9
- package/dist/renderables/prompt.js +3 -2
- package/dist/renderables/python-space.js +2 -1
- package/dist/renderables/scroll.d.ts +50 -0
- package/dist/renderables/scroll.js +106 -0
- package/dist/renderables/spinner.d.ts +35 -14
- package/dist/renderables/spinner.js +65 -25
- package/dist/renderables/status.js +1 -1
- package/dist/renderables/syntax.d.ts +10 -9
- package/dist/renderables/syntax.js +3 -2
- package/dist/renderables/table.d.ts +34 -40
- package/dist/renderables/table.js +41 -63
- package/dist/renderables/traceback.d.ts +2 -2
- package/dist/renderables/traceback.js +6 -5
- package/dist/renderables/tree.d.ts +27 -25
- package/dist/renderables/tree.js +104 -58
- package/dist/renderables/viewport.d.ts +75 -44
- package/dist/renderables/viewport.js +145 -82
- package/dist/template-bindings/animation-funcs.d.ts +78 -9
- package/dist/template-bindings/animation-funcs.js +132 -14
- package/dist/template-bindings/index.d.ts +5 -5
- package/dist/template-bindings/index.js +5 -5
- package/dist/themes/ramp.d.ts +46 -3
- package/dist/themes/ramp.js +61 -4
- package/dist/themes/registry.js +5 -7
- package/dist/widgets/button.js +3 -2
- package/dist/widgets/checkbox.js +4 -3
- package/dist/widgets/dropdown.d.ts +3 -1
- package/dist/widgets/dropdown.js +20 -15
- package/dist/widgets/event-router.js +4 -2
- package/dist/widgets/focus-manager.d.ts +2 -0
- package/dist/widgets/focus-manager.js +6 -4
- package/dist/widgets/hit.d.ts +6 -0
- package/dist/widgets/hit.js +8 -1
- package/dist/widgets/observable.d.ts +23 -0
- package/dist/widgets/observable.js +43 -0
- package/dist/widgets/slider.d.ts +1 -1
- package/dist/widgets/slider.js +12 -3
- package/dist/widgets/static-item.d.ts +2 -3
- package/dist/widgets/static-item.js +0 -3
- package/dist/widgets/text-input.d.ts +28 -32
- package/dist/widgets/text-input.js +360 -346
- package/dist/widgets/themed-widget.js +2 -1
- package/dist/widgets/toggle.js +4 -3
- package/dist/widgets/types.d.ts +10 -4
- package/dist/widgets/types.js +8 -2
- package/dist/widgets/widget-app.d.ts +14 -4
- package/dist/widgets/widget-app.js +36 -7
- package/dist/widgets/widget-base.d.ts +2 -2
- package/dist/widgets/widget-base.js +29 -18
- package/package.json +8 -1
package/dist/core/strip.js
CHANGED
|
@@ -39,41 +39,11 @@ import { drawable, getStyle, isAscii, render } from "./protocol.js";
|
|
|
39
39
|
* not draw at all. An effect reads it to leave a seam out of the words it
|
|
40
40
|
* keeps legible (`drawnOf`, `../renderables/effect.ts`).
|
|
41
41
|
*
|
|
42
|
-
* Inside it, every cell a `CellJoiner` draws
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* points into — so a cell has no single owner; each side has one.
|
|
42
|
+
* Inside it, every cell a `CellJoiner` draws is stamped with what it was
|
|
43
|
+
* resolved from (`JoinedCell`), so a cell whose neighbours an effect moves is
|
|
44
|
+
* resolved again from where they moved to.
|
|
46
45
|
*/
|
|
47
46
|
export const JOIN = Object.freeze({ name: "join" });
|
|
48
|
-
/**
|
|
49
|
-
* Whose colour each side of a join cell shows on screen, its ink and its
|
|
50
|
-
* ground: the neighbour whose edge a `Paint` names, or `null` for a role, a
|
|
51
|
-
* mix or the terminal's ground, which are no neighbour's.
|
|
52
|
-
*/
|
|
53
|
-
class ColorOwners {
|
|
54
|
-
fg;
|
|
55
|
-
bg;
|
|
56
|
-
constructor(fg, bg) {
|
|
57
|
-
this.fg = fg;
|
|
58
|
-
this.bg = bg;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Which of a cell's two colours on screen are one of `owners`': both, for a
|
|
63
|
-
* cell one of them drew, itself or through an owner nested in its output; for
|
|
64
|
-
* a cell a `CellJoiner` drew, the sides shown in one of their colours.
|
|
65
|
-
*/
|
|
66
|
-
export function colorsOwnedBy(anchor, owners) {
|
|
67
|
-
for (let level = anchor; level; level = level.inner) {
|
|
68
|
-
if (owners.has(level.owner))
|
|
69
|
-
return { fg: true, bg: true };
|
|
70
|
-
if (level.owner instanceof ColorOwners) {
|
|
71
|
-
const { fg, bg } = level.owner;
|
|
72
|
-
return { fg: fg !== null && owners.has(fg), bg: bg !== null && owners.has(bg) };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return { fg: false, bg: false };
|
|
76
|
-
}
|
|
77
47
|
/**
|
|
78
48
|
* [LAW:single-enforcer] What `joiner` draws at one join, every cell stamped
|
|
79
49
|
* as `JOIN`'s: the one way `Strip` and `FlexStrip` draw a join.
|
|
@@ -131,10 +101,6 @@ export class Strip {
|
|
|
131
101
|
// of which renderables end their own line and which are fragments.
|
|
132
102
|
yield Segment.line();
|
|
133
103
|
}
|
|
134
|
-
// The items; a join is drawn from what the joiner emits for it, not held.
|
|
135
|
-
contents() {
|
|
136
|
-
return this.items;
|
|
137
|
-
}
|
|
138
104
|
/**
|
|
139
105
|
* [LAW:one-source-of-truth] The width of the one row it draws, and that is
|
|
140
106
|
* both bounds: the row never wraps and no item is offered less than the whole
|
|
@@ -149,12 +115,12 @@ export class Strip {
|
|
|
149
115
|
return { minimum: width, maximum: width };
|
|
150
116
|
}
|
|
151
117
|
}
|
|
152
|
-
const PARTS = ["seam", "
|
|
118
|
+
const PARTS = ["seam", "lead", "tail"];
|
|
153
119
|
/**
|
|
154
|
-
* The least ΔE_OK a
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* one cell wide.
|
|
120
|
+
* The least ΔE_OK a join cell's ink must stand off its own ground by to be
|
|
121
|
+
* seen. Below it the eye cannot tell the ink from the ground, so the joiner
|
|
122
|
+
* lifts the ink to it (`standOff`). Twice the ~.02 threshold of a visible
|
|
123
|
+
* difference, because a seam is one cell wide.
|
|
158
124
|
*/
|
|
159
125
|
export const SEAM_MIN_DELTA_E = 0.04;
|
|
160
126
|
function* paintsIn(paint) {
|
|
@@ -174,7 +140,6 @@ const pickGlyph = (cell, part, index, at) => {
|
|
|
174
140
|
return glyphs[Math.floor((parseInt(fnv1a(`${part}:${index}:${at}`), 16) / 2 ** 32) * glyphs.length)];
|
|
175
141
|
};
|
|
176
142
|
const cellWidth = (cell) => cellLen(glyphsOf(cell)[0] ?? "");
|
|
177
|
-
const partWidth = (cells) => cells.reduce((width, cell) => width + cellWidth(cell), 0);
|
|
178
143
|
// `raw` as a `Paint`, or refused. `absent` is the neighbour this part may not
|
|
179
144
|
// name, because the part is also drawn where that neighbour does not exist.
|
|
180
145
|
function parsePaint(raw, absent, refuse) {
|
|
@@ -197,9 +162,9 @@ function parsePaint(raw, absent, refuse) {
|
|
|
197
162
|
return refuse(`has a colour that is not a Paint: ${JSON.stringify(raw)}`);
|
|
198
163
|
}
|
|
199
164
|
const parseColor = (raw, absent, refuse) => raw === "ground" ? raw : parsePaint(raw, absent, refuse);
|
|
200
|
-
const ABSENT = { seam: undefined,
|
|
165
|
+
const ABSENT = { seam: undefined, lead: "left", tail: "right" };
|
|
201
166
|
// Which argument of a joiner a part is authored in, so a refusal names it.
|
|
202
|
-
const AUTHORED_IN = { seam: "seam",
|
|
167
|
+
const AUTHORED_IN = { seam: "seam", lead: "caps", tail: "caps" };
|
|
203
168
|
function parseCell(cell, form, part, refuse) {
|
|
204
169
|
const glyph = cell.glyph;
|
|
205
170
|
const oneOf = typeof glyph === "object" && glyph !== null ? glyph.oneOf : undefined;
|
|
@@ -247,14 +212,6 @@ const asSeamCell = (form, part) => (cell, refuse) => {
|
|
|
247
212
|
refuse("names a cap and draws cells of its own; a cell is one or the other");
|
|
248
213
|
return cap === "lead" || cap === "tail" ? Object.freeze({ cap }) : refuse(`names a cap that is neither lead nor tail: ${JSON.stringify(cap)}`);
|
|
249
214
|
};
|
|
250
|
-
// A seam's width as a sum over whatever caps stand in it: its own cells', and
|
|
251
|
-
// how many times it names each cap. Two parts equal in all three are the same
|
|
252
|
-
// width under every caps.
|
|
253
|
-
const seamWidth = (cells) => [
|
|
254
|
-
partWidth(cells.filter((cell) => !("cap" in cell))),
|
|
255
|
-
cells.filter((cell) => "cap" in cell && cell.cap === "lead").length,
|
|
256
|
-
cells.filter((cell) => "cap" in cell && cell.cap === "tail").length,
|
|
257
|
-
];
|
|
258
215
|
/**
|
|
259
216
|
* [LAW:parse-dont-validate] The one place a seam is checked, so every rule
|
|
260
217
|
* the cell model states is refused at construction and the render reads cells
|
|
@@ -263,16 +220,7 @@ const seamWidth = (cells) => [
|
|
|
263
220
|
* back is a frozen copy the caller can no longer change.
|
|
264
221
|
*/
|
|
265
222
|
function parseSeam(raw) {
|
|
266
|
-
const parseForm = (form) => {
|
|
267
|
-
const seam = parseCells(raw, form, "seam", asSeamCell(form, "seam"));
|
|
268
|
-
// A divider authored as the seam itself stays the seam, so a render can see
|
|
269
|
-
// it has no choice to make.
|
|
270
|
-
const divider = raw[form].divider === raw[form].seam ? seam : parseCells(raw, form, "divider", asSeamCell(form, "divider"));
|
|
271
|
-
const [seamAt, dividerAt] = [seamWidth(seam), seamWidth(divider)];
|
|
272
|
-
if (seamAt.some((n, i) => n !== dividerAt[i]))
|
|
273
|
-
throw new Error(`seam: ${form} divider is not the width of the seam under every caps`);
|
|
274
|
-
return Object.freeze({ seam, divider });
|
|
275
|
-
};
|
|
223
|
+
const parseForm = (form) => Object.freeze({ seam: parseCells(raw, form, "seam", asSeamCell(form, "seam")) });
|
|
276
224
|
return Object.freeze({ glyph: parseForm("glyph"), ascii: parseForm("ascii") });
|
|
277
225
|
}
|
|
278
226
|
/** [LAW:parse-dont-validate] `parseSeam`'s twin for the caps. */
|
|
@@ -282,21 +230,22 @@ function parseCaps(raw) {
|
|
|
282
230
|
}
|
|
283
231
|
// One form of the seam joined with that form of the caps.
|
|
284
232
|
function joinForms(seam, caps) {
|
|
285
|
-
|
|
286
|
-
const seamCells = splice(seam.seam);
|
|
287
|
-
return { seam: seamCells, divider: seam.divider === seam.seam ? seamCells : splice(seam.divider), lead: caps.lead, tail: caps.tail };
|
|
233
|
+
return { seam: seam.seam.flatMap((cell) => ("cap" in cell ? caps[cell.cap] : [cell])), lead: caps.lead, tail: caps.tail };
|
|
288
234
|
}
|
|
235
|
+
// The parts of `side`'s edge `cell` paints with: its ground (`bg`), its text (`fg`).
|
|
236
|
+
const partsRead = (cell, side) => new Set([cell.fg, cell.bg].flatMap((color) => (color === "ground" ? [] : [...paintsIn(color)].flatMap((p) => ("edge" in p && p.edge === side ? [p.part] : [])))));
|
|
289
237
|
// Whether any of `cells` paints with `side`'s ground.
|
|
290
238
|
const readsGround = (cells, side) => cells.some((cell) => [cell.fg, cell.bg].some((color) => color !== "ground" && [...paintsIn(color)].some((p) => "edge" in p && p.edge === side && p.part === "bg")));
|
|
291
239
|
function formOf(shape) {
|
|
292
|
-
const
|
|
240
|
+
const cells = (part) => shape[part].map((cell) => ({ cell, parts: { left: partsRead(cell, "left"), right: partsRead(cell, "right") } }));
|
|
293
241
|
return {
|
|
294
242
|
shape,
|
|
295
243
|
reads: {
|
|
296
|
-
seam: { left: readsGround(
|
|
244
|
+
seam: { left: readsGround(shape.seam, "left"), right: readsGround(shape.seam, "right") },
|
|
297
245
|
lead: readsGround(shape.lead, "right"),
|
|
298
246
|
tail: readsGround(shape.tail, "left"),
|
|
299
247
|
},
|
|
248
|
+
cells: { seam: cells("seam"), lead: cells("lead"), tail: cells("tail") },
|
|
300
249
|
};
|
|
301
250
|
}
|
|
302
251
|
// A bg with a real colour to paint. `undefined` (no bg) and the terminal
|
|
@@ -312,29 +261,82 @@ function paintableBg(bg) {
|
|
|
312
261
|
function drawnGround(bg) {
|
|
313
262
|
return bg.flattenAlpha(SURFACE_BLACK);
|
|
314
263
|
}
|
|
315
|
-
//
|
|
316
|
-
// is
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
264
|
+
// Whether ink stands off its ground, both as a depth draws them, by the floor a
|
|
265
|
+
// seam is seen at. A colour whose RGB is the terminal theme's own (ANSI 0–15, a
|
|
266
|
+
// blend reaching one) has no value here, so two of them stand apart unless they
|
|
267
|
+
// are one expression: the same palette slot — its `number`, never the name or
|
|
268
|
+
// the depth that spells it ("red", "color(1)", an EIGHT_BIT spec on 0–15 are
|
|
269
|
+
// one slot) — or the same blend, whose name spells each end by its slot for the
|
|
270
|
+
// same reason. At sixteen colours, then, the floor is a different slot. The
|
|
271
|
+
// terminal's default colour is nobody's to measure, and stands apart.
|
|
272
|
+
function standsOff(ink, ground) {
|
|
273
|
+
if (ink.isDefault || ground.isDefault)
|
|
274
|
+
return true;
|
|
275
|
+
const [a, b] = [ink.fixedValue, ground.fixedValue];
|
|
276
|
+
return a !== undefined && b !== undefined
|
|
277
|
+
? Oklch.fromRgba(a).deltaE(Oklch.fromRgba(b)) >= SEAM_MIN_DELTA_E
|
|
278
|
+
: ink.number !== undefined ? ink.number !== ground.number : ink.name !== ground.name;
|
|
279
|
+
}
|
|
280
|
+
// A step along a lightness ray: finer than the steps between the colours a
|
|
281
|
+
// truecolor writer draws, so the walk passes over none of them.
|
|
282
|
+
const LIFT_STEP = 0.001;
|
|
283
|
+
// The steps along `origin`'s lightness ray, its chroma and hue held, in the
|
|
284
|
+
// order the lift tries them: the smaller move first, and at an equal move the
|
|
285
|
+
// lighter, out to black and to white.
|
|
286
|
+
function* lightnessRay(origin) {
|
|
287
|
+
for (let k = 1; k * LIFT_STEP <= 1; k++) {
|
|
288
|
+
for (const l of [origin.l + k * LIFT_STEP, origin.l - k * LIFT_STEP]) {
|
|
289
|
+
if (l >= 0 && l <= 1)
|
|
290
|
+
yield new Oklch(l, origin.c, origin.h);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* `ink`, a glyph's colour on `ground`, held at least `SEAM_MIN_DELTA_E` off it
|
|
296
|
+
* as `depth` draws both (`Style.drawnColors`). Ink that already stands off is
|
|
297
|
+
* returned as it is. Ink that does not becomes the drawn form of the nearest
|
|
298
|
+
* step along its own OKLCH lightness ray, chroma and hue held, that stands off:
|
|
299
|
+
* the smaller step, toward white or toward black. Every step is measured as the
|
|
300
|
+
* depth draws it, so at 256 colours and at sixteen the candidates are the
|
|
301
|
+
* entries the depth draws, and the side the ink moves to can differ between
|
|
302
|
+
* depths. A floor measured on rounded colours is not monotone along a ray, so
|
|
303
|
+
* the walk enumerates and never bisects. A side with no colour to measure is
|
|
304
|
+
* left alone.
|
|
305
|
+
*
|
|
306
|
+
* [LAW:one-source-of-truth] The colour returned is the one measured — the
|
|
307
|
+
* entry the depth draws, not the step that rounds to it — so a reader of the
|
|
308
|
+
* cell at another depth (an export reads a recording in truecolor) sees the
|
|
309
|
+
* colour that cleared the floor, never a step one unit off its ground.
|
|
310
|
+
*
|
|
311
|
+
* [LAW:single-enforcer] The one place a join cell's visibility is decided:
|
|
312
|
+
* nothing outside the joiner predicts whether a seam will show.
|
|
313
|
+
*/
|
|
314
|
+
function standOff(ink, ground, depth) {
|
|
315
|
+
if (ink === undefined || ground === undefined)
|
|
316
|
+
return ink;
|
|
317
|
+
const drawn = (color, at) => new Style({ color, bgcolor: ground }).drawnColors(at);
|
|
318
|
+
const { color: shown, bgcolor: under } = drawn(ink, depth);
|
|
319
|
+
if (standsOff(shown, under))
|
|
320
|
+
return ink;
|
|
321
|
+
// The ray starts from the ink as it is laid on its ground, before a depth
|
|
322
|
+
// rounds it; ink the terminal's theme draws starts from the colour the
|
|
323
|
+
// default terminal theme gives it. Ink that vanishes is drawn in the same
|
|
324
|
+
// kind as its ground — both fixed, or both the theme's — and every step is
|
|
325
|
+
// drawn in that kind too, so it is measured as the ink was. Ink the depth
|
|
326
|
+
// draws as the theme's (a slot, or a mix reaching one at truecolor) steps
|
|
327
|
+
// between slots: an RGB beside a colour only the terminal knows could be
|
|
328
|
+
// that very colour. Ink the depth fixes (that same mix is a cube entry at
|
|
329
|
+
// 256) steps between fixed colours, for the same reason turned round.
|
|
330
|
+
const laid = drawn(ink).color;
|
|
331
|
+
const kind = shown.fixedValue === undefined ? ColorDepth.STANDARD : ColorDepth.TRUECOLOR;
|
|
332
|
+
for (const step of lightnessRay(Oklch.fromRgba(laid.getTruecolor()))) {
|
|
333
|
+
const candidate = drawn(ColorSpec.fromRgba(step.toRgba()).downgrade(kind), depth).color;
|
|
334
|
+
if (standsOff(candidate, under))
|
|
335
|
+
return candidate;
|
|
336
|
+
}
|
|
337
|
+
// [LAW:no-silent-failure] Unreachable: the ray runs out to black and to
|
|
338
|
+
// white, and no ground lies within the floor of both, nor is one slot both.
|
|
339
|
+
throw new Error(`no colour on the lightness ray of ${ink.name} stands off ${ground.name} at depth ${ColorDepth[depth]}`);
|
|
338
340
|
}
|
|
339
341
|
function resolvePaint(paint, edges, options) {
|
|
340
342
|
if ("edge" in paint) {
|
|
@@ -352,14 +354,97 @@ function resolvePaint(paint, edges, options) {
|
|
|
352
354
|
// A mix with no colour at one end has nothing to blend toward.
|
|
353
355
|
return a && b && ColorSpec.blend(a, b, t);
|
|
354
356
|
}
|
|
357
|
+
// [LAW:single-enforcer] The one resolution of a join cell's paints: at join
|
|
358
|
+
// time, and again whenever an effect moves the neighbours it reads
|
|
359
|
+
// (`JoinedCell`).
|
|
355
360
|
function cellStyle(cell, edges, options) {
|
|
356
361
|
// [LAW:dataflow-not-control-flow] "ground" is the absence of a colour on its
|
|
357
362
|
// side; as the fg it is reverse video over the bg colour, so the glyph's ink
|
|
358
363
|
// is the terminal's own background.
|
|
359
364
|
if (cell.fg === "ground")
|
|
360
365
|
return new Style({ color: cell.bg === "ground" ? undefined : resolvePaint(cell.bg, edges, options), reverse: true });
|
|
361
|
-
const
|
|
362
|
-
|
|
366
|
+
const bgcolor = cell.bg === "ground" ? undefined : resolvePaint(cell.bg, edges, options);
|
|
367
|
+
// [LAW:dataflow-not-control-flow] Every cell's ink is held off its ground;
|
|
368
|
+
// the gap measured between them decides how far it moves, usually not at all.
|
|
369
|
+
return new Style({ color: standOff(resolvePaint(cell.fg, edges, options), bgcolor, options.colorSystem ?? ColorDepth.TRUECOLOR), bgcolor });
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* A cell a `CellJoiner` drew, as what it is: one function of its two
|
|
373
|
+
* neighbours' edges. It holds the cell's paints, the neighbour each side of
|
|
374
|
+
* them reads, and the edges and render it was resolved from, and it is stamped
|
|
375
|
+
* on the cell as the owner of its innermost anchor level.
|
|
376
|
+
*
|
|
377
|
+
* [LAW:one-source-of-truth] A seam's colours are its neighbours', so nothing
|
|
378
|
+
* paints them but this resolution. An effect paints a strip's items and never
|
|
379
|
+
* a join cell that `follows` them; once the items are painted, each such cell
|
|
380
|
+
* is handed what moved at the item cells beside it and resolved again through
|
|
381
|
+
* `cellStyle`, the path the join was drawn by, lift included
|
|
382
|
+
* (`../renderables/effect.ts`). A seam then follows its neighbours wherever an
|
|
383
|
+
* effect takes them, a mix of the two included, and an effect that paints
|
|
384
|
+
* both one colour leaves the seam's ink lifted off it. A cell painted from
|
|
385
|
+
* roles and the terminal's ground alone, as `plain`'s separator is, follows
|
|
386
|
+
* nobody, and an effect paints it as it paints any cell.
|
|
387
|
+
*/
|
|
388
|
+
export class JoinedCell {
|
|
389
|
+
cell;
|
|
390
|
+
parts;
|
|
391
|
+
neighbours;
|
|
392
|
+
edges;
|
|
393
|
+
options;
|
|
394
|
+
/** What the cell's paints read on each side: that neighbour and its edge as the cell was resolved from it, or `null` for a side they read nothing of. */
|
|
395
|
+
reads;
|
|
396
|
+
/** Whether the cell's paints read either neighbour, so it follows them under an effect. */
|
|
397
|
+
follows;
|
|
398
|
+
/** The cell as drawn from its edges: the one resolution, at join time and after an effect alike. */
|
|
399
|
+
style;
|
|
400
|
+
constructor(cell, parts, neighbours, edges, options) {
|
|
401
|
+
this.cell = cell;
|
|
402
|
+
this.parts = parts;
|
|
403
|
+
this.neighbours = neighbours;
|
|
404
|
+
this.edges = edges;
|
|
405
|
+
this.options = options;
|
|
406
|
+
const read = (side) => {
|
|
407
|
+
if (parts[side].size === 0)
|
|
408
|
+
return null;
|
|
409
|
+
const [owner, edge] = [neighbours[side], edges[side]];
|
|
410
|
+
// [LAW:no-silent-failure] Unreachable: a join draws a part only beside
|
|
411
|
+
// the neighbours its cells may name: a cap naming the one it is drawn
|
|
412
|
+
// without is refused when parsed (`parsePaint`).
|
|
413
|
+
if (owner === null || edge === undefined)
|
|
414
|
+
throw new Error(`a join cell paints with its ${side} neighbour's edge, and the join has no ${side} neighbour`);
|
|
415
|
+
return { owner, edge };
|
|
416
|
+
};
|
|
417
|
+
this.reads = { left: read("left"), right: read("right") };
|
|
418
|
+
this.follows = this.reads.left !== null || this.reads.right !== null;
|
|
419
|
+
this.style = cellStyle(cell, edges, options);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The cell resolved again once each side's edge has moved as `moves` says:
|
|
423
|
+
* its `colors`, as `cellStyle` draws them, and `style`, the cell's own, with
|
|
424
|
+
* the record of that stamped where this one was, so an effect drawn over
|
|
425
|
+
* this one moves on from these edges. Resolved, lift included, at `depth`,
|
|
426
|
+
* the depth the effect writes the frame at. None when nothing moved of what
|
|
427
|
+
* the cell paints with: a seam of arrows in two grounds is as it was drawn
|
|
428
|
+
* while an effect moves only the lettering beside it, and its lift is not
|
|
429
|
+
* walked again for a frame that cannot change it.
|
|
430
|
+
*/
|
|
431
|
+
rederived(moves, style, depth) {
|
|
432
|
+
const reaches = (side) => (moves[side]?.color !== undefined && this.parts[side].has("fg")) || (moves[side]?.bgcolor !== undefined && this.parts[side].has("bg"));
|
|
433
|
+
if (!reaches("left") && !reaches("right"))
|
|
434
|
+
return undefined;
|
|
435
|
+
const moved = (edge, move) => move === undefined ? edge : new Style({ color: move.color ?? edge?.color, bgcolor: move.bgcolor ?? edge?.bgcolor });
|
|
436
|
+
const edges = { left: moved(this.edges.left, moves.left), right: moved(this.edges.right, moves.right) };
|
|
437
|
+
const next = new JoinedCell(this.cell, this.parts, this.neighbours, edges, { ...this.options, colorSystem: depth });
|
|
438
|
+
const restamp = (level) => ({ ...level, owner: level.owner === this ? next : level.owner, inner: level.inner && restamp(level.inner) });
|
|
439
|
+
return { colors: next.style, style: style.withAnchor(style.anchor && restamp(style.anchor)) };
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/** The record a `CellJoiner` stamped on the cell `anchor` names, or none for a cell no `CellJoiner` drew. */
|
|
443
|
+
export function joinedCell(anchor) {
|
|
444
|
+
for (let level = anchor; level; level = level.inner)
|
|
445
|
+
if (level.owner instanceof JoinedCell)
|
|
446
|
+
return level.owner;
|
|
447
|
+
return undefined;
|
|
363
448
|
}
|
|
364
449
|
const shapeGlyphs = (shape) => PARTS.flatMap((part) => shape[part].flatMap(glyphsOf)).join("");
|
|
365
450
|
/**
|
|
@@ -370,9 +455,10 @@ const shapeGlyphs = (shape) => PARTS.flatMap((part) => shape[part].flatMap(glyph
|
|
|
370
455
|
* Which part a join draws is read off its two neighbours. A neighbour is
|
|
371
456
|
* missing at the strip's ends, and counts as missing — an endpoint — when the
|
|
372
457
|
* seam paints with its ground anywhere and it has none to paint. With both
|
|
373
|
-
* present the join is the seam
|
|
374
|
-
*
|
|
375
|
-
*
|
|
458
|
+
* present the join is the seam; with only the right, the lead; with only the
|
|
459
|
+
* left, the tail; with neither, nothing. Every cell is drawn with its ink held
|
|
460
|
+
* off its ground at `options.colorSystem` (`standOff`), measured per cell, so a
|
|
461
|
+
* seam stepping in thirds shows every step however close its grounds. A cap
|
|
376
462
|
* that paints with its neighbour's ground is drawn only beside a neighbour
|
|
377
463
|
* with one, so caps that need grounds never stop a seam that needs none.
|
|
378
464
|
*
|
|
@@ -391,7 +477,7 @@ export class CellJoiner {
|
|
|
391
477
|
const forms = this._forms;
|
|
392
478
|
return {
|
|
393
479
|
*render(options) {
|
|
394
|
-
const {
|
|
480
|
+
const { cells, reads } = drawable(options, forms.glyph, forms.ascii, (form) => shapeGlyphs(form.shape));
|
|
395
481
|
const edges = { left: left?.edgeStyle("right", options), right: right?.edgeStyle("left", options) };
|
|
396
482
|
const leftBg = paintableBg(edges.left?.bgcolor);
|
|
397
483
|
const rightBg = paintableBg(edges.right?.bgcolor);
|
|
@@ -400,25 +486,16 @@ export class CellJoiner {
|
|
|
400
486
|
const leads = hasRight && (!reads.lead || rightBg !== undefined);
|
|
401
487
|
const tails = hasLeft && (!reads.tail || leftBg !== undefined);
|
|
402
488
|
const neighbours = { left, right };
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const styled = (part) => drawn[part].map((cell, at) => {
|
|
407
|
-
const owners = new ColorOwners(ownerOf(cell.fg), ownerOf(cell.bg));
|
|
408
|
-
return new Segment(pickGlyph(cell, part, index, at), cellStyle(cell, edges, options).withAnchor({ owner: owners, row: 0, col: 0, inner: undefined }));
|
|
489
|
+
const styled = (part) => cells[part].map(({ cell, parts }, at) => {
|
|
490
|
+
const joined = new JoinedCell(cell, parts, neighbours, edges, options);
|
|
491
|
+
return new Segment(pickGlyph(cell, part, index, at), joined.style.withAnchor({ owner: joined, row: 0, col: 0, inner: undefined }));
|
|
409
492
|
});
|
|
410
493
|
if (!hasLeft || !hasRight) {
|
|
411
494
|
if (leads || tails)
|
|
412
495
|
yield* styled(leads ? "lead" : "tail");
|
|
413
496
|
return;
|
|
414
497
|
}
|
|
415
|
-
|
|
416
|
-
// its ground at a shallow depth still leaves the others to show the
|
|
417
|
-
// step, and measuring per cell, not across the two grounds, divides a
|
|
418
|
-
// seam stepping in thirds where each third would not be seen.
|
|
419
|
-
const seam = styled("seam");
|
|
420
|
-
const lost = drawn.divider !== drawn.seam && seam.every((segment) => segment.style !== undefined && vanishes(segment.style, options.colorSystem));
|
|
421
|
-
yield* lost ? styled("divider") : seam;
|
|
498
|
+
yield* styled("seam");
|
|
422
499
|
},
|
|
423
500
|
};
|
|
424
501
|
}
|
|
@@ -432,52 +509,35 @@ const GROUND = "ground";
|
|
|
432
509
|
const LEAD = { cap: "lead" };
|
|
433
510
|
const TAIL = { cap: "tail" };
|
|
434
511
|
const both = (glyph, ascii) => ({ glyph, ascii });
|
|
435
|
-
const POWERLINE = { glyph: "\ue0b0",
|
|
436
|
-
const SLANT = { glyph: "\ue0bc",
|
|
437
|
-
const BACKSLANT = { glyph: "\ue0b8",
|
|
438
|
-
const FLAME = { glyph: "\ue0c0",
|
|
439
|
-
const PIXEL = { glyph: "\ue0c4",
|
|
440
|
-
const ICE = { glyph: "\ue0c8",
|
|
441
|
-
const BUBBLE = { glyph: "\ue0b4",
|
|
442
|
-
// `glyph` in the left ground over the right
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
seam: [{ glyph, fg: LEFT_BG, bg: RIGHT_BG }],
|
|
446
|
-
divider: [{ glyph: thin, fg: LEFT_FG, bg: LEFT_BG }],
|
|
447
|
-
});
|
|
448
|
-
const arrowSeam = (f) => both(arrow(f.glyph, f.thin), arrow(f.ascii, f.asciiThin));
|
|
512
|
+
const POWERLINE = { glyph: "\ue0b0", ascii: ">" };
|
|
513
|
+
const SLANT = { glyph: "\ue0bc", ascii: "/" };
|
|
514
|
+
const BACKSLANT = { glyph: "\ue0b8", ascii: "\\" };
|
|
515
|
+
const FLAME = { glyph: "\ue0c0", ascii: "}" };
|
|
516
|
+
const PIXEL = { glyph: "\ue0c4", ascii: "#" };
|
|
517
|
+
const ICE = { glyph: "\ue0c8", ascii: "]" };
|
|
518
|
+
const BUBBLE = { glyph: "\ue0b4", ascii: ")" };
|
|
519
|
+
// `glyph` in the left ground over the right.
|
|
520
|
+
const arrow = (glyph) => ({ seam: [{ glyph, fg: LEFT_BG, bg: RIGHT_BG }] });
|
|
521
|
+
const arrowSeam = (f) => both(arrow(f.glyph), arrow(f.ascii));
|
|
449
522
|
// Three arrows stepping through the two thirds between the grounds.
|
|
450
|
-
function prism(glyph
|
|
523
|
+
function prism(glyph) {
|
|
451
524
|
const third = (t) => ({ mix: [LEFT_BG, RIGHT_BG, t] });
|
|
452
|
-
const pad = { glyph: " ", fg: LEFT_FG, bg: LEFT_BG };
|
|
453
525
|
return {
|
|
454
526
|
seam: [
|
|
455
527
|
{ glyph, fg: LEFT_BG, bg: third(1 / 3) },
|
|
456
528
|
{ glyph, fg: third(1 / 3), bg: third(2 / 3) },
|
|
457
529
|
{ glyph, fg: third(2 / 3), bg: RIGHT_BG },
|
|
458
530
|
],
|
|
459
|
-
divider: [pad, { glyph: thin, fg: LEFT_FG, bg: LEFT_BG }, pad],
|
|
460
531
|
};
|
|
461
532
|
}
|
|
462
533
|
// The runs parted: the caps close the one and open the other, `between` —
|
|
463
534
|
// cells on the terminal's ground — set between them.
|
|
464
|
-
|
|
465
|
-
const seam = [TAIL, ...between, LEAD];
|
|
466
|
-
return { seam, divider: seam };
|
|
467
|
-
}
|
|
535
|
+
const parted = (between) => ({ seam: [TAIL, ...between, LEAD] });
|
|
468
536
|
// One cell drawn over the two grounds' midpoint, so it reads as neither item's.
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
// A ragged tear in the left ground over the midpoint; where that ink would
|
|
474
|
-
// vanish into the midpoint — grounds a few steps apart, or one ground — the
|
|
475
|
-
// same tear in the left item's text.
|
|
476
|
-
function torn(glyphs) {
|
|
477
|
-
return { seam: midpoint({ oneOf: glyphs }, LEFT_BG).seam, divider: [{ glyph: { oneOf: glyphs }, fg: LEFT_FG, bg: HALF }] };
|
|
478
|
-
}
|
|
479
|
-
const PLAIN_SEAM = [{ glyph: " | ", fg: { role: "strip.separator" }, bg: GROUND }];
|
|
480
|
-
const PLAIN = { seam: PLAIN_SEAM, divider: PLAIN_SEAM };
|
|
537
|
+
const midpoint = (glyph, fg) => ({ seam: [{ glyph, fg, bg: HALF }] });
|
|
538
|
+
// A ragged tear in the left ground over the midpoint.
|
|
539
|
+
const torn = (glyphs) => midpoint({ oneOf: glyphs }, LEFT_BG);
|
|
540
|
+
const PLAIN = { seam: [{ glyph: " | ", fg: { role: "strip.separator" }, bg: GROUND }] };
|
|
481
541
|
const SPACE = { glyph: " ", fg: LEFT_FG, bg: GROUND };
|
|
482
542
|
const rail = (glyph) => ({ glyph, fg: { role: "strip.rail" }, bg: GROUND });
|
|
483
543
|
/**
|
|
@@ -487,7 +547,7 @@ const rail = (glyph) => ({ glyph, fg: { role: "strip.rail" }, bg: GROUND });
|
|
|
487
547
|
*/
|
|
488
548
|
export const SEAMS = Object.freeze({
|
|
489
549
|
powerline: parseSeam(arrowSeam(POWERLINE)),
|
|
490
|
-
prism: parseSeam(both(prism(POWERLINE.glyph
|
|
550
|
+
prism: parseSeam(both(prism(POWERLINE.glyph), prism(POWERLINE.ascii))),
|
|
491
551
|
slant: parseSeam(arrowSeam(SLANT)),
|
|
492
552
|
backslant: parseSeam(arrowSeam(BACKSLANT)),
|
|
493
553
|
flame: parseSeam(arrowSeam(FLAME)),
|
|
@@ -572,12 +632,13 @@ function gradient(steps, glyph) {
|
|
|
572
632
|
// samples 2i (its ink, the left half) and 2i+1 (its ground, the right half),
|
|
573
633
|
// so no sample equals either neighbour's ground.
|
|
574
634
|
const samples = 2 * steps;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
635
|
+
return {
|
|
636
|
+
seam: Array.from({ length: steps }, (_, i) => ({
|
|
637
|
+
glyph,
|
|
638
|
+
fg: { mix: [LEFT_BG, RIGHT_BG, (2 * i + 0.5) / samples] },
|
|
639
|
+
bg: { mix: [LEFT_BG, RIGHT_BG, (2 * i + 1.5) / samples] },
|
|
640
|
+
})),
|
|
641
|
+
};
|
|
581
642
|
}
|
|
582
643
|
/**
|
|
583
644
|
* A ramp of `steps` cells from the left ground to the right. Each cell is the
|
package/dist/core/style.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ import { type Anchor } from "./anchor.js";
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const ATTRIBUTE_NAMES: readonly ["bold", "dim", "italic", "underline", "blink", "blink2", "reverse", "conceal", "strike", "underline2", "frame", "encircle", "overline"];
|
|
13
13
|
export type AttributeName = (typeof ATTRIBUTE_NAMES)[number];
|
|
14
|
+
/**
|
|
15
|
+
* Each text attribute as a style sets it: on, off, or unset — and an unset
|
|
16
|
+
* one lets a style laid beneath (`Style.add`) show through.
|
|
17
|
+
*/
|
|
18
|
+
export type Attributes = {
|
|
19
|
+
readonly [A in AttributeName]: boolean | undefined;
|
|
20
|
+
};
|
|
14
21
|
export declare const ATTRIBUTE_SGR: Record<AttributeName, number>;
|
|
15
22
|
/**
|
|
16
23
|
* Canonical short-attribute aliases (`b` → `bold`, `i` → `italic`, …).
|
|
@@ -18,7 +25,7 @@ export declare const ATTRIBUTE_SGR: Record<AttributeName, number>;
|
|
|
18
25
|
* bindings — adding an alias here makes it available everywhere.
|
|
19
26
|
* [LAW:one-source-of-truth]
|
|
20
27
|
*/
|
|
21
|
-
export declare const ATTRIBUTE_SHORT_ALIASES: Record<string, AttributeName
|
|
28
|
+
export declare const ATTRIBUTE_SHORT_ALIASES: Readonly<Record<string, AttributeName>>;
|
|
22
29
|
export interface StyleOptions {
|
|
23
30
|
color?: string | ColorSpec;
|
|
24
31
|
bgcolor?: string | ColorSpec;
|
|
@@ -38,7 +45,18 @@ export interface StyleOptions {
|
|
|
38
45
|
link?: string;
|
|
39
46
|
meta?: Record<string, unknown>;
|
|
40
47
|
anchor?: Anchor;
|
|
41
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The hold the style's cells are in, both ends or neither: a cell saying
|
|
50
|
+
* only when it next changes would claim, by default, that it always was,
|
|
51
|
+
* and a timeline run backwards past its change would never wake for it.
|
|
52
|
+
* [LAW:types-are-the-program] Absent, the cells never change.
|
|
53
|
+
*/
|
|
54
|
+
hold?: Hold;
|
|
55
|
+
}
|
|
56
|
+
/** A hold: since when a sample has been what it is, and until when it stays so, on one clock. */
|
|
57
|
+
export interface Hold {
|
|
58
|
+
readonly lastChange: number;
|
|
59
|
+
readonly nextChange: number;
|
|
42
60
|
}
|
|
43
61
|
export declare class StyleSyntaxError extends Error {
|
|
44
62
|
constructor(message: string, options?: ErrorOptions);
|
|
@@ -60,7 +78,7 @@ export declare class Style {
|
|
|
60
78
|
readonly encircle: boolean | undefined;
|
|
61
79
|
readonly overline: boolean | undefined;
|
|
62
80
|
readonly link: string | undefined;
|
|
63
|
-
readonly meta: Record<string, unknown
|
|
81
|
+
readonly meta: Readonly<Record<string, unknown>> | undefined;
|
|
64
82
|
/**
|
|
65
83
|
* Where this style's cells sat in the output of whatever drew them; see
|
|
66
84
|
* `./anchor.ts`. It draws nothing, and it makes two styles that draw alike
|
|
@@ -68,17 +86,19 @@ export declare class Style {
|
|
|
68
86
|
*/
|
|
69
87
|
readonly anchor: Anchor | undefined;
|
|
70
88
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
89
|
+
* The hold this style's cells are in, on the timeline of whoever drew the
|
|
90
|
+
* frame: since when what they show has been what it is (`lastChange`), and
|
|
91
|
+
* when it next changes (`nextChange`) — both `t` for a cell drawn by
|
|
92
|
+
* something that moves every frame, and `-Infinity`/`Infinity` for one
|
|
74
93
|
* that never changes. It draws nothing. Whatever draws for a handed time
|
|
75
|
-
* stamps its cells with it (`
|
|
76
|
-
* through every container as the anchor does (`./anchor.ts`), and
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* asking each container. Two styles
|
|
94
|
+
* stamps its cells with it (`placedRender`, `Effected`), the stamp rides up
|
|
95
|
+
* through every container as the anchor does (`./anchor.ts`), and whoever
|
|
96
|
+
* holds the composed frame reads it off (`Segment.nextChange`, and
|
|
97
|
+
* `Segment.lastChange` for a host running its timeline backwards), so a
|
|
98
|
+
* host knows when to draw again without asking each container. Two styles
|
|
99
|
+
* laid together are in the intersection of their holds.
|
|
80
100
|
*/
|
|
81
|
-
readonly
|
|
101
|
+
readonly hold: Hold;
|
|
82
102
|
constructor(options?: StyleOptions);
|
|
83
103
|
get isNull(): boolean;
|
|
84
104
|
get transparentBackground(): boolean;
|
|
@@ -97,6 +117,19 @@ export declare class Style {
|
|
|
97
117
|
* The same look, drawn from the place `anchor` names, or from nowhere.
|
|
98
118
|
*/
|
|
99
119
|
withAnchor(anchor: Anchor | undefined): Style;
|
|
120
|
+
/** The style's text attributes, each as it sets it. */
|
|
121
|
+
get attributes(): Attributes;
|
|
122
|
+
/**
|
|
123
|
+
* The same style with each attribute `attributes` names set as it says —
|
|
124
|
+
* on, off, or unset — and every other field as it was.
|
|
125
|
+
*/
|
|
126
|
+
withAttributes(attributes: Partial<Attributes>): Style;
|
|
127
|
+
/**
|
|
128
|
+
* This style with its motion taken out, what reduced motion draws: `blink`
|
|
129
|
+
* and `blink2`, the motion a terminal makes on its own, unset, and every
|
|
130
|
+
* other field as it was. A style that does not blink is its own.
|
|
131
|
+
*/
|
|
132
|
+
reduced(): Style;
|
|
100
133
|
/**
|
|
101
134
|
* This style on the cell `cells` to the right: its anchor shifted along its
|
|
102
135
|
* row, or the style itself when it has no anchor.
|
|
@@ -130,7 +163,7 @@ export declare class Style {
|
|
|
130
163
|
/**
|
|
131
164
|
* The look as a canonical string that round-trips through `Style.parse()`:
|
|
132
165
|
* colours, attributes and the link, which is all a style string can spell.
|
|
133
|
-
* What a style carries beyond its look — `meta`, `anchor`, `
|
|
166
|
+
* What a style carries beyond its look — `meta`, `anchor`, `hold` —
|
|
134
167
|
* has no spelling and is not here, so two styles that differ only there
|
|
135
168
|
* read alike; `equals` tells them apart.
|
|
136
169
|
*/
|
|
@@ -198,7 +231,7 @@ export declare class Theme {
|
|
|
198
231
|
resolve(style: TextStyle): Style;
|
|
199
232
|
has(name: string): boolean;
|
|
200
233
|
}
|
|
201
|
-
export declare const DEFAULT_STYLES: Record<string, Style
|
|
234
|
+
export declare const DEFAULT_STYLES: Readonly<Record<string, Style>>;
|
|
202
235
|
/**
|
|
203
236
|
* The theme a render resolves names against when nothing supplied one — what
|
|
204
237
|
* a renderable sees outside a `Console`, as in `renderToString`.
|