@textui/widgets 0.1.0 → 0.3.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.
- package/README.md +17 -15
- package/dist/control/checkbox.d.ts +2 -0
- package/dist/control/checkbox.d.ts.map +1 -1
- package/dist/control/checkbox.js +2 -2
- package/dist/control/radio-group.d.ts +2 -0
- package/dist/control/radio-group.d.ts.map +1 -1
- package/dist/control/radio-group.js +2 -2
- package/dist/control/text-area.d.ts +15 -2
- package/dist/control/text-area.d.ts.map +1 -1
- package/dist/control/text-area.js +402 -22
- package/dist/control/text-input.d.ts.map +1 -1
- package/dist/control/text-input.js +40 -0
- package/dist/data/feed.d.ts +14 -0
- package/dist/data/feed.d.ts.map +1 -1
- package/dist/data/feed.js +88 -4
- package/dist/data/list.d.ts +60 -7
- package/dist/data/list.d.ts.map +1 -1
- package/dist/data/list.js +66 -10
- package/dist/data/markdown-view.d.ts.map +1 -1
- package/dist/data/markdown-view.js +49 -0
- package/dist/data/shared.d.ts +18 -1
- package/dist/data/shared.d.ts.map +1 -1
- package/dist/data/shared.js +12 -2
- package/dist/display/color-text.d.ts +158 -0
- package/dist/display/color-text.d.ts.map +1 -0
- package/dist/display/color-text.js +246 -0
- package/dist/display/index.d.ts +1 -0
- package/dist/display/index.d.ts.map +1 -1
- package/dist/display/index.js +3 -0
- package/dist/layout/divider.d.ts +6 -1
- package/dist/layout/divider.d.ts.map +1 -1
- package/dist/layout/divider.js +5 -5
- package/dist/layout/scroll-view.d.ts +10 -0
- package/dist/layout/scroll-view.d.ts.map +1 -1
- package/dist/layout/scroll-view.js +2 -2
- package/dist/navigation/menu.d.ts +24 -0
- package/dist/navigation/menu.d.ts.map +1 -1
- package/dist/navigation/menu.js +58 -15
- package/dist/overlay/command-palette.d.ts +32 -1
- package/dist/overlay/command-palette.d.ts.map +1 -1
- package/dist/overlay/command-palette.js +84 -10
- package/dist/shells/workbench-shell.d.ts.map +1 -1
- package/dist/shells/workbench-shell.js +22 -2
- package/package.json +8 -8
- package/src/control/checkbox.ts +4 -2
- package/src/control/radio-group.ts +4 -2
- package/src/control/text-area.ts +394 -31
- package/src/control/text-input.ts +38 -1
- package/src/data/feed.ts +102 -3
- package/src/data/list.ts +125 -18
- package/src/data/markdown-view.ts +56 -0
- package/src/data/shared.ts +25 -3
- package/src/display/color-text.ts +386 -0
- package/src/display/index.ts +3 -0
- package/src/layout/divider.ts +15 -7
- package/src/layout/scroll-view.ts +12 -2
- package/src/navigation/menu.ts +89 -14
- package/src/overlay/command-palette.ts +125 -11
- package/src/shells/workbench-shell.ts +22 -3
package/dist/data/feed.js
CHANGED
|
@@ -19,7 +19,7 @@ import { FeedEntry, FeedScrollbar } from './shared.js';
|
|
|
19
19
|
* list of things that are not one line tall".
|
|
20
20
|
*/
|
|
21
21
|
export const Feed = defineComponent('Feed', (props) => {
|
|
22
|
-
const { children, follow: followProp, onFollowChange, selectedIndex, onSelect, onActivate, scrollbar = true, focusable = true, autoFocus, focusId, id, ...rest } = props;
|
|
22
|
+
const { children, follow: followProp, onFollowChange, selectedIndex, onSelect, onActivate, pageKeys = 'focused', scrollbar = true, focusable = true, autoFocus, focusId, id, ...rest } = props;
|
|
23
23
|
const focus = useFocus({
|
|
24
24
|
...(focusId ? { id: focusId } : {}),
|
|
25
25
|
disabled: !focusable,
|
|
@@ -28,6 +28,20 @@ export const Feed = defineComponent('Feed', (props) => {
|
|
|
28
28
|
const measured = useMeasure();
|
|
29
29
|
const extent = useScrollExtent();
|
|
30
30
|
const heights = useRef([]);
|
|
31
|
+
/**
|
|
32
|
+
* The width those heights were measured at.
|
|
33
|
+
*
|
|
34
|
+
* A height is a statement about a width - what a paragraph wrapped to in a
|
|
35
|
+
* pane this wide - so a resize does not make them stale, it makes them
|
|
36
|
+
* about a layout that no longer exists. Kept and compared rather than
|
|
37
|
+
* ignored, because the alternative is a feed that scrolls to the wrong
|
|
38
|
+
* place for ever after the window is dragged.
|
|
39
|
+
*/
|
|
40
|
+
const heightsAt = useRef(-1);
|
|
41
|
+
/** One handler for every entry, so an entry's props do not change with it. */
|
|
42
|
+
const report = useRef((index, height) => {
|
|
43
|
+
heights.current[index] = height;
|
|
44
|
+
});
|
|
31
45
|
// The catalog's rule, and this has to follow it like every other viewport:
|
|
32
46
|
// given `flex`, a `height`, a `maxHeight` or a `basis`, the layout decided
|
|
33
47
|
// the size and the feed fills it and scrolls; given none of those, the
|
|
@@ -41,7 +55,17 @@ export const Feed = defineComponent('Feed', (props) => {
|
|
|
41
55
|
// is how a log ends up frozen three lines from the bottom.
|
|
42
56
|
const [internalTop, setInternalTop] = useState(null);
|
|
43
57
|
const [internalIndex, setInternalIndex] = useState(0);
|
|
44
|
-
|
|
58
|
+
/*
|
|
59
|
+
* Flattened, because a feed counts entries and JSX groups them.
|
|
60
|
+
*
|
|
61
|
+
* `{caption}{items.map(...)}` arrives as `[caption, [a, b, c]]` - two
|
|
62
|
+
* children, one of which is an array - so a feed of twenty entries with
|
|
63
|
+
* anything written beside the map counted two. The cursor then clamped to
|
|
64
|
+
* the second, every key after the first did nothing, and the scroll never
|
|
65
|
+
* moved. It reads as a dead list and is an arity bug.
|
|
66
|
+
*/
|
|
67
|
+
const entries = (Array.isArray(children) ? children.flat(Infinity) : [children])
|
|
68
|
+
.filter((c) => c != null);
|
|
45
69
|
const count = entries.length;
|
|
46
70
|
const selects = onSelect !== undefined || selectedIndex !== undefined;
|
|
47
71
|
const index = Math.max(0, Math.min(count - 1, selectedIndex ?? internalIndex));
|
|
@@ -143,10 +167,70 @@ export const Feed = defineComponent('Feed', (props) => {
|
|
|
143
167
|
default: return false;
|
|
144
168
|
}
|
|
145
169
|
}, { focusId: focus.id, enabled: focusable });
|
|
170
|
+
/*
|
|
171
|
+
* The page keys, from wherever the keyboard happens to be.
|
|
172
|
+
*
|
|
173
|
+
* `global` handlers run only after the focused node has declined the key,
|
|
174
|
+
* so a field that pages its own content still keeps them - this is the one
|
|
175
|
+
* that catches what nothing else wanted.
|
|
176
|
+
*/
|
|
177
|
+
useInput((event) => {
|
|
178
|
+
if (event.name !== 'pageup' && event.name !== 'pagedown')
|
|
179
|
+
return false;
|
|
180
|
+
if (chorded(event))
|
|
181
|
+
return false;
|
|
182
|
+
const page = Math.max(1, measured.height - 2);
|
|
183
|
+
scrollTo(event.name === 'pageup' ? top - page : top + page);
|
|
184
|
+
return true;
|
|
185
|
+
}, { global: true, enabled: pageKeys === 'always' });
|
|
186
|
+
if (measured.width !== heightsAt.current) {
|
|
187
|
+
heightsAt.current = measured.width;
|
|
188
|
+
heights.current = [];
|
|
189
|
+
}
|
|
190
|
+
/*
|
|
191
|
+
* Which entries are far enough away not to be worth drawing.
|
|
192
|
+
*
|
|
193
|
+
* A feed lays out every entry it holds, and laying one out means wrapping
|
|
194
|
+
* its text - so a viewport thirty rows tall over a transcript of six
|
|
195
|
+
* hundred entries spent every frame measuring the five hundred and seventy
|
|
196
|
+
* nobody can see. That cost is paid per *frame*, not per change: a
|
|
197
|
+
* keystroke in a field elsewhere on the screen, a caret blinking, a
|
|
198
|
+
* spinner. It is why a long conversation is heavy to type into and a short
|
|
199
|
+
* one is not.
|
|
200
|
+
*
|
|
201
|
+
* An entry is skipped only once it has been measured, which is what keeps
|
|
202
|
+
* this honest: the first frame draws everything and learns every height,
|
|
203
|
+
* and from then on the ones outside the window are replaced by a box of
|
|
204
|
+
* exactly the height they had. Nothing is estimated, so the extent, the
|
|
205
|
+
* scrollbar and the position of every entry are what they would have been
|
|
206
|
+
* had all of them been drawn.
|
|
207
|
+
*
|
|
208
|
+
* A screenful either side, so scrolling and paging land on something that
|
|
209
|
+
* is already there rather than on a frame of blanks.
|
|
210
|
+
*/
|
|
211
|
+
const view = Math.max(1, measured.height);
|
|
212
|
+
const skipped = [];
|
|
213
|
+
{
|
|
214
|
+
let y = 0;
|
|
215
|
+
for (let i = 0; i < count; i++) {
|
|
216
|
+
const height = heights.current[i];
|
|
217
|
+
// Zero is not a height that has been learned, whatever wrote it: an
|
|
218
|
+
// entry standing in for itself at nothing tall is one that can never
|
|
219
|
+
// be drawn again to find out how tall it is.
|
|
220
|
+
if (height === undefined || height <= 0) {
|
|
221
|
+
skipped[i] = false;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
skipped[i] = fills && (y + height < top - view || y > top + view + view);
|
|
225
|
+
y += height;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
146
228
|
const drawn = entries.map((entry, i) => h(FeedEntry, {
|
|
147
229
|
key: i,
|
|
148
|
-
|
|
149
|
-
|
|
230
|
+
index: i,
|
|
231
|
+
onHeight: report.current,
|
|
232
|
+
...(skipped[i] ? { placeholder: true, height: heights.current[i] } : {}),
|
|
233
|
+
}, skipped[i] ? null : entry));
|
|
150
234
|
// Content-sized: draw everything and let the box grow. Clamping to a
|
|
151
235
|
// measurement here would clamp to how tall this happened to be last frame,
|
|
152
236
|
// which for a box sized *by* its own content is nothing at all - the entries
|
package/dist/data/list.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BoxProps, SemanticVariant } from '@textui/core';
|
|
1
|
+
import type { BoxProps, RenderOutput, SemanticVariant } from '@textui/core';
|
|
2
2
|
export interface ListItem {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
@@ -8,15 +8,38 @@ export interface ListItem {
|
|
|
8
8
|
meta?: string;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/** How a row stands at the moment it is asked to draw itself. */
|
|
12
|
+
export interface ListItemState {
|
|
13
|
+
/** The row the selection is on. */
|
|
14
|
+
selected: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* ...and the list itself has the keyboard.
|
|
17
|
+
*
|
|
18
|
+
* Both, and not one: a selected row in a list that has lost focus is a
|
|
19
|
+
* *remembered* choice, and drawing it as loudly as a live one makes two
|
|
20
|
+
* panes look like they both have the cursor.
|
|
21
|
+
*/
|
|
22
|
+
focused: boolean;
|
|
23
|
+
disabled: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface ListProps<T extends ListItem = ListItem> extends BoxProps {
|
|
26
|
+
/**
|
|
27
|
+
* The rows.
|
|
28
|
+
*
|
|
29
|
+
* `T` is whatever the caller's own row type is, so long as it is a
|
|
30
|
+
* `ListItem` - which is what the built-in row needs and what `id` being the
|
|
31
|
+
* selection's name needs. Passing plain `ListItem`s is the ordinary case and
|
|
32
|
+
* `T` costs nothing there; a caller with a `renderItem` gets its own fields
|
|
33
|
+
* back on the way in rather than a lookup by id.
|
|
34
|
+
*/
|
|
35
|
+
items: T[];
|
|
13
36
|
selectedId?: string;
|
|
14
|
-
onSelect?(id: string, item:
|
|
15
|
-
onActivate?(id: string, item:
|
|
37
|
+
onSelect?(id: string, item: T): void;
|
|
38
|
+
onActivate?(id: string, item: T): void;
|
|
16
39
|
/** Rows visible at once. Scrolls when there are more. */
|
|
17
40
|
visibleRows?: number;
|
|
18
41
|
emptyMessage?: string;
|
|
19
|
-
/** Draw a marker column for the selected row. */
|
|
42
|
+
/** Draw a marker column for the selected row. Drawn either way. */
|
|
20
43
|
marker?: boolean;
|
|
21
44
|
focusable?: boolean;
|
|
22
45
|
autoFocus?: boolean;
|
|
@@ -26,6 +49,36 @@ export interface ListProps extends BoxProps {
|
|
|
26
49
|
* nothing outside the render can know.
|
|
27
50
|
*/
|
|
28
51
|
focusId?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Draw one row's contents.
|
|
54
|
+
*
|
|
55
|
+
* The built-in row - icon, title, description, meta, on one line - is the
|
|
56
|
+
* shape most catalogues are, and it is what you get by leaving this alone.
|
|
57
|
+
* The moment a caller wants a different one, the repair is *not* another
|
|
58
|
+
* field on `ListItem` and another flag saying where to put it: that road
|
|
59
|
+
* ends with a component whose props are a small layout language, and it
|
|
60
|
+
* still cannot draw the row after next.
|
|
61
|
+
*
|
|
62
|
+
* So the row is the caller's, and everything a row cannot do for itself
|
|
63
|
+
* stays here: the selection, the keys that move it, the window that scrolls,
|
|
64
|
+
* the highlight, the marker column and the click. `state` is what the row
|
|
65
|
+
* cannot know - whether it is the selected one, and whether that selection
|
|
66
|
+
* is live.
|
|
67
|
+
*
|
|
68
|
+
* A row taller than one line has to say so with `itemHeight`.
|
|
69
|
+
*/
|
|
70
|
+
renderItem?(item: T, state: ListItemState): RenderOutput;
|
|
71
|
+
/**
|
|
72
|
+
* Lines one row occupies, when `renderItem` draws more than one.
|
|
73
|
+
*
|
|
74
|
+
* The list scrolls by arithmetic rather than by measurement - it decides how
|
|
75
|
+
* many rows fit *before* anything is drawn, which is the only way a thousand
|
|
76
|
+
* rows cost the same as ten. That arithmetic is in lines, so a row that is
|
|
77
|
+
* two of them has to be declared, not discovered.
|
|
78
|
+
*/
|
|
79
|
+
itemHeight?: number;
|
|
29
80
|
}
|
|
30
|
-
|
|
81
|
+
declare function ListView<T extends ListItem>(props: ListProps<T>): RenderOutput;
|
|
82
|
+
export declare const List: typeof ListView;
|
|
83
|
+
export {};
|
|
31
84
|
//# sourceMappingURL=list.d.ts.map
|
package/dist/data/list.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/data/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/data/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAgB5E,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,QAAQ;IACxE;;;;;;;;OAQG;IACH,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACrC,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACvC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,GAAG,YAAY,CAAC;IACzD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,iBAAS,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,YAAY,CA+HvE;AAED,eAAO,MAAM,IAAI,EAA8E,OAAO,QAAQ,CAAC"}
|
package/dist/data/list.js
CHANGED
|
@@ -2,9 +2,9 @@ import { chorded, defineComponent, h, useFocus, useInput, useMeasure, useState,
|
|
|
2
2
|
import { EmptyState } from '../display/index.js';
|
|
3
3
|
import { TONE } from '../tone.js';
|
|
4
4
|
import { viewportRows } from '../viewport.js';
|
|
5
|
-
|
|
5
|
+
function ListView(props) {
|
|
6
6
|
const theme = useTheme();
|
|
7
|
-
const { items, selectedId, onSelect, onActivate, visibleRows, emptyMessage = 'Nothing here', marker = true, focusable = true, autoFocus, focusId, ...rest } = props;
|
|
7
|
+
const { items, selectedId, onSelect, onActivate, visibleRows, emptyMessage = 'Nothing here', marker = true, focusable = true, autoFocus, focusId, renderItem, itemHeight = 1, ...rest } = props;
|
|
8
8
|
const focus = useFocus({
|
|
9
9
|
...(focusId ? { id: focusId } : {}),
|
|
10
10
|
disabled: !focusable,
|
|
@@ -13,7 +13,20 @@ export const List = defineComponent('List', (props) => {
|
|
|
13
13
|
const measured = useMeasure();
|
|
14
14
|
const [internalId, setInternalId] = useState(items.find((i) => !i.disabled)?.id ?? null);
|
|
15
15
|
const currentId = selectedId ?? internalId;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* How many *rows* fit, when what was measured is lines.
|
|
18
|
+
*
|
|
19
|
+
* `visibleRows` is already a count of rows, so it stands as given. Anything
|
|
20
|
+
* else comes from the space the list was handed, and a two-line row buys
|
|
21
|
+
* half as many of them.
|
|
22
|
+
*/
|
|
23
|
+
const lines = Math.max(1, itemHeight);
|
|
24
|
+
const fit = (content) => {
|
|
25
|
+
if (visibleRows !== undefined)
|
|
26
|
+
return Math.max(1, visibleRows);
|
|
27
|
+
return Math.max(1, Math.floor(viewportRows(props, measured, content * lines) / lines));
|
|
28
|
+
};
|
|
29
|
+
const pageSize = fit(10);
|
|
17
30
|
const index = Math.max(0, items.findIndex((i) => i.id === currentId));
|
|
18
31
|
/**
|
|
19
32
|
* Move to `target`, skipping past anything unselectable on the way.
|
|
@@ -73,11 +86,20 @@ export const List = defineComponent('List', (props) => {
|
|
|
73
86
|
// Unstated, the row count comes from the space the list was given rather
|
|
74
87
|
// than from how many items it holds - a thousand-row list must not decide
|
|
75
88
|
// how tall its own pane is.
|
|
76
|
-
const rows =
|
|
89
|
+
const rows = fit(items.length);
|
|
77
90
|
const start = Math.max(0, Math.min(index - Math.floor(rows / 2), items.length - rows));
|
|
78
91
|
const window = items.slice(start, start + rows);
|
|
79
92
|
return h('box', { id: focus.id, role: 'list', direction: 'column', ...rest }, ...window.map((item) => {
|
|
80
93
|
const active = item.id === currentId;
|
|
94
|
+
const state = {
|
|
95
|
+
selected: active,
|
|
96
|
+
focused: focus.focused,
|
|
97
|
+
disabled: item.disabled === true,
|
|
98
|
+
};
|
|
99
|
+
// `item.id` is the key as well as the selection's name, and deliberately
|
|
100
|
+
// the same string: a row that reconciled under one identity while the
|
|
101
|
+
// selection pointed at another would be a highlight on the wrong row,
|
|
102
|
+
// and no amount of looking at either one would show why.
|
|
81
103
|
return h('box', {
|
|
82
104
|
key: item.id,
|
|
83
105
|
role: 'listitem',
|
|
@@ -85,6 +107,9 @@ export const List = defineComponent('List', (props) => {
|
|
|
85
107
|
selected: active,
|
|
86
108
|
direction: 'row',
|
|
87
109
|
gap: 1,
|
|
110
|
+
// One background over the whole row, however many lines it draws: a
|
|
111
|
+
// highlight that stopped after the first would split the row it is
|
|
112
|
+
// highlighting in two.
|
|
88
113
|
bg: active && focus.focused ? 'selected' : active ? 'active' : undefined,
|
|
89
114
|
fg: item.disabled ? 'disabled' : active && focus.focused ? 'inverted' : undefined,
|
|
90
115
|
onClick: () => {
|
|
@@ -94,11 +119,42 @@ export const List = defineComponent('List', (props) => {
|
|
|
94
119
|
setInternalId(item.id);
|
|
95
120
|
onSelect?.(item.id, item);
|
|
96
121
|
},
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
|
|
122
|
+
},
|
|
123
|
+
// The marker stays here even when the contents are the caller's. It
|
|
124
|
+
// belongs to the selection rather than to the row, and a column that
|
|
125
|
+
// every row has to remember to draw is a column that goes crooked.
|
|
126
|
+
marker
|
|
127
|
+
? h('text', { content: active ? theme.glyphs.chevronRight : ' ', shrink: 0 })
|
|
128
|
+
: null, ...(renderItem
|
|
129
|
+
? [h('box', { direction: 'column', flex: 1 }, renderItem(item, state))]
|
|
130
|
+
: defaultRow(item, active)));
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
export const List = defineComponent('List', ListView);
|
|
134
|
+
/**
|
|
135
|
+
* The row you get for free: an icon, a title, an elaboration, a state.
|
|
136
|
+
*
|
|
137
|
+
* One line, because a list of a thousand of them has to cost what a list of
|
|
138
|
+
* ten does, and because most catalogues are exactly this. Anything else is
|
|
139
|
+
* `renderItem`.
|
|
140
|
+
*/
|
|
141
|
+
function defaultRow(item, active) {
|
|
142
|
+
return [
|
|
143
|
+
item.icon ? h('text', { content: item.icon, fg: item.tone ? TONE[item.tone] : undefined }) : null,
|
|
144
|
+
h('text', { content: item.label, flex: 1, truncate: 'end' }),
|
|
100
145
|
// The secondary columns keep the row's colour once it is selected;
|
|
101
146
|
// `muted` on a selected background is unreadable.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
147
|
+
//
|
|
148
|
+
// The description yields first, and by a lot: it is the elaboration,
|
|
149
|
+
// and a row reading "brb_fram…" beside a status cut to "waiting on y…"
|
|
150
|
+
// has spent the width on the wrong two things. `meta` gives up none of
|
|
151
|
+
// it - a status is three words at most, and it is the column the row
|
|
152
|
+
// is being scanned for.
|
|
153
|
+
item.description
|
|
154
|
+
? h('text', { content: item.description, fg: active ? undefined : 'muted', truncate: 'end', shrink: 8 })
|
|
155
|
+
: null,
|
|
156
|
+
item.meta
|
|
157
|
+
? h('text', { content: item.meta, fg: active ? undefined : 'muted', shrink: 0 })
|
|
158
|
+
: null,
|
|
159
|
+
];
|
|
160
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-view.d.ts","sourceRoot":"","sources":["../../src/data/markdown-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAA0C,MAAM,cAAc,CAAC;AAclG,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrB,+EAA+E;IAC/E,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"markdown-view.d.ts","sourceRoot":"","sources":["../../src/data/markdown-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAA0C,MAAM,cAAc,CAAC;AAclG,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrB,+EAA+E;IAC/E,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,mEA8KvB,CAAC"}
|
|
@@ -24,6 +24,9 @@ export const MarkdownView = defineComponent('MarkdownView', (props) => {
|
|
|
24
24
|
bullet: theme.glyphs.bulletFilled,
|
|
25
25
|
quoteBar: theme.borderChars().left,
|
|
26
26
|
ruled,
|
|
27
|
+
// How many rules a table gets is the theme's, but *where* they go is a
|
|
28
|
+
// question about rows, so it is answered in the layout rather than here.
|
|
29
|
+
tableRules: theme.tableRules,
|
|
27
30
|
}), [given, content, width, theme, ruled]);
|
|
28
31
|
const first = slice?.first ?? 0;
|
|
29
32
|
const shown = slice ? laid.slice(first, first + slice.count) : laid;
|
|
@@ -89,6 +92,52 @@ export const MarkdownView = defineComponent('MarkdownView', (props) => {
|
|
|
89
92
|
i = end;
|
|
90
93
|
continue;
|
|
91
94
|
}
|
|
95
|
+
if (row.kind === 'table') {
|
|
96
|
+
/*
|
|
97
|
+
* A table is ruled even where nothing else is.
|
|
98
|
+
*
|
|
99
|
+
* `theme.border` being `none` is a theme saying "do not box things" -
|
|
100
|
+
* panels, fences, dialogs. It is not saying "do not tell these columns
|
|
101
|
+
* apart": the rules in a table are its structure, not its decoration,
|
|
102
|
+
* and without them it is text that happens to line up, with nothing to
|
|
103
|
+
* say where it ended. So a borderless theme still gets a table, drawn
|
|
104
|
+
* in the plainest set there is.
|
|
105
|
+
*
|
|
106
|
+
* Asked for by name rather than taken from `borderChars()`, which is
|
|
107
|
+
* the same request routed through the terminal's own limits: on a
|
|
108
|
+
* console that cannot draw box characters this comes back as `+`, `-`
|
|
109
|
+
* and `|` rather than as something it would print as a row of boxes.
|
|
110
|
+
*/
|
|
111
|
+
const chars = theme.borderChars(theme.border === 'none' ? 'single' : theme.border);
|
|
112
|
+
const fg = 'borderSubtle';
|
|
113
|
+
if (row.part !== 'head' && row.part !== 'body') {
|
|
114
|
+
const [left, joint, right] = row.part === 'top' ? [chars.topLeft, chars.teeTop, chars.topRight]
|
|
115
|
+
: row.part === 'bottom' ? [chars.bottomLeft, chars.teeBottom, chars.bottomRight]
|
|
116
|
+
: [chars.teeRight, chars.cross, chars.teeLeft];
|
|
117
|
+
const bar = row.part === 'bottom' ? chars.bottom : chars.top;
|
|
118
|
+
// Every column plus the space either side of it, which is what the
|
|
119
|
+
// cell rows spend - an edge measured off the cells alone is an edge
|
|
120
|
+
// two cells short per column.
|
|
121
|
+
out.push(h('text', {
|
|
122
|
+
key,
|
|
123
|
+
content: left
|
|
124
|
+
+ row.widths.map((w) => repeatToWidth(bar, w + 2)).join(joint)
|
|
125
|
+
+ right,
|
|
126
|
+
fg,
|
|
127
|
+
wrap: 'none',
|
|
128
|
+
}));
|
|
129
|
+
i++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// The cells arrive padded to their column, so nothing here measures
|
|
133
|
+
// anything: a row is its cells with a rule between each pair.
|
|
134
|
+
out.push(h('box', { key, direction: 'row', overflow: 'hidden' }, ...row.cells.flatMap((cell, c) => [
|
|
135
|
+
h('text', { key: `s${c}`, content: c === 0 ? `${chars.left} ` : ` ${chars.left} `, fg, wrap: 'none' }),
|
|
136
|
+
h('box', { key: `c${c}`, direction: 'row', overflow: 'hidden' }, ...runNodes(cell, quiet ? { fg: 'muted' } : {})),
|
|
137
|
+
]), h('text', { key: 'end', content: ` ${chars.right}`, fg, wrap: 'none' })));
|
|
138
|
+
i++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
92
141
|
if (row.kind === 'rule') {
|
|
93
142
|
out.push(h('box', { key, height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' }));
|
|
94
143
|
i++;
|
package/dist/data/shared.d.ts
CHANGED
|
@@ -4,9 +4,26 @@ import type { BoxProps } from '@textui/core';
|
|
|
4
4
|
*
|
|
5
5
|
* Through a ref rather than state, deliberately: a height arriving must not
|
|
6
6
|
* schedule a render, or every measurement would cause the next measurement.
|
|
7
|
+
*
|
|
8
|
+
* It reports its `index` to one shared handler rather than taking a closure
|
|
9
|
+
* that already knows it. A closure per entry is a new prop on every entry
|
|
10
|
+
* every time the feed itself re-renders, and a changed prop is a re-render -
|
|
11
|
+
* so a feed that redrew for its own reasons dragged every entry it holds
|
|
12
|
+
* along with it, however little any of them had changed.
|
|
7
13
|
*/
|
|
8
14
|
export declare const FeedEntry: (props: BoxProps & {
|
|
9
|
-
|
|
15
|
+
index: number;
|
|
16
|
+
/**
|
|
17
|
+
* Standing in for an entry that is not drawn, at the height it had.
|
|
18
|
+
*
|
|
19
|
+
* A stand-in must not answer the question it is an answer to. Its height is
|
|
20
|
+
* one the feed already knows - it is where it came from - and reporting it
|
|
21
|
+
* back is how a measurement gets to depend on itself: a round where a
|
|
22
|
+
* stand-in came out any shorter would teach the feed that it *was* shorter,
|
|
23
|
+
* and the next round would place the rest of them on top of each other.
|
|
24
|
+
*/
|
|
25
|
+
placeholder?: boolean;
|
|
26
|
+
onHeight(index: number, height: number): void;
|
|
10
27
|
}) => import("@textui/core").RenderOutput;
|
|
11
28
|
export declare const FeedScrollbar: (props: Record<string, never>) => import("@textui/core").RenderOutput;
|
|
12
29
|
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/data/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/data/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS;WACb,MAAM;IACb;;;;;;;;OAQG;kBACW,OAAO;oBACL,MAAM,UAAU,MAAM,GAAG,IAAI;yCAY9C,CAAC;AAEF,eAAO,MAAM,aAAa,uEAGxB,CAAC"}
|
package/dist/data/shared.js
CHANGED
|
@@ -4,11 +4,21 @@ import { defineComponent, h, useEffect, useMeasure, useTheme } from '@textui/cor
|
|
|
4
4
|
*
|
|
5
5
|
* Through a ref rather than state, deliberately: a height arriving must not
|
|
6
6
|
* schedule a render, or every measurement would cause the next measurement.
|
|
7
|
+
*
|
|
8
|
+
* It reports its `index` to one shared handler rather than taking a closure
|
|
9
|
+
* that already knows it. A closure per entry is a new prop on every entry
|
|
10
|
+
* every time the feed itself re-renders, and a changed prop is a re-render -
|
|
11
|
+
* so a feed that redrew for its own reasons dragged every entry it holds
|
|
12
|
+
* along with it, however little any of them had changed.
|
|
7
13
|
*/
|
|
8
14
|
export const FeedEntry = defineComponent('FeedEntry', (props) => {
|
|
9
|
-
const { onHeight, children, ...rest } = props;
|
|
15
|
+
const { index, placeholder, onHeight, children, ...rest } = props;
|
|
10
16
|
const measured = useMeasure();
|
|
11
|
-
useEffect(() => {
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (placeholder)
|
|
19
|
+
return;
|
|
20
|
+
onHeight(index, measured.height);
|
|
21
|
+
}, [measured.height, placeholder]);
|
|
12
22
|
return h('box', { direction: 'column', ...rest }, children);
|
|
13
23
|
});
|
|
14
24
|
export const FeedScrollbar = defineComponent('FeedScrollbar', () => {
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { CellStyle, Color, RenderContext, StyleColor, TextProps } from '@textui/core';
|
|
2
|
+
/**
|
|
3
|
+
* One cell, as the ink sees it.
|
|
4
|
+
*
|
|
5
|
+
* Both a column and an index, because they are not the same number and which
|
|
6
|
+
* one is wanted depends on the question. `col` is where the cell lands - a
|
|
7
|
+
* wide character advances it by two - so a gradient stays vertical over CJK
|
|
8
|
+
* and emoji. `index` counts graphemes, which is what "the fourth letter"
|
|
9
|
+
* means. Colouring by `index` and painting at `col` is the bug this pair
|
|
10
|
+
* exists to prevent.
|
|
11
|
+
*/
|
|
12
|
+
export interface InkCell {
|
|
13
|
+
/** The grapheme cluster about to be painted. */
|
|
14
|
+
char: string;
|
|
15
|
+
/** Column within the line, in cells. */
|
|
16
|
+
col: number;
|
|
17
|
+
/** Line index, after wrapping. */
|
|
18
|
+
line: number;
|
|
19
|
+
/** Grapheme index within the line. */
|
|
20
|
+
index: number;
|
|
21
|
+
/** Grapheme index within the whole block. */
|
|
22
|
+
offset: number;
|
|
23
|
+
/** Cells in this line. */
|
|
24
|
+
width: number;
|
|
25
|
+
/** Lines in the block. */
|
|
26
|
+
height: number;
|
|
27
|
+
/** Cells in the widest line of the block. */
|
|
28
|
+
blockWidth: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* An ink written as code. Returns a colour, a whole cell style, or nothing.
|
|
32
|
+
*
|
|
33
|
+
* Nothing means "leave this cell to the component's own style", which is what
|
|
34
|
+
* makes an ink that colours one thing - the vowels, the column under the
|
|
35
|
+
* cursor - a two-line function rather than an exhaustive one.
|
|
36
|
+
*/
|
|
37
|
+
export type InkFn = (cell: InkCell, ctx: RenderContext) => StyleColor | CellStyle | undefined;
|
|
38
|
+
/** A ramp between colour stops. */
|
|
39
|
+
export interface GradientInk {
|
|
40
|
+
/** Two or more stops. One stop is a flat colour, none is nothing. */
|
|
41
|
+
gradient: StyleColor[];
|
|
42
|
+
/** Across, down, or corner to corner. */
|
|
43
|
+
axis?: 'x' | 'y' | 'xy';
|
|
44
|
+
/**
|
|
45
|
+
* What the ramp is measured against.
|
|
46
|
+
*
|
|
47
|
+
* `block` is the widest line, so every line of a banner shares one ramp and
|
|
48
|
+
* the colours line up down the block. `line` restarts the ramp on each line,
|
|
49
|
+
* which is what a paragraph of ragged lines wants - under `block` a short
|
|
50
|
+
* line would stop halfway through the ramp and look unfinished.
|
|
51
|
+
*/
|
|
52
|
+
per?: 'block' | 'line';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* What advances the colour.
|
|
56
|
+
*
|
|
57
|
+
* `cell` counts columns, so bands stay vertical across the lines of a block -
|
|
58
|
+
* the reason it is the default. `grapheme` counts every cluster including
|
|
59
|
+
* spaces, `letter` counts only the ones that print, and `word` and `line`
|
|
60
|
+
* are what they say.
|
|
61
|
+
*/
|
|
62
|
+
export type InkUnit = 'cell' | 'grapheme' | 'letter' | 'word' | 'line';
|
|
63
|
+
/** A palette walked in order and repeated. */
|
|
64
|
+
export interface CycleInk {
|
|
65
|
+
cycle: StyleColor[];
|
|
66
|
+
/**
|
|
67
|
+
* How much of the text each colour takes.
|
|
68
|
+
*
|
|
69
|
+
* A number is a fixed run. An array is a repeating pattern of runs, so
|
|
70
|
+
* `[4, 3]` gives four cells of the first colour, three of the second, four
|
|
71
|
+
* of the third, and keeps going in fours and threes.
|
|
72
|
+
*/
|
|
73
|
+
every?: number | number[];
|
|
74
|
+
unit?: InkUnit;
|
|
75
|
+
/**
|
|
76
|
+
* Whether the count carries across a line break. Off by default: a run that
|
|
77
|
+
* restarts on every line keeps the bands of a block aligned, and a run that
|
|
78
|
+
* carries over puts them on a diagonal.
|
|
79
|
+
*/
|
|
80
|
+
continuous?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* How a `ColorText` is coloured.
|
|
84
|
+
*
|
|
85
|
+
* An array is the short spelling of one colour per line. The two object forms
|
|
86
|
+
* are data, so a screen written as JSON can carry them; the function form
|
|
87
|
+
* cannot be serialized and is the escape hatch - the same trade `canvas`
|
|
88
|
+
* makes with `draw`.
|
|
89
|
+
*/
|
|
90
|
+
export type Ink = StyleColor[] | GradientInk | CycleInk | InkFn;
|
|
91
|
+
/**
|
|
92
|
+
* Everything a `text` takes, plus the ink.
|
|
93
|
+
*
|
|
94
|
+
* The same props on purpose: `wrap`, `truncate`, `textAlign` and the style
|
|
95
|
+
* keys all mean here what they mean there, so swapping one for the other is a
|
|
96
|
+
* change of colour and nothing else.
|
|
97
|
+
*/
|
|
98
|
+
export interface ColorTextProps extends TextProps {
|
|
99
|
+
/** Left unset, this is an ordinary block of text. */
|
|
100
|
+
ink?: Ink;
|
|
101
|
+
/**
|
|
102
|
+
* Align the block as one thing, rather than each line on its own.
|
|
103
|
+
*
|
|
104
|
+
* `textAlign` centres every line over its own middle, which is right for
|
|
105
|
+
* prose and shears a picture: five rows of block letters do not have equal
|
|
106
|
+
* widths once the trailing spaces are gone, so each row lands somewhere
|
|
107
|
+
* slightly different and the letters lean. Under this, the whole block is
|
|
108
|
+
* placed once and the lines keep their offsets from each other.
|
|
109
|
+
*
|
|
110
|
+
* Off by default, because that is what `text` does and the two are supposed
|
|
111
|
+
* to mean the same thing by the same prop.
|
|
112
|
+
*/
|
|
113
|
+
alignBlock?: boolean;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Multiline text coloured cell by cell.
|
|
117
|
+
*
|
|
118
|
+
* A `text` takes one colour for the whole run, which is the right answer for
|
|
119
|
+
* nearly everything and no answer at all for the cases where the colour *is*
|
|
120
|
+
* the content - a banner, a ramp across a title, a palette walked down a
|
|
121
|
+
* block of ascii art. This is that case, and only that case: it is still just
|
|
122
|
+
* text, and the alternative to it is a `text` node.
|
|
123
|
+
*
|
|
124
|
+
* It paints on a `canvas`, and the price of the escape hatch is that inherited
|
|
125
|
+
* colour stops here. A cell the ink declines takes this component's own `fg`
|
|
126
|
+
* rather than the one a parent row would have handed a `text`, so a
|
|
127
|
+
* `ColorText` inside something that recolours its children when selected has
|
|
128
|
+
* to be told about it. Everything an ink does paint is unaffected.
|
|
129
|
+
*
|
|
130
|
+
* ```tsx
|
|
131
|
+
* <ColorText ink={{ gradient: ['cyan', 'magenta'] }}>{banner}</ColorText>
|
|
132
|
+
* <ColorText ink={['danger', 'warning', 'success']}>{lines}</ColorText>
|
|
133
|
+
* <ColorText ink={{ cycle: palette, every: [4, 3] }}>{title}</ColorText>
|
|
134
|
+
* <ColorText ink={(cell) => (cell.line === cell.col ? 'accent' : undefined)}>{grid}</ColorText>
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* The colour is decoration and never the message: a 16-colour session flattens
|
|
138
|
+
* a three-stop ramp into a couple of bands, and a piped log loses all of it.
|
|
139
|
+
*/
|
|
140
|
+
export declare const ColorText: (props: ColorTextProps) => import("@textui/core").RenderOutput;
|
|
141
|
+
/**
|
|
142
|
+
* A colour a fraction of the way along a set of stops.
|
|
143
|
+
*
|
|
144
|
+
* Exported because an ink written by hand wants it and the alternative is
|
|
145
|
+
* unpacking colours in application code. `t` outside 0..1 is clamped rather
|
|
146
|
+
* than extrapolated - a ramp has ends.
|
|
147
|
+
*/
|
|
148
|
+
export declare function gradientAt(stops: Color[], t: number): Color;
|
|
149
|
+
/** Two colours mixed. `t` of 0 is `a`, 1 is `b`. Tokens must be resolved first. */
|
|
150
|
+
export declare function blend(a: Color, b: Color, t: number): Color;
|
|
151
|
+
/**
|
|
152
|
+
* An ink in any of its spellings, as the one function paint uses.
|
|
153
|
+
*
|
|
154
|
+
* Exported so a component that paints its own cells - a chart, a viewer with a
|
|
155
|
+
* heat column - can take an `Ink` and mean the same thing by it.
|
|
156
|
+
*/
|
|
157
|
+
export declare function painterOf(ink: Ink | undefined, ctx: RenderContext): (cell: InkCell) => CellStyle | undefined;
|
|
158
|
+
//# sourceMappingURL=color-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-text.d.ts","sourceRoot":"","sources":["../../src/display/color-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAAE,KAAK,EAChB,aAAa,EAAE,UAAU,EAAE,SAAS,EACrC,MAAM,cAAc,CAAC;AAOtB;;;;;;;;;GASG;AACH,MAAM,WAAW,OAAO;IACtB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9F,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,yCAAyC;IACzC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;IACxB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvE,8CAA8C;AAC9C,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,GAAG,GAAG,UAAU,EAAE,GAAG,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,qDAAqD;IACrD,GAAG,CAAC,EAAE,GAAG,CAAC;IACV;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,SAAS,gEAyEpB,CAAC;AAIH;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,CAM3D;AAED,mFAAmF;AACnF,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,GAAG,EAAE,aAAa,GACjB,CAAC,IAAI,EAAE,OAAO,KAAK,SAAS,GAAG,SAAS,CA2D1C"}
|