vuetty 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,15 @@
1
+ <p align="center">
2
+ <a href="https://tterrasson.github.io/vuetty/" target="_blank" rel="noopener noreferrer">
3
+ <img src="docs/public/images/logo.webp" alt="Vuetty Logo" width="300" />
4
+ </a>
5
+ </p>
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/vuetty">
8
+ <img src="https://img.shields.io/npm/v/vuetty?logo=npm&style=plastic" alt="npm package">
9
+ </a>
10
+ </p>
11
+ <br/>
12
+
1
13
  # Vuetty
2
14
 
3
15
  A Vue.js custom renderer for building Terminal User Interfaces (TUIs). Vuetty brings Vue's reactive system and component model to the terminal, allowing you to build interactive command-line applications using familiar Vue.js syntax.
@@ -1 +1,11 @@
1
- export {};
1
+ /**
2
+ * Bun plugin for .vue files - for development/examples only
3
+ * Users should use the Rollup plugin for production builds
4
+ */
5
+
6
+ export interface CompileResult {
7
+ code: string;
8
+ errors: Array<{ message: string }>;
9
+ }
10
+
11
+ export function compileSFC(source: string, path: string): CompileResult;
@@ -5,14 +5,13 @@
5
5
  */
6
6
  import { plugin } from 'bun';
7
7
  import { compileSFC } from './compiler-core.js';
8
- import { readFileSync } from 'node:fs';
9
8
 
10
9
  plugin({
11
10
  name: 'vuetty-bun-loader',
12
11
 
13
12
  setup(build) {
14
13
  build.onLoad({ filter: /\.vue$/ }, async ({ path }) => {
15
- const source = readFileSync(path, 'utf-8');
14
+ const source = await Bun.file(path).text();
16
15
  const { code, errors } = compileSFC(source, path);
17
16
 
18
17
  if (errors.length > 0) {
package/dist/index.d.ts CHANGED
@@ -1,11 +1,50 @@
1
- import type { Component, DefineComponent } from "vue";
1
+ import type { Component, DefineComponent, ComputedRef } from "vue";
2
+
3
+ // ============================================================================
4
+ // Core Options and Classes
5
+ // ============================================================================
6
+
7
+ export interface CacheOptions {
8
+ layout?: {
9
+ textMeasurement?: number;
10
+ metricsPerNode?: number;
11
+ };
12
+ line?: {
13
+ width?: number;
14
+ truncateBuckets?: number;
15
+ truncatePerBucket?: number;
16
+ };
17
+ effects?: {
18
+ results?: number;
19
+ parsedColors?: number;
20
+ colorArrays?: number;
21
+ };
22
+ components?: {
23
+ markdown?: {
24
+ tokens?: number;
25
+ maxTokens?: number;
26
+ styles?: number;
27
+ };
28
+ bigText?: {
29
+ figlet?: number;
30
+ final?: number;
31
+ };
32
+ image?: {
33
+ rendered?: number;
34
+ };
35
+ box?: {
36
+ bufferPool?: number;
37
+ };
38
+ };
39
+ }
2
40
 
3
41
  export interface VuettyOptions {
4
- theme?: Record<string, any>;
42
+ theme?: Partial<Theme>;
5
43
  debugServer?: boolean | Record<string, any>;
6
44
  viewport?: Record<string, any>;
7
45
  forceColors?: boolean;
8
46
  scrollIndicatorMode?: string;
47
+ cache?: CacheOptions;
9
48
  [key: string]: any;
10
49
  }
11
50
 
@@ -27,26 +66,478 @@ export class CommentNode extends TUINode {}
27
66
  export function createTUIRenderer(options?: Record<string, any>): any;
28
67
  export function renderToString(root: any): string;
29
68
 
30
- export const Box: DefineComponent<any, any, any>;
31
- export const TextBox: DefineComponent<any, any, any>;
32
- export const Row: DefineComponent<any, any, any>;
33
- export const Col: DefineComponent<any, any, any>;
34
- export const Divider: DefineComponent<any, any, any>;
35
- export const Spacer: DefineComponent<any, any, any>;
36
- export const Newline: DefineComponent<any, any, any>;
37
- export const Spinner: DefineComponent<any, any, any>;
38
- export const ProgressBar: DefineComponent<any, any, any>;
39
- export const TextInput: DefineComponent<any, any, any>;
40
- export const SelectInput: DefineComponent<any, any, any>;
41
- export const Checkbox: DefineComponent<any, any, any>;
42
- export const Radiobox: DefineComponent<any, any, any>;
43
- export const Table: DefineComponent<any, any, any>;
44
- export const Markdown: DefineComponent<any, any, any>;
45
- export const Image: DefineComponent<any, any, any>;
46
- export const BigText: DefineComponent<any, any, any>;
47
- export const Gradient: DefineComponent<any, any, any>;
48
- export const Button: DefineComponent<any, any, any>;
49
- export const Tree: DefineComponent<any, any, any>;
69
+ // ============================================================================
70
+ // Color Utilities
71
+ // ============================================================================
72
+
73
+ export interface RGB {
74
+ r: number;
75
+ g: number;
76
+ b: number;
77
+ }
78
+
79
+ export interface HSL {
80
+ h: number;
81
+ s: number;
82
+ l: number;
83
+ }
84
+
85
+ export function parseColor(color: string): RGB | null;
86
+ export function interpolateColor(colors: string[], ratio: number, interpolation?: 'rgb' | 'hsv'): string;
87
+ export function adjustBrightness(color: RGB, factor: number): RGB;
88
+ export function hslToRgb(h: number, s: number, l: number): RGB;
89
+ export function rgbToHex(r: number, g: number, b: number): string;
90
+ export function rgbToHsl(r: number, g: number, b: number): HSL;
91
+
92
+ // ============================================================================
93
+ // Effect Registry
94
+ // ============================================================================
95
+
96
+ export interface EffectFunction {
97
+ (text: string, effectProps: Record<string, any>, frame: number): string;
98
+ }
99
+
100
+ export interface EffectDefinition {
101
+ fn: EffectFunction;
102
+ animated: boolean;
103
+ defaultInterval: number;
104
+ }
105
+
106
+ export const effectRegistry: {
107
+ register(name: string, effectFn: EffectFunction, options?: { animated?: boolean; defaultInterval?: number }): void;
108
+ get(name: string): EffectDefinition | null;
109
+ has(name: string): boolean;
110
+ unregister(name: string): void;
111
+ getAll(): string[];
112
+ };
113
+
114
+ // ============================================================================
115
+ // Theme System
116
+ // ============================================================================
117
+
118
+ export interface ButtonVariantConfig {
119
+ bg: string;
120
+ color: string;
121
+ bold: boolean;
122
+ focusBg?: string;
123
+ }
124
+
125
+ export interface Theme {
126
+ background?: string;
127
+ foreground?: string;
128
+ primary?: string;
129
+ secondary?: string;
130
+ success?: string;
131
+ warning?: string;
132
+ danger?: string;
133
+ info?: string;
134
+ components?: {
135
+ box?: {
136
+ color?: string;
137
+ bg?: string | null;
138
+ };
139
+ textBox?: {
140
+ color?: string;
141
+ bg?: string | null;
142
+ };
143
+ textInput?: {
144
+ color?: string;
145
+ borderColor?: string;
146
+ bg?: string | null;
147
+ focusColor?: string;
148
+ errorColor?: string;
149
+ };
150
+ button?: {
151
+ variants?: {
152
+ primary?: ButtonVariantConfig;
153
+ secondary?: ButtonVariantConfig;
154
+ danger?: ButtonVariantConfig;
155
+ warning?: ButtonVariantConfig;
156
+ info?: ButtonVariantConfig;
157
+ success?: ButtonVariantConfig;
158
+ };
159
+ };
160
+ checkbox?: {
161
+ color?: string;
162
+ checkedColor?: string;
163
+ uncheckedColor?: string;
164
+ };
165
+ radiobox?: {
166
+ color?: string;
167
+ selectedColor?: string;
168
+ unselectedColor?: string;
169
+ };
170
+ tabs?: {
171
+ focusColor?: string;
172
+ activeColor?: string;
173
+ highlightColor?: string;
174
+ };
175
+ };
176
+ [key: string]: any; // Allow custom theme properties
177
+ }
178
+
179
+ export function createTheme(userTheme?: Partial<Theme>): Theme;
180
+ export const DEFAULT_THEME: Theme;
181
+ export function resolveThemeColor(theme: Theme, path: string): string | null;
182
+
183
+ // ============================================================================
184
+ // Layout Prop Interfaces
185
+ // ============================================================================
186
+
187
+ export interface FlexContainerProps {
188
+ justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | null;
189
+ alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | null;
190
+ alignContent?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'space-between' | 'space-around' | null;
191
+ flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse' | null;
192
+ flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse' | null;
193
+ gap?: number | null;
194
+ }
195
+
196
+ export interface FlexItemProps {
197
+ flex?: number | string | null;
198
+ flexGrow?: number | null;
199
+ flexShrink?: number | null;
200
+ flexBasis?: number | string | null;
201
+ alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | null;
202
+ }
203
+
204
+ export interface DimensionProps {
205
+ width?: number | string | null;
206
+ height?: number | string | null;
207
+ minWidth?: number | null;
208
+ maxWidth?: number | null;
209
+ minHeight?: number | null;
210
+ maxHeight?: number | null;
211
+ }
212
+
213
+ export interface PaddingProps {
214
+ padding?: number | null;
215
+ paddingLeft?: number | null;
216
+ paddingRight?: number | null;
217
+ paddingTop?: number | null;
218
+ paddingBottom?: number | null;
219
+ }
220
+
221
+ export interface MarginProps {
222
+ margin?: number | null;
223
+ marginLeft?: number | null;
224
+ marginRight?: number | null;
225
+ marginTop?: number | null;
226
+ marginBottom?: number | null;
227
+ }
228
+
229
+ export type BoxProps = FlexItemProps & DimensionProps & PaddingProps & MarginProps;
230
+ export type LayoutProps = FlexContainerProps & FlexItemProps & DimensionProps & PaddingProps & MarginProps;
231
+
232
+ export interface StyleProps {
233
+ color?: string;
234
+ bg?: string;
235
+ bold?: boolean;
236
+ italic?: boolean;
237
+ underline?: boolean;
238
+ dim?: boolean;
239
+ }
240
+
241
+ // ============================================================================
242
+ // Component Prop Interfaces
243
+ // ============================================================================
244
+
245
+ // Layout Components
246
+ export interface RowProps extends LayoutProps {
247
+ justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
248
+ alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
249
+ flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
250
+ gap?: number;
251
+ responsive?: boolean;
252
+ }
253
+
254
+ export interface ColProps extends LayoutProps {
255
+ flex?: number | string;
256
+ gap?: number;
257
+ justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
258
+ alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
259
+ flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
260
+ responsive?: boolean;
261
+ }
262
+
263
+ // Visual Container Components
264
+ export type BorderStyle =
265
+ | 'rounded'
266
+ | 'square'
267
+ | 'double'
268
+ | 'classic'
269
+ | 'bold'
270
+ | 'dashed'
271
+ | 'sparse'
272
+ | 'light'
273
+ | 'button'
274
+ | {
275
+ topLeft: string;
276
+ topRight: string;
277
+ bottomLeft: string;
278
+ bottomRight: string;
279
+ horizontal: string;
280
+ vertical: string;
281
+ };
282
+
283
+ export interface BoxComponentProps extends BoxProps, StyleProps {
284
+ border?: boolean;
285
+ borderStyle?: BorderStyle;
286
+ title?: string | null;
287
+ titleAlign?: 'left' | 'center' | 'right';
288
+ titlePadding?: number;
289
+ align?: 'left' | 'center' | 'right';
290
+ }
291
+
292
+ export interface TextBoxProps extends BoxProps, StyleProps {
293
+ effect?: string | null;
294
+ effectProps?: Record<string, any> | null;
295
+ animated?: boolean;
296
+ animationInterval?: number | null;
297
+ }
298
+
299
+ // Simple Display Components
300
+ export interface DividerProps extends BoxProps, Pick<StyleProps, 'color'> {
301
+ char?: string;
302
+ length?: number;
303
+ }
304
+
305
+ export interface SpacerProps {
306
+ count?: number;
307
+ }
308
+
309
+ export interface NewlineProps {
310
+ count?: number;
311
+ }
312
+
313
+ // Interactive Input Components
314
+ export interface TextInputProps extends BoxProps, StyleProps {
315
+ modelValue?: string;
316
+ multiline?: boolean;
317
+ rows?: number;
318
+ minRows?: number;
319
+ maxRows?: number;
320
+ autoResize?: boolean;
321
+ wrapLines?: boolean;
322
+ label?: string;
323
+ placeholder?: string;
324
+ hint?: string | boolean;
325
+ borderColor?: string;
326
+ focusColor?: string;
327
+ errorColor?: string;
328
+ pattern?: RegExp;
329
+ required?: boolean;
330
+ maxLength?: number;
331
+ disabled?: boolean;
332
+ readonly?: boolean;
333
+ }
334
+
335
+ export interface ListItem {
336
+ value?: any;
337
+ label?: string;
338
+ disabled?: boolean;
339
+ }
340
+
341
+ export interface SelectInputProps extends BoxProps, Pick<StyleProps, 'color' | 'bg' | 'bold' | 'dim'> {
342
+ modelValue?: any | any[];
343
+ options?: Array<ListItem | string | number>;
344
+ label?: string;
345
+ height?: number;
346
+ marker?: string;
347
+ highlightMarker?: string;
348
+ disabled?: boolean;
349
+ multiple?: boolean;
350
+ focusColor?: string;
351
+ selectedColor?: string;
352
+ highlightColor?: string;
353
+ hint?: string | boolean;
354
+ }
355
+
356
+ export interface ListComponentProps extends BoxProps, Pick<StyleProps, 'color' | 'bg' | 'bold' | 'dim'> {
357
+ items?: Array<ListItem | string | number>;
358
+ label?: string;
359
+ marker?: string;
360
+ highlightedValue?: string | number | object | null;
361
+ highlightColor?: string;
362
+ }
363
+
364
+ export interface CheckboxProps extends BoxProps, Pick<StyleProps, 'color' | 'bg' | 'bold' | 'dim'> {
365
+ modelValue?: any[];
366
+ options?: Array<ListItem | string | number>;
367
+ label?: string;
368
+ direction?: 'vertical' | 'horizontal';
369
+ height?: number;
370
+ itemSpacing?: number;
371
+ disabled?: boolean;
372
+ focusColor?: string;
373
+ selectedColor?: string;
374
+ highlightColor?: string;
375
+ hint?: string | boolean;
376
+ }
377
+
378
+ export interface RadioboxProps extends BoxProps, Pick<StyleProps, 'color' | 'bg' | 'bold' | 'dim'> {
379
+ modelValue?: string | number | object | null;
380
+ options?: Array<ListItem | string | number>;
381
+ label?: string;
382
+ direction?: 'vertical' | 'horizontal';
383
+ height?: number;
384
+ itemSpacing?: number;
385
+ disabled?: boolean;
386
+ focusColor?: string;
387
+ selectedColor?: string;
388
+ highlightColor?: string;
389
+ hint?: string | boolean;
390
+ }
391
+
392
+ export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'warning' | 'info' | 'success';
393
+
394
+ export interface ButtonComponentProps extends BoxProps, Pick<StyleProps, 'bold' | 'italic' | 'dim'> {
395
+ label: string;
396
+ variant?: ButtonVariant;
397
+ color?: string;
398
+ bg?: string;
399
+ disabled?: boolean;
400
+ focusColor?: string;
401
+ focusBg?: string | null;
402
+ fullWidth?: boolean;
403
+ }
404
+
405
+ export interface TabItem {
406
+ value?: any;
407
+ label?: string;
408
+ disabled?: boolean;
409
+ }
410
+
411
+ export interface TabsProps extends BoxProps, Pick<StyleProps, 'color' | 'bg'> {
412
+ modelValue?: string | number | null;
413
+ tabs: Array<TabItem | string | number>;
414
+ disabled?: boolean;
415
+ focusColor?: string;
416
+ activeColor?: string;
417
+ highlightColor?: string;
418
+ panelBorder?: boolean;
419
+ panelBorderStyle?: string;
420
+ panelPadding?: number;
421
+ hint?: string | boolean;
422
+ }
423
+
424
+ export interface TableProps extends BoxProps, Pick<StyleProps, 'color' | 'bg' | 'bold' | 'dim'> {
425
+ modelValue?: number | null;
426
+ headers?: any[];
427
+ rows?: any[][];
428
+ label?: string;
429
+ height?: number;
430
+ columnWidths?: number[] | null;
431
+ striped?: boolean;
432
+ showHeader?: boolean;
433
+ disabled?: boolean;
434
+ focusColor?: string;
435
+ selectedColor?: string;
436
+ highlightColor?: string;
437
+ headerColor?: string;
438
+ stripedColor?: string;
439
+ hint?: string | boolean;
440
+ }
441
+
442
+ // Display Components
443
+ export type SpinnerType = 'dots' | 'line' | 'arc' | 'arrow' | 'bounce' | 'clock' | 'box';
444
+
445
+ export interface SpinnerProps extends BoxProps, StyleProps {
446
+ type?: SpinnerType;
447
+ modelValue?: boolean;
448
+ interval?: number;
449
+ label?: string;
450
+ labelPosition?: 'left' | 'right';
451
+ }
452
+
453
+ export interface ProgressBarProps extends BoxProps, StyleProps {
454
+ value?: number;
455
+ max?: number;
456
+ char?: string;
457
+ emptyChar?: string;
458
+ showPercentage?: boolean;
459
+ label?: string;
460
+ labelPosition?: 'left' | 'right' | 'above' | 'below';
461
+ brackets?: boolean;
462
+ emptyColor?: string;
463
+ percentageColor?: string;
464
+ }
465
+
466
+ export interface GradientProps extends BoxProps {
467
+ name?: string | null;
468
+ colors?: string[] | null;
469
+ interpolation?: 'rgb' | 'hsv';
470
+ }
471
+
472
+ export interface BigTextProps extends BoxProps, StyleProps {
473
+ font?: string;
474
+ horizontalLayout?: string;
475
+ align?: 'left' | 'center' | 'right';
476
+ }
477
+
478
+ export interface TreeNode {
479
+ name: string;
480
+ children?: TreeNode[];
481
+ [key: string]: any;
482
+ }
483
+
484
+ export interface TreeProps extends BoxProps, Pick<StyleProps, 'color' | 'bg'> {
485
+ data?: TreeNode[];
486
+ branchColor?: string;
487
+ folderColor?: string;
488
+ fileColor?: string | null;
489
+ showIcons?: boolean;
490
+ treeStyle?: string | Record<string, string>;
491
+ }
492
+
493
+ export interface MarkdownProps extends BoxProps, StyleProps {
494
+ source?: string;
495
+ codeTheme?: string;
496
+ enableTables?: boolean;
497
+ enableLists?: boolean;
498
+ enableCodeBlocks?: boolean;
499
+ }
500
+
501
+ export interface ImageProps extends BoxProps {
502
+ src: string | Buffer;
503
+ width?: number | string | null;
504
+ height?: number | string | null;
505
+ preserveAspectRatio?: boolean;
506
+ alt?: string;
507
+ errorColor?: string;
508
+ errorBorderStyle?: string;
509
+ }
510
+
511
+ // ============================================================================
512
+ // Component Exports
513
+ // ============================================================================
514
+
515
+ export const Box: DefineComponent<BoxComponentProps>;
516
+ export const TextBox: DefineComponent<TextBoxProps>;
517
+ export const Row: DefineComponent<RowProps>;
518
+ export const Col: DefineComponent<ColProps>;
519
+ export const Divider: DefineComponent<DividerProps>;
520
+ export const Spacer: DefineComponent<SpacerProps>;
521
+ export const Newline: DefineComponent<NewlineProps>;
522
+ export const Spinner: DefineComponent<SpinnerProps>;
523
+ export const ProgressBar: DefineComponent<ProgressBarProps>;
524
+ export const TextInput: DefineComponent<TextInputProps>;
525
+ export const SelectInput: DefineComponent<SelectInputProps>;
526
+ export const Checkbox: DefineComponent<CheckboxProps>;
527
+ export const Radiobox: DefineComponent<RadioboxProps>;
528
+ export const Table: DefineComponent<TableProps>;
529
+ export const Markdown: DefineComponent<MarkdownProps>;
530
+ export const Image: DefineComponent<ImageProps>;
531
+ export const BigText: DefineComponent<BigTextProps>;
532
+ export const Gradient: DefineComponent<GradientProps>;
533
+ export const Button: DefineComponent<ButtonComponentProps>;
534
+ export const Tree: DefineComponent<TreeProps>;
535
+ export const List: DefineComponent<ListComponentProps>;
536
+ export const Tabs: DefineComponent<TabsProps>;
537
+
538
+ // ============================================================================
539
+ // BigText Utilities
540
+ // ============================================================================
50
541
 
51
542
  export function clearBigTextCache(): void;
52
543
  export function getBigTextCacheStats(): {
@@ -54,26 +545,78 @@ export function getBigTextCacheStats(): {
54
545
  final: { size: number; maxSize: number };
55
546
  };
56
547
 
57
- export function createTheme(userTheme?: Record<string, any>): Record<string, any>;
58
- export const DEFAULT_THEME: Record<string, any>;
59
- export function resolveThemeColor(
60
- theme: Record<string, any>,
61
- path: string
62
- ): string | null;
548
+ // ============================================================================
549
+ // Injection Keys
550
+ // ============================================================================
63
551
 
64
552
  export const VUETTY_INPUT_MANAGER_KEY: string;
65
553
  export const VUETTY_THEME_KEY: string;
554
+ export const VUETTY_RENDERER_KEY: string;
555
+ export const VUETTY_ROUTER_KEY: string;
556
+ export const VUETTY_VIEWPORT_STATE_KEY: string;
557
+ export const VUETTY_INSTANCE_KEY: string;
558
+
559
+ // ============================================================================
560
+ // Render Handler System
561
+ // ============================================================================
562
+
563
+ export interface RenderContextOptions {
564
+ node: any;
565
+ depth: number;
566
+ absX: number;
567
+ absY: number;
568
+ inRow: boolean;
569
+ renderNodeFn: (node: any, depth: number, options: any) => string;
570
+ }
571
+
572
+ export interface RenderChildOptions {
573
+ parentAbsX?: number;
574
+ yOffset?: number;
575
+ inRow?: boolean;
576
+ }
66
577
 
67
578
  export class RenderContext {
68
- constructor(options: any);
69
- [key: string]: any;
579
+ node: any;
580
+ depth: number;
581
+ absX: number;
582
+ absY: number;
583
+ inRow: boolean;
584
+
585
+ constructor(options: RenderContextOptions);
586
+
587
+ get props(): Record<string, any>;
588
+ get text(): string;
589
+ get children(): any[];
590
+ get metrics(): any;
591
+
592
+ getEffectiveWidth(): number | null;
593
+ renderChild(child: any, options?: RenderChildOptions): string;
70
594
  }
595
+
71
596
  export class RenderHandler {
72
597
  render(ctx: RenderContext): string;
73
598
  }
599
+
74
600
  export const renderHandlerRegistry: {
75
601
  register(type: string, handler: RenderHandler): void;
76
602
  get(type: string): RenderHandler | null;
77
603
  has(type: string): boolean;
78
604
  unregister(type: string): void;
79
605
  };
606
+
607
+ // ============================================================================
608
+ // Theme Composable
609
+ // ============================================================================
610
+
611
+ export interface UseThemeReturn {
612
+ theme: ComputedRef<Theme | null>;
613
+ themeName: ComputedRef<string | null>;
614
+ isThemeSet: ComputedRef<boolean>;
615
+ setTheme: (themeName: string) => void;
616
+ getTheme: (themeName: string) => Theme | null;
617
+ listThemes: () => string[];
618
+ getAllThemes: () => Record<string, Theme>;
619
+ findThemes: (pattern: string) => Array<{ name: string; theme: Theme }>;
620
+ }
621
+
622
+ export function useTheme(): UseThemeReturn;