@flyingrobots/bijou 4.2.0 → 4.4.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 (86) hide show
  1. package/README.md +39 -179
  2. package/dist/context-theme.d.ts +15 -0
  3. package/dist/context-theme.d.ts.map +1 -0
  4. package/dist/context-theme.js +23 -0
  5. package/dist/context-theme.js.map +1 -0
  6. package/dist/core/components/alert-v3.js +4 -4
  7. package/dist/core/components/alert-v3.js.map +1 -1
  8. package/dist/core/components/alert.d.ts.map +1 -1
  9. package/dist/core/components/alert.js +12 -5
  10. package/dist/core/components/alert.js.map +1 -1
  11. package/dist/core/components/badge.d.ts.map +1 -1
  12. package/dist/core/components/badge.js +38 -7
  13. package/dist/core/components/badge.js.map +1 -1
  14. package/dist/core/components/box-v3.d.ts.map +1 -1
  15. package/dist/core/components/box-v3.js +101 -26
  16. package/dist/core/components/box-v3.js.map +1 -1
  17. package/dist/core/components/braille-chart.d.ts +45 -0
  18. package/dist/core/components/braille-chart.d.ts.map +1 -0
  19. package/dist/core/components/braille-chart.js +94 -0
  20. package/dist/core/components/braille-chart.js.map +1 -0
  21. package/dist/core/components/data-viz-utils.d.ts +25 -0
  22. package/dist/core/components/data-viz-utils.d.ts.map +1 -0
  23. package/dist/core/components/data-viz-utils.js +72 -0
  24. package/dist/core/components/data-viz-utils.js.map +1 -0
  25. package/dist/core/components/index.d.ts +8 -0
  26. package/dist/core/components/index.d.ts.map +1 -1
  27. package/dist/core/components/index.js +4 -0
  28. package/dist/core/components/index.js.map +1 -1
  29. package/dist/core/components/perf-overlay.d.ts +63 -0
  30. package/dist/core/components/perf-overlay.d.ts.map +1 -0
  31. package/dist/core/components/perf-overlay.js +84 -0
  32. package/dist/core/components/perf-overlay.js.map +1 -0
  33. package/dist/core/components/preference-list.d.ts.map +1 -1
  34. package/dist/core/components/preference-list.js +63 -11
  35. package/dist/core/components/preference-list.js.map +1 -1
  36. package/dist/core/components/separator-v3.d.ts.map +1 -1
  37. package/dist/core/components/separator-v3.js +55 -15
  38. package/dist/core/components/separator-v3.js.map +1 -1
  39. package/dist/core/components/sparkline.d.ts +33 -0
  40. package/dist/core/components/sparkline.d.ts.map +1 -0
  41. package/dist/core/components/sparkline.js +45 -0
  42. package/dist/core/components/sparkline.js.map +1 -0
  43. package/dist/core/components/stats-panel.d.ts +50 -0
  44. package/dist/core/components/stats-panel.d.ts.map +1 -0
  45. package/dist/core/components/stats-panel.js +83 -0
  46. package/dist/core/components/stats-panel.js.map +1 -0
  47. package/dist/core/components/surface-text.d.ts +1 -1
  48. package/dist/core/components/surface-text.d.ts.map +1 -1
  49. package/dist/core/components/surface-text.js +80 -9
  50. package/dist/core/components/surface-text.js.map +1 -1
  51. package/dist/core/components/table-v3.d.ts.map +1 -1
  52. package/dist/core/components/table-v3.js +34 -2
  53. package/dist/core/components/table-v3.js.map +1 -1
  54. package/dist/core/components/types.d.ts +4 -4
  55. package/dist/core/components/types.d.ts.map +1 -1
  56. package/dist/core/render/differ.d.ts +12 -1
  57. package/dist/core/render/differ.d.ts.map +1 -1
  58. package/dist/core/render/differ.js +502 -11
  59. package/dist/core/render/differ.js.map +1 -1
  60. package/dist/core/render/packed-cell.d.ts +110 -0
  61. package/dist/core/render/packed-cell.d.ts.map +1 -0
  62. package/dist/core/render/packed-cell.js +301 -0
  63. package/dist/core/render/packed-cell.js.map +1 -0
  64. package/dist/core/text/grapheme.d.ts.map +1 -1
  65. package/dist/core/text/grapheme.js +17 -5
  66. package/dist/core/text/grapheme.js.map +1 -1
  67. package/dist/core/theme/presets.d.ts +9 -1
  68. package/dist/core/theme/presets.d.ts.map +1 -1
  69. package/dist/core/theme/presets.js +44 -2
  70. package/dist/core/theme/presets.js.map +1 -1
  71. package/dist/core/theme/resolve.d.ts.map +1 -1
  72. package/dist/core/theme/resolve.js +21 -1
  73. package/dist/core/theme/resolve.js.map +1 -1
  74. package/dist/core/theme/tokens.d.ts +12 -0
  75. package/dist/core/theme/tokens.d.ts.map +1 -1
  76. package/dist/index.d.ts +4 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +3 -1
  79. package/dist/index.js.map +1 -1
  80. package/dist/ports/io.d.ts +17 -0
  81. package/dist/ports/io.d.ts.map +1 -1
  82. package/dist/ports/surface.d.ts +83 -2
  83. package/dist/ports/surface.d.ts.map +1 -1
  84. package/dist/ports/surface.js +319 -37
  85. package/dist/ports/surface.js.map +1 -1
  86. package/package.json +5 -1
package/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  The pure, zero-dependency core of Bijou.
4
4
 
5
- `@flyingrobots/bijou` is the degradation-first terminal toolkit in the Bijou stack. It contains components, prompts, themes, environment detection, test adapters, and the foundational `Surface` and `LayoutNode` primitives that the interactive runtime builds on.
5
+ `@flyingrobots/bijou` provides the foundational primitives for CLIs, prompts, and portable terminal output. It manages components, themes, environment detection, and the core `Surface` and `LayoutNode` types.
6
6
 
7
- ## Package Role
7
+ ## Role
8
8
 
9
- - **Core/runtime split stays explicit** — the core package remains the right place for CLIs, prompts, logs, and portable terminal output, while `@flyingrobots/bijou-tui` owns the fullscreen runtime.
10
- - **Surface primitives without abandoning strings** — the package is intentionally mixed-mode. String-oriented helpers remain first-class where they fit the toolkit identity, and runtime-friendly surface helpers exist where they actually help.
11
- - **Surface-first companions for common runtime chrome** — `boxSurface`, `headerBoxSurface`, `separatorSurface`, `alertSurface`, and `tableSurface` let runtime apps stay on the `Surface` path for common layout and status primitives.
12
- - **Explicit seam crossing** — when you move `Surface` output back into string-first APIs, you do it deliberately with `surfaceToString(surface, ctx.style)`.
13
- - **Same hexagonal core** — ports, themes, output-mode detection, and test adapters remain pure and dependency-free.
9
+ - **Degradation-First**: Automatic mode detection for `interactive`, `static`, `pipe`, and `accessible` output.
10
+ - **Mixed-Mode**: High-performance `Surface` primitives for rich TUI apps, with
11
+ string-first helpers for standalone CLI scripts.
12
+ - **Surface primitives without abandoning strings**: Runtime apps can stay on
13
+ the surface path while CLI-first flows still use the string-first helpers.
14
+ - **Hexagonal Core**: Pure TypeScript logic isolated from platform IO via `Runtime`, `IO`, and `Style` ports.
14
15
 
15
16
  ## Install
16
17
 
@@ -24,7 +25,6 @@ npm install @flyingrobots/bijou @flyingrobots/bijou-node
24
25
  import { initDefaultContext } from '@flyingrobots/bijou-node';
25
26
  import { badge, boxSurface, tableSurface } from '@flyingrobots/bijou';
26
27
 
27
- // Initialize Node.js adapters (auto-detects TTY, CI, NO_COLOR)
28
28
  const ctx = initDefaultContext();
29
29
 
30
30
  const panel = boxSurface(
@@ -33,186 +33,46 @@ const panel = boxSurface(
33
33
  rows: [['api', badge('LIVE', { variant: 'success', ctx })]],
34
34
  ctx,
35
35
  }),
36
- { title: 'Runtime', padding: { top: 1, bottom: 1, left: 2, right: 2 }, ctx },
36
+ {
37
+ title: 'Runtime',
38
+ padding: { top: 1, bottom: 1, left: 1, right: 1 },
39
+ ctx,
40
+ },
37
41
  );
38
-
39
- // Return `panel` from a runtime `view()` function or framed pane renderer.
40
42
  ```
41
43
 
42
- ## Features Breakdown
43
-
44
- - **Resilient rendering**: automatic mode switching for interactive, static, pipe, and accessible output.
45
- - **Core UI primitives**: `box`, `headerBox`, `table`, `tree`, `accordion`, `tabs`, `breadcrumb`, `stepper`, `timeline`, `paginator`.
46
- - **Graph tooling**: `dag`, `dagSlice`, and `dagStats` for visualizing and analyzing DAGs.
47
- - **Interactive forms**: `input`, `select`, `multiselect`, `confirm`, `group`, `wizard`, `textarea`, and `filter`.
48
- - **Theme system**: preset themes + DTCG-compatible custom token loading via `BIJOU_THEME`.
49
- - **Test adapters**: deterministic test context and assertion helpers for mock-free component testing.
50
-
51
- ## Design guidance
52
-
53
- For the system-level guidance behind the component catalog, see:
54
-
55
- - [`../../docs/design-system/README.md`](../../docs/design-system/README.md)
56
- - [`../../docs/design-system/foundations.md`](../../docs/design-system/foundations.md)
57
- - [`../../docs/design-system/patterns.md`](../../docs/design-system/patterns.md)
58
- - [`../../docs/design-system/component-families.md`](../../docs/design-system/component-families.md)
59
-
60
- Those docs answer the questions the API reference cannot:
61
-
62
- - when to use a family
63
- - when not to use it
64
- - which variation is semantic versus render-path versus interaction-layer
65
- - what belongs in core Bijou versus `@flyingrobots/bijou-tui`
66
-
67
- ## Choosing Component Families
68
-
69
- ### Status and feedback
70
-
71
- - Use `badge()` when status is compact and belongs inline with another object.
72
- - Use `note()` when the user needs explanation without urgency.
73
- - Use `alert()` when the message should persist inside the page or document flow.
74
- - Move to `@flyingrobots/bijou-tui` notifications when stacking, placement, actions, or history matter.
75
-
76
- ### Selection and prompts
77
-
78
- - Use `select()` when the user is choosing one stored value from a short, stable set.
79
- - Use `filter()` when the user is still choosing one stored value, but search and narrowing are the real job.
80
- - Use `multiselect()` when the user is building a lasting set, not firing one-off commands.
81
- - Use `confirm()` only when the decision is genuinely binary.
82
- - Move to `commandPaletteSurface()` in `@flyingrobots/bijou-tui` when the outcome is an action or navigation command instead of stored form state.
83
-
84
- ### Tables and inspection
85
-
86
- - Use `table()` when row/column comparison is the main job and string output is still the right endpoint.
87
- - Use `tableSurface()` when the job is still passive comparison, but your runtime app is already composing `Surface` output.
88
- - Use `navigableTable()` from `@flyingrobots/bijou-tui` when the user needs keyboard-owned row or cell inspection instead of passive reading.
89
-
90
- ### Hierarchy and chronology
91
-
92
- - Use `tree()` when parent/child nesting is the main thing the reader needs to understand.
93
- - Use `timeline()` when chronology is the actual reading path.
94
- - Move to `dag()` when dependency or causal flow matters more than simple order or nesting.
95
- - Use `dagSlice()` when a local neighborhood or ancestor/descendant chain is the honest scope.
96
- - Use `dagStats()` when graph health or structural summary matters more than visual shape.
97
-
98
- ### Wayfinding and progress
99
-
100
- - Use `breadcrumb()` when path context helps explain the current location.
101
- - Use `paginator()` when compact position-in-sequence feedback is enough.
102
- - Use `stepper()` when the user is progressing through ordered stages rather than switching among peers.
103
-
104
- ### Containment and formatted content
105
-
106
- - Use `box()` when a region needs visible containment or comparison against sibling panels.
107
- - Use `headerBox()` when that same region also needs a compact title and detail line.
108
- - Use `markdown()` for bounded help, reference, and release-note prose that should lower honestly across rich, pipe, and accessible output.
109
- - Avoid turning every subsection into a box or using markdown as a substitute layout engine for full application chrome.
110
-
111
- ### Loading, links, and expressive moments
112
-
113
- - Use `skeleton()` for short-lived placeholders when the final content shape is known.
114
- - Use `hyperlink()` when the destination itself should remain explicit and trustworthy in terminal output.
115
- - Use `kbd()` for local inline shortcut cues; use shell help in `@flyingrobots/bijou-tui` when the user needs a broader keybinding reference.
116
- - Use `gradientText()` and `loadRandomLogo()` sparingly for splash, docs, and celebratory moments rather than routine workspace chrome.
117
-
118
- ### Progress and custom primitives
44
+ ## Strategy: Choosing Component Families
119
45
 
120
- - Use `progressBar()` when completion can be estimated honestly.
121
- - Use `spinnerFrame()` or `createSpinner()` when the task is active but indeterminate.
122
- - Use `renderByMode()` when you are authoring an app-specific primitive that must stay truthful across rich, pipe, and accessible output.
46
+ Select the family based on the interaction semantic, not just the visual shape.
123
47
 
124
- ## Components
48
+ ### Status and Feedback
49
+ - **`badge()`**: Compact, inline status.
50
+ - **`note()`**: Non-urgent explanation.
51
+ - **`alert()`**: Persistent, in-flow message.
52
+ - *Use `@flyingrobots/bijou-tui` notifications for stacking, history, or active routing.*
125
53
 
126
- ### Layout
127
- `box()`, `headerBox()`, `separator()` plus `boxSurface()`, `headerBoxSurface()`, `separatorSurface()` — string-first helpers and surface-native companions for layout chrome.
54
+ ### Selection and Prompts
55
+ - **`select()`**: Single choice from a stable set.
56
+ - **`filter()`**: Search-led choice from a large or dynamic set.
57
+ - **`multiselect()`**: Choosing multiple values to build a set.
58
+ - **`confirm()`**: Strictly binary decisions.
128
59
 
129
- ### Elements
130
- `badge()`, `alert()`, `alertSurface()`, `kbd()`, `skeleton()`, `hyperlink()` — inline status, in-flow status blocks, loading placeholders, trusted links, and UI primitives.
60
+ ### Hierarchy and Chronology
61
+ - **`tree()`**: Parent/child nesting.
62
+ - **`timeline()`**: Sequential, time-ordered events.
63
+ - **`dag()`**: Causal or dependency-based graphs.
131
64
 
132
- ### Data
133
- `table()`, `tableSurface()`, `tree()`, `accordion()`, `timeline()`, `dag()`, `dagSlice()`, `dagLayout()`, `dagStats()` — passive comparison and structured data display, DAG rendering with `DagSource` adapter, and graph statistics.
65
+ ### Progress and Wayfinding
66
+ - **`progressBar()`**: Determinate completion.
67
+ - **`spinner()`**: Indeterminate activity.
68
+ - **`breadcrumb()`**: Path context.
69
+ - **`stepper()`**: Ordered stages in a linear process.
134
70
 
135
- ### Documents
136
- `markdown()` — structured terminal prose for help, readmes, and reference content with mode-aware lowering.
71
+ ## Documentation
137
72
 
138
- ### Navigation
139
- `tabs()`, `breadcrumb()`, `stepper()`, `paginator()` wayfinding components.
140
-
141
- ### Animation & Progress
142
- `spinnerFrame()`, `createSpinner()`, `progressBar()`, `createProgressBar()`, `createAnimatedProgressBar()`, `gradientText()`, `loadRandomLogo()` — determinate and indeterminate progress, live-updating output, expressive gradients, and branded ASCII moments.
143
-
144
- ### Authoring helpers
145
- `renderByMode()` — mode-aware helper for app-authored primitives that need honest rich/pipe/accessible lowering.
146
-
147
- ### Forms
148
- `input()`, `select()`, `multiselect()`, `confirm()`, `group()`, `wizard()`, `textarea()`, `filter()` — interactive prompts with validation that degrade to numbered-list selection in pipe/CI modes.
149
-
150
- ### Theme Engine
151
- DTCG (Design Tokens Community Group) interop. Built-in presets: `nord`, `catppuccin`, `cyan-magenta`, `teal-orange-pink`. Load custom themes via `BIJOU_THEME` env var or `extendTheme()`.
152
-
153
- ## Architecture
154
-
155
- bijou uses a Ports and Adapters (hexagonal) architecture. See [ARCHITECTURE.md](./ARCHITECTURE.md) for the package-level design and [`../../docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) for the monorepo-wide architecture.
156
-
157
- The core is pure TypeScript with zero runtime dependencies — all platform concerns flow through three ports:
158
-
159
- - **`RuntimePort`** — environment variables, TTY detection, terminal dimensions
160
- - **`IOPort`** — stdout writes, stdin reads, resize events, file I/O
161
- - **`StylePort`** — RGB/hex color application, bold/italic/etc.
162
-
163
- ### Output Modes
164
-
165
- bijou auto-detects the environment and adapts rendering:
166
-
167
- | Mode | Trigger | Behavior |
168
- | :--- | :--- | :--- |
169
- | **Interactive** | TTY | Full RGB, unicode, animations |
170
- | **Static** | `CI=true` | Single-frame, no animations |
171
- | **Pipe** | Piped stdout | Plain text, ASCII fallbacks |
172
- | **Accessible** | `BIJOU_ACCESSIBLE=1` | Screen-reader friendly |
173
-
174
- ## Testing
175
-
176
- Import test adapters for deterministic, mock-free component testing:
177
-
178
- ```typescript
179
- import { createTestContext } from '@flyingrobots/bijou/adapters/test';
180
- import { box } from '@flyingrobots/bijou';
181
-
182
- const ctx = createTestContext({ mode: 'interactive' });
183
- const result = box('hello', { ctx });
184
- // Assert on the string directly — no process mocking needed
185
- ```
186
-
187
- See [GUIDE.md](./GUIDE.md) for more on testing, theming, and component usage.
188
- For upgrading existing apps, see the monorepo migration guide at [`../../docs/MIGRATING_TO_V4.md`](../../docs/MIGRATING_TO_V4.md).
189
-
190
- ## Related Packages
191
-
192
- - [`@flyingrobots/bijou-node`](https://www.npmjs.com/package/@flyingrobots/bijou-node) — Node.js runtime adapter (chalk, readline, process)
193
- - [`@flyingrobots/bijou-tui`](https://www.npmjs.com/package/@flyingrobots/bijou-tui) — TEA runtime for interactive terminal apps
194
-
195
- ## License
196
-
197
- Apache-2.0
73
+ - **[GUIDE.md](./GUIDE.md)**: Productive-fast path.
74
+ - **[ADVANCED_GUIDE.md](./ADVANCED_GUIDE.md)**: Rendering doctrine, themes, and testing.
75
+ - **[Design System](../../docs/design-system/README.md)**: Semantic guidance and component families.
198
76
 
199
77
  ---
200
-
201
- <p align="center">
202
- Built with 💎 by <a href="https://github.com/flyingrobots">FLYING ROBOTS</a>
203
- </p>
204
-
205
- ```rust
206
- .-:::::'::: .-:. ::-.::::::. :::. .,-:::::/
207
- ;;;'''' ;;; ';;. ;;;;';;;`;;;;, `;;;,;;-'````'
208
- [[[,,== [[[ '[[,[[[' [[[ [[[[[. '[[[[[ [[[[[[/
209
- `$$$"`` $$' c$$" $$$ $$$ "Y$c$$"$$c. "$$
210
- 888 o88oo,.__ ,8P"` 888 888 Y88 `Y8bo,,,o88o
211
- "MM, """"YUMMMmM" MMM MMM YM `'YMUP"YMM
212
- :::::::.. ... :::::::. ... :::::::::::: .::::::.
213
- ;;;;``;;;; .;;;;;;;. ;;;'';;' .;;;;;;;.;;;;;;;;'''';;;` `
214
- [[[,/[[[' ,[[ \[[, [[[__[[\.,[[ \[[, [[ '[==/[[[[,
215
- $$$$$$c $$$, $$$ $$""""Y$$$$$, $$$ $$ ''' $
216
- 888b "88bo,"888,_ _,88P_88o,,od8P"888,_ _,88P 88, 88b dP
217
- MMMM "W" "YMMMMMP" ""YUMMMP" "YMMMMMP" MMM "YMmMY"
218
- ```
78
+ Built with 💎 by [FLYING ROBOTS](https://github.com/flyingrobots)
@@ -0,0 +1,15 @@
1
+ import type { BijouContext } from './ports/context.js';
2
+ import { type ResolvedTheme } from './core/theme/resolve.js';
3
+ import type { Theme } from './core/theme/tokens.js';
4
+ /**
5
+ * Clone a Bijou context with a different already-resolved theme.
6
+ *
7
+ * The original context is left untouched; callers get a fresh object with
8
+ * the same runtime/style/IO ports and updated theme accessors.
9
+ */
10
+ export declare function cloneContextWithResolvedTheme(ctx: BijouContext, theme: ResolvedTheme): BijouContext;
11
+ /**
12
+ * Clone a Bijou context with a different theme definition.
13
+ */
14
+ export declare function cloneContextWithTheme(ctx: BijouContext, theme: Theme): BijouContext;
15
+ //# sourceMappingURL=context-theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-theme.d.ts","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,aAAa,GACnB,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,KAAK,GACX,YAAY,CAKd"}
@@ -0,0 +1,23 @@
1
+ import { createThemeAccessors } from './core/theme/accessors.js';
2
+ import { createResolved } from './core/theme/resolve.js';
3
+ /**
4
+ * Clone a Bijou context with a different already-resolved theme.
5
+ *
6
+ * The original context is left untouched; callers get a fresh object with
7
+ * the same runtime/style/IO ports and updated theme accessors.
8
+ */
9
+ export function cloneContextWithResolvedTheme(ctx, theme) {
10
+ return {
11
+ ...ctx,
12
+ theme,
13
+ tokenGraph: theme.tokenGraph,
14
+ ...createThemeAccessors(theme),
15
+ };
16
+ }
17
+ /**
18
+ * Clone a Bijou context with a different theme definition.
19
+ */
20
+ export function cloneContextWithTheme(ctx, theme) {
21
+ return cloneContextWithResolvedTheme(ctx, createResolved(theme, ctx.theme.noColor, ctx.theme.colorScheme));
22
+ }
23
+ //# sourceMappingURL=context-theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-theme.js","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAsB,MAAM,yBAAyB,CAAC;AAG7E;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAC3C,GAAiB,EACjB,KAAoB;IAEpB,OAAO;QACL,GAAG,GAAG;QACN,KAAK;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,GAAG,oBAAoB,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAiB,EACjB,KAAY;IAEZ,OAAO,6BAA6B,CAClC,GAAG,EACH,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAChE,CAAC;AACJ,CAAC"}
@@ -3,10 +3,10 @@ import { resolveSafeCtx as resolveCtx } from '../resolve-ctx.js';
3
3
  import { boxSurface } from './box-v3.js';
4
4
  import { createTextSurface, tokenToCellStyle } from './surface-text.js';
5
5
  const ICONS = {
6
- success: '\u2713',
7
- error: '\u2717',
8
- warning: '\u26A0',
9
- info: '\u2139',
6
+ success: '\u2713', // ✓
7
+ error: '\u2717', // ✗
8
+ warning: '\u26A0', // ⚠
9
+ info: '\u2139', // ℹ
10
10
  };
11
11
  const BORDER_TOKENS = {
12
12
  success: 'success',
@@ -1 +1 @@
1
- {"version":3,"file":"alert-v3.js","sourceRoot":"","sources":["../../../src/core/components/alert-v3.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAExE,MAAM,KAAK,GAAiC;IAC1C,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,QAAQ;IACjB,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,MAAM,aAAa,GAAsE;IACvF,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAyB,EAAE,UAAwB,EAAE;IAChF,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAC1C,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,cAAc,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1F,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAE1E,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvD,OAAO,UAAU,CAAC,OAAO,EAAE;QACzB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,GAAG,EAAE,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACvE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC;KACrD,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"alert-v3.js","sourceRoot":"","sources":["../../../src/core/components/alert-v3.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAExE,MAAM,KAAK,GAAiC;IAC1C,OAAO,EAAE,QAAQ,EAAG,IAAI;IACxB,KAAK,EAAE,QAAQ,EAAK,IAAI;IACxB,OAAO,EAAE,QAAQ,EAAG,IAAI;IACxB,IAAI,EAAE,QAAQ,EAAM,IAAI;CACzB,CAAC;AAEF,MAAM,aAAa,GAAsE;IACvF,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAyB,EAAE,UAAwB,EAAE;IAChF,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAC1C,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,cAAc,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1F,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAE1E,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvD,OAAO,UAAU,CAAC,OAAO,EAAE;QACzB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,GAAG,EAAE,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACvE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC;KACrD,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"alert.d.ts","sourceRoot":"","sources":["../../../src/core/components/alert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAI5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,4BAA4B;AAC5B,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpE,gDAAgD;AAChD,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,yFAAyF;IACzF,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,wFAAwF;IACxF,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAsBzE"}
1
+ {"version":3,"file":"alert.d.ts","sourceRoot":"","sources":["../../../src/core/components/alert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAI5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,4BAA4B;AAC5B,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpE,gDAAgD;AAChD,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,yFAAyF;IACzF,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,wFAAwF;IACxF,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAyCD;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAsBzE"}
@@ -1,12 +1,19 @@
1
1
  import { resolveCtx } from '../resolve-ctx.js';
2
2
  import { box } from './box.js';
3
3
  import { renderByMode } from '../mode-render.js';
4
- /** Unicode icon characters for each alert variant. */
4
+ /**
5
+ * Unicode icon characters for each alert variant.
6
+ *
7
+ * ✓ (U+2713) and ✗ (U+2717) are Narrow per Unicode East Asian Width.
8
+ * ⚠ (U+26A0) and ℹ (U+2139) are Ambiguous — 1-wide in terminals,
9
+ * potentially 2-wide in some chat UIs. We treat them as 1-wide here
10
+ * since graphemeWidth correctly classifies them as Narrow.
11
+ */
5
12
  const ICONS = {
6
- success: '\u2713',
7
- error: '\u2717',
8
- warning: '\u26A0',
9
- info: '\u2139',
13
+ success: '\u2713', // ✓ CHECK MARK
14
+ error: '\u2717', // ✗ BALLOT X
15
+ warning: '\u26A0', // ⚠ WARNING SIGN
16
+ info: '\u2139', // ℹ INFORMATION SOURCE
10
17
  };
11
18
  /** Uppercase labels used in pipe mode output. */
12
19
  const PIPE_LABELS = {
@@ -1 +1 @@
1
- {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../src/core/components/alert.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgBjD,sDAAsD;AACtD,MAAM,KAAK,GAAiC;IAC1C,OAAO,EAAE,QAAQ;IACjB,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,QAAQ;IACjB,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,iDAAiD;AACjD,MAAM,WAAW,GAAiC;IAChD,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,yDAAyD;AACzD,MAAM,iBAAiB,GAAiC;IACtD,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,8EAA8E;AAC9E,MAAM,aAAa,GAAgD;IACjE,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,UAAwB,EAAE;IAC/D,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,IAAI,EAAE,CAAC;IAElC,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,WAAW,EAAE;QACtD,UAAU,EAAE,GAAG,EAAE,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,WAAW,EAAE;QACjE,WAAW,EAAE,GAAG,EAAE;YAChB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5B,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;YAC9E,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YAE1D,OAAO,GAAG,CAAC,WAAW,GAAG,GAAG,GAAG,WAAW,EAAE;gBAC1C,WAAW;gBACX,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;gBACnD,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC9B,GAAG;aACJ,CAAC,CAAC;QACL,CAAC;KACF,EAAE,OAAO,CAAC,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../src/core/components/alert.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgBjD;;;;;;;GAOG;AACH,MAAM,KAAK,GAAiC;IAC1C,OAAO,EAAE,QAAQ,EAAG,eAAe;IACnC,KAAK,EAAE,QAAQ,EAAK,aAAa;IACjC,OAAO,EAAE,QAAQ,EAAG,iBAAiB;IACrC,IAAI,EAAE,QAAQ,EAAM,uBAAuB;CAC5C,CAAC;AAEF,iDAAiD;AACjD,MAAM,WAAW,GAAiC;IAChD,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,yDAAyD;AACzD,MAAM,iBAAiB,GAAiC;IACtD,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,8EAA8E;AAC9E,MAAM,aAAa,GAAgD;IACjE,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,UAAwB,EAAE;IAC/D,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,IAAI,EAAE,CAAC;IAElC,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,WAAW,EAAE;QACtD,UAAU,EAAE,GAAG,EAAE,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,WAAW,EAAE;QACjE,WAAW,EAAE,GAAG,EAAE;YAChB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5B,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;YAC9E,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YAE1D,OAAO,GAAG,CAAC,WAAW,GAAG,GAAG,GAAG,WAAW,EAAE;gBAC1C,WAAW;gBACX,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;gBACnD,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC9B,GAAG;aACJ,CAAC,CAAC;QACL,CAAC;KACF,EAAE,OAAO,CAAC,CAAC;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/core/components/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAa,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhE,2CAA2C;AAC3C,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,4CAA4C;IAC5C,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA2CvE"}
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/core/components/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAiC,MAAM,wBAAwB,CAAC;AACpG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhE,2CAA2C;AAC3C,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,4CAA4C;IAC5C,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA6DvE"}
@@ -2,6 +2,7 @@ import { createSurface } from '../../ports/surface.js';
2
2
  import { resolveSafeCtx as resolveCtx } from '../resolve-ctx.js';
3
3
  import { segmentGraphemes } from '../text/grapheme.js';
4
4
  import { applyBCSSCellTextStyles } from './bcss-style.js';
5
+ import { parseHex, encodeModifiers } from '../render/packed-cell.js';
5
6
  /**
6
7
  * Render an inline badge (pill-shaped label) for the given text.
7
8
  *
@@ -28,13 +29,18 @@ export function badge(text, options = {}) {
28
29
  const baseToken = (variant === 'accent' || variant === 'primary')
29
30
  ? ctx.semantic(variant)
30
31
  : ctx.status(variant);
32
+ // Pass both hex and pre-parsed fgRGB — encodeCellIntoBuf picks
33
+ // fgRGB first, skipping inlineHexRGB on the hot path.
34
+ const baseStyle = {
35
+ fg: baseToken.hex,
36
+ bg: undefined,
37
+ modifiers: [...(baseToken.modifiers ?? []), 'inverse'],
38
+ };
39
+ if (baseToken.fgRGB)
40
+ baseStyle.fgRGB = baseToken.fgRGB;
31
41
  const cell = {
32
42
  char: ' ',
33
- ...applyBCSSCellTextStyles({
34
- fg: baseToken.hex,
35
- bg: undefined,
36
- modifiers: [...(baseToken.modifiers ?? []), 'inverse'],
37
- }, bcss),
43
+ ...applyBCSSCellTextStyles(baseStyle, bcss),
38
44
  empty: false
39
45
  };
40
46
  // If CSS background is set, we might want to disable 'inverse' modifier
@@ -42,8 +48,33 @@ export function badge(text, options = {}) {
42
48
  if (bcss['background']) {
43
49
  cell.modifiers = cell.modifiers?.filter(m => m !== 'inverse');
44
50
  }
45
- for (let i = 0; i < width; i++) {
46
- surface.set(i, 0, { ...cell, char: graphemes[i] });
51
+ const packed = 'buffer' in surface;
52
+ if (packed && cell.fg) {
53
+ const fg = parseHex(cell.fg);
54
+ if (fg) {
55
+ const [fR, fG, fB] = fg;
56
+ let bR = -1, bG = 0, bB = 0;
57
+ if (cell.bg) {
58
+ const bg = parseHex(cell.bg);
59
+ if (bg) {
60
+ bR = bg[0];
61
+ bG = bg[1];
62
+ bB = bg[2];
63
+ }
64
+ }
65
+ const flags = encodeModifiers(cell.modifiers);
66
+ for (let i = 0; i < width; i++) {
67
+ surface.setRGB(i, 0, graphemes[i], fR, fG, fB, bR, bG, bB, flags);
68
+ }
69
+ }
70
+ else {
71
+ for (let i = 0; i < width; i++)
72
+ surface.set(i, 0, { ...cell, char: graphemes[i] });
73
+ }
74
+ }
75
+ else {
76
+ for (let i = 0; i < width; i++)
77
+ surface.set(i, 0, { ...cell, char: graphemes[i] });
47
78
  }
48
79
  return surface;
49
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"badge.js","sourceRoot":"","sources":["../../../src/core/components/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA2B,MAAM,wBAAwB,CAAC;AAEhF,OAAO,EAAE,cAAc,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAW1D;;;;;;;;GAQG;AACH,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,UAAwB,EAAE;IAC5D,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC;IAE1C,MAAM,UAAU,GAAG,IAAI,IAAI,GAAG,CAAC;IAC/B,MAAM,SAAS,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAC/B,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAExC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC7D,uCAAuC;QACvC,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;QAC7D,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,4BAA4B;IAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEpG,MAAM,SAAS,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,SAAS,CAAC;QAC/D,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;QACvB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExB,MAAM,IAAI,GAAS;QACjB,IAAI,EAAE,GAAG;QACT,GAAG,uBAAuB,CAAC;YACzB,EAAE,EAAE,SAAS,CAAC,GAAG;YACjB,EAAE,EAAE,SAAS;YACb,SAAS,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC;SACvD,EAAE,IAAI,CAAC;QACR,KAAK,EAAE,KAAK;KACb,CAAC;IAEF,yEAAyE;IACzE,uDAAuD;IACvD,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,iCAAiC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"badge.js","sourceRoot":"","sources":["../../../src/core/components/badge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"box-v3.d.ts","sourceRoot":"","sources":["../../../src/core/components/box-v3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAa,MAAM,wBAAwB,CAAC;AAIhF,OAAO,EAAmB,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA4BnF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAwGvF;AACD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAmBvF"}
1
+ {"version":3,"file":"box-v3.d.ts","sourceRoot":"","sources":["../../../src/core/components/box-v3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAiC,MAAM,wBAAwB,CAAC;AAIpG,OAAO,EAAmB,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA0EnF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAmIvF;AACD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAmBvF"}
@@ -6,6 +6,32 @@ import { resolveFillChar } from './box.js';
6
6
  import { applyBCSSCellTextStyles } from './bcss-style.js';
7
7
  import { createSegmentSurface, createTextSurface, segmentSurfaceText, tokenToCellStyle, wrapSurfaceToWidth } from './surface-text.js';
8
8
  import { resolveOverflowBehavior } from './overflow.js';
9
+ import { parseHex, encodeModifiers, CELL_STRIDE, OFF_FLAGS, OFF_ALPHA, FLAG_EMPTY, FLAG_BG_SET } from '../render/packed-cell.js';
10
+ function isPackedSurface(s) {
11
+ return 'buffer' in s && s.buffer instanceof Uint8Array;
12
+ }
13
+ /** Pre-parse a CellTextStyle into numeric RGB + flags for setRGB. Returns undefined if not parseable. */
14
+ function parseStyleRGB(style) {
15
+ let fgR = -1, fgG = 0, fgB = 0;
16
+ let bgR = -1, bgG = 0, bgB = 0;
17
+ if (style.fg) {
18
+ const rgb = parseHex(style.fg);
19
+ if (!rgb)
20
+ return undefined;
21
+ fgR = rgb[0];
22
+ fgG = rgb[1];
23
+ fgB = rgb[2];
24
+ }
25
+ if (style.bg) {
26
+ const rgb = parseHex(style.bg);
27
+ if (!rgb)
28
+ return undefined;
29
+ bgR = rgb[0];
30
+ bgG = rgb[1];
31
+ bgB = rgb[2];
32
+ }
33
+ return { fgR, fgG, fgB, bgR, bgG, bgB, flags: encodeModifiers(style.modifiers) };
34
+ }
9
35
  const BORDER = { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };
10
36
  function normalizeFixedWidth(width) {
11
37
  if (width == null)
@@ -18,6 +44,28 @@ function withInheritedBackground(surface, background) {
18
44
  if (background == null)
19
45
  return surface;
20
46
  const next = surface.clone();
47
+ if (isPackedSurface(next)) {
48
+ // Fast path: write bg bytes directly into the buffer
49
+ const bgRGB = parseHex(background);
50
+ if (bgRGB) {
51
+ const buf = next.buffer;
52
+ const [bgR, bgG, bgB] = bgRGB;
53
+ const size = next.width * next.height;
54
+ for (let i = 0; i < size; i++) {
55
+ const off = i * CELL_STRIDE;
56
+ if (buf[off + OFF_FLAGS] & FLAG_EMPTY)
57
+ continue;
58
+ if (buf[off + OFF_ALPHA] & FLAG_BG_SET)
59
+ continue;
60
+ buf[off + 5] = bgR;
61
+ buf[off + 6] = bgG;
62
+ buf[off + 7] = bgB;
63
+ buf[off + OFF_ALPHA] = buf[off + OFF_ALPHA] | FLAG_BG_SET;
64
+ }
65
+ next.markAllDirty();
66
+ return next;
67
+ }
68
+ }
21
69
  for (let y = 0; y < next.height; y++) {
22
70
  for (let x = 0; x < next.width; x++) {
23
71
  const cell = next.get(x, y);
@@ -88,33 +136,60 @@ export function boxSurface(content, options = {}) {
88
136
  bg: borderToken?.bg,
89
137
  modifiers: borderToken?.modifiers,
90
138
  }, bcss);
91
- const borderCell = {
92
- char: ' ',
93
- fg: borderStyle.fg,
94
- bg: borderStyle.bg,
95
- modifiers: borderStyle.modifiers,
96
- };
97
- // Draw borders
98
- for (let x = 0; x < outerW; x++) {
99
- surface.set(x, 0, { ...borderCell, char: BORDER.h });
100
- surface.set(x, outerH - 1, { ...borderCell, char: BORDER.h });
101
- }
102
- for (let y = 0; y < outerH; y++) {
103
- surface.set(0, y, { ...borderCell, char: BORDER.v });
104
- surface.set(outerW - 1, y, { ...borderCell, char: BORDER.v });
139
+ // Fast path: use setRGB for borders when surface is packed
140
+ const bRGB = isPackedSurface(surface) ? parseStyleRGB(borderStyle) : undefined;
141
+ if (bRGB && isPackedSurface(surface)) {
142
+ const { fgR, fgG, fgB, bgR, bgG, bgB, flags } = bRGB;
143
+ const H = BORDER.h, V = BORDER.v;
144
+ for (let x = 0; x < outerW; x++) {
145
+ surface.setRGB(x, 0, H, fgR, fgG, fgB, bgR, bgG, bgB, flags);
146
+ surface.setRGB(x, outerH - 1, H, fgR, fgG, fgB, bgR, bgG, bgB, flags);
147
+ }
148
+ for (let y = 0; y < outerH; y++) {
149
+ surface.setRGB(0, y, V, fgR, fgG, fgB, bgR, bgG, bgB, flags);
150
+ surface.setRGB(outerW - 1, y, V, fgR, fgG, fgB, bgR, bgG, bgB, flags);
151
+ }
152
+ surface.setRGB(0, 0, BORDER.tl, fgR, fgG, fgB, bgR, bgG, bgB, flags);
153
+ surface.setRGB(outerW - 1, 0, BORDER.tr, fgR, fgG, fgB, bgR, bgG, bgB, flags);
154
+ surface.setRGB(0, outerH - 1, BORDER.bl, fgR, fgG, fgB, bgR, bgG, bgB, flags);
155
+ surface.setRGB(outerW - 1, outerH - 1, BORDER.br, fgR, fgG, fgB, bgR, bgG, bgB, flags);
156
+ if (title && outerW >= 4) {
157
+ const available = Math.max(0, outerW - 4);
158
+ const titleText = clipToWidth(` ${title} `, available);
159
+ const titleGs = segmentSurfaceText(titleText, 'boxSurface title');
160
+ const titleLen = Math.min(titleGs.length, available);
161
+ for (let i = 0; i < titleLen; i++) {
162
+ surface.setRGB(i + 2, 0, titleGs[i], fgR, fgG, fgB, bgR, bgG, bgB, flags);
163
+ }
164
+ }
105
165
  }
106
- surface.set(0, 0, { ...borderCell, char: BORDER.tl });
107
- surface.set(outerW - 1, 0, { ...borderCell, char: BORDER.tr });
108
- surface.set(0, outerH - 1, { ...borderCell, char: BORDER.bl });
109
- surface.set(outerW - 1, outerH - 1, { ...borderCell, char: BORDER.br });
110
- // Draw title
111
- if (title && outerW >= 4) {
112
- const available = Math.max(0, outerW - 4);
113
- const titleText = clipToWidth(` ${title} `, available);
114
- const titleGs = segmentSurfaceText(titleText, 'boxSurface title');
115
- const titleLen = Math.min(titleGs.length, available);
116
- for (let i = 0; i < titleLen; i++) {
117
- surface.set(i + 2, 0, { ...borderCell, char: titleGs[i] });
166
+ else {
167
+ const borderCell = {
168
+ char: ' ',
169
+ fg: borderStyle.fg,
170
+ bg: borderStyle.bg,
171
+ modifiers: borderStyle.modifiers,
172
+ };
173
+ for (let x = 0; x < outerW; x++) {
174
+ surface.set(x, 0, { ...borderCell, char: BORDER.h });
175
+ surface.set(x, outerH - 1, { ...borderCell, char: BORDER.h });
176
+ }
177
+ for (let y = 0; y < outerH; y++) {
178
+ surface.set(0, y, { ...borderCell, char: BORDER.v });
179
+ surface.set(outerW - 1, y, { ...borderCell, char: BORDER.v });
180
+ }
181
+ surface.set(0, 0, { ...borderCell, char: BORDER.tl });
182
+ surface.set(outerW - 1, 0, { ...borderCell, char: BORDER.tr });
183
+ surface.set(0, outerH - 1, { ...borderCell, char: BORDER.bl });
184
+ surface.set(outerW - 1, outerH - 1, { ...borderCell, char: BORDER.br });
185
+ if (title && outerW >= 4) {
186
+ const available = Math.max(0, outerW - 4);
187
+ const titleText = clipToWidth(` ${title} `, available);
188
+ const titleGs = segmentSurfaceText(titleText, 'boxSurface title');
189
+ const titleLen = Math.min(titleGs.length, available);
190
+ for (let i = 0; i < titleLen; i++) {
191
+ surface.set(i + 2, 0, { ...borderCell, char: titleGs[i] });
192
+ }
118
193
  }
119
194
  }
120
195
  // Blit content