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