@zaly/tui 0.0.4
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/LICENSE +21 -0
- package/README.md +59 -0
- package/assets/schemas/theme.schema.json +899 -0
- package/assets/themes/LICENSE-tokyonight.txt +201 -0
- package/assets/themes/NOTICES.md +69 -0
- package/assets/themes/ayu-dark.json +119 -0
- package/assets/themes/catppuccin-frappe.json +124 -0
- package/assets/themes/catppuccin-latte.json +124 -0
- package/assets/themes/catppuccin-macchiato.json +124 -0
- package/assets/themes/catppuccin-mocha.json +124 -0
- package/assets/themes/dracula-soft.json +119 -0
- package/assets/themes/dracula.json +119 -0
- package/assets/themes/everforest-dark.json +118 -0
- package/assets/themes/everforest-light.json +118 -0
- package/assets/themes/github-dark.json +123 -0
- package/assets/themes/github-light.json +123 -0
- package/assets/themes/gruvbox-dark-medium.json +112 -0
- package/assets/themes/kanagawa-dragon.json +115 -0
- package/assets/themes/kanagawa-wave.json +115 -0
- package/assets/themes/material-theme-palenight.json +114 -0
- package/assets/themes/min-dark.json +55 -0
- package/assets/themes/min-light.json +59 -0
- package/assets/themes/monokai.json +116 -0
- package/assets/themes/night-owl.json +116 -0
- package/assets/themes/nord.json +101 -0
- package/assets/themes/one-dark-pro.json +110 -0
- package/assets/themes/one-light.json +108 -0
- package/assets/themes/poimandres.json +123 -0
- package/assets/themes/rose-pine.json +98 -0
- package/assets/themes/solarized-dark.json +116 -0
- package/assets/themes/solarized-light.json +116 -0
- package/assets/themes/synthwave-84.json +100 -0
- package/assets/themes/tokyonight-day.json +157 -0
- package/assets/themes/tokyonight-moon.json +157 -0
- package/assets/themes/tokyonight-night.json +157 -0
- package/assets/themes/tokyonight-storm.json +157 -0
- package/assets/themes/vesper.json +103 -0
- package/assets/themes/vitesse-dark.json +126 -0
- package/assets/themes/vitesse-light.json +126 -0
- package/dist/ansi-Clq0ozyA.mjs +206 -0
- package/dist/ansi-Clq0ozyA.mjs.map +1 -0
- package/dist/ansi.d.mts +48 -0
- package/dist/ansi.d.mts.map +1 -0
- package/dist/ansi.mjs +2 -0
- package/dist/autocomplete-Dfw-yQDa.d.mts +100 -0
- package/dist/autocomplete-Dfw-yQDa.d.mts.map +1 -0
- package/dist/box-DyaByEiG.mjs +386 -0
- package/dist/box-DyaByEiG.mjs.map +1 -0
- package/dist/builder-D49ECBEf.mjs +385 -0
- package/dist/builder-D49ECBEf.mjs.map +1 -0
- package/dist/callbacks-CNjGNxVw.mjs +279 -0
- package/dist/callbacks-CNjGNxVw.mjs.map +1 -0
- package/dist/client-D6C_uczF.mjs +142 -0
- package/dist/client-D6C_uczF.mjs.map +1 -0
- package/dist/clipboard.d.mts +104 -0
- package/dist/clipboard.d.mts.map +1 -0
- package/dist/clipboard.mjs +404 -0
- package/dist/clipboard.mjs.map +1 -0
- package/dist/flex-Bguo-fUe.mjs +202 -0
- package/dist/flex-Bguo-fUe.mjs.map +1 -0
- package/dist/image-Cm5T-uw-.mjs +108 -0
- package/dist/image-Cm5T-uw-.mjs.map +1 -0
- package/dist/image.d.mts +123 -0
- package/dist/image.d.mts.map +1 -0
- package/dist/image.mjs +2 -0
- package/dist/index.d.mts +64 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +222 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input-B5Vy-iaa.d.mts +141 -0
- package/dist/input-B5Vy-iaa.d.mts.map +1 -0
- package/dist/inspect-D1d9t-ni.mjs +101 -0
- package/dist/inspect-D1d9t-ni.mjs.map +1 -0
- package/dist/inspect-D6FW_QUo.d.mts +67 -0
- package/dist/inspect-D6FW_QUo.d.mts.map +1 -0
- package/dist/kitty-JbCJC0iQ.mjs +673 -0
- package/dist/kitty-JbCJC0iQ.mjs.map +1 -0
- package/dist/markdown.d.mts +24 -0
- package/dist/markdown.d.mts.map +1 -0
- package/dist/markdown.mjs +2 -0
- package/dist/md.bun.d.mts +14 -0
- package/dist/md.bun.d.mts.map +1 -0
- package/dist/md.bun.mjs +28 -0
- package/dist/md.bun.mjs.map +1 -0
- package/dist/md.node.d.mts +14 -0
- package/dist/md.node.d.mts.map +1 -0
- package/dist/md.node.mjs +126 -0
- package/dist/md.node.mjs.map +1 -0
- package/dist/node-BZ7f6HzU.mjs +316 -0
- package/dist/node-BZ7f6HzU.mjs.map +1 -0
- package/dist/picker-D8OLb6kZ.d.mts +36 -0
- package/dist/picker-D8OLb6kZ.d.mts.map +1 -0
- package/dist/picker-ndVVt6qF.mjs +621 -0
- package/dist/picker-ndVVt6qF.mjs.map +1 -0
- package/dist/queries-DH3bj74K.d.mts +1963 -0
- package/dist/queries-DH3bj74K.d.mts.map +1 -0
- package/dist/reactive-f7NpAi69.mjs +623 -0
- package/dist/reactive-f7NpAi69.mjs.map +1 -0
- package/dist/registry-U654j61Y.mjs +356 -0
- package/dist/registry-U654j61Y.mjs.map +1 -0
- package/dist/render-DxVLqqB9.mjs +74 -0
- package/dist/render-DxVLqqB9.mjs.map +1 -0
- package/dist/renderer-CdLCkJB-.mjs +42 -0
- package/dist/renderer-CdLCkJB-.mjs.map +1 -0
- package/dist/renderer-CxL4xbkl.mjs +2644 -0
- package/dist/renderer-CxL4xbkl.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/search-FvGnswRl.d.mts +49 -0
- package/dist/search-FvGnswRl.d.mts.map +1 -0
- package/dist/select-CbmAZdpt.d.mts +116 -0
- package/dist/select-CbmAZdpt.d.mts.map +1 -0
- package/dist/services/logger.d.mts +2 -0
- package/dist/services/logger.mjs +71 -0
- package/dist/services/logger.mjs.map +1 -0
- package/dist/services/notifier.d.mts +17 -0
- package/dist/services/notifier.d.mts.map +1 -0
- package/dist/services/notifier.mjs +71 -0
- package/dist/services/notifier.mjs.map +1 -0
- package/dist/services/picker.d.mts +36 -0
- package/dist/services/picker.d.mts.map +1 -0
- package/dist/services/picker.mjs +137 -0
- package/dist/services/picker.mjs.map +1 -0
- package/dist/services/prompt.d.mts +30 -0
- package/dist/services/prompt.d.mts.map +1 -0
- package/dist/services/prompt.mjs +83 -0
- package/dist/services/prompt.mjs.map +1 -0
- package/dist/shiki-BrjVUkeh.mjs +423 -0
- package/dist/shiki-BrjVUkeh.mjs.map +1 -0
- package/dist/size-D8JogYLy.mjs +34 -0
- package/dist/size-D8JogYLy.mjs.map +1 -0
- package/dist/style.d.mts +10 -0
- package/dist/style.d.mts.map +1 -0
- package/dist/style.mjs +4 -0
- package/dist/text.d.mts +33 -0
- package/dist/text.d.mts.map +1 -0
- package/dist/text.mjs +111 -0
- package/dist/text.mjs.map +1 -0
- package/dist/theme.config-CU3B50HN.mjs +832 -0
- package/dist/theme.config-CU3B50HN.mjs.map +1 -0
- package/dist/themes.d.mts +113 -0
- package/dist/themes.d.mts.map +1 -0
- package/dist/themes.mjs +2 -0
- package/dist/tree-C28QOVIK.d.mts +23 -0
- package/dist/tree-C28QOVIK.d.mts.map +1 -0
- package/dist/types-B9Eh7k2v.d.mts +212 -0
- package/dist/types-B9Eh7k2v.d.mts.map +1 -0
- package/dist/types-D3jk1rtk.d.mts +140 -0
- package/dist/types-D3jk1rtk.d.mts.map +1 -0
- package/dist/utils-3M4D_AXZ.mjs +40 -0
- package/dist/utils-3M4D_AXZ.mjs.map +1 -0
- package/dist/widgets/autocomplete.d.mts +2 -0
- package/dist/widgets/autocomplete.mjs +165 -0
- package/dist/widgets/autocomplete.mjs.map +1 -0
- package/dist/widgets/box.d.mts +2 -0
- package/dist/widgets/box.mjs +2 -0
- package/dist/widgets/code.d.mts +48 -0
- package/dist/widgets/code.d.mts.map +1 -0
- package/dist/widgets/code.mjs +59 -0
- package/dist/widgets/code.mjs.map +1 -0
- package/dist/widgets/completions/actions.d.mts +41 -0
- package/dist/widgets/completions/actions.d.mts.map +1 -0
- package/dist/widgets/completions/actions.mjs +48 -0
- package/dist/widgets/completions/actions.mjs.map +1 -0
- package/dist/widgets/completions/files.d.mts +29 -0
- package/dist/widgets/completions/files.d.mts.map +1 -0
- package/dist/widgets/completions/files.mjs +42 -0
- package/dist/widgets/completions/files.mjs.map +1 -0
- package/dist/widgets/completions/github.d.mts +64 -0
- package/dist/widgets/completions/github.d.mts.map +1 -0
- package/dist/widgets/completions/github.mjs +137 -0
- package/dist/widgets/completions/github.mjs.map +1 -0
- package/dist/widgets/completions/index.d.mts +4 -0
- package/dist/widgets/completions/index.mjs +4 -0
- package/dist/widgets/diff.d.mts +57 -0
- package/dist/widgets/diff.d.mts.map +1 -0
- package/dist/widgets/diff.mjs +199 -0
- package/dist/widgets/diff.mjs.map +1 -0
- package/dist/widgets/divider.d.mts +11 -0
- package/dist/widgets/divider.d.mts.map +1 -0
- package/dist/widgets/divider.mjs +9 -0
- package/dist/widgets/divider.mjs.map +1 -0
- package/dist/widgets/image.d.mts +37 -0
- package/dist/widgets/image.d.mts.map +1 -0
- package/dist/widgets/image.mjs +77 -0
- package/dist/widgets/image.mjs.map +1 -0
- package/dist/widgets/input.d.mts +2 -0
- package/dist/widgets/input.mjs +497 -0
- package/dist/widgets/input.mjs.map +1 -0
- package/dist/widgets/log.d.mts +2 -0
- package/dist/widgets/log.mjs +130 -0
- package/dist/widgets/log.mjs.map +1 -0
- package/dist/widgets/markdown.d.mts +45 -0
- package/dist/widgets/markdown.d.mts.map +1 -0
- package/dist/widgets/markdown.mjs +124 -0
- package/dist/widgets/markdown.mjs.map +1 -0
- package/dist/widgets/overlay.d.mts +2 -0
- package/dist/widgets/overlay.mjs +18 -0
- package/dist/widgets/overlay.mjs.map +1 -0
- package/dist/widgets/picker.d.mts +2 -0
- package/dist/widgets/picker.mjs +2 -0
- package/dist/widgets/progress.d.mts +48 -0
- package/dist/widgets/progress.d.mts.map +1 -0
- package/dist/widgets/progress.mjs +48 -0
- package/dist/widgets/progress.mjs.map +1 -0
- package/dist/widgets/select.d.mts +2 -0
- package/dist/widgets/select.mjs +195 -0
- package/dist/widgets/select.mjs.map +1 -0
- package/dist/widgets/show.d.mts +55 -0
- package/dist/widgets/show.d.mts.map +1 -0
- package/dist/widgets/show.mjs +85 -0
- package/dist/widgets/show.mjs.map +1 -0
- package/dist/widgets/spinner.d.mts +65 -0
- package/dist/widgets/spinner.d.mts.map +1 -0
- package/dist/widgets/spinner.mjs +147 -0
- package/dist/widgets/spinner.mjs.map +1 -0
- package/dist/widgets/text.d.mts +2 -0
- package/dist/widgets/text.mjs +32 -0
- package/dist/widgets/text.mjs.map +1 -0
- package/dist/widgets/tree.d.mts +2 -0
- package/dist/widgets/tree.mjs +73 -0
- package/dist/widgets/tree.mjs.map +1 -0
- package/dist/widgets/widget.d.mts +49 -0
- package/dist/widgets/widget.d.mts.map +1 -0
- package/dist/widgets/widget.mjs +40 -0
- package/dist/widgets/widget.mjs.map +1 -0
- package/dist/worker-DjHuQSbY.mjs +27 -0
- package/dist/worker-DjHuQSbY.mjs.map +1 -0
- package/package.json +117 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Nt as Size, P as RenderCtx, X as State, f as BaseEvents, nt as Reactive, p as Node, rt as Ref } from "./queries-DH3bj74K.mjs";
|
|
2
|
+
import { f as Style } from "./types-B9Eh7k2v.mjs";
|
|
3
|
+
//#region src/widgets/select.d.ts
|
|
4
|
+
/** Default shape for selectable options. `text` is the canonical
|
|
5
|
+
* searchable/fallback label. `name` overrides the displayed label in the
|
|
6
|
+
* default renderer, and `desc` is shown as a dim right-column description. */
|
|
7
|
+
type Option = {
|
|
8
|
+
name?: string;
|
|
9
|
+
desc?: string;
|
|
10
|
+
text: string;
|
|
11
|
+
};
|
|
12
|
+
type OptionRenderCtx<T> = RenderCtx & {
|
|
13
|
+
visible: readonly T[];
|
|
14
|
+
items: readonly T[];
|
|
15
|
+
active?: boolean;
|
|
16
|
+
prefixWidth?: number;
|
|
17
|
+
};
|
|
18
|
+
/** Per-row rendering hook. `ctx.active` lets callers branch on selection
|
|
19
|
+
* state (e.g. swap an icon or pick a different fg) — but Select still
|
|
20
|
+
* applies the `optionActive` theme slot uniformly so the highlight stays
|
|
21
|
+
* visually consistent. The returned string is clipped/padded to the row
|
|
22
|
+
* width by Select. */
|
|
23
|
+
type OptionRender<T> = (item: T, ctx: OptionRenderCtx<T>) => string;
|
|
24
|
+
interface SelectState<T extends Option = Option> extends Style {
|
|
25
|
+
/** Items to show. Accepts a signal accessor so the list can be
|
|
26
|
+
* driven from reactive state (filtered results, search, etc.). */
|
|
27
|
+
items: Reactive<readonly T[]>;
|
|
28
|
+
/** Index of the highlighted row. Defaults to 0; clamped on render. */
|
|
29
|
+
active?: number;
|
|
30
|
+
/** Max item rows visible at once. The counter (when shown) is an
|
|
31
|
+
* extra row on top of this, not counted against the cap. Window
|
|
32
|
+
* slides to keep `active` in view (pin-until-leave). */
|
|
33
|
+
maxHeight?: Reactive<number>;
|
|
34
|
+
/** Show a `(active+1 / total)` footer as an extra row when items
|
|
35
|
+
* don't fit. `undefined` (default) auto-shows when needed;
|
|
36
|
+
* `false` disables, `true` forces on. */
|
|
37
|
+
counter?: boolean;
|
|
38
|
+
/** Render width. Defaults to `fill`. */
|
|
39
|
+
width?: Size;
|
|
40
|
+
/** Width of the label column for the default renderer. Defaults to the
|
|
41
|
+
* widest visible label, capped to half the row width. Ignored when
|
|
42
|
+
* `render` is set. */
|
|
43
|
+
labelWidth?: number;
|
|
44
|
+
/** Per-item renderer. When omitted, the default two-column layout uses
|
|
45
|
+
* `name ?? text` as the label and `desc` as the right-column hint. */
|
|
46
|
+
render?: Reactive<OptionRender<T> | undefined>;
|
|
47
|
+
reverse?: boolean;
|
|
48
|
+
/** Whether there are more items available than are currently shown. This is a hint for the
|
|
49
|
+
* default renderer to show a "more" indicator in the counter. */
|
|
50
|
+
more?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface SelectEvents<T extends Option = Option> extends BaseEvents {
|
|
53
|
+
/** Fired when the user completes the active item. Payload is the item. */
|
|
54
|
+
complete: {
|
|
55
|
+
item: T;
|
|
56
|
+
};
|
|
57
|
+
/** Fired when the user picks the active item. Payload is the item. */
|
|
58
|
+
accept: {
|
|
59
|
+
item: T;
|
|
60
|
+
};
|
|
61
|
+
/** Fired when the user closes the select (esc). */
|
|
62
|
+
close: {};
|
|
63
|
+
changed: {
|
|
64
|
+
active: number;
|
|
65
|
+
item?: T;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Selectable list. Items are rendered one per row with an active-row
|
|
70
|
+
* highlight; navigation actions (`next`, `prev`, `first`, `last`,
|
|
71
|
+
* `accept`, `complete`, `cancel`) live on `this.actions`, same pattern as
|
|
72
|
+
* `Input`.
|
|
73
|
+
*
|
|
74
|
+
* Used standalone for simple lists and as the underlying list primitive for
|
|
75
|
+
* `picker`, `tree`, and `autocomplete`. Doesn't open/close itself — callers
|
|
76
|
+
* control visibility via `state.visible`.
|
|
77
|
+
*/
|
|
78
|
+
declare class Select<T extends Option = Option> extends Node<SelectState<T>, SelectEvents<T>> {
|
|
79
|
+
#private;
|
|
80
|
+
static readonly type = "select";
|
|
81
|
+
readonly type = "select";
|
|
82
|
+
actions: {
|
|
83
|
+
"select.accept": () => void;
|
|
84
|
+
"select.close": () => void;
|
|
85
|
+
"select.complete": () => void;
|
|
86
|
+
"select.first": () => void;
|
|
87
|
+
"select.last": () => void;
|
|
88
|
+
"select.next": () => void;
|
|
89
|
+
"select.page-down": () => void;
|
|
90
|
+
"select.page-up": () => void;
|
|
91
|
+
"select.prev": () => void;
|
|
92
|
+
};
|
|
93
|
+
constructor(initial: SelectState<T>);
|
|
94
|
+
set active(i: number);
|
|
95
|
+
get active(): number;
|
|
96
|
+
bind(node: Node | Ref<Node>): this;
|
|
97
|
+
get count(): number;
|
|
98
|
+
get pageSize(): number;
|
|
99
|
+
get item(): T | undefined;
|
|
100
|
+
protected _render(ctx: RenderCtx): string[];
|
|
101
|
+
get renderer(): OptionRender<T>;
|
|
102
|
+
extendRenderer(fn: (prev: OptionRender<T>) => OptionRender<T>): this;
|
|
103
|
+
defaultRenderer(): OptionRender<Option>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Factory for a selectable list.
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* const s = select({ items: [{ text: "/help" }, { text: "/quit" }] })
|
|
110
|
+
* s.on("accept", ({ item }) => console.log("picked", item.text))
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
declare function select<T extends Option = Option>(state: State<SelectState<T>>): Select<T>;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { SelectEvents as a, Select as i, OptionRender as n, SelectState as o, OptionRenderCtx as r, select as s, Option as t };
|
|
116
|
+
//# sourceMappingURL=select-CbmAZdpt.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-CbmAZdpt.d.mts","names":[],"sources":["../src/widgets/select.ts"],"mappings":";;;;;;KAgBY;EACV;EACA;EACA;;KAGU,gBAAgB,KAAK;EAC/B,kBAAkB;EAClB,gBAAgB;EAChB;EACA;;;;;;;KAQU,aAAa,MAAM,MAAM,GAAG,KAAK,gBAAgB;UAE5C,YAAY,UAAU,SAAS,gBAAgB;;;EAG9D,OAAO,kBAAkB;;EAEzB;;;;EAIA,YAAY;;;;EAIZ;;EAEA,QAAQ;;;;EAIR;;;EAGA,SAAS,SAAS,aAAa;EAC/B;;;EAGA;;UAGe,aAAa,UAAU,SAAS,gBAAgB;;EAE/D;IAAY,MAAM;;;EAElB;IAAU,MAAM;;;EAEhB;EACA;IAAW;IAAgB,OAAO;;;;;;;;;;;;;cAavB,OAAO,UAAU,SAAS,gBAAgB,KAAK,YAAY,IAAI,aAAa;;kBACvE;WACE;EAET;;;;;;;;;;;EAqDT,YAAY,SAAS,YAAY;MAyB7B,OAAO;MAKP;EAOJ,KAAK,MAAM,OAAO,IAAI;MASlB;MAIA;MAIA,QAAQ;YAIF,QAAQ,KAAK;MA2CnB,YAAY,aAAa;EAI7B,eAAe,KAAK,MAAM,aAAa,OAAO,aAAa;EAM3D,mBAAmB,aAAa;;;;;;;;;;iBAmClB,OAAO,UAAU,SAAS,QAAQ,OAAO,MAAM,YAAY,MAAM,OAAO"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { t as Node } from "../node-BZ7f6HzU.mjs";
|
|
2
|
+
import { n as inspectFormat, r as isMarkdown } from "../inspect-D1d9t-ni.mjs";
|
|
3
|
+
import { log } from "../widgets/log.mjs";
|
|
4
|
+
//#region src/services/logger.ts
|
|
5
|
+
const ERR_LEVELS = /* @__PURE__ */ new Set([
|
|
6
|
+
"error",
|
|
7
|
+
"fatal",
|
|
8
|
+
"warn"
|
|
9
|
+
]);
|
|
10
|
+
function defaultWrite(text, kind) {
|
|
11
|
+
if (typeof process === "undefined") return;
|
|
12
|
+
(kind === "stderr" ? process.stderr : process.stdout).write(text);
|
|
13
|
+
}
|
|
14
|
+
var TuiReporter = class {
|
|
15
|
+
#stream;
|
|
16
|
+
#opts;
|
|
17
|
+
#factory;
|
|
18
|
+
constructor(opts = {}) {
|
|
19
|
+
this.#opts = opts;
|
|
20
|
+
this.#factory = opts.factory ?? ((level, msg) => this.#defaultFactory(level, msg));
|
|
21
|
+
}
|
|
22
|
+
attach(stream) {
|
|
23
|
+
this.#stream = stream;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
detach() {
|
|
27
|
+
this.#stream = void 0;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
$log({ level, msg }) {
|
|
31
|
+
if (this.#stream) {
|
|
32
|
+
this.#stream.append(() => {
|
|
33
|
+
const node = this.#factory(level, msg);
|
|
34
|
+
return this.#opts.wrap?.(node) ?? node;
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.#writeFallback(level, msg);
|
|
39
|
+
}
|
|
40
|
+
#defaultFactory(level, msg) {
|
|
41
|
+
const nodes = msg.filter((m) => m instanceof Node);
|
|
42
|
+
msg = msg.filter((m) => !(m instanceof Node));
|
|
43
|
+
msg = this.#opts.stacktrace ? msg : msg.map((v) => v instanceof Error ? v.message : v);
|
|
44
|
+
if (msg.length && msg.every((m) => typeof m === "string")) msg = [msg.join(" ")];
|
|
45
|
+
let text = msg.length === 1 && typeof msg[0] === "string" ? msg[0] : void 0;
|
|
46
|
+
if (msg.length === 0) text = "";
|
|
47
|
+
const markdown = (this.#opts.markdown ?? true) && text !== void 0 && isMarkdown(text);
|
|
48
|
+
const overrides = this.#opts.styles?.[level] ?? {};
|
|
49
|
+
return log({
|
|
50
|
+
content: text ?? ((ctx) => inspectFormat(msg, {
|
|
51
|
+
...this.#opts,
|
|
52
|
+
style: ctx.style
|
|
53
|
+
})),
|
|
54
|
+
level,
|
|
55
|
+
markdown,
|
|
56
|
+
...overrides
|
|
57
|
+
}, ...nodes);
|
|
58
|
+
}
|
|
59
|
+
/** String path for the no-stream fallback — builds a plain inspected
|
|
60
|
+
* line (no prefix chrome) and writes it to stdout/stderr. Keeps the
|
|
61
|
+
* fallback synchronous and ordered. */
|
|
62
|
+
#writeFallback(level, msg) {
|
|
63
|
+
const str = inspectFormat(msg, this.#opts);
|
|
64
|
+
const kind = ERR_LEVELS.has(level) ? "stderr" : "stdout";
|
|
65
|
+
(this.#opts.write ?? defaultWrite)(`${str}\n`, kind);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { TuiReporter };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=logger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":["#opts","#factory","#defaultFactory","#stream","#writeFallback"],"sources":["../../src/services/logger.ts"],"sourcesContent":["import type { LogEntry, LogLevel, LogReporter } from \"@zaly/shared/logger\"\nimport type { InspectOpts } from \"../style/inspect.ts\"\nimport type { LogState } from \"../widgets/log.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { inspectFormat, isMarkdown } from \"../style/inspect.ts\"\nimport { log } from \"../widgets/log.ts\"\n\n/** Minimal stream surface the logger needs. Stream satisfies this. */\nexport interface LoggerStream {\n append: (node: () => Node) => unknown\n}\n\nexport type LogEntryFactory = (level: LogLevel, msg: unknown[]) => Node\n\nexport type LogStyleOverride = Omit<LogState, \"level\" | \"content\">\n\nexport interface TuiReporterOpts extends InspectOpts {\n /** Render string messages as markdown when they look like it.\n * Default: `true`. */\n markdown?: boolean\n /** Per-level overrides for the default `log()` widget style fields. */\n styles?: Partial<Record<LogLevel, LogStyleOverride>>\n /** Override the node produced per entry. Default uses `log()`. */\n factory?: LogEntryFactory\n wrap?: (node: Node) => Node\n /** Fallback writer for when no stream is attached. Defaults to\n * `process.stdout/stderr`. Injectable for tests. */\n write?: (text: string, kind: \"stdout\" | \"stderr\") => void\n}\n\nconst ERR_LEVELS = new Set<LogLevel>([\"error\", \"fatal\", \"warn\"])\n\nfunction defaultWrite(text: string, kind: \"stdout\" | \"stderr\"): void {\n if (typeof process === \"undefined\") return\n const stream = kind === \"stderr\" ? process.stderr : process.stdout\n stream.write(text)\n}\n\nexport class TuiReporter implements LogReporter {\n #stream?: LoggerStream\n #opts: TuiReporterOpts\n #factory: LogEntryFactory\n\n constructor(opts: TuiReporterOpts = {}) {\n this.#opts = opts\n this.#factory = opts.factory ?? ((level, msg) => this.#defaultFactory(level, msg))\n }\n\n attach(stream: LoggerStream): this {\n this.#stream = stream\n return this\n }\n\n detach(): this {\n this.#stream = undefined\n return this\n }\n\n $log({ level, msg }: LogEntry): void {\n if (this.#stream) {\n this.#stream.append(() => {\n const node = this.#factory(level, msg)\n return this.#opts.wrap?.(node) ?? node\n })\n return\n }\n this.#writeFallback(level, msg)\n }\n\n #defaultFactory(level: LogLevel, msg: unknown[]): Node {\n const nodes = msg.filter((m): m is Node => m instanceof Node)\n msg = msg.filter((m) => !(m instanceof Node))\n\n // Convert Error objects to their message unless stacktrace is requested.\n msg = this.#opts.stacktrace ? msg : msg.map((v) => (v instanceof Error ? v.message : v))\n\n // If all remaining messages are strings, join them into one string for the log content.\n if (msg.length && msg.every((m) => typeof m === \"string\")) msg = [msg.join(\" \")]\n\n // If there's exactly one string message, use it as the log content;\n // otherwise, leave it undefined to be formatted with `inspect()`.\n // Text allow markdown if the message looks like markdown and the option is enabled.\n let text = msg.length === 1 && typeof msg[0] === \"string\" ? msg[0] : undefined\n if (msg.length === 0) text = \"\"\n const markdown = (this.#opts.markdown ?? true) && text !== undefined && isMarkdown(text)\n const overrides = this.#opts.styles?.[level] ?? {}\n return log(\n {\n content: text ?? ((ctx) => inspectFormat(msg, { ...this.#opts, style: ctx.style })),\n level,\n markdown,\n ...overrides,\n },\n ...nodes\n )\n }\n\n /** String path for the no-stream fallback — builds a plain inspected\n * line (no prefix chrome) and writes it to stdout/stderr. Keeps the\n * fallback synchronous and ordered. */\n #writeFallback(level: LogLevel, msg: unknown[]): void {\n const str = inspectFormat(msg, this.#opts)\n const kind: \"stdout\" | \"stderr\" = ERR_LEVELS.has(level) ? \"stderr\" : \"stdout\"\n const write = this.#opts.write ?? defaultWrite\n write(`${str}\\n`, kind)\n }\n}\n"],"mappings":";;;;AA+BA,MAAM,6BAAa,IAAI,IAAc;CAAC;CAAS;CAAS;AAAM,CAAC;AAE/D,SAAS,aAAa,MAAc,MAAiC;CACnE,IAAI,OAAO,YAAY,aAAa;CAEpC,CADe,SAAS,WAAW,QAAQ,SAAS,QAAQ,OAAA,CACrD,MAAM,IAAI;AACnB;AAEA,IAAa,cAAb,MAAgD;CAC9C;CACA;CACA;CAEA,YAAY,OAAwB,CAAC,GAAG;EACtC,KAAKA,QAAQ;EACb,KAAKC,WAAW,KAAK,aAAa,OAAO,QAAQ,KAAKC,gBAAgB,OAAO,GAAG;CAClF;CAEA,OAAO,QAA4B;EACjC,KAAKC,UAAU;EACf,OAAO;CACT;CAEA,SAAe;EACb,KAAKA,UAAU,KAAA;EACf,OAAO;CACT;CAEA,KAAK,EAAE,OAAO,OAAuB;EACnC,IAAI,KAAKA,SAAS;GAChB,KAAKA,QAAQ,aAAa;IACxB,MAAM,OAAO,KAAKF,SAAS,OAAO,GAAG;IACrC,OAAO,KAAKD,MAAM,OAAO,IAAI,KAAK;GACpC,CAAC;GACD;EACF;EACA,KAAKI,eAAe,OAAO,GAAG;CAChC;CAEA,gBAAgB,OAAiB,KAAsB;EACrD,MAAM,QAAQ,IAAI,QAAQ,MAAiB,aAAa,IAAI;EAC5D,MAAM,IAAI,QAAQ,MAAM,EAAE,aAAa,KAAK;EAG5C,MAAM,KAAKJ,MAAM,aAAa,MAAM,IAAI,KAAK,MAAO,aAAa,QAAQ,EAAE,UAAU,CAAE;EAGvF,IAAI,IAAI,UAAU,IAAI,OAAO,MAAM,OAAO,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC;EAK/E,IAAI,OAAO,IAAI,WAAW,KAAK,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK,KAAA;EACrE,IAAI,IAAI,WAAW,GAAG,OAAO;EAC7B,MAAM,YAAY,KAAKA,MAAM,YAAY,SAAS,SAAS,KAAA,KAAa,WAAW,IAAI;EACvF,MAAM,YAAY,KAAKA,MAAM,SAAS,UAAU,CAAC;EACjD,OAAO,IACL;GACE,SAAS,UAAU,QAAQ,cAAc,KAAK;IAAE,GAAG,KAAKA;IAAO,OAAO,IAAI;GAAM,CAAC;GACjF;GACA;GACA,GAAG;EACL,GACA,GAAG,KACL;CACF;;;;CAKA,eAAe,OAAiB,KAAsB;EACpD,MAAM,MAAM,cAAc,KAAK,KAAKA,KAAK;EACzC,MAAM,OAA4B,WAAW,IAAI,KAAK,IAAI,WAAW;EAErE,CADc,KAAKA,MAAM,SAAS,aAAA,CAC5B,GAAG,IAAI,KAAK,IAAI;CACxB;AACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { A as LogState, C as OverlaySurface, F as Overlay, nt as Reactive } from "../queries-DH3bj74K.mjs";
|
|
2
|
+
import { LogLevel } from "@zaly/shared/logger";
|
|
3
|
+
//#region src/services/notifier.d.ts
|
|
4
|
+
type NotifProps = Omit<LogState, "content" | "level"> & {
|
|
5
|
+
level?: LogLevel;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
keep?: () => boolean;
|
|
8
|
+
onClose?: () => void;
|
|
9
|
+
};
|
|
10
|
+
declare class Notifier {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(ui: OverlaySurface);
|
|
13
|
+
notify(msg: Reactive<string>, opts?: NotifProps): Overlay;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { NotifProps, Notifier };
|
|
17
|
+
//# sourceMappingURL=notifier.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifier.d.mts","names":[],"sources":["../../src/services/notifier.ts"],"mappings":";;;KAUY,aAAa,KAAK;EAC5B,QAAQ;EACR;EACA;EACA;;cASW;;EAKX,YAAY,IAAI;EAmDhB,OAAO,KAAK,kBAAkB,OAAO,aAAa"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { log } from "../widgets/log.mjs";
|
|
2
|
+
import { overlay } from "../widgets/overlay.mjs";
|
|
3
|
+
//#region src/services/notifier.ts
|
|
4
|
+
var Notifier = class {
|
|
5
|
+
#ui;
|
|
6
|
+
#active = /* @__PURE__ */ new Map();
|
|
7
|
+
#queue = [];
|
|
8
|
+
constructor(ui) {
|
|
9
|
+
this.#ui = ui;
|
|
10
|
+
ui.on("render-node", (state) => {
|
|
11
|
+
const notif = this.#active.get(state.node);
|
|
12
|
+
if (!notif) return;
|
|
13
|
+
notif.state = state;
|
|
14
|
+
setImmediate(() => this.#check());
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
#notif(msg, opts) {
|
|
18
|
+
return overlay({
|
|
19
|
+
padding: [0, 0],
|
|
20
|
+
width: 40,
|
|
21
|
+
x: -40,
|
|
22
|
+
y: 1,
|
|
23
|
+
zIndex: 1e3
|
|
24
|
+
}, log({
|
|
25
|
+
level: "info",
|
|
26
|
+
...opts,
|
|
27
|
+
content: msg,
|
|
28
|
+
style: "notif"
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
#start(notif) {
|
|
32
|
+
this.#active.set(notif.node, notif);
|
|
33
|
+
notif.node.state.visible = true;
|
|
34
|
+
const t = setInterval(() => {
|
|
35
|
+
if (notif.opts?.keep?.()) return;
|
|
36
|
+
clearInterval(t);
|
|
37
|
+
this.#active.delete(notif.node);
|
|
38
|
+
this.#ui.close(notif.node);
|
|
39
|
+
notif.opts?.onClose?.();
|
|
40
|
+
this.#check();
|
|
41
|
+
}, notif.opts?.timeout ?? 3e3);
|
|
42
|
+
t.unref();
|
|
43
|
+
}
|
|
44
|
+
#check() {
|
|
45
|
+
while (this.#queue.length) {
|
|
46
|
+
const termHeight = this.#ui.$r.terminal.rows;
|
|
47
|
+
let y = 2;
|
|
48
|
+
for (const n of this.#active.values()) {
|
|
49
|
+
if (!n.state) return;
|
|
50
|
+
y = Math.max(y, n.state.y + n.state.height + 1);
|
|
51
|
+
}
|
|
52
|
+
if (termHeight - y < 10) return;
|
|
53
|
+
const next = this.#queue.shift();
|
|
54
|
+
next.node.state.y = y;
|
|
55
|
+
this.#start(next);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
notify(msg, opts) {
|
|
59
|
+
const node = this.#ui.add(() => this.#notif(msg, opts));
|
|
60
|
+
this.#queue.push({
|
|
61
|
+
node,
|
|
62
|
+
opts
|
|
63
|
+
});
|
|
64
|
+
setImmediate(() => this.#check());
|
|
65
|
+
return node;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { Notifier };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=notifier.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifier.mjs","names":["#ui","#active","#check","#queue","#start","#notif"],"sources":["../../src/services/notifier.ts"],"sourcesContent":["import type { LogLevel } from \"@zaly/shared/logger\"\nimport type { Node } from \"../core/node.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\nimport type { OverlayRenderState, OverlaySurface } from \"../renderer/overlay.ts\"\nimport type { LogState } from \"../widgets/log.ts\"\nimport type { Overlay } from \"../widgets/overlay.ts\"\n\nimport { log } from \"../widgets/log.ts\"\nimport { overlay } from \"../widgets/overlay.ts\"\n\nexport type NotifProps = Omit<LogState, \"content\" | \"level\"> & {\n level?: LogLevel\n timeout?: number\n keep?: () => boolean\n onClose?: () => void\n}\n\ntype Notif = {\n node: Overlay\n opts?: NotifProps\n state?: OverlayRenderState\n}\n\nexport class Notifier {\n #ui: OverlaySurface\n #active = new Map<Node, Notif>()\n #queue: Notif[] = []\n\n constructor(ui: OverlaySurface) {\n this.#ui = ui\n ui.on(\"render-node\", (state) => {\n const notif = this.#active.get(state.node)\n if (!notif) return\n notif.state = state\n setImmediate(() => this.#check())\n })\n }\n\n #notif(msg: Reactive<string>, opts?: NotifProps) {\n return overlay(\n { padding: [0, 0], width: 40, x: -40, y: 1, zIndex: 1000 },\n log({\n level: \"info\",\n ...opts,\n content: msg,\n style: \"notif\",\n })\n )\n }\n\n #start(notif: Notif) {\n this.#active.set(notif.node, notif)\n notif.node.state.visible = true\n const t = setInterval(() => {\n if (notif.opts?.keep?.()) return\n clearInterval(t)\n this.#active.delete(notif.node)\n this.#ui.close(notif.node)\n notif.opts?.onClose?.()\n this.#check()\n }, notif.opts?.timeout ?? 3000)\n t.unref()\n }\n\n #check() {\n while (this.#queue.length) {\n const termHeight = this.#ui.$r.terminal.rows\n let y = 2\n for (const n of this.#active.values()) {\n if (!n.state) return // wait till it renders\n y = Math.max(y, n.state.y + n.state.height + 1)\n }\n if (termHeight - y < 10) return // Don't start if less than 10 rows remain below the last notif\n const next = this.#queue.shift()!\n next.node.state.y = y\n this.#start(next)\n }\n }\n\n notify(msg: Reactive<string>, opts?: NotifProps): Overlay {\n const node = this.#ui.add(() => this.#notif(msg, opts))\n this.#queue.push({ node, opts })\n setImmediate(() => this.#check())\n return node\n }\n}\n"],"mappings":";;;AAuBA,IAAa,WAAb,MAAsB;CACpB;CACA,0BAAU,IAAI,IAAiB;CAC/B,SAAkB,CAAC;CAEnB,YAAY,IAAoB;EAC9B,KAAKA,MAAM;EACX,GAAG,GAAG,gBAAgB,UAAU;GAC9B,MAAM,QAAQ,KAAKC,QAAQ,IAAI,MAAM,IAAI;GACzC,IAAI,CAAC,OAAO;GACZ,MAAM,QAAQ;GACd,mBAAmB,KAAKC,OAAO,CAAC;EAClC,CAAC;CACH;CAEA,OAAO,KAAuB,MAAmB;EAC/C,OAAO,QACL;GAAE,SAAS,CAAC,GAAG,CAAC;GAAG,OAAO;GAAI,GAAG;GAAK,GAAG;GAAG,QAAQ;EAAK,GACzD,IAAI;GACF,OAAO;GACP,GAAG;GACH,SAAS;GACT,OAAO;EACT,CAAC,CACH;CACF;CAEA,OAAO,OAAc;EACnB,KAAKD,QAAQ,IAAI,MAAM,MAAM,KAAK;EAClC,MAAM,KAAK,MAAM,UAAU;EAC3B,MAAM,IAAI,kBAAkB;GAC1B,IAAI,MAAM,MAAM,OAAO,GAAG;GAC1B,cAAc,CAAC;GACf,KAAKA,QAAQ,OAAO,MAAM,IAAI;GAC9B,KAAKD,IAAI,MAAM,MAAM,IAAI;GACzB,MAAM,MAAM,UAAU;GACtB,KAAKE,OAAO;EACd,GAAG,MAAM,MAAM,WAAW,GAAI;EAC9B,EAAE,MAAM;CACV;CAEA,SAAS;EACP,OAAO,KAAKC,OAAO,QAAQ;GACzB,MAAM,aAAa,KAAKH,IAAI,GAAG,SAAS;GACxC,IAAI,IAAI;GACR,KAAK,MAAM,KAAK,KAAKC,QAAQ,OAAO,GAAG;IACrC,IAAI,CAAC,EAAE,OAAO;IACd,IAAI,KAAK,IAAI,GAAG,EAAE,MAAM,IAAI,EAAE,MAAM,SAAS,CAAC;GAChD;GACA,IAAI,aAAa,IAAI,IAAI;GACzB,MAAM,OAAO,KAAKE,OAAO,MAAM;GAC/B,KAAK,KAAK,MAAM,IAAI;GACpB,KAAKC,OAAO,IAAI;EAClB;CACF;CAEA,OAAO,KAAuB,MAA4B;EACxD,MAAM,OAAO,KAAKJ,IAAI,UAAU,KAAKK,OAAO,KAAK,IAAI,CAAC;EACtD,KAAKF,OAAO,KAAK;GAAE;GAAM;EAAK,CAAC;EAC/B,mBAAmB,KAAKD,OAAO,CAAC;EAChC,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { C as OverlaySurface, F as Overlay, Lt as ActionFilter, Q as Accessor, nt as Reactive, rt as Ref } from "../queries-DH3bj74K.mjs";
|
|
2
|
+
import { t as Input } from "../input-B5Vy-iaa.mjs";
|
|
3
|
+
import { i as Select, t as Option } from "../select-CbmAZdpt.mjs";
|
|
4
|
+
import { i as PickerTreeProps, n as PickerItem, r as PickerSelectProps } from "../picker-D8OLb6kZ.mjs";
|
|
5
|
+
import { Widget } from "../widgets/widget.mjs";
|
|
6
|
+
//#region src/services/picker.d.ts
|
|
7
|
+
type ToggleItem = PickerItem & {
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
type PickOpts<T extends Option = Option> = {
|
|
11
|
+
title?: Reactive<string>;
|
|
12
|
+
multi?: boolean | {
|
|
13
|
+
action?: boolean;
|
|
14
|
+
render?: boolean;
|
|
15
|
+
};
|
|
16
|
+
ref?: Ref<Select<T>>;
|
|
17
|
+
details?: Widget | string;
|
|
18
|
+
clearInput?: boolean;
|
|
19
|
+
restoreInput?: boolean;
|
|
20
|
+
whichKey?: boolean | ActionFilter;
|
|
21
|
+
} & (Omit<PickerSelectProps<T>, "input"> | Omit<PickerTreeProps<T>, "input">);
|
|
22
|
+
declare class Picker {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(ui: OverlaySurface, input: Input);
|
|
25
|
+
get isOpen(): Accessor<boolean>;
|
|
26
|
+
close(opts?: {
|
|
27
|
+
all?: boolean;
|
|
28
|
+
}): void;
|
|
29
|
+
get active(): Overlay | undefined;
|
|
30
|
+
suspend(): void;
|
|
31
|
+
resume(): void;
|
|
32
|
+
pick<T extends Option = Option>(opts: PickOpts<T>): Promise<T | undefined>;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { PickOpts, Picker, ToggleItem };
|
|
36
|
+
//# sourceMappingURL=picker.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.d.mts","names":[],"sources":["../../src/services/picker.ts"],"mappings":";;;;;;KAkBY,aAAa;EAAe;;KAE5B,SAAS,UAAU,SAAS;EACtC,QAAQ;EACR;IAAoB;IAAkB;;EACtC,MAAM,IAAI,OAAO;EACjB,UAAU;EACV;EACA;EACA,qBAAqB;KAClB,KAAK,kBAAkB,eAAe,KAAK,gBAAgB;cAEnD;;EAMX,YAAY,IAAI,gBAAgB,OAAO;MAKnC,UALmC;EAyFvC,MAAM;IAAQ;;MAQV,UAAM;EAIV;EAIA;EAIM,KAAK,UAAU,SAAS,QAAQ,MAAM,SAAS,KAAK,QAAQ"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { c as createRef, y as signal } from "../reactive-f7NpAi69.mjs";
|
|
2
|
+
import { r as isMarkdown } from "../inspect-D1d9t-ni.mjs";
|
|
3
|
+
import { text } from "../widgets/text.mjs";
|
|
4
|
+
import { markdown } from "../widgets/markdown.mjs";
|
|
5
|
+
import { overlay } from "../widgets/overlay.mjs";
|
|
6
|
+
import { divider } from "../widgets/divider.mjs";
|
|
7
|
+
import { t as picker } from "../picker-ndVVt6qF.mjs";
|
|
8
|
+
//#region src/services/picker.ts
|
|
9
|
+
var Picker = class {
|
|
10
|
+
#ui;
|
|
11
|
+
#input;
|
|
12
|
+
#open = signal(false);
|
|
13
|
+
#active = [];
|
|
14
|
+
constructor(ui, input) {
|
|
15
|
+
this.#ui = ui;
|
|
16
|
+
this.#input = input;
|
|
17
|
+
}
|
|
18
|
+
get isOpen() {
|
|
19
|
+
return this.#open.get;
|
|
20
|
+
}
|
|
21
|
+
#pick(opts) {
|
|
22
|
+
const children = [];
|
|
23
|
+
if (opts.title) children.push(markdown(opts.title, { style: "borderTitle" }));
|
|
24
|
+
if (opts.details) if (typeof opts.details === "string") children.push(isMarkdown(opts.details) ? markdown(opts.details) : text(opts.details));
|
|
25
|
+
else children.push(opts.details());
|
|
26
|
+
const select = picker({
|
|
27
|
+
maxHeight: 8,
|
|
28
|
+
...opts
|
|
29
|
+
});
|
|
30
|
+
select.ref(opts.ref);
|
|
31
|
+
if (opts.multi) this.#multi(select, opts.multi === true ? {} : opts.multi);
|
|
32
|
+
const wk = this.#whichKey(select, opts.whichKey);
|
|
33
|
+
if (wk) children.push(wk);
|
|
34
|
+
if (children.length > 0) children.push(divider({ style: "border" }));
|
|
35
|
+
return overlay({
|
|
36
|
+
padding: [0, 1],
|
|
37
|
+
relative: "ui",
|
|
38
|
+
style: "ui",
|
|
39
|
+
verticalAnchor: "bottom",
|
|
40
|
+
x: 0,
|
|
41
|
+
y: 1
|
|
42
|
+
}, divider({ style: "accent" }), ...children, select);
|
|
43
|
+
}
|
|
44
|
+
#whichKey(select, opts) {
|
|
45
|
+
if (opts === false || opts === void 0) return;
|
|
46
|
+
const filter = opts === true ? { hidden: false } : opts;
|
|
47
|
+
const ret = text((ctx) => {
|
|
48
|
+
const s = ctx.style;
|
|
49
|
+
const bo = s.syntaxDelimiter.dim("<");
|
|
50
|
+
const bc = s.syntaxDelimiter.dim(">");
|
|
51
|
+
return this.#ui.$r.actions.whichKey(select, { filter }).map((a) => {
|
|
52
|
+
const name = s.muted(a.desc ?? a.cmd ?? a.id);
|
|
53
|
+
return `${a.keys.map((k) => bo + s.syntaxSpecial.dim(k) + bc).join(s.delim.dim("/"))} ${name.toLowerCase()}`;
|
|
54
|
+
}).join(s.delim(" • "));
|
|
55
|
+
});
|
|
56
|
+
select.once("mount", () => ret.invalidate());
|
|
57
|
+
return ret;
|
|
58
|
+
}
|
|
59
|
+
#multi(select, opts = {}) {
|
|
60
|
+
if (opts.render !== false) select.extendRenderer((prev) => (item, ctx) => {
|
|
61
|
+
const s = ctx.style;
|
|
62
|
+
const row = prev(item, {
|
|
63
|
+
...ctx,
|
|
64
|
+
width: ctx.width - 4
|
|
65
|
+
});
|
|
66
|
+
const enabled = item.enabled;
|
|
67
|
+
if (enabled === void 0) return row;
|
|
68
|
+
return `${enabled ? s.mdListChecked("[x]") : s.mdListUnchecked("[ ]")} ${row}`;
|
|
69
|
+
});
|
|
70
|
+
if (opts.action !== false) select.withActions({ "picker.toggle": {
|
|
71
|
+
desc: "Toggle item",
|
|
72
|
+
fn: () => {
|
|
73
|
+
const active = select.item;
|
|
74
|
+
if (!active) return;
|
|
75
|
+
active.enabled = !active.enabled;
|
|
76
|
+
select.invalidate();
|
|
77
|
+
},
|
|
78
|
+
keys: ["tab", "enter"],
|
|
79
|
+
priority: 10
|
|
80
|
+
} });
|
|
81
|
+
}
|
|
82
|
+
close(opts = {}) {
|
|
83
|
+
while (this.#active.length > 0) {
|
|
84
|
+
const node = this.#active.pop();
|
|
85
|
+
this.#ui.close(node);
|
|
86
|
+
if (!opts.all) break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
get active() {
|
|
90
|
+
return this.#active.at(-1);
|
|
91
|
+
}
|
|
92
|
+
suspend() {
|
|
93
|
+
this.active?.hide();
|
|
94
|
+
}
|
|
95
|
+
resume() {
|
|
96
|
+
this.active?.show();
|
|
97
|
+
}
|
|
98
|
+
async pick(opts) {
|
|
99
|
+
this.active?.hide();
|
|
100
|
+
const res = Promise.withResolvers();
|
|
101
|
+
let settled = false;
|
|
102
|
+
const clear = opts.clearInput ?? true;
|
|
103
|
+
const restore = opts.restoreInput ?? true;
|
|
104
|
+
const prevInput = clear ? this.#input.consume().value : void 0;
|
|
105
|
+
const ref = opts.ref ?? createRef();
|
|
106
|
+
const node = this.#ui.open(() => this.#pick({
|
|
107
|
+
...opts,
|
|
108
|
+
input: this.#input,
|
|
109
|
+
ref
|
|
110
|
+
}));
|
|
111
|
+
this.#active.push(node);
|
|
112
|
+
this.#open.set(true);
|
|
113
|
+
const select = ref();
|
|
114
|
+
const ac = new AbortController();
|
|
115
|
+
const done = (value) => {
|
|
116
|
+
if (settled) return;
|
|
117
|
+
settled = true;
|
|
118
|
+
ac.abort();
|
|
119
|
+
this.#active = this.#active.filter((n) => n !== node);
|
|
120
|
+
if (restore && prevInput !== void 0) this.#input.replace(prevInput);
|
|
121
|
+
else if (!restore) this.#input.consume();
|
|
122
|
+
res.resolve(value);
|
|
123
|
+
this.#ui.close(node);
|
|
124
|
+
this.active?.show();
|
|
125
|
+
this.#open.set(this.#active.length > 0);
|
|
126
|
+
};
|
|
127
|
+
node.once("unmount", () => done(), { signal: ac.signal });
|
|
128
|
+
select.once("close", () => done(), { signal: ac.signal });
|
|
129
|
+
select.once("accept", ({ item }) => done(item), { signal: ac.signal });
|
|
130
|
+
select.once("complete", ({ item }) => done(item), { signal: ac.signal });
|
|
131
|
+
return res.promise;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
//#endregion
|
|
135
|
+
export { Picker };
|
|
136
|
+
|
|
137
|
+
//# sourceMappingURL=picker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.mjs","names":["#ui","#input","#open","#multi","#whichKey","#active","#pick"],"sources":["../../src/services/picker.ts"],"sourcesContent":["import type { Node } from \"../core/node.ts\"\nimport type { Reactive, Ref } from \"../core/reactive.ts\"\nimport type { ActionFilter } from \"../input/actions.ts\"\nimport type { OverlaySurface } from \"../renderer/overlay.ts\"\nimport type { Input } from \"../widgets/input.ts\"\nimport type { Overlay } from \"../widgets/overlay.ts\"\nimport type { PickerItem, PickerSelectProps, PickerTreeProps } from \"../widgets/picker.ts\"\nimport type { Option, Select } from \"../widgets/select.ts\"\nimport type { Widget } from \"../widgets/widget.ts\"\n\nimport { createRef, signal } from \"../core/reactive.ts\"\nimport { isMarkdown } from \"../style/inspect.ts\"\nimport { divider } from \"../widgets/divider.ts\"\nimport { markdown } from \"../widgets/markdown.ts\"\nimport { overlay } from \"../widgets/overlay.ts\"\nimport { picker } from \"../widgets/picker.ts\"\nimport { text } from \"../widgets/text.ts\"\n\nexport type ToggleItem = PickerItem & { enabled?: boolean }\n\nexport type PickOpts<T extends Option = Option> = {\n title?: Reactive<string>\n multi?: boolean | { action?: boolean; render?: boolean }\n ref?: Ref<Select<T>>\n details?: Widget | string\n clearInput?: boolean\n restoreInput?: boolean\n whichKey?: boolean | ActionFilter\n} & (Omit<PickerSelectProps<T>, \"input\"> | Omit<PickerTreeProps<T>, \"input\">)\n\nexport class Picker {\n #ui: OverlaySurface\n #input: Input\n #open = signal(false)\n #active: Overlay[] = []\n\n constructor(ui: OverlaySurface, input: Input) {\n this.#ui = ui\n this.#input = input\n }\n\n get isOpen() {\n return this.#open.get\n }\n\n #pick<T extends Option = Option>(\n opts: PickOpts<T> & { input: Input; ref: Ref<Select<T>> }\n ): Overlay {\n const children: Node[] = []\n if (opts.title) children.push(markdown(opts.title, { style: \"borderTitle\" }))\n if (opts.details) {\n if (typeof opts.details === \"string\")\n children.push(isMarkdown(opts.details) ? markdown(opts.details) : text(opts.details))\n else children.push(opts.details())\n }\n\n const select = picker<T>({ maxHeight: 8, ...opts })\n select.ref(opts.ref)\n if (opts.multi)\n this.#multi(select as unknown as Select<ToggleItem>, opts.multi === true ? {} : opts.multi)\n\n const wk = this.#whichKey(select as unknown as Select, opts.whichKey)\n if (wk) children.push(wk)\n\n if (children.length > 0) children.push(divider({ style: \"border\" }))\n return overlay(\n {\n padding: [0, 1],\n relative: \"ui\",\n style: \"ui\",\n verticalAnchor: \"bottom\",\n x: 0,\n y: 1,\n },\n divider({ style: \"accent\" }),\n ...children,\n select\n )\n }\n\n #whichKey(select: Select, opts: PickOpts[\"whichKey\"]): Node | undefined {\n if (opts === false || opts === undefined) return\n const filter = opts === true ? { hidden: false } : opts\n const ret = text((ctx) => {\n const s = ctx.style\n const bo = s.syntaxDelimiter.dim(\"<\")\n const bc = s.syntaxDelimiter.dim(\">\")\n const wk = this.#ui.$r.actions.whichKey(select, { filter })\n const parts = wk.map((a) => {\n const name = s.muted(a.desc ?? a.cmd ?? a.id)\n const keys = a.keys.map((k) => bo + s.syntaxSpecial.dim(k) + bc).join(s.delim.dim(\"/\"))\n return `${keys} ${name.toLowerCase()}`\n })\n return parts.join(s.delim(\" • \"))\n })\n\n select.once(\"mount\", () => ret.invalidate())\n return ret\n }\n\n #multi(select: Select<ToggleItem>, opts: { action?: boolean; render?: boolean } = {}) {\n if (opts.render !== false)\n select.extendRenderer((prev) => (item, ctx) => {\n const s = ctx.style\n const row = prev(item, { ...ctx, width: ctx.width - 4 })\n const enabled = item.enabled\n if (enabled === undefined) return row\n return `${enabled ? s.mdListChecked(\"[x]\") : s.mdListUnchecked(\"[ ]\")} ${row}`\n })\n if (opts.action !== false)\n select.withActions({\n \"picker.toggle\": {\n desc: \"Toggle item\",\n fn: () => {\n const active = select.item\n if (!active) return\n active.enabled = !active.enabled\n select.invalidate()\n },\n keys: [\"tab\", \"enter\"],\n priority: 10,\n },\n })\n }\n\n close(opts: { all?: boolean } = {}) {\n while (this.#active.length > 0) {\n const node = this.#active.pop()!\n this.#ui.close(node)\n if (!opts.all) break\n }\n }\n\n get active() {\n return this.#active.at(-1)\n }\n\n suspend() {\n this.active?.hide()\n }\n\n resume() {\n this.active?.show()\n }\n\n async pick<T extends Option = Option>(opts: PickOpts<T>): Promise<T | undefined> {\n this.active?.hide()\n const res = Promise.withResolvers<T | undefined>()\n let settled = false\n const clear = opts.clearInput ?? true\n const restore = opts.restoreInput ?? true\n const prevInput = clear ? this.#input.consume().value : undefined\n const ref = opts.ref ?? createRef<Select<T>>()\n const node = this.#ui.open(() => this.#pick({ ...opts, input: this.#input, ref }))\n this.#active.push(node)\n this.#open.set(true)\n const select = ref()\n\n const ac = new AbortController()\n const done = (value?: T) => {\n if (settled) return\n settled = true\n ac.abort()\n this.#active = this.#active.filter((n) => n !== node)\n if (restore && prevInput !== undefined) this.#input.replace(prevInput)\n else if (!restore) this.#input.consume()\n res.resolve(value)\n this.#ui.close(node)\n this.active?.show()\n this.#open.set(this.#active.length > 0)\n }\n\n node.once(\"unmount\", () => done(), { signal: ac.signal })\n select.once(\"close\", () => done(), { signal: ac.signal })\n select.once(\"accept\", ({ item }) => done(item), { signal: ac.signal })\n select.once(\"complete\", ({ item }) => done(item), { signal: ac.signal })\n\n return res.promise\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { C as OverlaySurface, Q as Accessor } from "../queries-DH3bj74K.mjs";
|
|
2
|
+
import { t as Input } from "../input-B5Vy-iaa.mjs";
|
|
3
|
+
import { n as PickerItem } from "../picker-D8OLb6kZ.mjs";
|
|
4
|
+
import { Widget } from "../widgets/widget.mjs";
|
|
5
|
+
//#region src/services/prompt.d.ts
|
|
6
|
+
type ToggleItem = PickerItem & {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
type PromptOpts = {
|
|
10
|
+
title?: string;
|
|
11
|
+
details?: Widget | string;
|
|
12
|
+
clearInput?: boolean;
|
|
13
|
+
restoreInput?: boolean;
|
|
14
|
+
};
|
|
15
|
+
type PromptEvents = {
|
|
16
|
+
close: {};
|
|
17
|
+
submit: {
|
|
18
|
+
value: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
declare class Prompt {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(ui: OverlaySurface, input: Input);
|
|
24
|
+
get isOpen(): Accessor<boolean>;
|
|
25
|
+
close(): void;
|
|
26
|
+
open(msg: string | PromptOpts): Promise<string | undefined>;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Prompt, PromptEvents, PromptOpts, ToggleItem };
|
|
30
|
+
//# sourceMappingURL=prompt.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.mts","names":[],"sources":["../../src/services/prompt.ts"],"mappings":";;;;;KAcY,aAAa;EAAe;;KAE5B;EACV;EACA,UAAU;EACV;EACA;;KAGU;EACV;EACA;IAAU;;;cAGC;;EAMX,YAAY,IAAI,gBAAgB,OAAO;MAKnC,UALmC;EA+CvC;EAOM,KAAK,cAAc,aAAa"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { y as signal } from "../reactive-f7NpAi69.mjs";
|
|
2
|
+
import { r as isMarkdown } from "../inspect-D1d9t-ni.mjs";
|
|
3
|
+
import { text } from "../widgets/text.mjs";
|
|
4
|
+
import { markdown } from "../widgets/markdown.mjs";
|
|
5
|
+
import { overlay } from "../widgets/overlay.mjs";
|
|
6
|
+
import { divider } from "../widgets/divider.mjs";
|
|
7
|
+
//#region src/services/prompt.ts
|
|
8
|
+
var Prompt = class {
|
|
9
|
+
#ui;
|
|
10
|
+
#input;
|
|
11
|
+
#open = signal(false);
|
|
12
|
+
#node;
|
|
13
|
+
constructor(ui, input) {
|
|
14
|
+
this.#ui = ui;
|
|
15
|
+
this.#input = input;
|
|
16
|
+
}
|
|
17
|
+
get isOpen() {
|
|
18
|
+
return this.#open.get;
|
|
19
|
+
}
|
|
20
|
+
#overlay(opts) {
|
|
21
|
+
const children = [];
|
|
22
|
+
if (opts.title) children.push(isMarkdown(opts.title) ? markdown(opts.title, { style: "borderTitle" }) : text(opts.title, { style: "borderTitle" }));
|
|
23
|
+
if (opts.details) if (typeof opts.details === "string") children.push(isMarkdown(opts.details) ? markdown(opts.details) : text(opts.details));
|
|
24
|
+
else children.push(opts.details());
|
|
25
|
+
const ret = overlay({
|
|
26
|
+
padding: [0, 1],
|
|
27
|
+
relative: "ui",
|
|
28
|
+
style: "ui",
|
|
29
|
+
verticalAnchor: "bottom",
|
|
30
|
+
x: 0,
|
|
31
|
+
y: 1
|
|
32
|
+
}, divider({ style: "accent" }), ...children).withEvents();
|
|
33
|
+
return ret.withActions({
|
|
34
|
+
"prompt.close": {
|
|
35
|
+
fn: () => void ret.emit("close"),
|
|
36
|
+
keys: ["esc"]
|
|
37
|
+
},
|
|
38
|
+
"prompt.submit": {
|
|
39
|
+
fn: () => void ret.emit("submit", { value: this.#input.state.value ?? "" }),
|
|
40
|
+
keys: ["enter"]
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
close() {
|
|
45
|
+
const node = this.#node;
|
|
46
|
+
if (!node) return;
|
|
47
|
+
this.#ui.close(node);
|
|
48
|
+
this.#node = void 0;
|
|
49
|
+
}
|
|
50
|
+
async open(msg) {
|
|
51
|
+
this.close();
|
|
52
|
+
const opts = typeof msg === "string" ? { title: msg } : msg;
|
|
53
|
+
const res = Promise.withResolvers();
|
|
54
|
+
let settled = false;
|
|
55
|
+
const clear = opts.clearInput ?? true;
|
|
56
|
+
const restore = opts.restoreInput ?? true;
|
|
57
|
+
const prevInput = clear ? this.#input.consume().value : void 0;
|
|
58
|
+
const node = this.#ui.open(() => this.#overlay(opts));
|
|
59
|
+
this.#node = node;
|
|
60
|
+
this.#open.set(true);
|
|
61
|
+
this.#input.addActionTarget(node);
|
|
62
|
+
const ac = new AbortController();
|
|
63
|
+
const done = (value) => {
|
|
64
|
+
if (settled) return;
|
|
65
|
+
settled = true;
|
|
66
|
+
ac.abort();
|
|
67
|
+
this.#input.removeActionTarget(node);
|
|
68
|
+
if (restore && prevInput !== void 0) this.#input.replace(prevInput);
|
|
69
|
+
else if (!restore) this.#input.consume();
|
|
70
|
+
res.resolve(value);
|
|
71
|
+
this.close();
|
|
72
|
+
this.#open.set(false);
|
|
73
|
+
};
|
|
74
|
+
node.once("unmount", () => done(), { signal: ac.signal });
|
|
75
|
+
node.once("close", () => done(), { signal: ac.signal });
|
|
76
|
+
node.once("submit", ({ value }) => done(value), { signal: ac.signal });
|
|
77
|
+
return res.promise;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
//#endregion
|
|
81
|
+
export { Prompt };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=prompt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.mjs","names":["#ui","#input","#open","#node","#overlay"],"sources":["../../src/services/prompt.ts"],"sourcesContent":["import type { Node } from \"../core/node.ts\"\nimport type { OverlaySurface } from \"../renderer/overlay.ts\"\nimport type { Input } from \"../widgets/input.ts\"\nimport type { Overlay } from \"../widgets/overlay.ts\"\nimport type { PickerItem } from \"../widgets/picker.ts\"\nimport type { Widget } from \"../widgets/widget.ts\"\n\nimport { signal } from \"../core/reactive.ts\"\nimport { isMarkdown } from \"../style/inspect.ts\"\nimport { divider } from \"../widgets/divider.ts\"\nimport { markdown } from \"../widgets/markdown.ts\"\nimport { overlay } from \"../widgets/overlay.ts\"\nimport { text } from \"../widgets/text.ts\"\n\nexport type ToggleItem = PickerItem & { enabled?: boolean }\n\nexport type PromptOpts = {\n title?: string\n details?: Widget | string\n clearInput?: boolean\n restoreInput?: boolean\n}\n\nexport type PromptEvents = {\n close: {}\n submit: { value: string }\n}\n\nexport class Prompt {\n #ui: OverlaySurface\n #input: Input\n #open = signal(false)\n #node?: Overlay\n\n constructor(ui: OverlaySurface, input: Input) {\n this.#ui = ui\n this.#input = input\n }\n\n get isOpen() {\n return this.#open.get\n }\n\n #overlay(opts: PromptOpts) {\n const children: Node[] = []\n if (opts.title)\n children.push(\n isMarkdown(opts.title)\n ? markdown(opts.title, { style: \"borderTitle\" })\n : text(opts.title, { style: \"borderTitle\" })\n )\n if (opts.details) {\n if (typeof opts.details === \"string\")\n children.push(isMarkdown(opts.details) ? markdown(opts.details) : text(opts.details))\n else children.push(opts.details())\n }\n\n const ret = overlay(\n {\n padding: [0, 1],\n relative: \"ui\",\n style: \"ui\",\n verticalAnchor: \"bottom\",\n x: 0,\n y: 1,\n },\n divider({ style: \"accent\" }),\n ...children\n ).withEvents<PromptEvents>()\n return ret.withActions({\n \"prompt.close\": {\n fn: () => void ret.emit(\"close\"),\n keys: [\"esc\"],\n },\n \"prompt.submit\": {\n fn: () => void ret.emit(\"submit\", { value: this.#input.state.value ?? \"\" }),\n keys: [\"enter\"],\n },\n })\n }\n\n close() {\n const node = this.#node\n if (!node) return\n this.#ui.close(node)\n this.#node = undefined\n }\n\n async open(msg: string | PromptOpts): Promise<string | undefined> {\n this.close()\n const opts = typeof msg === \"string\" ? { title: msg } : msg\n const res = Promise.withResolvers<string | undefined>()\n let settled = false\n const clear = opts.clearInput ?? true\n const restore = opts.restoreInput ?? true\n const prevInput = clear ? this.#input.consume().value : undefined\n const node = this.#ui.open(() => this.#overlay(opts))\n this.#node = node\n this.#open.set(true)\n this.#input.addActionTarget(node)\n\n const ac = new AbortController()\n const done = (value?: string) => {\n if (settled) return\n settled = true\n ac.abort()\n this.#input.removeActionTarget(node)\n if (restore && prevInput !== undefined) this.#input.replace(prevInput)\n else if (!restore) this.#input.consume()\n res.resolve(value)\n this.close()\n this.#open.set(false)\n }\n\n node.once(\"unmount\", () => done(), { signal: ac.signal })\n node.once(\"close\", () => done(), { signal: ac.signal })\n node.once(\"submit\", ({ value }) => done(value), { signal: ac.signal })\n\n return res.promise\n }\n}\n"],"mappings":";;;;;;;AA4BA,IAAa,SAAb,MAAoB;CAClB;CACA;CACA,QAAQ,OAAO,KAAK;CACpB;CAEA,YAAY,IAAoB,OAAc;EAC5C,KAAKA,MAAM;EACX,KAAKC,SAAS;CAChB;CAEA,IAAI,SAAS;EACX,OAAO,KAAKC,MAAM;CACpB;CAEA,SAAS,MAAkB;EACzB,MAAM,WAAmB,CAAC;EAC1B,IAAI,KAAK,OACP,SAAS,KACP,WAAW,KAAK,KAAK,IACjB,SAAS,KAAK,OAAO,EAAE,OAAO,cAAc,CAAC,IAC7C,KAAK,KAAK,OAAO,EAAE,OAAO,cAAc,CAAC,CAC/C;EACF,IAAI,KAAK,SACP,IAAI,OAAO,KAAK,YAAY,UAC1B,SAAS,KAAK,WAAW,KAAK,OAAO,IAAI,SAAS,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO,CAAC;OACjF,SAAS,KAAK,KAAK,QAAQ,CAAC;EAGnC,MAAM,MAAM,QACV;GACE,SAAS,CAAC,GAAG,CAAC;GACd,UAAU;GACV,OAAO;GACP,gBAAgB;GAChB,GAAG;GACH,GAAG;EACL,GACA,QAAQ,EAAE,OAAO,SAAS,CAAC,GAC3B,GAAG,QACL,CAAC,CAAC,WAAyB;EAC3B,OAAO,IAAI,YAAY;GACrB,gBAAgB;IACd,UAAU,KAAK,IAAI,KAAK,OAAO;IAC/B,MAAM,CAAC,KAAK;GACd;GACA,iBAAiB;IACf,UAAU,KAAK,IAAI,KAAK,UAAU,EAAE,OAAO,KAAKD,OAAO,MAAM,SAAS,GAAG,CAAC;IAC1E,MAAM,CAAC,OAAO;GAChB;EACF,CAAC;CACH;CAEA,QAAQ;EACN,MAAM,OAAO,KAAKE;EAClB,IAAI,CAAC,MAAM;EACX,KAAKH,IAAI,MAAM,IAAI;EACnB,KAAKG,QAAQ,KAAA;CACf;CAEA,MAAM,KAAK,KAAuD;EAChE,KAAK,MAAM;EACX,MAAM,OAAO,OAAO,QAAQ,WAAW,EAAE,OAAO,IAAI,IAAI;EACxD,MAAM,MAAM,QAAQ,cAAkC;EACtD,IAAI,UAAU;EACd,MAAM,QAAQ,KAAK,cAAc;EACjC,MAAM,UAAU,KAAK,gBAAgB;EACrC,MAAM,YAAY,QAAQ,KAAKF,OAAO,QAAQ,CAAC,CAAC,QAAQ,KAAA;EACxD,MAAM,OAAO,KAAKD,IAAI,WAAW,KAAKI,SAAS,IAAI,CAAC;EACpD,KAAKD,QAAQ;EACb,KAAKD,MAAM,IAAI,IAAI;EACnB,KAAKD,OAAO,gBAAgB,IAAI;EAEhC,MAAM,KAAK,IAAI,gBAAgB;EAC/B,MAAM,QAAQ,UAAmB;GAC/B,IAAI,SAAS;GACb,UAAU;GACV,GAAG,MAAM;GACT,KAAKA,OAAO,mBAAmB,IAAI;GACnC,IAAI,WAAW,cAAc,KAAA,GAAW,KAAKA,OAAO,QAAQ,SAAS;QAChE,IAAI,CAAC,SAAS,KAAKA,OAAO,QAAQ;GACvC,IAAI,QAAQ,KAAK;GACjB,KAAK,MAAM;GACX,KAAKC,MAAM,IAAI,KAAK;EACtB;EAEA,KAAK,KAAK,iBAAiB,KAAK,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;EACxD,KAAK,KAAK,eAAe,KAAK,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;EACtD,KAAK,KAAK,WAAW,EAAE,YAAY,KAAK,KAAK,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;EAErE,OAAO,IAAI;CACb;AACF"}
|