@zakmandhro/bunti 0.1.5 → 0.2.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.
Files changed (192) hide show
  1. package/AGENTS.md +65 -0
  2. package/README.md +86 -11
  3. package/dist/cli.d.ts +44 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +147 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/colors.d.ts +77 -7
  8. package/dist/colors.d.ts.map +1 -1
  9. package/dist/colors.js +238 -39
  10. package/dist/colors.js.map +1 -1
  11. package/dist/components/Box.d.ts +6 -0
  12. package/dist/components/Box.d.ts.map +1 -1
  13. package/dist/components/Box.js +5 -0
  14. package/dist/components/Box.js.map +1 -1
  15. package/dist/components/Button.d.ts +15 -2
  16. package/dist/components/Button.d.ts.map +1 -1
  17. package/dist/components/Button.js +45 -25
  18. package/dist/components/Button.js.map +1 -1
  19. package/dist/components/Card.d.ts +24 -2
  20. package/dist/components/Card.d.ts.map +1 -1
  21. package/dist/components/Card.js +56 -14
  22. package/dist/components/Card.js.map +1 -1
  23. package/dist/components/Header.d.ts +11 -1
  24. package/dist/components/Header.d.ts.map +1 -1
  25. package/dist/components/Header.js +12 -8
  26. package/dist/components/Header.js.map +1 -1
  27. package/dist/components/Input.d.ts +10 -1
  28. package/dist/components/Input.d.ts.map +1 -1
  29. package/dist/components/Input.js +176 -41
  30. package/dist/components/Input.js.map +1 -1
  31. package/dist/components/Link.d.ts +21 -0
  32. package/dist/components/Link.d.ts.map +1 -0
  33. package/dist/components/Link.js +38 -0
  34. package/dist/components/Link.js.map +1 -0
  35. package/dist/components/Modal.d.ts +25 -0
  36. package/dist/components/Modal.d.ts.map +1 -1
  37. package/dist/components/Modal.js +88 -24
  38. package/dist/components/Modal.js.map +1 -1
  39. package/dist/components/Progress.d.ts +27 -0
  40. package/dist/components/Progress.d.ts.map +1 -0
  41. package/dist/components/Progress.js +39 -0
  42. package/dist/components/Progress.js.map +1 -0
  43. package/dist/components/Spinner.d.ts +19 -0
  44. package/dist/components/Spinner.d.ts.map +1 -0
  45. package/dist/components/Spinner.js +27 -0
  46. package/dist/components/Spinner.js.map +1 -0
  47. package/dist/components/index.d.ts +3 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/index.js +3 -0
  50. package/dist/components/index.js.map +1 -1
  51. package/dist/data/nf-glyphs.d.ts +11 -0
  52. package/dist/data/nf-glyphs.d.ts.map +1 -0
  53. package/dist/data/nf-glyphs.js +535 -0
  54. package/dist/data/nf-glyphs.js.map +1 -0
  55. package/dist/data/nf-names.d.ts +8 -0
  56. package/dist/data/nf-names.d.ts.map +1 -0
  57. package/dist/data/nf-names.js +2 -0
  58. package/dist/data/nf-names.js.map +1 -0
  59. package/dist/demo-registry.d.ts +27 -0
  60. package/dist/demo-registry.d.ts.map +1 -0
  61. package/dist/demo-registry.js +57 -0
  62. package/dist/demo-registry.js.map +1 -0
  63. package/dist/demos/2048.ts +743 -0
  64. package/dist/demos/animation.ts +246 -0
  65. package/dist/demos/demo-layout.ts +124 -0
  66. package/dist/demos/engine.ts +374 -0
  67. package/dist/demos/interaction.ts +91 -0
  68. package/dist/demos/login.ts +203 -0
  69. package/dist/demos/mission-control.ts +558 -0
  70. package/dist/demos/showcase.ts +224 -0
  71. package/dist/detect.d.ts +92 -3
  72. package/dist/detect.d.ts.map +1 -1
  73. package/dist/detect.js +218 -40
  74. package/dist/detect.js.map +1 -1
  75. package/dist/diagnostics.d.ts +73 -0
  76. package/dist/diagnostics.d.ts.map +1 -0
  77. package/dist/diagnostics.js +225 -0
  78. package/dist/diagnostics.js.map +1 -0
  79. package/dist/dsl/context.d.ts +11 -0
  80. package/dist/dsl/context.d.ts.map +1 -0
  81. package/dist/dsl/context.js +658 -0
  82. package/dist/dsl/context.js.map +1 -0
  83. package/dist/dsl/hooks.d.ts +12 -0
  84. package/dist/dsl/hooks.d.ts.map +1 -0
  85. package/dist/dsl/hooks.js +148 -0
  86. package/dist/dsl/hooks.js.map +1 -0
  87. package/dist/dsl/interaction.d.ts +31 -0
  88. package/dist/dsl/interaction.d.ts.map +1 -0
  89. package/dist/dsl/interaction.js +150 -0
  90. package/dist/dsl/interaction.js.map +1 -0
  91. package/dist/dsl/layers.d.ts +14 -0
  92. package/dist/dsl/layers.d.ts.map +1 -0
  93. package/dist/dsl/layers.js +87 -0
  94. package/dist/dsl/layers.js.map +1 -0
  95. package/dist/dsl/motion.d.ts +10 -0
  96. package/dist/dsl/motion.d.ts.map +1 -0
  97. package/dist/dsl/motion.js +150 -0
  98. package/dist/dsl/motion.js.map +1 -0
  99. package/dist/dsl/render.d.ts +22 -0
  100. package/dist/dsl/render.d.ts.map +1 -0
  101. package/dist/dsl/render.js +69 -0
  102. package/dist/dsl/render.js.map +1 -0
  103. package/dist/dsl/types.d.ts +555 -0
  104. package/dist/dsl/types.d.ts.map +1 -0
  105. package/dist/dsl/types.js +33 -0
  106. package/dist/dsl/types.js.map +1 -0
  107. package/dist/dsl.d.ts +13 -154
  108. package/dist/dsl.d.ts.map +1 -1
  109. package/dist/dsl.js +12 -658
  110. package/dist/dsl.js.map +1 -1
  111. package/dist/easing.d.ts +41 -1
  112. package/dist/easing.d.ts.map +1 -1
  113. package/dist/easing.js +105 -2
  114. package/dist/easing.js.map +1 -1
  115. package/dist/geometry.d.ts +39 -0
  116. package/dist/geometry.d.ts.map +1 -1
  117. package/dist/geometry.js +20 -0
  118. package/dist/geometry.js.map +1 -1
  119. package/dist/icons-full.d.ts +5 -0
  120. package/dist/icons-full.d.ts.map +1 -0
  121. package/dist/icons-full.js +31 -0
  122. package/dist/icons-full.js.map +1 -0
  123. package/dist/icons.d.ts +426 -5
  124. package/dist/icons.d.ts.map +1 -1
  125. package/dist/icons.js +144 -15
  126. package/dist/icons.js.map +1 -1
  127. package/dist/index.d.ts +95 -23
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +17 -7
  130. package/dist/index.js.map +1 -1
  131. package/dist/input.d.ts +177 -0
  132. package/dist/input.d.ts.map +1 -0
  133. package/dist/input.js +533 -0
  134. package/dist/input.js.map +1 -0
  135. package/dist/layout.d.ts +153 -7
  136. package/dist/layout.d.ts.map +1 -1
  137. package/dist/layout.js +221 -34
  138. package/dist/layout.js.map +1 -1
  139. package/dist/render.d.ts +33 -1
  140. package/dist/render.d.ts.map +1 -1
  141. package/dist/render.js +431 -116
  142. package/dist/render.js.map +1 -1
  143. package/dist/state.d.ts +156 -3
  144. package/dist/state.d.ts.map +1 -1
  145. package/dist/state.js +25 -0
  146. package/dist/state.js.map +1 -1
  147. package/dist/theme.d.ts +129 -0
  148. package/dist/theme.d.ts.map +1 -0
  149. package/dist/theme.js +167 -0
  150. package/dist/theme.js.map +1 -0
  151. package/dist/themes/catppuccin-mocha.d.ts +19 -0
  152. package/dist/themes/catppuccin-mocha.d.ts.map +1 -0
  153. package/dist/themes/catppuccin-mocha.js +36 -0
  154. package/dist/themes/catppuccin-mocha.js.map +1 -0
  155. package/dist/themes/dracula.d.ts +21 -0
  156. package/dist/themes/dracula.d.ts.map +1 -0
  157. package/dist/themes/dracula.js +37 -0
  158. package/dist/themes/dracula.js.map +1 -0
  159. package/dist/themes/github-light.d.ts +21 -0
  160. package/dist/themes/github-light.d.ts.map +1 -0
  161. package/dist/themes/github-light.js +36 -0
  162. package/dist/themes/github-light.js.map +1 -0
  163. package/dist/themes/index.d.ts +19 -0
  164. package/dist/themes/index.d.ts.map +1 -0
  165. package/dist/themes/index.js +17 -0
  166. package/dist/themes/index.js.map +1 -0
  167. package/dist/themes/nord.d.ts +23 -0
  168. package/dist/themes/nord.d.ts.map +1 -0
  169. package/dist/themes/nord.js +38 -0
  170. package/dist/themes/nord.js.map +1 -0
  171. package/dist/themes/one-dark-pro.d.ts +21 -0
  172. package/dist/themes/one-dark-pro.d.ts.map +1 -0
  173. package/dist/themes/one-dark-pro.js +36 -0
  174. package/dist/themes/one-dark-pro.js.map +1 -0
  175. package/dist/themes/tokyo-night.d.ts +20 -0
  176. package/dist/themes/tokyo-night.d.ts.map +1 -0
  177. package/dist/themes/tokyo-night.js +37 -0
  178. package/dist/themes/tokyo-night.js.map +1 -0
  179. package/dist/utils.d.ts +1 -0
  180. package/dist/utils.d.ts.map +1 -1
  181. package/dist/utils.js +1 -0
  182. package/dist/utils.js.map +1 -1
  183. package/dist/vendor/colors.d.ts +45 -0
  184. package/dist/vendor/colors.d.ts.map +1 -0
  185. package/dist/vendor/colors.js +72 -0
  186. package/dist/vendor/colors.js.map +1 -0
  187. package/llms.txt +79 -0
  188. package/package.json +23 -7
  189. package/dist/data/glyphs.d.ts +0 -5
  190. package/dist/data/glyphs.d.ts.map +0 -1
  191. package/dist/data/glyphs.js +0 -29
  192. package/dist/data/glyphs.js.map +0 -1
package/dist/icons.d.ts CHANGED
@@ -1,21 +1,442 @@
1
1
  /**
2
2
  * Bunti Icon Engine
3
3
  * Purely tactical: Nerd Fonts or ASCII fallbacks.
4
+ *
5
+ * Two tiers of names resolve through icon()/getIcon():
6
+ * 1. The curated ICON_MAP below (89 short names with ASCII fallbacks).
7
+ * 2. A runtime registry filled via register()/registerAll() — most notably
8
+ * by `import '@zakmandhro/bunti/icons-full'`, which installs the full
9
+ * Nerd Fonts v3.4.0 glyph set (~10.7k names like 'fa-rocket').
4
10
  */
5
- import type { TerminalCapabilities } from './detect';
11
+ import type { IconName } from './data/nf-names';
12
+ import { type TerminalCapabilities, type TerminalProfile } from './detect';
13
+ /** An icon's Nerd Font glyph plus its plain-terminal ASCII stand-in. */
6
14
  export interface IconDefinition {
15
+ /** Nerd Font glyph (private-use-area codepoint). */
7
16
  nf: string;
17
+ /** Single-char ASCII fallback for non-NF terminals. */
8
18
  ascii: string;
9
19
  }
20
+ declare const CURATED_ICONS: {
21
+ add: {
22
+ nf: string;
23
+ ascii: string;
24
+ };
25
+ 'arrow-left': {
26
+ nf: string;
27
+ ascii: string;
28
+ };
29
+ 'arrow-right': {
30
+ nf: string;
31
+ ascii: string;
32
+ };
33
+ bars: {
34
+ nf: string;
35
+ ascii: string;
36
+ };
37
+ bell: {
38
+ nf: string;
39
+ ascii: string;
40
+ };
41
+ branch: {
42
+ nf: string;
43
+ ascii: string;
44
+ };
45
+ bullet: {
46
+ nf: string;
47
+ ascii: string;
48
+ };
49
+ bun: {
50
+ nf: string;
51
+ ascii: string;
52
+ };
53
+ bunti: {
54
+ nf: string;
55
+ ascii: string;
56
+ };
57
+ check: {
58
+ nf: string;
59
+ ascii: string;
60
+ };
61
+ checkbox: {
62
+ nf: string;
63
+ ascii: string;
64
+ };
65
+ 'checkbox-check': {
66
+ nf: string;
67
+ ascii: string;
68
+ };
69
+ 'chevron-down': {
70
+ nf: string;
71
+ ascii: string;
72
+ };
73
+ 'chevron-left': {
74
+ nf: string;
75
+ ascii: string;
76
+ };
77
+ 'chevron-right': {
78
+ nf: string;
79
+ ascii: string;
80
+ };
81
+ close: {
82
+ nf: string;
83
+ ascii: string;
84
+ };
85
+ cloud: {
86
+ nf: string;
87
+ ascii: string;
88
+ };
89
+ code: {
90
+ nf: string;
91
+ ascii: string;
92
+ };
93
+ commit: {
94
+ nf: string;
95
+ ascii: string;
96
+ };
97
+ copy: {
98
+ nf: string;
99
+ ascii: string;
100
+ };
101
+ cpu: {
102
+ nf: string;
103
+ ascii: string;
104
+ };
105
+ database: {
106
+ nf: string;
107
+ ascii: string;
108
+ };
109
+ desktop: {
110
+ nf: string;
111
+ ascii: string;
112
+ };
113
+ disk: {
114
+ nf: string;
115
+ ascii: string;
116
+ };
117
+ download: {
118
+ nf: string;
119
+ ascii: string;
120
+ };
121
+ 'draft-pr': {
122
+ nf: string;
123
+ ascii: string;
124
+ };
125
+ edit: {
126
+ nf: string;
127
+ ascii: string;
128
+ };
129
+ error: {
130
+ nf: string;
131
+ ascii: string;
132
+ };
133
+ exit: {
134
+ nf: string;
135
+ ascii: string;
136
+ };
137
+ external: {
138
+ nf: string;
139
+ ascii: string;
140
+ };
141
+ eye: {
142
+ nf: string;
143
+ ascii: string;
144
+ };
145
+ 'eye-off': {
146
+ nf: string;
147
+ ascii: string;
148
+ };
149
+ file: {
150
+ nf: string;
151
+ ascii: string;
152
+ };
153
+ folder: {
154
+ nf: string;
155
+ ascii: string;
156
+ };
157
+ 'folder-open': {
158
+ nf: string;
159
+ ascii: string;
160
+ };
161
+ fork: {
162
+ nf: string;
163
+ ascii: string;
164
+ };
165
+ gear: {
166
+ nf: string;
167
+ ascii: string;
168
+ };
169
+ git: {
170
+ nf: string;
171
+ ascii: string;
172
+ };
173
+ grid: {
174
+ nf: string;
175
+ ascii: string;
176
+ };
177
+ heart: {
178
+ nf: string;
179
+ ascii: string;
180
+ };
181
+ 'help-circle': {
182
+ nf: string;
183
+ ascii: string;
184
+ };
185
+ home: {
186
+ nf: string;
187
+ ascii: string;
188
+ };
189
+ image: {
190
+ nf: string;
191
+ ascii: string;
192
+ };
193
+ info: {
194
+ nf: string;
195
+ ascii: string;
196
+ };
197
+ issue: {
198
+ nf: string;
199
+ ascii: string;
200
+ };
201
+ json: {
202
+ nf: string;
203
+ ascii: string;
204
+ };
205
+ laptop: {
206
+ nf: string;
207
+ ascii: string;
208
+ };
209
+ list: {
210
+ nf: string;
211
+ ascii: string;
212
+ };
213
+ loading: {
214
+ nf: string;
215
+ ascii: string;
216
+ };
217
+ lock: {
218
+ nf: string;
219
+ ascii: string;
220
+ };
221
+ mail: {
222
+ nf: string;
223
+ ascii: string;
224
+ };
225
+ markdown: {
226
+ nf: string;
227
+ ascii: string;
228
+ };
229
+ maximize: {
230
+ nf: string;
231
+ ascii: string;
232
+ };
233
+ memory: {
234
+ nf: string;
235
+ ascii: string;
236
+ };
237
+ menu: {
238
+ nf: string;
239
+ ascii: string;
240
+ };
241
+ merge: {
242
+ nf: string;
243
+ ascii: string;
244
+ };
245
+ minimize: {
246
+ nf: string;
247
+ ascii: string;
248
+ };
249
+ network: {
250
+ nf: string;
251
+ ascii: string;
252
+ };
253
+ node: {
254
+ nf: string;
255
+ ascii: string;
256
+ };
257
+ pause: {
258
+ nf: string;
259
+ ascii: string;
260
+ };
261
+ pencil: {
262
+ nf: string;
263
+ ascii: string;
264
+ };
265
+ planet: {
266
+ nf: string;
267
+ ascii: string;
268
+ };
269
+ play: {
270
+ nf: string;
271
+ ascii: string;
272
+ };
273
+ 'plus-circle': {
274
+ nf: string;
275
+ ascii: string;
276
+ };
277
+ pr: {
278
+ nf: string;
279
+ ascii: string;
280
+ };
281
+ refresh: {
282
+ nf: string;
283
+ ascii: string;
284
+ };
285
+ remove: {
286
+ nf: string;
287
+ ascii: string;
288
+ };
289
+ repo: {
290
+ nf: string;
291
+ ascii: string;
292
+ };
293
+ robot: {
294
+ nf: string;
295
+ ascii: string;
296
+ };
297
+ rocket: {
298
+ nf: string;
299
+ ascii: string;
300
+ };
301
+ satellite: {
302
+ nf: string;
303
+ ascii: string;
304
+ };
305
+ save: {
306
+ nf: string;
307
+ ascii: string;
308
+ };
309
+ search: {
310
+ nf: string;
311
+ ascii: string;
312
+ };
313
+ send: {
314
+ nf: string;
315
+ ascii: string;
316
+ };
317
+ server: {
318
+ nf: string;
319
+ ascii: string;
320
+ };
321
+ settings: {
322
+ nf: string;
323
+ ascii: string;
324
+ };
325
+ 'staggered-bars': {
326
+ nf: string;
327
+ ascii: string;
328
+ };
329
+ star: {
330
+ nf: string;
331
+ ascii: string;
332
+ };
333
+ stop: {
334
+ nf: string;
335
+ ascii: string;
336
+ };
337
+ success: {
338
+ nf: string;
339
+ ascii: string;
340
+ };
341
+ tag: {
342
+ nf: string;
343
+ ascii: string;
344
+ };
345
+ terminal: {
346
+ nf: string;
347
+ ascii: string;
348
+ };
349
+ trash: {
350
+ nf: string;
351
+ ascii: string;
352
+ };
353
+ user: {
354
+ nf: string;
355
+ ascii: string;
356
+ };
357
+ warning: {
358
+ nf: string;
359
+ ascii: string;
360
+ };
361
+ wizard: {
362
+ nf: string;
363
+ ascii: string;
364
+ };
365
+ yaml: {
366
+ nf: string;
367
+ ascii: string;
368
+ };
369
+ zap: {
370
+ nf: string;
371
+ ascii: string;
372
+ };
373
+ };
374
+ /** Short names of the curated, width-audited icon set. */
375
+ export type CuratedIconName = keyof typeof CURATED_ICONS;
376
+ /**
377
+ * Any icon name Bunti can resolve: curated short names, full Nerd Fonts
378
+ * names (available after `import '@zakmandhro/bunti/icons-full'`), or
379
+ * custom names added via register(). Arbitrary strings stay assignable.
380
+ */
381
+ export type BuntiIconName = CuratedIconName | IconName | (string & Record<never, never>);
382
+ /** The curated icon table: 89 width-audited names with ASCII fallbacks. */
10
383
  export declare const ICON_MAP: Record<string, IconDefinition>;
384
+ /**
385
+ * Emoji-to-icon-name swaps applied automatically to drawn text (emoji
386
+ * render at unreliable widths across terminals; their NF twins are
387
+ * width-audited). Set `raw: true` on a cell to bypass.
388
+ */
11
389
  export declare const EMOJI_MAP: Record<string, string>;
390
+ /**
391
+ * Swaps known emoji in a string for their width-audited Nerd Font icons
392
+ * (see EMOJI_MAP). Applied automatically by draw calls; no-op on the
393
+ * ASCII tier.
394
+ */
12
395
  export declare function replaceEmojis(text: string): string;
396
+ /**
397
+ * Initializes the icon tier from terminal detection.
398
+ *
399
+ * - `init({ nerdFont })` forces the tier explicitly (always wins).
400
+ * - `init({ profile })` derives it from a pre-detected TerminalProfile
401
+ * (render() passes the per-screen profile here).
402
+ * - `init()` runs env detection itself via `identifyTerminal()`.
403
+ *
404
+ * 'yes' / 'assumed-yes' policies map to Nerd Font glyphs; everything else
405
+ * falls back to the ASCII tier. Until init() is called the module defaults
406
+ * to Nerd Font glyphs (back-compat for direct icon() usage).
407
+ */
13
408
  export declare function init(options?: {
14
409
  nerdFont?: boolean;
410
+ profile?: TerminalProfile;
15
411
  }): Promise<TerminalCapabilities>;
16
- export declare function getIcon(name: string, caps: TerminalCapabilities): string;
17
- export declare function icon(name: string): string;
18
- export declare function nerd(name: string): string;
19
- export declare function register(_name: string, _glyph: string): void;
412
+ /**
413
+ * Registers a runtime icon. Accepts a bare Nerd Font glyph, or a full
414
+ * definition with an ASCII fallback for `init({ nerdFont: false })` tiers
415
+ * (bare glyphs fall back to '*' in the ASCII tier).
416
+ */
417
+ export declare function register(name: string, glyphOrDef: string | IconDefinition): void;
418
+ /** Bulk-registers name -> glyph pairs (used by the icons-full subpath). */
419
+ export declare function registerAll(glyphs: Record<string, string>): void;
420
+ /** @internal Test hook: unresolved names buffered so far. */
421
+ export declare function __iconMisses(): string[];
422
+ /**
423
+ * Resolves an icon name. Resolution order:
424
+ * 1. Curated ICON_MAP (short names, keeps ASCII fallbacks + aliases).
425
+ * 2. Runtime registry (register()/registerAll(), e.g. the icons-full
426
+ * pack). A leading 'nf-' is stripped: 'nf-fa-rocket' === 'fa-rocket'.
427
+ * 3. '' — the miss is buffered and reported once on process exit.
428
+ */
429
+ export declare function getIcon(name: BuntiIconName, caps: TerminalCapabilities): string;
430
+ /**
431
+ * Resolves an icon name to a glyph on the active tier (Nerd Font glyph,
432
+ * or ASCII fallback on plain terminals). Unknown names render as '' and
433
+ * are reported once on process exit with a nearest-name hint.
434
+ * @example text(`${icon('rocket')} Launch`);
435
+ */
436
+ export declare function icon(name: BuntiIconName): string;
437
+ /** Returns the Nerd Font glyph for a name regardless of the active tier. */
438
+ export declare function nerd(name: BuntiIconName): string;
439
+ /** Picks the given Nerd Font char on the NF tier, else the fallback. */
20
440
  export declare function nerdIcon(nfChar: string, fallback: string): string;
441
+ export {};
21
442
  //# sourceMappingURL=icons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAyFnD,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkC5C,CAAC;AAuBF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBlD;AAED,wBAAsB,IAAI,CAAC,OAAO,CAAC,EAAE;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAGhC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAIxE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAG;AAEhE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,UAAU,CAAC;AAOlB,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFuB,CAAC;AAE3C,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,aAAa,CAAC;AAEzD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,QAAQ,GACR,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAEpC,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAiB,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkC5C,CAAC;AAuBF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBlD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,IAAI,CAAC,OAAO,CAAC,EAAE;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAUhC;AAgBD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GAAG,cAAc,GAClC,IAAI,CAON;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAIhE;AAgDD,6DAA6D;AAC7D,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,oBAAoB,GACzB,MAAM,CAaR;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAEhD;AAED,4EAA4E;AAC5E,wBAAgB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAOhD;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE"}
package/dist/icons.js CHANGED
@@ -1,16 +1,18 @@
1
- export const ICON_MAP = {
1
+ import { identifyTerminal, } from './detect';
2
+ import { hintsSuppressed, nearestMatch, registerHintFlusher, } from './diagnostics';
3
+ const CURATED_ICONS = {
2
4
  add: { nf: '\uf067', ascii: '+' },
3
5
  'arrow-left': { nf: '\uf060', ascii: '<' },
4
6
  'arrow-right': { nf: '\uf061', ascii: '>' },
5
- bars: { nf: '\uf0c9', ascii: '≡' },
7
+ bars: { nf: '\uf0c9', ascii: '=' },
6
8
  bell: { nf: '\uf0f3', ascii: '!' },
7
9
  branch: { nf: '\uf418', ascii: '*' },
8
- bullet: { nf: '\uf111', ascii: '•' },
10
+ bullet: { nf: '\uf111', ascii: '*' },
9
11
  bun: { nf: '\ue76f', ascii: 'B' },
10
12
  bunti: { nf: '\u{f0065}', ascii: '@' },
11
13
  check: { nf: '\uf00c', ascii: 'v' },
12
- checkbox: { nf: '\uf0c8', ascii: '[ ]' },
13
- 'checkbox-check': { nf: '\uf14a', ascii: '[x]' },
14
+ checkbox: { nf: '\uf0c8', ascii: '#' },
15
+ 'checkbox-check': { nf: '\uf14a', ascii: 'X' },
14
16
  'chevron-down': { nf: '\uf078', ascii: 'v' },
15
17
  'chevron-left': { nf: '\uf053', ascii: '<' },
16
18
  'chevron-right': { nf: '\uf054', ascii: '>' },
@@ -53,16 +55,16 @@ export const ICON_MAP = {
53
55
  markdown: { nf: '\uf48a', ascii: 'M' },
54
56
  maximize: { nf: '\uf0c8', ascii: '^' },
55
57
  memory: { nf: '\uf0c7', ascii: 'M' },
56
- menu: { nf: '\uf0c9', ascii: '≡' },
58
+ menu: { nf: '\uf0c9', ascii: '=' },
57
59
  merge: { nf: '\uf419', ascii: '>' },
58
60
  minimize: { nf: '\u{f10fe}', ascii: 'v' },
59
61
  network: { nf: '\uf0ac', ascii: 'N' },
60
62
  node: { nf: '\ue718', ascii: 'N' },
61
63
  pause: { nf: '\uf04c', ascii: '|' },
62
64
  pencil: { nf: '\uf044', ascii: 'e' },
63
- planet: { nf: '\ue22e', ascii: '㊀' },
65
+ planet: { nf: '\ue22e', ascii: 'O' },
64
66
  play: { nf: '\uf04b', ascii: '>' },
65
- 'plus-circle': { nf: '\uea60', ascii: '(+)' },
67
+ 'plus-circle': { nf: '\uea60', ascii: '+' },
66
68
  pr: { nf: '\uf41d', ascii: '!' },
67
69
  refresh: { nf: '\uf021', ascii: 'R' },
68
70
  remove: { nf: '\uf068', ascii: '-' },
@@ -75,7 +77,7 @@ export const ICON_MAP = {
75
77
  send: { nf: '\uec0f', ascii: '>' },
76
78
  server: { nf: '\uf233', ascii: 'S' },
77
79
  settings: { nf: '\uf013', ascii: '*' },
78
- 'staggered-bars': { nf: '\u{ee19}', ascii: '≡' },
80
+ 'staggered-bars': { nf: '\u{ee19}', ascii: '=' },
79
81
  star: { nf: '\uf005', ascii: '*' },
80
82
  stop: { nf: '\uf04d', ascii: 'X' },
81
83
  success: { nf: '\uf00c', ascii: 'v' },
@@ -88,6 +90,13 @@ export const ICON_MAP = {
88
90
  yaml: { nf: '\ue6a8', ascii: 'Y' },
89
91
  zap: { nf: '\uf0e7', ascii: 'z' },
90
92
  };
93
+ /** The curated icon table: 89 width-audited names with ASCII fallbacks. */
94
+ export const ICON_MAP = CURATED_ICONS;
95
+ /**
96
+ * Emoji-to-icon-name swaps applied automatically to drawn text (emoji
97
+ * render at unreliable widths across terminals; their NF twins are
98
+ * width-audited). Set `raw: true` on a cell to bypass.
99
+ */
91
100
  export const EMOJI_MAP = {
92
101
  '🌿': 'branch',
93
102
  '📥': 'pr',
@@ -140,6 +149,11 @@ function getEmojiPattern() {
140
149
  }
141
150
  return emojiPattern;
142
151
  }
152
+ /**
153
+ * Swaps known emoji in a string for their width-audited Nerd Font icons
154
+ * (see EMOJI_MAP). Applied automatically by draw calls; no-op on the
155
+ * ASCII tier.
156
+ */
143
157
  export function replaceEmojis(text) {
144
158
  if (!text)
145
159
  return '';
@@ -161,24 +175,139 @@ export function replaceEmojis(text) {
161
175
  return name ? getIcon(name, cachedCaps) : match;
162
176
  });
163
177
  }
178
+ /**
179
+ * Initializes the icon tier from terminal detection.
180
+ *
181
+ * - `init({ nerdFont })` forces the tier explicitly (always wins).
182
+ * - `init({ profile })` derives it from a pre-detected TerminalProfile
183
+ * (render() passes the per-screen profile here).
184
+ * - `init()` runs env detection itself via `identifyTerminal()`.
185
+ *
186
+ * 'yes' / 'assumed-yes' policies map to Nerd Font glyphs; everything else
187
+ * falls back to the ASCII tier. Until init() is called the module defaults
188
+ * to Nerd Font glyphs (back-compat for direct icon() usage).
189
+ */
164
190
  export async function init(options) {
165
- if (options?.nerdFont !== undefined)
191
+ if (options?.nerdFont !== undefined) {
166
192
  cachedCaps.nerdFont = options.nerdFont;
193
+ return cachedCaps;
194
+ }
195
+ const profile = options?.profile ?? identifyTerminal();
196
+ cachedCaps.nerdFont =
197
+ profile.nerdFont === 'yes' || profile.nerdFont === 'assumed-yes';
198
+ cachedCaps.glyphProtocol = profile.app === 'ghostty';
167
199
  return cachedCaps;
168
200
  }
201
+ // --- Runtime icon registry (tier 2) ---
202
+ // Consulted after the curated ICON_MAP. The icons-full subpath bulk-loads
203
+ // every Nerd Fonts glyph here; apps can also register their own icons.
204
+ const registryNf = new Map();
205
+ const registryAscii = new Map();
206
+ /** ASCII-tier stand-in for registered icons without an explicit fallback. */
207
+ const REGISTRY_ASCII_FALLBACK = '*';
208
+ function stripNfPrefix(name) {
209
+ return name.startsWith('nf-') ? name.slice(3) : name;
210
+ }
211
+ /**
212
+ * Registers a runtime icon. Accepts a bare Nerd Font glyph, or a full
213
+ * definition with an ASCII fallback for `init({ nerdFont: false })` tiers
214
+ * (bare glyphs fall back to '*' in the ASCII tier).
215
+ */
216
+ export function register(name, glyphOrDef) {
217
+ if (typeof glyphOrDef === 'string') {
218
+ registryNf.set(name, glyphOrDef);
219
+ }
220
+ else {
221
+ registryNf.set(name, glyphOrDef.nf);
222
+ registryAscii.set(name, glyphOrDef.ascii);
223
+ }
224
+ }
225
+ /** Bulk-registers name -> glyph pairs (used by the icons-full subpath). */
226
+ export function registerAll(glyphs) {
227
+ for (const name in glyphs) {
228
+ registryNf.set(name, glyphs[name]);
229
+ }
230
+ }
231
+ // --- Unknown-name diagnostics ---
232
+ // Misses are buffered in a Set and drained through the shared diagnostics
233
+ // exit flush (src/diagnostics.ts), so warnings never tear an active frame
234
+ // mid-render and every dev hint arrives in one block on process exit.
235
+ const missedNames = new Set();
236
+ let flusherRegistered = false;
237
+ function recordMiss(name) {
238
+ if (hintsSuppressed())
239
+ return;
240
+ missedNames.add(name);
241
+ if (!flusherRegistered) {
242
+ flusherRegistered = true;
243
+ registerHintFlusher(drainIconHintLines);
244
+ }
245
+ }
246
+ function* iconNameCandidates() {
247
+ yield* Object.keys(ICON_MAP);
248
+ yield* registryNf.keys();
249
+ }
250
+ function nearestIconName(name) {
251
+ return nearestMatch(stripNfPrefix(name), iconNameCandidates());
252
+ }
253
+ /** Drains buffered misses into hint lines (called by the exit flush). */
254
+ function drainIconHintLines() {
255
+ if (missedNames.size === 0)
256
+ return [];
257
+ const lines = [];
258
+ for (const name of missedNames) {
259
+ const hint = nearestIconName(name);
260
+ lines.push(`unknown icon '${name}' rendered as ''` +
261
+ `${hint ? ` (did you mean '${hint}'?)` : ''}`);
262
+ }
263
+ if (registryNf.size === 0) {
264
+ lines.push("tip: import '@zakmandhro/bunti/icons-full' to enable all ~10.7k Nerd Font icons by name");
265
+ }
266
+ missedNames.clear();
267
+ return lines;
268
+ }
269
+ /** @internal Test hook: unresolved names buffered so far. */
270
+ export function __iconMisses() {
271
+ return [...missedNames];
272
+ }
273
+ /**
274
+ * Resolves an icon name. Resolution order:
275
+ * 1. Curated ICON_MAP (short names, keeps ASCII fallbacks + aliases).
276
+ * 2. Runtime registry (register()/registerAll(), e.g. the icons-full
277
+ * pack). A leading 'nf-' is stripped: 'nf-fa-rocket' === 'fa-rocket'.
278
+ * 3. '' — the miss is buffered and reported once on process exit.
279
+ */
169
280
  export function getIcon(name, caps) {
170
281
  const def = ICON_MAP[name];
171
- if (!def)
172
- return '';
173
- return caps.nerdFont ? def.nf : def.ascii;
282
+ if (def)
283
+ return caps.nerdFont ? def.nf : def.ascii;
284
+ const key = registryNf.has(name) ? name : stripNfPrefix(name);
285
+ const nf = registryNf.get(key);
286
+ if (nf !== undefined) {
287
+ if (caps.nerdFont)
288
+ return nf;
289
+ return registryAscii.get(key) ?? REGISTRY_ASCII_FALLBACK;
290
+ }
291
+ recordMiss(name);
292
+ return '';
174
293
  }
294
+ /**
295
+ * Resolves an icon name to a glyph on the active tier (Nerd Font glyph,
296
+ * or ASCII fallback on plain terminals). Unknown names render as '' and
297
+ * are reported once on process exit with a nearest-name hint.
298
+ * @example text(`${icon('rocket')} Launch`);
299
+ */
175
300
  export function icon(name) {
176
301
  return getIcon(name, cachedCaps);
177
302
  }
303
+ /** Returns the Nerd Font glyph for a name regardless of the active tier. */
178
304
  export function nerd(name) {
179
- return ICON_MAP[name]?.nf || '';
305
+ return (ICON_MAP[name]?.nf ??
306
+ registryNf.get(name) ??
307
+ registryNf.get(stripNfPrefix(name)) ??
308
+ '');
180
309
  }
181
- export function register(_name, _glyph) { }
310
+ /** Picks the given Nerd Font char on the NF tier, else the fallback. */
182
311
  export function nerdIcon(nfChar, fallback) {
183
312
  return cachedCaps.nerdFont ? nfChar : fallback;
184
313
  }