@promptctl/rich-js 0.27.0 → 0.28.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 +1 -0
- package/THIRD-PARTY-NOTICES +42 -0
- package/dist/core/animation.d.ts +36 -17
- package/dist/core/animation.js +61 -37
- package/dist/core/ansi.d.ts +15 -8
- package/dist/core/ansi.js +106 -28
- package/dist/core/bidi-data.d.ts +14 -0
- package/dist/core/bidi-data.js +385 -0
- package/dist/core/bidi.d.ts +89 -0
- package/dist/core/bidi.js +615 -0
- package/dist/core/box.d.ts +9 -1
- package/dist/core/box.js +11 -0
- package/dist/core/cell-widths.d.ts +3 -2
- package/dist/core/cell-widths.js +93 -93
- package/dist/core/cells.d.ts +20 -0
- package/dist/core/cells.js +93 -5
- package/dist/core/color.d.ts +6 -7
- package/dist/core/color.js +11 -13
- package/dist/core/console.d.ts +18 -1
- package/dist/core/console.js +24 -5
- package/dist/core/control-codes.d.ts +61 -0
- package/dist/core/control-codes.js +157 -0
- package/dist/core/env.d.ts +6 -0
- package/dist/core/env.js +9 -1
- package/dist/core/export-html.js +4 -3
- package/dist/core/export-lines.d.ts +2 -0
- package/dist/core/export-lines.js +7 -3
- package/dist/core/export-svg.js +6 -5
- package/dist/core/json.js +9 -2
- package/dist/core/markup.js +4 -3
- package/dist/core/orient.d.ts +68 -0
- package/dist/core/orient.js +224 -0
- package/dist/core/osc8.d.ts +12 -5
- package/dist/core/osc8.js +14 -7
- package/dist/core/pretty.js +22 -18
- package/dist/core/protocol.d.ts +27 -6
- package/dist/core/protocol.js +14 -6
- package/dist/core/render.d.ts +8 -3
- package/dist/core/render.js +18 -5
- package/dist/core/seal.d.ts +26 -0
- package/dist/core/seal.js +75 -0
- package/dist/core/segment.d.ts +9 -1
- package/dist/core/segment.js +11 -1
- package/dist/core/style.d.ts +29 -1
- package/dist/core/style.js +41 -5
- package/dist/core/text-order.d.ts +51 -0
- package/dist/core/text-order.js +50 -0
- package/dist/core/text.d.ts +10 -0
- package/dist/core/text.js +133 -87
- package/dist/core/timeline.js +6 -6
- package/dist/core/view.d.ts +1 -1
- package/dist/core/view.js +5 -4
- package/dist/core/wrap.d.ts +24 -6
- package/dist/core/wrap.js +82 -16
- package/dist/host/app.d.ts +44 -3
- package/dist/host/app.js +111 -6
- package/dist/host/index.d.ts +3 -2
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +35 -2
- package/dist/host/input.js +88 -4
- package/dist/host/terminal-colors.d.ts +18 -0
- package/dist/host/terminal-colors.js +46 -0
- package/dist/host/terminal-host.d.ts +2 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +2 -2
- package/dist/renderables/change.d.ts +1 -3
- package/dist/renderables/change.js +4 -6
- package/dist/renderables/effect.d.ts +60 -59
- package/dist/renderables/effect.js +91 -81
- package/dist/renderables/effects.d.ts +37 -8
- package/dist/renderables/effects.js +185 -52
- package/dist/renderables/frames.d.ts +1 -10
- package/dist/renderables/frames.js +1 -16
- package/dist/renderables/glyph-effect.d.ts +12 -13
- package/dist/renderables/glyph-effect.js +34 -32
- package/dist/renderables/glyph-effects.d.ts +27 -8
- package/dist/renderables/glyph-effects.js +75 -7
- package/dist/renderables/lifecycle.d.ts +5 -7
- package/dist/renderables/lifecycle.js +6 -7
- package/dist/renderables/markdown.js +4 -2
- package/dist/renderables/panel.js +6 -4
- package/dist/renderables/progressBar.d.ts +3 -3
- package/dist/renderables/progressBar.js +16 -13
- package/dist/renderables/syntax.js +7 -2
- package/dist/renderables/table.js +2 -1
- package/dist/template-bindings/animation-funcs.d.ts +49 -18
- package/dist/template-bindings/animation-funcs.js +115 -32
- package/dist/template-bindings/index.d.ts +7 -5
- package/dist/template-bindings/index.js +8 -5
- package/dist/template-bindings/palette-funcs.d.ts +1 -1
- package/dist/template-bindings/palette-funcs.js +1 -1
- package/dist/themes/buildPalette.d.ts +3 -2
- package/dist/themes/buildPalette.js +2 -2
- package/dist/themes/data/index.js +1 -4
- package/dist/themes/data/textual-ansi.js +0 -143
- package/dist/themes/ramp.d.ts +1 -1
- package/dist/themes/ramp.js +1 -1
- package/dist/themes/registry.d.ts +6 -8
- package/dist/themes/registry.js +2 -4
- package/dist/themes/terminalThemes.d.ts +4 -11
- package/dist/themes/terminalThemes.js +31 -47
- package/dist/widgets/button.d.ts +1 -1
- package/dist/widgets/button.js +6 -6
- package/dist/widgets/checkbox.js +4 -4
- package/dist/widgets/dropdown.d.ts +1 -1
- package/dist/widgets/dropdown.js +7 -5
- package/dist/widgets/themed-widget.js +3 -3
- package/dist/widgets/toggle.d.ts +1 -1
- package/dist/widgets/toggle.js +5 -5
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -397,6 +397,7 @@ npm run demo
|
|
|
397
397
|
| `npm run animation-playground` | animation-playground | Every kind of motion — tweens, moving ramps, a marching border, glyph and attribute effects, transitions, a list that comes and goes, a marquee, staggers and a blinking caret — on one timeline, with buttons to pause, reverse, scrub, change speed, reduce motion, drop to sixteen colours or none, and paint at one frame a second or sixty. |
|
|
398
398
|
| `npm run markup-plugins` | rich-markup-plugins | Custom markup tags registered through `MarkupRegistry`. Prints once and exits. |
|
|
399
399
|
| `npm run viewport` | rich-viewport | A selection you move through a list taller than its window with the arrow keys, `j`/`k`, PgUp/PgDn and Home/End, kept in view by `Viewport.ensureVisible`; the mouse wheel scrolls the window, and `q` quits. |
|
|
400
|
+
| `npm run terminal-colors` | terminal-colors | Your terminal asked for its own foreground and background with OSC 10 and OSC 11, shown as swatches, and whether it answered or the colours are assumed. |
|
|
400
401
|
| `npm run terminal-host` | terminal-host | Each key you press printed as the bytes the terminal sends for it, and each resize as the new size — a program written against `TerminalHost` alone. `examples/terminal-host/embed.ts` runs the same program on an xterm.js terminal in your own page. |
|
|
401
402
|
|
|
402
403
|
`Ctrl-C` quits any demo that stays running.
|
package/THIRD-PARTY-NOTICES
CHANGED
|
@@ -107,3 +107,45 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
107
107
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
108
108
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
109
109
|
SOFTWARE.
|
|
110
|
+
|
|
111
|
+
--------------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
src/core/bidi-data.ts holds data derived from the Unicode Character Database.
|
|
114
|
+
|
|
115
|
+
UNICODE LICENSE V3
|
|
116
|
+
|
|
117
|
+
COPYRIGHT AND PERMISSION NOTICE
|
|
118
|
+
|
|
119
|
+
Copyright (c) 1991-2026 Unicode, Inc.
|
|
120
|
+
|
|
121
|
+
NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
|
|
122
|
+
INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU
|
|
123
|
+
UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS
|
|
124
|
+
OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
|
|
125
|
+
DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
|
126
|
+
|
|
127
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
128
|
+
data files and any associated documentation (the "Data Files") or software and
|
|
129
|
+
any associated documentation (the "Software") to deal in the Data Files or
|
|
130
|
+
Software without restriction, including without limitation the rights to use,
|
|
131
|
+
copy, modify, merge, publish, distribute, and/or sell copies of the Data Files
|
|
132
|
+
or Software, and to permit persons to whom the Data Files or Software are
|
|
133
|
+
furnished to do so, provided that either (a) this copyright and permission
|
|
134
|
+
notice appear with all copies of the Data Files or Software, or (b) this
|
|
135
|
+
copyright and permission notice appear in associated Documentation.
|
|
136
|
+
|
|
137
|
+
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
138
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
139
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
|
|
140
|
+
PARTY RIGHTS.
|
|
141
|
+
|
|
142
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
|
|
143
|
+
LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
|
|
144
|
+
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
145
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
146
|
+
CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
|
147
|
+
|
|
148
|
+
Except as contained in this notice, the name of a copyright holder shall not be
|
|
149
|
+
used in advertising or otherwise to promote the sale, use or other dealings in
|
|
150
|
+
these Data Files or Software without prior written authorization of the
|
|
151
|
+
copyright holder.
|
package/dist/core/animation.d.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* changes every frame, however close together they are drawn. An early
|
|
10
10
|
* answer costs a host a frame that draws what the last one did; a late one
|
|
11
11
|
* skips a change. So an animation that cannot say answers `t`, as
|
|
12
|
-
* `continuous` does.
|
|
12
|
+
* `continuous` does. An answer that depends on what the frame drew, an
|
|
13
|
+
* effect's, is told by that drawing (`Moves`). A value drawn as cells carries this answer on every
|
|
13
14
|
* cell (`Style.hold`, both ends of the hold below), so a host holding
|
|
14
15
|
* the composed frame reads it there (`Segment.nextChange`); a value that is
|
|
15
16
|
* not drawn — a number, a colour — has `nextChange` as its only way to say
|
|
@@ -76,14 +77,31 @@ import { type Beat } from "./easing.js";
|
|
|
76
77
|
import { type Measurable, type Motion, type Renderable, type RenderOptions } from "./protocol.js";
|
|
77
78
|
import { Segment } from "./segment.js";
|
|
78
79
|
import { Style, type Hold } from "./style.js";
|
|
80
|
+
/**
|
|
81
|
+
* What a frame's drawing said of the hold the element named `key`, drawn at
|
|
82
|
+
* `t`, is in, or nothing if the frame heard of no such drawing: handed to an
|
|
83
|
+
* animation asked about a frame already drawn, so an answer only a drawing
|
|
84
|
+
* knows goes up through the combinators that remapped the time. It reads by
|
|
85
|
+
* `key` and not by the effect, which `reduced()` and a `repeat`'s `nth` build
|
|
86
|
+
* anew at each asking, and by `t`, since one element may be drawn at two
|
|
87
|
+
* moments. Parts sharing both share the intersection of what was drawn:
|
|
88
|
+
* narrower and never wider. A drawing a container hid, by not handing on its
|
|
89
|
+
* options, reads as none and stays early, unless a part sharing its key and
|
|
90
|
+
* `t` told. A measurement, which draws nothing, answers held for good for
|
|
91
|
+
* every part (`UNLAID`). An animation that does not read it ignores it, and
|
|
92
|
+
* one that forwards it to no part stays early. [LAW:one-source-of-truth] The
|
|
93
|
+
* frame's one drawing says it, so the answer cannot disagree with what the
|
|
94
|
+
* frame shows.
|
|
95
|
+
*/
|
|
96
|
+
export type Moves = (t: number, key: string) => Hold | undefined;
|
|
79
97
|
/** A value of `T` at a time in seconds, and the hold it is in: what every animation answers, whatever its values. */
|
|
80
98
|
export interface Timed<T> {
|
|
81
99
|
/** The value at `t` seconds. */
|
|
82
100
|
at(t: number): T;
|
|
83
101
|
/** The first moment, never before `t`, at which the value may stop being `at(t)`: `t` while it moves, `Infinity` once it never will. */
|
|
84
|
-
nextChange(t: number): number;
|
|
102
|
+
nextChange(t: number, moves?: Moves): number;
|
|
85
103
|
/** The last moment, never after `t`, at which the value may have become `at(t)`: `t` while it moves, `-Infinity` if it always was. */
|
|
86
|
-
lastChange(t: number): number;
|
|
104
|
+
lastChange(t: number, moves?: Moves): number;
|
|
87
105
|
/** This animation with its motion taken out — a loop at its first value, a one-shot cut to its end — drawn in its place under reduced motion. */
|
|
88
106
|
reduced(): Animation<T>;
|
|
89
107
|
}
|
|
@@ -99,8 +117,6 @@ export type Animation<T> = Timed<T> & ([T] extends [Renderable] ? Renderable & M
|
|
|
99
117
|
/** What a frame drawn at a time shows of an animation, and what that says. */
|
|
100
118
|
export interface Shown<T> {
|
|
101
119
|
readonly value: T;
|
|
102
|
-
/** The first moment, never before the time drawn at, the value may stop being this. */
|
|
103
|
-
readonly nextChange: number;
|
|
104
120
|
/** The animation the value is drawn from: the one handed in, or under reduced motion its reduced form. */
|
|
105
121
|
readonly drawn: Timed<T>;
|
|
106
122
|
/** Whether it is the animation reduced: drawn under reduced motion, changing only where content does. */
|
|
@@ -115,8 +131,8 @@ export interface Shown<T> {
|
|
|
115
131
|
* reduces every one.
|
|
116
132
|
*/
|
|
117
133
|
export declare function shownAt<T>(animation: Timed<T>, t: number, motion: Motion): Shown<T>;
|
|
118
|
-
/** The hold `shown`, drawn at `t`, is in: its animation's two answers there. */
|
|
119
|
-
export declare function holdOf(shown: Shown<unknown>, t: number): Hold;
|
|
134
|
+
/** The hold `shown`, drawn at `t`, is in: its animation's two answers there, given what its drawing said. */
|
|
135
|
+
export declare function holdOf(shown: Shown<unknown>, t: number, moves?: Moves): Hold;
|
|
120
136
|
/** The style saying a cell is in `hold`. */
|
|
121
137
|
export declare function stamp(hold: Hold): Style;
|
|
122
138
|
/**
|
|
@@ -138,17 +154,20 @@ export declare function stampFrame(segments: Iterable<Segment>, hold: Hold): Ite
|
|
|
138
154
|
export declare function frameTimeOf(options: RenderOptions): number;
|
|
139
155
|
/**
|
|
140
156
|
* An animation placed in the frame `options` draws: its value at the frame's
|
|
141
|
-
* time (`frameTimeOf`, `shownAt`), drawn by `draw
|
|
142
|
-
* with its hold there under whatever
|
|
143
|
-
* the frame (`RenderOptions.onHold`),
|
|
144
|
-
* element not yet entered — may have cells
|
|
145
|
-
* taking a row to say it in.
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
157
|
+
* time (`frameTimeOf`, `shownAt`), drawn whole by `draw` under the options it
|
|
158
|
+
* is handed, every segment then stamped with its hold there under whatever
|
|
159
|
+
* its own cells say, and the hold told to the frame (`RenderOptions.onHold`),
|
|
160
|
+
* because a frame of no cells — an element not yet entered — may have cells
|
|
161
|
+
* later, and must say when without taking a row to say it in. Drawn first,
|
|
162
|
+
* because the hold is asked with what the drawing said (`Moves`); each report
|
|
163
|
+
* goes on outward too, since a value drawn inside a placement in this value
|
|
164
|
+
* may be a part of an animation placed further out. [LAW:single-enforcer]
|
|
165
|
+
* The one placement: an animation of renderables (`placedRender`), an effect
|
|
166
|
+
* and a widget drawing one cell from an animation of its own (a caret's
|
|
167
|
+
* blink) place through it, so how a time reaches an animation and how its
|
|
168
|
+
* hold reaches the frame is written once.
|
|
150
169
|
*/
|
|
151
|
-
export declare function placed<T>(animation: Timed<T>, options: RenderOptions, draw: (value: T) => Iterable<Segment>): Iterable<Segment>;
|
|
170
|
+
export declare function placed<T>(animation: Timed<T>, options: RenderOptions, draw: (value: T, options: RenderOptions) => Iterable<Segment>): Iterable<Segment>;
|
|
152
171
|
/**
|
|
153
172
|
* An animation's face, `render`: `placed`, its value drawn as the renderable
|
|
154
173
|
* it is. A container — the library's or a user's — that draws its children
|
package/dist/core/animation.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* changes every frame, however close together they are drawn. An early
|
|
10
10
|
* answer costs a host a frame that draws what the last one did; a late one
|
|
11
11
|
* skips a change. So an animation that cannot say answers `t`, as
|
|
12
|
-
* `continuous` does.
|
|
12
|
+
* `continuous` does. An answer that depends on what the frame drew, an
|
|
13
|
+
* effect's, is told by that drawing (`Moves`). A value drawn as cells carries this answer on every
|
|
13
14
|
* cell (`Style.hold`, both ends of the hold below), so a host holding
|
|
14
15
|
* the composed frame reads it there (`Segment.nextChange`); a value that is
|
|
15
16
|
* not drawn — a number, a colour — has `nextChange` as its only way to say
|
|
@@ -76,7 +77,7 @@ import { beat, firstReaching, passAt, positiveSeconds } from "./easing.js";
|
|
|
76
77
|
import { Measurement } from "./measure.js";
|
|
77
78
|
import { isRenderable, render } from "./protocol.js";
|
|
78
79
|
import { Segment } from "./segment.js";
|
|
79
|
-
import { Style } from "./style.js";
|
|
80
|
+
import { intersection, NEVER_CHANGES, Style } from "./style.js";
|
|
80
81
|
/**
|
|
81
82
|
* What a frame drawn at `t` shows of `animation` under `motion`, and when
|
|
82
83
|
* that changes: the animation's, or under reduced motion its reduced form's
|
|
@@ -88,11 +89,11 @@ import { Style } from "./style.js";
|
|
|
88
89
|
export function shownAt(animation, t, motion) {
|
|
89
90
|
const reduced = motion.reducedMotion === true;
|
|
90
91
|
const drawn = reduced ? animation.reduced() : animation;
|
|
91
|
-
return { value: drawn.at(t),
|
|
92
|
+
return { value: drawn.at(t), drawn, reduced };
|
|
92
93
|
}
|
|
93
|
-
/** The hold `shown`, drawn at `t`, is in: its animation's two answers there. */
|
|
94
|
-
export function holdOf(shown, t) {
|
|
95
|
-
return { lastChange: shown.drawn.lastChange(t), nextChange: shown.nextChange };
|
|
94
|
+
/** The hold `shown`, drawn at `t`, is in: its animation's two answers there, given what its drawing said. */
|
|
95
|
+
export function holdOf(shown, t, moves) {
|
|
96
|
+
return { lastChange: shown.drawn.lastChange(t, moves), nextChange: shown.drawn.nextChange(t, moves) };
|
|
96
97
|
}
|
|
97
98
|
/** The style saying a cell is in `hold`. */
|
|
98
99
|
export function stamp(hold) {
|
|
@@ -127,22 +128,33 @@ function drawable(value) {
|
|
|
127
128
|
}
|
|
128
129
|
/**
|
|
129
130
|
* An animation placed in the frame `options` draws: its value at the frame's
|
|
130
|
-
* time (`frameTimeOf`, `shownAt`), drawn by `draw
|
|
131
|
-
* with its hold there under whatever
|
|
132
|
-
* the frame (`RenderOptions.onHold`),
|
|
133
|
-
* element not yet entered — may have cells
|
|
134
|
-
* taking a row to say it in.
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
131
|
+
* time (`frameTimeOf`, `shownAt`), drawn whole by `draw` under the options it
|
|
132
|
+
* is handed, every segment then stamped with its hold there under whatever
|
|
133
|
+
* its own cells say, and the hold told to the frame (`RenderOptions.onHold`),
|
|
134
|
+
* because a frame of no cells — an element not yet entered — may have cells
|
|
135
|
+
* later, and must say when without taking a row to say it in. Drawn first,
|
|
136
|
+
* because the hold is asked with what the drawing said (`Moves`); each report
|
|
137
|
+
* goes on outward too, since a value drawn inside a placement in this value
|
|
138
|
+
* may be a part of an animation placed further out. [LAW:single-enforcer]
|
|
139
|
+
* The one placement: an animation of renderables (`placedRender`), an effect
|
|
140
|
+
* and a widget drawing one cell from an animation of its own (a caret's
|
|
141
|
+
* blink) place through it, so how a time reaches an animation and how its
|
|
142
|
+
* hold reaches the frame is written once.
|
|
139
143
|
*/
|
|
140
144
|
export function* placed(animation, options, draw) {
|
|
141
145
|
const t = frameTimeOf(options);
|
|
142
146
|
const shown = shownAt(animation, t, options);
|
|
143
|
-
const
|
|
147
|
+
const said = new Map();
|
|
148
|
+
const part = (at, key) => `${at} ${key}`;
|
|
149
|
+
const onMoved = (at, key, hold) => {
|
|
150
|
+
const known = said.get(part(at, key));
|
|
151
|
+
said.set(part(at, key), known === undefined ? hold : intersection(known, hold));
|
|
152
|
+
options.onMoved?.(at, key, hold);
|
|
153
|
+
};
|
|
154
|
+
const segments = [...draw(shown.value, { ...options, onMoved })];
|
|
155
|
+
const hold = holdOf(shown, t, (at, key) => said.get(part(at, key)));
|
|
144
156
|
options.onHold?.(hold);
|
|
145
|
-
yield* stampFrame(
|
|
157
|
+
yield* stampFrame(segments, hold);
|
|
146
158
|
}
|
|
147
159
|
/**
|
|
148
160
|
* An animation's face, `render`: `placed`, its value drawn as the renderable
|
|
@@ -151,7 +163,7 @@ export function* placed(animation, options, draw) {
|
|
|
151
163
|
* the hold goes back the way the time came in. [LAW:composability]
|
|
152
164
|
*/
|
|
153
165
|
export function placedRender(animation, options) {
|
|
154
|
-
return placed(animation, options, (value) => render(drawable(value),
|
|
166
|
+
return placed(animation, options, (value, drawing) => render(drawable(value), drawing));
|
|
155
167
|
}
|
|
156
168
|
/**
|
|
157
169
|
* An animation's face, `measure`: what it shows at the frame's time, measured,
|
|
@@ -161,9 +173,16 @@ export function placedRender(animation, options) {
|
|
|
161
173
|
export function placedMeasure(animation, options) {
|
|
162
174
|
const t = frameTimeOf(options);
|
|
163
175
|
const shown = shownAt(animation, t, options);
|
|
164
|
-
options.onHold?.(holdOf(shown, t));
|
|
176
|
+
options.onHold?.(holdOf(shown, t, UNLAID));
|
|
165
177
|
return Measurement.get(options, drawable(shown.value));
|
|
166
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* What a measurement's drawing would say: held for good. An effect changes
|
|
181
|
+
* how cells look and never which exist, so nothing it does can change a
|
|
182
|
+
* layout; a combinator's own switches and a child's holds still reach the
|
|
183
|
+
* measurement. [LAW:types-are-the-program]
|
|
184
|
+
*/
|
|
185
|
+
const UNLAID = () => NEVER_CHANGES;
|
|
167
186
|
/**
|
|
168
187
|
* Every member of `source`, its own and its class's, as own properties of a
|
|
169
188
|
* new object: a method bound to `source`, a getter read off it live, a field
|
|
@@ -258,8 +277,8 @@ export const Animation = {
|
|
|
258
277
|
map(animation, f) {
|
|
259
278
|
return Animation.of({
|
|
260
279
|
at: (t) => f(animation.at(t)),
|
|
261
|
-
nextChange: (t) => animation.nextChange(t),
|
|
262
|
-
lastChange: (t) => animation.lastChange(t),
|
|
280
|
+
nextChange: (t, moves) => animation.nextChange(t, moves),
|
|
281
|
+
lastChange: (t, moves) => animation.lastChange(t, moves),
|
|
263
282
|
reduced: () => Animation.map(animation.reduced(), f),
|
|
264
283
|
});
|
|
265
284
|
},
|
|
@@ -276,8 +295,8 @@ export const Animation = {
|
|
|
276
295
|
at: (t) => animations.map((animation) => animation.at(t)),
|
|
277
296
|
// A fold, not a spread: a stagger over a table's rows is a list as long
|
|
278
297
|
// as the table, past what an engine takes as arguments.
|
|
279
|
-
nextChange: (t) => animations.reduce((soonest, animation) => Math.min(soonest, animation.nextChange(t)), Number.POSITIVE_INFINITY),
|
|
280
|
-
lastChange: (t) => animations.reduce((latest, animation) => Math.max(latest, animation.lastChange(t)), Number.NEGATIVE_INFINITY),
|
|
298
|
+
nextChange: (t, moves) => animations.reduce((soonest, animation) => Math.min(soonest, animation.nextChange(t, moves)), Number.POSITIVE_INFINITY),
|
|
299
|
+
lastChange: (t, moves) => animations.reduce((latest, animation) => Math.max(latest, animation.lastChange(t, moves)), Number.NEGATIVE_INFINITY),
|
|
281
300
|
reduced: () => Animation.all(animations.map((animation) => animation.reduced())),
|
|
282
301
|
});
|
|
283
302
|
},
|
|
@@ -296,8 +315,8 @@ export const Animation = {
|
|
|
296
315
|
onBeat(animation, beat) {
|
|
297
316
|
return Animation.of({
|
|
298
317
|
at: (t) => animation.at(beat.lastChange(t)),
|
|
299
|
-
nextChange(t) {
|
|
300
|
-
const moved = animation.nextChange(beat.lastChange(t));
|
|
318
|
+
nextChange(t, moves) {
|
|
319
|
+
const moved = animation.nextChange(beat.lastChange(t), moves);
|
|
301
320
|
if (moved === Number.POSITIVE_INFINITY)
|
|
302
321
|
return moved;
|
|
303
322
|
const end = beat.nextChange(t);
|
|
@@ -306,8 +325,13 @@ export const Animation = {
|
|
|
306
325
|
return moved <= end ? end : beat.lastChange(moved) === moved ? moved : beat.nextChange(moved);
|
|
307
326
|
},
|
|
308
327
|
// The value held now began at this hold's start at the latest: an early
|
|
309
|
-
// answer where the animation had not moved by it, which the contract
|
|
310
|
-
|
|
328
|
+
// answer where the animation had not moved by it, which the contract
|
|
329
|
+
// allows. One that always was never turned on any beat.
|
|
330
|
+
lastChange(t, moves) {
|
|
331
|
+
const began = beat.lastChange(t);
|
|
332
|
+
const moved = animation.lastChange(began, moves);
|
|
333
|
+
return moved === Number.NEGATIVE_INFINITY ? moved : began;
|
|
334
|
+
},
|
|
311
335
|
// Reduced, nothing moves between beats, so there is nothing to sample on them.
|
|
312
336
|
reduced: () => animation.reduced(),
|
|
313
337
|
});
|
|
@@ -331,19 +355,19 @@ export const Animation = {
|
|
|
331
355
|
const carried = (local) => (Number.isFinite(local) ? firstReaching(local + seconds, (x) => x - seconds >= local) : local);
|
|
332
356
|
return Animation.of({
|
|
333
357
|
at: (t) => (t - seconds >= 0 ? then.at(t - seconds) : first.at(t)),
|
|
334
|
-
nextChange(t) {
|
|
358
|
+
nextChange(t, moves) {
|
|
335
359
|
const into = t - seconds;
|
|
336
360
|
if (into < 0)
|
|
337
|
-
return Math.min(first.nextChange(t), seconds);
|
|
338
|
-
return Math.max(t, carried(then.nextChange(into)));
|
|
361
|
+
return Math.min(first.nextChange(t, moves), seconds);
|
|
362
|
+
return Math.max(t, carried(then.nextChange(into, moves)));
|
|
339
363
|
},
|
|
340
364
|
// After the switch the value became what it is at the switch or when
|
|
341
365
|
// `then`'s did since, whichever is later; before it, when `first`'s did.
|
|
342
|
-
lastChange(t) {
|
|
366
|
+
lastChange(t, moves) {
|
|
343
367
|
const into = t - seconds;
|
|
344
368
|
if (into < 0)
|
|
345
|
-
return first.lastChange(t);
|
|
346
|
-
return Math.min(t, Math.max(seconds, carried(then.lastChange(into))));
|
|
369
|
+
return first.lastChange(t, moves);
|
|
370
|
+
return Math.min(t, Math.max(seconds, carried(then.lastChange(into, moves))));
|
|
347
371
|
},
|
|
348
372
|
reduced: () => Animation.sequence(first.reduced(), seconds, then.reduced()),
|
|
349
373
|
});
|
|
@@ -381,14 +405,14 @@ export const Animation = {
|
|
|
381
405
|
const { pass, into } = passAt("Animation.repeat", t, period);
|
|
382
406
|
return nth(pass).at(into);
|
|
383
407
|
},
|
|
384
|
-
nextChange(t) {
|
|
408
|
+
nextChange(t, moves) {
|
|
385
409
|
const { pass, into } = passAt("Animation.repeat", t, period);
|
|
386
|
-
return Math.max(t, Math.min(turns.nextChange(t), carried(pass, turns.lastChange(t), nth(pass).nextChange(into))));
|
|
410
|
+
return Math.max(t, Math.min(turns.nextChange(t), carried(pass, turns.lastChange(t), nth(pass).nextChange(into, moves))));
|
|
387
411
|
},
|
|
388
|
-
lastChange(t) {
|
|
412
|
+
lastChange(t, moves) {
|
|
389
413
|
const { pass, into } = passAt("Animation.repeat", t, period);
|
|
390
414
|
const began = turns.lastChange(t);
|
|
391
|
-
return Math.min(t, Math.max(began, carried(pass, began, nth(pass).lastChange(into))));
|
|
415
|
+
return Math.min(t, Math.max(began, carried(pass, began, nth(pass).lastChange(into, moves))));
|
|
392
416
|
},
|
|
393
417
|
reduced: () => Animation.repeat(period, (n) => nth(n).reduced()),
|
|
394
418
|
});
|
package/dist/core/ansi.d.ts
CHANGED
|
@@ -21,18 +21,25 @@
|
|
|
21
21
|
*
|
|
22
22
|
* Carriage returns are the other departure, and the same argument. Rich splits
|
|
23
23
|
* lines with Python's `splitlines`, which also breaks at `\r`, so its `a\rb`
|
|
24
|
-
* is two lines. Here a line ends
|
|
25
|
-
* column, so later text overwrites earlier text
|
|
26
|
-
* `50%\r100%` is `100%`, `Downloading\rDone` is `Doneloading`, and `done\r`
|
|
27
|
-
* is still `done`. Columns are
|
|
28
|
-
*
|
|
29
|
-
* Erase in line (`\x1b[K`) is honoured for the same reason, because a redraw
|
|
24
|
+
* is two lines. Here a line ends at `\n` and the census's other line breaks, and
|
|
25
|
+
* `\r` returns to the first column, so later text overwrites earlier text cell by
|
|
26
|
+
* cell: `50%\r100%` is `100%`, `Downloading\rDone` is `Doneloading`, and `done\r`
|
|
27
|
+
* is still `done`. Columns are a terminal's cells: a wide character takes two, a
|
|
28
|
+
* combining mark none, a tab moves to the next stop over what is there, and a wide
|
|
29
|
+
* character or a tab half overwritten leaves blanks. Erase in line (`\x1b[K`) is honoured for the same reason, because a redraw
|
|
30
30
|
* is usually `\r\x1b[K` and the old text must not show through a shorter new
|
|
31
31
|
* one.
|
|
32
32
|
*
|
|
33
|
+
* Backspace is the third. Rich drops it; here it is nroff's overstrike, the
|
|
34
|
+
* adjacent `x BS x` bold and `_ BS x` underline that `man` writes, and a bare one
|
|
35
|
+
* moves back a column, so `12%\b\b\b13%` is the redraw it looks like. The bytes
|
|
36
|
+
* alone cannot tell `1\b1` the redraw from `1\b1` the bold, and `less` reads them
|
|
37
|
+
* as overstrike with no other evidence, so this does.
|
|
38
|
+
*
|
|
33
39
|
* Everything else follows Rich: malformed SGR parameters are skipped rather
|
|
34
|
-
* than refused, and every other escape is dropped
|
|
35
|
-
* emulator — any other cursor movement is
|
|
40
|
+
* than refused, and every other escape is dropped, with every control a terminal
|
|
41
|
+
* draws nothing for. It is not a terminal emulator — any other cursor movement is
|
|
42
|
+
* dropped, not performed.
|
|
36
43
|
*
|
|
37
44
|
* Tier 5 of `src/core/`: it builds `RichText`, so it sits above `text`, and
|
|
38
45
|
* `RichText` cannot offer a `fromAnsi` static without importing upward.
|
package/dist/core/ansi.js
CHANGED
|
@@ -21,48 +21,78 @@
|
|
|
21
21
|
*
|
|
22
22
|
* Carriage returns are the other departure, and the same argument. Rich splits
|
|
23
23
|
* lines with Python's `splitlines`, which also breaks at `\r`, so its `a\rb`
|
|
24
|
-
* is two lines. Here a line ends
|
|
25
|
-
* column, so later text overwrites earlier text
|
|
26
|
-
* `50%\r100%` is `100%`, `Downloading\rDone` is `Doneloading`, and `done\r`
|
|
27
|
-
* is still `done`. Columns are
|
|
28
|
-
*
|
|
29
|
-
* Erase in line (`\x1b[K`) is honoured for the same reason, because a redraw
|
|
24
|
+
* is two lines. Here a line ends at `\n` and the census's other line breaks, and
|
|
25
|
+
* `\r` returns to the first column, so later text overwrites earlier text cell by
|
|
26
|
+
* cell: `50%\r100%` is `100%`, `Downloading\rDone` is `Doneloading`, and `done\r`
|
|
27
|
+
* is still `done`. Columns are a terminal's cells: a wide character takes two, a
|
|
28
|
+
* combining mark none, a tab moves to the next stop over what is there, and a wide
|
|
29
|
+
* character or a tab half overwritten leaves blanks. Erase in line (`\x1b[K`) is honoured for the same reason, because a redraw
|
|
30
30
|
* is usually `\r\x1b[K` and the old text must not show through a shorter new
|
|
31
31
|
* one.
|
|
32
32
|
*
|
|
33
|
+
* Backspace is the third. Rich drops it; here it is nroff's overstrike, the
|
|
34
|
+
* adjacent `x BS x` bold and `_ BS x` underline that `man` writes, and a bare one
|
|
35
|
+
* moves back a column, so `12%\b\b\b13%` is the redraw it looks like. The bytes
|
|
36
|
+
* alone cannot tell `1\b1` the redraw from `1\b1` the bold, and `less` reads them
|
|
37
|
+
* as overstrike with no other evidence, so this does.
|
|
38
|
+
*
|
|
33
39
|
* Everything else follows Rich: malformed SGR parameters are skipped rather
|
|
34
|
-
* than refused, and every other escape is dropped
|
|
35
|
-
* emulator — any other cursor movement is
|
|
40
|
+
* than refused, and every other escape is dropped, with every control a terminal
|
|
41
|
+
* draws nothing for. It is not a terminal emulator — any other cursor movement is
|
|
42
|
+
* dropped, not performed.
|
|
36
43
|
*
|
|
37
44
|
* Tier 5 of `src/core/`: it builds `RichText`, so it sits above `text`, and
|
|
38
45
|
* `RichText` cannot offer a `fromAnsi` static without importing upward.
|
|
39
46
|
*/
|
|
47
|
+
import { cellLen, graphemes } from "./cells.js";
|
|
40
48
|
import { ColorSpec } from "./color.js";
|
|
49
|
+
import { controlClass } from "./control-codes.js";
|
|
41
50
|
import { osc8Sequences } from "./osc8.js";
|
|
42
51
|
import { ATTRIBUTE_NAMES, ATTRIBUTE_SGR, NULL_STYLE, Style } from "./style.js";
|
|
43
52
|
import { RichText } from "./text.js";
|
|
53
|
+
const BOLD = new Style({ bold: true });
|
|
54
|
+
const UNDERLINED = new Style({ underline: true });
|
|
55
|
+
const BOLD_UNDERLINED = BOLD.add(UNDERLINED);
|
|
56
|
+
const STRING_ESCAPE = String.raw `\x1b[\]P_^X][^\n]*?(?:\x07|\x1b\\|\x9c|\n|$)`;
|
|
44
57
|
/**
|
|
45
58
|
* Every escape but OSC 8, which `osc8Sequences` reads before this runs. In
|
|
46
|
-
* order: a carriage return; an SGR sequence (
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
59
|
+
* order: a carriage return; an SGR sequence (`sgr`, its parameters — a private
|
|
60
|
+
* marker such as the `>` of `\x1b[>4;2m` makes it some other CSI); erase in line
|
|
61
|
+
* (`mode`); any other CSI sequence; any other string escape — OSC, DCS, APC, PM,
|
|
62
|
+
* SOS — run to the terminators OSC 8 accepts or cut off by the end of the line;
|
|
63
|
+
* any other escape, ECMA-48's intermediates and one final byte (`\x1b(B`,
|
|
64
|
+
* `\x1b)0`, `\x1b#8`, `\x1bc`); a character struck over itself (`struck`), over an
|
|
65
|
+
* underscore first or not (`underscore`); a character struck over an underscore
|
|
66
|
+
* alone (`underlined`); a backspace; and every control a line may not hold or a
|
|
67
|
+
* terminal draws nothing for. The silent ones are the two "any other" escapes and
|
|
68
|
+
* that last class.
|
|
53
69
|
*/
|
|
54
|
-
const
|
|
70
|
+
const ESCAPES = [
|
|
71
|
+
String.raw `\r|\x1b\[(?<sgr>[0-9;:]*)m|\x1b\[(?<mode>[012]?)K|\x1b\[[0-?]*[ -/]*[@-~]|${STRING_ESCAPE}|\x1b[ -/]*[0-~]`,
|
|
72
|
+
String.raw `(?<underscore>_\x08)?(?<struck>\P{Cc})(?:\x08\k<struck>)+|_\x08(?<underlined>\P{Cc})|\x08`,
|
|
73
|
+
controlClass((disposition) => disposition !== "keep" && disposition !== "withheld"),
|
|
74
|
+
].join("|");
|
|
75
|
+
const escapes = () => new RegExp(ESCAPES, "gu");
|
|
76
|
+
// A string escape goes first so a line break in its payload stays in the payload.
|
|
77
|
+
const lineBreaks = () => new RegExp(`${STRING_ESCAPE}|${controlClass((disposition) => disposition === "line-break")}`, "gu");
|
|
55
78
|
function* escapeTokens(bytes) {
|
|
56
79
|
let at = 0;
|
|
57
80
|
for (const match of bytes.matchAll(escapes())) {
|
|
81
|
+
const { sgr, mode, underscore, struck, underlined } = match.groups;
|
|
58
82
|
if (match.index > at)
|
|
59
83
|
yield { kind: "text", text: bytes.slice(at, match.index) };
|
|
60
84
|
if (match[0] === "\r")
|
|
61
85
|
yield { kind: "return" };
|
|
62
|
-
if (
|
|
63
|
-
yield { kind: "sgr", params:
|
|
64
|
-
if (
|
|
65
|
-
yield { kind: "erase", mode: (
|
|
86
|
+
if (sgr !== undefined)
|
|
87
|
+
yield { kind: "sgr", params: sgr };
|
|
88
|
+
if (mode !== undefined)
|
|
89
|
+
yield { kind: "erase", mode: (mode || "0") };
|
|
90
|
+
if (struck !== undefined)
|
|
91
|
+
yield { kind: "overstrike", character: struck, emphasis: underscore === undefined ? BOLD : BOLD_UNDERLINED };
|
|
92
|
+
if (underlined !== undefined)
|
|
93
|
+
yield { kind: "overstrike", character: underlined, emphasis: UNDERLINED };
|
|
94
|
+
if (match[0] === "\b")
|
|
95
|
+
yield { kind: "backspace" };
|
|
66
96
|
at = match.index + match[0].length;
|
|
67
97
|
}
|
|
68
98
|
if (at < bytes.length)
|
|
@@ -153,11 +183,52 @@ function applySgr(style, params) {
|
|
|
153
183
|
result = (SGR_OPS.get(code) ?? identity)(result, codes);
|
|
154
184
|
return result;
|
|
155
185
|
}
|
|
186
|
+
const ORIGIN = ["", NULL_STYLE];
|
|
156
187
|
const BLANK = [" ", NULL_STYLE];
|
|
188
|
+
const TAB_STOP = 8;
|
|
189
|
+
/** The column holding the cluster drawn across `column`. */
|
|
190
|
+
function leadOf(cells, column) {
|
|
191
|
+
let at = column;
|
|
192
|
+
while (at > 0 && cells[at][0] === "")
|
|
193
|
+
at -= 1;
|
|
194
|
+
return at;
|
|
195
|
+
}
|
|
196
|
+
/** A cluster across the edge before `column` goes blank, as on a terminal. */
|
|
197
|
+
function splitWide(cells, column) {
|
|
198
|
+
if (cells[column]?.[0] !== "")
|
|
199
|
+
return;
|
|
200
|
+
const lead = leadOf(cells, column);
|
|
201
|
+
for (let at = lead; at === lead || cells[at]?.[0] === ""; at += 1)
|
|
202
|
+
cells[at] = BLANK;
|
|
203
|
+
}
|
|
204
|
+
/** `cluster` drawn at `column`, and the columns the cursor moves. */
|
|
205
|
+
function draw(cells, column, cluster, style) {
|
|
206
|
+
const width = cluster === "\t" ? TAB_STOP - ((column - 1) % TAB_STOP) : cellLen(cluster);
|
|
207
|
+
if (width === 0) {
|
|
208
|
+
const lead = leadOf(cells, column - 1);
|
|
209
|
+
cells[lead] = [cells[lead][0] + cluster, cells[lead][1]];
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
if (cluster === "\t" && column < cells.length) {
|
|
213
|
+
while (cells.length < column + width)
|
|
214
|
+
cells.push(BLANK);
|
|
215
|
+
return width;
|
|
216
|
+
}
|
|
217
|
+
splitWide(cells, column);
|
|
218
|
+
splitWide(cells, column + width);
|
|
219
|
+
cells[column] = [cells[0][0] + cluster, style];
|
|
220
|
+
cells[0] = ORIGIN;
|
|
221
|
+
for (let at = 1; at < width; at += 1)
|
|
222
|
+
cells[column + at] = ["", style];
|
|
223
|
+
return width;
|
|
224
|
+
}
|
|
157
225
|
/** Erase in line: the cells before the cursor go blank, the ones from it on go. */
|
|
158
226
|
function erase(cells, column, mode) {
|
|
227
|
+
splitWide(cells, column);
|
|
228
|
+
splitWide(cells, column + 1);
|
|
229
|
+
cells[0] = ORIGIN;
|
|
159
230
|
if (mode !== "0")
|
|
160
|
-
cells.fill(BLANK,
|
|
231
|
+
cells.fill(BLANK, 1, Math.min(column + 1, cells.length));
|
|
161
232
|
if (mode !== "1")
|
|
162
233
|
cells.length = Math.min(column, cells.length);
|
|
163
234
|
}
|
|
@@ -173,25 +244,32 @@ export class AnsiDecoder {
|
|
|
173
244
|
link = undefined;
|
|
174
245
|
/** One `RichText` per line of `ansi`; a final newline ends a line rather than starting one. */
|
|
175
246
|
decode(ansi) {
|
|
176
|
-
|
|
247
|
+
const lined = ansi.replace(lineBreaks(), (found) => (found.startsWith("\x1b") ? found : "\n"));
|
|
248
|
+
return (lined.match(/[^\n]*\n|[^\n]+/g) ?? []).map((line) => this.decodeLine(line.replace(/\r?\n$/, "")));
|
|
177
249
|
}
|
|
178
250
|
/**
|
|
179
251
|
* One line of output, holding no `\n`, written the way a terminal writes
|
|
180
252
|
* it: `\r` returns to the first column, and text overwrites from there.
|
|
181
253
|
*/
|
|
182
254
|
decodeLine(line) {
|
|
183
|
-
const cells = [];
|
|
184
|
-
let column =
|
|
255
|
+
const cells = [ORIGIN];
|
|
256
|
+
let column = 1;
|
|
185
257
|
for (const token of tokens(line)) {
|
|
186
258
|
switch (token.kind) {
|
|
187
259
|
case "text": {
|
|
188
260
|
const style = this.sgr.withLink(this.link);
|
|
189
|
-
for (const
|
|
190
|
-
|
|
261
|
+
for (const cluster of graphemes(token.text))
|
|
262
|
+
column += draw(cells, column, cluster, style);
|
|
191
263
|
break;
|
|
192
264
|
}
|
|
265
|
+
case "overstrike":
|
|
266
|
+
column += draw(cells, column, token.character, this.sgr.add(token.emphasis).withLink(this.link));
|
|
267
|
+
break;
|
|
193
268
|
case "return":
|
|
194
|
-
column =
|
|
269
|
+
column = 1;
|
|
270
|
+
break;
|
|
271
|
+
case "backspace":
|
|
272
|
+
column = Math.max(1, column - 1);
|
|
195
273
|
break;
|
|
196
274
|
case "erase":
|
|
197
275
|
erase(cells, column, token.mode);
|
|
@@ -205,7 +283,7 @@ export class AnsiDecoder {
|
|
|
205
283
|
}
|
|
206
284
|
}
|
|
207
285
|
const runs = [];
|
|
208
|
-
for (const [char, style] of cells) {
|
|
286
|
+
for (const [char, style] of cells.filter(([char]) => char !== "")) {
|
|
209
287
|
const last = runs.at(-1);
|
|
210
288
|
if (last?.[1].equals(style))
|
|
211
289
|
last[0] += char;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Unicode properties UAX #9 and Arabic joining read. Generated by
|
|
3
|
+
* scripts/bidi-data.py from the Unicode 17.0.0 Character Database; regenerate
|
|
4
|
+
* rather than edit.
|
|
5
|
+
*/
|
|
6
|
+
/** The bidi classes other than L, in the order `CLASS_RANGES` numbers them. */
|
|
7
|
+
export declare const BIDI_CLASSES: readonly ["R", "AL", "EN", "ES", "ET", "AN", "CS", "NSM", "BN", "B", "S", "WS", "ON", "LRE", "LRO", "RLE", "RLO", "PDF", "LRI", "RLI", "FSI", "PDI"];
|
|
8
|
+
/** The joining types other than U, in the order `JOINING_RANGES` numbers them. */
|
|
9
|
+
export declare const JOINING_TYPES: readonly ["R", "L", "D", "C", "T"];
|
|
10
|
+
export declare const CLASS_RANGES: readonly (readonly [number, number, number])[];
|
|
11
|
+
export declare const JOINING_RANGES: readonly (readonly [number, number, number])[];
|
|
12
|
+
export declare const BRACKET_PAIRS: readonly (readonly [number, number])[];
|
|
13
|
+
export declare const MIRRORS: readonly (readonly [number, number])[];
|
|
14
|
+
export declare const PRESENTATION_FORMS: readonly (readonly [number, number, number, number, number])[];
|