@vizejs/fresco 0.717.0 → 0.719.0

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 (50) hide show
  1. package/dist/{accessibility-DY_alnTr.d.mts → accessibility-DwzT925M.d.mts} +11 -5
  2. package/dist/accessibility-DwzT925M.d.mts.map +1 -0
  3. package/dist/{app-B9yJzz5S.mjs → app-C_wFlWSV.mjs} +368 -123
  4. package/dist/app-C_wFlWSV.mjs.map +1 -0
  5. package/dist/app-_QmZ-PoH.d.mts +270 -0
  6. package/dist/app-_QmZ-PoH.d.mts.map +1 -0
  7. package/dist/ascii-font/index.d.mts +60 -0
  8. package/dist/ascii-font/index.d.mts.map +1 -0
  9. package/dist/ascii-font/index.mjs +68 -0
  10. package/dist/ascii-font/index.mjs.map +1 -0
  11. package/dist/components/index.d.mts +2 -2
  12. package/dist/components/index.mjs +2 -2
  13. package/dist/components-DzkL-yHj.mjs +6165 -0
  14. package/dist/components-DzkL-yHj.mjs.map +1 -0
  15. package/dist/composables/index.d.mts +3 -3
  16. package/dist/composables/index.mjs +4 -4
  17. package/dist/{composables-uj7hkBfP.mjs → composables-BJeirPSH.mjs} +116 -55
  18. package/dist/composables-BJeirPSH.mjs.map +1 -0
  19. package/dist/{index-BjK3JSNo.d.mts → index-BCxB_ZLV.d.mts} +1079 -239
  20. package/dist/index-BCxB_ZLV.d.mts.map +1 -0
  21. package/dist/{index-Dikou9bu.d.mts → index-Ddp2Txtm.d.mts} +52 -4
  22. package/dist/index-Ddp2Txtm.d.mts.map +1 -0
  23. package/dist/index.d.mts +98 -7
  24. package/dist/index.d.mts.map +1 -0
  25. package/dist/index.mjs +262 -5
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/{protocol-D8xt3DG7.d.mts → protocol-DavoeNLn.d.mts} +14 -4
  28. package/dist/{protocol-D8xt3DG7.d.mts.map → protocol-DavoeNLn.d.mts.map} +1 -1
  29. package/dist/qr-code/index.d.mts +101 -0
  30. package/dist/qr-code/index.d.mts.map +1 -0
  31. package/dist/qr-code/index.mjs +88 -0
  32. package/dist/qr-code/index.mjs.map +1 -0
  33. package/dist/testing/index.d.mts +3 -3
  34. package/dist/testing/index.mjs +1 -1
  35. package/dist/{useApp-CVB2jNCO.d.mts → useApp-vIRJ5Th3.d.mts} +34 -8
  36. package/dist/useApp-vIRJ5Th3.d.mts.map +1 -0
  37. package/dist/{useVirtualViewport-DYuUlTxU.mjs → useBoxMetrics-lF5Myjc7.mjs} +66 -6
  38. package/dist/useBoxMetrics-lF5Myjc7.mjs.map +1 -0
  39. package/package.json +14 -6
  40. package/dist/accessibility-DY_alnTr.d.mts.map +0 -1
  41. package/dist/app-B9yJzz5S.mjs.map +0 -1
  42. package/dist/app-CKsTWQuP.d.mts +0 -154
  43. package/dist/app-CKsTWQuP.d.mts.map +0 -1
  44. package/dist/components-C57eT1BL.mjs +0 -3406
  45. package/dist/components-C57eT1BL.mjs.map +0 -1
  46. package/dist/composables-uj7hkBfP.mjs.map +0 -1
  47. package/dist/index-BjK3JSNo.d.mts.map +0 -1
  48. package/dist/index-Dikou9bu.d.mts.map +0 -1
  49. package/dist/useApp-CVB2jNCO.d.mts.map +0 -1
  50. package/dist/useVirtualViewport-DYuUlTxU.mjs.map +0 -1
@@ -1,3406 +0,0 @@
1
- import { i as useInput, r as useMouse, s as useIsScreenReaderEnabled, t as createVirtualViewport } from "./useVirtualViewport-DYuUlTxU.mjs";
2
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, h, mergeProps, normalizeStyle, onMounted, onUnmounted, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useSlots, watch, withCtx } from "vue";
3
- //#region src/components/Box.ts
4
- /**
5
- * Box Component - Container with flexbox layout
6
- */
7
- const dimensionProp = [Number, String];
8
- function normalizeBorderStyle(style) {
9
- if (style === "round") return "rounded";
10
- if (style === "bold") return "heavy";
11
- return style;
12
- }
13
- const Box = defineComponent({
14
- name: "Box",
15
- props: {
16
- display: String,
17
- position: String,
18
- top: dimensionProp,
19
- right: dimensionProp,
20
- bottom: dimensionProp,
21
- left: dimensionProp,
22
- flexDirection: String,
23
- flexWrap: String,
24
- justifyContent: String,
25
- alignItems: String,
26
- alignSelf: String,
27
- alignContent: String,
28
- flexGrow: Number,
29
- flexShrink: Number,
30
- flexBasis: dimensionProp,
31
- width: dimensionProp,
32
- height: dimensionProp,
33
- minWidth: dimensionProp,
34
- minHeight: dimensionProp,
35
- maxWidth: dimensionProp,
36
- maxHeight: dimensionProp,
37
- aspectRatio: Number,
38
- padding: Number,
39
- paddingX: Number,
40
- paddingY: Number,
41
- paddingTop: Number,
42
- paddingRight: Number,
43
- paddingBottom: Number,
44
- paddingLeft: Number,
45
- margin: Number,
46
- marginX: Number,
47
- marginY: Number,
48
- marginTop: Number,
49
- marginRight: Number,
50
- marginBottom: Number,
51
- marginLeft: Number,
52
- gap: Number,
53
- columnGap: Number,
54
- rowGap: Number,
55
- overflow: String,
56
- overflowX: String,
57
- overflowY: String,
58
- border: String,
59
- borderStyle: String,
60
- borderTop: Boolean,
61
- borderRight: Boolean,
62
- borderBottom: Boolean,
63
- borderLeft: Boolean,
64
- borderColor: String,
65
- borderTopColor: String,
66
- borderRightColor: String,
67
- borderBottomColor: String,
68
- borderLeftColor: String,
69
- borderDimColor: Boolean,
70
- borderTopDimColor: Boolean,
71
- borderRightDimColor: Boolean,
72
- borderBottomDimColor: Boolean,
73
- borderLeftDimColor: Boolean,
74
- borderBackgroundColor: String,
75
- borderTopBackgroundColor: String,
76
- borderRightBackgroundColor: String,
77
- borderBottomBackgroundColor: String,
78
- borderLeftBackgroundColor: String,
79
- fg: String,
80
- color: String,
81
- bg: String,
82
- backgroundColor: String,
83
- ariaLabel: String,
84
- ariaHidden: Boolean,
85
- ariaRole: String,
86
- ariaState: Object
87
- },
88
- setup(props, { slots }) {
89
- const isScreenReaderEnabled = useIsScreenReaderEnabled();
90
- return () => {
91
- if (isScreenReaderEnabled && props.ariaHidden) return null;
92
- const style = {};
93
- if (props.display) style.display = props.display;
94
- if (props.position) style.position = props.position;
95
- if (props.top !== void 0) style.top = String(props.top);
96
- if (props.right !== void 0) style.right = String(props.right);
97
- if (props.bottom !== void 0) style.bottom = String(props.bottom);
98
- if (props.left !== void 0) style.left = String(props.left);
99
- if (props.flexDirection) style.flexDirection = props.flexDirection;
100
- if (props.flexWrap) style.flexWrap = props.flexWrap;
101
- if (props.justifyContent) style.justifyContent = props.justifyContent;
102
- if (props.alignItems) style.alignItems = props.alignItems;
103
- if (props.alignSelf) style.alignSelf = props.alignSelf;
104
- if (props.alignContent) style.alignContent = props.alignContent;
105
- if (props.flexGrow !== void 0) style.flexGrow = props.flexGrow;
106
- if (props.flexShrink !== void 0) style.flexShrink = props.flexShrink;
107
- if (props.flexBasis !== void 0) style.flexBasis = String(props.flexBasis);
108
- if (props.width !== void 0) style.width = String(props.width);
109
- if (props.height !== void 0) style.height = String(props.height);
110
- if (props.minWidth !== void 0) style.minWidth = String(props.minWidth);
111
- if (props.minHeight !== void 0) style.minHeight = String(props.minHeight);
112
- if (props.maxWidth !== void 0) style.maxWidth = String(props.maxWidth);
113
- if (props.maxHeight !== void 0) style.maxHeight = String(props.maxHeight);
114
- if (props.aspectRatio !== void 0) style.aspectRatio = props.aspectRatio;
115
- if (props.padding !== void 0) style.padding = props.padding;
116
- if (props.paddingTop !== void 0 || props.paddingY !== void 0) style.paddingTop = props.paddingTop ?? props.paddingY ?? props.padding;
117
- if (props.paddingRight !== void 0 || props.paddingX !== void 0) style.paddingRight = props.paddingRight ?? props.paddingX ?? props.padding;
118
- if (props.paddingBottom !== void 0 || props.paddingY !== void 0) style.paddingBottom = props.paddingBottom ?? props.paddingY ?? props.padding;
119
- if (props.paddingLeft !== void 0 || props.paddingX !== void 0) style.paddingLeft = props.paddingLeft ?? props.paddingX ?? props.padding;
120
- if (props.margin !== void 0) style.margin = props.margin;
121
- if (props.marginTop !== void 0 || props.marginY !== void 0) style.marginTop = props.marginTop ?? props.marginY ?? props.margin;
122
- if (props.marginRight !== void 0 || props.marginX !== void 0) style.marginRight = props.marginRight ?? props.marginX ?? props.margin;
123
- if (props.marginBottom !== void 0 || props.marginY !== void 0) style.marginBottom = props.marginBottom ?? props.marginY ?? props.margin;
124
- if (props.marginLeft !== void 0 || props.marginX !== void 0) style.marginLeft = props.marginLeft ?? props.marginX ?? props.margin;
125
- if (props.gap !== void 0) style.gap = props.gap;
126
- if (props.columnGap !== void 0) style.columnGap = props.columnGap;
127
- if (props.rowGap !== void 0) style.rowGap = props.rowGap;
128
- if (props.overflow) style.overflow = props.overflow;
129
- if (props.overflowX) style.overflowX = props.overflowX;
130
- if (props.overflowY) style.overflowY = props.overflowY;
131
- const children = isScreenReaderEnabled && props.ariaLabel ? [h("text", { text: props.ariaLabel })] : slots.default?.();
132
- return h("box", {
133
- style,
134
- border: normalizeBorderStyle(props.borderStyle ?? props.border),
135
- borderColor: props.borderColor,
136
- borderTopColor: props.borderTopColor,
137
- borderRightColor: props.borderRightColor,
138
- borderBottomColor: props.borderBottomColor,
139
- borderLeftColor: props.borderLeftColor,
140
- borderDimColor: props.borderDimColor,
141
- borderBackgroundColor: props.borderBackgroundColor,
142
- fg: props.fg ?? props.color,
143
- bg: props.bg ?? props.backgroundColor,
144
- "aria-label": props.ariaLabel,
145
- "aria-hidden": props.ariaHidden,
146
- "aria-role": props.ariaRole,
147
- "aria-state": props.ariaState
148
- }, children);
149
- };
150
- }
151
- });
152
- //#endregion
153
- //#region src/components/FrescoSpacer.vue
154
- var FrescoSpacer_default = /* @__PURE__ */ defineComponent({
155
- name: "Spacer",
156
- __name: "FrescoSpacer",
157
- setup(__props) {
158
- return (_ctx, _cache) => {
159
- return openBlock(), createBlock(unref(Box), {
160
- "flex-grow": 1,
161
- "flex-shrink": 1
162
- });
163
- };
164
- }
165
- });
166
- //#endregion
167
- //#region src/components/FrescoDivider.vue?vue&type=script&setup=true&lang.ts
168
- const _hoisted_1$10 = ["fg"];
169
- const _hoisted_2$8 = ["fg"];
170
- const _hoisted_3$7 = ["fg"];
171
- const _hoisted_4$3 = ["fg"];
172
- const _hoisted_5$2 = ["fg"];
173
- //#endregion
174
- //#region src/components/FrescoDivider.vue
175
- var FrescoDivider_default = /* @__PURE__ */ defineComponent({
176
- name: "FrescoDivider",
177
- __name: "FrescoDivider",
178
- props: {
179
- direction: {
180
- type: String,
181
- required: false,
182
- default: "horizontal"
183
- },
184
- char: {
185
- type: String,
186
- required: false
187
- },
188
- title: {
189
- type: String,
190
- required: false
191
- },
192
- fg: {
193
- type: String,
194
- required: false,
195
- default: "gray"
196
- },
197
- titleFg: {
198
- type: String,
199
- required: false
200
- }
201
- },
202
- setup(__props) {
203
- const dividerChar = computed(() => __props.char ?? (__props.direction === "horizontal" ? "─" : "│"));
204
- const titleLabel = computed(() => ` ${__props.title} `);
205
- const titleRowStyle = {
206
- flexDirection: "row",
207
- alignItems: "center"
208
- };
209
- return (_ctx, _cache) => {
210
- return __props.direction === "vertical" ? (openBlock(), createElementBlock("text", {
211
- key: 0,
212
- fg: __props.fg
213
- }, toDisplayString(dividerChar.value), 9, _hoisted_1$10)) : __props.title ? (openBlock(), createElementBlock("div", {
214
- key: 1,
215
- style: titleRowStyle
216
- }, [
217
- createElementVNode("text", { fg: __props.fg }, toDisplayString(dividerChar.value.repeat(3)), 9, _hoisted_2$8),
218
- createElementVNode("text", {
219
- fg: __props.titleFg ?? __props.fg,
220
- bold: true
221
- }, toDisplayString(titleLabel.value), 9, _hoisted_3$7),
222
- createElementVNode("text", { fg: __props.fg }, toDisplayString(dividerChar.value.repeat(3)), 9, _hoisted_4$3)
223
- ])) : (openBlock(), createElementBlock("text", {
224
- key: 2,
225
- fg: __props.fg
226
- }, toDisplayString(dividerChar.value.repeat(40)), 9, _hoisted_5$2));
227
- };
228
- }
229
- });
230
- //#endregion
231
- //#region src/components/layout-primitive-types.ts
232
- const stackAlignValues = {
233
- start: "flex-start",
234
- center: "center",
235
- end: "flex-end",
236
- stretch: "stretch"
237
- };
238
- const stackJustifyValues = {
239
- start: "flex-start",
240
- center: "center",
241
- end: "flex-end",
242
- between: "space-between",
243
- around: "space-around",
244
- evenly: "space-evenly"
245
- };
246
- //#endregion
247
- //#region src/components/FrescoStack.vue
248
- var FrescoStack_default = /* @__PURE__ */ defineComponent({
249
- name: "FrescoStack",
250
- __name: "FrescoStack",
251
- props: {
252
- direction: {
253
- type: String,
254
- required: false,
255
- default: "vertical"
256
- },
257
- gap: {
258
- type: Number,
259
- required: false,
260
- default: 0
261
- },
262
- align: {
263
- type: String,
264
- required: false,
265
- default: "stretch"
266
- },
267
- justify: {
268
- type: String,
269
- required: false,
270
- default: "start"
271
- },
272
- wrap: {
273
- type: Boolean,
274
- required: false,
275
- default: false
276
- }
277
- },
278
- setup(__props) {
279
- const stackStyle = computed(() => ({
280
- flexDirection: __props.direction === "horizontal" ? "row" : "column",
281
- gap: __props.gap,
282
- alignItems: stackAlignValues[__props.align],
283
- justifyContent: stackJustifyValues[__props.justify],
284
- flexWrap: __props.wrap ? "wrap" : "nowrap"
285
- }));
286
- return (_ctx, _cache) => {
287
- return openBlock(), createElementBlock("div", { style: normalizeStyle(stackStyle.value) }, [renderSlot(_ctx.$slots, "default")], 4);
288
- };
289
- }
290
- });
291
- //#endregion
292
- //#region src/components/FrescoHStack.vue
293
- var FrescoHStack_default = /* @__PURE__ */ defineComponent({
294
- name: "FrescoHStack",
295
- __name: "FrescoHStack",
296
- props: {
297
- gap: {
298
- type: Number,
299
- required: false,
300
- default: 1
301
- },
302
- align: {
303
- type: String,
304
- required: false
305
- },
306
- justify: {
307
- type: String,
308
- required: false
309
- }
310
- },
311
- setup(__props) {
312
- return (_ctx, _cache) => {
313
- return openBlock(), createBlock(FrescoStack_default, {
314
- direction: "horizontal",
315
- gap: __props.gap,
316
- align: __props.align,
317
- justify: __props.justify
318
- }, {
319
- default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
320
- _: 3
321
- }, 8, [
322
- "gap",
323
- "align",
324
- "justify"
325
- ]);
326
- };
327
- }
328
- });
329
- //#endregion
330
- //#region src/components/FrescoVStack.vue
331
- var FrescoVStack_default = /* @__PURE__ */ defineComponent({
332
- name: "FrescoVStack",
333
- __name: "FrescoVStack",
334
- props: {
335
- gap: {
336
- type: Number,
337
- required: false,
338
- default: 0
339
- },
340
- align: {
341
- type: String,
342
- required: false
343
- },
344
- justify: {
345
- type: String,
346
- required: false
347
- }
348
- },
349
- setup(__props) {
350
- return (_ctx, _cache) => {
351
- return openBlock(), createBlock(FrescoStack_default, {
352
- direction: "vertical",
353
- gap: __props.gap,
354
- align: __props.align,
355
- justify: __props.justify
356
- }, {
357
- default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
358
- _: 3
359
- }, 8, [
360
- "gap",
361
- "align",
362
- "justify"
363
- ]);
364
- };
365
- }
366
- });
367
- //#endregion
368
- //#region src/components/Grid.ts
369
- /**
370
- * Grid Component - Grid layout helper
371
- */
372
- const Grid = defineComponent({
373
- name: "Grid",
374
- props: {
375
- columns: {
376
- type: Number,
377
- default: 2
378
- },
379
- gap: {
380
- type: Number,
381
- default: 1
382
- },
383
- rowGap: Number,
384
- columnGap: Number
385
- },
386
- setup(props, { slots }) {
387
- return () => {
388
- const children = slots.default?.() ?? [];
389
- const flatChildren = Array.isArray(children) ? children.flat() : [children];
390
- const rows = [];
391
- let currentRow = [];
392
- flatChildren.forEach((child, index) => {
393
- currentRow.push(child);
394
- if (currentRow.length === props.columns || index === flatChildren.length - 1) {
395
- rows.push([...currentRow]);
396
- currentRow = [];
397
- }
398
- });
399
- const rowGap = props.rowGap ?? props.gap;
400
- const columnGap = props.columnGap ?? props.gap;
401
- return h("box", { style: {
402
- flex_direction: "column",
403
- gap: rowGap
404
- } }, rows.map((row, rowIndex) => h("box", {
405
- key: `row-${rowIndex}`,
406
- style: {
407
- flex_direction: "row",
408
- gap: columnGap
409
- }
410
- }, row.map((cell, cellIndex) => h("box", {
411
- key: `cell-${rowIndex}-${cellIndex}`,
412
- style: { flex_grow: 1 }
413
- }, [cell])))));
414
- };
415
- }
416
- });
417
- //#endregion
418
- //#region src/components/FrescoCard.vue?vue&type=script&setup=true&lang.ts
419
- const _hoisted_1$9 = [
420
- "border",
421
- "fg",
422
- "bg"
423
- ];
424
- const _hoisted_2$7 = ["fg"];
425
- const _hoisted_3$6 = {
426
- key: 1,
427
- dim: true
428
- };
429
- const _hoisted_4$2 = { dim: true };
430
- //#endregion
431
- //#region src/components/FrescoCard.vue
432
- var FrescoCard_default = /* @__PURE__ */ defineComponent({
433
- name: "FrescoCard",
434
- __name: "FrescoCard",
435
- props: {
436
- title: {
437
- type: String,
438
- required: false
439
- },
440
- subtitle: {
441
- type: String,
442
- required: false
443
- },
444
- footer: {
445
- type: String,
446
- required: false
447
- },
448
- border: {
449
- type: String,
450
- required: false,
451
- default: "rounded"
452
- },
453
- padding: {
454
- type: Number,
455
- required: false,
456
- default: 1
457
- },
458
- titleFg: {
459
- type: String,
460
- required: false,
461
- default: "white"
462
- },
463
- borderFg: {
464
- type: String,
465
- required: false
466
- },
467
- bg: {
468
- type: String,
469
- required: false
470
- }
471
- },
472
- setup(__props) {
473
- const slots = useSlots();
474
- const hasHeader = computed(() => Boolean(__props.title || __props.subtitle));
475
- const hasFooter = computed(() => Boolean(__props.footer || slots.footer));
476
- const containerStyle = computed(() => ({
477
- flexDirection: "column",
478
- padding: __props.padding
479
- }));
480
- const headerStyle = {
481
- flexDirection: "row",
482
- marginBottom: 1
483
- };
484
- const contentStyle = { flexGrow: 1 };
485
- const footerStyle = { marginTop: 1 };
486
- const subtitleLabel = computed(() => __props.subtitle ? __props.title ? ` - ${__props.subtitle}` : __props.subtitle : "");
487
- return (_ctx, _cache) => {
488
- return openBlock(), createElementBlock("div", {
489
- border: __props.border === "none" ? void 0 : __props.border,
490
- fg: __props.borderFg,
491
- bg: __props.bg,
492
- style: normalizeStyle(containerStyle.value)
493
- }, [
494
- hasHeader.value ? (openBlock(), createElementBlock("div", {
495
- key: 0,
496
- style: headerStyle
497
- }, [__props.title ? (openBlock(), createElementBlock("text", {
498
- key: 0,
499
- fg: __props.titleFg,
500
- bold: true
501
- }, toDisplayString(__props.title), 9, _hoisted_2$7)) : createCommentVNode("v-if", true), __props.subtitle ? (openBlock(), createElementBlock("text", _hoisted_3$6, toDisplayString(subtitleLabel.value), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
502
- createElementVNode("div", { style: contentStyle }, [renderSlot(_ctx.$slots, "default")]),
503
- hasFooter.value ? (openBlock(), createElementBlock("div", {
504
- key: 1,
505
- style: footerStyle
506
- }, [renderSlot(_ctx.$slots, "footer", {}, () => [createElementVNode("text", _hoisted_4$2, toDisplayString(__props.footer), 1)])])) : createCommentVNode("v-if", true)
507
- ], 12, _hoisted_1$9);
508
- };
509
- }
510
- });
511
- //#endregion
512
- //#region src/utils/text.ts
513
- /**
514
- * Unicode-aware text helpers shared by input and text components.
515
- */
516
- const segmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
517
- function graphemes(value) {
518
- if (!value) return [];
519
- if (segmenter) return Array.from(segmenter.segment(value), (segment) => segment.segment);
520
- return Array.from(value);
521
- }
522
- function graphemeLength(value) {
523
- return graphemes(value).length;
524
- }
525
- function sliceGraphemes(value, start, end) {
526
- return graphemes(value).slice(start, end).join("");
527
- }
528
- function insertAtGrapheme(value, index, text) {
529
- return `${sliceGraphemes(value, 0, index)}${text}${sliceGraphemes(value, index)}`;
530
- }
531
- function deleteGraphemeBefore(value, index) {
532
- if (index <= 0) return value;
533
- return `${sliceGraphemes(value, 0, index - 1)}${sliceGraphemes(value, index)}`;
534
- }
535
- function deleteGraphemeAt(value, index) {
536
- const length = graphemeLength(value);
537
- if (index < 0 || index >= length) return value;
538
- return `${sliceGraphemes(value, 0, index)}${sliceGraphemes(value, index + 1)}`;
539
- }
540
- function stringifyChildren(children) {
541
- if (children == null || typeof children === "boolean") return "";
542
- if (typeof children === "string" || typeof children === "number") return String(children);
543
- if (Array.isArray(children)) return children.map((child) => stringifyChildren(child)).join("");
544
- if (typeof children === "object") {
545
- const vnode = children;
546
- if ((typeof vnode.type === "string" ? vnode.type : vnode.type?.name) === "Newline") {
547
- const count = typeof vnode.props?.count === "number" ? vnode.props.count : 1;
548
- return "\n".repeat(Math.max(0, count));
549
- }
550
- if (typeof vnode.props?.text === "string" || typeof vnode.props?.text === "number") return String(vnode.props.text);
551
- if (typeof vnode.props?.content === "string" || typeof vnode.props?.content === "number") return String(vnode.props.content);
552
- return stringifyChildren(vnode.children);
553
- }
554
- return "";
555
- }
556
- //#endregion
557
- //#region src/components/Text.ts
558
- /**
559
- * Text Component - Text display
560
- */
561
- const Text = defineComponent({
562
- name: "Text",
563
- props: {
564
- content: String,
565
- wrap: [Boolean, String],
566
- fg: String,
567
- color: String,
568
- bg: String,
569
- backgroundColor: String,
570
- bold: Boolean,
571
- dim: Boolean,
572
- dimColor: Boolean,
573
- italic: Boolean,
574
- underline: Boolean,
575
- strikethrough: Boolean,
576
- inverse: Boolean,
577
- blink: Boolean,
578
- hidden: Boolean,
579
- ariaLabel: String,
580
- ariaHidden: Boolean
581
- },
582
- setup(props, { slots }) {
583
- const isScreenReaderEnabled = useIsScreenReaderEnabled();
584
- return () => {
585
- if (isScreenReaderEnabled && props.ariaHidden) return null;
586
- return h("text", {
587
- text: isScreenReaderEnabled && props.ariaLabel ? props.ariaLabel : props.content ?? stringifyChildren(slots.default?.()),
588
- wrap: props.wrap,
589
- fg: props.fg ?? props.color,
590
- bg: props.bg ?? props.backgroundColor,
591
- bold: props.bold,
592
- dim: props.dim || props.dimColor,
593
- italic: props.italic,
594
- underline: props.underline,
595
- strikethrough: props.strikethrough,
596
- inverse: props.inverse,
597
- ...props.blink ? { blink: true } : {},
598
- ...props.hidden ? { hidden: true } : {},
599
- "aria-label": props.ariaLabel,
600
- "aria-hidden": props.ariaHidden
601
- });
602
- };
603
- }
604
- });
605
- defineComponent({
606
- name: "ErrorText",
607
- props: { content: String },
608
- setup(props, { slots }) {
609
- return () => h(Text, {
610
- fg: "red",
611
- ...props
612
- }, slots);
613
- }
614
- });
615
- defineComponent({
616
- name: "WarningText",
617
- props: { content: String },
618
- setup(props, { slots }) {
619
- return () => h(Text, {
620
- fg: "yellow",
621
- ...props
622
- }, slots);
623
- }
624
- });
625
- defineComponent({
626
- name: "SuccessText",
627
- props: { content: String },
628
- setup(props, { slots }) {
629
- return () => h(Text, {
630
- fg: "green",
631
- ...props
632
- }, slots);
633
- }
634
- });
635
- defineComponent({
636
- name: "InfoText",
637
- props: { content: String },
638
- setup(props, { slots }) {
639
- return () => h(Text, {
640
- fg: "blue",
641
- ...props
642
- }, slots);
643
- }
644
- });
645
- defineComponent({
646
- name: "MutedText",
647
- props: { content: String },
648
- setup(props, { slots }) {
649
- return () => h(Text, {
650
- dim: true,
651
- ...props
652
- }, slots);
653
- }
654
- });
655
- //#endregion
656
- //#region src/components/ScrollBar.vue
657
- var ScrollBar_default = /* @__PURE__ */ defineComponent({
658
- __name: "ScrollBar",
659
- props: {
660
- itemCount: {
661
- type: Number,
662
- required: true
663
- },
664
- viewportSize: {
665
- type: Number,
666
- required: true
667
- },
668
- offset: {
669
- type: Number,
670
- required: true
671
- },
672
- length: {
673
- type: Number,
674
- required: false
675
- },
676
- orientation: {
677
- type: String,
678
- required: false,
679
- default: "vertical"
680
- },
681
- track: {
682
- type: String,
683
- required: false,
684
- default: "│"
685
- },
686
- thumb: {
687
- type: String,
688
- required: false,
689
- default: "█"
690
- },
691
- fg: {
692
- type: String,
693
- required: false
694
- },
695
- thumbFg: {
696
- type: String,
697
- required: false
698
- }
699
- },
700
- setup(__props) {
701
- function nonNegativeInteger(value) {
702
- const floored = Math.floor(value);
703
- return Number.isSafeInteger(floored) && floored >= 0 ? floored : 0;
704
- }
705
- const metrics = computed(() => {
706
- const trackLength = nonNegativeInteger(__props.length ?? __props.viewportSize);
707
- const boundedViewportSize = nonNegativeInteger(__props.viewportSize);
708
- const boundedItemCount = nonNegativeInteger(__props.itemCount);
709
- const maxOffset = Math.max(0, boundedItemCount - boundedViewportSize);
710
- return {
711
- trackLength,
712
- boundedViewportSize,
713
- boundedItemCount,
714
- maxOffset,
715
- boundedOffset: Number.isFinite(__props.offset) ? Math.min(maxOffset, Math.max(0, __props.offset)) : 0
716
- };
717
- });
718
- const cells = computed(() => {
719
- const { trackLength, boundedViewportSize, boundedItemCount, maxOffset, boundedOffset } = metrics.value;
720
- if (trackLength === 0) return [];
721
- const thumbSize = maxOffset === 0 ? trackLength : Math.max(1, Math.min(trackLength, Math.floor(trackLength * boundedViewportSize / boundedItemCount)));
722
- const travel = trackLength - thumbSize;
723
- const thumbStart = maxOffset === 0 ? 0 : Math.round(boundedOffset / maxOffset * travel);
724
- return Array.from({ length: trackLength }, (_, position) => ({
725
- position,
726
- symbol: position >= thumbStart && position < thumbStart + thumbSize ? __props.thumb : __props.track,
727
- thumb: position >= thumbStart && position < thumbStart + thumbSize
728
- }));
729
- });
730
- const ariaState = computed(() => ({
731
- orientation: __props.orientation,
732
- valueMin: 0,
733
- valueMax: metrics.value.maxOffset,
734
- valueNow: metrics.value.boundedOffset
735
- }));
736
- const accessibilityProps = computed(() => ({
737
- ariaRole: "scrollbar",
738
- ariaState: ariaState.value
739
- }));
740
- const cellAccessibilityProps = { ariaHidden: true };
741
- return (_ctx, _cache) => {
742
- return openBlock(), createBlock(unref(Box), mergeProps({ "flex-direction": __props.orientation === "vertical" ? "column" : "row" }, accessibilityProps.value), {
743
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(cells.value, (cell) => {
744
- return openBlock(), createBlock(unref(Text), mergeProps({
745
- key: cell.position,
746
- content: cell.symbol,
747
- fg: cell.thumb ? __props.thumbFg ?? __props.fg : __props.fg
748
- }, { ref_for: true }, cellAccessibilityProps), null, 16, ["content", "fg"]);
749
- }), 128))]),
750
- _: 1
751
- }, 16, ["flex-direction"]);
752
- };
753
- }
754
- });
755
- //#endregion
756
- //#region src/components/ScrollBox.vue
757
- var ScrollBox_default = /* @__PURE__ */ defineComponent({
758
- __name: "ScrollBox",
759
- props: {
760
- itemCount: {
761
- type: Number,
762
- required: true
763
- },
764
- viewportSize: {
765
- type: Number,
766
- required: true
767
- },
768
- modelValue: {
769
- type: Number,
770
- required: false
771
- },
772
- overscan: {
773
- type: Number,
774
- required: false,
775
- default: 2
776
- },
777
- focused: {
778
- type: Boolean,
779
- required: false,
780
- default: false
781
- },
782
- disabled: {
783
- type: Boolean,
784
- required: false,
785
- default: false
786
- },
787
- wheelStep: {
788
- type: Number,
789
- required: false,
790
- default: 3
791
- },
792
- showScrollbar: {
793
- type: Boolean,
794
- required: false,
795
- default: true
796
- },
797
- followOutput: {
798
- type: Boolean,
799
- required: false,
800
- default: false
801
- },
802
- scrollbarTrack: {
803
- type: String,
804
- required: false,
805
- default: "│"
806
- },
807
- scrollbarThumb: {
808
- type: String,
809
- required: false,
810
- default: "█"
811
- }
812
- },
813
- emits: ["update:modelValue", "scroll"],
814
- setup(__props, { expose: __expose, emit: __emit }) {
815
- const emit = __emit;
816
- const viewport = createVirtualViewport({
817
- itemCount: __props.itemCount,
818
- viewportSize: __props.viewportSize,
819
- overscan: __props.overscan,
820
- initialOffset: __props.modelValue ?? 0
821
- });
822
- const isActive = computed(() => __props.focused && !__props.disabled);
823
- const normalizedWheelStep = computed(() => {
824
- const truncated = Math.trunc(__props.wheelStep);
825
- return Number.isSafeInteger(truncated) && truncated > 0 ? truncated : 1;
826
- });
827
- const retainedIndexes = computed(() => {
828
- const range = viewport.range.value;
829
- return Array.from({ length: range.overscanEnd - range.overscanStart }, (_, index) => range.overscanStart + index);
830
- });
831
- const rootAriaState = computed(() => ({ disabled: __props.disabled }));
832
- const rootAccessibilityProps = computed(() => ({
833
- ariaRole: "list",
834
- ariaState: rootAriaState.value
835
- }));
836
- function publish(changed) {
837
- if (!changed) return false;
838
- emit("update:modelValue", viewport.offset.value);
839
- emit("scroll", viewport.range.value);
840
- return true;
841
- }
842
- function scrollTo(offset) {
843
- return publish(viewport.scrollTo(offset));
844
- }
845
- function scrollBy(delta) {
846
- return publish(viewport.scrollBy(delta));
847
- }
848
- function scrollIntoView(index, alignment = "nearest") {
849
- return publish(viewport.scrollIntoView(index, alignment));
850
- }
851
- function isVisible(index) {
852
- const range = viewport.range.value;
853
- return index >= range.visibleStart && index < range.visibleEnd;
854
- }
855
- function itemSlot(index) {
856
- return {
857
- ...viewport.range.value,
858
- index,
859
- visible: isVisible(index)
860
- };
861
- }
862
- watch([
863
- () => __props.itemCount,
864
- () => __props.viewportSize,
865
- () => __props.modelValue
866
- ], ([itemCount, viewportSize, modelValue], [previousItemCount, previousViewportSize, previousModelValue]) => {
867
- const itemCountChanged = itemCount !== previousItemCount;
868
- const viewportSizeChanged = viewportSize !== previousViewportSize;
869
- const modelValueChanged = modelValue !== previousModelValue;
870
- const followedEnd = itemCountChanged && __props.followOutput && viewport.atEnd.value;
871
- const previousOffset = viewport.offset.value;
872
- if (itemCountChanged) viewport.setItemCount(itemCount);
873
- if (viewportSizeChanged) viewport.setViewportSize(viewportSize);
874
- if (followedEnd && !modelValueChanged) viewport.scrollTo(viewport.maxOffset.value);
875
- if (modelValue !== void 0 && (modelValueChanged || (itemCountChanged || viewportSizeChanged) && !followedEnd)) viewport.scrollTo(modelValue);
876
- const offsetChanged = previousOffset !== viewport.offset.value;
877
- const requestedOffsetWasClamped = modelValue !== void 0 && modelValue !== viewport.offset.value;
878
- if (requestedOffsetWasClamped || offsetChanged && !modelValueChanged) emit("update:modelValue", viewport.offset.value);
879
- if (offsetChanged && (itemCountChanged || viewportSizeChanged || requestedOffsetWasClamped)) emit("scroll", viewport.range.value);
880
- });
881
- watch(() => __props.overscan, (value) => viewport.setOverscan(value));
882
- useInput((_input, key) => {
883
- if (key.eventType === "release") return;
884
- if (key.upArrow) scrollBy(-1);
885
- else if (key.downArrow) scrollBy(1);
886
- else if (key.pageUp) scrollBy(-Math.max(1, __props.viewportSize - 1));
887
- else if (key.pageDown) scrollBy(Math.max(1, __props.viewportSize - 1));
888
- else if (key.home) scrollTo(0);
889
- else if (key.end) scrollTo(viewport.maxOffset.value);
890
- }, { isActive });
891
- useMouse((event) => {
892
- if (event.kind === "scroll-up") scrollBy(-normalizedWheelStep.value);
893
- else if (event.kind === "scroll-down") scrollBy(normalizedWheelStep.value);
894
- }, { isActive });
895
- __expose({
896
- scrollTo,
897
- scrollBy,
898
- scrollIntoView,
899
- range: () => viewport.range.value
900
- });
901
- return (_ctx, _cache) => {
902
- return openBlock(), createBlock(unref(Box), mergeProps({ "flex-direction": "column" }, rootAccessibilityProps.value), {
903
- default: withCtx(() => [
904
- renderSlot(_ctx.$slots, "start"),
905
- createVNode(unref(Box), { "flex-direction": __props.showScrollbar ? "row" : "column" }, {
906
- default: withCtx(() => [createVNode(unref(Box), {
907
- "flex-direction": "column",
908
- height: __props.viewportSize,
909
- overflow: "hidden"
910
- }, {
911
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(retainedIndexes.value, (index) => {
912
- return openBlock(), createBlock(unref(Box), {
913
- key: index,
914
- display: isVisible(index) ? "flex" : "none",
915
- "aria-hidden": !isVisible(index),
916
- "data-scroll-index": index
917
- }, {
918
- default: withCtx(() => [renderSlot(_ctx.$slots, "default", mergeProps({ ref_for: true }, itemSlot(index)))]),
919
- _: 2
920
- }, 1032, [
921
- "display",
922
- "aria-hidden",
923
- "data-scroll-index"
924
- ]);
925
- }), 128))]),
926
- _: 3
927
- }, 8, ["height"]), __props.showScrollbar && __props.itemCount > __props.viewportSize ? (openBlock(), createBlock(ScrollBar_default, {
928
- key: 0,
929
- "item-count": __props.itemCount,
930
- "viewport-size": __props.viewportSize,
931
- offset: unref(viewport).offset.value,
932
- track: __props.scrollbarTrack,
933
- thumb: __props.scrollbarThumb
934
- }, null, 8, [
935
- "item-count",
936
- "viewport-size",
937
- "offset",
938
- "track",
939
- "thumb"
940
- ])) : createCommentVNode("v-if", true)]),
941
- _: 3
942
- }, 8, ["flex-direction"]),
943
- renderSlot(_ctx.$slots, "end")
944
- ]),
945
- _: 3
946
- }, 16);
947
- };
948
- }
949
- });
950
- //#endregion
951
- //#region src/components/FrescoNewline.vue?vue&type=script&setup=true&lang.ts
952
- const _hoisted_1$8 = ["text"];
953
- //#endregion
954
- //#region src/components/FrescoNewline.vue
955
- var FrescoNewline_default = /* @__PURE__ */ defineComponent({
956
- name: "Newline",
957
- __name: "FrescoNewline",
958
- props: { count: {
959
- type: Number,
960
- required: false,
961
- default: 1
962
- } },
963
- setup(__props) {
964
- const content = computed(() => "\n".repeat(Math.max(0, __props.count)));
965
- return (_ctx, _cache) => {
966
- return openBlock(), createElementBlock("text", { text: content.value }, null, 8, _hoisted_1$8);
967
- };
968
- }
969
- });
970
- //#endregion
971
- //#region src/components/FrescoStatic.vue
972
- var FrescoStatic_default = /* @__PURE__ */ defineComponent({
973
- name: "Static",
974
- __name: "FrescoStatic",
975
- props: {
976
- items: {
977
- type: Array,
978
- required: false,
979
- default: () => []
980
- },
981
- style: {
982
- type: null,
983
- required: false
984
- }
985
- },
986
- setup(__props) {
987
- const containerStyle = computed(() => ({
988
- position: "absolute",
989
- flexDirection: "column",
990
- ...__props.style
991
- }));
992
- const itemStyle = { flexDirection: "column" };
993
- const renderedItems = computed(() => __props.items.map((item, index) => ({
994
- item,
995
- index,
996
- key: `static-${index}`
997
- })));
998
- return (_ctx, _cache) => {
999
- return openBlock(), createElementBlock("div", {
1000
- internal_static: true,
1001
- style: normalizeStyle(containerStyle.value)
1002
- }, [(openBlock(true), createElementBlock(Fragment, null, renderList(renderedItems.value, (entry) => {
1003
- return openBlock(), createElementBlock("div", {
1004
- key: entry.key,
1005
- internal_static_item: true,
1006
- style: itemStyle
1007
- }, [renderSlot(_ctx.$slots, "default", {
1008
- item: entry.item,
1009
- index: entry.index
1010
- })]);
1011
- }), 128))], 4);
1012
- };
1013
- }
1014
- });
1015
- //#endregion
1016
- //#region src/components/FrescoTransform.vue?vue&type=script&setup=true&lang.ts
1017
- const _hoisted_1$7 = ["text", "aria-label"];
1018
- //#endregion
1019
- //#region src/components/FrescoTransform.vue
1020
- var FrescoTransform_default = /* @__PURE__ */ defineComponent({
1021
- name: "Transform",
1022
- __name: "FrescoTransform",
1023
- props: {
1024
- accessibilityLabel: {
1025
- type: String,
1026
- required: false
1027
- },
1028
- transform: {
1029
- type: Function,
1030
- required: true
1031
- }
1032
- },
1033
- setup(__props) {
1034
- const props = __props;
1035
- const slots = useSlots();
1036
- const isScreenReaderEnabled = useIsScreenReaderEnabled();
1037
- const content = computed(() => {
1038
- const text = stringifyChildren(slots.default?.());
1039
- return isScreenReaderEnabled && props.accessibilityLabel ? props.accessibilityLabel : text.split("\n").map((line, index) => props.transform(line, index)).join("\n");
1040
- });
1041
- return (_ctx, _cache) => {
1042
- return openBlock(), createElementBlock("text", {
1043
- text: content.value,
1044
- "aria-label": __props.accessibilityLabel
1045
- }, null, 8, _hoisted_1$7);
1046
- };
1047
- }
1048
- });
1049
- //#endregion
1050
- //#region src/components/Code.ts
1051
- /**
1052
- * Code Component - Code block display
1053
- */
1054
- const Code = defineComponent({
1055
- name: "Code",
1056
- props: {
1057
- code: {
1058
- type: String,
1059
- required: true
1060
- },
1061
- language: String,
1062
- lineNumbers: {
1063
- type: Boolean,
1064
- default: true
1065
- },
1066
- startLine: {
1067
- type: Number,
1068
- default: 1
1069
- },
1070
- highlightLines: {
1071
- type: Array,
1072
- default: () => []
1073
- },
1074
- border: {
1075
- type: String,
1076
- default: "single"
1077
- },
1078
- fg: {
1079
- type: String,
1080
- default: "white"
1081
- },
1082
- lineNumberFg: {
1083
- type: String,
1084
- default: "gray"
1085
- },
1086
- highlightBg: {
1087
- type: String,
1088
- default: "blue"
1089
- }
1090
- },
1091
- setup(props) {
1092
- return () => {
1093
- const lines = props.code.split("\n");
1094
- const maxLineNum = props.startLine + lines.length - 1;
1095
- const lineNumWidth = String(maxLineNum).length;
1096
- const children = lines.map((line, index) => {
1097
- const lineNum = props.startLine + index;
1098
- const isHighlighted = props.highlightLines?.includes(lineNum);
1099
- const parts = [];
1100
- if (props.lineNumbers) parts.push(h("text", {
1101
- key: `ln-${lineNum}`,
1102
- fg: props.lineNumberFg
1103
- }, `${String(lineNum).padStart(lineNumWidth)} │ `));
1104
- parts.push(h("text", {
1105
- key: `code-${lineNum}`,
1106
- fg: props.fg,
1107
- bg: isHighlighted ? props.highlightBg : void 0
1108
- }, line || " "));
1109
- return h("box", {
1110
- key: `line-${lineNum}`,
1111
- style: { flex_direction: "row" }
1112
- }, parts);
1113
- });
1114
- if (props.language) children.unshift(h("text", {
1115
- key: "lang",
1116
- dim: true,
1117
- style: { margin_bottom: 1 }
1118
- }, `// ${props.language}`));
1119
- return h("box", {
1120
- border: props.border === "none" ? void 0 : props.border,
1121
- style: {
1122
- flex_direction: "column",
1123
- padding: props.border !== "none" ? 1 : 0
1124
- }
1125
- }, children);
1126
- };
1127
- }
1128
- });
1129
- //#endregion
1130
- //#region src/components/FrescoLink.vue?vue&type=script&setup=true&lang.ts
1131
- const _hoisted_1$6 = ["fg", "underline"];
1132
- const _hoisted_2$6 = {
1133
- key: 0,
1134
- dim: true
1135
- };
1136
- //#endregion
1137
- //#region src/components/FrescoLink.vue
1138
- var FrescoLink_default = /* @__PURE__ */ defineComponent({
1139
- name: "FrescoLink",
1140
- __name: "FrescoLink",
1141
- props: {
1142
- text: {
1143
- type: String,
1144
- required: true
1145
- },
1146
- url: {
1147
- type: String,
1148
- required: false
1149
- },
1150
- fg: {
1151
- type: String,
1152
- required: false,
1153
- default: "blue"
1154
- },
1155
- underline: {
1156
- type: Boolean,
1157
- required: false,
1158
- default: true
1159
- },
1160
- showUrl: {
1161
- type: Boolean,
1162
- required: false,
1163
- default: false
1164
- }
1165
- },
1166
- setup(__props) {
1167
- const rowStyle = { flexDirection: "row" };
1168
- return (_ctx, _cache) => {
1169
- return openBlock(), createElementBlock("div", { style: rowStyle }, [createElementVNode("text", {
1170
- fg: __props.fg,
1171
- underline: __props.underline
1172
- }, toDisplayString(__props.text), 9, _hoisted_1$6), __props.showUrl && __props.url ? (openBlock(), createElementBlock("text", _hoisted_2$6, " (" + toDisplayString(__props.url) + ")", 1)) : createCommentVNode("v-if", true)]);
1173
- };
1174
- }
1175
- });
1176
- //#endregion
1177
- //#region src/components/TextInput.ts
1178
- /**
1179
- * TextInput Component - Text input with builtin cursor management and IME support
1180
- */
1181
- const TextInput = defineComponent({
1182
- name: "TextInput",
1183
- props: {
1184
- modelValue: {
1185
- type: String,
1186
- default: ""
1187
- },
1188
- placeholder: {
1189
- type: String,
1190
- default: ""
1191
- },
1192
- focus: {
1193
- type: Boolean,
1194
- default: false
1195
- },
1196
- focused: {
1197
- type: Boolean,
1198
- default: void 0
1199
- },
1200
- mask: {
1201
- type: Boolean,
1202
- default: false
1203
- },
1204
- maskChar: {
1205
- type: String,
1206
- default: "*"
1207
- },
1208
- width: [Number, String],
1209
- fg: String,
1210
- bg: String
1211
- },
1212
- emits: [
1213
- "update:modelValue",
1214
- "submit",
1215
- "cancel",
1216
- "compositionstart",
1217
- "compositionupdate",
1218
- "compositionend"
1219
- ],
1220
- setup(props, { emit }) {
1221
- const internalValue = ref(props.modelValue);
1222
- const cursorPos = ref(graphemeLength(props.modelValue));
1223
- const isComposing = ref(false);
1224
- const compositionAnchor = ref(cursorPos.value);
1225
- const preedit = ref("");
1226
- const preeditCursor = ref(0);
1227
- const focused = computed(() => props.focused ?? props.focus);
1228
- watch(() => props.modelValue, (newValue) => {
1229
- internalValue.value = newValue;
1230
- const length = graphemeLength(newValue);
1231
- if (cursorPos.value > length) cursorPos.value = length;
1232
- });
1233
- const updateValue = (value) => {
1234
- internalValue.value = value;
1235
- emit("update:modelValue", value);
1236
- };
1237
- const insertText = (text) => {
1238
- updateValue(insertAtGrapheme(internalValue.value, cursorPos.value, text));
1239
- cursorPos.value += graphemeLength(text);
1240
- };
1241
- const deleteBack = () => {
1242
- if (cursorPos.value > 0) {
1243
- updateValue(deleteGraphemeBefore(internalValue.value, cursorPos.value));
1244
- cursorPos.value--;
1245
- }
1246
- };
1247
- const deleteForward = () => {
1248
- if (cursorPos.value < graphemeLength(internalValue.value)) updateValue(deleteGraphemeAt(internalValue.value, cursorPos.value));
1249
- };
1250
- const moveLeft = () => {
1251
- if (cursorPos.value > 0) cursorPos.value--;
1252
- };
1253
- const moveRight = () => {
1254
- if (cursorPos.value < graphemeLength(internalValue.value)) cursorPos.value++;
1255
- };
1256
- const moveToStart = () => {
1257
- cursorPos.value = 0;
1258
- };
1259
- const moveToEnd = () => {
1260
- cursorPos.value = graphemeLength(internalValue.value);
1261
- };
1262
- const updatePreedit = (text, cursor = graphemeLength(text)) => {
1263
- if (!isComposing.value) {
1264
- isComposing.value = true;
1265
- compositionAnchor.value = cursorPos.value;
1266
- emit("compositionstart");
1267
- }
1268
- preedit.value = text;
1269
- preeditCursor.value = Math.max(0, Math.min(cursor, graphemeLength(text)));
1270
- emit("compositionupdate", preedit.value, preeditCursor.value);
1271
- };
1272
- const finishComposition = (text = preedit.value) => {
1273
- if (!isComposing.value) return;
1274
- cursorPos.value = compositionAnchor.value;
1275
- isComposing.value = false;
1276
- preedit.value = "";
1277
- preeditCursor.value = 0;
1278
- if (text) insertText(text);
1279
- emit("compositionend", text);
1280
- };
1281
- const cancelComposition = () => {
1282
- if (!isComposing.value) return false;
1283
- isComposing.value = false;
1284
- preedit.value = "";
1285
- preeditCursor.value = 0;
1286
- cursorPos.value = compositionAnchor.value;
1287
- emit("compositionend", "");
1288
- return true;
1289
- };
1290
- const deletePreeditBack = () => {
1291
- if (!isComposing.value || preeditCursor.value === 0) return false;
1292
- preedit.value = deleteGraphemeBefore(preedit.value, preeditCursor.value);
1293
- preeditCursor.value--;
1294
- emit("compositionupdate", preedit.value, preeditCursor.value);
1295
- return true;
1296
- };
1297
- const deletePreeditForward = () => {
1298
- if (!isComposing.value || preeditCursor.value >= graphemeLength(preedit.value)) return false;
1299
- preedit.value = deleteGraphemeAt(preedit.value, preeditCursor.value);
1300
- emit("compositionupdate", preedit.value, preeditCursor.value);
1301
- return true;
1302
- };
1303
- const movePreeditLeft = () => {
1304
- if (!isComposing.value || preeditCursor.value === 0) return false;
1305
- preeditCursor.value--;
1306
- emit("compositionupdate", preedit.value, preeditCursor.value);
1307
- return true;
1308
- };
1309
- const movePreeditRight = () => {
1310
- if (!isComposing.value || preeditCursor.value >= graphemeLength(preedit.value)) return false;
1311
- preeditCursor.value++;
1312
- emit("compositionupdate", preedit.value, preeditCursor.value);
1313
- return true;
1314
- };
1315
- const movePreeditToStart = () => {
1316
- if (!isComposing.value) return false;
1317
- preeditCursor.value = 0;
1318
- emit("compositionupdate", preedit.value, preeditCursor.value);
1319
- return true;
1320
- };
1321
- const movePreeditToEnd = () => {
1322
- if (!isComposing.value) return false;
1323
- preeditCursor.value = graphemeLength(preedit.value);
1324
- emit("compositionupdate", preedit.value, preeditCursor.value);
1325
- return true;
1326
- };
1327
- const displayValue = computed(() => {
1328
- if (!isComposing.value) return internalValue.value;
1329
- return [
1330
- sliceGraphemes(internalValue.value, 0, compositionAnchor.value),
1331
- preedit.value,
1332
- sliceGraphemes(internalValue.value, compositionAnchor.value)
1333
- ].join("");
1334
- });
1335
- const displayCursor = computed(() => {
1336
- if (!isComposing.value) return cursorPos.value;
1337
- return compositionAnchor.value + preeditCursor.value;
1338
- });
1339
- useInput({
1340
- isActive: computed(() => focused.value),
1341
- onChar: (char) => {
1342
- if (isComposing.value) return;
1343
- insertText(char);
1344
- },
1345
- onArrow: (direction) => {
1346
- if (direction === "left") {
1347
- if (!movePreeditLeft()) moveLeft();
1348
- }
1349
- if (direction === "right") {
1350
- if (!movePreeditRight()) moveRight();
1351
- }
1352
- },
1353
- onKey: (key, modifiers) => {
1354
- if (key === "backspace") {
1355
- if (!deletePreeditBack()) deleteBack();
1356
- } else if (key === "delete") {
1357
- if (!deletePreeditForward()) deleteForward();
1358
- } else if (key === "home") {
1359
- if (!movePreeditToStart()) moveToStart();
1360
- } else if (key === "end") {
1361
- if (!movePreeditToEnd()) moveToEnd();
1362
- } else if (key === "a" && modifiers.ctrl) {
1363
- if (!movePreeditToEnd()) moveToEnd();
1364
- }
1365
- },
1366
- onSubmit: () => {
1367
- if (isComposing.value) {
1368
- finishComposition();
1369
- return;
1370
- }
1371
- emit("submit", internalValue.value);
1372
- },
1373
- onEscape: () => {
1374
- if (cancelComposition()) return;
1375
- emit("cancel");
1376
- },
1377
- onCompositionStart: () => {
1378
- isComposing.value = true;
1379
- compositionAnchor.value = cursorPos.value;
1380
- preedit.value = "";
1381
- preeditCursor.value = 0;
1382
- emit("compositionstart");
1383
- },
1384
- onCompositionUpdate: updatePreedit,
1385
- onCompositionEnd: finishComposition
1386
- });
1387
- return () => {
1388
- const style = {};
1389
- if (props.width !== void 0) style.width = String(props.width);
1390
- return h("input", {
1391
- value: displayValue.value,
1392
- placeholder: props.placeholder,
1393
- focused: focused.value,
1394
- cursor: displayCursor.value,
1395
- mask: props.mask,
1396
- maskChar: props.maskChar,
1397
- style,
1398
- fg: props.fg,
1399
- bg: props.bg
1400
- });
1401
- };
1402
- }
1403
- });
1404
- defineComponent({
1405
- name: "PasswordInput",
1406
- props: {
1407
- modelValue: {
1408
- type: String,
1409
- default: ""
1410
- },
1411
- placeholder: {
1412
- type: String,
1413
- default: "Enter password..."
1414
- },
1415
- focus: Boolean,
1416
- width: [Number, String],
1417
- fg: String,
1418
- bg: String
1419
- },
1420
- emits: [
1421
- "update:modelValue",
1422
- "submit",
1423
- "cancel"
1424
- ],
1425
- setup(props, { emit }) {
1426
- return () => h(TextInput, {
1427
- ...props,
1428
- mask: true,
1429
- "onUpdate:modelValue": (v) => emit("update:modelValue", v),
1430
- onSubmit: (v) => emit("submit", v),
1431
- onCancel: () => emit("cancel")
1432
- });
1433
- }
1434
- });
1435
- //#endregion
1436
- //#region src/components/TextArea.ts
1437
- /**
1438
- * TextArea Component - Multiline text input
1439
- */
1440
- const TextArea = defineComponent({
1441
- name: "TextArea",
1442
- props: {
1443
- modelValue: {
1444
- type: String,
1445
- default: ""
1446
- },
1447
- placeholder: String,
1448
- rows: {
1449
- type: Number,
1450
- default: 5
1451
- },
1452
- focused: {
1453
- type: Boolean,
1454
- default: false
1455
- },
1456
- disabled: {
1457
- type: Boolean,
1458
- default: false
1459
- },
1460
- lineNumbers: {
1461
- type: Boolean,
1462
- default: false
1463
- },
1464
- border: {
1465
- type: String,
1466
- default: "single"
1467
- },
1468
- fg: String,
1469
- placeholderFg: {
1470
- type: String,
1471
- default: "gray"
1472
- },
1473
- lineNumberFg: {
1474
- type: String,
1475
- default: "gray"
1476
- },
1477
- cursorLine: {
1478
- type: Number,
1479
- default: 0
1480
- },
1481
- cursorColumn: {
1482
- type: Number,
1483
- default: 0
1484
- }
1485
- },
1486
- emits: ["update:modelValue"],
1487
- setup(props) {
1488
- const lines = computed(() => {
1489
- const textLines = (props.modelValue || "").split("\n");
1490
- while (textLines.length < props.rows) textLines.push("");
1491
- return textLines.slice(0, props.rows);
1492
- });
1493
- const showPlaceholder = computed(() => !props.modelValue && props.placeholder && !props.focused);
1494
- return () => {
1495
- const lineNumWidth = String(lines.value.length).length;
1496
- const children = lines.value.map((line, index) => {
1497
- const isCursorLine = props.focused && index === props.cursorLine;
1498
- const parts = [];
1499
- if (props.lineNumbers) parts.push(h("text", {
1500
- key: `ln-${index}`,
1501
- fg: props.lineNumberFg,
1502
- dim: !isCursorLine
1503
- }, `${String(index + 1).padStart(lineNumWidth)} │ `));
1504
- let content = line || (showPlaceholder.value && index === 0 ? props.placeholder : " ");
1505
- parts.push(h("text", {
1506
- key: `content-${index}`,
1507
- fg: showPlaceholder.value && index === 0 ? props.placeholderFg : props.fg,
1508
- dim: props.disabled,
1509
- bold: isCursorLine
1510
- }, content));
1511
- return h("box", {
1512
- key: `line-${index}`,
1513
- style: { flex_direction: "row" },
1514
- bg: isCursorLine ? "gray" : void 0
1515
- }, parts);
1516
- });
1517
- return h("box", {
1518
- border: props.border === "none" ? void 0 : props.border,
1519
- style: {
1520
- flex_direction: "column",
1521
- padding: props.border !== "none" ? 1 : 0,
1522
- height: String(props.rows + (props.border !== "none" ? 2 : 0))
1523
- }
1524
- }, children);
1525
- };
1526
- }
1527
- });
1528
- //#endregion
1529
- //#region src/components/Select.ts
1530
- /**
1531
- * Select Component - Dropdown/menu selection
1532
- */
1533
- const Select = defineComponent({
1534
- name: "Select",
1535
- props: {
1536
- options: {
1537
- type: Array,
1538
- required: true
1539
- },
1540
- modelValue: String,
1541
- placeholder: {
1542
- type: String,
1543
- default: "Select an option"
1544
- },
1545
- focused: {
1546
- type: Boolean,
1547
- default: false
1548
- },
1549
- indicator: {
1550
- type: String,
1551
- default: "> "
1552
- },
1553
- indicatorEmpty: {
1554
- type: String,
1555
- default: " "
1556
- },
1557
- fg: String,
1558
- bg: String,
1559
- selectedFg: {
1560
- type: String,
1561
- default: "cyan"
1562
- },
1563
- selectedBg: String
1564
- },
1565
- emits: ["update:modelValue", "select"],
1566
- setup(props, { emit: _emit }) {
1567
- const highlightedIndex = ref(0);
1568
- watch(() => props.modelValue, (value) => {
1569
- if (value) {
1570
- const index = props.options.findIndex((opt) => opt.value === value);
1571
- if (index !== -1) highlightedIndex.value = index;
1572
- }
1573
- }, { immediate: true });
1574
- return () => {
1575
- const children = props.options.map((option, index) => {
1576
- const isHighlighted = index === highlightedIndex.value;
1577
- const isSelected = option.value === props.modelValue;
1578
- const indicator = isHighlighted ? props.indicator : props.indicatorEmpty;
1579
- return h("box", {
1580
- key: option.value,
1581
- style: { flex_direction: "row" }
1582
- }, [h("text", {
1583
- fg: isHighlighted ? props.selectedFg : props.fg,
1584
- bg: isHighlighted ? props.selectedBg : props.bg,
1585
- dim: option.disabled
1586
- }, `${indicator}${option.label}${isSelected ? " (selected)" : ""}`)]);
1587
- });
1588
- return h("box", {
1589
- style: { flex_direction: "column" },
1590
- fg: props.fg,
1591
- bg: props.bg
1592
- }, children);
1593
- };
1594
- }
1595
- });
1596
- //#endregion
1597
- //#region src/components/Checkbox.ts
1598
- /**
1599
- * Checkbox Component - Toggle checkbox
1600
- */
1601
- const Checkbox = defineComponent({
1602
- name: "Checkbox",
1603
- props: {
1604
- modelValue: {
1605
- type: Boolean,
1606
- default: false
1607
- },
1608
- label: String,
1609
- focused: {
1610
- type: Boolean,
1611
- default: false
1612
- },
1613
- disabled: {
1614
- type: Boolean,
1615
- default: false
1616
- },
1617
- checked: {
1618
- type: String,
1619
- default: "[x]"
1620
- },
1621
- unchecked: {
1622
- type: String,
1623
- default: "[ ]"
1624
- },
1625
- fg: String,
1626
- checkedFg: {
1627
- type: String,
1628
- default: "green"
1629
- }
1630
- },
1631
- emits: ["update:modelValue", "change"],
1632
- setup(props, { emit: _emit }) {
1633
- return () => {
1634
- const indicator = props.modelValue ? props.checked : props.unchecked;
1635
- return h("box", { style: { flex_direction: "row" } }, [h("text", {
1636
- fg: props.modelValue ? props.checkedFg : props.fg,
1637
- dim: props.disabled,
1638
- bold: props.focused
1639
- }, `${indicator} ${props.label ?? ""}`)]);
1640
- };
1641
- }
1642
- });
1643
- //#endregion
1644
- //#region src/components/RadioGroup.ts
1645
- /**
1646
- * RadioGroup Component - Radio button group selection
1647
- */
1648
- const RadioGroup = defineComponent({
1649
- name: "RadioGroup",
1650
- props: {
1651
- options: {
1652
- type: Array,
1653
- required: true
1654
- },
1655
- modelValue: String,
1656
- direction: {
1657
- type: String,
1658
- default: "vertical"
1659
- },
1660
- focusedIndex: Number,
1661
- selected: {
1662
- type: String,
1663
- default: "◉"
1664
- },
1665
- unselected: {
1666
- type: String,
1667
- default: "○"
1668
- },
1669
- fg: String,
1670
- selectedFg: {
1671
- type: String,
1672
- default: "green"
1673
- }
1674
- },
1675
- emits: ["update:modelValue", "change"],
1676
- setup(props, { emit: _emit }) {
1677
- return () => {
1678
- const children = props.options.map((option, index) => {
1679
- const isSelected = option.value === props.modelValue;
1680
- const isFocused = index === props.focusedIndex;
1681
- const indicator = isSelected ? props.selected : props.unselected;
1682
- return h("text", {
1683
- key: option.value,
1684
- fg: isSelected ? props.selectedFg : props.fg,
1685
- bold: isFocused,
1686
- dim: option.disabled
1687
- }, `${indicator} ${option.label}`);
1688
- });
1689
- return h("box", { style: {
1690
- flex_direction: props.direction === "horizontal" ? "row" : "column",
1691
- gap: props.direction === "horizontal" ? 2 : 0
1692
- } }, children);
1693
- };
1694
- }
1695
- });
1696
- //#endregion
1697
- //#region src/components/Confirm.ts
1698
- /**
1699
- * Confirm Component - Confirmation dialog
1700
- */
1701
- const Confirm = defineComponent({
1702
- name: "Confirm",
1703
- props: {
1704
- message: {
1705
- type: String,
1706
- required: true
1707
- },
1708
- confirmText: {
1709
- type: String,
1710
- default: "Yes"
1711
- },
1712
- cancelText: {
1713
- type: String,
1714
- default: "No"
1715
- },
1716
- defaultConfirm: {
1717
- type: Boolean,
1718
- default: true
1719
- },
1720
- confirmFg: {
1721
- type: String,
1722
- default: "green"
1723
- },
1724
- cancelFg: {
1725
- type: String,
1726
- default: "red"
1727
- },
1728
- selectedFg: {
1729
- type: String,
1730
- default: "cyan"
1731
- }
1732
- },
1733
- emits: [
1734
- "confirm",
1735
- "cancel",
1736
- "select"
1737
- ],
1738
- setup(props, { emit: _emit }) {
1739
- const isConfirmSelected = ref(props.defaultConfirm);
1740
- return () => {
1741
- return h("box", { style: { flex_direction: "column" } }, [h("text", { key: "message" }, props.message), h("box", {
1742
- key: "buttons",
1743
- style: {
1744
- flex_direction: "row",
1745
- gap: 2,
1746
- margin_top: 1
1747
- }
1748
- }, [h("text", {
1749
- key: "confirm",
1750
- fg: isConfirmSelected.value ? props.selectedFg : props.confirmFg,
1751
- bold: isConfirmSelected.value
1752
- }, `[${props.confirmText}]`), h("text", {
1753
- key: "cancel",
1754
- fg: !isConfirmSelected.value ? props.selectedFg : props.cancelFg,
1755
- bold: !isConfirmSelected.value
1756
- }, `[${props.cancelText}]`)])]);
1757
- };
1758
- }
1759
- });
1760
- //#endregion
1761
- //#region src/components/Form.ts
1762
- /**
1763
- * Form Component - Form container with labels
1764
- */
1765
- const Form = defineComponent({
1766
- name: "Form",
1767
- props: {
1768
- fields: {
1769
- type: Array,
1770
- default: () => []
1771
- },
1772
- labelWidth: {
1773
- type: Number,
1774
- default: 15
1775
- },
1776
- gap: {
1777
- type: Number,
1778
- default: 1
1779
- },
1780
- labelPosition: {
1781
- type: String,
1782
- default: "left"
1783
- },
1784
- labelFg: String,
1785
- requiredIndicator: {
1786
- type: String,
1787
- default: "*"
1788
- },
1789
- hintFg: {
1790
- type: String,
1791
- default: "gray"
1792
- }
1793
- },
1794
- setup(props, { slots }) {
1795
- return () => {
1796
- const children = [];
1797
- props.fields.forEach((field, _index) => {
1798
- const labelContent = [h("text", { fg: props.labelFg }, field.label.padEnd(props.labelWidth))];
1799
- if (field.required) labelContent.push(h("text", { fg: "red" }, props.requiredIndicator));
1800
- const fieldSlot = slots[field.key]?.();
1801
- if (props.labelPosition === "top") children.push(h("box", {
1802
- key: field.key,
1803
- style: {
1804
- flex_direction: "column",
1805
- margin_bottom: props.gap
1806
- }
1807
- }, [
1808
- h("box", { style: { flex_direction: "row" } }, labelContent),
1809
- fieldSlot ? h("box", { style: { margin_top: .5 } }, fieldSlot) : null,
1810
- field.hint ? h("text", {
1811
- fg: props.hintFg,
1812
- dim: true
1813
- }, field.hint) : null
1814
- ].filter(Boolean)));
1815
- else {
1816
- children.push(h("box", {
1817
- key: field.key,
1818
- style: {
1819
- flex_direction: "row",
1820
- align_items: "center",
1821
- margin_bottom: props.gap
1822
- }
1823
- }, [h("box", { style: {
1824
- width: String(props.labelWidth),
1825
- flex_direction: "row"
1826
- } }, labelContent), h("box", { style: { flex_grow: 1 } }, fieldSlot)]));
1827
- if (field.hint) children.push(h("text", {
1828
- key: `hint-${field.key}`,
1829
- fg: props.hintFg,
1830
- dim: true,
1831
- style: {
1832
- margin_left: props.labelWidth,
1833
- margin_bottom: props.gap
1834
- }
1835
- }, field.hint));
1836
- }
1837
- });
1838
- return h("box", { style: { flex_direction: "column" } }, children);
1839
- };
1840
- }
1841
- });
1842
- //#endregion
1843
- //#region src/components/display-primitive-types.ts
1844
- /** Default foreground and background colors for each Badge variant. */
1845
- const badgeVariantColors = {
1846
- default: { fg: "white" },
1847
- success: { fg: "green" },
1848
- warning: { fg: "yellow" },
1849
- error: { fg: "red" },
1850
- info: { fg: "cyan" }
1851
- };
1852
- /** Built-in animation frame sets for Spinner. */
1853
- const spinnerTypes = {
1854
- dots: [
1855
- "⠋",
1856
- "⠙",
1857
- "⠹",
1858
- "⠸",
1859
- "⠼",
1860
- "⠴",
1861
- "⠦",
1862
- "⠧",
1863
- "⠇",
1864
- "⠏"
1865
- ],
1866
- dots2: [
1867
- "⣾",
1868
- "⣽",
1869
- "⣻",
1870
- "⢿",
1871
- "⡿",
1872
- "⣟",
1873
- "⣯",
1874
- "⣷"
1875
- ],
1876
- line: [
1877
- "-",
1878
- "\\",
1879
- "|",
1880
- "/"
1881
- ],
1882
- arc: [
1883
- "◜",
1884
- "◠",
1885
- "◝",
1886
- "◞",
1887
- "◡",
1888
- "◟"
1889
- ],
1890
- circle: [
1891
- "◐",
1892
- "◓",
1893
- "◑",
1894
- "◒"
1895
- ],
1896
- bounce: [
1897
- "⠁",
1898
- "⠂",
1899
- "⠄",
1900
- "⡀",
1901
- "⢀",
1902
- "⠠",
1903
- "⠐",
1904
- "⠈"
1905
- ],
1906
- box: [
1907
- "▖",
1908
- "▘",
1909
- "▝",
1910
- "▗"
1911
- ],
1912
- arrow: [
1913
- "←",
1914
- "↖",
1915
- "↑",
1916
- "↗",
1917
- "→",
1918
- "↘",
1919
- "↓",
1920
- "↙"
1921
- ],
1922
- clock: [
1923
- "🕛",
1924
- "🕐",
1925
- "🕑",
1926
- "🕒",
1927
- "🕓",
1928
- "🕔",
1929
- "🕕",
1930
- "🕖",
1931
- "🕗",
1932
- "🕘",
1933
- "🕙",
1934
- "🕚"
1935
- ],
1936
- moon: [
1937
- "🌑",
1938
- "🌒",
1939
- "🌓",
1940
- "🌔",
1941
- "🌕",
1942
- "🌖",
1943
- "🌗",
1944
- "🌘"
1945
- ],
1946
- earth: [
1947
- "🌍",
1948
- "🌎",
1949
- "🌏"
1950
- ]
1951
- };
1952
- //#endregion
1953
- //#region src/components/FrescoSpinner.vue
1954
- var FrescoSpinner_default = /* @__PURE__ */ defineComponent({
1955
- name: "Spinner",
1956
- __name: "FrescoSpinner",
1957
- props: {
1958
- type: {
1959
- type: null,
1960
- required: false,
1961
- default: "dots"
1962
- },
1963
- frames: {
1964
- type: Array,
1965
- required: false
1966
- },
1967
- interval: {
1968
- type: Number,
1969
- required: false,
1970
- default: 80
1971
- },
1972
- label: {
1973
- type: String,
1974
- required: false
1975
- },
1976
- fg: {
1977
- type: String,
1978
- required: false
1979
- }
1980
- },
1981
- setup(__props) {
1982
- const frameIndex = ref(0);
1983
- const frames = computed(() => {
1984
- const selectedFrames = __props.frames ?? spinnerTypes[__props.type] ?? spinnerTypes.dots;
1985
- return selectedFrames.length > 0 ? selectedFrames : spinnerTypes.dots;
1986
- });
1987
- const content = computed(() => {
1988
- const frame = frames.value[frameIndex.value % frames.value.length];
1989
- return __props.label ? `${frame} ${__props.label}` : frame;
1990
- });
1991
- let timer = null;
1992
- onMounted(() => {
1993
- timer = setInterval(() => {
1994
- frameIndex.value = (frameIndex.value + 1) % frames.value.length;
1995
- }, __props.interval);
1996
- });
1997
- onUnmounted(() => {
1998
- if (timer) clearInterval(timer);
1999
- });
2000
- return (_ctx, _cache) => {
2001
- return openBlock(), createBlock(unref(Text), {
2002
- content: content.value,
2003
- fg: __props.fg
2004
- }, null, 8, ["content", "fg"]);
2005
- };
2006
- }
2007
- });
2008
- //#endregion
2009
- //#region src/components/ProgressBar.ts
2010
- /**
2011
- * ProgressBar Component - Progress indicator
2012
- */
2013
- const ProgressBar = defineComponent({
2014
- name: "ProgressBar",
2015
- props: {
2016
- value: {
2017
- type: Number,
2018
- required: true,
2019
- validator: (v) => v >= 0 && v <= 100
2020
- },
2021
- width: {
2022
- type: Number,
2023
- default: 20
2024
- },
2025
- showLabel: {
2026
- type: Boolean,
2027
- default: true
2028
- },
2029
- labelPosition: {
2030
- type: String,
2031
- default: "right"
2032
- },
2033
- filledChar: {
2034
- type: String,
2035
- default: "█"
2036
- },
2037
- emptyChar: {
2038
- type: String,
2039
- default: "░"
2040
- },
2041
- leftBorder: {
2042
- type: String,
2043
- default: ""
2044
- },
2045
- rightBorder: {
2046
- type: String,
2047
- default: ""
2048
- },
2049
- filledFg: {
2050
- type: String,
2051
- default: "green"
2052
- },
2053
- emptyFg: {
2054
- type: String,
2055
- default: "gray"
2056
- }
2057
- },
2058
- setup(props) {
2059
- const normalizedValue = computed(() => Math.max(0, Math.min(100, props.value)));
2060
- const filledWidth = computed(() => Math.round(normalizedValue.value / 100 * props.width));
2061
- const emptyWidth = computed(() => props.width - filledWidth.value);
2062
- const label = computed(() => `${Math.round(normalizedValue.value)}%`);
2063
- return () => {
2064
- const filled = props.filledChar.repeat(filledWidth.value);
2065
- const empty = props.emptyChar.repeat(emptyWidth.value);
2066
- const barContent = [
2067
- props.leftBorder && h(Text, {}, () => props.leftBorder),
2068
- h(Text, { fg: props.filledFg }, () => filled),
2069
- h(Text, { fg: props.emptyFg }, () => empty),
2070
- props.rightBorder && h(Text, {}, () => props.rightBorder)
2071
- ].filter(Boolean);
2072
- if (!props.showLabel) return h(Box, { flexDirection: "row" }, () => barContent);
2073
- const labelElement = h(Text, { dim: true }, () => label.value);
2074
- switch (props.labelPosition) {
2075
- case "left": return h(Box, {
2076
- flexDirection: "row",
2077
- gap: 1
2078
- }, () => [labelElement, ...barContent]);
2079
- case "inside": return h(Box, {
2080
- flexDirection: "row",
2081
- gap: 1
2082
- }, () => [...barContent, labelElement]);
2083
- default: return h(Box, {
2084
- flexDirection: "row",
2085
- gap: 1
2086
- }, () => [...barContent, labelElement]);
2087
- }
2088
- };
2089
- }
2090
- });
2091
- defineComponent({
2092
- name: "IndeterminateProgressBar",
2093
- props: {
2094
- width: {
2095
- type: Number,
2096
- default: 20
2097
- },
2098
- fg: {
2099
- type: String,
2100
- default: "cyan"
2101
- }
2102
- },
2103
- setup(props) {
2104
- return () => {
2105
- const display = "▓▒░░░░░░░░░░░░░░░░░░".slice(0, props.width);
2106
- return h(Text, { fg: props.fg }, () => display);
2107
- };
2108
- }
2109
- });
2110
- //#endregion
2111
- //#region src/components/presentational-primitive-types.ts
2112
- /** Visual defaults for each alert type. */
2113
- const alertConfigs = {
2114
- info: {
2115
- icon: "ℹ",
2116
- fg: "cyan",
2117
- title: "Info"
2118
- },
2119
- success: {
2120
- icon: "✓",
2121
- fg: "green",
2122
- title: "Success"
2123
- },
2124
- warning: {
2125
- icon: "⚠",
2126
- fg: "yellow",
2127
- title: "Warning"
2128
- },
2129
- error: {
2130
- icon: "✗",
2131
- fg: "red",
2132
- title: "Error"
2133
- }
2134
- };
2135
- /** Foreground colors for avatar statuses. */
2136
- const avatarStatusColors = {
2137
- online: "green",
2138
- offline: "gray",
2139
- away: "yellow",
2140
- busy: "red"
2141
- };
2142
- /** Glyphs for avatar statuses. */
2143
- const avatarStatusIcons = {
2144
- online: "●",
2145
- offline: "○",
2146
- away: "◐",
2147
- busy: "⊘"
2148
- };
2149
- //#endregion
2150
- //#region src/components/FrescoAlert.vue?vue&type=script&setup=true&lang.ts
2151
- const _hoisted_1$5 = ["border", "fg"];
2152
- const _hoisted_2$5 = ["fg"];
2153
- const _hoisted_3$5 = ["fg"];
2154
- //#endregion
2155
- //#region src/components/FrescoAlert.vue
2156
- var FrescoAlert_default = /* @__PURE__ */ defineComponent({
2157
- name: "FrescoAlert",
2158
- __name: "FrescoAlert",
2159
- props: {
2160
- message: {
2161
- type: String,
2162
- required: true
2163
- },
2164
- type: {
2165
- type: String,
2166
- required: false,
2167
- default: "info"
2168
- },
2169
- title: {
2170
- type: String,
2171
- required: false
2172
- },
2173
- showIcon: {
2174
- type: Boolean,
2175
- required: false,
2176
- default: true
2177
- },
2178
- border: {
2179
- type: String,
2180
- required: false,
2181
- default: "rounded"
2182
- }
2183
- },
2184
- setup(__props) {
2185
- const config = computed(() => alertConfigs[__props.type]);
2186
- const heading = computed(() => __props.title ?? config.value.title);
2187
- const iconLabel = computed(() => `${config.value.icon} `);
2188
- const containerStyle = {
2189
- flexDirection: "column",
2190
- padding: 1
2191
- };
2192
- const headerStyle = { flexDirection: "row" };
2193
- const messageStyle = { marginTop: 1 };
2194
- return (_ctx, _cache) => {
2195
- return openBlock(), createElementBlock("div", {
2196
- border: __props.border === "none" ? void 0 : __props.border,
2197
- fg: config.value.fg,
2198
- style: containerStyle
2199
- }, [createElementVNode("div", { style: headerStyle }, [__props.showIcon ? (openBlock(), createElementBlock("text", {
2200
- key: 0,
2201
- fg: config.value.fg
2202
- }, toDisplayString(iconLabel.value), 9, _hoisted_2$5)) : createCommentVNode("v-if", true), createElementVNode("text", {
2203
- fg: config.value.fg,
2204
- bold: true
2205
- }, toDisplayString(heading.value), 9, _hoisted_3$5)]), createElementVNode("text", { style: messageStyle }, toDisplayString(__props.message), 1)], 8, _hoisted_1$5);
2206
- };
2207
- }
2208
- });
2209
- //#endregion
2210
- //#region src/components/FrescoBadge.vue?vue&type=script&setup=true&lang.ts
2211
- const _hoisted_1$4 = ["fg", "bg"];
2212
- const _hoisted_2$4 = ["fg", "bg"];
2213
- const _hoisted_3$4 = ["fg", "bg"];
2214
- //#endregion
2215
- //#region src/components/FrescoBadge.vue
2216
- var FrescoBadge_default = /* @__PURE__ */ defineComponent({
2217
- name: "Badge",
2218
- __name: "FrescoBadge",
2219
- props: {
2220
- label: {
2221
- type: String,
2222
- required: true
2223
- },
2224
- variant: {
2225
- type: String,
2226
- required: false,
2227
- default: "default"
2228
- },
2229
- fg: {
2230
- type: String,
2231
- required: false
2232
- },
2233
- bg: {
2234
- type: String,
2235
- required: false
2236
- },
2237
- border: {
2238
- type: Boolean,
2239
- required: false,
2240
- default: false
2241
- }
2242
- },
2243
- setup(__props) {
2244
- const colors = computed(() => badgeVariantColors[__props.variant]);
2245
- const foreground = computed(() => __props.fg ?? colors.value.fg);
2246
- const background = computed(() => __props.bg ?? colors.value.bg);
2247
- const borderStyle = {
2248
- paddingLeft: 1,
2249
- paddingRight: 1
2250
- };
2251
- return (_ctx, _cache) => {
2252
- return __props.border ? (openBlock(), createElementBlock("div", {
2253
- key: 0,
2254
- border: "single",
2255
- fg: foreground.value,
2256
- bg: background.value,
2257
- style: borderStyle
2258
- }, [createElementVNode("text", {
2259
- fg: foreground.value,
2260
- bg: background.value
2261
- }, toDisplayString(__props.label), 9, _hoisted_2$4)], 8, _hoisted_1$4)) : (openBlock(), createElementBlock("text", {
2262
- key: 1,
2263
- fg: foreground.value,
2264
- bg: background.value,
2265
- bold: true
2266
- }, "[" + toDisplayString(__props.label) + "]", 9, _hoisted_3$4));
2267
- };
2268
- }
2269
- });
2270
- //#endregion
2271
- //#region src/components/Timer.ts
2272
- /**
2273
- * Timer Component - Countdown/stopwatch timer
2274
- */
2275
- const Timer = defineComponent({
2276
- name: "Timer",
2277
- props: {
2278
- mode: {
2279
- type: String,
2280
- default: "stopwatch"
2281
- },
2282
- initialSeconds: {
2283
- type: Number,
2284
- default: 0
2285
- },
2286
- autoStart: {
2287
- type: Boolean,
2288
- default: true
2289
- },
2290
- showHours: {
2291
- type: Boolean,
2292
- default: false
2293
- },
2294
- showMilliseconds: {
2295
- type: Boolean,
2296
- default: false
2297
- },
2298
- fg: {
2299
- type: String,
2300
- default: "white"
2301
- },
2302
- warningFg: {
2303
- type: String,
2304
- default: "yellow"
2305
- },
2306
- dangerFg: {
2307
- type: String,
2308
- default: "red"
2309
- }
2310
- },
2311
- emits: ["tick", "complete"],
2312
- setup(props, { emit, expose }) {
2313
- const elapsed = ref(0);
2314
- const isRunning = ref(false);
2315
- let intervalId = null;
2316
- const totalMs = computed(() => {
2317
- if (props.mode === "countdown") return Math.max(0, props.initialSeconds * 1e3 - elapsed.value);
2318
- return elapsed.value;
2319
- });
2320
- const formatted = computed(() => {
2321
- const ms = totalMs.value;
2322
- const totalSeconds = Math.floor(ms / 1e3);
2323
- const hours = Math.floor(totalSeconds / 3600);
2324
- const minutes = Math.floor(totalSeconds % 3600 / 60);
2325
- const seconds = totalSeconds % 60;
2326
- const milliseconds = Math.floor(ms % 1e3 / 10);
2327
- let result = "";
2328
- if (props.showHours || hours > 0) result += `${String(hours).padStart(2, "0")}:`;
2329
- result += `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
2330
- if (props.showMilliseconds) result += `.${String(milliseconds).padStart(2, "0")}`;
2331
- return result;
2332
- });
2333
- const color = computed(() => {
2334
- if (props.mode === "countdown") {
2335
- const seconds = totalMs.value / 1e3;
2336
- if (seconds <= 5) return props.dangerFg;
2337
- if (seconds <= 10) return props.warningFg;
2338
- }
2339
- return props.fg;
2340
- });
2341
- const start = () => {
2342
- if (isRunning.value) return;
2343
- isRunning.value = true;
2344
- intervalId = setInterval(() => {
2345
- elapsed.value += 100;
2346
- emit("tick", totalMs.value);
2347
- if (props.mode === "countdown" && totalMs.value <= 0) {
2348
- stop();
2349
- emit("complete");
2350
- }
2351
- }, 100);
2352
- };
2353
- const stop = () => {
2354
- isRunning.value = false;
2355
- if (intervalId) {
2356
- clearInterval(intervalId);
2357
- intervalId = null;
2358
- }
2359
- };
2360
- const reset = () => {
2361
- elapsed.value = 0;
2362
- };
2363
- const toggle = () => {
2364
- if (isRunning.value) stop();
2365
- else start();
2366
- };
2367
- expose({
2368
- start,
2369
- stop,
2370
- reset,
2371
- toggle,
2372
- isRunning
2373
- });
2374
- onMounted(() => {
2375
- if (props.autoStart) start();
2376
- });
2377
- onUnmounted(() => {
2378
- stop();
2379
- });
2380
- return () => {
2381
- return h("text", {
2382
- fg: color.value,
2383
- bold: true
2384
- }, formatted.value);
2385
- };
2386
- }
2387
- });
2388
- //#endregion
2389
- //#region src/components/FrescoTooltip.vue?vue&type=script&setup=true&lang.ts
2390
- const _hoisted_1$3 = { key: 0 };
2391
- const _hoisted_2$3 = [
2392
- "border",
2393
- "bg",
2394
- "fg"
2395
- ];
2396
- const _hoisted_3$3 = ["fg", "bg"];
2397
- const _hoisted_4$1 = { key: 1 };
2398
- const _hoisted_5$1 = { key: 1 };
2399
- //#endregion
2400
- //#region src/components/FrescoTooltip.vue
2401
- var FrescoTooltip_default = /* @__PURE__ */ defineComponent({
2402
- name: "FrescoTooltip",
2403
- __name: "FrescoTooltip",
2404
- props: {
2405
- text: {
2406
- type: String,
2407
- required: true
2408
- },
2409
- visible: {
2410
- type: Boolean,
2411
- required: false,
2412
- default: true
2413
- },
2414
- position: {
2415
- type: String,
2416
- required: false,
2417
- default: "top"
2418
- },
2419
- border: {
2420
- type: String,
2421
- required: false,
2422
- default: "rounded"
2423
- },
2424
- bg: {
2425
- type: String,
2426
- required: false,
2427
- default: "white"
2428
- },
2429
- fg: {
2430
- type: String,
2431
- required: false,
2432
- default: "black"
2433
- }
2434
- },
2435
- setup(__props) {
2436
- const containerStyle = computed(() => ({ flexDirection: __props.position === "left" || __props.position === "right" ? "row" : "column" }));
2437
- const tooltipStyle = {
2438
- paddingLeft: 1,
2439
- paddingRight: 1
2440
- };
2441
- const contentComesFirst = computed(() => __props.position === "bottom" || __props.position === "right");
2442
- return (_ctx, _cache) => {
2443
- return __props.visible ? (openBlock(), createElementBlock("div", {
2444
- key: 0,
2445
- style: normalizeStyle(containerStyle.value)
2446
- }, [
2447
- contentComesFirst.value ? (openBlock(), createElementBlock("div", _hoisted_1$3, [renderSlot(_ctx.$slots, "default")])) : createCommentVNode("v-if", true),
2448
- createElementVNode("div", {
2449
- border: __props.border === "none" ? void 0 : __props.border,
2450
- bg: __props.bg,
2451
- fg: __props.fg,
2452
- style: tooltipStyle
2453
- }, [createElementVNode("text", {
2454
- fg: __props.fg,
2455
- bg: __props.bg
2456
- }, toDisplayString(__props.text), 9, _hoisted_3$3)], 8, _hoisted_2$3),
2457
- !contentComesFirst.value ? (openBlock(), createElementBlock("div", _hoisted_4$1, [renderSlot(_ctx.$slots, "default")])) : createCommentVNode("v-if", true)
2458
- ], 4)) : (openBlock(), createElementBlock("div", _hoisted_5$1, [renderSlot(_ctx.$slots, "default")]));
2459
- };
2460
- }
2461
- });
2462
- //#endregion
2463
- //#region src/components/List.ts
2464
- /**
2465
- * List Component - Scrollable list of items
2466
- */
2467
- const List = defineComponent({
2468
- name: "List",
2469
- props: {
2470
- items: {
2471
- type: Array,
2472
- required: true
2473
- },
2474
- modelValue: String,
2475
- maxHeight: Number,
2476
- focused: {
2477
- type: Boolean,
2478
- default: false
2479
- },
2480
- indicator: {
2481
- type: String,
2482
- default: "> "
2483
- },
2484
- indicatorEmpty: {
2485
- type: String,
2486
- default: " "
2487
- },
2488
- fg: String,
2489
- selectedFg: {
2490
- type: String,
2491
- default: "cyan"
2492
- },
2493
- selectedBg: String
2494
- },
2495
- emits: ["update:modelValue", "select"],
2496
- setup(props, { emit: _emit }) {
2497
- const scrollOffset = ref(0);
2498
- const highlightedIndex = ref(0);
2499
- const visibleItems = computed(() => {
2500
- if (!props.maxHeight) return props.items;
2501
- const start = scrollOffset.value;
2502
- const end = start + props.maxHeight;
2503
- return props.items.slice(start, end);
2504
- });
2505
- const scrollIndicator = computed(() => {
2506
- if (!props.maxHeight || props.items.length <= props.maxHeight) return {
2507
- showUp: false,
2508
- showDown: false
2509
- };
2510
- return {
2511
- showUp: scrollOffset.value > 0,
2512
- showDown: scrollOffset.value + props.maxHeight < props.items.length
2513
- };
2514
- });
2515
- return () => {
2516
- const children = [];
2517
- if (scrollIndicator.value.showUp) children.push(h("text", {
2518
- key: "scroll-up",
2519
- dim: true
2520
- }, " ..."));
2521
- visibleItems.value.forEach((item, visibleIndex) => {
2522
- const isHighlighted = scrollOffset.value + visibleIndex === highlightedIndex.value;
2523
- const isSelected = item.key === props.modelValue;
2524
- const indicator = isHighlighted ? props.indicator : props.indicatorEmpty;
2525
- children.push(h("text", {
2526
- key: item.key,
2527
- fg: isHighlighted ? props.selectedFg : props.fg,
2528
- bg: isHighlighted ? props.selectedBg : void 0,
2529
- dim: item.disabled,
2530
- bold: isSelected
2531
- }, `${indicator}${item.label}`));
2532
- });
2533
- if (scrollIndicator.value.showDown) children.push(h("text", {
2534
- key: "scroll-down",
2535
- dim: true
2536
- }, " ..."));
2537
- return h("box", {
2538
- style: { flex_direction: "column" },
2539
- fg: props.fg
2540
- }, children);
2541
- };
2542
- }
2543
- });
2544
- //#endregion
2545
- //#region src/components/Table.ts
2546
- /**
2547
- * Table Component - Display tabular data
2548
- */
2549
- const Table = defineComponent({
2550
- name: "Table",
2551
- props: {
2552
- columns: {
2553
- type: Array,
2554
- required: true
2555
- },
2556
- data: {
2557
- type: Array,
2558
- required: true
2559
- },
2560
- showHeader: {
2561
- type: Boolean,
2562
- default: true
2563
- },
2564
- border: {
2565
- type: String,
2566
- default: "single"
2567
- },
2568
- headerFg: {
2569
- type: String,
2570
- default: "white"
2571
- },
2572
- headerBg: String,
2573
- rowFg: String,
2574
- stripedBg: String,
2575
- cellPadding: {
2576
- type: Number,
2577
- default: 1
2578
- }
2579
- },
2580
- setup(props) {
2581
- const formatCell = (value, width) => {
2582
- const str = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : value == null ? "" : JSON.stringify(value);
2583
- if (typeof width === "number" && str.length < width) return str.padEnd(width);
2584
- return str;
2585
- };
2586
- return () => {
2587
- const rows = [];
2588
- if (props.showHeader) {
2589
- const headerCells = props.columns.map((col) => h("text", {
2590
- key: col.key,
2591
- bold: true,
2592
- fg: props.headerFg,
2593
- bg: props.headerBg
2594
- }, formatCell(col.header, col.width)));
2595
- rows.push(h("box", {
2596
- key: "header",
2597
- style: {
2598
- flex_direction: "row",
2599
- gap: props.cellPadding
2600
- }
2601
- }, headerCells));
2602
- if (props.border !== "none") {
2603
- const sepChar = props.border === "double" ? "=" : "-";
2604
- const totalWidth = props.columns.reduce((acc, col) => {
2605
- return acc + (typeof col.width === "number" ? col.width : 10) + (props.cellPadding ?? 1);
2606
- }, 0);
2607
- rows.push(h("text", {
2608
- key: "separator",
2609
- dim: true
2610
- }, sepChar.repeat(totalWidth)));
2611
- }
2612
- }
2613
- props.data.forEach((row, rowIndex) => {
2614
- const cells = props.columns.map((col) => h("text", {
2615
- key: col.key,
2616
- fg: props.rowFg,
2617
- bg: rowIndex % 2 === 1 ? props.stripedBg : void 0
2618
- }, formatCell(row[col.key], col.width)));
2619
- rows.push(h("box", {
2620
- key: `row-${rowIndex}`,
2621
- style: {
2622
- flex_direction: "row",
2623
- gap: props.cellPadding
2624
- }
2625
- }, cells));
2626
- });
2627
- return h("box", {
2628
- style: { flex_direction: "column" },
2629
- border: props.border
2630
- }, rows);
2631
- };
2632
- }
2633
- });
2634
- //#endregion
2635
- //#region src/components/Tree.ts
2636
- /**
2637
- * Tree Component - Tree view for hierarchical data
2638
- */
2639
- const Tree = defineComponent({
2640
- name: "Tree",
2641
- props: {
2642
- data: {
2643
- type: Array,
2644
- required: true
2645
- },
2646
- expanded: {
2647
- type: Array,
2648
- default: () => []
2649
- },
2650
- selected: String,
2651
- showLines: {
2652
- type: Boolean,
2653
- default: true
2654
- },
2655
- indent: {
2656
- type: Number,
2657
- default: 2
2658
- },
2659
- expandedIcon: {
2660
- type: String,
2661
- default: "▼"
2662
- },
2663
- collapsedIcon: {
2664
- type: String,
2665
- default: "▶"
2666
- },
2667
- leafIcon: {
2668
- type: String,
2669
- default: "•"
2670
- },
2671
- fg: String,
2672
- selectedFg: {
2673
- type: String,
2674
- default: "cyan"
2675
- }
2676
- },
2677
- emits: ["select", "toggle"],
2678
- setup(props, { emit: _emit }) {
2679
- const renderNode = (node, depth, isLast, prefix) => {
2680
- const nodes = [];
2681
- const hasChildren = node.children && node.children.length > 0;
2682
- const isExpanded = props.expanded?.includes(node.key);
2683
- const isSelected = node.key === props.selected;
2684
- let linePrefix = prefix;
2685
- if (props.showLines && depth > 0) linePrefix += isLast ? "└─" : "├─";
2686
- let icon = props.leafIcon;
2687
- if (hasChildren) icon = isExpanded ? props.expandedIcon : props.collapsedIcon;
2688
- if (node.icon) icon = node.icon;
2689
- nodes.push(h("text", {
2690
- key: node.key,
2691
- fg: isSelected ? props.selectedFg : props.fg,
2692
- bold: isSelected,
2693
- dim: node.disabled
2694
- }, `${linePrefix}${icon} ${node.label}`));
2695
- if (hasChildren && isExpanded) {
2696
- const childPrefix = prefix + (props.showLines && depth > 0 ? isLast ? " " : "│ " : "");
2697
- node.children.forEach((child, index) => {
2698
- const childIsLast = index === node.children.length - 1;
2699
- nodes.push(...renderNode(child, depth + 1, childIsLast, childPrefix + " ".repeat(props.indent)));
2700
- });
2701
- }
2702
- return nodes;
2703
- };
2704
- return () => {
2705
- const children = [];
2706
- props.data.forEach((node, index) => {
2707
- const isLast = index === props.data.length - 1;
2708
- children.push(...renderNode(node, 0, isLast, ""));
2709
- });
2710
- return h("box", { style: { flex_direction: "column" } }, children);
2711
- };
2712
- }
2713
- });
2714
- //#endregion
2715
- //#region src/components/Menu.ts
2716
- /**
2717
- * Menu Component - Command menu/palette
2718
- */
2719
- const Menu = defineComponent({
2720
- name: "Menu",
2721
- props: {
2722
- items: {
2723
- type: Array,
2724
- required: true
2725
- },
2726
- focusedIndex: {
2727
- type: Number,
2728
- default: 0
2729
- },
2730
- border: {
2731
- type: String,
2732
- default: "single"
2733
- },
2734
- width: Number,
2735
- fg: String,
2736
- focusedFg: {
2737
- type: String,
2738
- default: "black"
2739
- },
2740
- focusedBg: {
2741
- type: String,
2742
- default: "cyan"
2743
- },
2744
- shortcutFg: {
2745
- type: String,
2746
- default: "gray"
2747
- }
2748
- },
2749
- emits: ["select"],
2750
- setup(props, { emit: _emit }) {
2751
- return () => {
2752
- const children = [];
2753
- props.items.forEach((item, index) => {
2754
- if (item.separator) {
2755
- children.push(h("text", {
2756
- key: `sep-${index}`,
2757
- dim: true
2758
- }, "─".repeat(props.width ?? 20)));
2759
- return;
2760
- }
2761
- const isFocused = index === props.focusedIndex;
2762
- const itemContent = [];
2763
- if (item.icon) itemContent.push(h("text", { key: "icon" }, `${item.icon} `));
2764
- itemContent.push(h("text", {
2765
- key: "label",
2766
- fg: isFocused ? props.focusedFg : props.fg,
2767
- bg: isFocused ? props.focusedBg : void 0,
2768
- dim: item.disabled,
2769
- style: { flex_grow: 1 }
2770
- }, item.label));
2771
- if (item.shortcut) itemContent.push(h("text", {
2772
- key: "shortcut",
2773
- fg: props.shortcutFg,
2774
- dim: true
2775
- }, ` ${item.shortcut}`));
2776
- children.push(h("box", {
2777
- key: item.key,
2778
- style: {
2779
- flex_direction: "row",
2780
- padding_left: 1,
2781
- padding_right: 1
2782
- },
2783
- bg: isFocused ? props.focusedBg : void 0
2784
- }, itemContent));
2785
- });
2786
- return h("box", {
2787
- border: props.border === "none" ? void 0 : props.border,
2788
- style: {
2789
- flex_direction: "column",
2790
- width: props.width ? String(props.width) : void 0
2791
- }
2792
- }, children);
2793
- };
2794
- }
2795
- });
2796
- //#endregion
2797
- //#region src/components/Tabs.ts
2798
- /**
2799
- * Tabs Component - Tab navigation
2800
- */
2801
- const Tabs = defineComponent({
2802
- name: "Tabs",
2803
- props: {
2804
- tabs: {
2805
- type: Array,
2806
- required: true
2807
- },
2808
- modelValue: String,
2809
- position: {
2810
- type: String,
2811
- default: "top"
2812
- },
2813
- separator: {
2814
- type: String,
2815
- default: " | "
2816
- },
2817
- activeFg: {
2818
- type: String,
2819
- default: "cyan"
2820
- },
2821
- activeBg: String,
2822
- inactiveFg: String,
2823
- underline: {
2824
- type: Boolean,
2825
- default: true
2826
- }
2827
- },
2828
- emits: ["update:modelValue", "change"],
2829
- setup(props, { slots, emit: _emit }) {
2830
- return () => {
2831
- const tabItems = [];
2832
- props.tabs.forEach((tab, index) => {
2833
- if (index > 0) tabItems.push(h("text", {
2834
- key: `sep-${index}`,
2835
- dim: true
2836
- }, props.separator));
2837
- const isActive = tab.key === props.modelValue;
2838
- tabItems.push(h("text", {
2839
- key: tab.key,
2840
- fg: isActive ? props.activeFg : props.inactiveFg,
2841
- bg: isActive ? props.activeBg : void 0,
2842
- bold: isActive,
2843
- underline: isActive && props.underline,
2844
- dim: tab.disabled
2845
- }, tab.label));
2846
- });
2847
- const tabBar = h("box", {
2848
- key: "tab-bar",
2849
- style: {
2850
- flex_direction: "row",
2851
- padding_bottom: props.position === "top" ? 1 : 0,
2852
- padding_top: props.position === "bottom" ? 1 : 0
2853
- }
2854
- }, tabItems);
2855
- const content = h("box", {
2856
- key: "content",
2857
- style: { flex_grow: 1 }
2858
- }, slots.default?.());
2859
- return h("box", { style: {
2860
- flex_direction: "column",
2861
- flex_grow: 1
2862
- } }, props.position === "top" ? [tabBar, content] : [content, tabBar]);
2863
- };
2864
- }
2865
- });
2866
- //#endregion
2867
- //#region src/components/FrescoBreadcrumb.vue?vue&type=script&setup=true&lang.ts
2868
- const _hoisted_1$2 = ["fg"];
2869
- const _hoisted_2$2 = [
2870
- "fg",
2871
- "bold",
2872
- "underline"
2873
- ];
2874
- const _hoisted_3$2 = ["fg"];
2875
- //#endregion
2876
- //#region src/components/FrescoBreadcrumb.vue
2877
- var FrescoBreadcrumb_default = /* @__PURE__ */ defineComponent({
2878
- name: "FrescoBreadcrumb",
2879
- __name: "FrescoBreadcrumb",
2880
- props: {
2881
- items: {
2882
- type: Array,
2883
- required: true
2884
- },
2885
- separator: {
2886
- type: String,
2887
- required: false,
2888
- default: " > "
2889
- },
2890
- fg: {
2891
- type: String,
2892
- required: false,
2893
- default: "gray"
2894
- },
2895
- activeFg: {
2896
- type: String,
2897
- required: false,
2898
- default: "white"
2899
- },
2900
- separatorFg: {
2901
- type: String,
2902
- required: false,
2903
- default: "gray"
2904
- }
2905
- },
2906
- emits: ["select"],
2907
- setup(__props) {
2908
- const rowStyle = { flexDirection: "row" };
2909
- const iconLabel = (item) => item.icon ? `${item.icon} ` : "";
2910
- return (_ctx, _cache) => {
2911
- return openBlock(), createElementBlock("div", { style: rowStyle }, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, index) => {
2912
- return openBlock(), createElementBlock(Fragment, { key: item.key }, [
2913
- item.icon ? (openBlock(), createElementBlock("text", {
2914
- key: 0,
2915
- fg: index === __props.items.length - 1 ? __props.activeFg : __props.fg
2916
- }, toDisplayString(iconLabel(item)), 9, _hoisted_1$2)) : createCommentVNode("v-if", true),
2917
- createElementVNode("text", {
2918
- fg: index === __props.items.length - 1 ? __props.activeFg : __props.fg,
2919
- bold: index === __props.items.length - 1,
2920
- underline: index !== __props.items.length - 1
2921
- }, toDisplayString(item.label), 9, _hoisted_2$2),
2922
- index !== __props.items.length - 1 ? (openBlock(), createElementBlock("text", {
2923
- key: 1,
2924
- fg: __props.separatorFg
2925
- }, toDisplayString(__props.separator), 9, _hoisted_3$2)) : createCommentVNode("v-if", true)
2926
- ], 64);
2927
- }), 128))]);
2928
- };
2929
- }
2930
- });
2931
- //#endregion
2932
- //#region src/components/Stepper.ts
2933
- /**
2934
- * Stepper Component - Step indicator for wizards
2935
- */
2936
- const Stepper = defineComponent({
2937
- name: "Stepper",
2938
- props: {
2939
- steps: {
2940
- type: Array,
2941
- required: true
2942
- },
2943
- current: {
2944
- type: Number,
2945
- default: 0
2946
- },
2947
- completed: {
2948
- type: Array,
2949
- default: () => []
2950
- },
2951
- errors: {
2952
- type: Array,
2953
- default: () => []
2954
- },
2955
- direction: {
2956
- type: String,
2957
- default: "horizontal"
2958
- },
2959
- showNumbers: {
2960
- type: Boolean,
2961
- default: true
2962
- },
2963
- completedIcon: {
2964
- type: String,
2965
- default: "✓"
2966
- },
2967
- errorIcon: {
2968
- type: String,
2969
- default: "✗"
2970
- },
2971
- currentIcon: {
2972
- type: String,
2973
- default: "●"
2974
- },
2975
- pendingIcon: {
2976
- type: String,
2977
- default: "○"
2978
- }
2979
- },
2980
- setup(props) {
2981
- const getStatus = (index) => {
2982
- if (props.errors?.includes(index)) return "error";
2983
- if (props.completed?.includes(index)) return "completed";
2984
- if (index === props.current) return "current";
2985
- return "pending";
2986
- };
2987
- const getIcon = (index, status) => {
2988
- if (props.showNumbers && status === "pending") return String(index + 1);
2989
- switch (status) {
2990
- case "completed": return props.completedIcon;
2991
- case "error": return props.errorIcon;
2992
- case "current": return props.currentIcon;
2993
- default: return props.pendingIcon;
2994
- }
2995
- };
2996
- const getColor = (status) => {
2997
- switch (status) {
2998
- case "completed": return "green";
2999
- case "error": return "red";
3000
- case "current": return "cyan";
3001
- default: return "gray";
3002
- }
3003
- };
3004
- return () => {
3005
- const isHorizontal = props.direction === "horizontal";
3006
- const connector = isHorizontal ? "───" : "│";
3007
- const children = props.steps.flatMap((step, index) => {
3008
- const status = getStatus(index);
3009
- const icon = getIcon(index, status);
3010
- const color = getColor(status);
3011
- const isLast = index === props.steps.length - 1;
3012
- const stepContent = [h("box", {
3013
- key: `step-${step.key}`,
3014
- style: {
3015
- flex_direction: isHorizontal ? "column" : "row",
3016
- align_items: "center"
3017
- }
3018
- }, [h("text", {
3019
- fg: color,
3020
- bold: status === "current"
3021
- }, `[${icon}]`), h("text", {
3022
- fg: status === "current" ? "white" : "gray",
3023
- bold: status === "current",
3024
- style: isHorizontal ? { margin_top: .5 } : { margin_left: 1 }
3025
- }, step.label)])];
3026
- if (!isLast) stepContent.push(h("text", {
3027
- key: `connector-${index}`,
3028
- dim: true,
3029
- style: isHorizontal ? {
3030
- margin_left: 1,
3031
- margin_right: 1
3032
- } : {
3033
- margin_top: .5,
3034
- margin_bottom: .5,
3035
- margin_left: 1
3036
- }
3037
- }, connector));
3038
- return stepContent;
3039
- });
3040
- return h("box", { style: {
3041
- flex_direction: isHorizontal ? "row" : "column",
3042
- align_items: isHorizontal ? "flex-start" : "stretch"
3043
- } }, children);
3044
- };
3045
- }
3046
- });
3047
- //#endregion
3048
- //#region src/components/Modal.ts
3049
- /**
3050
- * Modal Component - Overlay dialog
3051
- */
3052
- const Modal = defineComponent({
3053
- name: "Modal",
3054
- props: {
3055
- visible: {
3056
- type: Boolean,
3057
- default: true
3058
- },
3059
- title: String,
3060
- width: {
3061
- type: [Number, String],
3062
- default: "50%"
3063
- },
3064
- height: {
3065
- type: [Number, String],
3066
- default: "auto"
3067
- },
3068
- border: {
3069
- type: String,
3070
- default: "rounded"
3071
- },
3072
- titleFg: {
3073
- type: String,
3074
- default: "white"
3075
- },
3076
- borderFg: String,
3077
- bg: String
3078
- },
3079
- emits: ["close"],
3080
- setup(props, { slots, emit: _emit }) {
3081
- return () => {
3082
- if (!props.visible) return null;
3083
- const children = [];
3084
- if (props.title) children.push(h("box", {
3085
- key: "title",
3086
- style: {
3087
- flex_direction: "row",
3088
- justify_content: "center",
3089
- padding_bottom: 1
3090
- }
3091
- }, [h("text", {
3092
- bold: true,
3093
- fg: props.titleFg
3094
- }, props.title)]));
3095
- children.push(h("box", {
3096
- key: "content",
3097
- style: { flex_grow: 1 }
3098
- }, slots.default?.()));
3099
- return h("box", { style: {
3100
- justify_content: "center",
3101
- align_items: "center",
3102
- width: "100%",
3103
- height: "100%"
3104
- } }, [h("box", {
3105
- style: {
3106
- flex_direction: "column",
3107
- width: String(props.width),
3108
- height: String(props.height),
3109
- padding: 1
3110
- },
3111
- border: props.border,
3112
- fg: props.borderFg,
3113
- bg: props.bg
3114
- }, children)]);
3115
- };
3116
- }
3117
- });
3118
- //#endregion
3119
- //#region src/components/StatusBar.ts
3120
- /**
3121
- * StatusBar Component - Status bar (typically at bottom of screen)
3122
- */
3123
- const StatusBar = defineComponent({
3124
- name: "StatusBar",
3125
- props: {
3126
- items: {
3127
- type: Array,
3128
- required: true
3129
- },
3130
- bg: {
3131
- type: String,
3132
- default: "blue"
3133
- },
3134
- fg: {
3135
- type: String,
3136
- default: "white"
3137
- },
3138
- separator: {
3139
- type: String,
3140
- default: " │ "
3141
- }
3142
- },
3143
- setup(props) {
3144
- return () => {
3145
- const leftItems = props.items.filter((item) => item.align !== "right");
3146
- const rightItems = props.items.filter((item) => item.align === "right");
3147
- const renderItems = (items) => {
3148
- const result = [];
3149
- items.forEach((item, index) => {
3150
- if (index > 0) result.push(h("text", {
3151
- key: `sep-${item.key}`,
3152
- fg: props.fg,
3153
- bg: props.bg,
3154
- dim: true
3155
- }, props.separator));
3156
- result.push(h("text", {
3157
- key: item.key,
3158
- fg: item.fg ?? props.fg,
3159
- bg: item.bg ?? props.bg,
3160
- bold: item.bold
3161
- }, item.content));
3162
- });
3163
- return result;
3164
- };
3165
- return h("box", {
3166
- bg: props.bg,
3167
- style: {
3168
- flex_direction: "row",
3169
- justify_content: "space-between",
3170
- width: "100%",
3171
- padding_left: 1,
3172
- padding_right: 1
3173
- }
3174
- }, [h("box", {
3175
- key: "left",
3176
- style: { flex_direction: "row" }
3177
- }, renderItems(leftItems)), h("box", {
3178
- key: "right",
3179
- style: { flex_direction: "row" }
3180
- }, renderItems(rightItems))]);
3181
- };
3182
- }
3183
- });
3184
- //#endregion
3185
- //#region src/components/FrescoHeader.vue?vue&type=script&setup=true&lang.ts
3186
- const _hoisted_1$1 = ["bg"];
3187
- const _hoisted_2$1 = { key: 0 };
3188
- const _hoisted_3$1 = ["fg"];
3189
- const _hoisted_4 = ["fg"];
3190
- const _hoisted_5 = { key: 0 };
3191
- const _hoisted_6 = {
3192
- key: 0,
3193
- dim: true
3194
- };
3195
- //#endregion
3196
- //#region src/components/FrescoHeader.vue
3197
- var FrescoHeader_default = /* @__PURE__ */ defineComponent({
3198
- name: "FrescoHeader",
3199
- __name: "FrescoHeader",
3200
- props: {
3201
- title: {
3202
- type: String,
3203
- required: true
3204
- },
3205
- subtitle: {
3206
- type: String,
3207
- required: false
3208
- },
3209
- left: {
3210
- type: String,
3211
- required: false
3212
- },
3213
- right: {
3214
- type: String,
3215
- required: false
3216
- },
3217
- bg: {
3218
- type: String,
3219
- required: false
3220
- },
3221
- titleFg: {
3222
- type: String,
3223
- required: false,
3224
- default: "white"
3225
- },
3226
- subtitleFg: {
3227
- type: String,
3228
- required: false,
3229
- default: "gray"
3230
- },
3231
- borderBottom: {
3232
- type: Boolean,
3233
- required: false,
3234
- default: false
3235
- }
3236
- },
3237
- setup(__props) {
3238
- const rootStyle = { flexDirection: "column" };
3239
- const contentStyle = {
3240
- flexDirection: "row",
3241
- justifyContent: "space-between",
3242
- alignItems: "center",
3243
- width: "100%",
3244
- padding: 1
3245
- };
3246
- const rowStyle = { flexDirection: "row" };
3247
- const borderLabel = "─".repeat(80);
3248
- return (_ctx, _cache) => {
3249
- return openBlock(), createElementBlock("div", { style: rootStyle }, [createElementVNode("div", {
3250
- bg: __props.bg,
3251
- style: contentStyle
3252
- }, [
3253
- createElementVNode("div", { style: rowStyle }, [renderSlot(_ctx.$slots, "left", {}, () => [__props.left ? (openBlock(), createElementBlock("text", _hoisted_2$1, toDisplayString(__props.left), 1)) : createCommentVNode("v-if", true)])]),
3254
- createElementVNode("div", { style: rowStyle }, [createElementVNode("text", {
3255
- fg: __props.titleFg,
3256
- bold: true
3257
- }, toDisplayString(__props.title), 9, _hoisted_3$1), __props.subtitle ? (openBlock(), createElementBlock("text", {
3258
- key: 0,
3259
- fg: __props.subtitleFg,
3260
- dim: true
3261
- }, " - " + toDisplayString(__props.subtitle), 9, _hoisted_4)) : createCommentVNode("v-if", true)]),
3262
- createElementVNode("div", { style: rowStyle }, [renderSlot(_ctx.$slots, "right", {}, () => [__props.right ? (openBlock(), createElementBlock("text", _hoisted_5, toDisplayString(__props.right), 1)) : createCommentVNode("v-if", true)])])
3263
- ], 8, _hoisted_1$1), __props.borderBottom ? (openBlock(), createElementBlock("text", _hoisted_6, toDisplayString(unref(borderLabel)), 1)) : createCommentVNode("v-if", true)]);
3264
- };
3265
- }
3266
- });
3267
- //#endregion
3268
- //#region src/components/KeyHint.ts
3269
- /**
3270
- * KeyHint Component - Display keyboard shortcut hints
3271
- */
3272
- const KeyHint = defineComponent({
3273
- name: "KeyHint",
3274
- props: {
3275
- bindings: {
3276
- type: Array,
3277
- required: true
3278
- },
3279
- direction: {
3280
- type: String,
3281
- default: "horizontal"
3282
- },
3283
- keyFg: {
3284
- type: String,
3285
- default: "black"
3286
- },
3287
- keyBg: {
3288
- type: String,
3289
- default: "white"
3290
- },
3291
- descFg: {
3292
- type: String,
3293
- default: "gray"
3294
- },
3295
- separator: {
3296
- type: String,
3297
- default: " "
3298
- }
3299
- },
3300
- setup(props) {
3301
- return () => {
3302
- const children = props.bindings.map((binding, index) => {
3303
- const keyParts = binding.keys.map((key, keyIndex) => [h("text", {
3304
- key: `key-${keyIndex}`,
3305
- fg: props.keyFg,
3306
- bg: props.keyBg,
3307
- bold: true
3308
- }, ` ${key} `), keyIndex < binding.keys.length - 1 ? h("text", { key: `plus-${keyIndex}` }, "+") : null]).flat().filter(Boolean);
3309
- return h("box", {
3310
- key: `binding-${index}`,
3311
- style: {
3312
- flex_direction: "row",
3313
- margin_right: props.direction === "horizontal" ? 2 : 0
3314
- }
3315
- }, [
3316
- ...keyParts,
3317
- h("text", {}, props.separator),
3318
- h("text", { fg: props.descFg }, binding.description)
3319
- ]);
3320
- });
3321
- return h("box", { style: {
3322
- flex_direction: props.direction === "horizontal" ? "row" : "column",
3323
- flex_wrap: "wrap"
3324
- } }, children);
3325
- };
3326
- }
3327
- });
3328
- //#endregion
3329
- //#region src/components/FrescoAvatar.vue?vue&type=script&setup=true&lang.ts
3330
- const _hoisted_1 = ["border", "bg"];
3331
- const _hoisted_2 = ["fg", "bg"];
3332
- const _hoisted_3 = ["fg"];
3333
- //#endregion
3334
- //#region src/components/FrescoAvatar.vue
3335
- var FrescoAvatar_default = /* @__PURE__ */ defineComponent({
3336
- name: "FrescoAvatar",
3337
- __name: "FrescoAvatar",
3338
- props: {
3339
- name: {
3340
- type: String,
3341
- required: false
3342
- },
3343
- initials: {
3344
- type: String,
3345
- required: false
3346
- },
3347
- size: {
3348
- type: String,
3349
- required: false,
3350
- default: "md"
3351
- },
3352
- bg: {
3353
- type: String,
3354
- required: false,
3355
- default: "blue"
3356
- },
3357
- fg: {
3358
- type: String,
3359
- required: false,
3360
- default: "white"
3361
- },
3362
- border: {
3363
- type: Boolean,
3364
- required: false,
3365
- default: true
3366
- },
3367
- status: {
3368
- type: String,
3369
- required: false
3370
- }
3371
- },
3372
- setup(__props) {
3373
- const takeCodePoints = (value, count) => Array.from(value).slice(0, count).join("");
3374
- const displayInitials = computed(() => {
3375
- if (__props.initials) return __props.initials;
3376
- const parts = __props.name?.split(" ").filter(Boolean) ?? [];
3377
- if (parts.length >= 2) return `${takeCodePoints(parts[0], 1)}${takeCodePoints(parts[1], 1)}`.toUpperCase();
3378
- if (parts.length === 1) return takeCodePoints(parts[0], 2).toUpperCase();
3379
- return "??";
3380
- });
3381
- const padding = computed(() => __props.size === "lg" ? 1 : 0);
3382
- const containerStyle = computed(() => ({
3383
- flexDirection: "row",
3384
- paddingLeft: padding.value,
3385
- paddingRight: padding.value
3386
- }));
3387
- return (_ctx, _cache) => {
3388
- return openBlock(), createElementBlock("div", {
3389
- border: __props.border ? "rounded" : void 0,
3390
- bg: __props.bg,
3391
- style: normalizeStyle(containerStyle.value)
3392
- }, [createElementVNode("text", {
3393
- fg: __props.fg,
3394
- bg: __props.bg,
3395
- bold: true
3396
- }, toDisplayString(displayInitials.value), 9, _hoisted_2), __props.status ? (openBlock(), createElementBlock("text", {
3397
- key: 0,
3398
- fg: unref(avatarStatusColors)[__props.status]
3399
- }, toDisplayString(unref(avatarStatusIcons)[__props.status]), 9, _hoisted_3)) : createCommentVNode("v-if", true)], 12, _hoisted_1);
3400
- };
3401
- }
3402
- });
3403
- //#endregion
3404
- export { FrescoNewline_default as A, FrescoSpacer_default as B, Select as C, Code as D, FrescoLink_default as E, Grid as F, FrescoVStack_default as I, FrescoHStack_default as L, ScrollBar_default as M, Text as N, FrescoTransform_default as O, FrescoCard_default as P, FrescoStack_default as R, Checkbox as S, TextInput as T, Box as V, ProgressBar as _, Modal as a, Confirm as b, Tabs as c, Table as d, List as f, FrescoAlert_default as g, FrescoBadge_default as h, StatusBar as i, ScrollBox_default as j, FrescoStatic_default as k, Menu as l, Timer as m, KeyHint as n, Stepper as o, FrescoTooltip_default as p, FrescoHeader_default as r, FrescoBreadcrumb_default as s, FrescoAvatar_default as t, Tree as u, FrescoSpinner_default as v, TextArea as w, RadioGroup as x, Form as y, FrescoDivider_default as z };
3405
-
3406
- //# sourceMappingURL=components-C57eT1BL.mjs.map