@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
@@ -1,22 +1,49 @@
1
+ import { adjustBrightness } from '../colors';
2
+ import { visibleWidth } from '../utils';
1
3
  import { Box } from './Box';
2
4
  /**
3
5
  * Tactical Card Component
4
- * A structural container with an integrated header.
6
+ * A structural container with an integrated header. Colors derive from
7
+ * ctx.theme tokens:
8
+ * - default: border `theme.border`, title `theme.muted`
9
+ * - accent: border `theme.border`, title `theme.accent`
10
+ * - danger: border `theme.danger`, title `theme.danger`
11
+ *
12
+ * With an `id`, hovering lifts the border to `theme.focus` and shifts the
13
+ * background one step. Hover styling reads the hitbox registered on the
14
+ * previous frame (immediate-mode: geometry is only exact after a render),
15
+ * which is invisible at interactive frame rates.
5
16
  */
6
17
  export function Card(ctx, props, callback) {
7
- const { color } = ctx;
8
- const neutralGray = { r: 217, g: 216, b: 213 };
9
- let borderColor = neutralGray;
10
- let titleColor = neutralGray;
11
- if (props.theme === 'accent') {
12
- titleColor = 'black';
13
- // Border remains neutral gray
18
+ const { color, theme } = ctx;
19
+ const variant = props.variant ?? props.theme ?? 'default';
20
+ let borderColor = theme.border;
21
+ let titleColor = theme.muted;
22
+ if (variant === 'accent') {
23
+ titleColor = theme.accent;
14
24
  }
15
- else if (props.theme === 'danger') {
16
- borderColor = 'error';
17
- titleColor = 'error';
25
+ else if (variant === 'danger') {
26
+ borderColor = theme.danger;
27
+ titleColor = theme.danger;
18
28
  }
19
- return Box(ctx, {
29
+ // Hover affordance (previous-frame hover state; see docblock).
30
+ const hoverable = props.id !== undefined;
31
+ const hovered = hoverable
32
+ ? (ctx.state.hoverStates.get(props.id) ?? false)
33
+ : false;
34
+ let bgColor = props.bgColor;
35
+ let finalBorder = props.borderColor || borderColor;
36
+ if (hovered) {
37
+ finalBorder = theme.focus;
38
+ const shift = theme.mode === 'dark' ? 12 : -12;
39
+ bgColor =
40
+ bgColor !== undefined &&
41
+ !(typeof bgColor === 'object' && 'colors' in bgColor)
42
+ ? adjustBrightness(bgColor, shift)
43
+ : (bgColor ?? theme.surface);
44
+ }
45
+ const startY = ctx.cursorY;
46
+ const rendered = Box(ctx, {
20
47
  x: props.x,
21
48
  y: props.y,
22
49
  anchor: props.anchor,
@@ -24,14 +51,29 @@ export function Card(ctx, props, callback) {
24
51
  height: props.height,
25
52
  minHeight: props.minHeight,
26
53
  border: props.border || 'frame',
27
- borderColor: props.borderColor || borderColor,
54
+ borderColor: finalBorder,
28
55
  padding: props.padding || [1, 2],
29
- bgColor: props.bgColor,
56
+ bgColor,
30
57
  }, (sub) => {
31
58
  if (props.title) {
32
59
  sub.text(color.fg(titleColor, color.bold(`${props.title.toUpperCase()}\n\n`)));
33
60
  }
34
61
  callback(sub);
35
62
  });
63
+ if (hoverable) {
64
+ const lines = rendered.split('\n');
65
+ const h = lines.length;
66
+ const w = Math.max(0, ...lines.map(visibleWidth));
67
+ // Mirror resolveBoxArea's placement defaults (centered when unplaced).
68
+ const area = ctx.resolveLocalRect({
69
+ x: props.x,
70
+ y: props.y ?? (startY || undefined),
71
+ width: w,
72
+ height: h,
73
+ anchor: props.anchor,
74
+ });
75
+ ctx.hitbox(props.id, area);
76
+ }
77
+ return rendered;
36
78
  }
37
79
  //# sourceMappingURL=Card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/components/Card.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAO5B;;;GAGG;AACH,MAAM,UAAU,IAAI,CAClB,GAAiB,EACjB,KAAgB,EAChB,QAAqC;IAErC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;IAEtB,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;IAC/C,IAAI,WAAW,GAAQ,WAAW,CAAC;IACnC,IAAI,UAAU,GAAQ,WAAW,CAAC;IAElC,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC7B,UAAU,GAAG,OAAO,CAAC;QACrB,8BAA8B;IAChC,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACpC,WAAW,GAAG,OAAO,CAAC;QACtB,UAAU,GAAG,OAAO,CAAC;IACvB,CAAC;IAED,OAAO,GAAG,CACR,GAAG,EACH;QACE,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,MAAM;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,OAAO;QAC/B,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,WAAW;QAC7C,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QAChC,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,EACD,CAAC,GAAG,EAAE,EAAE;QACN,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CACN,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CACrE,CAAC;QACJ,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/components/Card.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,23 @@
1
1
  import type { BuntiContext } from '../dsl';
2
+ /** Props for Header. */
2
3
  export interface HeaderProps {
4
+ /** Centered bar title. */
3
5
  title: string;
6
+ /** Brand glyph on the left edge (use ctx.icon(name)). */
4
7
  leftIcon?: string;
8
+ /** Muted telemetry/exit label on the right edge. */
5
9
  rightLabel?: string;
10
+ /**
11
+ * @deprecated Colors now derive from `ctx.theme` tokens; wrap the Header
12
+ * in `ctx.themed(...)` to restyle it. This prop is ignored.
13
+ */
6
14
  theme?: 'light' | 'dark';
7
15
  }
8
16
  /**
9
17
  * Enterprise Tactical Header
10
- * A full-width, high-signal branding bar.
18
+ * A full-width, high-signal branding bar. Colors derive from ctx.theme:
19
+ * bar `theme.surfaceRaised`, title `theme.foreground`, brand icon
20
+ * `theme.accent`, right label `theme.muted`.
11
21
  */
12
22
  export declare function Header(ctx: BuntiContext, props: HeaderProps): void;
13
23
  //# sourceMappingURL=Header.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/components/Header.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAI3C,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,QAwD3D"}
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/components/Header.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAI3C,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,QA0D3D"}
@@ -2,14 +2,14 @@ import { box as engineBox } from '../layout';
2
2
  import { Box } from './Box';
3
3
  /**
4
4
  * Enterprise Tactical Header
5
- * A full-width, high-signal branding bar.
5
+ * A full-width, high-signal branding bar. Colors derive from ctx.theme:
6
+ * bar `theme.surfaceRaised`, title `theme.foreground`, brand icon
7
+ * `theme.accent`, right label `theme.muted`.
6
8
  */
7
9
  export function Header(ctx, props) {
8
- const { color, joinHorizontal } = ctx;
9
- // Resolve Theme Colors
10
- const isLight = props.theme !== 'dark';
11
- const bg = isLight ? 'white' : 'midnight';
12
- const fg = isLight ? 236 : 'silver';
10
+ const { color, joinHorizontal, theme } = ctx;
11
+ const bg = theme.surfaceRaised;
12
+ const fg = theme.foreground;
13
13
  // Master Background Box
14
14
  Box(ctx, {
15
15
  anchor: 'top',
@@ -24,7 +24,9 @@ export function Header(ctx, props) {
24
24
  constraints: [12, '1fr', 12],
25
25
  });
26
26
  // 1. Left: Branding
27
- const leftStr = props.leftIcon ? color.fg('plasma', props.leftIcon) : '';
27
+ const leftStr = props.leftIcon
28
+ ? color.fg(theme.accent, props.leftIcon)
29
+ : '';
28
30
  const leftNode = engineBox(leftStr, {
29
31
  width: leftArea?.width ?? 0,
30
32
  align: 'left',
@@ -40,7 +42,9 @@ export function Header(ctx, props) {
40
42
  padding: [0, 0],
41
43
  });
42
44
  // 3. Right: Telemetry / Exit
43
- const rightStr = props.rightLabel ? color.dim(props.rightLabel) : '';
45
+ const rightStr = props.rightLabel
46
+ ? color.fg(theme.muted, props.rightLabel)
47
+ : '';
44
48
  const rightNode = engineBox(rightStr, {
45
49
  width: rightArea?.width ?? 0,
46
50
  align: 'right',
@@ -1 +1 @@
1
- {"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/components/Header.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAS5B;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,GAAiB,EAAE,KAAkB;IAC1D,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC;IAEtC,uBAAuB;IACvB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC;IACvC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC1C,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEpC,wBAAwB;IACxB,GAAG,CACD,GAAG,EACH;QACE,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;KAChB,EACD,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC;YAC3C,SAAS,EAAE,YAAY;YACvB,WAAW,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;SAC7B,CAAC,CAAC;QAEH,oBAAoB;QACpB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,EAAE;YAClC,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;YAC3B,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,mBAAmB;QACnB,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE;YAChC,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;YAC1B,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,EAAE;YACpC,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;YAC5B,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,mCAAmC;QACnC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IACrD,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/components/Header.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAiB5B;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAiB,EAAE,KAAkB;IAC1D,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;IAE7C,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC;IAC/B,MAAM,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;IAE5B,wBAAwB;IACxB,GAAG,CACD,GAAG,EACH;QACE,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;KAChB,EACD,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC;YAC3C,SAAS,EAAE,YAAY;YACvB,WAAW,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;SAC7B,CAAC,CAAC;QAEH,oBAAoB;QACpB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ;YAC5B,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;YACxC,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,EAAE;YAClC,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;YAC3B,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,mBAAmB;QACnB,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE;YAChC,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;YAC1B,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;YAC/B,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC;YACzC,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,EAAE;YACpC,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;YAC5B,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;SAChB,CAAC,CAAC;QAEH,mCAAmC;QACnC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IACrD,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1,16 +1,25 @@
1
1
  import type { BuntiContext } from '../dsl';
2
2
  import type { StyleOptions } from '../layout';
3
+ /** Props for Input. */
3
4
  export interface InputProps extends StyleOptions {
5
+ /** Stable id: keys the value state, focus slot, and hitbox. */
4
6
  id: string;
7
+ /** Label rendered above the field. */
5
8
  label?: string;
9
+ /** Ghost text shown while the field is empty. */
6
10
  placeholder?: string;
11
+ /** Initial value (state lives in useState(id) afterwards). */
7
12
  value?: string;
13
+ /** 'password' masks every glyph as '*'. */
8
14
  type?: 'text' | 'password';
15
+ /** Fires with the new value after every edit. */
9
16
  onChange?: (value: string) => void;
10
17
  }
11
18
  /**
12
19
  * Tactical Input Component
13
- * Managed state HOC with cursor simulation, keyboard interception, and mouse focus.
20
+ * Managed state HOC with a grapheme-aware editing cursor (insert/delete at
21
+ * cursor, arrows/home/end, ctrl+a/ctrl+e), an inverse-video cursor cell, and
22
+ * a width-aware horizontal scroll window.
14
23
  */
15
24
  export declare function Input(ctx: BuntiContext, props: InputProps): string;
16
25
  //# sourceMappingURL=Input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,UA2GzD"}
1
+ {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,uBAAuB;AACvB,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAyJD;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,UA6HzD"}
@@ -1,7 +1,128 @@
1
- import { indentBlock } from '../utils';
1
+ import { charWidth, indentBlock } from '../utils';
2
+ /** Key names that must never insert as text. */
3
+ const NON_TEXT_KEYS = new Set([
4
+ 'up',
5
+ 'down',
6
+ 'left',
7
+ 'right',
8
+ 'enter',
9
+ 'escape',
10
+ 'tab',
11
+ 'backspace',
12
+ 'home',
13
+ 'end',
14
+ 'delete',
15
+ 'pageup',
16
+ 'pagedown',
17
+ 'insert',
18
+ 'click',
19
+ 'wheel_up',
20
+ 'wheel_down',
21
+ ]);
22
+ const FN_KEY_RE = /^f\d{1,2}$/;
23
+ function graphemes(text) {
24
+ if (text.length === 0)
25
+ return [];
26
+ const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
27
+ return Array.from(segmenter.segment(text), ({ segment }) => segment);
28
+ }
29
+ function isTextKey(key) {
30
+ return key.length > 0 && !NON_TEXT_KEYS.has(key) && !FN_KEY_RE.test(key);
31
+ }
32
+ /**
33
+ * Applies one frame of KeyEvents to the (value, cursor) pair. Grapheme-aware:
34
+ * cursor is a grapheme index, insert/delete operate on whole graphemes.
35
+ * Ctrl/alt combos never insert; ctrl+a/ctrl+e map to home/end (readline).
36
+ */
37
+ function applyKeys(keys, value, cursor) {
38
+ let glyphs = graphemes(value);
39
+ let pos = Math.max(0, Math.min(cursor, glyphs.length));
40
+ let changed = false;
41
+ for (const event of keys) {
42
+ if (event.kind === 'release')
43
+ continue;
44
+ if (event.ctrl || event.alt) {
45
+ // Readline muscle memory; every other modified combo is ignored so
46
+ // control bytes can never leak into the value.
47
+ if (event.ctrl && !event.alt && event.key === 'a')
48
+ pos = 0;
49
+ if (event.ctrl && !event.alt && event.key === 'e')
50
+ pos = glyphs.length;
51
+ continue;
52
+ }
53
+ switch (event.key) {
54
+ case 'left':
55
+ pos = Math.max(0, pos - 1);
56
+ break;
57
+ case 'right':
58
+ pos = Math.min(glyphs.length, pos + 1);
59
+ break;
60
+ case 'home':
61
+ pos = 0;
62
+ break;
63
+ case 'end':
64
+ pos = glyphs.length;
65
+ break;
66
+ case 'backspace':
67
+ if (pos > 0) {
68
+ glyphs = [...glyphs.slice(0, pos - 1), ...glyphs.slice(pos)];
69
+ pos--;
70
+ changed = true;
71
+ }
72
+ break;
73
+ case 'delete':
74
+ if (pos < glyphs.length) {
75
+ glyphs = [...glyphs.slice(0, pos), ...glyphs.slice(pos + 1)];
76
+ changed = true;
77
+ }
78
+ break;
79
+ default:
80
+ if (isTextKey(event.key)) {
81
+ glyphs = [...glyphs.slice(0, pos), event.key, ...glyphs.slice(pos)];
82
+ pos++;
83
+ changed = true;
84
+ }
85
+ }
86
+ }
87
+ return { value: glyphs.join(''), cursor: pos, changed };
88
+ }
89
+ /**
90
+ * Computes the horizontal scroll window that keeps the cursor visible in
91
+ * `innerW` columns. Width-aware: wide graphemes (emoji) count their real
92
+ * column width, so the window never overflows the field.
93
+ */
94
+ function cursorWindow(glyphs, cursor, scrollX, innerW) {
95
+ const widths = glyphs.map((g) => charWidth(g));
96
+ const cursorGlyph = cursor < glyphs.length ? glyphs[cursor] : ' ';
97
+ const cursorW = cursor < glyphs.length ? widths[cursor] : 1;
98
+ let scroll = Math.max(0, Math.min(scrollX, glyphs.length));
99
+ if (cursor < scroll)
100
+ scroll = cursor;
101
+ const spanWidth = (from) => {
102
+ let w = 0;
103
+ for (let i = from; i < cursor; i++)
104
+ w += widths[i];
105
+ return w + cursorW;
106
+ };
107
+ // Scroll right until the cursor cell fits (tail view when cursor at end).
108
+ while (scroll < cursor && spanWidth(scroll) > innerW)
109
+ scroll++;
110
+ const before = glyphs.slice(scroll, cursor).join('');
111
+ let used = spanWidth(scroll);
112
+ let after = '';
113
+ for (let i = cursor + 1; i < glyphs.length; i++) {
114
+ if (used + widths[i] > innerW)
115
+ break;
116
+ after += glyphs[i];
117
+ used += widths[i];
118
+ }
119
+ return { scroll, before, cursorGlyph, after };
120
+ }
2
121
  /**
3
122
  * Tactical Input Component
4
- * Managed state HOC with cursor simulation, keyboard interception, and mouse focus.
123
+ * Managed state HOC with a grapheme-aware editing cursor (insert/delete at
124
+ * cursor, arrows/home/end, ctrl+a/ctrl+e), an inverse-video cursor cell, and
125
+ * a width-aware horizontal scroll window.
5
126
  */
6
127
  export function Input(ctx, props) {
7
128
  const { box, color, focusable, state, useState, hitbox, resolveLocalRect } = ctx;
@@ -21,6 +142,10 @@ export function Input(ctx, props) {
21
142
  y: area.y,
22
143
  width: area.width,
23
144
  height: area.height,
145
+ // In a box the field joins the text flow (indented to area.x), so the
146
+ // hitbox is flow-anchored and re-placed with the painted line — content
147
+ // alignment can't separate it from the rendered field.
148
+ flow: !ctx.isRoot,
24
149
  });
25
150
  const isHovered = interaction.hovered;
26
151
  // If clicked, force focus state
@@ -29,52 +154,61 @@ export function Input(ctx, props) {
29
154
  }
30
155
  // 2. Register in the global focus loop
31
156
  const isSelected = focusable(props.id);
32
- // 3. Manage internal state
157
+ // 3. Manage internal state: value + grapheme cursor + scroll window
33
158
  const [value, setValue] = useState(props.id, props.value || '');
34
- // 4. Handle Keyboard Interaction (only when focused)
35
- if (isSelected && state.lastKey) {
36
- const key = state.lastKey;
37
- if (key === 'backspace') {
38
- if (value.length > 0) {
39
- const newValue = value.slice(0, -1);
40
- setValue(newValue);
41
- if (props.onChange)
42
- props.onChange(newValue);
43
- }
44
- }
45
- else if (key === 'enter' ||
46
- key === 'tab' ||
47
- key === 'escape' ||
48
- key === 'up' ||
49
- key === 'down' ||
50
- key === 'left' ||
51
- key === 'right') {
52
- // System keys: ignore
53
- }
54
- else if (key.length === 1) {
55
- // Standard character input
56
- const newValue = value + key;
57
- setValue(newValue);
159
+ const [storedCursor, setCursor] = useState(`${props.id}_cursor`, graphemes(value).length);
160
+ const [scrollX, setScrollX] = useState(`${props.id}_scroll`, 0);
161
+ // The value can change externally (props/onChange round-trips): re-clamp.
162
+ let glyphs = graphemes(value);
163
+ let cursor = Math.max(0, Math.min(storedCursor, glyphs.length));
164
+ // 4. Keyboard interaction via the KeyEvent frame queue (only when focused)
165
+ if (isSelected && ctx.keys.length > 0) {
166
+ const edit = applyKeys(ctx.keys, value, cursor);
167
+ if (edit.changed) {
168
+ setValue(edit.value);
58
169
  if (props.onChange)
59
- props.onChange(newValue);
170
+ props.onChange(edit.value);
171
+ glyphs = graphemes(edit.value);
60
172
  }
173
+ if (edit.cursor !== storedCursor)
174
+ setCursor(edit.cursor);
175
+ cursor = edit.cursor;
61
176
  }
62
- // 5. Resolve Theme
63
- const neutralGray = { r: 217, g: 216, b: 213 };
64
- const borderCol = isSelected ? 'bunti-blue' : isHovered ? 'ash' : neutralGray;
65
- const labelColor = 'silver';
66
- const placeholderColor = 'ash';
67
- const textColor = 'white';
177
+ // 5. Resolve Theme — all colors come from ctx.theme tokens so the field
178
+ // restyles on live theme swaps.
179
+ const theme = ctx.theme;
180
+ const borderCol = isSelected
181
+ ? theme.focus
182
+ : isHovered
183
+ ? theme.muted
184
+ : theme.border;
185
+ const labelColor = theme.foreground;
186
+ const placeholderColor = theme.muted;
187
+ const textColor = theme.foreground;
188
+ // Inverse-video cursor cell: swap the field's fg/bg at the cursor.
189
+ const inverse = (s) => color.bg(theme.foreground, color.fg(theme.surface, s));
190
+ const displayGlyphs = props.type === 'password' ? glyphs.map(() => '*') : glyphs;
191
+ // Inner columns between the borders and [0,1] padding.
192
+ const innerW = Math.max(1, area.width - 4);
68
193
  let fieldValue = '';
69
- if (value.length === 0 && props.placeholder) {
70
- fieldValue = color.fg(placeholderColor, props.placeholder);
194
+ if (glyphs.length === 0) {
195
+ const placeholder = props.placeholder
196
+ ? color.fg(placeholderColor, props.placeholder)
197
+ : '';
198
+ // Focused empty field: inverse-space cursor, ghost placeholder after it.
199
+ fieldValue = isSelected ? inverse(' ') + placeholder : placeholder;
71
200
  }
72
- else {
73
- const displayValue = props.type === 'password' ? '*'.repeat(value.length) : value;
74
- fieldValue = color.fg(textColor, displayValue);
201
+ else if (isSelected) {
202
+ const win = cursorWindow(displayGlyphs, cursor, scrollX, innerW);
203
+ if (win.scroll !== scrollX)
204
+ setScrollX(win.scroll);
205
+ fieldValue =
206
+ color.fg(textColor, win.before) +
207
+ inverse(win.cursorGlyph) +
208
+ color.fg(textColor, win.after);
75
209
  }
76
- if (isSelected) {
77
- fieldValue += color.fg('silver', '█');
210
+ else {
211
+ fieldValue = color.fg(textColor, displayGlyphs.join(''));
78
212
  }
79
213
  const field = box({
80
214
  x: area.x,
@@ -83,6 +217,7 @@ export function Input(ctx, props) {
83
217
  height: area.height,
84
218
  border: 'rounded',
85
219
  borderColor: borderCol,
220
+ bgColor: theme.surface,
86
221
  padding: [0, 1],
87
222
  align: 'left',
88
223
  valign: 'middle',
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/components/Input.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/components/Input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type ColorValue } from '../colors';
2
+ import type { BuntiContext } from '../dsl';
3
+ export interface LinkProps {
4
+ id: string;
5
+ label: string;
6
+ /** Base color (default theme.accent); brightens on hover (mode-aware). */
7
+ color?: ColorValue;
8
+ onClick?: () => void;
9
+ /** Explicit column (default: current flow cursor). */
10
+ x?: number;
11
+ /** Explicit row (default: current flow cursor). */
12
+ y?: number;
13
+ }
14
+ /**
15
+ * Inline hyperlink: underlined themed text with a pointer-friendly hitbox.
16
+ * Hover brightens the color one step (mode-aware); clicks fire once per
17
+ * mouse release via the hitbox harness. Appends to the current flow and
18
+ * returns the styled string.
19
+ */
20
+ export declare function Link(ctx: BuntiContext, props: LinkProps): string;
21
+ //# sourceMappingURL=Link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/components/Link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,UAAU,EAAM,MAAM,WAAW,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAG3C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,sDAAsD;IACtD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAgChE"}
@@ -0,0 +1,38 @@
1
+ import { adjustBrightness, fg } from '../colors';
2
+ import { visibleWidth } from '../utils';
3
+ /**
4
+ * Inline hyperlink: underlined themed text with a pointer-friendly hitbox.
5
+ * Hover brightens the color one step (mode-aware); clicks fire once per
6
+ * mouse release via the hitbox harness. Appends to the current flow and
7
+ * returns the styled string.
8
+ */
9
+ export function Link(ctx, props) {
10
+ const width = visibleWidth(props.label);
11
+ const x = props.x ?? ctx.cursorX;
12
+ const y = props.y ?? ctx.cursorY;
13
+ // The label joins the text flow at (x, y), so the hitbox is flow-anchored
14
+ // (re-placed with the painted line by the enclosing box) unless the
15
+ // caller pinned an explicit row.
16
+ const interaction = ctx.hitbox(props.id, {
17
+ x,
18
+ y,
19
+ width,
20
+ height: 1,
21
+ flow: props.y === undefined,
22
+ });
23
+ if (interaction.clicked)
24
+ props.onClick?.();
25
+ const theme = ctx.theme;
26
+ const base = props.color ?? theme.accent;
27
+ const shift = theme.mode === 'dark' ? 25 : -25;
28
+ const colorNow = interaction.hovered ? adjustBrightness(base, shift) : base;
29
+ // Raw SGR 4/24 (not ctx.color.underline) so underline survives regardless
30
+ // of the vendor formatter's TTY color gate.
31
+ const styled = `\x1b[4m${fg(colorNow, props.label)}\x1b[24m`;
32
+ // When explicitly placed right of the cursor, pad the gap so the flow
33
+ // lands the label on its hitbox.
34
+ const pad = props.x !== undefined ? ' '.repeat(Math.max(0, props.x - ctx.cursorX)) : '';
35
+ ctx.text(pad + styled);
36
+ return styled;
37
+ }
38
+ //# sourceMappingURL=Link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/components/Link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAmB,EAAE,EAAE,MAAM,WAAW,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAcxC;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,GAAiB,EAAE,KAAgB;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC;IACjC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC;IAEjC,0EAA0E;IAC1E,oEAAoE;IACpE,iCAAiC;IACjC,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE;QACvC,CAAC;QACD,CAAC;QACD,KAAK;QACL,MAAM,EAAE,CAAC;QACT,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,SAAS;KAC5B,CAAC,CAAC;IACH,IAAI,WAAW,CAAC,OAAO;QAAE,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IAE3C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACxB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;IACzC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5E,0EAA0E;IAC1E,4CAA4C;IAC5C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC;IAE7D,sEAAsE;IACtE,iCAAiC;IACjC,MAAM,GAAG,GACP,KAAK,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,13 +1,38 @@
1
1
  import type { BuntiContext } from '../dsl';
2
+ /** Props for Modal. */
2
3
  export interface ModalProps {
4
+ /** Dialog width in cells. */
3
5
  width: number;
6
+ /** Dialog height in rows. */
4
7
  height: number;
8
+ /** Border glyph set (default 'double'). */
5
9
  border?: 'default' | 'rounded' | 'double' | 'dashed' | 'dotted' | 'frame' | 'thick-frame' | 'classic' | 'none';
10
+ /** Border color (default theme.border). */
6
11
  borderColor?: any;
12
+ /** Surface color (default theme.surfaceRaised). */
7
13
  bgColor?: any;
14
+ /** Horizontal content alignment (default 'center'). */
8
15
  align?: 'left' | 'center' | 'right';
16
+ /** Vertical content alignment. */
9
17
  valign?: 'top' | 'middle' | 'bottom';
18
+ /** [vertical, horizontal] padding inside the border, in cells. */
10
19
  padding?: [number, number];
20
+ /** Keys the entrance animation when multiple modals coexist. */
21
+ id?: string;
22
+ /** Layer z-index the modal composites at (default 100). */
23
+ zIndex?: number;
24
+ /** Backdrop dim 0..1 under the modal; `false` or 0 disables (default 0.55). */
25
+ backdrop?: number | false;
26
+ /** Drop shadow under the modal surface (default true). */
27
+ shadow?: boolean;
28
+ /** 150ms fade + slide-in entrance (default true). */
29
+ entrance?: boolean;
11
30
  }
31
+ /**
32
+ * Modal dialog: renders on its own layer with a dimmed backdrop and drop
33
+ * shadow, centered, with a 150ms fade/slide-in entrance. Surface and border
34
+ * derive from ctx.theme tokens; every visual default can be overridden or
35
+ * disabled via props.
36
+ */
12
37
  export declare function Modal(ctx: BuntiContext, props: ModalProps, callback: (sub: BuntiContext) => void): string;
13
38
  //# sourceMappingURL=Modal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/components/Modal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EACH,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,aAAa,GACb,SAAS,GACT,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,wBAAgB,KAAK,CACnB,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,UAiCtC"}
1
+ {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/components/Modal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAI3C,uBAAuB;AACvB,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,CAAC,EACH,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,aAAa,GACb,SAAS,GACT,MAAM,CAAC;IACX,2CAA2C;IAC3C,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,mDAAmD;IACnD,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,kCAAkC;IAClC,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrC,kEAAkE;IAClE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAcD;;;;;GAKG;AACH,wBAAgB,KAAK,CACnB,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,GACpC,MAAM,CAqFR"}