@textui/core 0.1.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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +11 -0
- package/dist/app/app.d.ts +200 -0
- package/dist/app/app.d.ts.map +1 -0
- package/dist/app/app.js +980 -0
- package/dist/core/animation.d.ts +34 -0
- package/dist/core/animation.d.ts.map +1 -0
- package/dist/core/animation.js +125 -0
- package/dist/core/clipboard.d.ts +29 -0
- package/dist/core/clipboard.d.ts.map +1 -0
- package/dist/core/clipboard.js +30 -0
- package/dist/core/commands.d.ts +42 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +146 -0
- package/dist/core/components.d.ts +27 -0
- package/dist/core/components.d.ts.map +1 -0
- package/dist/core/components.js +78 -0
- package/dist/core/events.d.ts +23 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +77 -0
- package/dist/core/focus.d.ts +69 -0
- package/dist/core/focus.d.ts.map +1 -0
- package/dist/core/focus.js +336 -0
- package/dist/core/i18n.d.ts +27 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/i18n.js +88 -0
- package/dist/core/keybindings.d.ts +53 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +163 -0
- package/dist/core/layers.d.ts +28 -0
- package/dist/core/layers.d.ts.map +1 -0
- package/dist/core/layers.js +84 -0
- package/dist/core/manifest.d.ts +22 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +85 -0
- package/dist/core/navigation.d.ts +47 -0
- package/dist/core/navigation.d.ts.map +1 -0
- package/dist/core/navigation.js +110 -0
- package/dist/core/resources.d.ts +115 -0
- package/dist/core/resources.d.ts.map +1 -0
- package/dist/core/resources.js +321 -0
- package/dist/core/services.d.ts +21 -0
- package/dist/core/services.d.ts.map +1 -0
- package/dist/core/services.js +63 -0
- package/dist/core/store.d.ts +60 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +593 -0
- package/dist/core/surfaces.d.ts +81 -0
- package/dist/core/surfaces.d.ts.map +1 -0
- package/dist/core/surfaces.js +237 -0
- package/dist/core/syntax.d.ts +49 -0
- package/dist/core/syntax.d.ts.map +1 -0
- package/dist/core/syntax.js +172 -0
- package/dist/core/when.d.ts +15 -0
- package/dist/core/when.d.ts.map +1 -0
- package/dist/core/when.js +224 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/jsx/factory.d.ts +27 -0
- package/dist/jsx/factory.d.ts.map +1 -0
- package/dist/jsx/factory.js +102 -0
- package/dist/jsx/intrinsics.d.ts +96 -0
- package/dist/jsx/intrinsics.d.ts.map +1 -0
- package/dist/jsx/intrinsics.js +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +13 -0
- package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-dev-runtime.js +12 -0
- package/dist/jsx/jsx-runtime.d.ts +42 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-runtime.js +16 -0
- package/dist/render/buffer.d.ts +77 -0
- package/dist/render/buffer.d.ts.map +1 -0
- package/dist/render/buffer.js +275 -0
- package/dist/render/color.d.ts +35 -0
- package/dist/render/color.d.ts.map +1 -0
- package/dist/render/color.js +160 -0
- package/dist/render/diff.d.ts +37 -0
- package/dist/render/diff.d.ts.map +1 -0
- package/dist/render/diff.js +66 -0
- package/dist/render/layout.d.ts +72 -0
- package/dist/render/layout.d.ts.map +1 -0
- package/dist/render/layout.js +633 -0
- package/dist/render/static.d.ts +63 -0
- package/dist/render/static.d.ts.map +1 -0
- package/dist/render/static.js +209 -0
- package/dist/runtime/bindings.d.ts +46 -0
- package/dist/runtime/bindings.d.ts.map +1 -0
- package/dist/runtime/bindings.js +116 -0
- package/dist/runtime/hooks.d.ts +284 -0
- package/dist/runtime/hooks.d.ts.map +1 -0
- package/dist/runtime/hooks.js +846 -0
- package/dist/runtime/instance.d.ts +106 -0
- package/dist/runtime/instance.d.ts.map +1 -0
- package/dist/runtime/instance.js +181 -0
- package/dist/runtime/paint.d.ts +27 -0
- package/dist/runtime/paint.d.ts.map +1 -0
- package/dist/runtime/paint.js +567 -0
- package/dist/runtime/reconcile.d.ts +23 -0
- package/dist/runtime/reconcile.d.ts.map +1 -0
- package/dist/runtime/reconcile.js +260 -0
- package/dist/runtime/runtime.d.ts +42 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +1 -0
- package/dist/runtime/style.d.ts +55 -0
- package/dist/runtime/style.d.ts.map +1 -0
- package/dist/runtime/style.js +143 -0
- package/dist/themes/borders.d.ts +10 -0
- package/dist/themes/borders.d.ts.map +1 -0
- package/dist/themes/borders.js +88 -0
- package/dist/themes/builtin.d.ts +31 -0
- package/dist/themes/builtin.d.ts.map +1 -0
- package/dist/themes/builtin.js +291 -0
- package/dist/themes/glyphs.d.ts +15 -0
- package/dist/themes/glyphs.d.ts.map +1 -0
- package/dist/themes/glyphs.js +97 -0
- package/dist/themes/index.d.ts +5 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +4 -0
- package/dist/themes/registry.d.ts +20 -0
- package/dist/themes/registry.d.ts.map +1 -0
- package/dist/themes/registry.js +204 -0
- package/dist/types/adapter.d.ts +38 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/adapter.js +1 -0
- package/dist/types/animation.d.ts +31 -0
- package/dist/types/animation.d.ts.map +1 -0
- package/dist/types/animation.js +1 -0
- package/dist/types/app.d.ts +148 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +1 -0
- package/dist/types/async.d.ts +30 -0
- package/dist/types/async.d.ts.map +1 -0
- package/dist/types/async.js +1 -0
- package/dist/types/capabilities.d.ts +44 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +33 -0
- package/dist/types/cells.d.ts +72 -0
- package/dist/types/cells.d.ts.map +1 -0
- package/dist/types/cells.js +10 -0
- package/dist/types/command.d.ts +127 -0
- package/dist/types/command.d.ts.map +1 -0
- package/dist/types/command.js +1 -0
- package/dist/types/component-registry.d.ts +77 -0
- package/dist/types/component-registry.d.ts.map +1 -0
- package/dist/types/component-registry.js +1 -0
- package/dist/types/disposable.d.ts +8 -0
- package/dist/types/disposable.d.ts.map +1 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/focus.d.ts +72 -0
- package/dist/types/focus.d.ts.map +1 -0
- package/dist/types/focus.js +1 -0
- package/dist/types/geometry.d.ts +28 -0
- package/dist/types/geometry.d.ts.map +1 -0
- package/dist/types/geometry.js +14 -0
- package/dist/types/graph.d.ts +129 -0
- package/dist/types/graph.d.ts.map +1 -0
- package/dist/types/graph.js +31 -0
- package/dist/types/i18n.d.ts +23 -0
- package/dist/types/i18n.d.ts.map +1 -0
- package/dist/types/i18n.js +1 -0
- package/dist/types/index.d.ts +32 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +31 -0
- package/dist/types/input.d.ts +65 -0
- package/dist/types/input.d.ts.map +1 -0
- package/dist/types/input.js +1 -0
- package/dist/types/keybinding.d.ts +49 -0
- package/dist/types/keybinding.d.ts.map +1 -0
- package/dist/types/keybinding.js +1 -0
- package/dist/types/layer.d.ts +54 -0
- package/dist/types/layer.d.ts.map +1 -0
- package/dist/types/layer.js +1 -0
- package/dist/types/manifest.d.ts +114 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +1 -0
- package/dist/types/markdown.d.ts +58 -0
- package/dist/types/markdown.d.ts.map +1 -0
- package/dist/types/markdown.js +1 -0
- package/dist/types/navigation.d.ts +40 -0
- package/dist/types/navigation.d.ts.map +1 -0
- package/dist/types/navigation.js +1 -0
- package/dist/types/render.d.ts +72 -0
- package/dist/types/render.d.ts.map +1 -0
- package/dist/types/render.js +1 -0
- package/dist/types/resource.d.ts +170 -0
- package/dist/types/resource.d.ts.map +1 -0
- package/dist/types/resource.js +1 -0
- package/dist/types/services.d.ts +24 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +3 -0
- package/dist/types/shell.d.ts +32 -0
- package/dist/types/shell.d.ts.map +1 -0
- package/dist/types/shell.js +1 -0
- package/dist/types/store.d.ts +124 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/store.js +1 -0
- package/dist/types/stream.d.ts +18 -0
- package/dist/types/stream.d.ts.map +1 -0
- package/dist/types/stream.js +1 -0
- package/dist/types/style.d.ts +166 -0
- package/dist/types/style.d.ts.map +1 -0
- package/dist/types/style.js +1 -0
- package/dist/types/surface.d.ts +97 -0
- package/dist/types/surface.d.ts.map +1 -0
- package/dist/types/surface.js +1 -0
- package/dist/types/syntax.d.ts +68 -0
- package/dist/types/syntax.d.ts.map +1 -0
- package/dist/types/syntax.js +5 -0
- package/dist/types/terminal.d.ts +52 -0
- package/dist/types/terminal.d.ts.map +1 -0
- package/dist/types/terminal.js +1 -0
- package/dist/types/theme.d.ts +117 -0
- package/dist/types/theme.d.ts.map +1 -0
- package/dist/types/theme.js +1 -0
- package/dist/types/when.d.ts +19 -0
- package/dist/types/when.d.ts.map +1 -0
- package/dist/types/when.js +1 -0
- package/dist/ui/primitives.d.ts +56 -0
- package/dist/ui/primitives.d.ts.map +1 -0
- package/dist/ui/primitives.js +108 -0
- package/dist/ui/screen.d.ts +23 -0
- package/dist/ui/screen.d.ts.map +1 -0
- package/dist/ui/screen.js +18 -0
- package/dist/util/disposable.d.ts +6 -0
- package/dist/util/disposable.d.ts.map +1 -0
- package/dist/util/disposable.js +49 -0
- package/dist/util/markdown.d.ts +24 -0
- package/dist/util/markdown.d.ts.map +1 -0
- package/dist/util/markdown.js +220 -0
- package/dist/util/paths.d.ts +47 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +134 -0
- package/dist/util/stream.d.ts +32 -0
- package/dist/util/stream.d.ts.map +1 -0
- package/dist/util/stream.js +206 -0
- package/dist/util/text.d.ts +65 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +419 -0
- package/package.json +70 -0
- package/src/adapters/index.ts +11 -0
- package/src/app/app.ts +1096 -0
- package/src/core/animation.ts +144 -0
- package/src/core/clipboard.ts +40 -0
- package/src/core/commands.ts +169 -0
- package/src/core/components.ts +91 -0
- package/src/core/events.ts +95 -0
- package/src/core/focus.ts +358 -0
- package/src/core/i18n.ts +107 -0
- package/src/core/keybindings.ts +184 -0
- package/src/core/layers.ts +94 -0
- package/src/core/manifest.ts +84 -0
- package/src/core/navigation.ts +135 -0
- package/src/core/resources.ts +362 -0
- package/src/core/services.ts +69 -0
- package/src/core/store.ts +640 -0
- package/src/core/surfaces.ts +292 -0
- package/src/core/syntax.ts +200 -0
- package/src/core/when.ts +238 -0
- package/src/index.ts +76 -0
- package/src/jsx/factory.ts +124 -0
- package/src/jsx/intrinsics.ts +99 -0
- package/src/jsx/jsx-dev-runtime.ts +23 -0
- package/src/jsx/jsx-runtime.ts +76 -0
- package/src/render/buffer.ts +318 -0
- package/src/render/color.ts +180 -0
- package/src/render/diff.ts +99 -0
- package/src/render/layout.ts +764 -0
- package/src/render/static.ts +290 -0
- package/src/runtime/bindings.ts +150 -0
- package/src/runtime/hooks.ts +1057 -0
- package/src/runtime/instance.ts +284 -0
- package/src/runtime/paint.ts +737 -0
- package/src/runtime/reconcile.ts +335 -0
- package/src/runtime/runtime.ts +47 -0
- package/src/runtime/style.ts +205 -0
- package/src/themes/borders.ts +95 -0
- package/src/themes/builtin.ts +301 -0
- package/src/themes/glyphs.ts +101 -0
- package/src/themes/index.ts +4 -0
- package/src/themes/registry.ts +224 -0
- package/src/types/adapter.ts +41 -0
- package/src/types/animation.ts +34 -0
- package/src/types/app.ts +149 -0
- package/src/types/async.ts +35 -0
- package/src/types/capabilities.ts +79 -0
- package/src/types/cells.ts +79 -0
- package/src/types/command.ts +139 -0
- package/src/types/component-registry.ts +82 -0
- package/src/types/disposable.ts +8 -0
- package/src/types/focus.ts +77 -0
- package/src/types/geometry.ts +50 -0
- package/src/types/graph.ts +174 -0
- package/src/types/i18n.ts +25 -0
- package/src/types/index.ts +31 -0
- package/src/types/input.ts +81 -0
- package/src/types/keybinding.ts +51 -0
- package/src/types/layer.ts +46 -0
- package/src/types/manifest.ts +101 -0
- package/src/types/markdown.ts +47 -0
- package/src/types/navigation.ts +42 -0
- package/src/types/render.ts +86 -0
- package/src/types/resource.ts +185 -0
- package/src/types/services.ts +28 -0
- package/src/types/shell.ts +30 -0
- package/src/types/store.ts +148 -0
- package/src/types/stream.ts +24 -0
- package/src/types/style.ts +205 -0
- package/src/types/surface.ts +119 -0
- package/src/types/syntax.ts +93 -0
- package/src/types/terminal.ts +58 -0
- package/src/types/theme.ts +121 -0
- package/src/types/when.ts +21 -0
- package/src/ui/primitives.ts +118 -0
- package/src/ui/screen.ts +41 -0
- package/src/util/disposable.ts +49 -0
- package/src/util/markdown.ts +225 -0
- package/src/util/paths.ts +138 -0
- package/src/util/stream.ts +213 -0
- package/src/util/text.ts +428 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import type { ThemeDefinition } from '../types/theme.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The built-in themes.
|
|
5
|
+
*
|
|
6
|
+
* `dark` and `light` are the two bases; everything else extends one of them
|
|
7
|
+
* and restates only what it changes. The three that follow exist because the
|
|
8
|
+
* same application should be able to look like a dense operator console, an
|
|
9
|
+
* airy report or a workbench without a component knowing which - so the
|
|
10
|
+
* difference lives here, in border style and density, not in the catalog.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const DARK: ThemeDefinition = {
|
|
14
|
+
id: 'dark',
|
|
15
|
+
name: 'Dark',
|
|
16
|
+
appearance: 'dark',
|
|
17
|
+
border: 'single',
|
|
18
|
+
density: 'normal',
|
|
19
|
+
colors: {
|
|
20
|
+
canvas: '#0d1117',
|
|
21
|
+
surface: '#161b22',
|
|
22
|
+
surfaceAlt: '#1c2128',
|
|
23
|
+
overlay: '#1c2128',
|
|
24
|
+
border: '#30363d',
|
|
25
|
+
borderStrong: '#484f58',
|
|
26
|
+
borderSubtle: '#21262d',
|
|
27
|
+
text: '#e6edf3',
|
|
28
|
+
muted: '#8b949e',
|
|
29
|
+
subtle: '#6e7681',
|
|
30
|
+
inverted: '#0d1117',
|
|
31
|
+
accent: '#58a6ff',
|
|
32
|
+
primary: '#388bfd',
|
|
33
|
+
secondary: '#a371f7',
|
|
34
|
+
success: '#3fb950',
|
|
35
|
+
warning: '#d29922',
|
|
36
|
+
danger: '#f85149',
|
|
37
|
+
info: '#58a6ff',
|
|
38
|
+
onAccent: '#0d1117',
|
|
39
|
+
onDefault: '#0d1117',
|
|
40
|
+
onPrimary: '#0d1117',
|
|
41
|
+
onSecondary: '#0d1117',
|
|
42
|
+
onMuted: '#0d1117',
|
|
43
|
+
onSuccess: '#0d1117',
|
|
44
|
+
onInfo: '#0d1117',
|
|
45
|
+
onWarning: '#0d1117',
|
|
46
|
+
onDanger: '#0d1117',
|
|
47
|
+
hover: '#1f2937',
|
|
48
|
+
active: '#264466',
|
|
49
|
+
selected: '#1f6feb',
|
|
50
|
+
focus: '#58a6ff',
|
|
51
|
+
disabled: '#484f58',
|
|
52
|
+
scrim: '#010409',
|
|
53
|
+
cursor: '#58a6ff',
|
|
54
|
+
shadow: '#010409',
|
|
55
|
+
},
|
|
56
|
+
spacing: { none: 0, xs: 0, sm: 1, md: 1, lg: 2, xl: 3 },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const LIGHT: ThemeDefinition = {
|
|
60
|
+
id: 'light',
|
|
61
|
+
name: 'Light',
|
|
62
|
+
appearance: 'light',
|
|
63
|
+
border: 'single',
|
|
64
|
+
density: 'normal',
|
|
65
|
+
colors: {
|
|
66
|
+
canvas: '#ffffff',
|
|
67
|
+
surface: '#f6f8fa',
|
|
68
|
+
surfaceAlt: '#eaeef2',
|
|
69
|
+
overlay: '#ffffff',
|
|
70
|
+
border: '#d0d7de',
|
|
71
|
+
borderStrong: '#8c959f',
|
|
72
|
+
borderSubtle: '#eaeef2',
|
|
73
|
+
text: '#1f2328',
|
|
74
|
+
muted: '#656d76',
|
|
75
|
+
subtle: '#8c959f',
|
|
76
|
+
inverted: '#ffffff',
|
|
77
|
+
accent: '#0969da',
|
|
78
|
+
primary: '#0969da',
|
|
79
|
+
secondary: '#8250df',
|
|
80
|
+
success: '#1a7f37',
|
|
81
|
+
warning: '#faca00',
|
|
82
|
+
danger: '#e95c5e',
|
|
83
|
+
info: '#0969da',
|
|
84
|
+
onAccent: '#ffffff',
|
|
85
|
+
onDefault: '#ffffff',
|
|
86
|
+
onPrimary: '#ffffff',
|
|
87
|
+
onSecondary: '#ffffff',
|
|
88
|
+
onMuted: '#ffffff',
|
|
89
|
+
onSuccess: '#ffffff',
|
|
90
|
+
onInfo: '#ffffff',
|
|
91
|
+
onWarning: '#ffffff',
|
|
92
|
+
onDanger: '#ffffff',
|
|
93
|
+
hover: '#eaeef2',
|
|
94
|
+
active: '#dbeafe',
|
|
95
|
+
selected: '#0969da',
|
|
96
|
+
focus: '#0969da',
|
|
97
|
+
disabled: '#8c959f',
|
|
98
|
+
scrim: '#8c959f',
|
|
99
|
+
cursor: '#0969da',
|
|
100
|
+
shadow: '#d0d7de',
|
|
101
|
+
},
|
|
102
|
+
spacing: { none: 0, xs: 0, sm: 1, md: 1, lg: 2, xl: 3 },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** Dense, bordered, high contrast. Every region is a labelled box. */
|
|
106
|
+
export const CONSOLE: ThemeDefinition = {
|
|
107
|
+
id: 'console',
|
|
108
|
+
name: 'Console',
|
|
109
|
+
appearance: 'dark',
|
|
110
|
+
extends: 'dark',
|
|
111
|
+
border: 'single',
|
|
112
|
+
density: 'compact',
|
|
113
|
+
colors: {
|
|
114
|
+
canvas: '#000000',
|
|
115
|
+
surface: '#0a0e14',
|
|
116
|
+
border: '#3b4252',
|
|
117
|
+
borderStrong: '#5e81ac',
|
|
118
|
+
accent: '#88c0d0',
|
|
119
|
+
text: '#d8dee9',
|
|
120
|
+
muted: '#616e88',
|
|
121
|
+
// The accent is teal, so the things made of it are too. Inheriting these
|
|
122
|
+
// from `dark` is what left a teal underline over a blue focus ring and a
|
|
123
|
+
// blue selected row - one theme wearing two accents.
|
|
124
|
+
//
|
|
125
|
+
// The two selection backgrounds are picked rather than derived: `selected`
|
|
126
|
+
// carries `inverted` text so it has to be light, and `active` carries
|
|
127
|
+
// `text` so it has to be dark. Same hue, opposite ends.
|
|
128
|
+
primary: '#88c0d0',
|
|
129
|
+
info: '#88c0d0',
|
|
130
|
+
selected: '#6ba3b2',
|
|
131
|
+
active: '#1e3d47',
|
|
132
|
+
onAccent: '#0a0e14',
|
|
133
|
+
onPrimary: '#0a0e14',
|
|
134
|
+
onInfo: '#0a0e14',
|
|
135
|
+
hover: '#141a21',
|
|
136
|
+
},
|
|
137
|
+
spacing: { none: 0, xs: 0, sm: 0, md: 1, lg: 1, xl: 2 },
|
|
138
|
+
components: {
|
|
139
|
+
Panel: { base: { border: 'single', padding: 0 } },
|
|
140
|
+
Button: { base: { padding: [0, 1] } },
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/** Borderless. Whitespace and alignment do the separating. */
|
|
145
|
+
export const PAPER: ThemeDefinition = {
|
|
146
|
+
id: 'paper',
|
|
147
|
+
name: 'Paper',
|
|
148
|
+
appearance: 'light',
|
|
149
|
+
extends: 'light',
|
|
150
|
+
border: 'none',
|
|
151
|
+
density: 'airy',
|
|
152
|
+
colors: {
|
|
153
|
+
canvas: '#fffdf9',
|
|
154
|
+
surface: '#fffdf9',
|
|
155
|
+
surfaceAlt: '#f5f2ec',
|
|
156
|
+
border: '#e5e0d8',
|
|
157
|
+
borderSubtle: '#f0ece5',
|
|
158
|
+
subtle: '#c56532',
|
|
159
|
+
text: '#2b2a27',
|
|
160
|
+
muted: '#7a756c',
|
|
161
|
+
accent: '#b4531f',
|
|
162
|
+
primary: '#b4531f',
|
|
163
|
+
// Selection as a tint of the page, not a block of another colour.
|
|
164
|
+
// `paper` inherits from `light`, whose selection is a saturated blue -
|
|
165
|
+
// dropped onto cream it reads as damage rather than as a highlight, and
|
|
166
|
+
// every component that fills with `selected` inherits that.
|
|
167
|
+
hover: '#f7f1e7',
|
|
168
|
+
active: '#efe4d2',
|
|
169
|
+
selected: '#eadcc6',
|
|
170
|
+
inverted: '#2b2a27',
|
|
171
|
+
focus: '#b4531f',
|
|
172
|
+
},
|
|
173
|
+
spacing: { none: 0, xs: 1, sm: 1, md: 2, lg: 3, xl: 4 },
|
|
174
|
+
components: {
|
|
175
|
+
Panel: { base: { border: 'none', padding: [1, 2] } },
|
|
176
|
+
Button: { base: { padding: [0, 2] } },
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/** Rounded chrome around a persistent frame. */
|
|
181
|
+
export const WORKBENCH: ThemeDefinition = {
|
|
182
|
+
id: 'workbench',
|
|
183
|
+
name: 'Workbench',
|
|
184
|
+
appearance: 'dark',
|
|
185
|
+
extends: 'dark',
|
|
186
|
+
border: 'round',
|
|
187
|
+
density: 'normal',
|
|
188
|
+
colors: {
|
|
189
|
+
canvas: '#1e1e2e',
|
|
190
|
+
surface: '#181825',
|
|
191
|
+
surfaceAlt: '#313244',
|
|
192
|
+
overlay: '#181825',
|
|
193
|
+
border: '#45475a',
|
|
194
|
+
borderStrong: '#585b70',
|
|
195
|
+
text: '#cdd6f4',
|
|
196
|
+
muted: '#a6adc8',
|
|
197
|
+
subtle: '#6c7086',
|
|
198
|
+
accent: '#89b4fa',
|
|
199
|
+
primary: '#89b4fa',
|
|
200
|
+
secondary: '#cba6f7',
|
|
201
|
+
success: '#a6e3a1',
|
|
202
|
+
warning: '#f9e2af',
|
|
203
|
+
danger: '#f38ba8',
|
|
204
|
+
info: '#89dceb',
|
|
205
|
+
hover: '#313244',
|
|
206
|
+
active: '#45475a',
|
|
207
|
+
selected: '#585b70',
|
|
208
|
+
focus: '#89b4fa',
|
|
209
|
+
scrim: '#11111b',
|
|
210
|
+
},
|
|
211
|
+
components: {
|
|
212
|
+
Panel: { base: { border: 'round' } },
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/** No colour at all. What a `colorDepth: 0` terminal or a pipe gets. */
|
|
217
|
+
export const MONO: ThemeDefinition = {
|
|
218
|
+
id: 'mono',
|
|
219
|
+
name: 'Monochrome',
|
|
220
|
+
appearance: 'dark',
|
|
221
|
+
border: 'ascii',
|
|
222
|
+
density: 'normal',
|
|
223
|
+
colors: {
|
|
224
|
+
canvas: 'default',
|
|
225
|
+
surface: 'default',
|
|
226
|
+
surfaceAlt: 'default',
|
|
227
|
+
overlay: 'default',
|
|
228
|
+
border: 'default',
|
|
229
|
+
borderStrong: 'default',
|
|
230
|
+
borderSubtle: 'default',
|
|
231
|
+
text: 'default',
|
|
232
|
+
muted: 'default',
|
|
233
|
+
subtle: 'default',
|
|
234
|
+
inverted: 'default',
|
|
235
|
+
accent: 'default',
|
|
236
|
+
primary: 'default',
|
|
237
|
+
secondary: 'default',
|
|
238
|
+
success: 'default',
|
|
239
|
+
warning: 'default',
|
|
240
|
+
danger: 'default',
|
|
241
|
+
info: 'default',
|
|
242
|
+
onAccent: 'default',
|
|
243
|
+
onPrimary: 'default',
|
|
244
|
+
onSuccess: 'default',
|
|
245
|
+
onWarning: 'default',
|
|
246
|
+
onDanger: 'default',
|
|
247
|
+
onInfo: 'default',
|
|
248
|
+
hover: 'default',
|
|
249
|
+
active: 'default',
|
|
250
|
+
selected: 'default',
|
|
251
|
+
focus: 'default',
|
|
252
|
+
disabled: 'default',
|
|
253
|
+
scrim: 'default',
|
|
254
|
+
cursor: 'default',
|
|
255
|
+
shadow: 'default',
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Paper, after dark.
|
|
261
|
+
*
|
|
262
|
+
* The same airy, borderless, warm-accented character as `paper` - the point of
|
|
263
|
+
* it is the restraint, not the brightness - with the ink and the page swapped.
|
|
264
|
+
* A warm dark rather than a blue one, so the two read as one family and a
|
|
265
|
+
* reader moving between them is not moving between two different products.
|
|
266
|
+
*/
|
|
267
|
+
export const PAPER_DARK: ThemeDefinition = {
|
|
268
|
+
id: 'paper-dark',
|
|
269
|
+
name: 'Paper Dark',
|
|
270
|
+
appearance: 'dark',
|
|
271
|
+
extends: 'dark',
|
|
272
|
+
border: 'none',
|
|
273
|
+
density: 'airy',
|
|
274
|
+
colors: {
|
|
275
|
+
canvas: '#1c1a17',
|
|
276
|
+
surface: '#1c1a17',
|
|
277
|
+
surfaceAlt: '#26231f',
|
|
278
|
+
border: '#3a352e',
|
|
279
|
+
borderSubtle: '#2a2621',
|
|
280
|
+
subtle: '#db8c4c',
|
|
281
|
+
text: '#e8e3d9',
|
|
282
|
+
muted: '#9a9287',
|
|
283
|
+
accent: '#e0873f',
|
|
284
|
+
primary: '#e0873f',
|
|
285
|
+
// The same restraint, the other way up.
|
|
286
|
+
hover: '#26231f',
|
|
287
|
+
active: '#332e27',
|
|
288
|
+
selected: '#3d362c',
|
|
289
|
+
inverted: '#f4efe6',
|
|
290
|
+
focus: '#e0873f',
|
|
291
|
+
},
|
|
292
|
+
spacing: { none: 0, xs: 1, sm: 1, md: 2, lg: 3, xl: 4 },
|
|
293
|
+
components: {
|
|
294
|
+
Panel: { base: { border: 'none', padding: [1, 2] } },
|
|
295
|
+
Button: { base: { padding: [0, 2] } },
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const BUILTIN_THEMES: ThemeDefinition[] = [
|
|
300
|
+
DARK, LIGHT, CONSOLE, PAPER, PAPER_DARK, WORKBENCH, MONO,
|
|
301
|
+
];
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { ThemeGlyphs } from '../types/theme.js';
|
|
2
|
+
import type { UnicodeLevel } from '../types/capabilities.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The glyph vocabulary, named by role.
|
|
6
|
+
*
|
|
7
|
+
* A component asks for `bulletFilled`, never for `'●'`, so the same catalog
|
|
8
|
+
* renders on a full-Unicode terminal and on one that can only do ASCII - and
|
|
9
|
+
* so a theme can restate the vocabulary without touching a component.
|
|
10
|
+
*/
|
|
11
|
+
export const FULL_GLYPHS: ThemeGlyphs = {
|
|
12
|
+
bulletFilled: '●',
|
|
13
|
+
bulletHollow: '○',
|
|
14
|
+
bulletHalf: '◌',
|
|
15
|
+
check: '✓',
|
|
16
|
+
cross: '✕',
|
|
17
|
+
warning: '⚠',
|
|
18
|
+
info: 'ℹ',
|
|
19
|
+
chevronRight: '▸',
|
|
20
|
+
chevronDown: '▾',
|
|
21
|
+
chevronLeft: '◂',
|
|
22
|
+
chevronUp: '▴',
|
|
23
|
+
arrowUp: '↑',
|
|
24
|
+
arrowDown: '↓',
|
|
25
|
+
ellipsis: '…',
|
|
26
|
+
search: '⌕',
|
|
27
|
+
radioOn: '●',
|
|
28
|
+
radioOff: '○',
|
|
29
|
+
checkboxOn: '■',
|
|
30
|
+
checkboxOff: '□',
|
|
31
|
+
checkboxMixed: '☒',
|
|
32
|
+
blocks: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'],
|
|
33
|
+
progressFull: '█',
|
|
34
|
+
progressEmpty: '░',
|
|
35
|
+
progressPartial: ['▏', '▎', '▍', '▌', '▋', '▊', '▉'],
|
|
36
|
+
spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
|
|
37
|
+
caret: '▏',
|
|
38
|
+
separator: '·',
|
|
39
|
+
breadcrumb: '›',
|
|
40
|
+
regionTop: '⬒',
|
|
41
|
+
regionBottom: '⬓',
|
|
42
|
+
regionLeft: '◧',
|
|
43
|
+
regionRight: '◨',
|
|
44
|
+
regionCentre: '▣',
|
|
45
|
+
regionOff: '□',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Box-drawing and geometric shapes only - no braille, no dingbats. */
|
|
49
|
+
export const BMP_GLYPHS: ThemeGlyphs = {
|
|
50
|
+
...FULL_GLYPHS,
|
|
51
|
+
check: '√',
|
|
52
|
+
cross: 'x',
|
|
53
|
+
info: 'i',
|
|
54
|
+
spinner: ['|', '/', '-', '\\'],
|
|
55
|
+
checkboxOn: '[x]',
|
|
56
|
+
checkboxOff: '[ ]',
|
|
57
|
+
checkboxMixed: '[-]',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const ASCII_GLYPHS: ThemeGlyphs = {
|
|
61
|
+
bulletFilled: '*',
|
|
62
|
+
bulletHollow: 'o',
|
|
63
|
+
bulletHalf: '+',
|
|
64
|
+
check: 'v',
|
|
65
|
+
cross: 'x',
|
|
66
|
+
warning: '!',
|
|
67
|
+
info: 'i',
|
|
68
|
+
chevronRight: '>',
|
|
69
|
+
chevronDown: 'v',
|
|
70
|
+
chevronLeft: '<',
|
|
71
|
+
chevronUp: '^',
|
|
72
|
+
arrowUp: '^',
|
|
73
|
+
arrowDown: 'v',
|
|
74
|
+
ellipsis: '...',
|
|
75
|
+
search: '/',
|
|
76
|
+
radioOn: '(*)',
|
|
77
|
+
radioOff: '( )',
|
|
78
|
+
checkboxOn: '[x]',
|
|
79
|
+
checkboxOff: '[ ]',
|
|
80
|
+
checkboxMixed: '[-]',
|
|
81
|
+
blocks: ['_', '.', ',', '-', '=', '+', '*', '#'],
|
|
82
|
+
progressFull: '#',
|
|
83
|
+
progressEmpty: '-',
|
|
84
|
+
progressPartial: ['-'],
|
|
85
|
+
spinner: ['|', '/', '-', '\\'],
|
|
86
|
+
caret: '_',
|
|
87
|
+
separator: '-',
|
|
88
|
+
breadcrumb: '>',
|
|
89
|
+
regionTop: '^',
|
|
90
|
+
regionBottom: 'v',
|
|
91
|
+
regionLeft: '[',
|
|
92
|
+
regionRight: ']',
|
|
93
|
+
regionCentre: '+',
|
|
94
|
+
regionOff: '.',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export function glyphsFor(unicode: UnicodeLevel): ThemeGlyphs {
|
|
98
|
+
if (unicode === 'ascii') return ASCII_GLYPHS;
|
|
99
|
+
if (unicode === 'bmp') return BMP_GLYPHS;
|
|
100
|
+
return FULL_GLYPHS;
|
|
101
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ResolvedTheme, ThemeDefinition, ThemeGlyphs, ThemeRegistry, ThemeSpacing,
|
|
3
|
+
} from '../types/theme.js';
|
|
4
|
+
import type { Color } from '../types/cells.js';
|
|
5
|
+
import type { BorderChars, BorderStyle, ColorToken, Density, StyleColor } from '../types/style.js';
|
|
6
|
+
import type { Style } from '../types/style.js';
|
|
7
|
+
import type { SyntaxScope } from '../types/syntax.js';
|
|
8
|
+
import type { TerminalCapabilities } from '../types/capabilities.js';
|
|
9
|
+
import type { Disposable } from '../types/disposable.js';
|
|
10
|
+
import { toDisposable } from '../util/disposable.js';
|
|
11
|
+
import { borderCharsFor } from './borders.js';
|
|
12
|
+
import { glyphsFor } from './glyphs.js';
|
|
13
|
+
import { BUILTIN_THEMES } from './builtin.js';
|
|
14
|
+
|
|
15
|
+
const DEFAULT_SPACING: ThemeSpacing = { none: 0, xs: 0, sm: 1, md: 1, lg: 2, xl: 3 };
|
|
16
|
+
|
|
17
|
+
const FALLBACK_COLORS: Record<ColorToken, Color> = {
|
|
18
|
+
canvas: 'default', surface: 'default', surfaceAlt: 'default', overlay: 'default',
|
|
19
|
+
border: 'default', borderStrong: 'default', borderSubtle: 'default',
|
|
20
|
+
text: 'default', muted: 'default', subtle: 'default', inverted: 'default',
|
|
21
|
+
accent: 'default', primary: 'default', secondary: 'default',
|
|
22
|
+
success: 'default', warning: 'default', danger: 'default', info: 'default',
|
|
23
|
+
onDefault: 'default', onMuted: 'default',
|
|
24
|
+
onAccent: 'default', onPrimary: 'default', onSecondary: 'default',
|
|
25
|
+
onSuccess: 'default', onWarning: 'default', onDanger: 'default', onInfo: 'default',
|
|
26
|
+
hover: 'default', active: 'default', selected: 'default', focus: 'default',
|
|
27
|
+
disabled: 'default', scrim: 'default', cursor: 'default', shadow: 'default',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* What each syntax scope means in semantic terms.
|
|
32
|
+
*
|
|
33
|
+
* Naming a token rather than a colour is what makes highlighting survive a
|
|
34
|
+
* theme swap: `paper` gets ink-on-white strings and `console` gets green ones
|
|
35
|
+
* from the same highlighter, and a theme with no palette at all - or a
|
|
36
|
+
* terminal with no colour - resolves the lot to the default foreground.
|
|
37
|
+
*/
|
|
38
|
+
const SYNTAX_DEFAULTS: Record<SyntaxScope, ColorToken> = {
|
|
39
|
+
plain: 'text',
|
|
40
|
+
keyword: 'primary',
|
|
41
|
+
string: 'success',
|
|
42
|
+
number: 'info',
|
|
43
|
+
boolean: 'warning',
|
|
44
|
+
null: 'muted',
|
|
45
|
+
comment: 'subtle',
|
|
46
|
+
punctuation: 'muted',
|
|
47
|
+
key: 'accent',
|
|
48
|
+
operator: 'text',
|
|
49
|
+
type: 'secondary',
|
|
50
|
+
function: 'accent',
|
|
51
|
+
tag: 'primary',
|
|
52
|
+
attribute: 'accent',
|
|
53
|
+
regexp: 'warning',
|
|
54
|
+
escape: 'warning',
|
|
55
|
+
invalid: 'danger',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** Tokens that are the accent rather than merely near it. */
|
|
59
|
+
const FOLLOWS_ACCENT = ['focus', 'cursor'] as const;
|
|
60
|
+
|
|
61
|
+
export class Themes implements ThemeRegistry {
|
|
62
|
+
private defs = new Map<string, ThemeDefinition>();
|
|
63
|
+
private cache = new Map<string, ResolvedTheme>();
|
|
64
|
+
|
|
65
|
+
constructor(initial: ThemeDefinition[] = BUILTIN_THEMES) {
|
|
66
|
+
for (const def of initial) this.defs.set(def.id, def);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
register(def: ThemeDefinition): Disposable {
|
|
70
|
+
this.defs.set(def.id, def);
|
|
71
|
+
this.cache.clear();
|
|
72
|
+
return toDisposable(() => {
|
|
73
|
+
this.defs.delete(def.id);
|
|
74
|
+
this.cache.clear();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
unregister(id: string): void {
|
|
79
|
+
this.defs.delete(id);
|
|
80
|
+
this.cache.clear();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get(id: string): ThemeDefinition | undefined {
|
|
84
|
+
return this.defs.get(id);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
list(): ThemeDefinition[] {
|
|
88
|
+
return [...this.defs.values()];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Flatten the `extends` chain, then degrade glyphs and borders to what the
|
|
93
|
+
* terminal can draw. Colour is *not* reduced here - the writer does that per
|
|
94
|
+
* cell against `colorDepth`, so one resolved theme serves every depth.
|
|
95
|
+
*/
|
|
96
|
+
resolve(id: string, caps: TerminalCapabilities): ResolvedTheme {
|
|
97
|
+
const key = `${id}:${caps.unicode}:${caps.colorDepth}`;
|
|
98
|
+
const cached = this.cache.get(key);
|
|
99
|
+
if (cached) return cached;
|
|
100
|
+
|
|
101
|
+
const chain: ThemeDefinition[] = [];
|
|
102
|
+
let cursor = this.defs.get(id);
|
|
103
|
+
const seen = new Set<string>();
|
|
104
|
+
while (cursor && !seen.has(cursor.id)) {
|
|
105
|
+
seen.add(cursor.id);
|
|
106
|
+
chain.unshift(cursor);
|
|
107
|
+
cursor = cursor.extends ? this.defs.get(cursor.extends) : undefined;
|
|
108
|
+
}
|
|
109
|
+
if (chain.length === 0) {
|
|
110
|
+
throw new Error(`[textui] no theme registered as "${id}"`);
|
|
111
|
+
}
|
|
112
|
+
const leaf = chain[chain.length - 1] as ThemeDefinition;
|
|
113
|
+
|
|
114
|
+
const colors = { ...FALLBACK_COLORS };
|
|
115
|
+
let spacing = { ...DEFAULT_SPACING };
|
|
116
|
+
let glyphOverrides: Partial<ThemeGlyphs> = {};
|
|
117
|
+
let border: BorderStyle = 'single';
|
|
118
|
+
let density: Density = 'normal';
|
|
119
|
+
const components: Record<string, Record<string, Style>> = {};
|
|
120
|
+
let syntaxOverrides: Partial<Record<SyntaxScope, StyleColor>> = {};
|
|
121
|
+
|
|
122
|
+
for (const def of chain) {
|
|
123
|
+
Object.assign(colors, def.colors);
|
|
124
|
+
// A theme that restates the accent restates what the accent is *for*.
|
|
125
|
+
//
|
|
126
|
+
// `focus` and `cursor` have no identity of their own - a focus ring and
|
|
127
|
+
// a caret are the accent, drawn somewhere. Left to a plain merge they
|
|
128
|
+
// keep whatever the extended theme set, so `console` overrode accent to
|
|
129
|
+
// teal and kept a blue focus ring, and `paper` went warm all over with a
|
|
130
|
+
// blue caret still in it. Accent teal here and blue there, in one theme.
|
|
131
|
+
//
|
|
132
|
+
// Only these two. `selected` and `active` are backgrounds that have to
|
|
133
|
+
// be dim or bright enough for the text on them, which is a decision
|
|
134
|
+
// about contrast rather than hue - a theme picks those itself.
|
|
135
|
+
const stated = def.colors ?? {};
|
|
136
|
+
if (stated.accent !== undefined) {
|
|
137
|
+
for (const token of FOLLOWS_ACCENT) {
|
|
138
|
+
if (stated[token] === undefined) colors[token] = stated.accent;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (def.syntax) syntaxOverrides = { ...syntaxOverrides, ...def.syntax };
|
|
142
|
+
if (def.spacing) spacing = { ...spacing, ...def.spacing };
|
|
143
|
+
if (def.glyphs) glyphOverrides = { ...glyphOverrides, ...def.glyphs };
|
|
144
|
+
if (def.border) border = def.border;
|
|
145
|
+
if (def.density) density = def.density;
|
|
146
|
+
for (const [name, variants] of Object.entries(def.components ?? {})) {
|
|
147
|
+
components[name] = { ...components[name], ...variants };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A colourless terminal gets no colour, whatever the theme says.
|
|
152
|
+
if (caps.colorDepth === 0) {
|
|
153
|
+
for (const token of Object.keys(colors) as ColorToken[]) {
|
|
154
|
+
colors[token] = 'default';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const syntax = {} as Record<SyntaxScope, Color>;
|
|
159
|
+
for (const [scope, token] of Object.entries(SYNTAX_DEFAULTS) as [SyntaxScope, ColorToken][]) {
|
|
160
|
+
const override = syntaxOverrides[scope];
|
|
161
|
+
syntax[scope] = override === undefined
|
|
162
|
+
? (colors[token] as Color)
|
|
163
|
+
: ((typeof override === 'string' && override in colors
|
|
164
|
+
? colors[override as ColorToken]
|
|
165
|
+
: override) as Color);
|
|
166
|
+
}
|
|
167
|
+
// A theme may name a literal colour for a scope, so blanking `colors` is
|
|
168
|
+
// not enough to make a colourless terminal colourless.
|
|
169
|
+
if (caps.colorDepth === 0) {
|
|
170
|
+
for (const scope of Object.keys(syntax) as SyntaxScope[]) syntax[scope] = 'default';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const glyphs: ThemeGlyphs = { ...glyphsFor(caps.unicode), ...glyphOverrides };
|
|
174
|
+
const charCache = new Map<BorderStyle, BorderChars>();
|
|
175
|
+
|
|
176
|
+
const resolved: ResolvedTheme = {
|
|
177
|
+
id: leaf.id,
|
|
178
|
+
name: leaf.name,
|
|
179
|
+
appearance: leaf.appearance,
|
|
180
|
+
colors,
|
|
181
|
+
spacing,
|
|
182
|
+
glyphs,
|
|
183
|
+
border,
|
|
184
|
+
density,
|
|
185
|
+
components,
|
|
186
|
+
syntax,
|
|
187
|
+
|
|
188
|
+
color(token: string): Color {
|
|
189
|
+
if (token in colors) return colors[token as ColorToken] as Color;
|
|
190
|
+
// Not a token: a literal colour passed straight through.
|
|
191
|
+
return token as Color;
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
borderChars(style?: BorderStyle): BorderChars {
|
|
195
|
+
const s = style ?? border;
|
|
196
|
+
let chars = charCache.get(s);
|
|
197
|
+
if (!chars) {
|
|
198
|
+
const base = borderCharsFor(s, caps.unicode);
|
|
199
|
+
const custom = leaf.borderChars?.[s];
|
|
200
|
+
chars = custom ? { ...base, ...custom } : base;
|
|
201
|
+
charCache.set(s, chars);
|
|
202
|
+
}
|
|
203
|
+
return chars;
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
styleFor(component: string, variants: string[] = []): Style {
|
|
207
|
+
const entry = components[component];
|
|
208
|
+
if (!entry) return {};
|
|
209
|
+
let out: Style = { ...entry.base };
|
|
210
|
+
for (const variant of variants) {
|
|
211
|
+
if (entry[variant]) out = { ...out, ...entry[variant] };
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
this.cache.set(key, resolved);
|
|
218
|
+
return resolved;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function createThemes(initial?: ThemeDefinition[]): Themes {
|
|
223
|
+
return new Themes(initial);
|
|
224
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Disposable } from './disposable.js';
|
|
2
|
+
import type { ComponentDefinition } from './component-registry.js';
|
|
3
|
+
import type { CommandDefinition } from './command.js';
|
|
4
|
+
import type { KeybindingDefinition } from './keybinding.js';
|
|
5
|
+
import type { HighlighterDefinition } from './syntax.js';
|
|
6
|
+
import type {
|
|
7
|
+
ResourceActionDefinition, ResourceEditorDefinition, ResourceKind,
|
|
8
|
+
ResourceProvider, ResourceViewerDefinition,
|
|
9
|
+
} from './resource.js';
|
|
10
|
+
import type { TextUIApp } from './app.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A resource adapter.
|
|
14
|
+
*
|
|
15
|
+
* Everything one resource type needs, in one value: what it is, where it comes
|
|
16
|
+
* from, what opens it, how it is coloured, and what can be done to it. The
|
|
17
|
+
* registries underneath stay separate - an adapter is a convenience for the
|
|
18
|
+
* author and a unit of undo for the application, not a new mechanism.
|
|
19
|
+
*
|
|
20
|
+
* Registering returns a `Disposable` that removes exactly what was added, so a
|
|
21
|
+
* plugin can be unloaded without the screen keeping a viewer nobody can
|
|
22
|
+
* explain.
|
|
23
|
+
*/
|
|
24
|
+
export interface ResourceAdapter {
|
|
25
|
+
id: string;
|
|
26
|
+
title?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
kinds?: ResourceKind[];
|
|
29
|
+
providers?: ResourceProvider[];
|
|
30
|
+
viewers?: ResourceViewerDefinition[];
|
|
31
|
+
editors?: ResourceEditorDefinition[];
|
|
32
|
+
actions?: ResourceActionDefinition[];
|
|
33
|
+
highlighters?: HighlighterDefinition[];
|
|
34
|
+
/** Commands the adapter contributes. Usually one per action. */
|
|
35
|
+
commands?: CommandDefinition[];
|
|
36
|
+
keybindings?: KeybindingDefinition[];
|
|
37
|
+
/** Components the viewers and editors name. */
|
|
38
|
+
components?: ComponentDefinition[];
|
|
39
|
+
/** Anything the fields above cannot express. */
|
|
40
|
+
register?(app: TextUIApp): Disposable | void;
|
|
41
|
+
}
|