@iyulab/chat-components 0.6.0 → 0.7.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 (211) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +15 -39
  3. package/dist/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.139.0/helpers/esm}/decorate.js +2 -2
  4. package/dist/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.139.0/helpers/esm}/decorateMetadata.js +2 -2
  5. package/dist/_virtual/_glob-assets_raw/alert-triangle-fill.svg.4cfc4305.js +4 -0
  6. package/dist/_virtual/_glob-assets_raw/arrows-sort.svg.dda43a85.js +4 -0
  7. package/dist/_virtual/_glob-assets_raw/code.svg.c69bc144.js +4 -0
  8. package/dist/_virtual/_glob-assets_raw/download.svg.bce82177.js +4 -0
  9. package/dist/_virtual/_glob-assets_raw/element-prompt.md.7047ffcc.js +4 -0
  10. package/dist/_virtual/_glob-assets_raw/external-link.svg.a9f7f02d.js +4 -0
  11. package/dist/_virtual/_glob-assets_raw/file-code.svg.0e706f93.js +4 -0
  12. package/dist/_virtual/_glob-assets_raw/file-music.svg.b9970203.js +4 -0
  13. package/dist/_virtual/_glob-assets_raw/file-spreadsheet.svg.8c03bdfa.js +4 -0
  14. package/dist/_virtual/_glob-assets_raw/file-text.svg.85bdd923.js +4 -0
  15. package/dist/_virtual/_glob-assets_raw/file-type-pdf.svg.bc12db6d.js +4 -0
  16. package/dist/_virtual/_glob-assets_raw/file-zip.svg.76dde660.js +4 -0
  17. package/dist/_virtual/_glob-assets_raw/file.svg.28f5d6f1.js +4 -0
  18. package/dist/_virtual/_glob-assets_raw/photo.svg.cc273cc1.js +4 -0
  19. package/dist/_virtual/_glob-assets_raw/player-stop-fill.svg.5378b752.js +4 -0
  20. package/dist/_virtual/_glob-assets_raw/send.svg.02326253.js +4 -0
  21. package/dist/_virtual/_glob-assets_raw/sort-ascending-letters.svg.14a3df67.js +4 -0
  22. package/dist/_virtual/_glob-assets_raw/sort-descending-letters.svg.3e03647c.js +4 -0
  23. package/dist/_virtual/_glob-assets_raw/video.svg.c183f03c.js +4 -0
  24. package/dist/_virtual/_glob-assets_raw/world.svg.cd9903c8.js +4 -0
  25. package/dist/components/UDataElement.d.ts +48 -0
  26. package/dist/components/UDataElement.js +80 -0
  27. package/dist/components/blocks/UCodeBlock.d.ts +0 -4
  28. package/dist/components/blocks/UCodeBlock.js +6 -12
  29. package/dist/components/{views/UView.d.ts → blocks/UElementBlock.d.ts} +18 -8
  30. package/dist/components/{views/UView.js → blocks/UElementBlock.js} +31 -21
  31. package/dist/components/{views/UView.styles.js → blocks/UElementBlock.styles.js} +1 -1
  32. package/dist/components/blocks/UFileBlock.d.ts +15 -5
  33. package/dist/components/blocks/UFileBlock.js +81 -68
  34. package/dist/components/blocks/UFileBlock.styles.js +86 -29
  35. package/dist/components/blocks/UMarkedBlock.d.ts +3 -1
  36. package/dist/components/blocks/UMarkedBlock.js +23 -18
  37. package/dist/components/blocks/URefBlock.js +2 -2
  38. package/dist/components/blocks/UTableBlock.d.ts +2 -2
  39. package/dist/components/blocks/UTableBlock.js +9 -8
  40. package/dist/components/blocks/UTableBlock.styles.js +1 -1
  41. package/dist/components/blocks/UTextBlock.d.ts +2 -0
  42. package/dist/components/blocks/UTextBlock.js +4 -5
  43. package/dist/components/message/UMessage.js +2 -2
  44. package/dist/components/prompt/UPrompt.d.ts +0 -5
  45. package/dist/components/prompt/UPrompt.js +18 -27
  46. package/dist/components/prompt/UPrompt.styles.js +9 -10
  47. package/dist/components/references/URefCard.d.ts +6 -5
  48. package/dist/components/references/URefCard.js +14 -11
  49. package/dist/components/references/URefCardGroup.js +2 -2
  50. package/dist/components/references/URefTag.js +5 -4
  51. package/dist/{components/views/UChartView.d.ts → components-extra/UChartBlock.d.ts} +4 -4
  52. package/dist/{components/views/UChartView.js → components-extra/UChartBlock.js} +22 -34
  53. package/dist/components-extra/UChartBlock.schema.d.ts +3 -0
  54. package/dist/components-extra/UChartBlock.schema.js +34 -0
  55. package/dist/{components/views/UChartView.styles.js → components-extra/UChartBlock.styles.js} +1 -1
  56. package/dist/{components/views/UImagesView.d.ts → components-extra/UImagesBlock.d.ts} +4 -4
  57. package/dist/{components/views/UImagesView.js → components-extra/UImagesBlock.js} +15 -15
  58. package/dist/components-extra/UImagesBlock.schema.d.ts +3 -0
  59. package/dist/components-extra/UImagesBlock.schema.js +31 -0
  60. package/dist/{components/views/UImagesView.styles.js → components-extra/UImagesBlock.styles.js} +5 -5
  61. package/dist/{components/views/UMapView.d.ts → components-extra/UMapBlock.d.ts} +4 -4
  62. package/dist/{components/views/UMapView.js → components-extra/UMapBlock.js} +18 -18
  63. package/dist/components-extra/UMapBlock.schema.d.ts +3 -0
  64. package/dist/components-extra/UMapBlock.schema.js +33 -0
  65. package/dist/{components/views/UMapView.styles.js → components-extra/UMapBlock.styles.js} +1 -1
  66. package/dist/{components/views/UVideoView.d.ts → components-extra/UVideoBlock.d.ts} +4 -4
  67. package/dist/{components/views/UVideoView.js → components-extra/UVideoBlock.js} +10 -10
  68. package/dist/components-extra/UVideoBlock.schema.d.ts +3 -0
  69. package/dist/components-extra/UVideoBlock.schema.js +28 -0
  70. package/dist/{components/views/UVideoView.styles.js → components-extra/UVideoBlock.styles.js} +1 -1
  71. package/dist/events/SendEvent.d.ts +0 -5
  72. package/dist/events/StopEvent.d.ts +0 -5
  73. package/dist/extra.d.ts +6 -0
  74. package/dist/extra.js +14 -0
  75. package/dist/index.d.ts +5 -17
  76. package/dist/index.js +6 -16
  77. package/dist/react/UCodeBlock.js +2 -2
  78. package/dist/react/UElementBlock.d.ts +9 -0
  79. package/dist/react/UElementBlock.js +10 -0
  80. package/dist/react/UFileBlock.js +2 -2
  81. package/dist/react/UImagesBlock.d.ts +9 -0
  82. package/dist/react/UImagesBlock.js +10 -0
  83. package/dist/react/UMapBlock.d.ts +9 -0
  84. package/dist/react/UMapBlock.js +10 -0
  85. package/dist/react/UMarkedBlock.js +2 -2
  86. package/dist/react/UMessage.js +2 -2
  87. package/dist/react/UPrompt.js +2 -2
  88. package/dist/react/URefBlock.js +2 -2
  89. package/dist/react/URefCard.js +2 -2
  90. package/dist/react/URefCardGroup.js +2 -2
  91. package/dist/react/URefTag.js +2 -2
  92. package/dist/react/UTableBlock.js +2 -2
  93. package/dist/react/UTextBlock.d.ts +1 -0
  94. package/dist/react/UTextBlock.js +5 -3
  95. package/dist/react/UVideoBlock.d.ts +9 -0
  96. package/dist/react/UVideoBlock.js +10 -0
  97. package/dist/react/index.d.ts +4 -11
  98. package/dist/react/index.js +4 -11
  99. package/dist/types/BlockItem.d.ts +1 -24
  100. package/dist/types/{JsonSchema.d.ts → Schema.d.ts} +13 -0
  101. package/dist/utilities/HtmlBuilder.d.ts +28 -0
  102. package/dist/utilities/HtmlBuilder.js +41 -0
  103. package/dist/utilities/PromptBuilder.d.ts +21 -0
  104. package/dist/utilities/PromptBuilder.js +60 -0
  105. package/dist/utilities/icons.d.ts +1 -0
  106. package/dist/utilities/icons.js +52 -0
  107. package/dist/utilities/sanitizers.d.ts +35 -0
  108. package/dist/utilities/sanitizers.js +75 -0
  109. package/package.json +18 -19
  110. package/skills/iyulab-chat-components/SKILL.md +18 -33
  111. package/skills/iyulab-chat-components/references/components/{chart-view.md → chart-block.md} +16 -12
  112. package/skills/iyulab-chat-components/references/components/code-block.md +1 -5
  113. package/skills/iyulab-chat-components/references/components/element-block.md +57 -0
  114. package/skills/iyulab-chat-components/references/components/file-block.md +22 -25
  115. package/skills/iyulab-chat-components/references/components/{images-view.md → images-block.md} +10 -10
  116. package/skills/iyulab-chat-components/references/components/{map-view.md → map-block.md} +9 -9
  117. package/skills/iyulab-chat-components/references/components/marked-block.md +5 -4
  118. package/skills/iyulab-chat-components/references/components/message.md +1 -2
  119. package/skills/iyulab-chat-components/references/components/prompt.md +12 -21
  120. package/skills/iyulab-chat-components/references/components/{video-view.md → video-block.md} +10 -10
  121. package/skills/iyulab-chat-components/references/extra-system.md +95 -0
  122. package/skills/iyulab-chat-components/references/types.md +17 -31
  123. package/skills/iyulab-chat-components/references/usage.md +13 -81
  124. package/skills/iyulab-chat-components/references/utilities/html-builder.md +35 -0
  125. package/skills/iyulab-chat-components/references/utilities/prompt-builder.md +73 -0
  126. package/dist/_virtual/_glob-assets_raw/intent-prompt.md.1907474e.js +0 -4
  127. package/dist/_virtual/_glob-assets_raw/view-prompt.md.e0dbcffe.js +0 -4
  128. package/dist/chart.d.ts +0 -1
  129. package/dist/chart.js +0 -2
  130. package/dist/components/blocks/UJsonBlock.d.ts +0 -49
  131. package/dist/components/blocks/UJsonBlock.js +0 -130
  132. package/dist/components/blocks/UJsonBlock.styles.js +0 -115
  133. package/dist/components/blocks/UThinkBlock.d.ts +0 -35
  134. package/dist/components/blocks/UThinkBlock.js +0 -87
  135. package/dist/components/blocks/UThinkBlock.styles.js +0 -74
  136. package/dist/components/blocks/UToolBlock.d.ts +0 -24
  137. package/dist/components/blocks/UToolBlock.js +0 -70
  138. package/dist/components/blocks/UToolBlock.styles.js +0 -66
  139. package/dist/components/buttons/UAttachButton.d.ts +0 -26
  140. package/dist/components/buttons/UAttachButton.js +0 -63
  141. package/dist/components/buttons/UAttachButton.styles.js +0 -14
  142. package/dist/components/buttons/UCopyButton.d.ts +0 -24
  143. package/dist/components/buttons/UCopyButton.js +0 -59
  144. package/dist/components/buttons/UCopyButton.styles.js +0 -18
  145. package/dist/components/buttons/UVoteButton.d.ts +0 -19
  146. package/dist/components/buttons/UVoteButton.js +0 -64
  147. package/dist/components/buttons/UVoteButton.styles.d.ts +0 -1
  148. package/dist/components/buttons/UVoteButton.styles.js +0 -19
  149. package/dist/components/intents/UQuestionIntent.d.ts +0 -22
  150. package/dist/components/intents/UQuestionIntent.js +0 -41
  151. package/dist/components/intents/UQuestionIntent.styles.d.ts +0 -1
  152. package/dist/components/intents/UQuestionIntent.styles.js +0 -43
  153. package/dist/components/views/UChartView.styles.d.ts +0 -1
  154. package/dist/components/views/UImagesView.styles.d.ts +0 -1
  155. package/dist/components/views/UMapView.styles.d.ts +0 -1
  156. package/dist/components/views/UVideoView.styles.d.ts +0 -1
  157. package/dist/components/views/UView.styles.d.ts +0 -1
  158. package/dist/events/AttachEvent.d.ts +0 -9
  159. package/dist/events/ChoiceEvent.d.ts +0 -9
  160. package/dist/react/UAttachButton.d.ts +0 -11
  161. package/dist/react/UAttachButton.js +0 -12
  162. package/dist/react/UCopyButton.d.ts +0 -9
  163. package/dist/react/UCopyButton.js +0 -10
  164. package/dist/react/UImagesView.d.ts +0 -9
  165. package/dist/react/UImagesView.js +0 -10
  166. package/dist/react/UJsonBlock.d.ts +0 -9
  167. package/dist/react/UJsonBlock.js +0 -10
  168. package/dist/react/UMapView.d.ts +0 -9
  169. package/dist/react/UMapView.js +0 -10
  170. package/dist/react/UQuestionIntent.d.ts +0 -11
  171. package/dist/react/UQuestionIntent.js +0 -12
  172. package/dist/react/UThinkBlock.d.ts +0 -9
  173. package/dist/react/UThinkBlock.js +0 -10
  174. package/dist/react/UToolBlock.d.ts +0 -9
  175. package/dist/react/UToolBlock.js +0 -10
  176. package/dist/react/UVideoView.d.ts +0 -9
  177. package/dist/react/UVideoView.js +0 -10
  178. package/dist/react/UView.d.ts +0 -9
  179. package/dist/react/UView.js +0 -10
  180. package/dist/react/UVoteButton.d.ts +0 -9
  181. package/dist/react/UVoteButton.js +0 -10
  182. package/dist/types/Intents.d.ts +0 -26
  183. package/dist/types/Intents.js +0 -30
  184. package/dist/types/JsonNode.d.ts +0 -20
  185. package/dist/types/Views.d.ts +0 -34
  186. package/dist/types/Views.js +0 -148
  187. package/dist/utilities/IntentPromptBuilder.d.ts +0 -40
  188. package/dist/utilities/IntentPromptBuilder.js +0 -95
  189. package/dist/utilities/ViewPromptBuilder.d.ts +0 -28
  190. package/dist/utilities/ViewPromptBuilder.js +0 -78
  191. package/dist/utilities/dom-agent/DOMAgent.d.ts +0 -74
  192. package/dist/utilities/dom-agent/DOMController.d.ts +0 -78
  193. package/dist/utilities/dom-agent/DOMPromptBuilder.d.ts +0 -54
  194. package/dist/utilities/dom-agent/DOMScanner.d.ts +0 -83
  195. package/dist/utilities/dom-agent/index.d.ts +0 -9
  196. package/dist/utilities/dom-agent/types.d.ts +0 -209
  197. package/skills/iyulab-chat-components/references/components/attach-button.md +0 -69
  198. package/skills/iyulab-chat-components/references/components/copy-button.md +0 -46
  199. package/skills/iyulab-chat-components/references/components/json-block.md +0 -41
  200. package/skills/iyulab-chat-components/references/components/question-intent.md +0 -75
  201. package/skills/iyulab-chat-components/references/components/think-block.md +0 -48
  202. package/skills/iyulab-chat-components/references/components/tool-block.md +0 -57
  203. package/skills/iyulab-chat-components/references/components/view.md +0 -51
  204. package/skills/iyulab-chat-components/references/components/vote-button.md +0 -60
  205. package/skills/iyulab-chat-components/references/utilities/intent-prompt-builder.md +0 -123
  206. package/skills/iyulab-chat-components/references/utilities/view-prompt-builder.md +0 -112
  207. /package/dist/components/{buttons/UCopyButton.styles.d.ts → blocks/UElementBlock.styles.d.ts} +0 -0
  208. /package/dist/{components/blocks/UJsonBlock.styles.d.ts → components-extra/UChartBlock.styles.d.ts} +0 -0
  209. /package/dist/{components/blocks/UThinkBlock.styles.d.ts → components-extra/UImagesBlock.styles.d.ts} +0 -0
  210. /package/dist/{components/blocks/UToolBlock.styles.d.ts → components-extra/UMapBlock.styles.d.ts} +0 -0
  211. /package/dist/{components/buttons/UAttachButton.styles.d.ts → components-extra/UVideoBlock.styles.d.ts} +0 -0
@@ -1,12 +1,11 @@
1
- import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js";
3
- import { styles } from "./UView.styles.js";
1
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.js";
2
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.js";
3
+ import { UDataElement } from "../UDataElement.js";
4
+ import { styles } from "./UElementBlock.styles.js";
4
5
  import { html, nothing } from "lit";
5
6
  import { customElement, property, state } from "lit/decorators.js";
6
- import { UDataElement } from "@iyulab/components/dist/components/UDataElement.js";
7
7
  import "@iyulab/components/dist/components/skeleton/USkeleton.js";
8
- //#region src/components/views/UView.ts
9
- var _ref;
8
+ //#region src/components/blocks/UElementBlock.ts
10
9
  var DEFAULT_BLACKLIST = [
11
10
  "innerHTML",
12
11
  "outerHTML",
@@ -15,7 +14,7 @@ var DEFAULT_BLACKLIST = [
15
14
  "outerText",
16
15
  "srcdoc"
17
16
  ];
18
- var UView = class UView extends UDataElement {
17
+ var UElementBlock = class UElementBlock extends UDataElement {
19
18
  constructor(..._args) {
20
19
  super(..._args);
21
20
  this.loading = false;
@@ -50,28 +49,31 @@ var UView = class UView extends UDataElement {
50
49
  if (this.element != null) return this.element;
51
50
  return nothing;
52
51
  }
53
- /**
54
- * `loading`이 `true`인 경우, 에러 UI로 대체하지 않습니다.
52
+ /**
53
+ * `UDataElement.load()`의 JSON 파싱 실패 시 호출됩니다. 스트리밍 중(`loading`)에는
54
+ * JSON이 아직 완성되지 않아 일시적으로 파싱에 실패하는 것이 정상이므로 콘솔 기록도 건너뜁니다.
55
55
  */
56
56
  async error(error) {
57
57
  if (this.loading) return;
58
- await super.error(error);
58
+ this.reportError(error);
59
59
  }
60
60
  /**
61
61
  * `tag` 프로퍼티에 등록된 커스텀 엘리먼트를 렌더링하는 컴포넌트입니다.
62
62
  * `tag`가 변경될 때마다 등록된 커스텀 엘리먼트를 새로 생성하여 렌더링합니다.
63
63
  * `tag`가 유효하지 않거나 등록된 커스텀 엘리먼트가 아닌 경우, 에러 처리합니다.
64
+ * JSON 자체는 이미 파싱에 성공한 상태이므로(스트리밍 중 파싱 실패와는 다른 케이스),
65
+ * `loading` 여부와 무관하게 항상 기록합니다.
64
66
  */
65
67
  updateElement(tag) {
66
68
  tag = tag?.trim();
67
69
  if (!tag) {
68
70
  this.element = null;
69
- super.error(/* @__PURE__ */ new Error("Tag is required"));
71
+ this.reportError(/* @__PURE__ */ new Error("Tag is required"));
70
72
  return;
71
73
  }
72
74
  if (!customElements.get(tag)) {
73
75
  this.element = null;
74
- super.error(/* @__PURE__ */ new Error(`Unknown tag: ${tag}`));
76
+ this.reportError(/* @__PURE__ */ new Error(`Unknown tag: ${tag}`));
75
77
  return;
76
78
  }
77
79
  this.element = document.createElement(tag);
@@ -85,9 +87,9 @@ var UView = class UView extends UDataElement {
85
87
  if (this.validateProperties(props)) try {
86
88
  Object.assign(element, props);
87
89
  } catch (error) {
88
- super.error(error);
90
+ this.reportError(error);
89
91
  }
90
- else super.error(/* @__PURE__ */ new Error(`Not allowed properties: ${JSON.stringify(props)}`));
92
+ else this.reportError(/* @__PURE__ */ new Error(`Not allowed properties: ${JSON.stringify(props)}`));
91
93
  }
92
94
  /**
93
95
  * `properties` 객체에 위험한 프로퍼티가 포함되어 있는지 검증합니다.
@@ -99,15 +101,23 @@ var UView = class UView extends UDataElement {
99
101
  for (const key of Object.keys(obj)) if (this.blacklist.includes(key)) return false;
100
102
  return true;
101
103
  }
104
+ /**
105
+ * 에러 카드 없이 콘솔에만 기록합니다. 채팅 UI에 갑작스러운 에러 카드가 뜨는 것을 피하기 위함입니다 —
106
+ * addon 모듈을 import하지 않아 아직 등록되지 않은 태그일 수도 있으므로, 실제 에러라기보다
107
+ * "아직 준비 안 됨"에 가깝습니다.
108
+ */
109
+ reportError(error) {
110
+ console.error(`[u-element-block]`, error);
111
+ }
102
112
  };
103
113
  __decorate([property({
104
114
  type: Boolean,
105
115
  reflect: true
106
- }), __decorateMetadata("design:type", Object)], UView.prototype, "loading", void 0);
107
- __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UView.prototype, "tag", void 0);
108
- __decorate([property({ type: Object }), __decorateMetadata("design:type", typeof (_ref = typeof Record !== "undefined" && Record) === "function" ? _ref : Object)], UView.prototype, "properties", void 0);
109
- __decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UView.prototype, "blacklist", void 0);
110
- __decorate([state(), __decorateMetadata("design:type", Object)], UView.prototype, "element", void 0);
111
- UView = __decorate([customElement("u-view")], UView);
116
+ }), __decorateMetadata("design:type", Object)], UElementBlock.prototype, "loading", void 0);
117
+ __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UElementBlock.prototype, "tag", void 0);
118
+ __decorate([property({ type: Object }), __decorateMetadata("design:type", typeof Record === "undefined" ? Object : Record)], UElementBlock.prototype, "properties", void 0);
119
+ __decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UElementBlock.prototype, "blacklist", void 0);
120
+ __decorate([state(), __decorateMetadata("design:type", Object)], UElementBlock.prototype, "element", void 0);
121
+ UElementBlock = __decorate([customElement("u-element-block")], UElementBlock);
112
122
  //#endregion
113
- export { UView };
123
+ export { UElementBlock };
@@ -1,5 +1,5 @@
1
1
  import { css } from "lit";
2
- //#region src/components/views/UView.styles.ts
2
+ //#region src/components/blocks/UElementBlock.styles.ts
3
3
  var styles = css`
4
4
  :host {
5
5
  display: contents;
@@ -1,25 +1,35 @@
1
1
  import { UElement } from '@iyulab/components/dist/components/UElement.js';
2
2
  /**
3
3
  * 단일 파일을 표시하는 블록 컴포넌트입니다.
4
+ * 이미지/비디오는 실제 미리보기를, 그 외 타입은 아이콘을 썸네일로 보여주며
5
+ * 미리보기가 가능한 경우 클릭 시 오버레이로 원본을 확인할 수 있습니다.
4
6
  */
5
7
  export declare class UFileBlock extends UElement {
6
8
  static styles: import('lit').CSSResultGroup[];
7
9
  /** 삭제 버튼 표시 */
8
10
  removable: boolean;
9
- /** 파일 상태 */
10
- status?: 'idle' | 'uploading' | 'error';
11
11
  /** 파일 이름 */
12
12
  name?: string;
13
13
  /** MIME 타입 */
14
14
  type?: string;
15
15
  /** 파일 크기 (bytes) */
16
16
  size?: number;
17
- /** 다운로드 URL */
17
+ /** 미리보기용 파일 URL */
18
18
  url?: string;
19
+ /** 미리보기 오버레이가 열려있는지 여부 */
20
+ private previewOpen;
21
+ connectedCallback(): void;
22
+ disconnectedCallback(): void;
23
+ private get isImage();
24
+ private get isVideo();
25
+ /** 클릭 시 오버레이로 미리볼 수 있는 타입인지 여부 */
26
+ private get previewable();
19
27
  render(): import('lit-html').TemplateResult<1>;
20
- private handleDownloadClick;
28
+ private handleCardClick;
29
+ private closePreview;
30
+ private handleKeyDown;
21
31
  private handleRemoveClick;
22
- /** MIME 타입 → Bootstrap Icon 이름 */
32
+ /** MIME 타입 → Tabler Icon 이름 */
23
33
  private resolveIcon;
24
34
  /** 파일명 또는 MIME 타입에서 확장자를 추출합니다. */
25
35
  private resolveExt;
@@ -1,28 +1,28 @@
1
- import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js";
1
+ import "../../utilities/icons.js";
2
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.js";
3
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.js";
3
4
  import { styles } from "./UFileBlock.styles.js";
4
- import { html } from "lit";
5
- import { customElement, property } from "lit/decorators.js";
5
+ import { html, nothing } from "lit";
6
+ import { customElement, property, state } from "lit/decorators.js";
6
7
  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
8
  import { UElement } from "@iyulab/components/dist/components/UElement.js";
9
+ import "@iyulab/components/dist/components/button/UButton.js";
10
10
  //#region src/components/blocks/UFileBlock.ts
11
11
  var UFileBlock = class UFileBlock extends UElement {
12
12
  constructor(..._args) {
13
13
  super(..._args);
14
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();
15
+ this.previewOpen = false;
16
+ this.handleCardClick = () => {
17
+ if (!this.previewable || this.previewOpen) return;
18
+ this.previewOpen = true;
19
+ };
20
+ this.closePreview = (e) => {
21
+ e?.stopPropagation();
22
+ this.previewOpen = false;
23
+ };
24
+ this.handleKeyDown = (e) => {
25
+ if (this.previewOpen && e.key === "Escape") this.closePreview();
26
26
  };
27
27
  this.handleRemoveClick = (e) => {
28
28
  e.stopPropagation();
@@ -32,57 +32,73 @@ var UFileBlock = class UFileBlock extends UElement {
32
32
  static {
33
33
  this.styles = [super.styles, styles];
34
34
  }
35
+ connectedCallback() {
36
+ super.connectedCallback();
37
+ document.addEventListener("keydown", this.handleKeyDown);
38
+ }
39
+ disconnectedCallback() {
40
+ document.removeEventListener("keydown", this.handleKeyDown);
41
+ super.disconnectedCallback();
42
+ }
43
+ get isImage() {
44
+ return !!this.url && !!this.type?.startsWith("image/");
45
+ }
46
+ get isVideo() {
47
+ return !!this.url && !!this.type?.startsWith("video/");
48
+ }
49
+ /** 클릭 시 오버레이로 미리볼 수 있는 타입인지 여부 */
50
+ get previewable() {
51
+ return this.isImage || this.isVideo;
52
+ }
35
53
  render() {
36
54
  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>
55
+ <div class="card" @click=${this.handleCardClick}>
56
+ <div class="thumbnail">
57
+ ${this.isImage ? html`<img src=${this.url} alt=${this.name || ""} loading="lazy" />` : this.isVideo ? html`<video src="${this.url}#t=0.1" preload="metadata" muted playsinline></video>` : html`<u-icon lib="internal-chat" name=${this.resolveIcon(this.type)}></u-icon>`}
58
+ </div>
59
+
60
+ <div class="info">
61
+ <div class="name">${this.name}</div>
62
+ <div class="meta">
63
+ <span class="type">
64
+ ${this.resolveExt(this.name, this.type)}
65
+ </span>
66
+ <span class="size">
67
+ ${this.formatSize(this.size || 0)}
68
+ </span>
69
+ </div>
70
+ </div>
71
+
72
+ <u-button class="remove-btn"
73
+ ?hidden=${!this.removable}
74
+ title="Remove"
75
+ @click=${this.handleRemoveClick}>
76
+ <u-icon lib="internal" name="x"></u-icon>
56
77
  </u-button>
57
78
  </div>
58
79
 
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>
80
+ ${this.previewOpen && this.previewable ? html`
81
+ <div class="preview-overlay" @click=${this.closePreview}>
82
+ <header class="preview-header">
83
+ <span class="preview-name">${this.name}</span>
84
+ <button class="preview-close" @click=${this.closePreview}>
85
+ <u-icon lib="internal" name="x"></u-icon>
86
+ </button>
87
+ </header>
88
+ <div class="preview-body" @click=${(e) => e.stopPropagation()}>
89
+ ${this.isImage ? html`<img src=${this.url} alt=${this.name || ""} />` : html`<video src=${this.url} controls autoplay></video>`}
90
+ </div>
68
91
  </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>
92
+ ` : nothing}
77
93
  `;
78
94
  }
79
- /** MIME 타입 → Bootstrap Icon 이름 */
95
+ /** MIME 타입 → Tabler Icon 이름 */
80
96
  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";
97
+ if (!mimeType) return "file";
98
+ if (mimeType.startsWith("image/")) return "photo";
99
+ if (mimeType.startsWith("video/")) return "video";
100
+ if (mimeType.startsWith("audio/")) return "file-music";
101
+ if (mimeType === "application/pdf") return "file-type-pdf";
86
102
  if ([
87
103
  "application/json",
88
104
  "application/javascript",
@@ -93,12 +109,12 @@ var UFileBlock = class UFileBlock extends UElement {
93
109
  "text/javascript",
94
110
  "text/x-python",
95
111
  "text/x-java-source"
96
- ].includes(mimeType) || mimeType.startsWith("text/x-")) return "file-earmark-code";
112
+ ].includes(mimeType) || mimeType.startsWith("text/x-")) return "file-code";
97
113
  if ([
98
114
  "application/vnd.ms-excel",
99
115
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
100
116
  "text/csv"
101
- ].includes(mimeType)) return "file-earmark-spreadsheet";
117
+ ].includes(mimeType)) return "file-spreadsheet";
102
118
  if ([
103
119
  "application/zip",
104
120
  "application/x-zip-compressed",
@@ -106,9 +122,9 @@ var UFileBlock = class UFileBlock extends UElement {
106
122
  "application/x-rar-compressed",
107
123
  "application/gzip",
108
124
  "application/x-7z-compressed"
109
- ].includes(mimeType)) return "file-earmark-zip";
110
- if (mimeType.startsWith("text/")) return "file-earmark-text";
111
- return "file-earmark";
125
+ ].includes(mimeType)) return "file-zip";
126
+ if (mimeType.startsWith("text/")) return "file-text";
127
+ return "file";
112
128
  }
113
129
  /** 파일명 또는 MIME 타입에서 확장자를 추출합니다. */
114
130
  resolveExt(name, mimeType) {
@@ -141,14 +157,11 @@ __decorate([property({
141
157
  type: Boolean,
142
158
  reflect: true
143
159
  }), __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
160
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "name", void 0);
149
161
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "type", void 0);
150
162
  __decorate([property({ type: Number }), __decorateMetadata("design:type", Number)], UFileBlock.prototype, "size", void 0);
151
163
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFileBlock.prototype, "url", void 0);
164
+ __decorate([state(), __decorateMetadata("design:type", Object)], UFileBlock.prototype, "previewOpen", void 0);
152
165
  UFileBlock = __decorate([customElement("u-file-block")], UFileBlock);
153
166
  //#endregion
154
167
  export { UFileBlock };
@@ -2,12 +2,19 @@ import { css } from "lit";
2
2
  //#region src/components/blocks/UFileBlock.styles.ts
3
3
  var styles = css`
4
4
  :host {
5
+ position: relative;
6
+ display: block;
7
+ min-width: 0;
8
+ max-width: 200px;
9
+ font-size: 14px;
10
+ }
11
+
12
+ .card {
5
13
  position: relative;
6
14
  display: flex;
7
15
  flex-direction: row;
8
16
  align-items: center;
9
17
  min-width: 0;
10
- max-width: 200px;
11
18
  gap: 10px;
12
19
  padding: 8px 10px;
13
20
  border: 1px solid var(--u-border-color);
@@ -16,17 +23,12 @@ var styles = css`
16
23
  overflow: visible;
17
24
  cursor: pointer;
18
25
  transition: background-color 0.12s ease, border-color 0.12s ease;
19
- font-size: 14px;
20
26
  }
21
- :host(:hover) {
27
+ .card:hover {
22
28
  background-color: var(--u-neutral-100);
23
29
  border-color: var(--u-border-color-strong);
24
30
  }
25
31
 
26
- u-icon[name="file-earmark-x"] {
27
- color: var(--u-red-600);
28
- }
29
-
30
32
  .thumbnail {
31
33
  position: relative;
32
34
  flex-shrink: 0;
@@ -42,6 +44,14 @@ var styles = css`
42
44
  transition: background 0.15s ease;
43
45
  overflow: hidden;
44
46
  }
47
+ .thumbnail img,
48
+ .thumbnail video {
49
+ display: block;
50
+ width: 100%;
51
+ height: 100%;
52
+ object-fit: cover;
53
+ pointer-events: none;
54
+ }
45
55
 
46
56
  .info {
47
57
  flex: 1;
@@ -82,27 +92,6 @@ var styles = css`
82
92
  font-variant-numeric: tabular-nums;
83
93
  }
84
94
 
85
- .download-btn {
86
- position: absolute;
87
- inset: 0;
88
- width: 100%;
89
- height: 100%;
90
- color: var(--u-neutral-0);
91
- font-size: 14px;
92
- border-radius: 6px;
93
- background-color: color-mix(in srgb, var(--u-neutral-900) 70%, transparent);
94
- opacity: 0;
95
- pointer-events: none;
96
- transition: opacity 0.15s ease;
97
- }
98
- .thumbnail:hover .download-btn {
99
- opacity: 1;
100
- pointer-events: auto;
101
- }
102
- .download-btn:hover {
103
- background-color: color-mix(in srgb, var(--u-neutral-900) 85%, transparent);
104
- }
105
-
106
95
  .remove-btn {
107
96
  position: absolute;
108
97
  z-index: 10;
@@ -116,13 +105,81 @@ var styles = css`
116
105
  pointer-events: none;
117
106
  transition: opacity 0.12s ease, background-color 0.12s ease;
118
107
  }
119
- :host(:hover) .remove-btn {
108
+ .card:hover .remove-btn {
120
109
  opacity: 1;
121
110
  pointer-events: auto;
122
111
  }
123
112
  .remove-btn:hover {
124
113
  background-color: var(--u-red-600);
125
114
  }
115
+
116
+ /* ─── 미리보기 오버레이 ─── */
117
+
118
+ .preview-overlay {
119
+ position: fixed;
120
+ inset: 0;
121
+ z-index: 9999;
122
+ display: flex;
123
+ flex-direction: column;
124
+ background: rgba(0, 0, 0, 0.92);
125
+ cursor: default;
126
+ animation: preview-fadeIn 0.2s ease;
127
+ }
128
+
129
+ .preview-header {
130
+ height: 56px;
131
+ flex-shrink: 0;
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: space-between;
135
+ padding: 0 16px;
136
+ }
137
+
138
+ .preview-name {
139
+ color: rgba(255, 255, 255, 0.85);
140
+ font-size: 0.875em;
141
+ overflow: hidden;
142
+ text-overflow: ellipsis;
143
+ white-space: nowrap;
144
+ }
145
+
146
+ .preview-close {
147
+ flex-shrink: 0;
148
+ width: 36px;
149
+ height: 36px;
150
+ border: none;
151
+ border-radius: 12px;
152
+ background: transparent;
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ cursor: pointer;
157
+ transition: background 0.2s;
158
+ }
159
+ .preview-close:hover { background: rgba(255, 255, 255, 0.18); }
160
+ .preview-close:active { background: rgba(255, 255, 255, 0.28); }
161
+ .preview-close u-icon { color: white; font-size: 1.25em; }
162
+
163
+ .preview-body {
164
+ flex: 1;
165
+ min-height: 0;
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ padding: 0 24px 24px;
170
+ }
171
+ .preview-body img,
172
+ .preview-body video {
173
+ max-width: 100%;
174
+ max-height: 100%;
175
+ object-fit: contain;
176
+ border-radius: 6px;
177
+ }
178
+
179
+ @keyframes preview-fadeIn {
180
+ from { opacity: 0; }
181
+ to { opacity: 1; }
182
+ }
126
183
  `;
127
184
  //#endregion
128
185
  export { styles };
@@ -18,7 +18,9 @@ export declare class UMarkedBlock extends UElement {
18
18
  private parser;
19
19
  private placeholder;
20
20
  private queued;
21
- private timer?;
21
+ private queuedTimer?;
22
+ private streaming;
23
+ private streamingTimer?;
22
24
  disconnectedCallback(): void;
23
25
  protected shouldUpdate(_changedProperties: PropertyValues): boolean;
24
26
  protected willUpdate(changedProperties: PropertyValues): void;
@@ -1,21 +1,21 @@
1
- import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js";
1
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.js";
2
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.js";
3
3
  import "./UCodeBlock.js";
4
+ import { escapeHtmlText, stripZeroWidth } from "../../utilities/sanitizers.js";
5
+ import { HtmlBuilder } from "../../utilities/HtmlBuilder.js";
6
+ import { UElementBlock } from "./UElementBlock.js";
4
7
  import "../references/URefTag.js";
5
8
  import { URefCard } from "../references/URefCard.js";
6
9
  import "../references/URefCardGroup.js";
7
10
  import { UTableBlock } from "./UTableBlock.js";
8
- import { UView } from "../views/UView.js";
9
11
  import { HtmlPlaceholder } from "../../utilities/HtmlPlaceholder.js";
10
12
  import { styles } from "./UMarkedBlock.styles.js";
11
13
  import { nothing } from "lit";
12
- import { customElement, property } from "lit/decorators.js";
14
+ import { customElement, property, state } from "lit/decorators.js";
13
15
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
14
16
  import { UElement } from "@iyulab/components/dist/components/UElement.js";
15
17
  import { Marked, Parser } from "marked";
16
18
  import markedKatex from "marked-katex-extension";
17
- import { escapeHtmlText, stripZeroWidth } from "@iyulab/components/dist/utilities/sanitizers.js";
18
- import { buildElementHTML } from "@iyulab/components/dist/utilities/elements.js";
19
19
  //#region src/components/blocks/UMarkedBlock.ts
20
20
  var UMarkedBlock = class UMarkedBlock extends UElement {
21
21
  constructor(..._args) {
@@ -32,12 +32,14 @@ var UMarkedBlock = class UMarkedBlock extends UElement {
32
32
  }).use(markedKatex({ output: "mathml" }));
33
33
  this.placeholder = new HtmlPlaceholder();
34
34
  this.queued = false;
35
+ this.streaming = false;
35
36
  }
36
37
  static {
37
38
  this.styles = [super.styles, styles];
38
39
  }
39
40
  disconnectedCallback() {
40
- clearTimeout(this.timer);
41
+ clearTimeout(this.queuedTimer);
42
+ clearTimeout(this.streamingTimer);
41
43
  super.disconnectedCallback();
42
44
  }
43
45
  shouldUpdate(_changedProperties) {
@@ -47,9 +49,14 @@ var UMarkedBlock = class UMarkedBlock extends UElement {
47
49
  willUpdate(changedProperties) {
48
50
  super.willUpdate(changedProperties);
49
51
  if (changedProperties.has("value")) {
52
+ this.streaming = true;
53
+ clearTimeout(this.streamingTimer);
54
+ this.streamingTimer = window.setTimeout(() => {
55
+ this.streaming = false;
56
+ }, 1500);
50
57
  if (this.queued) return;
51
58
  this.queued = true;
52
- this.timer = window.setTimeout(() => {
59
+ this.queuedTimer = window.setTimeout(() => {
53
60
  this.queued = false;
54
61
  this.requestUpdate();
55
62
  }, 80);
@@ -69,15 +76,9 @@ var UMarkedBlock = class UMarkedBlock extends UElement {
69
76
  */
70
77
  renderCode(token) {
71
78
  const lang = token.lang ?? "plaintext";
72
- const trimmed = token.raw.trimEnd();
73
- const isClosed = trimmed.endsWith("```") || trimmed.endsWith("~~~");
74
- if (lang === "view-json") return UView.buildHTML(token.text, { loading: !isClosed });
75
- if (lang === "intent-json") return "";
79
+ if (lang === "block-json") return UElementBlock.buildHTML(token.text, { loading: this.streaming });
76
80
  const safeText = this.removeRefs(token.text);
77
- return buildElementHTML("u-code-block", {
78
- lang,
79
- loading: !isClosed
80
- }, safeText);
81
+ return HtmlBuilder.build("u-code-block", { lang }, safeText);
81
82
  }
82
83
  /**
83
84
  * 테이블은 JSON 데이터로 변환하여 별도의 컴포넌트로 렌더링합니다.
@@ -108,8 +109,11 @@ var UMarkedBlock = class UMarkedBlock extends UElement {
108
109
  const label = escapeHtmlText(ref.label ?? `[${refs.indexOf(ref) + 1}]`);
109
110
  const link = sources.at(0)?.url;
110
111
  let tooltip = "";
111
- if (sources.length > 0) tooltip = buildElementHTML("u-ref-card-group", { slot: "tooltip" }, sources.map((s) => URefCard.buildHTML(s)).join(""));
112
- const html = buildElementHTML("u-ref-tag", { href: link }, label + tooltip);
112
+ if (sources.length > 0) {
113
+ const cards = sources.map((s) => URefCard.buildHTML(s)).join("");
114
+ tooltip = HtmlBuilder.build("u-ref-card-group", { slot: "tooltip" }, cards);
115
+ }
116
+ const html = HtmlBuilder.build("u-ref-tag", { href: link }, label + tooltip);
113
117
  const key = this.placeholder.store(html);
114
118
  value = value.slice(0, ref.endIndex) + key + value.slice(ref.endIndex);
115
119
  }
@@ -126,6 +130,7 @@ var UMarkedBlock = class UMarkedBlock extends UElement {
126
130
  };
127
131
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UMarkedBlock.prototype, "value", void 0);
128
132
  __decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UMarkedBlock.prototype, "refs", void 0);
133
+ __decorate([state(), __decorateMetadata("design:type", Boolean)], UMarkedBlock.prototype, "streaming", void 0);
129
134
  UMarkedBlock = __decorate([customElement("u-marked-block")], UMarkedBlock);
130
135
  //#endregion
131
136
  export { UMarkedBlock };
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js";
1
+ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorateMetadata.js";
2
+ import __decorate from "../../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/decorate.js";
3
3
  import "../references/URefCard.js";
4
4
  import { styles } from "./URefBlock.styles.js";
5
5
  import { html } from "lit";
@@ -1,4 +1,4 @@
1
- import { UDataElement } from '@iyulab/components/dist/components/UDataElement.js';
1
+ import { UDataElement } from '../UDataElement.js';
2
2
  /** 테이블 셀 데이터 타입 */
3
3
  export interface TableCell {
4
4
  /** 셀에 표시할 텍스트 내용 */
@@ -19,7 +19,7 @@ export interface SortState {
19
19
  * light DOM 내 `<script type="application/json">` 에서 데이터를 자동으로 읽어냅니다.
20
20
  */
21
21
  export declare class UTableBlock extends UDataElement {
22
- static styles: (import('lit').CSSResult | import('lit').CSSResultGroup[])[];
22
+ static styles: import('lit').CSSResultGroup[];
23
23
  /** 테이블 헤더 목록. 각 헤더는 { text, align } 형식입니다. */
24
24
  headers: TableCell[];
25
25
  /** 테이블 행 목록. 각 행은 셀 배열입니다. */