@promptctl/rich-js 0.27.0 → 0.29.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 +7 -6
- package/THIRD-PARTY-NOTICES +42 -0
- package/dist/core/animation.d.ts +65 -46
- package/dist/core/animation.js +91 -67
- package/dist/core/ansi.d.ts +19 -12
- package/dist/core/ansi.js +114 -36
- 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 +94 -6
- package/dist/core/clock.d.ts +1 -1
- package/dist/core/color.d.ts +56 -57
- package/dist/core/color.js +79 -81
- package/dist/core/console.d.ts +24 -7
- package/dist/core/console.js +27 -8
- package/dist/core/control-codes.d.ts +61 -0
- package/dist/core/control-codes.js +157 -0
- package/dist/core/easing.d.ts +40 -40
- package/dist/core/easing.js +40 -40
- package/dist/core/env.d.ts +6 -0
- package/dist/core/env.js +9 -1
- package/dist/core/export-html.js +5 -4
- package/dist/core/export-lines.d.ts +13 -11
- package/dist/core/export-lines.js +19 -15
- package/dist/core/export-svg.d.ts +3 -3
- package/dist/core/export-svg.js +10 -9
- package/dist/core/json.js +9 -2
- package/dist/core/markup.js +5 -4
- package/dist/core/memo.d.ts +1 -1
- package/dist/core/memo.js +1 -1
- package/dist/core/oklch.d.ts +14 -14
- package/dist/core/oklch.js +10 -10
- 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/paint.d.ts +9 -9
- package/dist/core/paint.js +3 -3
- package/dist/core/pretty.d.ts +1 -1
- package/dist/core/pretty.js +23 -19
- package/dist/core/protocol.d.ts +47 -26
- package/dist/core/protocol.js +31 -23
- package/dist/core/render.d.ts +19 -14
- package/dist/core/render.js +30 -17
- package/dist/core/seal.d.ts +26 -0
- package/dist/core/seal.js +75 -0
- package/dist/core/segment.d.ts +12 -4
- package/dist/core/segment.js +16 -6
- package/dist/core/strip.d.ts +83 -83
- package/dist/core/strip.js +70 -70
- package/dist/core/style.d.ts +46 -18
- package/dist/core/style.js +92 -56
- package/dist/core/text-order.d.ts +51 -0
- package/dist/core/text-order.js +50 -0
- package/dist/core/text.d.ts +12 -2
- package/dist/core/text.js +136 -90
- package/dist/core/timeline.d.ts +5 -5
- package/dist/core/timeline.js +11 -11
- package/dist/core/tween.d.ts +6 -6
- package/dist/core/tween.js +10 -10
- package/dist/core/view.d.ts +5 -5
- package/dist/core/view.js +15 -14
- package/dist/core/wrap.d.ts +24 -6
- package/dist/core/wrap.js +82 -16
- package/dist/host/app.d.ts +50 -9
- package/dist/host/app.js +120 -15
- package/dist/host/host-environment.d.ts +2 -2
- package/dist/host/host-environment.js +2 -2
- package/dist/host/index.d.ts +3 -2
- package/dist/host/index.js +1 -0
- package/dist/host/input.d.ts +42 -9
- package/dist/host/input.js +91 -7
- package/dist/host/terminal-colors.d.ts +18 -0
- package/dist/host/terminal-colors.js +46 -0
- package/dist/host/terminal-host.d.ts +4 -3
- package/dist/host/terminal-host.js +1 -1
- package/dist/index.d.ts +17 -16
- package/dist/index.js +11 -11
- package/dist/node/prompt.d.ts +1 -1
- package/dist/node/prompt.js +1 -1
- package/dist/node/terminal-host.d.ts +1 -1
- package/dist/node/traceback.js +2 -2
- package/dist/renderables/change.d.ts +1 -3
- package/dist/renderables/change.js +6 -8
- package/dist/renderables/effect.d.ts +88 -87
- package/dist/renderables/effect.js +124 -114
- package/dist/renderables/effects.d.ts +105 -76
- package/dist/renderables/effects.js +309 -176
- package/dist/renderables/embed.d.ts +1 -1
- package/dist/renderables/embed.js +2 -2
- package/dist/renderables/flexStrip.d.ts +7 -7
- package/dist/renderables/flexStrip.js +15 -15
- package/dist/renderables/frames.d.ts +7 -16
- package/dist/renderables/frames.js +12 -27
- package/dist/renderables/glyph-effect.d.ts +22 -23
- package/dist/renderables/glyph-effect.js +43 -41
- package/dist/renderables/glyph-effects.d.ts +33 -14
- package/dist/renderables/glyph-effects.js +90 -22
- package/dist/renderables/html-entities.d.ts +1 -1
- package/dist/renderables/html-entities.js +1 -1
- package/dist/renderables/lifecycle.d.ts +8 -10
- package/dist/renderables/lifecycle.js +17 -18
- package/dist/renderables/live.d.ts +2 -2
- package/dist/renderables/live.js +7 -7
- package/dist/renderables/markdown-parse.js +3 -3
- package/dist/renderables/markdown.js +4 -2
- package/dist/renderables/panel.js +7 -5
- package/dist/renderables/progress.d.ts +1 -1
- package/dist/renderables/progress.js +1 -1
- package/dist/renderables/progressBar.d.ts +3 -3
- package/dist/renderables/progressBar.js +21 -18
- package/dist/renderables/prompt.d.ts +1 -1
- package/dist/renderables/scroll.d.ts +1 -1
- package/dist/renderables/scroll.js +3 -3
- package/dist/renderables/spinner.d.ts +4 -4
- package/dist/renderables/spinner.js +10 -10
- package/dist/renderables/syntax.d.ts +2 -2
- package/dist/renderables/syntax.js +9 -4
- package/dist/renderables/table.js +5 -4
- package/dist/renderables/traceback.d.ts +1 -1
- package/dist/renderables/traceback.js +1 -1
- package/dist/renderables/tree.js +3 -3
- package/dist/template-bindings/animation-funcs.d.ts +60 -29
- package/dist/template-bindings/animation-funcs.js +126 -43
- package/dist/template-bindings/color-funcs.d.ts +14 -14
- package/dist/template-bindings/color-funcs.js +25 -25
- package/dist/template-bindings/index.d.ts +16 -14
- package/dist/template-bindings/index.js +17 -14
- package/dist/template-bindings/palette-funcs.d.ts +2 -2
- package/dist/template-bindings/palette-funcs.js +4 -4
- package/dist/template-bindings/style-funcs.d.ts +5 -5
- package/dist/template-bindings/style-funcs.js +16 -16
- package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
- package/dist/themes/{transpose.js → adjust.js} +28 -28
- package/dist/themes/buildPalette.d.ts +6 -5
- package/dist/themes/buildPalette.js +22 -22
- package/dist/themes/colorMath.d.ts +16 -16
- package/dist/themes/colorMath.js +32 -32
- package/dist/themes/data/ansi-tables.d.ts +2 -2
- package/dist/themes/data/ansi-tables.js +2 -2
- package/dist/themes/data/index.js +1 -4
- package/dist/themes/data/textual-ansi.js +0 -143
- package/dist/themes/data/types.d.ts +4 -4
- package/dist/themes/data/types.js +2 -2
- package/dist/themes/palette.d.ts +12 -12
- package/dist/themes/palette.js +16 -16
- package/dist/themes/ramp.d.ts +17 -17
- package/dist/themes/ramp.js +12 -12
- package/dist/themes/registry.d.ts +6 -8
- package/dist/themes/registry.js +6 -8
- package/dist/themes/terminalThemes.d.ts +4 -11
- package/dist/themes/terminalThemes.js +31 -47
- package/dist/widgets/button.d.ts +3 -3
- package/dist/widgets/button.js +8 -8
- package/dist/widgets/checkbox.d.ts +2 -2
- package/dist/widgets/checkbox.js +4 -4
- package/dist/widgets/dropdown.d.ts +3 -3
- package/dist/widgets/dropdown.js +7 -5
- package/dist/widgets/event-router.d.ts +6 -6
- package/dist/widgets/event-router.js +2 -2
- package/dist/widgets/focus-manager.d.ts +3 -3
- package/dist/widgets/focus-manager.js +3 -3
- package/dist/widgets/index.d.ts +2 -2
- package/dist/widgets/index.js +1 -1
- package/dist/widgets/ink.d.ts +3 -3
- package/dist/widgets/ink.js +4 -4
- package/dist/widgets/slider.d.ts +2 -2
- package/dist/widgets/static-item.d.ts +2 -2
- package/dist/widgets/text-input.d.ts +2 -2
- package/dist/widgets/text-input.js +5 -5
- package/dist/widgets/themed-widget.js +4 -4
- package/dist/widgets/toggle.d.ts +4 -4
- package/dist/widgets/toggle.js +6 -6
- package/dist/widgets/types.d.ts +6 -6
- package/dist/widgets/types.js +2 -2
- package/dist/widgets/widget-app.d.ts +10 -10
- package/dist/widgets/widget-app.js +8 -8
- package/dist/widgets/widget-base.d.ts +2 -2
- package/package.json +5 -4
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
* they are gone.
|
|
64
64
|
*/
|
|
65
65
|
import { resolveColorRef } from "../themes/colorRef.js";
|
|
66
|
-
import {
|
|
66
|
+
import { parseEasing } from "../core/easing.js";
|
|
67
67
|
import { ColorRamp } from "../themes/ramp.js";
|
|
68
68
|
import { computable } from "./color-funcs.js";
|
|
69
69
|
/**
|
|
@@ -97,7 +97,7 @@ function colorStops(tail, palette) {
|
|
|
97
97
|
*
|
|
98
98
|
* `color` resolves a palette variable name to its hex string — `#RRGGBB`, or
|
|
99
99
|
* `#00000000` for a theme's "no background", which `bg` paints as no
|
|
100
|
-
* background and the
|
|
100
|
+
* background and the color functions refuse — and passes
|
|
101
101
|
* an already-literal color through unchanged. That second half is not a
|
|
102
102
|
* convenience — it makes `color` **idempotent**, which is what lets consumers
|
|
103
103
|
* apply it unconditionally to any author-written color string without first
|
|
@@ -111,7 +111,7 @@ function colorStops(tail, palette) {
|
|
|
111
111
|
* @example
|
|
112
112
|
* ```ts
|
|
113
113
|
* const engine = createEngine({
|
|
114
|
-
* fromString: (s) => new RichText(s),
|
|
114
|
+
* fromString: (s) => new RichText(s), isT: (v) => v instanceof RichText,
|
|
115
115
|
* toString: (rt) => rt.plain,
|
|
116
116
|
* funcs: {
|
|
117
117
|
* ...richTextFuncs(),
|
|
@@ -135,7 +135,7 @@ export function paletteFuncs(getPalette) {
|
|
|
135
135
|
// value, the ease, and one stop, so the gate refuses a stopless call.
|
|
136
136
|
// [LAW:types-are-the-program]
|
|
137
137
|
const rampFunc = {
|
|
138
|
-
fn: ((value, ease, ...tail) => new ColorRamp(
|
|
138
|
+
fn: ((value, ease, ...tail) => new ColorRamp(parseEasing(ease), colorStops(tail, getPalette())).at(value)
|
|
139
139
|
.hex),
|
|
140
140
|
argTypes: ["float", "string"],
|
|
141
141
|
arity: { kind: "alternating", minimum: 4 },
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* [LAW:one-source-of-truth] The function inventory below mirrors the
|
|
5
5
|
* string-syntax style vocabulary documented in `docs/style.md` — the two
|
|
6
|
-
*
|
|
6
|
+
* color slots (`fg`/`bg`), text attributes (positive + negated), short
|
|
7
7
|
* aliases, and the hyperlink. Each registration is a templating-time analogue
|
|
8
8
|
* of a piece of `Style.parse`, so a template fragment composed by these
|
|
9
9
|
* functions round-trips through `Style` without semantic drift.
|
|
@@ -12,17 +12,17 @@
|
|
|
12
12
|
* shape: child `RichText` in, `RichText` out. The styling difference
|
|
13
13
|
* lives in a captured `Style` value (or constructor closure), not in
|
|
14
14
|
* branches inside a single dispatch. That is why this file is mostly
|
|
15
|
-
* factories — the data (the
|
|
15
|
+
* factories — the data (the color, the attribute name) is the
|
|
16
16
|
* variability; the operation is fixed.
|
|
17
17
|
*/
|
|
18
18
|
import type { FuncMap } from "@promptctl/go-template-js";
|
|
19
19
|
/**
|
|
20
|
-
* Text-styling registrations: the two
|
|
20
|
+
* Text-styling registrations: the two color sinks (`fg`, `bg`), text
|
|
21
21
|
* attributes (canonical names, short aliases, and `not_*` negations), the
|
|
22
22
|
* hyperlink cell-splitter (`link`), and the multi-attribute `style` spec.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
* math, `paletteFuncs()` for naming a theme
|
|
24
|
+
* Colors themselves come from elsewhere: `colorFuncs()` for the palette-free
|
|
25
|
+
* math, `paletteFuncs()` for naming a theme color. This module only paints.
|
|
26
26
|
* [LAW:one-way-deps] — nothing here imports a palette.
|
|
27
27
|
*/
|
|
28
28
|
export declare function richTextStyleFuncs(): FuncMap;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* [LAW:one-source-of-truth] The function inventory below mirrors the
|
|
5
5
|
* string-syntax style vocabulary documented in `docs/style.md` — the two
|
|
6
|
-
*
|
|
6
|
+
* color slots (`fg`/`bg`), text attributes (positive + negated), short
|
|
7
7
|
* aliases, and the hyperlink. Each registration is a templating-time analogue
|
|
8
8
|
* of a piece of `Style.parse`, so a template fragment composed by these
|
|
9
9
|
* functions round-trips through `Style` without semantic drift.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* shape: child `RichText` in, `RichText` out. The styling difference
|
|
13
13
|
* lives in a captured `Style` value (or constructor closure), not in
|
|
14
14
|
* branches inside a single dispatch. That is why this file is mostly
|
|
15
|
-
* factories — the data (the
|
|
15
|
+
* factories — the data (the color, the attribute name) is the
|
|
16
16
|
* variability; the operation is fixed.
|
|
17
17
|
*/
|
|
18
18
|
import { Style, ATTRIBUTE_NAMES, ATTRIBUTE_SHORT_ALIASES, } from "../core/style.js";
|
|
@@ -26,26 +26,26 @@ function attrFunc(style) {
|
|
|
26
26
|
returnType: "T",
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
// ---
|
|
29
|
+
// --- Color sinks ---
|
|
30
30
|
//
|
|
31
|
-
// `fg` and `bg` are the only two
|
|
32
|
-
// terminal step of the
|
|
31
|
+
// `fg` and `bg` are the only two color-applying functions, and they are the
|
|
32
|
+
// terminal step of the color pipeline: `color` names a color, the functions
|
|
33
33
|
// in `color-funcs.ts` transform it, these paint it onto text.
|
|
34
34
|
//
|
|
35
35
|
// [LAW:composability] They replace five separate families — one function per
|
|
36
|
-
// ANSI
|
|
37
|
-
// and `on` (background). Every one of those encoded *which
|
|
36
|
+
// ANSI color name (`red`, `bright_blue`, …), `hex`, `rgb`, `color` (256-index),
|
|
37
|
+
// and `on` (background). Every one of those encoded *which color* in the
|
|
38
38
|
// function's identity, so the vocabulary could only grow by adding names, and
|
|
39
|
-
// a
|
|
40
|
-
// is an argument, so the sink admits every
|
|
39
|
+
// a color computed at render time could not be applied at all. Here the color
|
|
40
|
+
// is an argument, so the sink admits every color that exists and every color
|
|
41
41
|
// that will ever exist. Two functions, unbounded reach.
|
|
42
42
|
//
|
|
43
43
|
// [LAW:types-are-the-program] The slot accepts the full `ColorSpec.parse`
|
|
44
|
-
// vocabulary, which is wider than the hex the
|
|
45
|
-
// width is deliberate, not laxity. `#7aa2f7` is a *concrete*
|
|
44
|
+
// vocabulary, which is wider than the hex the color math produces — and that
|
|
45
|
+
// width is deliberate, not laxity. `#7aa2f7` is a *concrete* color; `"red"`
|
|
46
46
|
// and `"color(42)"` are *symbolic* ones the terminal resolves against its own
|
|
47
|
-
// theme. Only concrete
|
|
48
|
-
//
|
|
47
|
+
// theme. Only concrete colors can be darkened or blended, which is why the
|
|
48
|
+
// color-math functions take hex alone; but both kinds can be painted, so the
|
|
49
49
|
// sink takes the union. The type of each slot is exactly the set of values that
|
|
50
50
|
// slot can mean something for.
|
|
51
51
|
function colorSinkFunc(slot) {
|
|
@@ -138,12 +138,12 @@ const linkFunc = {
|
|
|
138
138
|
};
|
|
139
139
|
// --- Public assembly ---
|
|
140
140
|
/**
|
|
141
|
-
* Text-styling registrations: the two
|
|
141
|
+
* Text-styling registrations: the two color sinks (`fg`, `bg`), text
|
|
142
142
|
* attributes (canonical names, short aliases, and `not_*` negations), the
|
|
143
143
|
* hyperlink cell-splitter (`link`), and the multi-attribute `style` spec.
|
|
144
144
|
*
|
|
145
|
-
*
|
|
146
|
-
* math, `paletteFuncs()` for naming a theme
|
|
145
|
+
* Colors themselves come from elsewhere: `colorFuncs()` for the palette-free
|
|
146
|
+
* math, `paletteFuncs()` for naming a theme color. This module only paints.
|
|
147
147
|
* [LAW:one-way-deps] — nothing here imports a palette.
|
|
148
148
|
*/
|
|
149
149
|
export function richTextStyleFuncs() {
|
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Adjust a Palette to a new "key" — analogous to adjusting a melody.
|
|
3
3
|
*
|
|
4
4
|
* melody / chord progression :: Palette (relationships between colors)
|
|
5
|
-
* key (signature) ::
|
|
6
|
-
* "in C major" / "in D…" :: the resulting
|
|
5
|
+
* key (signature) :: ColorAdjustment (hue / chroma / lightness deltas)
|
|
6
|
+
* "in C major" / "in D…" :: the resulting adjusted Palette
|
|
7
7
|
*
|
|
8
8
|
* Because OKLCH is perceptually uniform, "+30° hue" looks like a
|
|
9
9
|
* consistent jump everywhere on the color wheel — the way a perfect-fifth
|
|
10
|
-
* interval sounds the same in every musical key.
|
|
11
|
-
* under composition: `
|
|
12
|
-
* colors as a single
|
|
10
|
+
* interval sounds the same in every musical key. Adjustment is closed
|
|
11
|
+
* under composition: `adjust(adjust(p, k1), k2)` produces the same
|
|
12
|
+
* colors as a single adjust with the combined deltas, modulo round-trip
|
|
13
13
|
* quantization.
|
|
14
14
|
*
|
|
15
15
|
* [LAW:dataflow-not-control-flow] A single uniform per-color transform
|
|
16
16
|
* runs for every var in the palette. Anchor protection selects *which*
|
|
17
|
-
* `
|
|
17
|
+
* `ColorAdjustment` to apply (data), not *whether* to apply one (branch).
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] Anchor classification lives only in
|
|
20
|
-
* `
|
|
20
|
+
* `HUE_LOCKED_ROOTS` below. Every variant of a semantic root carries the root
|
|
21
21
|
* as its first hyphen segment (`error`, `error-darken-1`, `error-muted`, ...)
|
|
22
22
|
* or after a `text-` or `on-` that draws on it (`text-error`, `on-error`), so
|
|
23
23
|
* one set covers the whole family.
|
|
24
24
|
*
|
|
25
|
-
* [LAW:one-way-deps] Imports flow `core/oklch → themes/
|
|
25
|
+
* [LAW:one-way-deps] Imports flow `core/oklch → themes/adjust`;
|
|
26
26
|
* nothing in core/ depends back on this file.
|
|
27
27
|
*/
|
|
28
|
-
import { type
|
|
28
|
+
import { type ColorAdjustment } from "../core/oklch.js";
|
|
29
29
|
import { Palette } from "./palette.js";
|
|
30
30
|
/**
|
|
31
|
-
* Semantic roots whose hue is locked under
|
|
31
|
+
* Semantic roots whose hue is locked under adjustment. `error` must
|
|
32
32
|
* look red-ish, `success` green-ish, `warning` amber-ish — rotating the
|
|
33
33
|
* hue would make the UI lie about meaning. Lightness and chroma *still*
|
|
34
34
|
* transform for these roles, so they invert correctly during dark↔light
|
|
35
35
|
* flips and respond to chroma scaling alongside everything else.
|
|
36
36
|
*/
|
|
37
|
-
export declare const
|
|
37
|
+
export declare const HUE_LOCKED_ROOTS: ReadonlySet<string>;
|
|
38
38
|
/**
|
|
39
|
-
* Whether a palette var's hue is locked under
|
|
40
|
-
* predicate used by `
|
|
39
|
+
* Whether a palette var's hue is locked under adjustment. The single
|
|
40
|
+
* predicate used by `adjustPalette`. Exported so callers building
|
|
41
41
|
* higher-level theme machinery can stay consistent with the locking rule.
|
|
42
42
|
*/
|
|
43
|
-
export declare function
|
|
43
|
+
export declare function isHueLocked(varName: string): boolean;
|
|
44
44
|
/**
|
|
45
|
-
* Return a new `Palette` whose colors are the
|
|
45
|
+
* Return a new `Palette` whose colors are the adjustment of `palette`'s
|
|
46
46
|
* colors by `key`. Pure. Identity (`IDENTITY`) returns a Palette with byte-exact
|
|
47
47
|
* colors — fast-pathed so identity does not pay the sRGB↔OKLCH round-trip
|
|
48
48
|
* quantization cost.
|
|
@@ -57,12 +57,12 @@ export declare function isAnchored(varName: string): boolean;
|
|
|
57
57
|
* The identity fast-path preserves the source `dark` flag verbatim.
|
|
58
58
|
*
|
|
59
59
|
* @param name Optional override for the resulting palette name. Defaults
|
|
60
|
-
* to the source palette's name. Callers building a family of
|
|
60
|
+
* to the source palette's name. Callers building a family of adjusted
|
|
61
61
|
* palettes (e.g. "gruvbox +60°") supply their own.
|
|
62
62
|
*/
|
|
63
|
-
export declare function
|
|
63
|
+
export declare function adjustPalette(palette: Palette, key: ColorAdjustment, name?: string): Palette;
|
|
64
64
|
/**
|
|
65
|
-
* Build the `
|
|
65
|
+
* Build the `ColorAdjustment` that rotates `palette` so its *tonic* var lands on
|
|
66
66
|
* `targetHueDeg`. The musical operation directly: a key is the set of
|
|
67
67
|
* intervals from the tonic, so "play this theme in the key of <hue>" means
|
|
68
68
|
* "shift every color by exactly the interval that carries the tonic's
|
|
@@ -70,13 +70,13 @@ export declare function transposePalette(palette: Palette, key: ThemeKey, name?:
|
|
|
70
70
|
*
|
|
71
71
|
* Returns a hue-only key (chroma and lightness untouched). Callers that also
|
|
72
72
|
* want to scale chroma or shift lightness spread their own axes over the
|
|
73
|
-
* result — those are independent
|
|
73
|
+
* result — those are independent adjustment dimensions, not part of
|
|
74
74
|
* choosing the key. [LAW:one-type-per-behavior] a degree-shift key and a
|
|
75
75
|
* root-note key are the *same* transform; this is just a second constructor
|
|
76
|
-
* for it, so `
|
|
76
|
+
* for it, so `adjustPalette` stays untouched.
|
|
77
77
|
*
|
|
78
78
|
* Throws if `tonicVar` is absent — the interval has no anchor to measure
|
|
79
79
|
* from, so there is no honest key to return. Failing loudly beats inventing
|
|
80
|
-
* a zero shift that would silently mean "no
|
|
80
|
+
* a zero shift that would silently mean "no adjustment."
|
|
81
81
|
*/
|
|
82
|
-
export declare function
|
|
82
|
+
export declare function adjustmentForRoot(palette: Palette, tonicVar: string, targetHueDeg: number): ColorAdjustment;
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Adjust a Palette to a new "key" — analogous to adjusting a melody.
|
|
3
3
|
*
|
|
4
4
|
* melody / chord progression :: Palette (relationships between colors)
|
|
5
|
-
* key (signature) ::
|
|
6
|
-
* "in C major" / "in D…" :: the resulting
|
|
5
|
+
* key (signature) :: ColorAdjustment (hue / chroma / lightness deltas)
|
|
6
|
+
* "in C major" / "in D…" :: the resulting adjusted Palette
|
|
7
7
|
*
|
|
8
8
|
* Because OKLCH is perceptually uniform, "+30° hue" looks like a
|
|
9
9
|
* consistent jump everywhere on the color wheel — the way a perfect-fifth
|
|
10
|
-
* interval sounds the same in every musical key.
|
|
11
|
-
* under composition: `
|
|
12
|
-
* colors as a single
|
|
10
|
+
* interval sounds the same in every musical key. Adjustment is closed
|
|
11
|
+
* under composition: `adjust(adjust(p, k1), k2)` produces the same
|
|
12
|
+
* colors as a single adjust with the combined deltas, modulo round-trip
|
|
13
13
|
* quantization.
|
|
14
14
|
*
|
|
15
15
|
* [LAW:dataflow-not-control-flow] A single uniform per-color transform
|
|
16
16
|
* runs for every var in the palette. Anchor protection selects *which*
|
|
17
|
-
* `
|
|
17
|
+
* `ColorAdjustment` to apply (data), not *whether* to apply one (branch).
|
|
18
18
|
*
|
|
19
19
|
* [LAW:one-source-of-truth] Anchor classification lives only in
|
|
20
|
-
* `
|
|
20
|
+
* `HUE_LOCKED_ROOTS` below. Every variant of a semantic root carries the root
|
|
21
21
|
* as its first hyphen segment (`error`, `error-darken-1`, `error-muted`, ...)
|
|
22
22
|
* or after a `text-` or `on-` that draws on it (`text-error`, `on-error`), so
|
|
23
23
|
* one set covers the whole family.
|
|
24
24
|
*
|
|
25
|
-
* [LAW:one-way-deps] Imports flow `core/oklch → themes/
|
|
25
|
+
* [LAW:one-way-deps] Imports flow `core/oklch → themes/adjust`;
|
|
26
26
|
* nothing in core/ depends back on this file.
|
|
27
27
|
*/
|
|
28
28
|
import { Oklch, isIdentityKey } from "../core/oklch.js";
|
|
29
29
|
import { pattern } from "../core/pattern.js";
|
|
30
30
|
import { Palette } from "./palette.js";
|
|
31
31
|
/**
|
|
32
|
-
* Semantic roots whose hue is locked under
|
|
32
|
+
* Semantic roots whose hue is locked under adjustment. `error` must
|
|
33
33
|
* look red-ish, `success` green-ish, `warning` amber-ish — rotating the
|
|
34
34
|
* hue would make the UI lie about meaning. Lightness and chroma *still*
|
|
35
35
|
* transform for these roles, so they invert correctly during dark↔light
|
|
@@ -39,7 +39,7 @@ import { Palette } from "./palette.js";
|
|
|
39
39
|
// enforcement — typed code cannot call `add`/`delete`. (`Object.freeze` is
|
|
40
40
|
// not used here because it is a no-op on Set membership; relying on it would
|
|
41
41
|
// imply a runtime guarantee it does not provide.)
|
|
42
|
-
export const
|
|
42
|
+
export const HUE_LOCKED_ROOTS = new Set([
|
|
43
43
|
"error",
|
|
44
44
|
"success",
|
|
45
45
|
"warning",
|
|
@@ -51,15 +51,15 @@ function rootOf(varName) {
|
|
|
51
51
|
return dash === -1 ? role : role.slice(0, dash);
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Whether a palette var's hue is locked under
|
|
55
|
-
* predicate used by `
|
|
54
|
+
* Whether a palette var's hue is locked under adjustment. The single
|
|
55
|
+
* predicate used by `adjustPalette`. Exported so callers building
|
|
56
56
|
* higher-level theme machinery can stay consistent with the locking rule.
|
|
57
57
|
*/
|
|
58
|
-
export function
|
|
59
|
-
return
|
|
58
|
+
export function isHueLocked(varName) {
|
|
59
|
+
return HUE_LOCKED_ROOTS.has(rootOf(varName));
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* Return a new `Palette` whose colors are the
|
|
62
|
+
* Return a new `Palette` whose colors are the adjustment of `palette`'s
|
|
63
63
|
* colors by `key`. Pure. Identity (`IDENTITY`) returns a Palette with byte-exact
|
|
64
64
|
* colors — fast-pathed so identity does not pay the sRGB↔OKLCH round-trip
|
|
65
65
|
* quantization cost.
|
|
@@ -74,23 +74,23 @@ export function isAnchored(varName) {
|
|
|
74
74
|
* The identity fast-path preserves the source `dark` flag verbatim.
|
|
75
75
|
*
|
|
76
76
|
* @param name Optional override for the resulting palette name. Defaults
|
|
77
|
-
* to the source palette's name. Callers building a family of
|
|
77
|
+
* to the source palette's name. Callers building a family of adjusted
|
|
78
78
|
* palettes (e.g. "gruvbox +60°") supply their own.
|
|
79
79
|
*/
|
|
80
|
-
export function
|
|
80
|
+
export function adjustPalette(palette, key, name) {
|
|
81
81
|
if (isIdentityKey(key)) {
|
|
82
|
-
return new Palette(name ?? palette.name, palette.dark, palette.mapRoles((
|
|
82
|
+
return new Palette(name ?? palette.name, palette.dark, palette.mapRoles((color) => color));
|
|
83
83
|
}
|
|
84
84
|
// Anchors share *everything except* hue with the user's key. They still
|
|
85
85
|
// lightness-invert in a dark↔light flip; they still chroma-scale in a
|
|
86
86
|
// saturation sweep — only their hue is held.
|
|
87
87
|
const anchorKey = { ...key, hueShift: 0 };
|
|
88
|
-
const next = palette.mapRoles((
|
|
88
|
+
const next = palette.mapRoles((color, role) => Oklch.fromRgba(color).applyKey(isHueLocked(role) ? anchorKey : key).toRgba());
|
|
89
89
|
const newDark = Oklch.fromRgba(next.background).l < 0.5;
|
|
90
90
|
return new Palette(name ?? palette.name, newDark, next);
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
* Build the `
|
|
93
|
+
* Build the `ColorAdjustment` that rotates `palette` so its *tonic* var lands on
|
|
94
94
|
* `targetHueDeg`. The musical operation directly: a key is the set of
|
|
95
95
|
* intervals from the tonic, so "play this theme in the key of <hue>" means
|
|
96
96
|
* "shift every color by exactly the interval that carries the tonic's
|
|
@@ -98,26 +98,26 @@ export function transposePalette(palette, key, name) {
|
|
|
98
98
|
*
|
|
99
99
|
* Returns a hue-only key (chroma and lightness untouched). Callers that also
|
|
100
100
|
* want to scale chroma or shift lightness spread their own axes over the
|
|
101
|
-
* result — those are independent
|
|
101
|
+
* result — those are independent adjustment dimensions, not part of
|
|
102
102
|
* choosing the key. [LAW:one-type-per-behavior] a degree-shift key and a
|
|
103
103
|
* root-note key are the *same* transform; this is just a second constructor
|
|
104
|
-
* for it, so `
|
|
104
|
+
* for it, so `adjustPalette` stays untouched.
|
|
105
105
|
*
|
|
106
106
|
* Throws if `tonicVar` is absent — the interval has no anchor to measure
|
|
107
107
|
* from, so there is no honest key to return. Failing loudly beats inventing
|
|
108
|
-
* a zero shift that would silently mean "no
|
|
108
|
+
* a zero shift that would silently mean "no adjustment."
|
|
109
109
|
*/
|
|
110
|
-
export function
|
|
110
|
+
export function adjustmentForRoot(palette, tonicVar, targetHueDeg) {
|
|
111
111
|
// Validate the numeric input at the boundary: a non-finite target would
|
|
112
112
|
// propagate as NaN to Oklch's constructor several calls downstream, where
|
|
113
113
|
// the error is far less actionable.
|
|
114
114
|
if (!Number.isFinite(targetHueDeg)) {
|
|
115
|
-
throw new RangeError(`
|
|
115
|
+
throw new RangeError(`adjustmentForRoot: targetHueDeg must be a finite number; got ${targetHueDeg}`);
|
|
116
116
|
}
|
|
117
117
|
const tonic = palette.get(tonicVar);
|
|
118
118
|
if (tonic === undefined) {
|
|
119
|
-
throw new Error(`
|
|
120
|
-
`to use as the tonic; cannot measure the
|
|
119
|
+
throw new Error(`adjustmentForRoot: palette "${palette.name}" has no "${tonicVar}" var ` +
|
|
120
|
+
`to use as the tonic; cannot measure the adjustment interval.`);
|
|
121
121
|
}
|
|
122
122
|
const tonicHue = Oklch.fromRgba(tonic).h;
|
|
123
123
|
let hueShift = (targetHueDeg - tonicHue) % 360;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ColorRgba } from "../core/color.js";
|
|
2
|
-
import { Palette, type PaletteRole, type PaletteRoles } from "./palette.js";
|
|
2
|
+
import { Palette, type BaseRole, type PaletteRole, type PaletteRoles } from "./palette.js";
|
|
3
3
|
/**
|
|
4
4
|
* Base colors required to build a full semantic palette.
|
|
5
5
|
* All are ColorRgba — callers construct from whatever source (hex, HSL, etc.).
|
|
@@ -16,17 +16,18 @@ export interface BaseColors {
|
|
|
16
16
|
}
|
|
17
17
|
/** The eight roles every palette is given, and every role it may also state. */
|
|
18
18
|
export type StatedRoles = BaseColors & Partial<PaletteRoles>;
|
|
19
|
+
export declare const BASE_KEYS: readonly BaseRole[];
|
|
19
20
|
/** Every role of every palette, read off the rules. */
|
|
20
21
|
export declare const PALETTE_ROLES: readonly PaletteRole[];
|
|
21
22
|
/**
|
|
22
23
|
* Build a full semantic palette from its base colors and any other role it
|
|
23
|
-
* states: a stated role keeps its
|
|
24
|
+
* states: a stated role keeps its color, and everything derived from it
|
|
24
25
|
* follows it, but for `text-*`, which is held to read on its `*-muted`. An
|
|
25
|
-
* authored theme is this with
|
|
26
|
+
* authored theme is this with roles stated; see `RULES` for what a role
|
|
26
27
|
* not stated becomes.
|
|
27
28
|
*
|
|
28
|
-
* A translucent
|
|
29
|
-
* from it, so `on-*` is chosen against the
|
|
29
|
+
* A translucent color is drawn onto `background` before anything is derived
|
|
30
|
+
* from it, so `on-*` is chosen against the color the accent is drawn as.
|
|
30
31
|
* `boost` alone stays a layer: it is what `panel` composites.
|
|
31
32
|
*/
|
|
32
33
|
export declare function buildPalette(name: string, dark: boolean, given: StatedRoles): Palette;
|
|
@@ -24,9 +24,9 @@ const TEXT_ON_MUTED = 4.5;
|
|
|
24
24
|
const ACCENT_KEYS = ["primary", "secondary", "accent", "success", "warning", "error"];
|
|
25
25
|
const TRANSPARENT = new ColorRgba(0, 0, 0, 0);
|
|
26
26
|
const WHITE = new ColorRgba(255, 255, 255);
|
|
27
|
-
const withAlpha = (
|
|
27
|
+
const withAlpha = (color, alpha) => new ColorRgba(color.red, color.green, color.blue, alpha);
|
|
28
28
|
const textOn = (alpha) => (at) => withAlpha(contrastFor(at("background")), alpha);
|
|
29
|
-
// [LAW:one-type-per-behavior] The roles naming another role's
|
|
29
|
+
// [LAW:one-type-per-behavior] The roles naming another role's color outright.
|
|
30
30
|
const same = (role) => (at) => at(role);
|
|
31
31
|
const none = () => TRANSPARENT;
|
|
32
32
|
/** The six rungs around `root`, each `-darken-3`…`-lighten-3` one `LADDER_STEP` apart. */
|
|
@@ -58,7 +58,7 @@ function accentRules(accent) {
|
|
|
58
58
|
* How each role not given to `buildPalette` is derived, following Textual's
|
|
59
59
|
* `ColorSystem`, which generated the bundled themes:
|
|
60
60
|
*
|
|
61
|
-
* - `*-muted` = the
|
|
61
|
+
* - `*-muted` = the color blended 70% toward its opposite base role — every
|
|
62
62
|
* accent AND the two base roles themselves, so a caller
|
|
63
63
|
* de-emphasizing body text reaches for `foreground-muted` the
|
|
64
64
|
* way it reaches for `primary-muted` to de-emphasize an accent.
|
|
@@ -67,7 +67,7 @@ function accentRules(accent) {
|
|
|
67
67
|
* terminal-support-dependent SGR attribute.
|
|
68
68
|
* - `text-*` = contrast text tinted 66% with the accent, the foreground for
|
|
69
69
|
* a `*-muted` ground; `buildPalette` then holds it to that ground
|
|
70
|
-
* - `on-*` = WCAG-correct contrast
|
|
70
|
+
* - `on-*` = WCAG-correct contrast color (black or white) for use as
|
|
71
71
|
* foreground when the FULL accent is the background. Picked by
|
|
72
72
|
* relative luminance — single source of truth so widgets never
|
|
73
73
|
* need to invert fg/bg to get readable text. `contrastFor` is
|
|
@@ -152,19 +152,19 @@ const RULES = {
|
|
|
152
152
|
"scrollbar-background-hover": same("scrollbar-background"),
|
|
153
153
|
"scrollbar-corner-color": same("scrollbar-background"),
|
|
154
154
|
};
|
|
155
|
-
const BASE_KEYS = [...ACCENT_KEYS, "background", "foreground"];
|
|
155
|
+
export const BASE_KEYS = [...ACCENT_KEYS, "background", "foreground"];
|
|
156
156
|
/** Every role of every palette, read off the rules. */
|
|
157
157
|
export const PALETTE_ROLES = [...BASE_KEYS, ...Object.keys(RULES)];
|
|
158
158
|
const ROLE_NAMES = new Set(PALETTE_ROLES);
|
|
159
159
|
/**
|
|
160
160
|
* Build a full semantic palette from its base colors and any other role it
|
|
161
|
-
* states: a stated role keeps its
|
|
161
|
+
* states: a stated role keeps its color, and everything derived from it
|
|
162
162
|
* follows it, but for `text-*`, which is held to read on its `*-muted`. An
|
|
163
|
-
* authored theme is this with
|
|
163
|
+
* authored theme is this with roles stated; see `RULES` for what a role
|
|
164
164
|
* not stated becomes.
|
|
165
165
|
*
|
|
166
|
-
* A translucent
|
|
167
|
-
* from it, so `on-*` is chosen against the
|
|
166
|
+
* A translucent color is drawn onto `background` before anything is derived
|
|
167
|
+
* from it, so `on-*` is chosen against the color the accent is drawn as.
|
|
168
168
|
* `boost` alone stays a layer: it is what `panel` composites.
|
|
169
169
|
*/
|
|
170
170
|
export function buildPalette(name, dark, given) {
|
|
@@ -172,9 +172,9 @@ export function buildPalette(name, dark, given) {
|
|
|
172
172
|
// [LAW:no-ambient-temporal-coupling] A rule asks for the roles it reads, so
|
|
173
173
|
// no order among the rules matters. The eight base roles are always known.
|
|
174
174
|
const at = (role) => {
|
|
175
|
-
const
|
|
176
|
-
known.set(role,
|
|
177
|
-
return
|
|
175
|
+
const color = known.get(role) ?? RULES[role](at, dark);
|
|
176
|
+
known.set(role, color);
|
|
177
|
+
return color;
|
|
178
178
|
};
|
|
179
179
|
// [LAW:single-enforcer] Stated and derived `text-*` alike: the tint is the
|
|
180
180
|
// palette's, whether it reads is decided here. A stated tint stays translucent
|
|
@@ -193,23 +193,23 @@ export function buildPalette(name, dark, given) {
|
|
|
193
193
|
*/
|
|
194
194
|
function statedRoles(name, given) {
|
|
195
195
|
const drawn = drawnOn(name, given.background);
|
|
196
|
-
const stated = Object.entries(given).flatMap(([role,
|
|
196
|
+
const stated = Object.entries(given).flatMap(([role, color]) => {
|
|
197
197
|
if (!ROLE_NAMES.has(role))
|
|
198
198
|
throw new RangeError(`palette ${JSON.stringify(name)}: ${JSON.stringify(role)} is not a role`);
|
|
199
|
-
if (
|
|
199
|
+
if (color === undefined)
|
|
200
200
|
return [];
|
|
201
|
-
return [[role, role === "boost" ?
|
|
201
|
+
return [[role, role === "boost" ? color : drawn(color)]];
|
|
202
202
|
});
|
|
203
203
|
const known = new Map(stated);
|
|
204
|
-
// Every base
|
|
205
|
-
//
|
|
204
|
+
// Every base color is derived from, and a fully transparent one draws no
|
|
205
|
+
// color of its own to derive a muted shade or a contrast from.
|
|
206
206
|
// [LAW:no-silent-failure]
|
|
207
207
|
for (const key of BASE_KEYS) {
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
210
|
-
throw new RangeError(`palette ${JSON.stringify(name)}: ${key} is fully transparent (${
|
|
208
|
+
const color = given[key];
|
|
209
|
+
if (color.alpha === 0) {
|
|
210
|
+
throw new RangeError(`palette ${JSON.stringify(name)}: ${key} is fully transparent (${color.hex}), so there is no color to derive the palette from`);
|
|
211
211
|
}
|
|
212
|
-
known.set(key, drawn(
|
|
212
|
+
known.set(key, drawn(color));
|
|
213
213
|
}
|
|
214
214
|
return known;
|
|
215
215
|
}
|
|
@@ -217,7 +217,7 @@ function statedRoles(name, given) {
|
|
|
217
217
|
* A palette's `text-*`: its tint held to WCAG AA on `*-muted`, moved toward
|
|
218
218
|
* the palette's own text side so it also reads on `background`, where widgets
|
|
219
219
|
* draw it too. The muted floor is the promise: where no lightness on the text
|
|
220
|
-
* side clears it, the
|
|
220
|
+
* side clears it, the color that does is on the other side, and the
|
|
221
221
|
* background pair is the one given up. Every bundled palette clears both
|
|
222
222
|
* (test/themes/text-on-muted.test.ts).
|
|
223
223
|
*
|
|
@@ -10,7 +10,7 @@ export declare function darken(color: ColorRgba, levels: number): ColorRgba;
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function lighten(color: ColorRgba, levels: number): ColorRgba;
|
|
12
12
|
/**
|
|
13
|
-
* Move a
|
|
13
|
+
* Move a color's CIE L* by `amount` (0..1 of the L* scale), keeping its alpha.
|
|
14
14
|
* Textual's `Color.lighten`, which drew every shade ladder in the bundled
|
|
15
15
|
* themes, so a ladder derived here continues the ones authored there.
|
|
16
16
|
*/
|
|
@@ -45,16 +45,16 @@ export { relativeLuminance, contrastRatio };
|
|
|
45
45
|
* in, so the ratio is measured on what the eye actually sees and the returned
|
|
46
46
|
* color is opaque.
|
|
47
47
|
*
|
|
48
|
-
* `drawnAt` is the depth the terminal will draw the pair at. At 256
|
|
48
|
+
* `drawnAt` is the depth the terminal will draw the pair at. At 256 colors
|
|
49
49
|
* the terminal rounds text and background independently, and two roundings
|
|
50
50
|
* can meet in the middle, so the ratio is measured on the drawn pair: a
|
|
51
|
-
*
|
|
51
|
+
* color that loses the floor there is replaced by the nearest cube/grey entry
|
|
52
52
|
* that clears it (whose own rounding is itself). At ANSI the terminal draws
|
|
53
|
-
* each index in its own theme's
|
|
53
|
+
* each index in its own theme's color, so the ratio is measured on
|
|
54
54
|
* `terminal`'s sixteen: a theme whose black is light and white dark (Rosé Pine
|
|
55
|
-
* Dawn) turns the nominal table's sides over. A replacement is the
|
|
55
|
+
* Dawn) turns the nominal table's sides over. A replacement is the color the
|
|
56
56
|
* writer emits as the index nearest `fg` that clears the floor as `terminal`
|
|
57
|
-
* draws it. Truecolor draws the
|
|
57
|
+
* draws it. Truecolor draws the color chosen.
|
|
58
58
|
*
|
|
59
59
|
* [LAW:single-enforcer] The one place "is this text readable, and if not fix
|
|
60
60
|
* it" is decided. Callers route every fg/bg pair through here and the
|
|
@@ -66,35 +66,35 @@ export declare function ensureContrast(fg: ColorRgba, bg: ColorRgba, minRatio?:
|
|
|
66
66
|
drawnAt?: ColorDepth, substrate?: ColorRgba, terminal?: TerminalColors): ColorRgba;
|
|
67
67
|
/**
|
|
68
68
|
* `chosen` (composited opaque over `substrate`), or — when the depth the
|
|
69
|
-
* terminal draws at rounds it to a
|
|
69
|
+
* terminal draws at rounds it to a color `accept` refuses — the color the
|
|
70
70
|
* writer emits as the nearest entry `accept` takes. `accept` sees the
|
|
71
|
-
* candidate as drawn, and `drawn`, the same rounding for any other
|
|
71
|
+
* candidate as drawn, and `drawn`, the same rounding for any other color it
|
|
72
72
|
* measures against, so the caller states a floor once and it holds on the
|
|
73
|
-
*
|
|
73
|
+
* colors the terminal shows — at ANSI, `terminal`'s own sixteen, as
|
|
74
74
|
* `ensureContrast` measures there. Truecolor
|
|
75
|
-
* draws from no table, so a
|
|
75
|
+
* draws from no table, so a color refused there has no replacement;
|
|
76
76
|
* `undefined` means nothing the depth draws is accepted.
|
|
77
77
|
*
|
|
78
78
|
* `ensureContrast` is this with a contrast ratio as the floor; this is for a
|
|
79
79
|
* floor that is not text on its background (an open state standing off every
|
|
80
80
|
* closed cell, two planes standing off each other).
|
|
81
81
|
*/
|
|
82
|
-
export declare function
|
|
82
|
+
export declare function ensureMinimumDelta(chosen: ColorRgba, drawnAt: ColorDepth, accept: (candidate: ColorRgba, drawn: (c: ColorRgba) => ColorRgba) => boolean, substrate?: ColorRgba, terminal?: TerminalColors): ColorRgba | undefined;
|
|
83
83
|
/**
|
|
84
|
-
* The
|
|
84
|
+
* The color a ground is shown as at `drawnAt`: composited over `substrate`
|
|
85
85
|
* (the SGR writer's black by default), rounded to the index the writer emits
|
|
86
86
|
* at that depth, and shown as the terminal shows that index — at ANSI, in
|
|
87
|
-
* `terminal`'s own
|
|
87
|
+
* `terminal`'s own color. The one account `ensureMinimumDelta` and `ensureContrast`
|
|
88
88
|
* measure by, for a caller that measures a floor of its own.
|
|
89
89
|
*/
|
|
90
|
-
export declare function
|
|
90
|
+
export declare function compositedColor(color: ColorRgba, drawnAt: ColorDepth, substrate?: ColorRgba, terminal?: TerminalColors): ColorRgba;
|
|
91
91
|
/**
|
|
92
92
|
* `fg` held to `minRatio` on `bg` in truecolor, moving in lightness toward
|
|
93
93
|
* `toward` (black or white). `ensureContrast` moves toward the pole `bg`
|
|
94
|
-
* itself contrasts with; a
|
|
94
|
+
* itself contrasts with; a color that already has a side (a palette's
|
|
95
95
|
* `text-*` is its text, tinted) passes that side, since on a ground near the
|
|
96
96
|
* 0.179 cutoff both poles clear and only one also reads on everything else
|
|
97
|
-
* the
|
|
97
|
+
* the color is drawn on. Where `toward` cannot clear `minRatio` on `bg`,
|
|
98
98
|
* the floor wins over the side: the answer is `contrastFor(bg)`.
|
|
99
99
|
*/
|
|
100
100
|
export declare function ensureContrastToward(fg: ColorRgba, bg: ColorRgba, minRatio: number, toward: ColorRgba): ColorRgba;
|