@iyulab/chat-components 0.3.0 → 0.5.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.
Files changed (208) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +133 -16
  3. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js +9 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js +6 -0
  5. package/dist/_virtual/_glob-assets_raw/intent-prompt.md.1907474e.js +4 -0
  6. package/dist/_virtual/_glob-assets_raw/view-prompt.md.e0dbcffe.js +4 -0
  7. package/dist/components/blocks/UCodeBlock.d.ts +24 -2
  8. package/dist/components/blocks/UCodeBlock.js +65 -2
  9. package/dist/components/blocks/UCodeBlock.styles.js +10 -4
  10. package/dist/components/blocks/UFileBlock.d.ts +33 -0
  11. package/dist/components/blocks/UFileBlock.js +154 -0
  12. package/dist/components/blocks/UFileBlock.styles.js +128 -0
  13. package/dist/components/blocks/UJsonBlock.d.ts +44 -2
  14. package/dist/components/blocks/UJsonBlock.js +128 -3
  15. package/dist/components/blocks/UJsonBlock.styles.js +4 -4
  16. package/dist/components/blocks/UMarkedBlock.d.ts +44 -2
  17. package/dist/components/blocks/UMarkedBlock.js +154 -4
  18. package/dist/components/blocks/UMarkedBlock.styles.js +4 -4
  19. package/dist/components/blocks/URefBlock.d.ts +16 -2
  20. package/dist/components/blocks/URefBlock.js +58 -3
  21. package/dist/components/blocks/URefBlock.styles.js +4 -4
  22. package/dist/components/blocks/UTableBlock.d.ts +52 -0
  23. package/dist/components/blocks/UTableBlock.js +198 -0
  24. package/dist/components/blocks/UTableBlock.styles.js +133 -0
  25. package/dist/components/blocks/UTextBlock.d.ts +36 -2
  26. package/dist/components/blocks/UTextBlock.js +94 -4
  27. package/dist/components/blocks/UTextBlock.styles.js +4 -4
  28. package/dist/components/blocks/UThinkBlock.d.ts +30 -2
  29. package/dist/components/blocks/UThinkBlock.js +86 -4
  30. package/dist/components/blocks/UThinkBlock.styles.js +4 -4
  31. package/dist/components/blocks/UToolBlock.d.ts +19 -2
  32. package/dist/components/blocks/UToolBlock.js +68 -3
  33. package/dist/components/blocks/UToolBlock.styles.js +4 -4
  34. package/dist/components/buttons/UAttachButton.d.ts +21 -2
  35. package/dist/components/buttons/UAttachButton.js +61 -3
  36. package/dist/components/buttons/UAttachButton.styles.js +4 -4
  37. package/dist/components/buttons/UCopyButton.d.ts +19 -2
  38. package/dist/components/buttons/UCopyButton.js +57 -3
  39. package/dist/components/buttons/UCopyButton.styles.js +4 -4
  40. package/dist/components/buttons/UVoteButton.d.ts +14 -3
  41. package/dist/components/buttons/UVoteButton.js +62 -3
  42. package/dist/components/buttons/UVoteButton.styles.js +4 -4
  43. package/dist/components/intents/UQuestionIntent.d.ts +22 -0
  44. package/dist/components/intents/UQuestionIntent.js +41 -0
  45. package/dist/components/intents/UQuestionIntent.styles.js +43 -0
  46. package/dist/components/message/UMessage.d.ts +18 -2
  47. package/dist/components/message/UMessage.js +47 -2
  48. package/dist/components/message/UMessage.styles.js +42 -15
  49. package/dist/components/prompt/UPrompt.d.ts +32 -2
  50. package/dist/components/prompt/UPrompt.js +118 -2
  51. package/dist/components/prompt/UPrompt.styles.js +43 -5
  52. package/dist/components/references/URefCard.d.ts +30 -2
  53. package/dist/components/references/URefCard.js +97 -2
  54. package/dist/components/references/URefCard.styles.js +4 -4
  55. package/dist/components/references/URefCardGroup.d.ts +25 -2
  56. package/dist/components/references/URefCardGroup.js +69 -4
  57. package/dist/components/references/URefCardGroup.styles.js +4 -4
  58. package/dist/components/references/URefTag.d.ts +12 -2
  59. package/dist/components/references/URefTag.js +37 -2
  60. package/dist/components/references/URefTag.styles.js +4 -4
  61. package/dist/components/views/UChartView.d.ts +39 -0
  62. package/dist/components/views/UChartView.js +167 -0
  63. package/dist/components/views/UChartView.styles.js +86 -0
  64. package/dist/components/views/UImagesView.d.ts +33 -0
  65. package/dist/components/views/UImagesView.js +144 -0
  66. package/dist/components/views/UImagesView.styles.d.ts +1 -0
  67. package/dist/components/views/UImagesView.styles.js +219 -0
  68. package/dist/components/views/UMapView.d.ts +24 -0
  69. package/dist/components/views/UMapView.js +45 -0
  70. package/dist/components/views/UMapView.styles.d.ts +1 -0
  71. package/dist/components/views/UMapView.styles.js +47 -0
  72. package/dist/components/views/UVideoView.d.ts +25 -0
  73. package/dist/components/views/UVideoView.js +81 -0
  74. package/dist/components/views/UVideoView.styles.d.ts +1 -0
  75. package/dist/components/views/UVideoView.styles.js +36 -0
  76. package/dist/components/views/UView.d.ts +46 -0
  77. package/dist/components/views/UView.js +113 -0
  78. package/dist/components/views/UView.styles.d.ts +1 -0
  79. package/dist/components/views/UView.styles.js +33 -0
  80. package/dist/events/AttachEvent.d.ts +9 -0
  81. package/dist/events/ChoiceEvent.d.ts +9 -0
  82. package/dist/events/SendEvent.d.ts +7 -0
  83. package/dist/events/StopEvent.d.ts +7 -0
  84. package/dist/index.d.ts +15 -6
  85. package/dist/index.js +28 -38
  86. package/dist/react/UAttachButton.d.ts +11 -0
  87. package/dist/react/UAttachButton.js +12 -0
  88. package/dist/react/UChartView.d.ts +9 -0
  89. package/dist/react/UChartView.js +10 -0
  90. package/dist/react/UCodeBlock.d.ts +9 -0
  91. package/dist/react/UCodeBlock.js +10 -0
  92. package/dist/react/UCopyButton.d.ts +9 -0
  93. package/dist/react/UCopyButton.js +10 -0
  94. package/dist/react/UFileBlock.d.ts +11 -0
  95. package/dist/react/UFileBlock.js +12 -0
  96. package/dist/react/UImagesView.d.ts +9 -0
  97. package/dist/react/UImagesView.js +10 -0
  98. package/dist/react/UJsonBlock.d.ts +9 -0
  99. package/dist/react/UJsonBlock.js +10 -0
  100. package/dist/react/UMapView.d.ts +9 -0
  101. package/dist/react/UMapView.js +10 -0
  102. package/dist/react/UMarkedBlock.d.ts +9 -0
  103. package/dist/react/UMarkedBlock.js +10 -0
  104. package/dist/react/UMessage.d.ts +9 -0
  105. package/dist/react/UMessage.js +10 -0
  106. package/dist/react/UPrompt.d.ts +13 -0
  107. package/dist/react/UPrompt.js +13 -0
  108. package/dist/react/UQuestionIntent.d.ts +11 -0
  109. package/dist/react/UQuestionIntent.js +12 -0
  110. package/dist/react/URefBlock.d.ts +9 -0
  111. package/dist/react/URefBlock.js +10 -0
  112. package/dist/react/URefCard.d.ts +9 -0
  113. package/dist/react/URefCard.js +10 -0
  114. package/dist/react/URefCardGroup.d.ts +9 -0
  115. package/dist/react/URefCardGroup.js +10 -0
  116. package/dist/react/URefTag.d.ts +9 -0
  117. package/dist/react/URefTag.js +10 -0
  118. package/dist/react/UTableBlock.d.ts +9 -0
  119. package/dist/react/UTableBlock.js +10 -0
  120. package/dist/react/UTextBlock.d.ts +9 -0
  121. package/dist/react/UTextBlock.js +10 -0
  122. package/dist/react/UThinkBlock.d.ts +9 -0
  123. package/dist/react/UThinkBlock.js +10 -0
  124. package/dist/react/UToolBlock.d.ts +9 -0
  125. package/dist/react/UToolBlock.js +10 -0
  126. package/dist/react/UVideoView.d.ts +9 -0
  127. package/dist/react/UVideoView.js +10 -0
  128. package/dist/react/UView.d.ts +9 -0
  129. package/dist/react/UView.js +10 -0
  130. package/dist/react/UVoteButton.d.ts +9 -0
  131. package/dist/react/UVoteButton.js +10 -0
  132. package/dist/react/index.d.ts +23 -0
  133. package/dist/react/index.js +23 -0
  134. package/dist/types/BlockItem.d.ts +21 -1
  135. package/dist/types/Intents.d.ts +26 -0
  136. package/dist/types/Intents.js +30 -0
  137. package/dist/types/JsonSchema.d.ts +59 -0
  138. package/dist/types/Views.d.ts +34 -0
  139. package/dist/types/Views.js +150 -0
  140. package/dist/utilities/IntentPromptBuilder.d.ts +40 -0
  141. package/dist/utilities/IntentPromptBuilder.js +95 -0
  142. package/dist/utilities/ViewPromptBuilder.d.ts +28 -0
  143. package/dist/utilities/ViewPromptBuilder.js +76 -0
  144. package/dist/utilities/dom-agent/DOMAgent.d.ts +74 -0
  145. package/dist/utilities/dom-agent/DOMController.d.ts +78 -0
  146. package/dist/utilities/dom-agent/DOMPromptBuilder.d.ts +54 -0
  147. package/dist/utilities/dom-agent/DOMScanner.d.ts +83 -0
  148. package/dist/utilities/dom-agent/index.d.ts +9 -0
  149. package/dist/utilities/dom-agent/types.d.ts +209 -0
  150. package/package.json +34 -18
  151. package/dist/components/blocks/UCodeBlock.component.d.ts +0 -23
  152. package/dist/components/blocks/UCodeBlock.component.js +0 -76
  153. package/dist/components/blocks/UJsonBlock.component.d.ts +0 -45
  154. package/dist/components/blocks/UJsonBlock.component.js +0 -140
  155. package/dist/components/blocks/UMarkedBlock.component.d.ts +0 -45
  156. package/dist/components/blocks/UMarkedBlock.component.js +0 -129
  157. package/dist/components/blocks/URefBlock.component.d.ts +0 -17
  158. package/dist/components/blocks/URefBlock.component.js +0 -74
  159. package/dist/components/blocks/UTextBlock.component.d.ts +0 -37
  160. package/dist/components/blocks/UTextBlock.component.js +0 -123
  161. package/dist/components/blocks/UThinkBlock.component.d.ts +0 -23
  162. package/dist/components/blocks/UThinkBlock.component.js +0 -90
  163. package/dist/components/blocks/UToolBlock.component.d.ts +0 -20
  164. package/dist/components/blocks/UToolBlock.component.js +0 -80
  165. package/dist/components/buttons/UAttachButton.component.d.ts +0 -22
  166. package/dist/components/buttons/UAttachButton.component.js +0 -89
  167. package/dist/components/buttons/UCopyButton.component.d.ts +0 -20
  168. package/dist/components/buttons/UCopyButton.component.js +0 -81
  169. package/dist/components/buttons/UReportButton.component.d.ts +0 -9
  170. package/dist/components/buttons/UReportButton.component.js +0 -36
  171. package/dist/components/buttons/UReportButton.d.ts +0 -7
  172. package/dist/components/buttons/UReportButton.js +0 -5
  173. package/dist/components/buttons/UReportButton.styles.js +0 -14
  174. package/dist/components/buttons/URetryButton.component.d.ts +0 -11
  175. package/dist/components/buttons/URetryButton.component.js +0 -53
  176. package/dist/components/buttons/URetryButton.d.ts +0 -7
  177. package/dist/components/buttons/URetryButton.js +0 -5
  178. package/dist/components/buttons/URetryButton.styles.js +0 -26
  179. package/dist/components/buttons/UShareButton.component.d.ts +0 -9
  180. package/dist/components/buttons/UShareButton.component.js +0 -36
  181. package/dist/components/buttons/UShareButton.d.ts +0 -7
  182. package/dist/components/buttons/UShareButton.js +0 -5
  183. package/dist/components/buttons/UShareButton.styles.js +0 -14
  184. package/dist/components/buttons/UVoteButton.component.d.ts +0 -15
  185. package/dist/components/buttons/UVoteButton.component.js +0 -70
  186. package/dist/components/loaders/UDotLoader.component.d.ts +0 -9
  187. package/dist/components/loaders/UDotLoader.component.js +0 -23
  188. package/dist/components/loaders/UDotLoader.d.ts +0 -7
  189. package/dist/components/loaders/UDotLoader.js +0 -5
  190. package/dist/components/loaders/UDotLoader.styles.js +0 -50
  191. package/dist/components/message/UMessage.component.d.ts +0 -19
  192. package/dist/components/message/UMessage.component.js +0 -90
  193. package/dist/components/prompt/UPrompt.component.d.ts +0 -25
  194. package/dist/components/prompt/UPrompt.component.js +0 -113
  195. package/dist/components/references/URefCard.component.d.ts +0 -24
  196. package/dist/components/references/URefCard.component.js +0 -105
  197. package/dist/components/references/URefCardGroup.component.d.ts +0 -25
  198. package/dist/components/references/URefCardGroup.component.js +0 -88
  199. package/dist/components/references/URefTag.component.d.ts +0 -13
  200. package/dist/components/references/URefTag.component.js +0 -54
  201. package/dist/events/UCancelEvent.d.ts +0 -6
  202. package/dist/events/USubmitEvent.d.ts +0 -6
  203. package/dist/utilities/converters.d.ts +0 -9
  204. package/dist/utilities/converters.js +0 -19
  205. /package/dist/components/{buttons/UReportButton.styles.d.ts → blocks/UFileBlock.styles.d.ts} +0 -0
  206. /package/dist/components/{buttons/URetryButton.styles.d.ts → blocks/UTableBlock.styles.d.ts} +0 -0
  207. /package/dist/components/{buttons/UShareButton.styles.d.ts → intents/UQuestionIntent.styles.d.ts} +0 -0
  208. /package/dist/components/{loaders/UDotLoader.styles.d.ts → views/UChartView.styles.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,151 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 (2026-04-01)
4
+
5
+ ### Breaking Changes
6
+
7
+ #### Full rename: Widget → View, Action → Intent
8
+ - **Widget System → View System**: All widget components renamed to views
9
+ - `UImagesWidget` → `UImagesView`
10
+ - `UVideoWidget` → `UVideoView`
11
+ - `UMapWidget` → `UMapView`
12
+ - `UChartWidget` → `UChartView`
13
+ - `UWidget` → `UView`
14
+ - `types/Widgets.ts` → `types/Views.ts` (`WidgetDefinition`, `PresetWidget` → `ViewDefinition`, `PresetView`)
15
+ - `WidgetPromptBuilder` → `ViewPromptBuilder`
16
+ - **Action System → Intent System**
17
+ - `UQuestionAction` → `UQuestionIntent`
18
+ - `types/Actions.ts` → `types/Intents.ts` (`ActionDefinition` → `IntentDefinition`)
19
+ - `ActionPromptBuilder` → `IntentPromptBuilder`
20
+
21
+ #### Event type renames
22
+ - `UCancelEvent` → `StopEvent`
23
+ - `USubmitEvent` → `SendEvent`
24
+ - Importing the old names will cause compile errors
25
+
26
+ #### Block rename
27
+ - `UFilesBlock` → `UFileBlock` (plural → singular)
28
+ - `FilesBlockItem` + `FileItem` → `FileBlockItem` (simplified structure)
29
+ - `FileUploadStatus` type removed — replaced by `status?: "idle" | "uploading" | "error"` field
30
+
31
+ #### Removed components
32
+ - `UReportButton`, `URetryButton`, `UShareButton` removed
33
+
34
+ #### `UToolBlock` property rename
35
+ - `heading` → `title`
36
+
37
+ #### `package.json` exports change
38
+ - `./dist/*` mapping simplified to a direct `./src/*` mapping
39
+ - `chart.js` moved from `dependencies` to optional `peerDependencies`
40
+
41
+ ### Added
42
+
43
+ #### New events
44
+ - `AttachEvent` (`attach`) — file attach event (`detail.files: File[]`)
45
+ - `ChoiceEvent` (`choice`) — choice selection event (`detail.value: string`)
46
+
47
+ #### DOM Agent utilities (`src/utilities/dom-agent/`) — Experimental
48
+ A utility suite enabling LLMs to autonomously interact with web pages (currently disabled in the main index export)
49
+ - `DOMScanner` — scans the DOM and extracts interactive elements (includes Shadow DOM, supports filter strategies)
50
+ - `DOMController` — executes LLM commands (`click`, `input`, `select`, `scroll`, etc.) against the live DOM
51
+ - `DOMAgent` — orchestrates Scanner and Controller into an automation agent (event-driven, execution history)
52
+ - `DOMPromptBuilder` — builds LLM prompts and formats multimodal messages (Anthropic / OpenAI)
53
+
54
+ #### React bindings
55
+ - Added `./react` package export entry point
56
+ - `@lit/react` and `react` added as optional peerDependencies
57
+
58
+ #### html2canvas dependency
59
+ - Added `html2canvas` for screenshot capture support
60
+
61
+ #### Type improvements
62
+ - `ThinkingBlockItem`: added `loading?: boolean` field
63
+ - `ToolBlockItem`: added `loading?: boolean` field
64
+
65
+ #### Skills documentation
66
+ - `skills/iyulab-chat-components/` — full component reference and utility docs added
67
+
68
+ ### Changed
69
+
70
+ #### Component file structure consolidation
71
+ - Split `.component.ts` + `.ts` pattern → merged into a single `.ts` file per component
72
+ - Component registration switched to `@customElement()` decorator
73
+
74
+ #### Bug fix
75
+ - `UTableBlock`: fixed inline markdown (**bold**, `` `code` ``, `<br>`, etc.) inside table cells rendering as raw text (now uses `Parser.parseInline()`)
76
+
77
+ #### `UThinkBlock` improvements
78
+ - Added `auto-scroll` attribute — automatically scrolls to bottom when `value` changes
79
+ - Added public `scrollToBottom()` method
80
+ - Auto-scroll is now interrupted by wheel or touch input
81
+
82
+ #### Dependency updates
83
+ - `@iyulab/components`: `^0.4.0` → `^1.0.1`
84
+ - `marked`: `^17.0.3` → `^17.0.5`
85
+ - `vite`: `^7.3.1` → `^8.0.3`
86
+ - `openai` (dev): `^6.25.0` → `^6.33.0`
87
+
88
+ #### Documentation overhaul
89
+ - `README.md` fully rewritten with detailed API documentation
90
+ - New `docs/` pages: architecture, block system, events, intent system, view system
91
+ - Old `docs/components/` files removed
92
+
93
+ ### Removed
94
+ - `UReportButton`, `URetryButton`, `UShareButton`
95
+ - `UCancelEvent`, `USubmitEvent` (→ `StopEvent`, `SendEvent`)
96
+ - `UQuestionAction` (→ `UQuestionIntent`)
97
+ - `UWidget`, `UImagesWidget`, `UVideoWidget`, `UMapWidget`, `UChartWidget` (→ View equivalents)
98
+ - `ActionPromptBuilder`, `WidgetPromptBuilder` (→ `IntentPromptBuilder`, `ViewPromptBuilder`)
99
+ - `types/Actions.ts`, `types/Widgets.ts` (→ `types/Intents.ts`, `types/Views.ts`)
100
+ - `utilities/converters.ts` (moved to `@iyulab/components`)
101
+ - `TODO.md`
102
+ - All `.component.ts` split files
103
+
104
+ ---
105
+
106
+ ## 0.4.0 (2026-03-03)
107
+
108
+ ### Breaking Changes
109
+ - `UMessage`: `items` prop removed — block components must now be inserted directly via slots
110
+ - `UMessage`: base class changed from `BaseElement` to `UElement`
111
+
112
+ ### Added
113
+
114
+ #### Widget System
115
+ - `UWidget` — widget container component (dynamic rendering from `widget-json` blocks)
116
+ - `UImagesWidget` — scrollable image gallery widget
117
+ - `UVideoWidget` — video embed widget (YouTube, Vimeo, and direct URL support)
118
+ - `UMapWidget` — OpenStreetMap-based map widget (lat/lng coordinates and marker display)
119
+ - `UChartWidget` — Chart.js chart widget (8 types: bar, line, pie, doughnut, etc.; PNG/JSON download, fullscreen, auto dark-mode theme detection)
120
+
121
+ #### Action System
122
+ - `UQuestionAction` — clickable question choices component (rendered from `action-json` block)
123
+
124
+ #### New Block Types
125
+ - `UFilesBlock` — file attachment list block (filename, size, MIME type, download URL, optional delete button)
126
+ - `UTableBlock` — table display block
127
+
128
+ #### New Types
129
+ - `JsonSchema` — JSON Schema types for LLM use (`BooleanJsonSchema`, `StringJsonSchema`, `NumberJsonSchema`, `ArrayJsonSchema`, `ObjectJsonSchema`)
130
+ - `ActionDefinition`, `ActionSchema`, `PresetAction` — action definition and preset types
131
+ - `WidgetDefinition`, `PresetWidget` — widget definition and preset types (`Images`, `Video`, `Map`, `Chart`)
132
+ - `FilesBlockItem`, `FileItem` — file block types
133
+ - `MessageFit` — message width setting type (`full` | `auto`)
134
+
135
+ #### New Utilities
136
+ - `ActionPromptBuilder` — utility for auto-generating LLM action prompts
137
+ - `WidgetPromptBuilder` — utility for auto-generating LLM widget prompts
138
+
139
+ ### Changed
140
+ - `UMessage`: migrated from `BaseElement` to `UElement`, removed `items` prop in favour of slot-based rendering, added `fit` attribute (`MessageFit`)
141
+ - `UMarkedBlock`: markdown rendering logic fully reworked
142
+ - `UPrompt`: style improvements
143
+
144
+ ### Removed
145
+ - `UDotLoader` component removed
146
+
147
+ ---
148
+
3
149
  ## 0.3.0 (2026-01-22)
4
150
 
5
151
  - Renamed `TextBlockReference` to `ReferenceCitation` and field `name` to `label`
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
- # @iyulab/chat-components
1
+ # @iyulab/chat-components
2
2
 
3
- LLM 채팅 인터페이스를 위한 웹 컴포넌트 라이브러리
3
+ Web component library for building LLM chat interfaces — works in any framework or vanilla HTML.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@iyulab/chat-components)](https://www.npmjs.com/package/@iyulab/chat-components)
6
+ [![license](https://img.shields.io/npm/l/@iyulab/chat-components)](./LICENSE)
7
+
8
+ ---
4
9
 
5
10
  ## Installation
6
11
 
@@ -8,29 +13,141 @@ LLM 채팅 인터페이스를 위한 웹 컴포넌트 라이브러리
8
13
  npm install @iyulab/chat-components
9
14
  ```
10
15
 
11
- ## Usage
16
+ ---
17
+
18
+ ## Quick Start
12
19
 
13
- ```typescript
20
+ ```ts
14
21
  import '@iyulab/chat-components';
15
22
  ```
16
23
 
24
+ ```html
25
+ <u-message>
26
+ <u-marked-block value="# Hello&#10;&#10;This is **markdown**."></u-marked-block>
27
+ </u-message>
28
+
29
+ <u-prompt placeholder="Type a message...">
30
+ <u-attach-button slot="left-actions" multiple>Attach</u-attach-button>
31
+ </u-prompt>
32
+ ```
33
+
34
+ ```ts
35
+ const prompt = document.querySelector('u-prompt');
36
+
37
+ prompt.addEventListener('send', () => {
38
+ console.log('value:', prompt.value);
39
+ console.log('files:', prompt.files);
40
+ });
41
+ ```
42
+
43
+ > For a complete setup guide, see **[docs/getting-started.md](./docs/getting-started.md)**.
44
+
45
+ ---
46
+
47
+ ## Skills Usage
48
+
49
+ Skills for LLM coding agents (Claude Code, GitHub Copilot, Cursor, etc.).
50
+
51
+ ```bash
52
+ # Install from GitHub
53
+ npx skills add iyulab/node-chat-components
54
+
55
+ # Reference locally after package install
56
+ npx skills add ./node_modules/@iyulab/chat-components
57
+ ```
58
+
59
+ ---
60
+
17
61
  ## Components
18
62
 
19
- - `u-message` - 메시지 컴포넌트
20
- - `u-code-block` - 코드 블록
21
- - `u-marked-block` - 마크다운 렌더링
22
- - `u-text-block` - 텍스트 블록
23
- - `u-think-block` - 추론 과정 표시
24
- - `u-tool-block` - 도구 호출 표시
25
- - `u-attach-button` - 파일 첨부
26
- - `u-copy-button` - 복사 버튼
27
- - `u-send-button` - 전송 버튼
28
- - `u-think-button` - 추론 레벨 설정
63
+ ### Message & Input
64
+
65
+ | Tag | Description |
66
+ |-----|-------------|
67
+ | `u-message` | Chat message wrapper. Slot-based block layout, loading animation, bubble/default styles |
68
+ | `u-prompt` | Chat input. Auto-resize textarea, file attachment preview, integrated send/stop button |
69
+
70
+ ### Content Blocks
71
+
72
+ | Tag | Description |
73
+ |-----|-------------|
74
+ | `u-marked-block` | Markdown renderer — KaTeX, code highlighting, citation injection, view-json/intent-json handling |
75
+ | `u-code-block` | Syntax-highlighted code block (Highlight.js) with language label and copy button |
76
+ | `u-text-block` | Plain text display or editable textarea |
77
+ | `u-think-block` | LLM reasoning block — collapse/expand, auto-scroll |
78
+ | `u-tool-block` | Tool call input/output display — collapse/expand |
79
+ | `u-file-block` | File card — type icon, upload status, download, remove |
80
+ | `u-ref-block` | Reference source group — collapse/expand, card grid |
81
+ | `u-json-block` | Collapsible JSON tree |
82
+ | `u-table-block` | Table — column sort, search, CSV/XLS download |
83
+
84
+ ### Action Buttons
85
+
86
+ | Tag | Description |
87
+ |-----|-------------|
88
+ | `u-copy-button` | Copies text to clipboard; icon confirms copy |
89
+ | `u-vote-button` | Thumbs-up / thumbs-down vote pair |
90
+ | `u-attach-button` | Opens file picker; fires `attach` event |
91
+
92
+ ---
93
+
94
+ ## Intent & View Systems
95
+
96
+ ```ts
97
+ import { IntentPromptBuilder, ViewPromptBuilder, PresetIntent, PresetView } from '@iyulab/chat-components';
98
+
99
+ // Build system prompt instructions
100
+ const intentInstructions = IntentPromptBuilder.instance.use(PresetIntent.Questions).build();
101
+ const viewInstructions = ViewPromptBuilder.instance.use(PresetView.All).build();
102
+
103
+ const systemPrompt = `You are a helpful assistant.\n\n${intentInstructions}\n\n${viewInstructions}`;
104
+
105
+ // Parse LLM response
106
+ const [intents, cleanText] = IntentPromptBuilder.instance.parse(llmResponse);
107
+ markedBlock.value = cleanText; // view-json blocks inside are rendered automatically
108
+
109
+ for (const intent of intents) {
110
+ if (intent.type === 'question') {
111
+ const el = document.createElement('u-question-intent') as any;
112
+ el.question = intent.properties?.question;
113
+ el.choices = intent.properties?.choices ?? [];
114
+ el.addEventListener('choice', (e: any) => { prompt.value = e.detail.value; prompt.submit(); });
115
+ msg.appendChild(el);
116
+ }
117
+ }
118
+ ```
119
+
120
+ > - Intent system details: **[docs/intent-system.md](./docs/intent-system.md)**
121
+ > - View system details: **[docs/view-system.md](./docs/view-system.md)**
122
+
123
+ ---
124
+
125
+ ## Events
126
+
127
+ | Event | Source | Detail | Description |
128
+ |-------|--------|--------|-------------|
129
+ | `send` | `u-prompt` | — | Send button clicked or Enter pressed |
130
+ | `stop` | `u-prompt` | — | Stop button clicked while loading |
131
+ | `attach` | `u-attach-button` | `{ files: File[] }` | File selection completed |
132
+ | `choice` | `u-question-intent` | `{ value: string }` | Choice button clicked |
133
+ | `change` | `u-vote-button` | — | Vote state changed |
134
+ | `remove` | `u-file-block` | — | Remove button clicked |
135
+
136
+ ---
29
137
 
30
138
  ## Documentation
31
139
 
32
- 자세한 사용법은 [docs](./docs/README.md)를 참고하세요.
140
+ | File | Description |
141
+ |------|-------------|
142
+ | [docs/getting-started.md](./docs/getting-started.md) | Installation, basic chat UI, streaming, history rendering |
143
+ | [docs/architecture.md](./docs/architecture.md) | Package structure, class hierarchy, rendering pipeline |
144
+ | [docs/block-system.md](./docs/block-system.md) | Block components and `BlockItem` types in depth |
145
+ | [docs/intent-system.md](./docs/intent-system.md) | Intent system setup and custom intents |
146
+ | [docs/view-system.md](./docs/view-system.md) | View system setup and custom views |
147
+ | [docs/events.md](./docs/events.md) | Full event reference |
148
+
149
+ ---
33
150
 
34
151
  ## License
35
152
 
36
- MIT
153
+ MIT © iyulab
@@ -0,0 +1,9 @@
1
+ //#region \0@oxc-project+runtime@0.122.0/helpers/decorate.js
2
+ function __decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
8
+ //#endregion
9
+ export { __decorate };
@@ -0,0 +1,6 @@
1
+ //#region \0@oxc-project+runtime@0.122.0/helpers/decorateMetadata.js
2
+ function __decorateMetadata(k, v) {
3
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4
+ }
5
+ //#endregion
6
+ export { __decorateMetadata };
@@ -0,0 +1,4 @@
1
+ //#region \0glob-assets_raw/intent-prompt.md.1907474e
2
+ var intent_prompt_md_default = "## Interactive Intents\n\nYou can guide the user with interactive intents by appending `intent-json` fenced code blocks at the end of your response. These intents can suggest follow-up questions, offer buttons to click, or provide other interactive elements that help the user continue the conversation.\n\n**Output format (the fence language must be `intent-json`):**\n```intent-json\n{\n \"type\": \"intent-type-here\",\n \"properties\" : {\n \"key\": \"value\"\n }\n}\n```\n\n**Rules — follow these STRICTLY. Violation means the feature will not work:**\n1. The fenced block language identifier must be `intent-json`, not `json` or anything else.\n2. `type` must be one of the exact strings listed below. Do not invent new types.\n3. place ALL intent blocks at the very end of your response, after all prose content.\n4. Output valid JSON only — no comments, no trailing commas, etc.\n\n---\n\n{{INTENT_DOCS}}\n";
3
+ //#endregion
4
+ export { intent_prompt_md_default as default };
@@ -0,0 +1,4 @@
1
+ //#region \0glob-assets_raw/view-prompt.md.e0dbcffe
2
+ var view_prompt_md_default = "## Renderable Views\n\nYou can render interactive visual views inside your response.\nWhen a view would make your answer clearer or more useful, output a `view-json` fenced code block.\n\n**Output format (the fence language must be `view-json`):**\n```view-json\n{\n \"tag\": \"view-tag-here\",\n \"properties\": {\n \"key\": \"value\"\n }\n}\n```\n\n**Rules — follow these strictly:**\n1. The fenced block language identifier must be `view-json`, not `json` or anything else.\n2. `tag` must be one of the exact strings listed below. Never invent a tag.\n3. Output valid JSON — no comments, no trailing commas.\n\n---\n\n{{VIEW_DOCS}}\n";
3
+ //#endregion
4
+ export { view_prompt_md_default as default };
@@ -1,7 +1,29 @@
1
- import { UCodeBlock } from './UCodeBlock.component.js';
1
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
2
+ /**
3
+ * 코드 블록을 렌더링하는 컴포넌트입니다.
4
+ * 언어와 코드를 받아 syntax highlighting을 적용합니다.
5
+ */
6
+ export declare class UCodeBlock extends UElement {
7
+ static styles: import('lit').CSSResultGroup[];
8
+ /** 코드 블록이 로딩 중인지 여부를 나타냅니다. */
9
+ loading: boolean;
10
+ /** 코드 블록의 헤더를 숨길지 여부를 지정합니다. */
11
+ headless: boolean;
12
+ /** 코드 언어를 지정합니다. */
13
+ lang: string;
14
+ /** 표시할 코드 내용입니다. */
15
+ value?: string;
16
+ /** 클립보드 복사 상태를 나타내는 플래그입니다. */
17
+ isCopied: boolean;
18
+ render(): import('lit-html').TemplateResult<1>;
19
+ /**
20
+ * slot에 할당된 코드를 value로 설정합니다.
21
+ * 이 기능을 통해 HTML 내에 직접 코드를 작성할 수 있습니다.
22
+ */
23
+ private handleSlotChange;
24
+ }
2
25
  declare global {
3
26
  interface HTMLElementTagNameMap {
4
27
  "u-code-block": UCodeBlock;
5
28
  }
6
29
  }
7
- export { UCodeBlock };
@@ -1,5 +1,68 @@
1
- import { UCodeBlock } from './UCodeBlock.component.js';
1
+ import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js";
3
+ import "../buttons/UCopyButton.js";
4
+ import { styles } from "./UCodeBlock.styles.js";
5
+ import { html } from "lit";
6
+ import { customElement, property, state } from "lit/decorators.js";
7
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
8
+ import hljs from "highlight.js";
9
+ import "@iyulab/components/dist/components/icon/UIcon.js";
10
+ import "@iyulab/components/dist/components/spinner/USpinner.js";
11
+ import { UElement } from "@iyulab/components/dist/components/UElement.js";
12
+ //#region src/components/blocks/UCodeBlock.ts
13
+ var UCodeBlock = class UCodeBlock extends UElement {
14
+ constructor(..._args) {
15
+ super(..._args);
16
+ this.loading = false;
17
+ this.headless = false;
18
+ this.lang = "plaintext";
19
+ this.isCopied = false;
20
+ this.handleSlotChange = (e) => {
21
+ this.value = e.target.assignedNodes({ flatten: true }).map((node) => node.textContent).join("\n\n");
22
+ };
23
+ }
24
+ static {
25
+ this.styles = [super.styles, styles];
26
+ }
27
+ render() {
28
+ const lang = hljs.getLanguage(this.lang) ? this.lang : "plaintext";
29
+ const value = this.value || "";
30
+ return html`
31
+ <div class="header" ?hidden=${this.headless}>
32
+ <span class="status">
33
+ ${this.loading ? html`<u-spinner></u-spinner>` : html`<u-icon lib="bootstrap" name="code-slash"></u-icon>`}
34
+ </span>
35
+ <span class="lang">
36
+ ${lang}
37
+ </span>
38
+ <div style="flex: 1"></div>
39
+ <u-copy-button
40
+ .value=${value}
41
+ ></u-copy-button>
42
+ </div>
2
43
 
3
- UCodeBlock.define("u-code-block");
44
+ <pre class="hljs">${unsafeHTML(hljs.highlight(value, { language: lang }).value)}</pre>
4
45
 
46
+ <div hidden aria-hidden="true">
47
+ <slot @slotchange=${this.handleSlotChange}></slot>
48
+ </div>
49
+ `;
50
+ }
51
+ };
52
+ __decorate([property({
53
+ type: Boolean,
54
+ reflect: true
55
+ }), __decorateMetadata("design:type", Boolean)], UCodeBlock.prototype, "loading", void 0);
56
+ __decorate([property({
57
+ type: Boolean,
58
+ reflect: true
59
+ }), __decorateMetadata("design:type", Boolean)], UCodeBlock.prototype, "headless", void 0);
60
+ __decorate([property({
61
+ type: String,
62
+ reflect: true
63
+ }), __decorateMetadata("design:type", String)], UCodeBlock.prototype, "lang", void 0);
64
+ __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UCodeBlock.prototype, "value", void 0);
65
+ __decorate([state(), __decorateMetadata("design:type", Boolean)], UCodeBlock.prototype, "isCopied", void 0);
66
+ UCodeBlock = __decorate([customElement("u-code-block")], UCodeBlock);
67
+ //#endregion
5
68
  export { UCodeBlock };
@@ -1,6 +1,6 @@
1
- import { css } from 'lit';
2
-
3
- const styles = css`
1
+ import { css } from "lit";
2
+ //#region src/components/blocks/UCodeBlock.styles.ts
3
+ var styles = css`
4
4
  :host {
5
5
  --hljs-text-color: #24292e;
6
6
  --hljs-background-color: #ffffff;
@@ -51,9 +51,15 @@ const styles = css`
51
51
  flex-direction: row;
52
52
  align-items: center;
53
53
  justify-content: space-between;
54
+ gap: 12px;
54
55
  margin-bottom: 12px;
55
56
  user-select: none;
56
57
  }
58
+ .header .status {
59
+ display: inline-flex;
60
+ font-size: 12px;
61
+ color: var(--u-txt-color-strong);
62
+ }
57
63
  .header .lang {
58
64
  font-family: Arial, Helvetica, sans-serif;
59
65
  font-size: 12px;
@@ -172,5 +178,5 @@ const styles = css`
172
178
  color: currentColor;
173
179
  }
174
180
  `;
175
-
181
+ //#endregion
176
182
  export { styles };
@@ -0,0 +1,33 @@
1
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
2
+ /**
3
+ * 단일 파일을 표시하는 블록 컴포넌트입니다.
4
+ */
5
+ export declare class UFileBlock extends UElement {
6
+ static styles: import('lit').CSSResultGroup[];
7
+ /** 삭제 버튼 표시 */
8
+ removable: boolean;
9
+ /** 파일 상태 */
10
+ status?: 'idle' | 'uploading' | 'error';
11
+ /** 파일 이름 */
12
+ name?: string;
13
+ /** MIME 타입 */
14
+ type?: string;
15
+ /** 파일 크기 (bytes) */
16
+ size?: number;
17
+ /** 다운로드 URL */
18
+ url?: string;
19
+ render(): import('lit-html').TemplateResult<1>;
20
+ private handleDownloadClick;
21
+ private handleRemoveClick;
22
+ /** MIME 타입 → Bootstrap Icon 이름 */
23
+ private resolveIcon;
24
+ /** 파일명 또는 MIME 타입에서 확장자를 추출합니다. */
25
+ private resolveExt;
26
+ /** bytes → 읽기 좋은 크기 문자열 */
27
+ private formatSize;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ "u-file-block": UFileBlock;
32
+ }
33
+ }
@@ -0,0 +1,154 @@
1
+ import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js";
3
+ import { styles } from "./UFileBlock.styles.js";
4
+ import { html } from "lit";
5
+ import { customElement, property } from "lit/decorators.js";
6
+ import "@iyulab/components/dist/components/icon/UIcon.js";
7
+ import "@iyulab/components/dist/components/spinner/USpinner.js";
8
+ import "@iyulab/components/dist/components/button/UButton.js";
9
+ import { UElement } from "@iyulab/components/dist/components/UElement.js";
10
+ //#region src/components/blocks/UFileBlock.ts
11
+ var UFileBlock = class UFileBlock extends UElement {
12
+ constructor(..._args) {
13
+ super(..._args);
14
+ this.removable = false;
15
+ this.handleDownloadClick = (e) => {
16
+ e.stopPropagation();
17
+ if (!this.url) return;
18
+ const a = document.createElement("a");
19
+ a.href = this.url;
20
+ a.download = this.name || "unknown-file";
21
+ a.target = "_blank";
22
+ a.rel = "noopener noreferrer";
23
+ document.body.appendChild(a);
24
+ a.click();
25
+ a.remove();
26
+ };
27
+ this.handleRemoveClick = (e) => {
28
+ e.stopPropagation();
29
+ if (this.fire("remove")) this.remove();
30
+ };
31
+ }
32
+ static {
33
+ this.styles = [super.styles, styles];
34
+ }
35
+ render() {
36
+ return html`
37
+ <div class="thumbnail">
38
+ <u-spinner
39
+ ?hidden=${this.status !== "uploading"}
40
+ ></u-spinner>
41
+ <u-icon
42
+ ?hidden=${this.status !== "error"}
43
+ lib="bootstrap"
44
+ name="file-earmark-x"
45
+ ></u-icon>
46
+ <u-icon
47
+ ?hidden=${this.status && this.status !== "idle"}
48
+ lib="bootstrap"
49
+ name=${this.resolveIcon(this.type)}
50
+ ></u-icon>
51
+ <u-button class="download-btn"
52
+ ?hidden=${!this.url || this.status === "uploading" || this.status === "error"}
53
+ title="Download"
54
+ @click=${this.handleDownloadClick}>
55
+ <u-icon lib="bootstrap" name="download"></u-icon>
56
+ </u-button>
57
+ </div>
58
+
59
+ <div class="info">
60
+ <div class="name">${this.name}</div>
61
+ <div class="meta">
62
+ <span class="type">
63
+ ${this.resolveExt(this.name, this.type)}
64
+ </span>
65
+ <span class="size">
66
+ ${this.formatSize(this.size || 0)}
67
+ </span>
68
+ </div>
69
+ </div>
70
+
71
+ <u-button class="remove-btn"
72
+ ?hidden=${!this.removable}
73
+ title="Remove"
74
+ @click=${this.handleRemoveClick}>
75
+ <u-icon lib="internal" name="x-lg"></u-icon>
76
+ </u-button>
77
+ `;
78
+ }
79
+ /** MIME 타입 → Bootstrap Icon 이름 */
80
+ resolveIcon(mimeType) {
81
+ if (!mimeType) return "file-earmark";
82
+ if (mimeType.startsWith("image/")) return "file-earmark-image";
83
+ if (mimeType.startsWith("video/")) return "file-earmark-play";
84
+ if (mimeType.startsWith("audio/")) return "file-earmark-music";
85
+ if (mimeType === "application/pdf") return "file-earmark-pdf";
86
+ if ([
87
+ "application/json",
88
+ "application/javascript",
89
+ "application/typescript",
90
+ "application/xml",
91
+ "text/html",
92
+ "text/css",
93
+ "text/javascript",
94
+ "text/x-python",
95
+ "text/x-java-source"
96
+ ].includes(mimeType) || mimeType.startsWith("text/x-")) return "file-earmark-code";
97
+ if ([
98
+ "application/vnd.ms-excel",
99
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
100
+ "text/csv"
101
+ ].includes(mimeType)) return "file-earmark-spreadsheet";
102
+ if ([
103
+ "application/zip",
104
+ "application/x-zip-compressed",
105
+ "application/x-tar",
106
+ "application/x-rar-compressed",
107
+ "application/gzip",
108
+ "application/x-7z-compressed"
109
+ ].includes(mimeType)) return "file-earmark-zip";
110
+ if (mimeType.startsWith("text/")) return "file-earmark-text";
111
+ return "file-earmark";
112
+ }
113
+ /** 파일명 또는 MIME 타입에서 확장자를 추출합니다. */
114
+ resolveExt(name, mimeType) {
115
+ if (name) {
116
+ const dot = name.lastIndexOf(".");
117
+ if (dot !== -1 && dot < name.length - 1) return name.slice(dot + 1).toLowerCase();
118
+ }
119
+ return mimeType ? {
120
+ "image/jpeg": "jpg",
121
+ "image/png": "png",
122
+ "image/gif": "gif",
123
+ "image/webp": "webp",
124
+ "image/svg+xml": "svg",
125
+ "application/pdf": "pdf",
126
+ "text/plain": "txt",
127
+ "text/csv": "csv",
128
+ "application/json": "json",
129
+ "application/zip": "zip"
130
+ }[mimeType] ?? mimeType.split("/").pop() ?? "" : "";
131
+ }
132
+ /** bytes → 읽기 좋은 크기 문자열 */
133
+ formatSize(bytes) {
134
+ if (bytes < 1024) return `${bytes} B`;
135
+ if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`;
136
+ if (bytes < 1024 ** 3) return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
137
+ return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
138
+ }
139
+ };
140
+ __decorate([property({
141
+ type: Boolean,
142
+ reflect: true
143
+ }), __decorateMetadata("design:type", Object)], UFileBlock.prototype, "removable", void 0);
144
+ __decorate([property({
145
+ type: String,
146
+ reflect: true
147
+ }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "status", void 0);
148
+ __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "name", void 0);
149
+ __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "type", void 0);
150
+ __decorate([property({ type: Number }), __decorateMetadata("design:type", Number)], UFileBlock.prototype, "size", void 0);
151
+ __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "url", void 0);
152
+ UFileBlock = __decorate([customElement("u-file-block")], UFileBlock);
153
+ //#endregion
154
+ export { UFileBlock };