@boba-cli/chapstick 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,719 @@
1
+ 'use strict';
2
+
3
+ var stringWidth2 = require('string-width');
4
+ var machine = require('@boba-cli/machine');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var stringWidth2__default = /*#__PURE__*/_interopDefault(stringWidth2);
9
+
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+
17
+ // src/borders.ts
18
+ var borderStyles = {
19
+ normal: {
20
+ top: "\u2500",
21
+ bottom: "\u2500",
22
+ left: "\u2502",
23
+ right: "\u2502",
24
+ topLeft: "\u250C",
25
+ topRight: "\u2510",
26
+ bottomLeft: "\u2514",
27
+ bottomRight: "\u2518"
28
+ },
29
+ rounded: {
30
+ top: "\u2500",
31
+ bottom: "\u2500",
32
+ left: "\u2502",
33
+ right: "\u2502",
34
+ topLeft: "\u256D",
35
+ topRight: "\u256E",
36
+ bottomLeft: "\u2570",
37
+ bottomRight: "\u256F"
38
+ },
39
+ bold: {
40
+ top: "\u2501",
41
+ bottom: "\u2501",
42
+ left: "\u2503",
43
+ right: "\u2503",
44
+ topLeft: "\u250F",
45
+ topRight: "\u2513",
46
+ bottomLeft: "\u2517",
47
+ bottomRight: "\u251B"
48
+ },
49
+ double: {
50
+ top: "\u2550",
51
+ bottom: "\u2550",
52
+ left: "\u2551",
53
+ right: "\u2551",
54
+ topLeft: "\u2554",
55
+ topRight: "\u2557",
56
+ bottomLeft: "\u255A",
57
+ bottomRight: "\u255D"
58
+ }
59
+ };
60
+ var defaultBorderStyle = borderStyles.normal;
61
+
62
+ // src/colors.ts
63
+ function getColorSupport(env) {
64
+ return env.getColorSupport();
65
+ }
66
+ function getTerminalBackground(env) {
67
+ return env.getTerminalBackground();
68
+ }
69
+ function isDarkTerminal(env) {
70
+ const bg = getTerminalBackground(env);
71
+ return bg !== "light";
72
+ }
73
+ function resolveColor(input, env) {
74
+ if (!input) {
75
+ return void 0;
76
+ }
77
+ if (typeof input === "string") {
78
+ return input;
79
+ }
80
+ const preferDark = isDarkTerminal(env);
81
+ return preferDark ? input.dark ?? input.light : input.light ?? input.dark;
82
+ }
83
+ var reflowTruncate;
84
+ var reflowWordwrap;
85
+ try {
86
+ const reflowjs = __require("terminal-reflowjs");
87
+ if (typeof reflowjs.truncate === "function") {
88
+ reflowTruncate = reflowjs.truncate;
89
+ }
90
+ if (typeof reflowjs.wordwrap === "function") {
91
+ reflowWordwrap = reflowjs.wordwrap;
92
+ }
93
+ } catch {
94
+ }
95
+ function width(text) {
96
+ return stringWidth2__default.default(String(text ?? ""));
97
+ }
98
+ function truncateLine(line, maxWidth) {
99
+ if (width(line) <= maxWidth) {
100
+ return line;
101
+ }
102
+ let acc = "";
103
+ let inAnsi = false;
104
+ for (const ch of line) {
105
+ if (ch === "\x1B") {
106
+ inAnsi = true;
107
+ acc += ch;
108
+ continue;
109
+ }
110
+ if (inAnsi) {
111
+ acc += ch;
112
+ if (/[a-zA-Z]/.test(ch)) {
113
+ inAnsi = false;
114
+ }
115
+ continue;
116
+ }
117
+ const nextWidth = width(acc + ch);
118
+ if (nextWidth > maxWidth) {
119
+ break;
120
+ }
121
+ acc += ch;
122
+ }
123
+ return acc;
124
+ }
125
+ function clampWidth(text, maxWidth) {
126
+ if (!maxWidth || maxWidth < 1) {
127
+ return text;
128
+ }
129
+ if (reflowTruncate) {
130
+ return text.split("\n").map((line) => reflowTruncate(line, maxWidth)).join("\n");
131
+ }
132
+ return text.split("\n").map((line) => truncateLine(line, maxWidth)).join("\n");
133
+ }
134
+ function simpleWordwrap(text, maxWidth) {
135
+ const lines = text.split("\n");
136
+ const result = [];
137
+ for (const line of lines) {
138
+ if (width(line) <= maxWidth) {
139
+ result.push(line);
140
+ continue;
141
+ }
142
+ const words = line.split(/(\s+)/);
143
+ let currentLine = "";
144
+ for (const word of words) {
145
+ if (!word) continue;
146
+ const testLine = currentLine + word;
147
+ if (width(testLine) <= maxWidth) {
148
+ currentLine = testLine;
149
+ } else {
150
+ if (currentLine.trim()) {
151
+ result.push(currentLine.trimEnd());
152
+ }
153
+ if (width(word.trim()) > maxWidth) {
154
+ let remaining = word.trim();
155
+ while (width(remaining) > maxWidth) {
156
+ const truncated = truncateLine(remaining, maxWidth);
157
+ result.push(truncated);
158
+ remaining = remaining.slice(truncated.length);
159
+ }
160
+ currentLine = remaining;
161
+ } else {
162
+ currentLine = word.trimStart();
163
+ }
164
+ }
165
+ }
166
+ if (currentLine.trim()) {
167
+ result.push(currentLine.trimEnd());
168
+ }
169
+ }
170
+ return result.join("\n");
171
+ }
172
+ function wrapWidth(text, maxWidth) {
173
+ if (!maxWidth || maxWidth < 1) {
174
+ return text;
175
+ }
176
+ if (reflowWordwrap) {
177
+ return reflowWordwrap(text, maxWidth);
178
+ }
179
+ return simpleWordwrap(text, maxWidth);
180
+ }
181
+ function padLines(text, left = 0, right = 0) {
182
+ if (left === 0 && right === 0) {
183
+ return text;
184
+ }
185
+ const padLeft = " ".repeat(Math.max(0, left));
186
+ const padRight = " ".repeat(Math.max(0, right));
187
+ return text.split("\n").map((line) => `${padLeft}${line}${padRight}`).join("\n");
188
+ }
189
+ var defaultContext;
190
+ function createDefaultContext() {
191
+ if (!defaultContext) {
192
+ const noColors = { level: 0, hasBasic: false, has256: false, has16m: false };
193
+ const noopEnv = {
194
+ get: () => void 0,
195
+ getColorSupport: () => noColors,
196
+ getTerminalBackground: () => "unknown"
197
+ };
198
+ defaultContext = {
199
+ env: noopEnv,
200
+ styleFn: machine.createStyle(noColors)
201
+ };
202
+ }
203
+ return defaultContext;
204
+ }
205
+ function setDefaultContext(context) {
206
+ defaultContext = context;
207
+ }
208
+ var Style = class _Style {
209
+ options;
210
+ /** Track which properties have been explicitly set */
211
+ setKeys;
212
+ /** Optional context for rendering - if not set, rendering will throw */
213
+ context;
214
+ constructor(options = {}, setKeys, context) {
215
+ this.options = { ...options };
216
+ this.setKeys = setKeys ? new Set(setKeys) : new Set(Object.keys(options));
217
+ this.context = context;
218
+ }
219
+ /**
220
+ * Create a deep copy of this style.
221
+ */
222
+ copy() {
223
+ return new _Style(structuredClone(this.options), new Set(this.setKeys), this.context);
224
+ }
225
+ /**
226
+ * Create a copy of this style with a new context.
227
+ * @param context - The new context to use for rendering
228
+ */
229
+ withContext(context) {
230
+ return new _Style(this.options, this.setKeys, context);
231
+ }
232
+ /**
233
+ * Inherit unset properties from another style.
234
+ * Only copies properties that are set in `other` but not set in `this`.
235
+ * Margins and padding are NOT inherited (matching Go Lip Gloss behavior).
236
+ */
237
+ inherit(other) {
238
+ const newOptions = { ...this.options };
239
+ const newSetKeys = new Set(this.setKeys);
240
+ const noInherit = ["padding", "margin"];
241
+ for (const key of other.setKeys) {
242
+ if (noInherit.includes(key)) continue;
243
+ if (!this.setKeys.has(key)) {
244
+ newOptions[key] = structuredClone(
245
+ other.options[key]
246
+ );
247
+ newSetKeys.add(key);
248
+ }
249
+ }
250
+ return new _Style(newOptions, newSetKeys, this.context);
251
+ }
252
+ /**
253
+ * Check if a property has been explicitly set.
254
+ */
255
+ isSet(key) {
256
+ return this.setKeys.has(key);
257
+ }
258
+ /**
259
+ * Unset a property, reverting to default behavior.
260
+ */
261
+ unset(...keys) {
262
+ const newOptions = { ...this.options };
263
+ const newSetKeys = new Set(this.setKeys);
264
+ for (const key of keys) {
265
+ delete newOptions[key];
266
+ newSetKeys.delete(key);
267
+ }
268
+ return new _Style(newOptions, newSetKeys, this.context);
269
+ }
270
+ foreground(color) {
271
+ return this.with({ foreground: color });
272
+ }
273
+ background(color) {
274
+ return this.with({ background: color });
275
+ }
276
+ bold(value = true) {
277
+ return this.with({ bold: value });
278
+ }
279
+ italic(value = true) {
280
+ return this.with({ italic: value });
281
+ }
282
+ underline(value = true) {
283
+ return this.with({ underline: value });
284
+ }
285
+ strikethrough(value = true) {
286
+ return this.with({ strikethrough: value });
287
+ }
288
+ padding(input, right, bottom, left) {
289
+ const next = normalizeSpacing(input, right, bottom, left);
290
+ return this.with({ padding: { ...this.options.padding, ...next } });
291
+ }
292
+ margin(input, right, bottom, left) {
293
+ const next = normalizeSpacing(input, right, bottom, left);
294
+ return this.with({ margin: { ...this.options.margin, ...next } });
295
+ }
296
+ width(value) {
297
+ return this.with({ width: value });
298
+ }
299
+ height(value) {
300
+ return this.with({ height: value });
301
+ }
302
+ maxWidth(value) {
303
+ return this.with({ maxWidth: value });
304
+ }
305
+ maxHeight(value) {
306
+ return this.with({ maxHeight: value });
307
+ }
308
+ border(arg = true) {
309
+ if (typeof arg === "boolean") {
310
+ if (arg) {
311
+ return this.with({
312
+ borderStyle: this.options.borderStyle ?? defaultBorderStyle
313
+ });
314
+ } else {
315
+ return this.unset("borderStyle", "borderColor");
316
+ }
317
+ }
318
+ return this.with({ borderStyle: arg });
319
+ }
320
+ /**
321
+ * Set the border style characters.
322
+ */
323
+ borderStyle(style) {
324
+ return this.with({ borderStyle: style });
325
+ }
326
+ /**
327
+ * Set the border foreground color.
328
+ */
329
+ borderForeground(color) {
330
+ return this.with({ borderColor: color });
331
+ }
332
+ /**
333
+ * Set horizontal alignment.
334
+ * @deprecated Use alignHorizontal() instead.
335
+ */
336
+ align(value) {
337
+ return this.alignHorizontal(value);
338
+ }
339
+ /**
340
+ * Set horizontal alignment (left, center, right).
341
+ */
342
+ alignHorizontal(value) {
343
+ return this.with({ alignHorizontal: value });
344
+ }
345
+ /**
346
+ * Set vertical alignment (top, center, bottom).
347
+ * Only applies when height is set.
348
+ */
349
+ alignVertical(value) {
350
+ return this.with({ alignVertical: value });
351
+ }
352
+ /**
353
+ * Enable inline mode. When true:
354
+ * - Newlines are stripped from the input
355
+ * - Padding and margins are not applied
356
+ */
357
+ inline(value = true) {
358
+ return this.with({ inline: value });
359
+ }
360
+ /**
361
+ * Render the style to a string.
362
+ * Uses the default no-op context if none was provided.
363
+ */
364
+ render(text) {
365
+ const ctx = this.context ?? createDefaultContext();
366
+ return this.renderWithContext(text, ctx);
367
+ }
368
+ /**
369
+ * Render the style to a string with an explicit context.
370
+ * @param text - Text to render
371
+ * @param ctx - Context for rendering
372
+ */
373
+ renderWithContext(text, ctx) {
374
+ const opts = this.options;
375
+ const isInline = opts.inline ?? false;
376
+ let content = text ?? "";
377
+ if (isInline) {
378
+ content = content.replace(/\r?\n/g, "");
379
+ }
380
+ const targetWidth = opts.width ?? opts.maxWidth;
381
+ const hasBorder = opts.borderStyle !== void 0 || this.setKeys.has("borderColor");
382
+ const padding = isInline ? { top: 0, right: 0, bottom: 0, left: 0 } : normalizeSpacing(opts.padding ?? 0);
383
+ const borderWidth = hasBorder ? 2 : 0;
384
+ const innerTargetWidth = targetWidth !== void 0 ? Math.max(0, targetWidth - padding.left - padding.right - borderWidth) : void 0;
385
+ if (opts.maxWidth && innerTargetWidth !== void 0) {
386
+ content = wrapWidth(content, innerTargetWidth);
387
+ }
388
+ if (opts.width && opts.width > 0 && innerTargetWidth !== void 0) {
389
+ content = clampWidth(content, innerTargetWidth);
390
+ }
391
+ const lines = content.split("\n");
392
+ const aligned = alignLinesHorizontal(
393
+ lines,
394
+ opts.alignHorizontal,
395
+ innerTargetWidth
396
+ );
397
+ const padded = isInline ? aligned : applySpacing(aligned, padding);
398
+ const borderStyle = opts.borderStyle ?? defaultBorderStyle;
399
+ const bordered = hasBorder ? applyBorder(padded, borderStyle, opts.borderColor, ctx) : padded;
400
+ const sized = applyHeight(
401
+ bordered,
402
+ opts.height,
403
+ opts.maxHeight,
404
+ opts.alignVertical
405
+ );
406
+ const colored = applyTextStyle(sized, opts, ctx);
407
+ if (isInline) {
408
+ return colored.join("");
409
+ }
410
+ const withMargin = applySpacing(
411
+ colored,
412
+ normalizeSpacing(opts.margin ?? 0)
413
+ ).join("\n");
414
+ return withMargin;
415
+ }
416
+ with(patch) {
417
+ const newSetKeys = new Set(this.setKeys);
418
+ for (const key of Object.keys(patch)) {
419
+ newSetKeys.add(key);
420
+ }
421
+ return new _Style({ ...this.options, ...patch }, newSetKeys, this.context);
422
+ }
423
+ };
424
+ function normalizeSpacing(input, right, bottom, left) {
425
+ if (typeof input === "number") {
426
+ const v = input;
427
+ if (right === void 0 && bottom === void 0 && left === void 0) {
428
+ return { top: v, right: v, bottom: v, left: v };
429
+ }
430
+ if (right !== void 0 && bottom === void 0 && left === void 0) {
431
+ return { top: v, right, bottom: v, left: right };
432
+ }
433
+ return {
434
+ top: v,
435
+ right: right ?? 0,
436
+ bottom: bottom ?? 0,
437
+ left: left ?? 0
438
+ };
439
+ }
440
+ return {
441
+ top: input.top ?? 0,
442
+ right: input.right ?? 0,
443
+ bottom: input.bottom ?? 0,
444
+ left: input.left ?? 0
445
+ };
446
+ }
447
+ function alignLinesHorizontal(lines, align, targetWidth) {
448
+ if (!targetWidth && !align) {
449
+ return lines;
450
+ }
451
+ const maxLineWidth = lines.reduce(
452
+ (acc, line) => Math.max(acc, width(line)),
453
+ 0
454
+ );
455
+ const width2 = targetWidth ?? maxLineWidth;
456
+ const effectiveAlign = align ?? "left";
457
+ return lines.map((line) => {
458
+ const w = width(line);
459
+ const space = Math.max(0, width2 - w);
460
+ switch (effectiveAlign) {
461
+ case "center": {
462
+ const left = Math.floor(space / 2);
463
+ const right = space - left;
464
+ return `${" ".repeat(left)}${line}${" ".repeat(right)}`;
465
+ }
466
+ case "right":
467
+ return `${" ".repeat(space)}${line}`;
468
+ case "left":
469
+ default:
470
+ return `${line}${" ".repeat(space)}`;
471
+ }
472
+ });
473
+ }
474
+ function applySpacing(lines, spacing) {
475
+ const { top, right, bottom, left } = spacing;
476
+ const spaceLeft = " ".repeat(Math.max(0, left));
477
+ const spaceRight = " ".repeat(Math.max(0, right));
478
+ const spaced = lines.map((line) => `${spaceLeft}${line}${spaceRight}`);
479
+ const maxWidth = spaced.reduce(
480
+ (acc, line) => Math.max(acc, width(line)),
481
+ 0
482
+ );
483
+ const empty = " ".repeat(maxWidth);
484
+ const withTop = Array.from({ length: Math.max(0, top) }, () => empty).concat(
485
+ spaced
486
+ );
487
+ return withTop.concat(
488
+ Array.from({ length: Math.max(0, bottom) }, () => empty)
489
+ );
490
+ }
491
+ function applyBorder(lines, style, borderColor, ctx) {
492
+ if (!style) return lines;
493
+ const widthMax = lines.reduce(
494
+ (acc, line) => Math.max(acc, width(line)),
495
+ 0
496
+ );
497
+ const top = style.top.repeat(Math.max(0, widthMax));
498
+ const bottom = style.bottom.repeat(Math.max(0, widthMax));
499
+ const wrap = (line) => `${style.left}${line}${style.right}`;
500
+ const sidePadded = lines.map((line) => {
501
+ const pad = Math.max(0, widthMax - width(line));
502
+ return wrap(`${line}${" ".repeat(pad)}`);
503
+ });
504
+ const topLine = `${style.topLeft}${top}${style.topRight}`;
505
+ const bottomLine = `${style.bottomLeft}${bottom}${style.bottomRight}`;
506
+ const withBorder = [topLine, ...sidePadded, bottomLine];
507
+ if (!borderColor) {
508
+ return withBorder;
509
+ }
510
+ const colored = applyColor(withBorder.join("\n"), borderColor, ctx);
511
+ return colored.split("\n");
512
+ }
513
+ function applyHeight(lines, height, maxHeight, vAlign) {
514
+ let result = [...lines];
515
+ if (height !== void 0 && height > 0) {
516
+ const widthMax = Math.max(...result.map(width), 0);
517
+ const blank = " ".repeat(widthMax);
518
+ if (result.length < height) {
519
+ const missing = height - result.length;
520
+ const topPad = vAlign === "bottom" ? missing : vAlign === "center" ? Math.floor(missing / 2) : 0;
521
+ const bottomPad = missing - topPad;
522
+ const topFill = [];
523
+ for (let i = 0; i < topPad; i++) topFill.push(blank);
524
+ const bottomFill = [];
525
+ for (let i = 0; i < bottomPad; i++) bottomFill.push(blank);
526
+ result = [...topFill, ...result, ...bottomFill];
527
+ } else if (result.length > height) {
528
+ result = result.slice(0, height);
529
+ }
530
+ }
531
+ if (maxHeight !== void 0 && maxHeight > 0 && result.length > maxHeight) {
532
+ result = result.slice(0, maxHeight);
533
+ }
534
+ return result;
535
+ }
536
+ function applyTextStyle(lines, opts, ctx) {
537
+ const fg = resolveColor(opts.foreground, ctx.env);
538
+ const bg = resolveColor(opts.background, ctx.env);
539
+ const styleFn = (input) => {
540
+ let instance = ctx.styleFn;
541
+ if (fg) instance = applyForeground(instance, fg);
542
+ if (bg) instance = applyBackground(instance, bg);
543
+ if (opts.bold) instance = instance.bold;
544
+ if (opts.italic) instance = instance.italic;
545
+ if (opts.underline) instance = instance.underline;
546
+ if (opts.strikethrough) instance = instance.strikethrough;
547
+ return instance(input);
548
+ };
549
+ return lines.map(styleFn);
550
+ }
551
+ function applyForeground(instance, color) {
552
+ if (color.startsWith("#")) {
553
+ return instance.hex(color);
554
+ }
555
+ const rgbMatch = color.match(
556
+ /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i
557
+ );
558
+ if (rgbMatch) {
559
+ const r = parseInt(rgbMatch[1] ?? "0", 10);
560
+ const g = parseInt(rgbMatch[2] ?? "0", 10);
561
+ const b = parseInt(rgbMatch[3] ?? "0", 10);
562
+ return instance.rgb(r, g, b);
563
+ }
564
+ const namedColor = color.toLowerCase();
565
+ const prop = instance[namedColor];
566
+ if (typeof prop === "function" || typeof prop === "object" && prop !== null) {
567
+ return prop;
568
+ }
569
+ return instance.hex(color);
570
+ }
571
+ function applyBackground(instance, color) {
572
+ if (color.startsWith("#")) {
573
+ return instance.bgHex(color);
574
+ }
575
+ const rgbMatch = color.match(
576
+ /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i
577
+ );
578
+ if (rgbMatch) {
579
+ const r = parseInt(rgbMatch[1] ?? "0", 10);
580
+ const g = parseInt(rgbMatch[2] ?? "0", 10);
581
+ const b = parseInt(rgbMatch[3] ?? "0", 10);
582
+ return instance.bgRgb(r, g, b);
583
+ }
584
+ const bgColor = `bg${color.charAt(0).toUpperCase()}${color.slice(1).toLowerCase()}`;
585
+ const prop = instance[bgColor];
586
+ if (typeof prop === "function" || typeof prop === "object" && prop !== null) {
587
+ return prop;
588
+ }
589
+ return instance.bgHex(color);
590
+ }
591
+ function applyColor(text, color, ctx) {
592
+ const resolved = resolveColor(color, ctx.env);
593
+ if (!resolved) return text;
594
+ return text.split("\n").map((line) => {
595
+ let instance = ctx.styleFn;
596
+ instance = applyForeground(instance, resolved);
597
+ return instance(line);
598
+ }).join("\n");
599
+ }
600
+
601
+ // src/provider.ts
602
+ var ChapstickStyleProvider = class {
603
+ context;
604
+ /**
605
+ * Create a new style provider.
606
+ * @param env - Environment adapter for detecting terminal capabilities
607
+ * @param styleFn - Style function for applying ANSI styling
608
+ */
609
+ constructor(env, styleFn) {
610
+ this.context = { env, styleFn };
611
+ }
612
+ createStyle() {
613
+ return new Style({}, void 0, this.context);
614
+ }
615
+ get semanticStyles() {
616
+ const ctx = this.context;
617
+ return {
618
+ success: new Style({}, void 0, ctx).bold(true).foreground("#50FA7B"),
619
+ error: new Style({}, void 0, ctx).bold(true).foreground("#FF5555"),
620
+ warning: new Style({}, void 0, ctx).bold(true).foreground("#F1FA8C"),
621
+ info: new Style({}, void 0, ctx).foreground("#8BE9FD"),
622
+ muted: new Style({}, void 0, ctx).foreground("#6272A4"),
623
+ highlight: new Style({}, void 0, ctx).background("#44475A").foreground("#F8F8F2"),
624
+ header: new Style({}, void 0, ctx).bold(true).foreground("#00D9FF").padding(0, 1)
625
+ };
626
+ }
627
+ };
628
+ function joinHorizontal(first, ...rest) {
629
+ const spacing = typeof first === "number" ? first : 0;
630
+ const blocks = typeof first === "number" ? rest : [first, ...rest];
631
+ if (blocks.length === 0) return "";
632
+ const split = blocks.map((b) => b.split("\n"));
633
+ const widths = split.map(
634
+ (lines) => Math.max(...lines.map((l) => stringWidth2__default.default(l)), 0)
635
+ );
636
+ const height = Math.max(...split.map((lines) => lines.length));
637
+ const padded = split.map((lines, idx) => {
638
+ const w = widths[idx] ?? 0;
639
+ const missing = height - lines.length;
640
+ const filled = lines.concat(Array(missing).fill(""));
641
+ return filled.map((line) => padToWidth(line, w));
642
+ });
643
+ const gap = " ".repeat(Math.max(0, spacing));
644
+ const rows = [];
645
+ for (let i = 0; i < height; i++) {
646
+ rows.push(padded.map((col) => col[i] ?? "").join(gap));
647
+ }
648
+ return rows.join("\n");
649
+ }
650
+ function joinVertical(first, ...rest) {
651
+ const spacing = typeof first === "number" ? first : 0;
652
+ const blocks = typeof first === "number" ? rest : [first, ...rest];
653
+ if (blocks.length === 0) return "";
654
+ const gap = "\n".repeat(Math.max(0, spacing + 1));
655
+ return blocks.join(gap);
656
+ }
657
+ function place(width2, height, hAlign, vAlign, content) {
658
+ const lines = content.split("\n");
659
+ const clamped = lines.slice(0, height).map((line) => truncateLine2(line, width2));
660
+ const paddedLines = clamped.map((line) => alignLine(line, width2, hAlign));
661
+ const missing = height - paddedLines.length;
662
+ const topPad = vAlign === "top" ? 0 : vAlign === "center" ? Math.floor(missing / 2) : missing;
663
+ const bottomPad = missing - topPad;
664
+ const empty = " ".repeat(Math.max(0, width2));
665
+ const prefix = createPadLines(empty, Math.max(0, topPad));
666
+ const suffix = createPadLines(empty, Math.max(0, bottomPad));
667
+ return [...prefix, ...paddedLines, ...suffix].join("\n");
668
+ }
669
+ function createPadLines(line, count) {
670
+ if (count <= 0) return [];
671
+ return Array(count).fill(line);
672
+ }
673
+ function padToWidth(input, width2) {
674
+ const w = stringWidth2__default.default(input);
675
+ if (w >= width2) return input;
676
+ return `${input}${" ".repeat(width2 - w)}`;
677
+ }
678
+ function truncateLine2(input, maxWidth) {
679
+ const w = stringWidth2__default.default(input);
680
+ if (w <= maxWidth) return input;
681
+ let acc = "";
682
+ for (const ch of input) {
683
+ if (stringWidth2__default.default(acc + ch) > maxWidth) break;
684
+ acc += ch;
685
+ }
686
+ return acc;
687
+ }
688
+ function alignLine(input, width2, align) {
689
+ const w = stringWidth2__default.default(input);
690
+ const space = Math.max(0, width2 - w);
691
+ if (align === "right") {
692
+ return `${" ".repeat(space)}${input}`;
693
+ }
694
+ if (align === "center") {
695
+ const left = Math.floor(space / 2);
696
+ const right = space - left;
697
+ return `${" ".repeat(left)}${input}${" ".repeat(right)}`;
698
+ }
699
+ return `${input}${" ".repeat(space)}`;
700
+ }
701
+
702
+ exports.ChapstickStyleProvider = ChapstickStyleProvider;
703
+ exports.Style = Style;
704
+ exports.borderStyles = borderStyles;
705
+ exports.clampWidth = clampWidth;
706
+ exports.createDefaultContext = createDefaultContext;
707
+ exports.defaultBorderStyle = defaultBorderStyle;
708
+ exports.getColorSupport = getColorSupport;
709
+ exports.getTerminalBackground = getTerminalBackground;
710
+ exports.joinHorizontal = joinHorizontal;
711
+ exports.joinVertical = joinVertical;
712
+ exports.padLines = padLines;
713
+ exports.place = place;
714
+ exports.resolveColor = resolveColor;
715
+ exports.setDefaultContext = setDefaultContext;
716
+ exports.width = width;
717
+ exports.wrapWidth = wrapWidth;
718
+ //# sourceMappingURL=index.cjs.map
719
+ //# sourceMappingURL=index.cjs.map