@axis-ds/cli 1.5.1 → 1.5.3

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.
@@ -12,7 +12,7 @@
12
12
  {
13
13
  "path": "components/agentic/streaming-text.tsx",
14
14
  "type": "registry:ui",
15
- "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/registry/axis/lib/utils\";\n\nexport interface StreamingTextProps {\n /** 접근성 라이브 영역 모드 */\n \"aria-live\"?: \"polite\" | \"assertive\" | \"off\";\n /** 접근성 레이블 */\n \"aria-label\"?: string;\n /** 스트리밍할 텍스트 */\n text: string;\n /** 스트리밍 속도 (ms) */\n speed?: number;\n /** 스트리밍 완료 여부 */\n isComplete?: boolean;\n /** 커서 표시 여부 */\n showCursor?: boolean;\n /** 완료 콜백 */\n onComplete?: () => void;\n /** 추가 클래스 */\n className?: string;\n}\n\n/**\n * 텍스트를 실시간으로 스트리밍하는 컴포넌트\n * AI 응답을 타이핑 효과로 표시할 때 사용\n */\nexport function StreamingText({\n text,\n speed = 20,\n isComplete = false,\n showCursor = true,\n onComplete,\n \"aria-live\": ariaLive,\n \"aria-label\": ariaLabel,\n className,\n}: StreamingTextProps) {\n const [displayedText, setDisplayedText] = React.useState(\"\");\n const [isStreaming, setIsStreaming] = React.useState(false);\n const prevTextRef = React.useRef(\"\");\n\n React.useEffect(() => {\n if (isComplete) {\n setDisplayedText(text);\n setIsStreaming(false);\n return;\n }\n\n // 새로운 텍스트가 추가된 경우에만 스트리밍\n if (text.length > prevTextRef.current.length && text.startsWith(prevTextRef.current)) {\n const newText = text.slice(prevTextRef.current.length);\n let charIndex = 0;\n setIsStreaming(true);\n\n const interval = setInterval(() => {\n if (charIndex < newText.length) {\n setDisplayedText((prev) => prev + newText[charIndex]);\n charIndex++;\n } else {\n clearInterval(interval);\n setIsStreaming(false);\n if (onComplete) onComplete();\n }\n }, speed);\n\n prevTextRef.current = text;\n return () => clearInterval(interval);\n } else if (text !== prevTextRef.current) {\n // 텍스트가 완전히 변경된 경우 리셋\n setDisplayedText(\"\");\n prevTextRef.current = \"\";\n }\n }, [text, speed, isComplete, onComplete]);\n\n return (\n <div\n role=\"region\"\n aria-label={ariaLabel || \"AI 응답\"}\n aria-live={ariaLive ?? \"polite\"}\n aria-busy={isStreaming}\n className={cn(\"relative\", className)}\n >\n <span className=\"text-[var(--axis-text-primary)] whitespace-pre-wrap\">\n {displayedText}\n </span>\n {showCursor && isStreaming && (\n <span className=\"inline-block w-0.5 h-4 ml-0.5 bg-[var(--axis-text-primary)] animate-pulse\" aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n"
15
+ "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/registry/axis/lib/utils\";\n\nexport interface StreamingTextProps {\n /** 접근성 라이브 영역 모드 */\n \"aria-live\"?: \"polite\" | \"assertive\" | \"off\";\n /** 접근성 레이블 */\n \"aria-label\"?: string;\n /** 스트리밍할 텍스트 */\n text: string;\n /** 스트리밍 속도 (ms) */\n speed?: number;\n /** 스트리밍 완료 여부 */\n isComplete?: boolean;\n /** 커서 표시 여부 */\n showCursor?: boolean;\n /** 완료 콜백 */\n onComplete?: () => void;\n /** 추가 클래스 */\n className?: string;\n}\n\n/**\n * 텍스트를 실시간으로 스트리밍하는 컴포넌트\n * AI 응답을 타이핑 효과로 표시할 때 사용\n */\nexport function StreamingText({\n text,\n speed = 20,\n isComplete = false,\n showCursor = true,\n onComplete,\n \"aria-live\": ariaLive,\n \"aria-label\": ariaLabel,\n className,\n}: StreamingTextProps) {\n // 글자는 코드 포인트 단위로 센다(이모지 등 서로게이트 쌍을 반쪽으로 보이지 않게)\n const chars = React.useMemo(() => Array.from(text), [text]);\n // 상태는 \"보여 줄 글자 수\"만 두고 화면 문자열은 text 에서 잘라 만든다.\n // effect 가 정리 후 다시 실행돼도(StrictMode · 부모 재렌더) 이 위치에서 이어 간다.\n const [visibleLength, setVisibleLength] = React.useState(0);\n const [prevText, setPrevText] = React.useState(text);\n // text 변경: 이어 붙이기면 진행 위치 유지, 통째 교체면 처음부터(렌더 중 상태 조정)\n if (text !== prevText) {\n setPrevText(text);\n if (!text.startsWith(prevText)) setVisibleLength(0);\n }\n\n const targetLength = chars.length;\n const isStreaming = !isComplete && visibleLength < targetLength;\n\n // onComplete 는 ref 로 읽어 effect 의존성에서 뺀다(부모가 매 렌더 새 함수를 넘겨도 진행 유지)\n const onCompleteRef = React.useRef(onComplete);\n React.useEffect(() => {\n onCompleteRef.current = onComplete;\n });\n\n React.useEffect(() => {\n if (!isStreaming) return;\n const interval = setInterval(() => {\n setVisibleLength((n) => Math.min(n + 1, targetLength));\n }, speed);\n return () => clearInterval(interval);\n }, [isStreaming, targetLength, speed]);\n\n // 화면이 text 끝까지 따라잡은 순간 한 번 onComplete 를 부른다(isComplete 로 즉시 표시한 경우는 제외)\n const wasStreamingRef = React.useRef(false);\n React.useEffect(() => {\n if (isStreaming) {\n wasStreamingRef.current = true;\n return;\n }\n if (wasStreamingRef.current) {\n wasStreamingRef.current = false;\n if (!isComplete) onCompleteRef.current?.();\n }\n }, [isStreaming, isComplete]);\n\n const displayedText = isComplete ? text : chars.slice(0, visibleLength).join(\"\");\n\n return (\n <div\n role=\"region\"\n aria-label={ariaLabel || \"AI 응답\"}\n aria-live={ariaLive ?? \"polite\"}\n aria-busy={isStreaming}\n className={cn(\"relative\", className)}\n >\n <span className=\"text-[var(--axis-text-primary)] whitespace-pre-wrap\">\n {displayedText}\n </span>\n {showCursor && isStreaming && (\n <span className=\"inline-block w-0.5 h-4 ml-0.5 bg-[var(--axis-text-primary)] animate-pulse\" aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n"
16
16
  }
17
17
  ]
18
18
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "axis",
3
3
  "homepage": "https://axis-design-system.pages.dev",
4
- "version": "1.5.0",
4
+ "version": "1.5.2",
5
5
  "items": [
6
6
  {
7
7
  "name": "utils",
@@ -99,7 +99,7 @@
99
99
  "type": "registry:ui",
100
100
  "title": "Streaming Text",
101
101
  "description": "LLM 스트리밍 텍스트 출력 컴포넌트",
102
- "sha256": "cb69396b9436fb17c670d1fa368a7579be344d24dfd438dc56eaa6f94dbd896e"
102
+ "sha256": "e39ef3ef19e7ce5d0a22ba4c9d168c7cd219ea0234b5df75bf74cfa70c6a4056"
103
103
  },
104
104
  {
105
105
  "name": "agentic-approval-card",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://ui.shadcn.com/schema/registry.json",
3
3
  "name": "axis",
4
4
  "homepage": "https://axis-design-system.pages.dev",
5
- "version": "1.5.0",
5
+ "version": "1.5.2",
6
6
  "items": [
7
7
  {
8
8
  "name": "utils",
@@ -100,7 +100,7 @@
100
100
  "type": "registry:ui",
101
101
  "title": "Streaming Text",
102
102
  "description": "LLM 스트리밍 텍스트 출력 컴포넌트",
103
- "sha256": "cb69396b9436fb17c670d1fa368a7579be344d24dfd438dc56eaa6f94dbd896e"
103
+ "sha256": "e39ef3ef19e7ce5d0a22ba4c9d168c7cd219ea0234b5df75bf74cfa70c6a4056"
104
104
  },
105
105
  {
106
106
  "name": "agentic-approval-card",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  fetchTemplateDetail,
3
3
  fetchTemplateIndex
4
- } from "./chunk-NVGENR3K.js";
4
+ } from "./chunk-IQY3WUGG.js";
5
5
  export {
6
6
  fetchTemplateDetail,
7
7
  fetchTemplateIndex
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-ds/cli",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "type": "module",
5
5
  "description": "AXIS Design System - CLI for adding components (shadcn compatible)",
6
6
  "publishConfig": {
@@ -29,7 +29,8 @@
29
29
  "@vitest/coverage-v8": "^2.1.0",
30
30
  "tsup": "^8.0.0",
31
31
  "typescript": "^5.7.0",
32
- "vitest": "^2.1.0"
32
+ "vitest": "^2.1.0",
33
+ "@axis-ds/registry-core": "0.0.0"
33
34
  },
34
35
  "keywords": [
35
36
  "cli",