@promptctl/rich-js 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/anchor.d.ts +45 -0
- package/dist/core/anchor.js +39 -0
- package/dist/core/ansi.d.ts +65 -0
- package/dist/core/ansi.js +231 -0
- package/dist/core/box.d.ts +143 -0
- package/dist/core/box.js +379 -0
- package/dist/core/cells.d.ts +159 -0
- package/dist/core/cells.js +287 -0
- package/dist/core/color.d.ts +246 -0
- package/dist/core/color.js +1038 -0
- package/dist/core/console.d.ts +165 -0
- package/dist/core/console.js +527 -0
- package/dist/core/emoji.d.ts +24 -0
- package/dist/core/emoji.js +391 -0
- package/dist/core/export-html.d.ts +59 -0
- package/dist/core/export-html.js +200 -0
- package/dist/core/export-lines.d.ts +121 -0
- package/dist/core/export-lines.js +141 -0
- package/dist/core/highlighter.d.ts +33 -0
- package/dist/core/highlighter.js +124 -0
- package/dist/core/json.d.ts +27 -0
- package/dist/core/json.js +53 -0
- package/dist/core/markup.d.ts +119 -0
- package/dist/core/markup.js +731 -0
- package/dist/core/measure.d.ts +27 -0
- package/dist/core/measure.js +62 -0
- package/dist/core/oklch.d.ts +161 -0
- package/dist/core/oklch.js +312 -0
- package/dist/core/osc8.d.ts +68 -0
- package/dist/core/osc8.js +90 -0
- package/dist/core/place.d.ts +30 -0
- package/dist/core/place.js +51 -0
- package/dist/core/pretty.d.ts +144 -0
- package/dist/core/pretty.js +476 -0
- package/dist/core/protocol.d.ts +267 -0
- package/dist/core/protocol.js +163 -0
- package/dist/core/render.d.ts +84 -0
- package/dist/core/render.js +145 -0
- package/dist/core/segment.d.ts +161 -0
- package/dist/core/segment.js +492 -0
- package/dist/core/spinnerData.d.ts +12 -0
- package/dist/core/spinnerData.js +117 -0
- package/dist/core/strip.d.ts +141 -0
- package/dist/core/strip.js +305 -0
- package/dist/core/style.d.ts +169 -0
- package/dist/core/style.js +695 -0
- package/dist/core/subscription.d.ts +12 -0
- package/dist/core/subscription.js +12 -0
- package/dist/core/text.d.ts +256 -0
- package/dist/core/text.js +976 -0
- package/dist/core/wrap.d.ts +41 -0
- package/dist/core/wrap.js +127 -0
- package/dist/host/app.d.ts +121 -0
- package/dist/host/app.js +255 -0
- package/dist/host/host-environment.d.ts +26 -0
- package/dist/host/host-environment.js +44 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.js +3 -0
- package/dist/host/terminal-host.d.ts +179 -0
- package/dist/host/terminal-host.js +186 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +107 -0
- package/dist/node/prompt.d.ts +21 -0
- package/dist/node/prompt.js +30 -0
- package/dist/node/save.d.ts +17 -0
- package/dist/node/save.js +21 -0
- package/dist/node/terminal-host.d.ts +113 -0
- package/dist/node/terminal-host.js +227 -0
- package/dist/node/traceback.d.ts +37 -0
- package/dist/node/traceback.js +134 -0
- package/dist/renderables/align.d.ts +16 -0
- package/dist/renderables/align.js +33 -0
- package/dist/renderables/columns.d.ts +61 -0
- package/dist/renderables/columns.js +152 -0
- package/dist/renderables/constrain.d.ts +15 -0
- package/dist/renderables/constrain.js +37 -0
- package/dist/renderables/embed.d.ts +50 -0
- package/dist/renderables/embed.js +71 -0
- package/dist/renderables/flexStrip.d.ts +41 -0
- package/dist/renderables/flexStrip.js +200 -0
- package/dist/renderables/group.d.ts +11 -0
- package/dist/renderables/group.js +17 -0
- package/dist/renderables/layout.d.ts +92 -0
- package/dist/renderables/layout.js +312 -0
- package/dist/renderables/live.d.ts +50 -0
- package/dist/renderables/live.js +175 -0
- package/dist/renderables/markdown.d.ts +24 -0
- package/dist/renderables/markdown.js +184 -0
- package/dist/renderables/padding.d.ts +38 -0
- package/dist/renderables/padding.js +141 -0
- package/dist/renderables/panel.d.ts +116 -0
- package/dist/renderables/panel.js +307 -0
- package/dist/renderables/progress.d.ts +90 -0
- package/dist/renderables/progress.js +238 -0
- package/dist/renderables/progressBar.d.ts +31 -0
- package/dist/renderables/progressBar.js +53 -0
- package/dist/renderables/prompt.d.ts +49 -0
- package/dist/renderables/prompt.js +125 -0
- package/dist/renderables/rule.d.ts +25 -0
- package/dist/renderables/rule.js +90 -0
- package/dist/renderables/spinner.d.ts +31 -0
- package/dist/renderables/spinner.js +70 -0
- package/dist/renderables/status.d.ts +23 -0
- package/dist/renderables/status.js +60 -0
- package/dist/renderables/syntax.d.ts +35 -0
- package/dist/renderables/syntax.js +115 -0
- package/dist/renderables/table.d.ts +194 -0
- package/dist/renderables/table.js +795 -0
- package/dist/renderables/traceback.d.ts +31 -0
- package/dist/renderables/traceback.js +108 -0
- package/dist/renderables/tree.d.ts +68 -0
- package/dist/renderables/tree.js +150 -0
- package/dist/renderables/viewport.d.ts +114 -0
- package/dist/renderables/viewport.js +198 -0
- package/dist/template-bindings/color-funcs.d.ts +87 -0
- package/dist/template-bindings/color-funcs.js +217 -0
- package/dist/template-bindings/helpers.d.ts +24 -0
- package/dist/template-bindings/helpers.js +48 -0
- package/dist/template-bindings/index.d.ts +107 -0
- package/dist/template-bindings/index.js +146 -0
- package/dist/template-bindings/palette-funcs.d.ts +94 -0
- package/dist/template-bindings/palette-funcs.js +141 -0
- package/dist/template-bindings/style-funcs.d.ts +28 -0
- package/dist/template-bindings/style-funcs.js +155 -0
- package/dist/themes/buildPalette.d.ts +36 -0
- package/dist/themes/buildPalette.js +56 -0
- package/dist/themes/colorMath.d.ts +82 -0
- package/dist/themes/colorMath.js +254 -0
- package/dist/themes/colorRef.d.ts +51 -0
- package/dist/themes/colorRef.js +96 -0
- package/dist/themes/data/ansi-tables.d.ts +14 -0
- package/dist/themes/data/ansi-tables.js +49 -0
- package/dist/themes/data/atom-one-dark.d.ts +3 -0
- package/dist/themes/data/atom-one-dark.js +177 -0
- package/dist/themes/data/atom-one-light.d.ts +3 -0
- package/dist/themes/data/atom-one-light.js +177 -0
- package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
- package/dist/themes/data/catppuccin-frappe.js +177 -0
- package/dist/themes/data/catppuccin-latte.d.ts +3 -0
- package/dist/themes/data/catppuccin-latte.js +177 -0
- package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
- package/dist/themes/data/catppuccin-macchiato.js +177 -0
- package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
- package/dist/themes/data/catppuccin-mocha.js +177 -0
- package/dist/themes/data/cyberpunk.d.ts +17 -0
- package/dist/themes/data/cyberpunk.js +193 -0
- package/dist/themes/data/default.d.ts +3 -0
- package/dist/themes/data/default.js +160 -0
- package/dist/themes/data/dracula.d.ts +3 -0
- package/dist/themes/data/dracula.js +177 -0
- package/dist/themes/data/flexoki.d.ts +3 -0
- package/dist/themes/data/flexoki.js +177 -0
- package/dist/themes/data/gruvbox.d.ts +3 -0
- package/dist/themes/data/gruvbox.js +177 -0
- package/dist/themes/data/index.d.ts +35 -0
- package/dist/themes/data/index.js +64 -0
- package/dist/themes/data/monokai.d.ts +3 -0
- package/dist/themes/data/monokai.js +177 -0
- package/dist/themes/data/nord.d.ts +3 -0
- package/dist/themes/data/nord.js +177 -0
- package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
- package/dist/themes/data/rose-pine-dawn.js +177 -0
- package/dist/themes/data/rose-pine-moon.d.ts +3 -0
- package/dist/themes/data/rose-pine-moon.js +177 -0
- package/dist/themes/data/rose-pine.d.ts +3 -0
- package/dist/themes/data/rose-pine.js +177 -0
- package/dist/themes/data/solarized-dark.d.ts +3 -0
- package/dist/themes/data/solarized-dark.js +177 -0
- package/dist/themes/data/solarized-light.d.ts +3 -0
- package/dist/themes/data/solarized-light.js +177 -0
- package/dist/themes/data/svg-export.d.ts +3 -0
- package/dist/themes/data/svg-export.js +177 -0
- package/dist/themes/data/textual-ansi.d.ts +3 -0
- package/dist/themes/data/textual-ansi.js +160 -0
- package/dist/themes/data/textual-dark.d.ts +3 -0
- package/dist/themes/data/textual-dark.js +160 -0
- package/dist/themes/data/textual-light.d.ts +3 -0
- package/dist/themes/data/textual-light.js +160 -0
- package/dist/themes/data/tokyo-night.d.ts +3 -0
- package/dist/themes/data/tokyo-night.js +177 -0
- package/dist/themes/data/types.d.ts +31 -0
- package/dist/themes/data/types.js +10 -0
- package/dist/themes/palette.d.ts +21 -0
- package/dist/themes/palette.js +28 -0
- package/dist/themes/ramp.d.ts +83 -0
- package/dist/themes/ramp.js +122 -0
- package/dist/themes/registry.d.ts +44 -0
- package/dist/themes/registry.js +94 -0
- package/dist/themes/terminalThemes.d.ts +49 -0
- package/dist/themes/terminalThemes.js +63 -0
- package/dist/themes/transpose.d.ts +87 -0
- package/dist/themes/transpose.js +138 -0
- package/dist/widgets/button.d.ts +49 -0
- package/dist/widgets/button.js +208 -0
- package/dist/widgets/checkbox.d.ts +41 -0
- package/dist/widgets/checkbox.js +157 -0
- package/dist/widgets/dropdown.d.ts +67 -0
- package/dist/widgets/dropdown.js +450 -0
- package/dist/widgets/event-router.d.ts +71 -0
- package/dist/widgets/event-router.js +629 -0
- package/dist/widgets/focus-manager.d.ts +45 -0
- package/dist/widgets/focus-manager.js +191 -0
- package/dist/widgets/hit.d.ts +64 -0
- package/dist/widgets/hit.js +113 -0
- package/dist/widgets/index.d.ts +20 -0
- package/dist/widgets/index.js +14 -0
- package/dist/widgets/slider.d.ts +57 -0
- package/dist/widgets/slider.js +270 -0
- package/dist/widgets/static-item.d.ts +34 -0
- package/dist/widgets/static-item.js +54 -0
- package/dist/widgets/text-input.d.ts +274 -0
- package/dist/widgets/text-input.js +1165 -0
- package/dist/widgets/toggle.d.ts +44 -0
- package/dist/widgets/toggle.js +180 -0
- package/dist/widgets/types.d.ts +87 -0
- package/dist/widgets/types.js +30 -0
- package/dist/widgets/widget-app.d.ts +63 -0
- package/dist/widgets/widget-app.js +199 -0
- package/dist/widgets/widget-base.d.ts +40 -0
- package/dist/widgets/widget-base.js +165 -0
- package/package.json +6 -2
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emoji shortcode support — dictionary, replacement, and renderable.
|
|
3
|
+
*/
|
|
4
|
+
import { Segment } from "./segment.js";
|
|
5
|
+
// [LAW:one-source-of-truth] Single emoji dictionary for all shortcode lookups
|
|
6
|
+
export const EMOJI = {
|
|
7
|
+
// Faces
|
|
8
|
+
smile: "😄",
|
|
9
|
+
laugh: "😂",
|
|
10
|
+
grinning: "😀",
|
|
11
|
+
wink: "😉",
|
|
12
|
+
blush: "😊",
|
|
13
|
+
innocent: "😇",
|
|
14
|
+
heart_eyes: "😍",
|
|
15
|
+
kissing: "😘",
|
|
16
|
+
thinking: "🤔",
|
|
17
|
+
shushing: "🤫",
|
|
18
|
+
zipper_mouth: "🤐",
|
|
19
|
+
raised_eyebrow: "🤨",
|
|
20
|
+
neutral: "😐",
|
|
21
|
+
expressionless: "😑",
|
|
22
|
+
unamused: "😒",
|
|
23
|
+
rolling_eyes: "🙄",
|
|
24
|
+
grimacing: "😬",
|
|
25
|
+
lying: "🤥",
|
|
26
|
+
relieved: "😌",
|
|
27
|
+
pensive: "😔",
|
|
28
|
+
sleepy: "😪",
|
|
29
|
+
sleeping: "😴",
|
|
30
|
+
mask: "😷",
|
|
31
|
+
thermometer_face: "🤒",
|
|
32
|
+
bandage_face: "🤕",
|
|
33
|
+
nauseated: "🤢",
|
|
34
|
+
sneezing: "🤧",
|
|
35
|
+
cold_face: "🥶",
|
|
36
|
+
hot_face: "🥵",
|
|
37
|
+
dizzy_face: "😵",
|
|
38
|
+
exploding_head: "🤯",
|
|
39
|
+
cowboy: "🤠",
|
|
40
|
+
party_face: "🥳",
|
|
41
|
+
sunglasses: "😎",
|
|
42
|
+
nerd: "🤓",
|
|
43
|
+
monocle: "🧐",
|
|
44
|
+
confused: "😕",
|
|
45
|
+
worried: "😟",
|
|
46
|
+
frowning: "☹",
|
|
47
|
+
open_mouth: "😮",
|
|
48
|
+
hushed: "😯",
|
|
49
|
+
astonished: "😲",
|
|
50
|
+
flushed: "😳",
|
|
51
|
+
pleading: "🥺",
|
|
52
|
+
cry: "😢",
|
|
53
|
+
sob: "😭",
|
|
54
|
+
scream: "😱",
|
|
55
|
+
sweat: "😰",
|
|
56
|
+
angry: "😡",
|
|
57
|
+
rage: "🤬",
|
|
58
|
+
devil: "😈",
|
|
59
|
+
skull: "💀",
|
|
60
|
+
poop: "💩",
|
|
61
|
+
clown: "🤡",
|
|
62
|
+
ghost: "👻",
|
|
63
|
+
alien: "👽",
|
|
64
|
+
robot: "🤖",
|
|
65
|
+
// Hands
|
|
66
|
+
wave: "👋",
|
|
67
|
+
raised_hand: "✋",
|
|
68
|
+
ok_hand: "👌",
|
|
69
|
+
pinching: "🤏",
|
|
70
|
+
victory: "✌",
|
|
71
|
+
crossed_fingers: "🤞",
|
|
72
|
+
love_you: "🤟",
|
|
73
|
+
rock_on: "🤘",
|
|
74
|
+
thumbs_up: "👍",
|
|
75
|
+
thumbs_down: "👎",
|
|
76
|
+
fist: "✊",
|
|
77
|
+
punch: "👊",
|
|
78
|
+
left_fist: "🤛",
|
|
79
|
+
right_fist: "🤜",
|
|
80
|
+
clap: "👏",
|
|
81
|
+
raised_hands: "🙌",
|
|
82
|
+
open_hands: "👐",
|
|
83
|
+
palms_up: "🤲",
|
|
84
|
+
handshake: "🤝",
|
|
85
|
+
pray: "🙏",
|
|
86
|
+
writing_hand: "✍",
|
|
87
|
+
nail_polish: "💅",
|
|
88
|
+
muscle: "💪",
|
|
89
|
+
point_up: "☝",
|
|
90
|
+
point_up_2: "👆",
|
|
91
|
+
point_down: "👇",
|
|
92
|
+
point_left: "👈",
|
|
93
|
+
point_right: "👉",
|
|
94
|
+
middle_finger: "🖕",
|
|
95
|
+
// Hearts
|
|
96
|
+
heart: "❤",
|
|
97
|
+
orange_heart: "🧡",
|
|
98
|
+
yellow_heart: "💛",
|
|
99
|
+
green_heart: "💚",
|
|
100
|
+
blue_heart: "💙",
|
|
101
|
+
purple_heart: "💜",
|
|
102
|
+
black_heart: "🖤",
|
|
103
|
+
white_heart: "🤍",
|
|
104
|
+
brown_heart: "🤎",
|
|
105
|
+
broken_heart: "💔",
|
|
106
|
+
heart_exclamation: "❣",
|
|
107
|
+
two_hearts: "💕",
|
|
108
|
+
revolving_hearts: "💞",
|
|
109
|
+
heartbeat: "💓",
|
|
110
|
+
heartpulse: "💗",
|
|
111
|
+
sparkling_heart: "💖",
|
|
112
|
+
growing_heart: "💗",
|
|
113
|
+
cupid: "💘",
|
|
114
|
+
gift_heart: "💝",
|
|
115
|
+
// Objects & Symbols
|
|
116
|
+
fire: "🔥",
|
|
117
|
+
star: "⭐",
|
|
118
|
+
star2: "🌟",
|
|
119
|
+
sparkles: "✨",
|
|
120
|
+
zap: "⚡",
|
|
121
|
+
boom: "💥",
|
|
122
|
+
droplet: "💧",
|
|
123
|
+
rainbow: "🌈",
|
|
124
|
+
sun: "☀",
|
|
125
|
+
moon: "🌙",
|
|
126
|
+
cloud: "☁",
|
|
127
|
+
snowflake: "❄",
|
|
128
|
+
umbrella: "☂",
|
|
129
|
+
// Status
|
|
130
|
+
check: "✅",
|
|
131
|
+
check_mark: "✔",
|
|
132
|
+
cross_mark: "❌",
|
|
133
|
+
warning: "⚠",
|
|
134
|
+
info: "ℹ",
|
|
135
|
+
question: "❓",
|
|
136
|
+
exclamation: "❗",
|
|
137
|
+
no_entry: "⛔",
|
|
138
|
+
prohibited: "🚫",
|
|
139
|
+
stop_sign: "🛑",
|
|
140
|
+
// Arrows
|
|
141
|
+
arrow_up: "⬆",
|
|
142
|
+
arrow_down: "⬇",
|
|
143
|
+
arrow_left: "⬅",
|
|
144
|
+
arrow_right: "➡",
|
|
145
|
+
arrow_upper_left: "↖",
|
|
146
|
+
arrow_upper_right: "↗",
|
|
147
|
+
arrow_lower_left: "↙",
|
|
148
|
+
arrow_lower_right: "↘",
|
|
149
|
+
left_right_arrow: "↔",
|
|
150
|
+
up_down_arrow: "↕",
|
|
151
|
+
arrows_clockwise: "🔃",
|
|
152
|
+
arrows_counterclockwise: "🔄",
|
|
153
|
+
// Tech
|
|
154
|
+
computer: "💻",
|
|
155
|
+
keyboard: "⌨",
|
|
156
|
+
desktop: "🖥",
|
|
157
|
+
printer: "🖨",
|
|
158
|
+
mouse: "🖱",
|
|
159
|
+
cd: "💿",
|
|
160
|
+
dvd: "📀",
|
|
161
|
+
floppy: "💾",
|
|
162
|
+
battery: "🔋",
|
|
163
|
+
plug: "🔌",
|
|
164
|
+
bulb: "💡",
|
|
165
|
+
flashlight: "🔦",
|
|
166
|
+
gear: "⚙",
|
|
167
|
+
wrench: "🔧",
|
|
168
|
+
hammer: "🔨",
|
|
169
|
+
nut_and_bolt: "🔩",
|
|
170
|
+
link: "🔗",
|
|
171
|
+
chains: "⛓",
|
|
172
|
+
lock: "🔒",
|
|
173
|
+
unlock: "🔓",
|
|
174
|
+
key: "🔑",
|
|
175
|
+
shield: "🛡",
|
|
176
|
+
bug: "🐛",
|
|
177
|
+
magnifying_glass: "🔍",
|
|
178
|
+
// Communication
|
|
179
|
+
speech_balloon: "💬",
|
|
180
|
+
thought_balloon: "💭",
|
|
181
|
+
megaphone: "📣",
|
|
182
|
+
loudspeaker: "📢",
|
|
183
|
+
bell: "🔔",
|
|
184
|
+
no_bell: "🔕",
|
|
185
|
+
envelope: "✉",
|
|
186
|
+
email: "📧",
|
|
187
|
+
inbox: "📥",
|
|
188
|
+
outbox: "📤",
|
|
189
|
+
package: "📦",
|
|
190
|
+
clipboard: "📋",
|
|
191
|
+
memo: "📝",
|
|
192
|
+
page: "📄",
|
|
193
|
+
bookmark: "🔖",
|
|
194
|
+
label: "🏷",
|
|
195
|
+
// Time
|
|
196
|
+
hourglass: "⌛",
|
|
197
|
+
hourglass_flowing: "⏳",
|
|
198
|
+
watch: "⌚",
|
|
199
|
+
alarm_clock: "⏰",
|
|
200
|
+
stopwatch: "⏱",
|
|
201
|
+
timer: "⏲",
|
|
202
|
+
clock: "🕐",
|
|
203
|
+
// Numbers
|
|
204
|
+
zero: "0️⃣",
|
|
205
|
+
one: "1️⃣",
|
|
206
|
+
two: "2️⃣",
|
|
207
|
+
three: "3️⃣",
|
|
208
|
+
four: "4️⃣",
|
|
209
|
+
five: "5️⃣",
|
|
210
|
+
six: "6️⃣",
|
|
211
|
+
seven: "7️⃣",
|
|
212
|
+
eight: "8️⃣",
|
|
213
|
+
nine: "9️⃣",
|
|
214
|
+
ten: "🔟",
|
|
215
|
+
hash: "#️⃣",
|
|
216
|
+
// Food & Drink
|
|
217
|
+
coffee: "☕",
|
|
218
|
+
tea: "🍵",
|
|
219
|
+
beer: "🍺",
|
|
220
|
+
wine: "🍷",
|
|
221
|
+
cocktail: "🍸",
|
|
222
|
+
pizza: "🍕",
|
|
223
|
+
hamburger: "🍔",
|
|
224
|
+
fries: "🍟",
|
|
225
|
+
hotdog: "🌭",
|
|
226
|
+
taco: "🌮",
|
|
227
|
+
cake: "🎂",
|
|
228
|
+
cookie: "🍪",
|
|
229
|
+
chocolate: "🍫",
|
|
230
|
+
candy: "🍬",
|
|
231
|
+
apple: "🍎",
|
|
232
|
+
banana: "🍌",
|
|
233
|
+
// Nature & Animals
|
|
234
|
+
dog: "🐕",
|
|
235
|
+
cat: "🐈",
|
|
236
|
+
snake: "🐍",
|
|
237
|
+
turtle: "🐢",
|
|
238
|
+
whale: "🐳",
|
|
239
|
+
dolphin: "🐬",
|
|
240
|
+
fish: "🐟",
|
|
241
|
+
butterfly: "🦋",
|
|
242
|
+
bee: "🐝",
|
|
243
|
+
ladybug: "🐞",
|
|
244
|
+
spider: "🕷",
|
|
245
|
+
tree: "🌲",
|
|
246
|
+
flower: "🌸",
|
|
247
|
+
rose: "🌹",
|
|
248
|
+
sunflower: "🌻",
|
|
249
|
+
cactus: "🌵",
|
|
250
|
+
// Activities
|
|
251
|
+
trophy: "🏆",
|
|
252
|
+
medal: "🏅",
|
|
253
|
+
crown: "👑",
|
|
254
|
+
gem: "💎",
|
|
255
|
+
money_bag: "💰",
|
|
256
|
+
dollar: "💵",
|
|
257
|
+
rocket: "🚀",
|
|
258
|
+
airplane: "✈",
|
|
259
|
+
car: "🚗",
|
|
260
|
+
bicycle: "🚲",
|
|
261
|
+
house: "🏠",
|
|
262
|
+
building: "🏢",
|
|
263
|
+
globe: "🌍",
|
|
264
|
+
world_map: "🗺",
|
|
265
|
+
flag: "🏁",
|
|
266
|
+
party: "🎉",
|
|
267
|
+
confetti: "🎊",
|
|
268
|
+
balloon: "🎈",
|
|
269
|
+
gift: "🎁",
|
|
270
|
+
art: "🎨",
|
|
271
|
+
music: "🎵",
|
|
272
|
+
notes: "🎶",
|
|
273
|
+
microphone: "🎤",
|
|
274
|
+
headphones: "🎧",
|
|
275
|
+
movie: "🎬",
|
|
276
|
+
camera: "📷",
|
|
277
|
+
book: "📖",
|
|
278
|
+
books: "📚",
|
|
279
|
+
scroll: "📜",
|
|
280
|
+
newspaper: "📰",
|
|
281
|
+
// People
|
|
282
|
+
person: "🧑",
|
|
283
|
+
man: "👨",
|
|
284
|
+
woman: "👩",
|
|
285
|
+
child: "🧒",
|
|
286
|
+
baby: "👶",
|
|
287
|
+
eyes: "👀",
|
|
288
|
+
eye: "👁",
|
|
289
|
+
brain: "🧠",
|
|
290
|
+
tongue: "👅",
|
|
291
|
+
ear: "👂",
|
|
292
|
+
nose: "👃",
|
|
293
|
+
foot: "🦶",
|
|
294
|
+
hand: "🤚",
|
|
295
|
+
// Misc
|
|
296
|
+
red_circle: "🔴",
|
|
297
|
+
orange_circle: "🟠",
|
|
298
|
+
yellow_circle: "🟡",
|
|
299
|
+
green_circle: "🟢",
|
|
300
|
+
blue_circle: "🔵",
|
|
301
|
+
purple_circle: "🟣",
|
|
302
|
+
black_circle: "⚫",
|
|
303
|
+
white_circle: "⚪",
|
|
304
|
+
red_square: "🟥",
|
|
305
|
+
orange_square: "🟧",
|
|
306
|
+
yellow_square: "🟨",
|
|
307
|
+
green_square: "🟩",
|
|
308
|
+
blue_square: "🟦",
|
|
309
|
+
purple_square: "🟪",
|
|
310
|
+
black_square: "⬛",
|
|
311
|
+
white_square: "⬜",
|
|
312
|
+
checkered_flag: "🏁",
|
|
313
|
+
triangular_flag: "🚩",
|
|
314
|
+
crossed_flags: "🎌",
|
|
315
|
+
pirate_flag: "🏴☠️",
|
|
316
|
+
white_flag: "🏳",
|
|
317
|
+
100: "💯",
|
|
318
|
+
infinity: "♾",
|
|
319
|
+
recycle: "♻",
|
|
320
|
+
peace: "☮",
|
|
321
|
+
yin_yang: "☯",
|
|
322
|
+
cross: "✝",
|
|
323
|
+
atom: "⚛",
|
|
324
|
+
radioactive: "☢",
|
|
325
|
+
biohazard: "☣",
|
|
326
|
+
};
|
|
327
|
+
const EMOJI_PATTERN = /:([a-z0-9_]+(?:-(?:emoji|text))?):/g;
|
|
328
|
+
/**
|
|
329
|
+
* Replaces :shortcode: patterns in text with emoji characters.
|
|
330
|
+
*/
|
|
331
|
+
export function emojiReplace(text, defaultVariant) {
|
|
332
|
+
return text.replace(EMOJI_PATTERN, (_match, code) => {
|
|
333
|
+
let variant = defaultVariant;
|
|
334
|
+
let name = code;
|
|
335
|
+
// Check for inline variant suffix
|
|
336
|
+
if (name.endsWith("-emoji")) {
|
|
337
|
+
variant = "emoji";
|
|
338
|
+
name = name.slice(0, -6);
|
|
339
|
+
}
|
|
340
|
+
else if (name.endsWith("-text")) {
|
|
341
|
+
variant = "text";
|
|
342
|
+
name = name.slice(0, -5);
|
|
343
|
+
}
|
|
344
|
+
const emoji = EMOJI[name];
|
|
345
|
+
if (emoji === undefined)
|
|
346
|
+
return _match; // Not found, leave unchanged
|
|
347
|
+
// Apply variant selector
|
|
348
|
+
// [LAW:dataflow-not-control-flow] Always compute suffix, let the value decide
|
|
349
|
+
const suffix = variant === "emoji"
|
|
350
|
+
? "\uFE0F"
|
|
351
|
+
: variant === "text"
|
|
352
|
+
? "\uFE0E"
|
|
353
|
+
: "";
|
|
354
|
+
return emoji + suffix;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
export class NoEmoji extends Error {
|
|
358
|
+
constructor(name) {
|
|
359
|
+
super(`No emoji with name: "${name}"`);
|
|
360
|
+
this.name = "NoEmoji";
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
export class Emoji {
|
|
364
|
+
name;
|
|
365
|
+
_char;
|
|
366
|
+
_style;
|
|
367
|
+
_variant;
|
|
368
|
+
constructor(name, style, variant) {
|
|
369
|
+
const emoji = EMOJI[name];
|
|
370
|
+
if (emoji === undefined)
|
|
371
|
+
throw new NoEmoji(name);
|
|
372
|
+
this.name = name;
|
|
373
|
+
this._char = emoji;
|
|
374
|
+
this._style = style;
|
|
375
|
+
this._variant = variant;
|
|
376
|
+
}
|
|
377
|
+
toString() {
|
|
378
|
+
const suffix = this._variant === "emoji"
|
|
379
|
+
? "\uFE0F"
|
|
380
|
+
: this._variant === "text"
|
|
381
|
+
? "\uFE0E"
|
|
382
|
+
: "";
|
|
383
|
+
return this._char + suffix;
|
|
384
|
+
}
|
|
385
|
+
*render(_options) {
|
|
386
|
+
yield new Segment(this.toString(), this._style);
|
|
387
|
+
}
|
|
388
|
+
static replace(text) {
|
|
389
|
+
return emojiReplace(text);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* export-html — recorded segments drawn as HTML: a fragment that can sit in
|
|
3
|
+
* a page this library does not own, and a standalone document around it.
|
|
4
|
+
*
|
|
5
|
+
* An encoding of `export-lines` and nothing more. What a run looks like under
|
|
6
|
+
* a theme is decided there; this module decides only how CSS says it. It never
|
|
7
|
+
* sees a `Style`, so it cannot disagree with the SVG exporter about what
|
|
8
|
+
* `reverse` or `dim` means — the two old converters that did disagree were
|
|
9
|
+
* deleted when this replaced them.
|
|
10
|
+
*
|
|
11
|
+
* The rows are already laid out at console width, so `pre` never re-wraps
|
|
12
|
+
* them: `white-space: pre`, and a scrollbar rather than a reflow when the page
|
|
13
|
+
* is narrower than the terminal was.
|
|
14
|
+
*/
|
|
15
|
+
import type { TerminalTheme } from "./color.js";
|
|
16
|
+
import type { Segment } from "./segment.js";
|
|
17
|
+
/**
|
|
18
|
+
* The CSS a page includes once, wherever fragments appear: what an inline
|
|
19
|
+
* style cannot say. A fragment that blinks draws steadily without it.
|
|
20
|
+
*
|
|
21
|
+
* The keyframes exist only for a reader who has not asked for reduced motion,
|
|
22
|
+
* so for one who has, the inline `animation` names nothing and the glyph holds
|
|
23
|
+
* still. One rule, so no second rule's order or survival in a host's CSS
|
|
24
|
+
* pipeline can bring the blink back.
|
|
25
|
+
*/
|
|
26
|
+
export declare const HTML_FRAGMENT_CSS = "@media (prefers-reduced-motion:no-preference){@keyframes rich-blink{50%{color:transparent}}}";
|
|
27
|
+
/**
|
|
28
|
+
* `segments` under `theme` as one `pre` carrying its canvas, for embedding.
|
|
29
|
+
*
|
|
30
|
+
* [LAW:locality-or-seam] Every rule is inline on the `pre` or below it, so the
|
|
31
|
+
* fragment styles nothing outside itself; the host page keeps its own `body`,
|
|
32
|
+
* `pre` and `a` rules. The seam holds the other way too: `all:initial` stops
|
|
33
|
+
* the host's `pre` rules and inherited typography from reaching the rows, and
|
|
34
|
+
* the two properties `all` does not cover pin the rows left to right.
|
|
35
|
+
*
|
|
36
|
+
* The one way in is the `--rich-fragment-font` custom property, read as the
|
|
37
|
+
* `font` shorthand (`14px/1.3 "JetBrains Mono", monospace`). `all` resets no
|
|
38
|
+
* custom property, so a host sets it on any ancestor to draw the rows in its
|
|
39
|
+
* own code font; unset, the rows are the browser's default monospace at a
|
|
40
|
+
* fixed line height, as a terminal's rows are. A host's value wants one too: at
|
|
41
|
+
* `normal`, a row holding a glyph from a taller fallback font grows and shifts
|
|
42
|
+
* every row below it. It must be a whole shorthand, a size and a family at
|
|
43
|
+
* least: any other value is invalid when computed, and the rows then inherit
|
|
44
|
+
* the host's font.
|
|
45
|
+
*
|
|
46
|
+
* A browser draws no line for a newline at either edge of a `pre`: the parser
|
|
47
|
+
* drops the one straight after the open tag, and the one before `</pre>` ends a
|
|
48
|
+
* line without starting another. So the fragment opens with a newline of its
|
|
49
|
+
* own and every row ends with one, and a blank first or last row is still drawn.
|
|
50
|
+
*/
|
|
51
|
+
export declare function encodeHtmlFragment(segments: Iterable<Segment>, theme?: TerminalTheme): string;
|
|
52
|
+
/**
|
|
53
|
+
* `segments` under `theme` as a complete HTML document.
|
|
54
|
+
*
|
|
55
|
+
* [LAW:one-source-of-truth] The document is the fragment in a shell, so the
|
|
56
|
+
* two cannot draw different pictures. The shell paints the page around the
|
|
57
|
+
* `pre` in the same canvas and includes the fragment CSS once.
|
|
58
|
+
*/
|
|
59
|
+
export declare function encodeHtml(segments: Iterable<Segment>, theme?: TerminalTheme): string;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* export-html — recorded segments drawn as HTML: a fragment that can sit in
|
|
3
|
+
* a page this library does not own, and a standalone document around it.
|
|
4
|
+
*
|
|
5
|
+
* An encoding of `export-lines` and nothing more. What a run looks like under
|
|
6
|
+
* a theme is decided there; this module decides only how CSS says it. It never
|
|
7
|
+
* sees a `Style`, so it cannot disagree with the SVG exporter about what
|
|
8
|
+
* `reverse` or `dim` means — the two old converters that did disagree were
|
|
9
|
+
* deleted when this replaced them.
|
|
10
|
+
*
|
|
11
|
+
* The rows are already laid out at console width, so `pre` never re-wraps
|
|
12
|
+
* them: `white-space: pre`, and a scrollbar rather than a reflow when the page
|
|
13
|
+
* is narrower than the terminal was.
|
|
14
|
+
*/
|
|
15
|
+
import { cellLen, graphemes } from "./cells.js";
|
|
16
|
+
import { exportCanvas, exportLines } from "./export-lines.js";
|
|
17
|
+
const ENTITIES = { "&": "&", "<": "<", ">": ">", '"': """ };
|
|
18
|
+
const escapeText = (text) => text.replace(/[&<>]/g, (c) => ENTITIES[c]);
|
|
19
|
+
const escapeAttribute = (value) => value.replace(/[&"<>]/g, (c) => ENTITIES[c]);
|
|
20
|
+
const BLINK_KEYFRAMES = "rich-blink";
|
|
21
|
+
// [LAW:dataflow-not-control-flow] Each enum-valued field of a look is a table
|
|
22
|
+
// from its values to the declarations it adds, so every value is spelled once
|
|
23
|
+
// and `Record` makes a new value a compile error until it has a row.
|
|
24
|
+
// A double underline adds no line to the glyph's own span; `runHtml` draws it.
|
|
25
|
+
const UNDERLINE_LINE = {
|
|
26
|
+
none: [],
|
|
27
|
+
single: ["underline"],
|
|
28
|
+
double: [],
|
|
29
|
+
};
|
|
30
|
+
const BLINK = {
|
|
31
|
+
none: [],
|
|
32
|
+
slow: [`animation:${BLINK_KEYFRAMES} 1s step-end infinite`],
|
|
33
|
+
fast: [`animation:${BLINK_KEYFRAMES} 0.5s step-end infinite`],
|
|
34
|
+
};
|
|
35
|
+
const FRAME = "box-shadow:inset 0 0 0 1px currentColor";
|
|
36
|
+
const OUTLINE = {
|
|
37
|
+
none: [],
|
|
38
|
+
frame: [FRAME],
|
|
39
|
+
encircle: [FRAME, "border-radius:0.5em"],
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The glyph colour, and the background when one is painted.
|
|
43
|
+
*
|
|
44
|
+
* Dim arrives already blended into `foreground`. `opacity` is never written:
|
|
45
|
+
* it fades a painted background along with the glyph, which is the bug the
|
|
46
|
+
* blend exists to avoid.
|
|
47
|
+
*/
|
|
48
|
+
function paintCss(look) {
|
|
49
|
+
return [
|
|
50
|
+
`color:${look.foreground.hex}`,
|
|
51
|
+
...(look.background === "canvas" ? [] : [`background-color:${look.background.hex}`]),
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
/** What is drawn on the glyph: weight, slant, single-style lines, blink, outline. */
|
|
55
|
+
function glyphCss(look) {
|
|
56
|
+
const lines = [
|
|
57
|
+
...UNDERLINE_LINE[look.underline],
|
|
58
|
+
...(look.strike ? ["line-through"] : []),
|
|
59
|
+
...(look.overline ? ["overline"] : []),
|
|
60
|
+
];
|
|
61
|
+
return [
|
|
62
|
+
...(look.bold ? ["font-weight:bold"] : []),
|
|
63
|
+
...(look.italic ? ["font-style:italic"] : []),
|
|
64
|
+
...(lines.length === 0 ? [] : [`text-decoration-line:${lines.join(" ")}`]),
|
|
65
|
+
...BLINK[look.blink],
|
|
66
|
+
...OUTLINE[look.outline],
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
// `unset` hands the anchor the run's look and drops the host's `a` rules;
|
|
70
|
+
// `revert` gives back the browser's link cursor and focus ring.
|
|
71
|
+
const ANCHOR_CSS = "all:unset;cursor:revert;outline:revert";
|
|
72
|
+
const span = (css, content) => `<span style="${escapeAttribute(css.join(";"))}">${content}</span>`;
|
|
73
|
+
/** Text of printable ASCII only: one cell a character, nothing to box. */
|
|
74
|
+
const ONE_CELL = /^[\x20-\x7e]*$/;
|
|
75
|
+
/**
|
|
76
|
+
* A box exactly `cells` of the monospace font wide (`ch` is one of its cells)
|
|
77
|
+
* for glyphs the browser would otherwise draw at a fallback font's width,
|
|
78
|
+
* which for a CJK character is rarely two cells: left to it, everything after
|
|
79
|
+
* them on the row shifts off its column. The box carries no paint, so the
|
|
80
|
+
* run's background runs through it at the run's own height; an atomic inline
|
|
81
|
+
* takes no decoration from its ancestors, so it inherits its parent's lines.
|
|
82
|
+
*/
|
|
83
|
+
const cellBox = (cells) => ["display:inline-block", `width:${cells}ch`, "text-align:center", "text-decoration:inherit"];
|
|
84
|
+
/**
|
|
85
|
+
* `text` with each stretch of graphemes wider than one cell in one box as wide
|
|
86
|
+
* as their cells together, and `draw` applied to every stretch of escaped text
|
|
87
|
+
* inside and between the boxes. A stretch, not a glyph apiece, because a
|
|
88
|
+
* browser's find-in-page does not match across two boxes. Graphemes, not code
|
|
89
|
+
* points, because `cellLen` measures a joined emoji as one glyph; a zero-width
|
|
90
|
+
* one joins the stretch before it, so it can still combine.
|
|
91
|
+
*/
|
|
92
|
+
function onGrid(text, draw) {
|
|
93
|
+
if (ONE_CELL.test(text))
|
|
94
|
+
return draw(escapeText(text));
|
|
95
|
+
const pieces = [];
|
|
96
|
+
let stretch = "";
|
|
97
|
+
let wideCells = 0;
|
|
98
|
+
const flush = () => {
|
|
99
|
+
if (stretch !== "")
|
|
100
|
+
pieces.push(wideCells === 0 ? draw(escapeText(stretch)) : span(cellBox(wideCells), draw(escapeText(stretch))));
|
|
101
|
+
stretch = "";
|
|
102
|
+
wideCells = 0;
|
|
103
|
+
};
|
|
104
|
+
for (const segment of graphemes(text)) {
|
|
105
|
+
const cells = cellLen(segment);
|
|
106
|
+
const wide = cells === 0 ? wideCells > 0 : cells > 1;
|
|
107
|
+
if (wide !== (wideCells > 0))
|
|
108
|
+
flush();
|
|
109
|
+
stretch += segment;
|
|
110
|
+
if (wide)
|
|
111
|
+
wideCells += cells;
|
|
112
|
+
}
|
|
113
|
+
flush();
|
|
114
|
+
return pieces.join("");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* One run as markup.
|
|
118
|
+
*
|
|
119
|
+
* An element has one `text-decoration-style`, so a double underline sharing a
|
|
120
|
+
* span with a strike would double the strike too. It gets an outer span of its
|
|
121
|
+
* own instead. That span carries the paint, because a descendant's background
|
|
122
|
+
* may be painted over an ancestor's underline, and the blink, so the underline
|
|
123
|
+
* blinks with the glyph. A wide glyph's box sits between the two: it inherits
|
|
124
|
+
* the double underline, and the inner span inside it draws the other lines.
|
|
125
|
+
*/
|
|
126
|
+
function runHtml({ text, look }) {
|
|
127
|
+
const drawn = look.underline === "double"
|
|
128
|
+
? span([...paintCss(look), "text-decoration-line:underline", "text-decoration-style:double", ...BLINK[look.blink]], onGrid(text, (glyph) => span([`color:${look.foreground.hex}`, ...glyphCss(look)], glyph)))
|
|
129
|
+
: span([...paintCss(look), ...glyphCss(look)], onGrid(text, (glyph) => glyph));
|
|
130
|
+
return look.href === null
|
|
131
|
+
? drawn
|
|
132
|
+
: `<a href="${escapeAttribute(look.href)}" style="${ANCHOR_CSS}">${drawn}</a>`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The CSS a page includes once, wherever fragments appear: what an inline
|
|
136
|
+
* style cannot say. A fragment that blinks draws steadily without it.
|
|
137
|
+
*
|
|
138
|
+
* The keyframes exist only for a reader who has not asked for reduced motion,
|
|
139
|
+
* so for one who has, the inline `animation` names nothing and the glyph holds
|
|
140
|
+
* still. One rule, so no second rule's order or survival in a host's CSS
|
|
141
|
+
* pipeline can bring the blink back.
|
|
142
|
+
*/
|
|
143
|
+
export const HTML_FRAGMENT_CSS = `@media (prefers-reduced-motion:no-preference){@keyframes ${BLINK_KEYFRAMES}{50%{color:transparent}}}`;
|
|
144
|
+
/**
|
|
145
|
+
* `segments` under `theme` as one `pre` carrying its canvas, for embedding.
|
|
146
|
+
*
|
|
147
|
+
* [LAW:locality-or-seam] Every rule is inline on the `pre` or below it, so the
|
|
148
|
+
* fragment styles nothing outside itself; the host page keeps its own `body`,
|
|
149
|
+
* `pre` and `a` rules. The seam holds the other way too: `all:initial` stops
|
|
150
|
+
* the host's `pre` rules and inherited typography from reaching the rows, and
|
|
151
|
+
* the two properties `all` does not cover pin the rows left to right.
|
|
152
|
+
*
|
|
153
|
+
* The one way in is the `--rich-fragment-font` custom property, read as the
|
|
154
|
+
* `font` shorthand (`14px/1.3 "JetBrains Mono", monospace`). `all` resets no
|
|
155
|
+
* custom property, so a host sets it on any ancestor to draw the rows in its
|
|
156
|
+
* own code font; unset, the rows are the browser's default monospace at a
|
|
157
|
+
* fixed line height, as a terminal's rows are. A host's value wants one too: at
|
|
158
|
+
* `normal`, a row holding a glyph from a taller fallback font grows and shifts
|
|
159
|
+
* every row below it. It must be a whole shorthand, a size and a family at
|
|
160
|
+
* least: any other value is invalid when computed, and the rows then inherit
|
|
161
|
+
* the host's font.
|
|
162
|
+
*
|
|
163
|
+
* A browser draws no line for a newline at either edge of a `pre`: the parser
|
|
164
|
+
* drops the one straight after the open tag, and the one before `</pre>` ends a
|
|
165
|
+
* line without starting another. So the fragment opens with a newline of its
|
|
166
|
+
* own and every row ends with one, and a blank first or last row is still drawn.
|
|
167
|
+
*/
|
|
168
|
+
export function encodeHtmlFragment(segments, theme) {
|
|
169
|
+
const canvas = exportCanvas(theme);
|
|
170
|
+
const rows = exportLines(segments, theme).map((row) => `${row.map(runHtml).join("")}\n`);
|
|
171
|
+
const css = [
|
|
172
|
+
"all:initial",
|
|
173
|
+
"direction:ltr",
|
|
174
|
+
"unicode-bidi:isolate",
|
|
175
|
+
"display:block",
|
|
176
|
+
`background:${canvas.background.hex}`,
|
|
177
|
+
`color:${canvas.foreground.hex}`,
|
|
178
|
+
"padding:1em",
|
|
179
|
+
"font:var(--rich-fragment-font,medium/1.2 monospace)",
|
|
180
|
+
"white-space:pre",
|
|
181
|
+
"overflow-x:auto",
|
|
182
|
+
].join(";");
|
|
183
|
+
return `<pre style="${css}">\n${rows.join("")}</pre>`;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* `segments` under `theme` as a complete HTML document.
|
|
187
|
+
*
|
|
188
|
+
* [LAW:one-source-of-truth] The document is the fragment in a shell, so the
|
|
189
|
+
* two cannot draw different pictures. The shell paints the page around the
|
|
190
|
+
* `pre` in the same canvas and includes the fragment CSS once.
|
|
191
|
+
*/
|
|
192
|
+
export function encodeHtml(segments, theme) {
|
|
193
|
+
const canvas = exportCanvas(theme);
|
|
194
|
+
const css = `body{background:${canvas.background.hex};color:${canvas.foreground.hex};margin:0}\n${HTML_FRAGMENT_CSS}`;
|
|
195
|
+
return [
|
|
196
|
+
"<!DOCTYPE html>",
|
|
197
|
+
`<html><head><meta charset="utf-8"><style>\n${css}\n</style></head>`,
|
|
198
|
+
`<body>${encodeHtmlFragment(segments, theme)}</body></html>`,
|
|
199
|
+
].join("\n");
|
|
200
|
+
}
|