@tooee/choose 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/choose-filter.d.ts +2 -11
  2. package/dist/choose-filter.d.ts.map +1 -1
  3. package/dist/choose-filter.js +1 -19
  4. package/dist/choose-filter.js.map +1 -1
  5. package/dist/choose-highlighted-text.d.ts +2 -8
  6. package/dist/choose-highlighted-text.d.ts.map +1 -1
  7. package/dist/choose-highlighted-text.js +1 -31
  8. package/dist/choose-highlighted-text.js.map +1 -1
  9. package/dist/choose-list.d.ts +2 -27
  10. package/dist/choose-list.d.ts.map +1 -1
  11. package/dist/choose-list.js +1 -65
  12. package/dist/choose-list.js.map +1 -1
  13. package/dist/choose-store.d.ts +2 -56
  14. package/dist/choose-store.d.ts.map +1 -1
  15. package/dist/choose-store.js +1 -101
  16. package/dist/choose-store.js.map +1 -1
  17. package/dist/choose.d.ts +1 -5
  18. package/dist/choose.d.ts.map +1 -1
  19. package/dist/choose.js +3 -19
  20. package/dist/choose.js.map +1 -1
  21. package/dist/choose.public-contract.typecheck.d.ts +11 -0
  22. package/dist/choose.public-contract.typecheck.d.ts.map +1 -0
  23. package/dist/choose.public-contract.typecheck.js +2 -0
  24. package/dist/choose.public-contract.typecheck.js.map +1 -0
  25. package/dist/fuzzy.d.ts +2 -8
  26. package/dist/fuzzy.d.ts.map +1 -1
  27. package/dist/fuzzy.js +1 -4
  28. package/dist/fuzzy.js.map +1 -1
  29. package/dist/launch.d.ts.map +1 -1
  30. package/dist/launch.js +1 -0
  31. package/dist/launch.js.map +1 -1
  32. package/dist/source.d.ts +1 -4
  33. package/dist/source.d.ts.map +1 -1
  34. package/dist/source.js +1 -25
  35. package/dist/source.js.map +1 -1
  36. package/dist/types.d.ts +1 -21
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/use-choose.d.ts +2 -79
  39. package/dist/use-choose.d.ts.map +1 -1
  40. package/dist/use-choose.js +1 -374
  41. package/dist/use-choose.js.map +1 -1
  42. package/package.json +7 -9
  43. package/src/choose-filter.tsx +2 -55
  44. package/src/choose-highlighted-text.tsx +2 -49
  45. package/src/choose-list.tsx +2 -156
  46. package/src/choose-store.ts +12 -146
  47. package/src/choose.public-contract.typecheck.ts +12 -0
  48. package/src/choose.tsx +15 -35
  49. package/src/fuzzy.ts +2 -13
  50. package/src/launch.tsx +1 -0
  51. package/src/source.ts +1 -36
  52. package/src/types.ts +7 -28
  53. package/src/use-choose.ts +9 -521
@@ -1,49 +1,2 @@
1
- import { Fragment } from "react";
2
- import type { ReactNode } from "react";
3
-
4
- export interface ChooseHighlightedTextProps {
5
- text: string;
6
- positions: number[];
7
- highlightColor: string;
8
- }
9
-
10
- /** Render fuzzy-match characters with one shared segmentation implementation. */
11
- export const ChooseHighlightedText = function ChooseHighlightedText({
12
- text,
13
- positions,
14
- highlightColor,
15
- }: ChooseHighlightedTextProps): ReactNode {
16
- if (positions.length === 0) {
17
- return text;
18
- }
19
-
20
- const positionSet = new Set(positions);
21
- const parts: { text: string; highlighted: boolean }[] = [];
22
- let current = "";
23
- let currentHighlighted = false;
24
-
25
- for (let index = 0; index < text.length; index += 1) {
26
- const highlighted = positionSet.has(index);
27
- if (index === 0) {
28
- current = text[index];
29
- currentHighlighted = highlighted;
30
- } else if (highlighted === currentHighlighted) {
31
- current += text[index];
32
- } else {
33
- parts.push({ highlighted: currentHighlighted, text: current });
34
- current = text[index];
35
- currentHighlighted = highlighted;
36
- }
37
- }
38
- if (current) {
39
- parts.push({ highlighted: currentHighlighted, text: current });
40
- }
41
-
42
- return parts.map(
43
- (part, index): ReactNode => (
44
- <Fragment key={index}>
45
- {part.highlighted ? <span fg={highlightColor}>{part.text}</span> : part.text}
46
- </Fragment>
47
- ),
48
- );
49
- };
1
+ export { ChooseHighlightedText } from "@tooee/renderers";
2
+ export type { ChooseHighlightedTextProps } from "@tooee/renderers";
@@ -1,156 +1,2 @@
1
- import { useEffect, useRef } from "react";
2
- import type { ReactNode } from "react";
3
- import { decodeReactContent } from "@tooee/layout";
4
- import type { ScrollBoxRenderable } from "@opentui/core";
5
- import { useTheme } from "@tooee/themes";
6
- import { ChooseHighlightedText } from "./choose-highlighted-text.js";
7
- import type { FuzzyMatch } from "./fuzzy.js";
8
- import type { ChooseItem } from "./types.js";
9
- import type { UseChooseResult } from "./use-choose.js";
10
-
11
- export interface ChooseItemRenderContext {
12
- item: ChooseItem;
13
- match: FuzzyMatch;
14
- index: number;
15
- originalIndex: number;
16
- positions: number[];
17
- isActive: boolean;
18
- isSelected: boolean;
19
- defaultContent: ReactNode;
20
- }
21
-
22
- export interface ChooseListProps {
23
- choose: UseChooseResult;
24
- /** Fullscreen defaults to activate; picker overlays default to submit. */
25
- rowClick?: "activate" | "submit" | "none";
26
- renderItem?: (context: ChooseItemRenderContext) => ReactNode;
27
- loadingContent?: ReactNode;
28
- errorContent?: (error: string) => ReactNode;
29
- emptyContent?: ReactNode;
30
- /** Mouse guard for visible rows covered by another surface. */
31
- suspended?: boolean;
32
- }
33
-
34
- const ThemedLine = function ThemedLine({
35
- content,
36
- color,
37
- }: {
38
- content: ReactNode;
39
- color: string;
40
- }): ReactNode {
41
- const decoded = decodeReactContent(content);
42
- let rendered: ReactNode = null;
43
- if (decoded.kind === "string") {
44
- rendered = <text content={decoded.value} fg={color} />;
45
- } else if (decoded.kind === "node") {
46
- rendered = decoded.value;
47
- }
48
- return (
49
- <box height={1} style={{ paddingLeft: 2 }}>
50
- {rendered}
51
- </box>
52
- );
53
- };
54
-
55
- const defaultErrorContent = function defaultErrorContent(error: string): ReactNode {
56
- return `Error: ${error}`;
57
- };
58
-
59
- /** Scrollable chooser rows plus loading/error/empty presentation. */
60
- export const ChooseList = function ChooseList({
61
- choose,
62
- rowClick = "activate",
63
- renderItem,
64
- loadingContent = "Loading...",
65
- errorContent = defaultErrorContent,
66
- emptyContent,
67
- suspended,
68
- }: ChooseListProps): ReactNode {
69
- const { theme } = useTheme();
70
- const scrollRef = useRef<ScrollBoxRenderable>(null);
71
- const { state, controller } = choose;
72
- const interactionSuspended = choose.view.suspended || (suspended ?? false);
73
-
74
- useEffect(() => {
75
- const activeMatch = state.matches[state.activeIndex];
76
- if (scrollRef.current && activeMatch !== undefined) {
77
- scrollRef.current.scrollChildIntoView(`choose-item-${activeMatch.originalIndex}`);
78
- }
79
- }, [state.activeIndex, state.matches]);
80
-
81
- return (
82
- <scrollbox ref={scrollRef} style={{ flexGrow: 1 }} focused={false}>
83
- {state.loading && <ThemedLine content={loadingContent} color={theme.textMuted} />}
84
-
85
- {!state.loading && state.error !== null && state.error !== "" && (
86
- <ThemedLine content={errorContent(state.error)} color={theme.error} />
87
- )}
88
-
89
- {!state.loading &&
90
- (state.error?.length ?? 0) === 0 &&
91
- state.matches.length === 0 &&
92
- emptyContent !== null &&
93
- emptyContent !== undefined && <ThemedLine content={emptyContent} color={theme.textMuted} />}
94
-
95
- {state.matches.map((match, index): ReactNode => {
96
- const isActive = index === state.activeIndex;
97
- const isSelected = state.selectedOriginalIndices.has(match.originalIndex);
98
- const defaultContent = (
99
- <text fg={isActive ? theme.primary : theme.text} style={{ flexGrow: 1 }}>
100
- {state.multi && (
101
- <span fg={isSelected ? theme.accent : theme.textMuted}>
102
- {isSelected ? "✓ " : " "}
103
- </span>
104
- )}
105
- {(match.item.icon?.length ?? 0) > 0 && (
106
- <span fg={theme.textMuted}>{`${match.item.icon} `}</span>
107
- )}
108
- <ChooseHighlightedText
109
- text={match.item.text}
110
- positions={match.positions}
111
- highlightColor={theme.warning}
112
- />
113
- {(match.item.description?.length ?? 0) > 0 && (
114
- <span fg={theme.textMuted}>{` ${match.item.description}`}</span>
115
- )}
116
- </text>
117
- );
118
- const context: ChooseItemRenderContext = {
119
- defaultContent,
120
- index,
121
- isActive,
122
- isSelected,
123
- item: match.item,
124
- match,
125
- originalIndex: match.originalIndex,
126
- positions: match.positions,
127
- };
128
-
129
- return (
130
- <box
131
- key={match.originalIndex}
132
- id={`choose-item-${match.originalIndex}`}
133
- flexDirection="row"
134
- backgroundColor={isActive ? theme.backgroundElement : undefined}
135
- style={{ paddingLeft: 1, paddingRight: 1 }}
136
- onMouseDown={(event) => {
137
- if (interactionSuspended || event.button !== 0 || rowClick === "none") {
138
- return;
139
- }
140
- if (rowClick === "submit") {
141
- event.preventDefault();
142
- event.stopPropagation();
143
- controller.setActiveIndex(index);
144
- controller.submit();
145
- } else {
146
- controller.setActiveIndex(index);
147
- }
148
- }}
149
- >
150
- {renderItem ? renderItem(context) : defaultContent}
151
- </box>
152
- );
153
- })}
154
- </scrollbox>
155
- );
156
- };
1
+ export { ChooseList } from "@tooee/renderers";
2
+ export type { ChooseItemRenderContext, ChooseListProps } from "@tooee/renderers";
@@ -1,146 +1,12 @@
1
- import { createStore } from "@xstate/store";
2
- import { fuzzyFilter } from "./fuzzy.js";
3
- import type { FuzzyMatch } from "./fuzzy.js";
4
- import type { ChooseItem } from "./types.js";
5
-
6
- export interface ChooseStoreContext {
7
- items: ChooseItem[];
8
- matches: FuzzyMatch[];
9
- filterQuery: string;
10
- activeIndex: number;
11
- selectedOriginalIndices: ReadonlySet<number>;
12
- loading: boolean;
13
- error: string | null;
14
- requestId: number;
15
- reloadRevision: number;
16
- }
17
-
18
- interface ChooseStoreEventDefinitions {
19
- filterChanged: { query: string };
20
- activeIndexSet: { index: number };
21
- moved: { delta: number };
22
- activeToggled: Record<never, never>;
23
- requestStarted: Record<never, never>;
24
- loadingStarted: { requestId: number };
25
- loadSucceeded: { requestId: number; items: ChooseItem[] };
26
- loadFailed: { requestId: number; error: string };
27
- reloadRequested: Record<never, never>;
28
- }
29
-
30
- export type ChooseStoreEvents = {
31
- [EventName in keyof ChooseStoreEventDefinitions]: ChooseStoreEventDefinitions[EventName];
32
- };
33
-
34
- const replaceItems = function replaceItems(
35
- ctx: ChooseStoreContext,
36
- items: ChooseItem[],
37
- ): ChooseStoreContext {
38
- return {
39
- ...ctx,
40
- activeIndex: 0,
41
- items,
42
- matches: fuzzyFilter(items, ctx.filterQuery),
43
- selectedOriginalIndices: new Set(),
44
- };
45
- };
46
-
47
- const clampActiveIndex = function clampActiveIndex(index: number, matchCount: number): number {
48
- return Math.min(Math.max(0, matchCount - 1), Math.max(0, index));
49
- };
50
-
51
- export const createChooseStore = function createChooseStore(options: {
52
- items?: ChooseItem[];
53
- initialFilter?: string;
54
- loading?: boolean;
55
- }) {
56
- const items = options.items ?? [];
57
- const filterQuery = options.initialFilter ?? "";
58
-
59
- return createStore<ChooseStoreContext, ChooseStoreEvents>({
60
- context: {
61
- activeIndex: 0,
62
- error: null,
63
- filterQuery,
64
- items,
65
- loading: options.loading ?? false,
66
- matches: fuzzyFilter(items, filterQuery),
67
- reloadRevision: 0,
68
- requestId: 0,
69
- selectedOriginalIndices: new Set(),
70
- },
71
- on: {
72
- activeIndexSet: (ctx, event) => {
73
- const activeIndex = clampActiveIndex(event.index, ctx.matches.length);
74
- return activeIndex === ctx.activeIndex ? ctx : { ...ctx, activeIndex };
75
- },
76
- activeToggled: (ctx) => {
77
- const originalIndex = ctx.matches[ctx.activeIndex]?.originalIndex;
78
- if (originalIndex === undefined) {
79
- return ctx;
80
- }
81
- const selectedOriginalIndices = new Set(ctx.selectedOriginalIndices);
82
- if (selectedOriginalIndices.has(originalIndex)) {
83
- selectedOriginalIndices.delete(originalIndex);
84
- } else {
85
- selectedOriginalIndices.add(originalIndex);
86
- }
87
- return { ...ctx, selectedOriginalIndices };
88
- },
89
- filterChanged: (ctx, event) => {
90
- if (event.query === ctx.filterQuery) {
91
- return ctx;
92
- }
93
- return {
94
- ...ctx,
95
- activeIndex: 0,
96
- filterQuery: event.query,
97
- matches: fuzzyFilter(ctx.items, event.query),
98
- };
99
- },
100
- loadFailed: (ctx, event) => {
101
- if (event.requestId !== ctx.requestId) {
102
- return ctx;
103
- }
104
- return {
105
- ...replaceItems(ctx, []),
106
- error: event.error,
107
- loading: false,
108
- };
109
- },
110
- loadSucceeded: (ctx, event) => {
111
- if (event.requestId !== ctx.requestId) {
112
- return ctx;
113
- }
114
- return {
115
- ...replaceItems(ctx, event.items),
116
- error: null,
117
- loading: false,
118
- };
119
- },
120
- loadingStarted: (ctx, event) =>
121
- event.requestId === ctx.requestId && !ctx.loading ? { ...ctx, loading: true } : ctx,
122
- moved: (ctx, event) => {
123
- const activeIndex = clampActiveIndex(ctx.activeIndex + event.delta, ctx.matches.length);
124
- return activeIndex === ctx.activeIndex ? ctx : { ...ctx, activeIndex };
125
- },
126
- reloadRequested: (ctx) => ({ ...ctx, reloadRevision: ctx.reloadRevision + 1 }),
127
- requestStarted: (ctx) => ({
128
- ...ctx,
129
- error: null,
130
- requestId: ctx.requestId + 1,
131
- }),
132
- },
133
- });
134
- };
135
-
136
- export type ChooseStore = ReturnType<typeof createChooseStore>;
137
-
138
- export const selectItems = (ctx: ChooseStoreContext): ChooseItem[] => ctx.items;
139
- export const selectMatches = (ctx: ChooseStoreContext): FuzzyMatch[] => ctx.matches;
140
- export const selectFilterQuery = (ctx: ChooseStoreContext): string => ctx.filterQuery;
141
- export const selectActiveIndex = (ctx: ChooseStoreContext): number => ctx.activeIndex;
142
- export const selectSelectedOriginalIndices = (ctx: ChooseStoreContext): ReadonlySet<number> =>
143
- ctx.selectedOriginalIndices;
144
- export const selectLoading = (ctx: ChooseStoreContext): boolean => ctx.loading;
145
- export const selectError = (ctx: ChooseStoreContext): string | null => ctx.error;
146
- export const selectReloadRevision = (ctx: ChooseStoreContext): number => ctx.reloadRevision;
1
+ export {
2
+ createChooseStore,
3
+ selectActiveIndex,
4
+ selectError,
5
+ selectFilterQuery,
6
+ selectItems,
7
+ selectLoading,
8
+ selectMatches,
9
+ selectReloadRevision,
10
+ selectSelectedOriginalIndices,
11
+ } from "@tooee/renderers";
12
+ export type { ChooseStore, ChooseStoreContext, ChooseStoreEvents } from "@tooee/renderers";
@@ -0,0 +1,12 @@
1
+ /** Compile-time checks for the Choose component's 0.9 public props. */
2
+ import type { ChooseProps } from "./choose.js";
3
+
4
+ type Assert<T extends true> = T;
5
+ type IsNever<T> = [T] extends [never] ? true : false;
6
+ type Has<TKeys, TName> = [Extract<TKeys, TName>] extends [never] ? false : true;
7
+
8
+ type Props = keyof ChooseProps;
9
+ type RetainedProps = Assert<Has<Props, "actions" | "multi" | "prompt" | "title">>;
10
+ type RemovedProps = Assert<IsNever<Extract<Props, "commands" | "options">>>;
11
+
12
+ export type ChoosePublicContractChecks = [RetainedProps, RemovedProps];
package/src/choose.tsx CHANGED
@@ -16,11 +16,7 @@ import type { ChooseController } from "./use-choose.js";
16
16
 
17
17
  export interface ChooseProps extends ChooseOptions {
18
18
  contentProvider: ChooseContentProvider;
19
- /** @deprecated Pass chooser options as top-level props. This alias will be removed in 0.9.0. */
20
- options?: ChooseOptions;
21
19
  actions?: ActionDefinition[];
22
- /** @deprecated Use `actions`. This alias will be removed in 0.9.0. */
23
- commands?: ActionDefinition[];
24
20
  controllerRef?: Ref<ChooseController>;
25
21
  renderItem?: ChooseListProps["renderItem"];
26
22
  /**
@@ -36,35 +32,19 @@ export interface ChooseProps extends ChooseOptions {
36
32
  onCancel?: () => void;
37
33
  }
38
34
 
39
- interface ResolvedChooseProps extends ChooseOptions {
40
- actions?: ActionDefinition[];
41
- }
42
-
43
- const resolveChooseProps = function resolveChooseProps(props: ChooseProps): ResolvedChooseProps {
44
- // oxlint-disable-next-line typescript/no-deprecated -- compatibility alias remains supported until 0.9.0
45
- const { options } = props;
46
- // oxlint-disable-next-line typescript/no-deprecated -- compatibility alias remains supported until 0.9.0
47
- const { commands } = props;
48
- return {
49
- actions: props.actions ?? commands,
50
- emptyMessage: props.emptyMessage ?? options?.emptyMessage,
51
- multi: props.multi ?? options?.multi,
52
- placeholder: props.placeholder ?? options?.placeholder,
53
- prompt: props.prompt ?? options?.prompt,
54
- title: props.title ?? options?.title,
55
- };
56
- };
57
-
58
- export const Choose = function Choose(props: ChooseProps): ReactNode {
59
- const { contentProvider, controllerRef, renderItem, onConfirm, onCancel } = props;
60
- const {
61
- actions: effectiveActions,
62
- emptyMessage,
63
- multi = false,
64
- placeholder,
65
- prompt,
66
- title,
67
- } = resolveChooseProps(props);
35
+ export const Choose = function Choose({
36
+ contentProvider,
37
+ actions,
38
+ controllerRef,
39
+ emptyMessage,
40
+ multi = false,
41
+ onCancel,
42
+ onConfirm,
43
+ placeholder,
44
+ prompt,
45
+ renderItem,
46
+ title,
47
+ }: ChooseProps): ReactNode {
68
48
  const { theme } = useTheme();
69
49
  const { invoke } = useSurfaceInvoke();
70
50
 
@@ -75,13 +55,13 @@ export const Choose = function Choose(props: ChooseProps): ReactNode {
75
55
  const hasModalOverlay = useHasModalOverlay();
76
56
 
77
57
  const choose = useChoose({
78
- commands: effectiveActions,
58
+ commands: actions,
79
59
  multi,
80
60
  onCancel,
81
61
  onSubmit: (result) => {
82
62
  // Standalone behaviour: a command named `submit` wins over `onConfirm`, so
83
63
  // action-driven CLIs keep their own submit semantics.
84
- if (effectiveActions?.some((action) => action.id === "submit") === true) {
64
+ if (actions?.some((action) => action.id === "submit") === true) {
85
65
  invoke("submit");
86
66
  return;
87
67
  }
package/src/fuzzy.ts CHANGED
@@ -1,13 +1,2 @@
1
- import { rankBy } from "@tooee/fuzzy";
2
- import type { ChooseItem } from "./types.js";
3
-
4
- export interface FuzzyMatch {
5
- item: ChooseItem;
6
- originalIndex: number;
7
- score: number;
8
- positions: number[];
9
- }
10
-
11
- export const fuzzyFilter = function fuzzyFilter(items: ChooseItem[], query: string): FuzzyMatch[] {
12
- return rankBy(items, query, (item) => item.text);
13
- };
1
+ export { fuzzyFilter } from "@tooee/renderers";
2
+ export type { FuzzyMatch } from "@tooee/renderers";
package/src/launch.tsx CHANGED
@@ -30,6 +30,7 @@ export const launch = async function launch(
30
30
  {
31
31
  provider: { initialMode: "insert" },
32
32
  stdinPolicy: "tty-if-piped",
33
+ stdoutPolicy: "tty-if-redirected",
33
34
  },
34
35
  );
35
36
  return result;
package/src/source.ts CHANGED
@@ -1,36 +1 @@
1
- import type { ChooseContentProvider, ChooseItem, ChooseSource } from "./types.js";
2
-
3
- type DecodedChooseSource =
4
- | { kind: "items"; items: ChooseItem[] }
5
- | { kind: "loader"; load: () => ChooseItem[] | Promise<ChooseItem[]> }
6
- | { kind: "provider"; provider: ChooseContentProvider };
7
-
8
- const decodeChooseSource = function decodeChooseSource(source: ChooseSource): DecodedChooseSource {
9
- if (Array.isArray(source)) {
10
- return { items: source, kind: "items" };
11
- }
12
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- public source boundary distinguishes the documented loader callback from a provider
13
- if (typeof source === "function") {
14
- return { kind: "loader", load: source };
15
- }
16
- return { kind: "provider", provider: source };
17
- };
18
-
19
- /** Resolve every public Choose source shape through one compatibility boundary. */
20
- export const loadChooseSource = function loadChooseSource(
21
- source: ChooseSource,
22
- ): ChooseItem[] | Promise<ChooseItem[]> {
23
- const decoded = decodeChooseSource(source);
24
- if (decoded.kind === "items") {
25
- return decoded.items;
26
- }
27
- if (decoded.kind === "loader") {
28
- return decoded.load();
29
- }
30
- return decoded.provider.load();
31
- };
32
-
33
- // oxlint-disable-next-line anti-slop/no-unknown-parameters -- caught loader failures enter here before conversion to display text
34
- export const chooseSourceError = function chooseSourceError(error: unknown): string {
35
- return error instanceof Error ? error.message : String(error);
36
- };
1
+ export { loadChooseSource } from "@tooee/renderers";
package/src/types.ts CHANGED
@@ -1,28 +1,7 @@
1
- export interface ChooseItem {
2
- text: string;
3
- value?: string;
4
- icon?: string;
5
- description?: string;
6
- }
7
-
8
- export interface ChooseContentProvider {
9
- load: () => Promise<ChooseItem[]> | ChooseItem[];
10
- }
11
-
12
- /** Any item source accepted by the shared chooser core. */
13
- export type ChooseSource =
14
- | ChooseItem[]
15
- | ChooseContentProvider
16
- | (() => ChooseItem[] | Promise<ChooseItem[]>);
17
-
18
- export interface ChooseResult {
19
- items: ChooseItem[];
20
- }
21
-
22
- export interface ChooseOptions {
23
- multi?: boolean;
24
- title?: string;
25
- prompt?: string;
26
- placeholder?: string;
27
- emptyMessage?: string;
28
- }
1
+ export type {
2
+ ChooseContentProvider,
3
+ ChooseItem,
4
+ ChooseOptions,
5
+ ChooseResult,
6
+ ChooseSource,
7
+ } from "@tooee/renderers";