|
| 1 | +--- |
| 2 | +title: ColorText |
| 3 | +parent: Display and data |
| 4 | +grand_parent: Components |
| 5 | +--- |
| 6 | + |
| 7 | +# ColorText |
| 8 | +{: .no_toc } |
| 9 | + |
| 10 | +Multiline text coloured cell by cell - a ramp, a palette per line, or a function. |
| 11 | + |
| 12 | +<!-- docs:setup |
| 13 | +declare const banner: string; |
| 14 | +--> |
| 15 | + |
| 16 | +```tsx |
| 17 | +import { ColorText } from '@textui/widgets'; |
| 18 | + |
| 19 | +<ColorText ink={{ gradient: ['cyan', 'magenta'] }} content={banner} alignBlock /> |
| 20 | +``` |
| 21 | + |
| 22 | +## Props |
| 23 | + |
| 24 | +<!-- props:start --> |
| 25 | +| Prop | Type | Default | | |
| 26 | +| --- | --- | --- | --- | |
| 27 | +| `ink` | `Ink` | | Left unset, this is an ordinary block of text. | |
| 28 | +| `alignBlock` | `boolean` | | Align the block as one thing, rather than each line on its own. `textAlign` centres every line over its own middle, which is right for prose and shears a picture: five rows of block letters do not have equal widths once the trailing spaces are gone, so each row lands somewhere slightly different and the letters lean. Under this, the whole block is placed once and the lines keep their offsets from each other. Off by default, because that is what `text` does and the two are supposed to mean the same thing by the same prop. | |
| 29 | + |
| 30 | +Plus everything on [`TextProps`](../base-props.md). |
| 31 | +<!-- props:end --> |
| 32 | + |
| 33 | +A `text` takes one colour for the whole run, which is right for nearly |
| 34 | +everything and no answer at all where the colour *is* the content - a banner, a |
| 35 | +ramp across a title, a palette walked down a block of ascii art. Everything else |
| 36 | +about this is a `text`: `wrap`, `truncate`, `textAlign` and the style keys |
| 37 | +all mean here what they mean there. |
| 38 | + |
| 39 | +`ink` is spelled three ways, and the first two are data: |
| 40 | + |
| 41 | +<!-- docs:local |
| 42 | +import { ColorText } from '@textui/widgets'; |
| 43 | +import type { Color } from '@textui/core'; |
| 44 | +declare const text: string; |
| 45 | +declare const palette: Color[]; |
| 46 | +--> |
| 47 | + |
| 48 | +```tsx |
| 49 | +<box direction="column"> |
| 50 | + <ColorText ink={{ gradient: ['#ff5f6d', '#ffc371'], axis: 'y' }} content={text} /> |
| 51 | + <ColorText ink={['danger', 'warning', 'success']} content={text} /> |
| 52 | + <ColorText ink={{ cycle: palette, every: [4, 3] }} content={text} /> |
| 53 | + <ColorText ink={(cell) => (cell.index % 2 ? 'muted' : 'accent')} content={text} /> |
| 54 | +</box> |
| 55 | +``` |
| 56 | + |
| 57 | +A **ramp** runs across the columns, down the lines, or corner to corner. It is |
| 58 | +measured against the widest line of the block, so the rows of a banner share one |
| 59 | +gradient and the colours line up down it; `per: 'line'` restarts it on each |
| 60 | +line, which is what ragged prose wants. |
| 61 | + |
| 62 | +A **cycle** walks a palette. An array on its own is the short spelling of one |
| 63 | +colour per line. `every` is how much of the text each colour takes - a number, |
| 64 | +or a repeating pattern of runs, so `[4, 3]` is four cells then three. The count |
| 65 | +restarts on each line, which is what keeps the bands vertical; `continuous` |
| 66 | +carries it over the line breaks and leans them into a diagonal. `unit` picks |
| 67 | +what advances the colour: `cell` (the default, and the one that keeps a block |
| 68 | +aligned), `grapheme`, `letter`, `word` or `line`. |
| 69 | + |
| 70 | +A **function** is handed each cell and answers with a colour, a whole |
| 71 | +`CellStyle`, or nothing - and nothing means "leave this one alone", which is |
| 72 | +what makes an ink that colours only the vowels two lines long. The cell carries |
| 73 | +a `col` *and* an `index` because they stop being the same number the moment |
| 74 | +the text is not plain ascii: colour by `index` and paint at `col`, or a |
| 75 | +gradient shears through the first wide character it meets. |
| 76 | + |
| 77 | +Only the data forms survive being written in a JSON screen. A function prop |
| 78 | +cannot be serialized - the same trade [`canvas`](../primitives/canvas.md) |
| 79 | +makes with `draw`, and for the same reason: this paints on one. |
| 80 | + |
| 81 | +Two consequences of that canvas are worth knowing. **Inherited colour stops |
| 82 | +here**: a cell the ink declines takes this component's own `fg`, not the one a |
| 83 | +parent row would have handed a `text`, so a `ColorText` inside something that |
| 84 | +recolours its children when selected has to be told. And **a block that wraps |
| 85 | +asks for no width** - it fills what it is given, the way anything that wraps |
| 86 | +must; a block that does not wrap is as wide as its widest line and says so. |
| 87 | + |
| 88 | +`alignBlock` is for pictures. `textAlign` centres every line over its own |
| 89 | +middle, which is right for prose and shears a banner, because five rows of block |
| 90 | +letters do not have equal widths once the trailing spaces are gone. Under |
| 91 | +`alignBlock` the whole block is placed once and the lines keep their offsets |
| 92 | +from each other. |
| 93 | + |
| 94 | +The colour is decoration and never the message. A 16-colour session flattens a |
| 95 | +six-stop ramp into a couple of bands and a piped log loses all of it, so |
| 96 | +anything the reader has to know has to be in the words. |
| 97 | + |
| 98 | +## See also |
| 99 | + |
| 100 | +- [text](../primitives/text.md) - one colour, and the right answer nearly always |
| 101 | +- [canvas](../primitives/canvas.md) - the primitive underneath, for cells that are not text |
| 102 | +- [Themes](../../themes/tokens.md) - the tokens an ink can name |
0 commit comments