@hauktui/registry 0.0.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 (139) hide show
  1. package/components/accordion/accordion.tsx +146 -0
  2. package/components/accordion/index.ts +2 -0
  3. package/components/alert/alert.tsx +69 -0
  4. package/components/alert/index.ts +2 -0
  5. package/components/alert-dialog/alert-dialog.tsx +185 -0
  6. package/components/alert-dialog/index.ts +2 -0
  7. package/components/avatar/avatar.tsx +57 -0
  8. package/components/avatar/index.ts +2 -0
  9. package/components/avatar-group/avatar-group.tsx +144 -0
  10. package/components/avatar-group/index.ts +2 -0
  11. package/components/badge/badge.tsx +52 -0
  12. package/components/badge/index.ts +2 -0
  13. package/components/banner/banner.tsx +407 -0
  14. package/components/banner/index.ts +2 -0
  15. package/components/breadcrumb/breadcrumb.tsx +58 -0
  16. package/components/breadcrumb/index.ts +2 -0
  17. package/components/button/button.tsx +114 -0
  18. package/components/button/index.ts +2 -0
  19. package/components/calendar/calendar.tsx +250 -0
  20. package/components/calendar/index.ts +2 -0
  21. package/components/card/card.tsx +88 -0
  22. package/components/card/index.ts +2 -0
  23. package/components/carousel/carousel.tsx +185 -0
  24. package/components/carousel/index.ts +2 -0
  25. package/components/chart/chart.tsx +189 -0
  26. package/components/chart/index.ts +2 -0
  27. package/components/checkbox/checkbox.tsx +98 -0
  28. package/components/checkbox/index.ts +2 -0
  29. package/components/code-block/code-block.tsx +214 -0
  30. package/components/code-block/index.ts +2 -0
  31. package/components/collapsible/collapsible.tsx +123 -0
  32. package/components/collapsible/index.ts +2 -0
  33. package/components/color-picker/color-picker.tsx +211 -0
  34. package/components/color-picker/index.ts +2 -0
  35. package/components/combobox/combobox.tsx +275 -0
  36. package/components/combobox/index.ts +2 -0
  37. package/components/command/command.tsx +304 -0
  38. package/components/command/index.ts +2 -0
  39. package/components/confirm-dialog/confirm-dialog.tsx +140 -0
  40. package/components/confirm-dialog/index.ts +2 -0
  41. package/components/context-menu/context-menu.tsx +188 -0
  42. package/components/context-menu/index.ts +2 -0
  43. package/components/countdown/countdown.tsx +165 -0
  44. package/components/countdown/index.ts +2 -0
  45. package/components/data-table/data-table.tsx +256 -0
  46. package/components/data-table/index.ts +2 -0
  47. package/components/date-picker/date-picker.tsx +280 -0
  48. package/components/date-picker/index.ts +2 -0
  49. package/components/dialog/dialog.tsx +84 -0
  50. package/components/dialog/index.ts +2 -0
  51. package/components/drawer/drawer.tsx +141 -0
  52. package/components/drawer/index.ts +2 -0
  53. package/components/dropdown-menu/dropdown-menu.tsx +188 -0
  54. package/components/dropdown-menu/index.ts +2 -0
  55. package/components/empty/empty.tsx +107 -0
  56. package/components/empty/index.ts +2 -0
  57. package/components/field/field.tsx +83 -0
  58. package/components/field/index.ts +2 -0
  59. package/components/form/form.tsx +202 -0
  60. package/components/form/index.ts +8 -0
  61. package/components/hover-card/hover-card.tsx +72 -0
  62. package/components/hover-card/index.ts +2 -0
  63. package/components/input-otp/index.ts +2 -0
  64. package/components/input-otp/input-otp.tsx +176 -0
  65. package/components/kbd/index.ts +2 -0
  66. package/components/kbd/kbd.tsx +30 -0
  67. package/components/label/index.ts +2 -0
  68. package/components/label/label.tsx +56 -0
  69. package/components/list/index.ts +2 -0
  70. package/components/list/list.tsx +247 -0
  71. package/components/menubar/index.ts +2 -0
  72. package/components/menubar/menubar.tsx +220 -0
  73. package/components/navigation-menu/index.ts +6 -0
  74. package/components/navigation-menu/navigation-menu.tsx +216 -0
  75. package/components/pagination/index.ts +2 -0
  76. package/components/pagination/pagination.tsx +158 -0
  77. package/components/password-input/index.ts +2 -0
  78. package/components/password-input/password-input.tsx +198 -0
  79. package/components/popover/index.ts +2 -0
  80. package/components/popover/popover.tsx +102 -0
  81. package/components/progress/index.ts +2 -0
  82. package/components/progress/progress.tsx +73 -0
  83. package/components/radio-group/index.ts +2 -0
  84. package/components/radio-group/radio-group.tsx +167 -0
  85. package/components/resizable/index.ts +2 -0
  86. package/components/resizable/resizable.tsx +141 -0
  87. package/components/scroll-area/index.ts +2 -0
  88. package/components/scroll-area/scroll-area.tsx +133 -0
  89. package/components/select/index.ts +2 -0
  90. package/components/select/select.tsx +185 -0
  91. package/components/separator/index.ts +2 -0
  92. package/components/separator/separator.tsx +63 -0
  93. package/components/sheet/index.ts +2 -0
  94. package/components/sheet/sheet.tsx +137 -0
  95. package/components/sidebar/index.ts +2 -0
  96. package/components/sidebar/sidebar.tsx +225 -0
  97. package/components/skeleton/index.ts +2 -0
  98. package/components/skeleton/skeleton.tsx +64 -0
  99. package/components/slider/index.ts +2 -0
  100. package/components/slider/slider.tsx +128 -0
  101. package/components/spinner/index.ts +2 -0
  102. package/components/spinner/spinner.tsx +57 -0
  103. package/components/stat/index.ts +2 -0
  104. package/components/stat/stat.tsx +138 -0
  105. package/components/stepper/index.ts +2 -0
  106. package/components/stepper/stepper.tsx +219 -0
  107. package/components/switch/index.ts +2 -0
  108. package/components/switch/switch.tsx +102 -0
  109. package/components/table/index.ts +2 -0
  110. package/components/table/table.tsx +242 -0
  111. package/components/tabs/index.ts +2 -0
  112. package/components/tabs/tabs.tsx +240 -0
  113. package/components/tag-input/index.ts +2 -0
  114. package/components/tag-input/tag-input.tsx +180 -0
  115. package/components/terminal/index.ts +2 -0
  116. package/components/terminal/terminal.tsx +162 -0
  117. package/components/text-input/index.ts +2 -0
  118. package/components/text-input/text-input.tsx +179 -0
  119. package/components/textarea/index.ts +2 -0
  120. package/components/textarea/textarea.tsx +206 -0
  121. package/components/timeline/index.ts +2 -0
  122. package/components/timeline/timeline.tsx +167 -0
  123. package/components/toast/index.ts +2 -0
  124. package/components/toast/toast.tsx +93 -0
  125. package/components/toggle/index.ts +2 -0
  126. package/components/toggle/toggle.tsx +114 -0
  127. package/components/toggle-group/index.ts +2 -0
  128. package/components/toggle-group/toggle-group.tsx +176 -0
  129. package/components/tooltip/index.ts +2 -0
  130. package/components/tooltip/tooltip.tsx +65 -0
  131. package/components/tree-view/index.ts +2 -0
  132. package/components/tree-view/tree-view.tsx +245 -0
  133. package/components/typography/index.ts +12 -0
  134. package/components/typography/typography.tsx +154 -0
  135. package/dist/index.d.ts +102 -0
  136. package/dist/index.js +938 -0
  137. package/dist/index.js.map +1 -0
  138. package/package.json +41 -0
  139. package/registry.json +923 -0
@@ -0,0 +1,407 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { Tokens } from "@hauktui/tokens";
4
+ import { useTokens } from "@hauktui/primitives-ink";
5
+
6
+ export type BannerFont = "block" | "slant" | "small" | "mini" | "simple";
7
+ export type BannerVariant = "default" | "gradient" | "box" | "minimal";
8
+
9
+ export interface BannerProps {
10
+ /** The text to display as ASCII art banner */
11
+ text: string;
12
+ /** Font style for ASCII art */
13
+ font?: BannerFont;
14
+ /** Banner color */
15
+ color?: string;
16
+ /** Secondary color for gradient effect */
17
+ gradientTo?: string;
18
+ /** Banner variant */
19
+ variant?: BannerVariant;
20
+ /** Center the banner */
21
+ center?: boolean;
22
+ /** Custom tokens override */
23
+ tokens?: Tokens;
24
+ /** Additional subtitle text */
25
+ subtitle?: string;
26
+ }
27
+
28
+ // Block-style font (like ANSI Shadow) - 6 lines tall
29
+ const BLOCK_FONT: Record<string, string[]> = {
30
+ A: [" █████╗ ", "██╔══██╗", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"],
31
+ B: ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██████╔╝", "╚═════╝ "],
32
+ C: [" ██████╗", "██╔════╝", "██║ ", "██║ ", "╚██████╗", " ╚═════╝"],
33
+ D: ["██████╗ ", "██╔══██╗", "██║ ██║", "██║ ██║", "██████╔╝", "╚═════╝ "],
34
+ E: ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "███████╗", "╚══════╝"],
35
+ F: ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "██║ ", "╚═╝ "],
36
+ G: [
37
+ " ██████╗ ",
38
+ "██╔════╝ ",
39
+ "██║ ███╗",
40
+ "██║ ██║",
41
+ "╚██████╔╝",
42
+ " ╚═════╝ ",
43
+ ],
44
+ H: ["██╗ ██╗", "██║ ██║", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"],
45
+ I: ["██╗", "██║", "██║", "██║", "██║", "╚═╝"],
46
+ J: [" ██╗", " ██║", " ██║", "██ ██║", "╚█████╔╝", " ╚════╝ "],
47
+ K: ["██╗ ██╗", "██║ ██╔╝", "█████╔╝ ", "██╔═██╗ ", "██║ ██╗", "╚═╝ ╚═╝"],
48
+ L: ["██╗ ", "██║ ", "██║ ", "██║ ", "███████╗", "╚══════╝"],
49
+ M: [
50
+ "███╗ ███╗",
51
+ "████╗ ████║",
52
+ "██╔████╔██║",
53
+ "██║╚██╔╝██║",
54
+ "██║ ╚═╝ ██║",
55
+ "╚═╝ ╚═╝",
56
+ ],
57
+ N: [
58
+ "███╗ ██╗",
59
+ "████╗ ██║",
60
+ "██╔██╗ ██║",
61
+ "██║╚██╗██║",
62
+ "██║ ╚████║",
63
+ "╚═╝ ╚═══╝",
64
+ ],
65
+ O: [
66
+ " ██████╗ ",
67
+ "██╔═══██╗",
68
+ "██║ ██║",
69
+ "██║ ██║",
70
+ "╚██████╔╝",
71
+ " ╚═════╝ ",
72
+ ],
73
+ P: ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔═══╝ ", "██║ ", "╚═╝ "],
74
+ Q: [
75
+ " ██████╗ ",
76
+ "██╔═══██╗",
77
+ "██║ ██║",
78
+ "██║▄▄ ██║",
79
+ "╚██████╔╝",
80
+ " ╚══▀▀═╝ ",
81
+ ],
82
+ R: ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██║ ██║", "╚═╝ ╚═╝"],
83
+ S: ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"],
84
+ T: [
85
+ "████████╗",
86
+ "╚══██╔══╝",
87
+ " ██║ ",
88
+ " ██║ ",
89
+ " ██║ ",
90
+ " ╚═╝ ",
91
+ ],
92
+ U: [
93
+ "██╗ ██╗",
94
+ "██║ ██║",
95
+ "██║ ██║",
96
+ "██║ ██║",
97
+ "╚██████╔╝",
98
+ " ╚═════╝ ",
99
+ ],
100
+ V: [
101
+ "██╗ ██╗",
102
+ "██║ ██║",
103
+ "██║ ██║",
104
+ "╚██╗ ██╔╝",
105
+ " ╚████╔╝ ",
106
+ " ╚═══╝ ",
107
+ ],
108
+ W: [
109
+ "██╗ ██╗",
110
+ "██║ ██║",
111
+ "██║ █╗ ██║",
112
+ "██║███╗██║",
113
+ "╚███╔███╔╝",
114
+ " ╚══╝╚══╝ ",
115
+ ],
116
+ X: ["██╗ ██╗", "╚██╗██╔╝", " ╚███╔╝ ", " ██╔██╗ ", "██╔╝ ██╗", "╚═╝ ╚═╝"],
117
+ Y: [
118
+ "██╗ ██╗",
119
+ "╚██╗ ██╔╝",
120
+ " ╚████╔╝ ",
121
+ " ╚██╔╝ ",
122
+ " ██║ ",
123
+ " ╚═╝ ",
124
+ ],
125
+ Z: ["███████╗", "╚══███╔╝", " ███╔╝ ", " ███╔╝ ", "███████╗", "╚══════╝"],
126
+ "0": [
127
+ " ██████╗ ",
128
+ "██╔═████╗",
129
+ "██║██╔██║",
130
+ "████╔╝██║",
131
+ "╚██████╔╝",
132
+ " ╚═════╝ ",
133
+ ],
134
+ "1": [" ██╗", "███║", "╚██║", " ██║", " ██║", " ╚═╝"],
135
+ "2": ["██████╗ ", "╚════██╗", " █████╔╝", "██╔═══╝ ", "███████╗", "╚══════╝"],
136
+ "3": ["██████╗ ", "╚════██╗", " █████╔╝", " ╚═══██╗", "██████╔╝", "╚═════╝ "],
137
+ "4": ["██╗ ██╗", "██║ ██║", "███████║", "╚════██║", " ██║", " ╚═╝"],
138
+ "5": ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"],
139
+ "6": [
140
+ " ██████╗ ",
141
+ "██╔════╝ ",
142
+ "███████╗ ",
143
+ "██╔═══██╗",
144
+ "╚██████╔╝",
145
+ " ╚═════╝ ",
146
+ ],
147
+ "7": ["███████╗", "╚════██║", " ██╔╝", " ██╔╝ ", " ██║ ", " ╚═╝ "],
148
+ "8": [" █████╗ ", "██╔══██╗", "╚█████╔╝", "██╔══██╗", "╚█████╔╝", " ╚════╝ "],
149
+ "9": [" █████╗ ", "██╔══██╗", "╚██████║", " ╚═══██║", " █████╔╝", " ╚════╝ "],
150
+ " ": [" ", " ", " ", " ", " ", " "],
151
+ "!": ["██╗", "██║", "██║", "╚═╝", "██╗", "╚═╝"],
152
+ ".": [" ", " ", " ", " ", "██╗", "╚═╝"],
153
+ "-": [" ", " ", "█████╗", "╚════╝", " ", " "],
154
+ _: [" ", " ", " ", " ", "███████╗", "╚══════╝"],
155
+ };
156
+
157
+ // Slant style font - 6 lines tall
158
+ const SLANT_FONT: Record<string, string[]> = {
159
+ A: [
160
+ " ___ ",
161
+ " / _ | ",
162
+ " / __ | ",
163
+ "/_/ |_| ",
164
+ " ",
165
+ " ",
166
+ ],
167
+ B: [" ___ ", " / _ )", " / _ |", "/____/ ", " ", " "],
168
+ C: [" _____", " / ___/", "/ /__ ", "\\___/ ", " ", " "],
169
+ D: [" ___ ", " / _ \\", " / // /", "/____/ ", " ", " "],
170
+ E: [" ____", " / __/", " / _/ ", "/___/ ", " ", " "],
171
+ F: [" ____", " / __/", " / _/ ", "/_/ ", " ", " "],
172
+ G: [" _____", " / ___/", "/ (_ / ", "\\___/ ", " ", " "],
173
+ H: [" __ __", " / // /", " / _ / ", "/_//_/ ", " ", " "],
174
+ I: [" ____", " / _/", " _/ / ", "/___/ ", " ", " "],
175
+ J: [" __", " _ / /", "/ / / ", "\\__/ ", " ", " "],
176
+ K: [" __ __", " / //_/", " / ,< ", "/_/|_| ", " ", " "],
177
+ L: [" __ ", " / / ", " / /__", "/____/", " ", " "],
178
+ M: [
179
+ " __ ___",
180
+ " / |/ /",
181
+ " / /|_/ / ",
182
+ "/_/ /_/ ",
183
+ " ",
184
+ " ",
185
+ ],
186
+ N: [" _ __", " / |/ /", " / / ", "/_/|_/ ", " ", " "],
187
+ O: [" ____ ", " / __ \\", "/ /_/ /", "\\____/ ", " ", " "],
188
+ P: [" ___ ", " / _ \\", " / ___/", "/_/ ", " ", " "],
189
+ Q: [" ____ ", " / __ \\", "/ /_/ /", "\\___\\_\\", " ", " "],
190
+ R: [" ___ ", " / _ \\", " / , _/", "/_/|_| ", " ", " "],
191
+ S: [" ____", " / __/", " _\\ \\ ", "/___/ ", " ", " "],
192
+ T: [" ______", "/_ __/", " / / ", "/_/ ", " ", " "],
193
+ U: [" __ __", " / / / /", "/ /_/ / ", "\\____/ ", " ", " "],
194
+ V: [" _ __", "| | / /", "| |/ / ", "|___/ ", " ", " "],
195
+ W: [
196
+ " _ __",
197
+ "| | /| / /",
198
+ "| |/ |/ / ",
199
+ "|__/|__/ ",
200
+ " ",
201
+ " ",
202
+ ],
203
+ X: [" _ __", " | |/_/", " _> < ", "/_/|_| ", " ", " "],
204
+ Y: ["__ __", "\\ \\/ /", " \\ / ", " /_/ ", " ", " "],
205
+ Z: [" ____", "/_ /", " / /_", "/___/", " ", " "],
206
+ " ": [" ", " ", " ", " ", " ", " "],
207
+ };
208
+
209
+ // Small block font - 4 lines tall
210
+ const SMALL_FONT: Record<string, string[]> = {
211
+ A: ["▄▀█", "█▀█", " ", " "],
212
+ B: ["█▄▄", "█▄█", " ", " "],
213
+ C: ["█▀▀", "█▄▄", " ", " "],
214
+ D: ["█▀▄", "█▄▀", " ", " "],
215
+ E: ["█▀▀", "██▄", " ", " "],
216
+ F: ["█▀▀", "█▀ ", " ", " "],
217
+ G: ["█▀▀", "█▄█", " ", " "],
218
+ H: ["█ █", "█▀█", " ", " "],
219
+ I: ["█", "█", " ", " "],
220
+ J: [" █", "▀█", " ", " "],
221
+ K: ["█▄▀", "█ █", " ", " "],
222
+ L: ["█ ", "█▄▄", " ", " "],
223
+ M: ["█▄ ▄█", "█ ▀ █", " ", " "],
224
+ N: ["█▄ █", "█ ▀█", " ", " "],
225
+ O: ["█▀█", "█▄█", " ", " "],
226
+ P: ["█▀█", "█▀▀", " ", " "],
227
+ Q: ["█▀█", "▀▀█", " ", " "],
228
+ R: ["█▀█", "█▀▄", " ", " "],
229
+ S: ["█▀▀", "▄▄█", " ", " "],
230
+ T: ["▀█▀", " █ ", " ", " "],
231
+ U: ["█ █", "█▄█", " ", " "],
232
+ V: ["█ █", "▀▄▀", " ", " "],
233
+ W: ["█ ▄ █", "▀▄▀▄▀", " ", " "],
234
+ X: ["▀▄▀", "█ █", " ", " "],
235
+ Y: ["█ █", " █ ", " ", " "],
236
+ Z: ["▀▀█", "█▄▄", " ", " "],
237
+ " ": [" ", " ", " ", " "],
238
+ };
239
+
240
+ // Mini font - 3 lines tall
241
+ const MINI_FONT: Record<string, string[]> = {
242
+ A: ["█▀█", "█▀█", "▀ ▀"],
243
+ B: ["██▄", "█▄█", " "],
244
+ C: ["█▀▀", "█▄▄", " "],
245
+ D: ["█▀▄", "█▄▀", " "],
246
+ E: ["█▀▀", "██▄", " "],
247
+ F: ["█▀▀", "█▀ ", " "],
248
+ G: ["█▀▀", "█▄█", " "],
249
+ H: ["█ █", "█▀█", " "],
250
+ I: ["█", "█", " "],
251
+ J: [" █", "▀█", " "],
252
+ K: ["█▀▄", "█ █", " "],
253
+ L: ["█ ", "█▄▄", " "],
254
+ M: ["█▄█", "█ █", " "],
255
+ N: ["█▀█", "█ █", " "],
256
+ O: ["█▀█", "█▄█", " "],
257
+ P: ["█▀█", "█▀ ", " "],
258
+ Q: ["█▀█", "▀▀█", " "],
259
+ R: ["█▀█", "█▀▄", " "],
260
+ S: ["█▀▀", "▄▄█", " "],
261
+ T: ["▀█▀", " █ ", " "],
262
+ U: ["█ █", "█▄█", " "],
263
+ V: ["█ █", "▀▄▀", " "],
264
+ W: ["█ █", "▀▄▀", " "],
265
+ X: ["▀▄▀", "█ █", " "],
266
+ Y: ["█ █", " █ ", " "],
267
+ Z: ["▀▀█", "█▄▄", " "],
268
+ " ": [" ", " ", " "],
269
+ };
270
+
271
+ // Simple font - 1 line, just bold text
272
+ const SIMPLE_FONT: Record<string, string[]> = {};
273
+
274
+ const FONTS: Record<string, Record<string, string[]>> = {
275
+ block: BLOCK_FONT,
276
+ slant: SLANT_FONT,
277
+ small: SMALL_FONT,
278
+ mini: MINI_FONT,
279
+ simple: SIMPLE_FONT,
280
+ };
281
+
282
+ function getDefaultChar(height: number): string[] {
283
+ return Array(height).fill(" ");
284
+ }
285
+
286
+ function textToAscii(text: string, font: BannerFont): string[] {
287
+ if (font === "simple") {
288
+ return [text.toUpperCase()];
289
+ }
290
+
291
+ const chars = text.toUpperCase().split("");
292
+ const fontData = FONTS[font] || BLOCK_FONT;
293
+ const sampleChar = fontData["A"] || fontData["H"];
294
+ const height = sampleChar?.length || 6;
295
+
296
+ const lines: string[] = Array(height).fill("");
297
+
298
+ for (const char of chars) {
299
+ const charArt = fontData[char] || fontData[" "] || getDefaultChar(height);
300
+ for (let i = 0; i < height; i++) {
301
+ lines[i] += charArt[i] || "";
302
+ }
303
+ }
304
+
305
+ // Trim trailing empty lines
306
+ while (lines.length > 0 && lines[lines.length - 1]!.trim() === "") {
307
+ lines.pop();
308
+ }
309
+
310
+ return lines;
311
+ }
312
+
313
+ function interpolateColor(
314
+ color1: string,
315
+ color2: string,
316
+ ratio: number
317
+ ): string {
318
+ // Simple color interpolation - just pick based on ratio
319
+ if (ratio < 0.5) return color1;
320
+ return color2;
321
+ }
322
+
323
+ export function Banner({
324
+ text,
325
+ font = "block",
326
+ color,
327
+ gradientTo,
328
+ variant = "default",
329
+ center = true,
330
+ tokens: propTokens,
331
+ subtitle,
332
+ }: BannerProps): React.ReactElement {
333
+ const contextTokens = useTokens();
334
+ const tokens = propTokens ?? contextTokens;
335
+
336
+ const asciiLines = textToAscii(text, font);
337
+ const bannerColor = color || tokens.colors.accent;
338
+
339
+ const renderLines = () => {
340
+ return asciiLines.map((line, index) => {
341
+ let textColor = bannerColor;
342
+
343
+ if (gradientTo && asciiLines.length > 1) {
344
+ const ratio = index / (asciiLines.length - 1);
345
+ textColor = interpolateColor(bannerColor, gradientTo, ratio);
346
+ }
347
+
348
+ return React.createElement(
349
+ Box,
350
+ { key: index, justifyContent: center ? "center" : "flex-start" },
351
+ React.createElement(Text, { color: textColor }, line)
352
+ );
353
+ });
354
+ };
355
+
356
+ const content = React.createElement(
357
+ Box,
358
+ { flexDirection: "column" },
359
+ ...renderLines(),
360
+ subtitle
361
+ ? React.createElement(
362
+ Box,
363
+ { justifyContent: center ? "center" : "flex-start", marginTop: 1 },
364
+ React.createElement(
365
+ Text,
366
+ { color: tokens.colors.muted, dimColor: true },
367
+ subtitle
368
+ )
369
+ )
370
+ : null
371
+ );
372
+
373
+ if (variant === "box") {
374
+ return React.createElement(
375
+ Box,
376
+ {
377
+ flexDirection: "column",
378
+ borderStyle: "round",
379
+ borderColor: bannerColor,
380
+ paddingX: 2,
381
+ paddingY: 1,
382
+ },
383
+ content
384
+ );
385
+ }
386
+
387
+ if (variant === "minimal") {
388
+ return React.createElement(
389
+ Box,
390
+ { flexDirection: "column" },
391
+ React.createElement(
392
+ Box,
393
+ { justifyContent: center ? "center" : "flex-start" },
394
+ React.createElement(Text, { color: bannerColor, bold: true }, text)
395
+ ),
396
+ subtitle
397
+ ? React.createElement(
398
+ Box,
399
+ { justifyContent: center ? "center" : "flex-start" },
400
+ React.createElement(Text, { color: tokens.colors.muted }, subtitle)
401
+ )
402
+ : null
403
+ );
404
+ }
405
+
406
+ return content;
407
+ }
@@ -0,0 +1,2 @@
1
+ export { Banner } from "./banner.js";
2
+ export type { BannerProps, BannerVariant } from "./banner.js";
@@ -0,0 +1,58 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { Tokens } from "@hauktui/tokens";
4
+ import { useTokens } from "@hauktui/primitives-ink";
5
+
6
+ export interface BreadcrumbItem {
7
+ /** Item label */
8
+ label: string;
9
+ /** Whether this is the current/active item */
10
+ active?: boolean;
11
+ }
12
+
13
+ export interface BreadcrumbProps {
14
+ /** Breadcrumb items */
15
+ items: BreadcrumbItem[];
16
+ /** Separator between items */
17
+ separator?: string;
18
+ /** Custom tokens override */
19
+ tokens?: Tokens;
20
+ }
21
+
22
+ export function Breadcrumb({
23
+ items,
24
+ separator = " / ",
25
+ tokens: propTokens,
26
+ }: BreadcrumbProps): React.ReactElement {
27
+ const contextTokens = useTokens();
28
+ const tokens = propTokens ?? contextTokens;
29
+
30
+ return React.createElement(
31
+ Box,
32
+ null,
33
+ items.map((item, index) => {
34
+ const isLast = index === items.length - 1;
35
+ const isActive = item.active || isLast;
36
+
37
+ return React.createElement(
38
+ React.Fragment,
39
+ { key: index },
40
+ React.createElement(
41
+ Text,
42
+ {
43
+ color: isActive ? tokens.colors.fg : tokens.colors.muted,
44
+ bold: isActive,
45
+ },
46
+ item.label
47
+ ),
48
+ !isLast
49
+ ? React.createElement(
50
+ Text,
51
+ { color: tokens.colors.border },
52
+ separator
53
+ )
54
+ : null
55
+ );
56
+ })
57
+ );
58
+ }
@@ -0,0 +1,2 @@
1
+ export { Breadcrumb } from "./breadcrumb.js";
2
+ export type { BreadcrumbProps, BreadcrumbItem } from "./breadcrumb.js";
@@ -0,0 +1,114 @@
1
+ import React, { useState, useCallback } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import type { Tokens } from "@hauktui/tokens";
4
+ import { useTokens, useFocusable } from "@hauktui/primitives-ink";
5
+ import { stableId } from "@hauktui/core";
6
+
7
+ export interface ButtonProps {
8
+ /** Button label */
9
+ children: React.ReactNode;
10
+ /** Callback when button is activated */
11
+ onPress?: () => void;
12
+ /** Whether the button is disabled */
13
+ disabled?: boolean;
14
+ /** Button variant */
15
+ variant?: "default" | "primary" | "danger" | "ghost";
16
+ /** Custom tokens override */
17
+ tokens?: Tokens;
18
+ /** Focus ID for focus management */
19
+ focusId?: string;
20
+ }
21
+
22
+ export function Button({
23
+ children,
24
+ onPress,
25
+ disabled = false,
26
+ variant = "default",
27
+ tokens: propTokens,
28
+ focusId,
29
+ }: ButtonProps): React.ReactElement {
30
+ const contextTokens = useTokens();
31
+ const tokens = propTokens ?? contextTokens;
32
+ const id = focusId ?? stableId("button");
33
+ const { isFocused } = useFocusable(id);
34
+ const [isPressed, setIsPressed] = useState(false);
35
+
36
+ // Handle key input when focused
37
+ useInput(
38
+ (input, key) => {
39
+ if (!isFocused || disabled) return;
40
+
41
+ if (key.return || input === " ") {
42
+ setIsPressed(true);
43
+ onPress?.();
44
+ setTimeout(() => setIsPressed(false), 100);
45
+ }
46
+ },
47
+ { isActive: isFocused }
48
+ );
49
+
50
+ // Determine colors based on state and variant
51
+ const getColors = useCallback(() => {
52
+ if (disabled) {
53
+ return {
54
+ bg: tokens.colors.disabled,
55
+ fg: tokens.colors.muted,
56
+ border: tokens.colors.disabled,
57
+ };
58
+ }
59
+
60
+ if (isPressed) {
61
+ return {
62
+ bg: tokens.colors.accent,
63
+ fg: tokens.colors.bg,
64
+ border: tokens.colors.accent,
65
+ };
66
+ }
67
+
68
+ switch (variant) {
69
+ case "primary":
70
+ return {
71
+ bg: isFocused ? tokens.colors.accent : tokens.colors.border,
72
+ fg: isFocused ? tokens.colors.bg : tokens.colors.fg,
73
+ border: tokens.colors.accent,
74
+ };
75
+ case "danger":
76
+ return {
77
+ bg: isFocused ? tokens.colors.danger : tokens.colors.border,
78
+ fg: isFocused ? tokens.colors.bg : tokens.colors.danger,
79
+ border: tokens.colors.danger,
80
+ };
81
+ case "ghost":
82
+ return {
83
+ bg: undefined,
84
+ fg: isFocused ? tokens.colors.accent : tokens.colors.fg,
85
+ border: isFocused ? tokens.colors.focus : tokens.colors.border,
86
+ };
87
+ default:
88
+ return {
89
+ bg: isFocused ? tokens.colors.border : undefined,
90
+ fg: isFocused ? tokens.colors.fg : tokens.colors.muted,
91
+ border: isFocused ? tokens.colors.focus : tokens.colors.border,
92
+ };
93
+ }
94
+ }, [disabled, isPressed, variant, isFocused, tokens]);
95
+
96
+ const colors = getColors();
97
+
98
+ return React.createElement(
99
+ Box,
100
+ {
101
+ borderStyle: "round",
102
+ borderColor: colors.border,
103
+ paddingX: 1,
104
+ },
105
+ React.createElement(
106
+ Text,
107
+ {
108
+ color: colors.fg,
109
+ bold: isFocused,
110
+ },
111
+ children
112
+ )
113
+ );
114
+ }
@@ -0,0 +1,2 @@
1
+ export { Button } from "./button.js";
2
+ export type { ButtonProps } from "./button.js";