@akanjs/devkit 3.0.0-alpha.9 → 3.0.0-alpha.90

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 (183) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/DEV_RUNTIME_KNOBS.md +27 -0
  3. package/README.ko.md +1 -1
  4. package/README.md +1 -1
  5. package/agentsIndex.test.ts +10 -0
  6. package/agentsIndex.ts +21 -1
  7. package/aiEditor.ts +1 -1
  8. package/akanApp/BackendImportGraph.test.ts +120 -0
  9. package/akanApp/BackendImportGraph.ts +167 -0
  10. package/akanApp/akanApp.host.test.ts +16 -678
  11. package/akanApp/akanApp.host.ts +113 -578
  12. package/akanApp/devHostPolicy.test.ts +542 -0
  13. package/akanApp/devHostPolicy.ts +442 -0
  14. package/akanApp/index.ts +2 -0
  15. package/akanConfig/akanConfig.test.ts +182 -14
  16. package/akanConfig/akanConfig.ts +143 -47
  17. package/akanConfig/types.ts +9 -0
  18. package/akanContext.ts +30 -14
  19. package/akanMcpContract.ts +25 -4
  20. package/appSelectionMemory.ts +28 -0
  21. package/applicationBuildRunner.test.ts +1 -1
  22. package/applicationBuildRunner.ts +45 -21
  23. package/artifact/implicitRootLayout.test.ts +67 -0
  24. package/artifact/implicitRootLayout.ts +27 -7
  25. package/artifact/routeSeedIndex.test.ts +1 -0
  26. package/biome.base.json +86 -47
  27. package/biomeBase.ts +6 -5
  28. package/capacitorApp.ts +10 -0
  29. package/cloud/globalConfig.ts +9 -2
  30. package/codegenLock.test.ts +137 -0
  31. package/codegenLock.ts +136 -0
  32. package/commandDecorators/argMeta.ts +9 -1
  33. package/commandDecorators/command.ts +94 -7
  34. package/commandDecorators/commandBuilder.ts +20 -5
  35. package/commandDecorators/commandDecorators.test.ts +115 -3
  36. package/commandDecorators/helpFormatter.ts +4 -0
  37. package/dependencyScanner.test.ts +99 -0
  38. package/dependencyScanner.ts +27 -24
  39. package/devkitUtils.test.ts +0 -104
  40. package/executors.test.ts +129 -4
  41. package/executors.ts +105 -24
  42. package/fileEditor.ts +19 -19
  43. package/fileSys.ts +19 -1
  44. package/formSetterScanner.test.ts +80 -0
  45. package/formSetterScanner.ts +92 -0
  46. package/frontendBuild/autoImportSync.test.ts +58 -0
  47. package/frontendBuild/autoImportSync.ts +7 -2
  48. package/frontendBuild/buildRouteClient.test.ts +47 -24
  49. package/frontendBuild/clientBuildTypes.ts +4 -0
  50. package/frontendBuild/clientEntriesBundler.ts +4 -1
  51. package/frontendBuild/clientEntryDiscovery.ts +2 -2
  52. package/frontendBuild/csrArtifactBuilder.ts +116 -84
  53. package/frontendBuild/cssCompiler.ts +123 -12
  54. package/frontendBuild/cssImportResolver.ts +8 -7
  55. package/frontendBuild/devGeneratedIndexSync.ts +3 -2
  56. package/frontendBuild/fontOptimizer.ts +37 -18
  57. package/frontendBuild/fontPruner.test.ts +220 -0
  58. package/frontendBuild/fontPruner.ts +206 -0
  59. package/frontendBuild/frontendBuild.test.ts +178 -10
  60. package/frontendBuild/hmrWatcher.ts +1 -1
  61. package/frontendBuild/index.ts +1 -1
  62. package/frontendBuild/pagesBundleBuilder.ts +3 -3
  63. package/frontendBuild/pagesEntrySourceGenerator.ts +11 -88
  64. package/frontendBuild/routeClientBuilder.ts +12 -5
  65. package/frontendBuild/sourceMtimeIndex.ts +1 -1
  66. package/frontendBuild/ssrBaseArtifactBuilder.ts +21 -4
  67. package/frontendBuild/styleContract.ts +14 -20
  68. package/frontendBuild/themeValidator.ts +22 -17
  69. package/frontendBuild/vendorSpecifiers.ts +1 -0
  70. package/frontendBuild/watchRootResolver.test.ts +67 -0
  71. package/frontendBuild/watchRootResolver.ts +13 -1
  72. package/incrementalBuilder/devWatchBatch.test.ts +18 -20
  73. package/incrementalBuilder/devWatchBatch.ts +6 -2
  74. package/incrementalBuilder/incrementalBuilder.host.ts +51 -7
  75. package/incrementalBuilder/incrementalBuilder.proc.ts +17 -6
  76. package/index.ts +0 -7
  77. package/integration/devStabilityHarness.ts +2 -10
  78. package/libSource.test.ts +112 -0
  79. package/libSource.ts +126 -0
  80. package/lint/__fixtures__/README.md +40 -0
  81. package/lint/__fixtures__/no-arbitrary-color/bad.tsx +3 -0
  82. package/lint/__fixtures__/no-arbitrary-color/good.tsx +4 -0
  83. package/lint/__fixtures__/no-async-component-in-ui/bad.tsx +4 -0
  84. package/lint/__fixtures__/no-async-component-in-ui/good.tsx +4 -0
  85. package/lint/__fixtures__/no-bang-comment-in-client/bad.tsx +4 -0
  86. package/lint/__fixtures__/no-bang-comment-in-client/fixture.json +1 -0
  87. package/lint/__fixtures__/no-bang-comment-in-client/good.tsx +3 -0
  88. package/lint/__fixtures__/no-daisyui-legacy-class/bad.tsx +7 -0
  89. package/lint/__fixtures__/no-daisyui-legacy-class/good.tsx +5 -0
  90. package/lint/__fixtures__/no-deep-internal-import/bad.tsx +3 -0
  91. package/lint/__fixtures__/no-deep-internal-import/fixture.json +1 -0
  92. package/lint/__fixtures__/no-deep-internal-import/good.tsx +3 -0
  93. package/lint/__fixtures__/no-deprecated-log-level/bad.tsx +4 -0
  94. package/lint/__fixtures__/no-deprecated-log-level/good.tsx +4 -0
  95. package/lint/__fixtures__/no-import-client-functions/bad.tsx +2 -0
  96. package/lint/__fixtures__/no-import-client-functions/good.tsx +4 -0
  97. package/lint/__fixtures__/no-import-client-in-server/bad.tsx +6 -0
  98. package/lint/__fixtures__/no-import-client-in-server/good.tsx +5 -0
  99. package/lint/__fixtures__/no-import-external-library/bad.tsx +4 -0
  100. package/lint/__fixtures__/no-import-external-library/good.tsx +5 -0
  101. package/lint/__fixtures__/no-import-server-in-client/bad.tsx +6 -0
  102. package/lint/__fixtures__/no-import-server-in-client/good.tsx +4 -0
  103. package/lint/__fixtures__/no-init-fetch-in-client/store-file/bad.ts +1 -0
  104. package/lint/__fixtures__/no-init-fetch-in-client/store-file/fixture.json +1 -0
  105. package/lint/__fixtures__/no-init-fetch-in-client/store-file/good.ts +1 -0
  106. package/lint/__fixtures__/no-init-fetch-in-client/use-client/bad.tsx +4 -0
  107. package/lint/__fixtures__/no-init-fetch-in-client/use-client/good.tsx +5 -0
  108. package/lint/__fixtures__/no-inline-color/bad.tsx +3 -0
  109. package/lint/__fixtures__/no-inline-color/good.tsx +3 -0
  110. package/lint/__fixtures__/no-interpolated-arbitrary-class/bad.tsx +3 -0
  111. package/lint/__fixtures__/no-interpolated-arbitrary-class/good.tsx +3 -0
  112. package/lint/__fixtures__/no-js-private-class-method/bad.tsx +3 -0
  113. package/lint/__fixtures__/no-js-private-class-method/good.tsx +3 -0
  114. package/lint/__fixtures__/no-model-type-in-util-zone/bad.tsx +3 -0
  115. package/lint/__fixtures__/no-model-type-in-util-zone/good.tsx +6 -0
  116. package/lint/__fixtures__/no-raw-palette-class/bad.tsx +6 -0
  117. package/lint/__fixtures__/no-raw-palette-class/good.tsx +8 -0
  118. package/lint/__fixtures__/no-redeclare-predefined-endpoint/bad.ts +10 -0
  119. package/lint/__fixtures__/no-redeclare-predefined-endpoint/fixture.json +1 -0
  120. package/lint/__fixtures__/no-redeclare-predefined-endpoint/good.ts +6 -0
  121. package/lint/__fixtures__/no-return-in-store-action/bad.tsx +2 -0
  122. package/lint/__fixtures__/no-return-in-store-action/good.tsx +6 -0
  123. package/lint/__fixtures__/no-throw-raw-error/bad.tsx +4 -0
  124. package/lint/__fixtures__/no-throw-raw-error/good.tsx +4 -0
  125. package/lint/__fixtures__/no-unpublished-form-setter/bad.tsx +3 -0
  126. package/lint/__fixtures__/no-unpublished-form-setter/good.tsx +5 -0
  127. package/lint/__fixtures__/no-use-client-in-server/bad.tsx +3 -0
  128. package/lint/__fixtures__/no-use-client-in-server/good.tsx +2 -0
  129. package/lint/__fixtures__/non-scalar-props-restricted/bad.tsx +5 -0
  130. package/lint/__fixtures__/non-scalar-props-restricted/good.tsx +4 -0
  131. package/lint/gritRules.test.ts +178 -0
  132. package/lint/no-arbitrary-color.grit +1 -1
  133. package/lint/no-async-component-in-ui.grit +35 -0
  134. package/lint/no-bang-comment-in-client.grit +23 -10
  135. package/lint/no-daisyui-legacy-class.grit +26 -9
  136. package/lint/no-deprecated-log-level.grit +17 -0
  137. package/lint/no-init-fetch-in-client.grit +47 -0
  138. package/lint/no-inline-color.grit +10 -8
  139. package/lint/no-interpolated-arbitrary-class.grit +3 -3
  140. package/lint/no-model-type-in-util-zone.grit +58 -0
  141. package/lint/no-raw-palette-class.grit +3 -3
  142. package/lint/no-unpublished-form-setter.grit +41 -0
  143. package/lint/non-scalar-props-restricted.grit +16 -7
  144. package/linter.test.ts +80 -0
  145. package/linter.ts +99 -25
  146. package/package.json +5 -8
  147. package/prompter.ts +9 -4
  148. package/qualityScanner.test.ts +116 -0
  149. package/qualityScanner.ts +89 -21
  150. package/recipeScanner.ts +4 -1
  151. package/scanInfo.ts +32 -26
  152. package/semver.test.ts +26 -0
  153. package/semver.ts +31 -0
  154. package/slicePlanner.test.ts +182 -0
  155. package/slicePlanner.ts +235 -0
  156. package/ssrScanner.test.ts +301 -0
  157. package/subspace.test.ts +418 -0
  158. package/subspace.ts +723 -0
  159. package/subspaceConfig.ts +76 -0
  160. package/transforms/asyncDefaultExportDetector.ts +103 -0
  161. package/transforms/barrelImportsPlugin.ts +1 -1
  162. package/transforms/externalizeFrameworkPlugin.ts +0 -1
  163. package/transforms/transforms.test.ts +5 -5
  164. package/transforms/tsconfigPackageResolver.test.ts +230 -0
  165. package/tsconfig.json +6 -2
  166. package/typeChecker.ts +1 -1
  167. package/types.ts +1 -0
  168. package/uploadRelease.ts +2 -2
  169. package/workflow/executor.test.ts +146 -0
  170. package/workspaceLayout.test.ts +56 -4
  171. package/workspaceLayout.ts +48 -2
  172. package/builder.ts +0 -164
  173. package/extractDeps.ts +0 -86
  174. package/frontendBuild/styleGuard.test.ts +0 -165
  175. package/frontendBuild/styleGuard.ts +0 -322
  176. package/getCredentials.ts +0 -19
  177. package/getModelFileData.ts +0 -62
  178. package/src/capacitorApp.ts +0 -282
  179. package/streamAi.ts +0 -45
  180. package/ui/MultiScrollList.tsx +0 -242
  181. package/ui/ScrollList.tsx +0 -107
  182. package/ui/index.ts +0 -2
  183. package/useStdoutDimensions.ts +0 -20
package/streamAi.ts DELETED
@@ -1,45 +0,0 @@
1
- import { PromptTemplate } from "@langchain/core/prompts";
2
- import { RunnableSequence } from "@langchain/core/runnables";
3
- import { ChatOpenAI } from "@langchain/openai";
4
-
5
- interface StreamResponse {
6
- content: string;
7
- chunk?: string;
8
- }
9
-
10
- export const streamAi = async (
11
- question: string,
12
- callback: (chunk: string) => void = (chunk) => {
13
- process.stdout.write(chunk);
14
- },
15
- ): Promise<StreamResponse> => {
16
- const createStreamingModel = (apiKey = process.env.DEEPSEEK_API_KEY) => {
17
- if (!apiKey) throw new Error(`process.env.DEEPSEEK_API_KEY is not set`);
18
- return new ChatOpenAI({
19
- modelName: "deepseek-reasoner",
20
- temperature: 0.7,
21
- streaming: true, // Enable streaming
22
- configuration: { baseURL: "https://api.deepseek.com/v1", apiKey },
23
- });
24
- };
25
- const createProcessingChain = () => {
26
- return RunnableSequence.from([PromptTemplate.fromTemplate(`Answer concisely: {question}`), createStreamingModel()]);
27
- };
28
- try {
29
- const chain = createProcessingChain();
30
- const stream = await chain.stream({ question });
31
-
32
- let fullResponse = "";
33
- for await (const chunk of stream) {
34
- const content = chunk.content;
35
- if (typeof content === "string") {
36
- fullResponse += content;
37
- callback(content); // Send individual chunks to callback
38
- }
39
- }
40
-
41
- return { content: fullResponse };
42
- } catch (error) {
43
- throw new Error("Failed to stream response");
44
- }
45
- };
@@ -1,242 +0,0 @@
1
- "use client";
2
- import { Box, Text, useInput } from "ink";
3
- import { useEffect, useState } from "react";
4
- import { useStdoutDimensions } from "../useStdoutDimensions";
5
-
6
- interface MultiScrollListProps {
7
- logList: {
8
- title: string;
9
- logs: {
10
- type: string;
11
- content: string;
12
- }[];
13
- color: string;
14
- }[];
15
-
16
- maxLength?: number;
17
- }
18
-
19
- /**
20
- * @param logList 로그 목록
21
- * @param maxLength 최대 로그 길이 (기본 100)
22
- */
23
- const HEADER_HEIGHT = 1;
24
- const FOOTER_HEIGHT = 1;
25
- const OUTER_BORDER_HEIGHT = 2;
26
- const BORDER_HEIGHT = 2;
27
- const ANSI_ESCAPE_RE = new RegExp(`${String.fromCharCode(27)}(?:[@-Z\\\\-_]|\\[[\\s\\S]*?[@-~])`, "g");
28
-
29
- export const MultiScrollList = ({ logList, maxLength = 100 }: MultiScrollListProps) => {
30
- // 창 너비, 높이
31
- const [width, height] = useStdoutDimensions();
32
- // 탭별 로그 렌더링
33
-
34
- const [focusLog, setFocusLog] = useState<{ type: string; content: string }[]>([]);
35
- // 탭별 로그 길이 저장 (스크롤시 로그 길이 변화로 위치 조정)
36
- const [lengthMap, setLengthMap] = useState<Map<number, number>>(new Map());
37
- // 스크롤 위치
38
- const [scrollPos, setScrollPos] = useState(0);
39
- // 현재 포커싱탭 인덱스
40
- const [tabIndex, setTabIndex] = useState<number>(0);
41
- // 스크롤 실행 여부
42
- const [isRunning, setIsRunning] = useState(false);
43
- // 박스 높이 (보더 사이즈 2, 헤더 사이즈 1, 푸터 사이즈 5 기본 1)
44
- const [boxHeight, setBoxHeight] = useState(
45
- height - HEADER_HEIGHT - OUTER_BORDER_HEIGHT - FOOTER_HEIGHT - BORDER_HEIGHT,
46
- );
47
- const boxWidth = width - 27;
48
-
49
- // maxLength에 따라 로그 배열을 제한하는 유틸리티 함수
50
- const getLimitedLogs = (logs: { type: string; content: string }[]) => {
51
- const sortedLogs = logs.reduce<{ type: string; content: string }[]>((acc, log) => {
52
- // log.content.length가 boxWidth보다 큰 경우 잘라서 줄 수 만큼 추가
53
- // ANSI 코드 보관
54
-
55
- const content = log.content.replace(ANSI_ESCAPE_RE, "");
56
- if (content.length > boxWidth) {
57
- const lines = Math.ceil(content.length / boxWidth);
58
- for (let i = 0; i < lines; i++) {
59
- acc.push({ type: log.type, content: content.slice(i * boxWidth, (i + 1) * boxWidth) });
60
- }
61
- } else {
62
- acc.push(log);
63
- }
64
- return acc;
65
- }, []);
66
- return sortedLogs.length > maxLength ? sortedLogs.slice(sortedLogs.length - maxLength) : sortedLogs;
67
- };
68
-
69
- // 입력 이벤트 처리
70
- useInput((input, key) => {
71
- // 탭 키 이벤트 처리(포커싱 탭 변경)
72
- if (key.tab) {
73
- setTabIndex((prev: number) => (prev + 1) % logList.length);
74
- setScrollPos(0);
75
- setIsRunning(false);
76
- }
77
- // 스크롤 중지 이벤트 처리 (포커싱까지 완전히 종료)
78
- if (key.escape) {
79
- setScrollPos(0);
80
- setIsRunning(false);
81
- }
82
- // 스크롤 중지 이벤트 처리 (포커싱 유지)
83
- if (input === " ") {
84
- setScrollPos(0);
85
- setIsRunning(false);
86
- }
87
- // 스크롤 다운 이벤트 처리
88
- if (key.downArrow && scrollPos > 0) {
89
- if (key.shift) {
90
- const newScrollPos = scrollPos - 10;
91
- // 스크롤 최소 위치에 도달 경우에 대한 예외 처리
92
- if (newScrollPos < 0) {
93
- setScrollPos(0);
94
- } else {
95
- setScrollPos(newScrollPos);
96
- }
97
- } else {
98
- const newScrollPos = scrollPos - 1;
99
- setScrollPos(newScrollPos);
100
- }
101
- }
102
- // 스크롤 업 이벤트 처리
103
- if (key.upArrow && scrollPos < logList[tabIndex].logs.length - boxHeight) {
104
- const limitedLogs = getLimitedLogs(logList[tabIndex].logs);
105
- if (scrollPos < limitedLogs.length - boxHeight) {
106
- // 스크롤 업 이벤트 처리 (스크롤 속도 증가)
107
- if (key.shift) {
108
- const newScrollPos = scrollPos + 10;
109
- // 스크롤 최대 위치에 도달 경우에 대한 예외 처리
110
- if (newScrollPos > limitedLogs.length - boxHeight) {
111
- setScrollPos(limitedLogs.length - boxHeight);
112
- } else {
113
- setScrollPos(newScrollPos);
114
- }
115
- } else {
116
- setScrollPos(scrollPos + 1);
117
- }
118
- if (!isRunning) setIsRunning(true);
119
- }
120
- }
121
- });
122
-
123
- useEffect(() => {
124
- // 공통 로직을 함수로 추출
125
- const getLogsToRender = (logs: { type: string; content: string }[], index: number) => {
126
- // maxLength에 따라 로그 제한
127
- const limitedLogs = getLimitedLogs(logs);
128
- // 로그 중 boxWidth보다 긴 것이 있는 경우 잘라서 출력
129
-
130
- // 활성 탭이고 스크롤 중인 특별한 경우
131
- if (scrollPos > 0 && tabIndex === index) {
132
- return limitedLogs.slice(limitedLogs.length - boxHeight - scrollPos, limitedLogs.length - scrollPos);
133
- }
134
- // 로그가 표시 영역보다 큰 경우 (공통 로직)
135
- else if (limitedLogs.length > boxHeight) {
136
- return limitedLogs.slice(limitedLogs.length - boxHeight, limitedLogs.length);
137
- }
138
- // 로그가 표시 영역에 모두 들어가는 경우 (공통 로직)
139
- else {
140
- return limitedLogs;
141
- }
142
- };
143
-
144
- // isRunning일 때 로직
145
- if (isRunning) {
146
- // 선택된 탭의 로그 길이 변화 확인 및 스크롤 포지션 업데이트
147
- if (lengthMap.has(tabIndex)) {
148
- const tabLength = lengthMap.get(tabIndex);
149
- const limitedLogsLength = Math.min(logList[tabIndex].logs.length, maxLength);
150
- if (tabLength && tabLength < limitedLogsLength) {
151
- setScrollPos(scrollPos + 1);
152
- lengthMap.set(tabIndex, limitedLogsLength);
153
- }
154
- }
155
-
156
- // 스크롤 위치에 따른 로그 렌더링 업데이트
157
-
158
- setFocusLog(getLogsToRender(logList[tabIndex].logs, tabIndex));
159
- }
160
- // isRunning이 아닐 때 로직
161
- else {
162
- // lengthMap 업데이트 및 초기 렌더링
163
- setFocusLog(getLogsToRender(logList[tabIndex].logs, tabIndex));
164
- }
165
- }, [logList, isRunning, scrollPos, tabIndex, boxHeight, maxLength]);
166
-
167
- useEffect(() => {
168
- setBoxHeight(height - HEADER_HEIGHT - OUTER_BORDER_HEIGHT - FOOTER_HEIGHT - BORDER_HEIGHT);
169
- }, [height]);
170
-
171
- // 초기 로그 사이즈 설정
172
- useEffect(() => {
173
- setLengthMap(new Map(logList.map((log, index) => [index, Math.min(log.logs.length, maxLength)])));
174
- }, [logList, maxLength]);
175
-
176
- return (
177
- <Box width={width} height={height} borderStyle="round" borderColor="blackBright" flexDirection="column">
178
- <Box width={"100%"} height={boxHeight + BORDER_HEIGHT + HEADER_HEIGHT} flexDirection="row">
179
- <Box width={30} height="100%" flexDirection="column">
180
- <Box>
181
- <Text>
182
- List {tabIndex + 1}/{logList.length}
183
- </Text>
184
- </Box>
185
- <Box borderStyle="round" borderColor="blackBright" width={"100%"} height="100%" flexDirection="column">
186
- {logList.map((log, index) => {
187
- return (
188
- <Text key={index} color={index === tabIndex ? "green" : "white"}>
189
- <Text>●</Text>&nbsp;
190
- {log.title.length > 25 ? `${log.title.slice(0, 25)}...` : log.title}
191
- </Text>
192
- );
193
- })}
194
- </Box>
195
- </Box>
196
- <Box width={"100%"} height="100%" flexDirection="column">
197
- <Box height={1}>
198
- <Text color={logList[tabIndex].color}>
199
- {logList[tabIndex].title} {logList[tabIndex].logs.length}
200
- </Text>
201
- </Box>
202
- <Box
203
- borderStyle={isRunning ? "double" : "round"}
204
- flexDirection="column"
205
- borderColor={logList[tabIndex].color}
206
- width="100%"
207
- height="100%"
208
- >
209
- {scrollPos > 0 ? (
210
- <>
211
- {focusLog.slice(0, focusLog.length - 1).map((log, index) => {
212
- return (
213
- <Text underline={false} color={log.type === "error" ? "red" : "white"} key={index}>
214
- {log.content}
215
- </Text>
216
- );
217
- })}
218
- <Text underline={false} backgroundColor="green">
219
- Scrolling... +{scrollPos}
220
- </Text>
221
- </>
222
- ) : (
223
- focusLog.map((log, index) => {
224
- return (
225
- <Text underline={false} color={log.type === "error" ? "red" : "white"} key={index}>
226
- {log.content}
227
- </Text>
228
- );
229
- })
230
- )}
231
- </Box>
232
- </Box>
233
- </Box>
234
- {/* <Text>{renderMultiLogs[tabIndex][0]}</Text> */}
235
- <Box width={"100%"} height={FOOTER_HEIGHT}>
236
- <Text dimColor={true}>
237
- Tab : switch tab | Up / Down(shift : x10) : scroll | Space : back last position | Esc : stop scrolling
238
- </Text>
239
- </Box>
240
- </Box>
241
- );
242
- };
package/ui/ScrollList.tsx DELETED
@@ -1,107 +0,0 @@
1
- "use client";
2
- import { Box, type BoxProps, Newline, Text, useInput } from "ink";
3
- import { type ReactNode, useEffect, useState } from "react";
4
- import { useStdoutDimensions } from "../useStdoutDimensions";
5
-
6
- interface ScrollListProps extends BoxProps {
7
- list: ReactNode[];
8
- }
9
-
10
- export const ScrollList = ({ list, ...props }: ScrollListProps) => {
11
- const [renderLogs, setRenderLogs] = useState<ReactNode[]>(list);
12
- const [width, height] = useStdoutDimensions();
13
- const [scrollPos, setScrollPos] = useState(0);
14
- const [isRunning, setIsRunning] = useState(false);
15
- const [boxHeight, setBoxHeight] = useState(height - 3);
16
-
17
- useInput((input, key) => {
18
- if (key.escape) {
19
- setIsRunning(false);
20
- setScrollPos(0);
21
- }
22
- if (input === " " && isRunning) {
23
- setIsRunning(false);
24
- setScrollPos(0);
25
- }
26
- if (key.downArrow && scrollPos > 0) {
27
- if (key.shift) {
28
- setScrollPos(scrollPos - 10);
29
- } else {
30
- setScrollPos(scrollPos - 1);
31
- }
32
- }
33
- if (key.upArrow && scrollPos < list.length - boxHeight) {
34
- if (key.shift) {
35
- setScrollPos(scrollPos + 10);
36
- } else {
37
- setScrollPos(scrollPos + 1);
38
- }
39
- }
40
- });
41
-
42
- useEffect(() => {
43
- //1 로그가 박스 높이보다 크면 스크롤 위치 조정
44
- //2. scrollPos값에 따라 포커싱 위치 변경하고 pos 활성시 포커싱 위치 고정
45
- if (isRunning) {
46
- setScrollPos(scrollPos + 1);
47
- return;
48
- }
49
- if (list.length > boxHeight) {
50
- setRenderLogs(list.slice(list.length - boxHeight, list.length));
51
- } else {
52
- setRenderLogs(list);
53
- }
54
- }, [list, isRunning]);
55
-
56
- useEffect(() => {
57
- setBoxHeight(Math.floor(height * 0.9));
58
- }, [height]);
59
-
60
- useEffect(() => {
61
- if (scrollPos > 0) {
62
- setRenderLogs(list.slice(list.length - boxHeight - scrollPos, list.length - scrollPos));
63
- setIsRunning(true);
64
- } else {
65
- setRenderLogs(list.slice(list.length - boxHeight, list.length));
66
- setIsRunning(false);
67
- }
68
- }, [scrollPos]);
69
-
70
- return (
71
- <Box {...props} width={width} height={"100%"} flexDirection="column">
72
- <Box borderStyle="round" width={width} height={height - 3}>
73
- <Newline />
74
- <Text>
75
- {isRunning ? (
76
- <>
77
- {renderLogs.slice(0, renderLogs.length - 1).map((log, index) => (
78
- <>
79
- <Text key={index}>{log}</Text>
80
- <Newline />
81
- </>
82
- ))}
83
- <Text backgroundColor="green">scrolling... + {scrollPos}</Text>
84
- </>
85
- ) : (
86
- <>
87
- {renderLogs.map((log, index) => (
88
- <>
89
- <Text key={index}>{log}</Text>
90
- <Newline />
91
- </>
92
- ))}
93
- </>
94
- )}
95
- </Text>
96
- </Box>
97
- <Box>
98
- <Text dimColor={true}>
99
- You can use the following shortcuts:
100
- <Newline />* <Text backgroundColor="green">up</Text> and <Text backgroundColor="green">down</Text> to scroll.{" "}
101
- <Text backgroundColor="green">shift</Text> to scroll faster.
102
- <Newline />* <Text backgroundColor="green">escape</Text> to stop scrolling.
103
- </Text>
104
- </Box>
105
- </Box>
106
- );
107
- };
package/ui/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./MultiScrollList";
2
- export * from "./ScrollList";
@@ -1,20 +0,0 @@
1
- "use client";
2
- import { useStdout } from "ink";
3
- import { useEffect, useState } from "react";
4
-
5
- export const useStdoutDimensions = (): [number, number] => {
6
- const { stdout } = useStdout();
7
- const [dimensions, setDimensions] = useState<[number, number]>([stdout.columns, stdout.rows]);
8
-
9
- useEffect(() => {
10
- const handler = () => {
11
- setDimensions([stdout.columns, stdout.rows]);
12
- };
13
- stdout.on("resize", handler);
14
- return () => {
15
- stdout.off("resize", handler);
16
- };
17
- }, [stdout]);
18
-
19
- return dimensions;
20
- };