@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
@@ -0,0 +1,39 @@
1
+ import { nothing, PropertyValues } from 'lit';
2
+ import { ChartType, ChartData, ChartOptions } from 'chart.js/auto';
3
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
4
+ /**
5
+ * Chart.js를 사용하여 다양한 차트를 렌더링하는 뷰 컴포넌트입니다.
6
+ */
7
+ export declare class UChartView extends UElement {
8
+ static styles: import('lit').CSSResultGroup[];
9
+ /** 차트 유형 (bar, line, pie 등) */
10
+ type?: ChartType;
11
+ /** 차트 데이터 */
12
+ data?: ChartData;
13
+ /** 차트 옵션 */
14
+ options?: ChartOptions;
15
+ private canvas?;
16
+ private viewport?;
17
+ /** 차트 생성 에러 메시지 */
18
+ private error;
19
+ private chartjs;
20
+ private observer?;
21
+ connectedCallback(): void;
22
+ disconnectedCallback(): void;
23
+ protected updated(changedProperties: PropertyValues): void;
24
+ render(): import('lit-html').TemplateResult<1> | typeof nothing;
25
+ /** Chart.js로 차트 생성 */
26
+ private createChart;
27
+ /** 기존 차트 인스턴스 제거 */
28
+ private destroyChart;
29
+ /** 현재 테마의 CSS 변수를 읽어 Chart.defaults에 전역 적용 */
30
+ private applyTheme;
31
+ private handleDownloadPNG;
32
+ private handleDownloadJSON;
33
+ private handleFullscreen;
34
+ }
35
+ declare global {
36
+ interface HTMLElementTagNameMap {
37
+ "u-chart-view": UChartView;
38
+ }
39
+ }
@@ -0,0 +1,167 @@
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 "./UChartView.styles.js";
4
+ import { html, nothing } from "lit";
5
+ import { customElement, property, query, state } from "lit/decorators.js";
6
+ import "@iyulab/components/dist/components/icon/UIcon.js";
7
+ import "@iyulab/components/dist/components/button/UButton.js";
8
+ import { UElement } from "@iyulab/components/dist/components/UElement.js";
9
+ //#region src/components/views/UChartView.ts
10
+ var _ref, _ref2;
11
+ /** chart.js lazy load */
12
+ var ChartCtor;
13
+ async function loadChartJS() {
14
+ if (!ChartCtor) ChartCtor = (await import("chart.js/auto")).Chart;
15
+ return ChartCtor;
16
+ }
17
+ var UChartView = class UChartView extends UElement {
18
+ constructor(..._args) {
19
+ super(..._args);
20
+ this.error = null;
21
+ this.chartjs = null;
22
+ }
23
+ static {
24
+ this.styles = [super.styles, styles];
25
+ }
26
+ connectedCallback() {
27
+ super.connectedCallback();
28
+ this.observer = new MutationObserver(() => {
29
+ this.createChart();
30
+ });
31
+ this.observer.observe(document.documentElement, {
32
+ attributes: true,
33
+ attributeFilter: ["theme"]
34
+ });
35
+ }
36
+ disconnectedCallback() {
37
+ super.disconnectedCallback();
38
+ this.observer?.disconnect();
39
+ this.destroyChart();
40
+ }
41
+ updated(changedProperties) {
42
+ super.updated(changedProperties);
43
+ if ([
44
+ "data",
45
+ "type",
46
+ "options"
47
+ ].some((k) => changedProperties.has(k))) this.createChart();
48
+ }
49
+ render() {
50
+ if (!this.data) return nothing;
51
+ return html`
52
+ <div class="toolbar">
53
+ <div class="toolbar-left"></div>
54
+ <div class="toolbar-right">
55
+ <u-button title="PNG Download" @click=${this.handleDownloadPNG}>
56
+ PNG
57
+ <u-icon slot="suffix" lib="bootstrap" name="download"></u-icon>
58
+ </u-button>
59
+ <u-button title="JSON Download" @click=${this.handleDownloadJSON}>
60
+ JSON
61
+ <u-icon slot="suffix" lib="bootstrap" name="download"></u-icon>
62
+ </u-button>
63
+ <u-button title="Full Screen" @click=${this.handleFullscreen}>
64
+ <u-icon lib="bootstrap" name="box-arrow-up-right"></u-icon>
65
+ </u-button>
66
+ </div>
67
+ </div>
68
+ <div class="viewport">
69
+ <canvas></canvas>
70
+ <div class="error-overlay" ?hidden=${!this.error}>
71
+ <u-icon lib="bootstrap" name="exclamation-triangle-fill"></u-icon>
72
+ <span>${this.error}</span>
73
+ </div>
74
+ </div>
75
+ `;
76
+ }
77
+ /** Chart.js로 차트 생성 */
78
+ async createChart() {
79
+ if (!this.canvas) return;
80
+ if (!this.type || !this.data) return;
81
+ this.destroyChart();
82
+ this.error = null;
83
+ let Chart;
84
+ try {
85
+ Chart = await loadChartJS();
86
+ } catch {
87
+ this.error = "chart.js를 로드할 수 없습니다. chart.js 패키지가 설치되어 있는지 확인하세요.";
88
+ return;
89
+ }
90
+ const ctx = this.canvas.getContext("2d");
91
+ if (!ctx) {
92
+ this.error = "Canvas 2D context를 가져올 수 없습니다.";
93
+ return;
94
+ }
95
+ try {
96
+ this.applyTheme(Chart);
97
+ this.chartjs = new Chart(ctx, {
98
+ type: this.type,
99
+ data: this.data,
100
+ options: {
101
+ responsive: true,
102
+ maintainAspectRatio: true,
103
+ ...this.options
104
+ }
105
+ });
106
+ } catch (e) {
107
+ this.error = e instanceof Error ? e.message : String(e);
108
+ }
109
+ }
110
+ /** 기존 차트 인스턴스 제거 */
111
+ destroyChart() {
112
+ if (this.chartjs) {
113
+ this.chartjs.destroy();
114
+ this.chartjs = null;
115
+ }
116
+ }
117
+ /** 현재 테마의 CSS 변수를 읽어 Chart.defaults에 전역 적용 */
118
+ applyTheme(Chart) {
119
+ const css = (v) => getComputedStyle(this).getPropertyValue(v).trim();
120
+ const textColor = css("--u-txt-color");
121
+ const weakColor = css("--u-txt-color-weak");
122
+ const borderColor = css("--u-border-color");
123
+ const bgColor = css("--u-bg-color");
124
+ Chart.defaults.color = textColor;
125
+ Chart.defaults.borderColor = borderColor;
126
+ Chart.defaults.plugins.tooltip.backgroundColor = bgColor;
127
+ Chart.defaults.plugins.tooltip.titleColor = textColor;
128
+ Chart.defaults.plugins.tooltip.bodyColor = weakColor;
129
+ Chart.defaults.plugins.tooltip.borderColor = borderColor;
130
+ Chart.defaults.plugins.tooltip.borderWidth = 1;
131
+ Chart.defaults.scale.ticks.color = weakColor;
132
+ Chart.defaults.scale.grid.color = borderColor;
133
+ }
134
+ handleDownloadPNG() {
135
+ if (!this.chartjs) return;
136
+ const url = this.chartjs.toBase64Image("image/png", 1);
137
+ const a = document.createElement("a");
138
+ a.href = url;
139
+ a.download = `chart-image-${Date.now()}.png`;
140
+ a.click();
141
+ }
142
+ handleDownloadJSON() {
143
+ if (!this.data) return;
144
+ const json = JSON.stringify(this.data, null, 2);
145
+ const blob = new Blob([json], { type: "application/json;charset=utf-8;" });
146
+ const url = URL.createObjectURL(blob);
147
+ const a = document.createElement("a");
148
+ a.href = url;
149
+ a.download = `chart-data-${Date.now()}.json`;
150
+ a.click();
151
+ URL.revokeObjectURL(url);
152
+ }
153
+ handleFullscreen() {
154
+ const target = this.viewport ?? this;
155
+ if (document.fullscreenElement) document.exitFullscreen();
156
+ else target.requestFullscreen?.();
157
+ }
158
+ };
159
+ __decorate([property({ type: String }), __decorateMetadata("design:type", Object)], UChartView.prototype, "type", void 0);
160
+ __decorate([property({ type: Object }), __decorateMetadata("design:type", Object)], UChartView.prototype, "data", void 0);
161
+ __decorate([property({ type: Object }), __decorateMetadata("design:type", Object)], UChartView.prototype, "options", void 0);
162
+ __decorate([query("canvas"), __decorateMetadata("design:type", typeof (_ref = typeof HTMLCanvasElement !== "undefined" && HTMLCanvasElement) === "function" ? _ref : Object)], UChartView.prototype, "canvas", void 0);
163
+ __decorate([query(".viewport"), __decorateMetadata("design:type", typeof (_ref2 = typeof HTMLElement !== "undefined" && HTMLElement) === "function" ? _ref2 : Object)], UChartView.prototype, "viewport", void 0);
164
+ __decorate([state(), __decorateMetadata("design:type", Object)], UChartView.prototype, "error", void 0);
165
+ UChartView = __decorate([customElement("u-chart-view")], UChartView);
166
+ //#endregion
167
+ export { UChartView };
@@ -0,0 +1,86 @@
1
+ import { css } from "lit";
2
+ //#region src/components/views/UChartView.styles.ts
3
+ var styles = css`
4
+ :host {
5
+ margin: 0.75em auto;
6
+ display: block;
7
+ width: 100%;
8
+ background: var(--u-bg-color);
9
+ border: 1px solid var(--u-border-color);
10
+ border-radius: 8px;
11
+ overflow: hidden;
12
+ }
13
+
14
+ .toolbar {
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ padding: 6px 12px;
19
+ background-color: var(--u-neutral-100);
20
+ border-bottom: 1px solid var(--u-border-color);
21
+ gap: 8px;
22
+ }
23
+
24
+ .toolbar-left {
25
+ flex: 1;
26
+ }
27
+
28
+ .toolbar-right {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 6px;
32
+ flex-shrink: 0;
33
+ }
34
+
35
+ .toolbar-right u-button {
36
+ font-size: 12px;
37
+ }
38
+ .toolbar-right u-button[title="Full Screen"] {
39
+ font-size: 15px;
40
+ }
41
+
42
+ .viewport {
43
+ position: relative;
44
+ padding: 1em;
45
+ }
46
+
47
+ .viewport:fullscreen {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ background: var(--u-bg-color);
52
+ padding: 2em;
53
+ }
54
+ .viewport:fullscreen canvas {
55
+ max-width: 90vw;
56
+ max-height: 90vh;
57
+ }
58
+
59
+ canvas {
60
+ width: 100% !important;
61
+ min-height: 60px;
62
+ }
63
+
64
+ .error-overlay {
65
+ position: absolute;
66
+ bottom: 10px;
67
+ right: 10px;
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 6px;
71
+ padding: 6px 10px;
72
+ background: var(--u-red-0);
73
+ border: 1px solid var(--u-red-200);
74
+ border-radius: 6px;
75
+ color: var(--u-red-800);
76
+ font-size: 12px;
77
+ pointer-events: none;
78
+ }
79
+
80
+ .error-overlay u-icon {
81
+ color: var(--u-red-600);
82
+ flex-shrink: 0;
83
+ }
84
+ `;
85
+ //#endregion
86
+ export { styles };
@@ -0,0 +1,33 @@
1
+ import { nothing } from 'lit';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
+ export interface ImageSlide {
4
+ src: string;
5
+ alt?: string;
6
+ caption?: string;
7
+ }
8
+ /**
9
+ * u-carousel 기반 가로 슬라이드 + 슬라이딩 라이트박스 형태의 이미지 뷰어입니다.
10
+ */
11
+ export declare class UImagesView extends UElement {
12
+ static styles: import('lit').CSSResultGroup[];
13
+ /** 이미지 슬라이드 배열 */
14
+ items: ImageSlide[];
15
+ /** 라이트박스에서 현재 열려있는 이미지 인덱스, null이면 라이트박스 닫힘 */
16
+ private index;
17
+ connectedCallback(): void;
18
+ disconnectedCallback(): void;
19
+ render(): import('lit-html').TemplateResult<1> | typeof nothing;
20
+ private renderLightbox;
21
+ open: (i: number) => void;
22
+ close: () => void;
23
+ prev: () => void;
24
+ next: () => void;
25
+ private handlePrevClick;
26
+ private handleNextClick;
27
+ private handleKeyDown;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ "u-images-view": UImagesView;
32
+ }
33
+ }
@@ -0,0 +1,144 @@
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 "./UImagesView.styles.js";
4
+ import { html, nothing } from "lit";
5
+ import { customElement, property, state } from "lit/decorators.js";
6
+ import "@iyulab/components/dist/components/icon/UIcon.js";
7
+ import { UElement } from "@iyulab/components/dist/components/UElement.js";
8
+ import { repeat } from "lit/directives/repeat.js";
9
+ import "@iyulab/components/dist/components/carousel/UCarousel.js";
10
+ //#region src/components/views/UImagesView.ts
11
+ var UImagesView = class UImagesView extends UElement {
12
+ constructor(..._args) {
13
+ super(..._args);
14
+ this.items = [];
15
+ this.index = null;
16
+ this.open = (i) => {
17
+ this.index = i;
18
+ };
19
+ this.close = () => {
20
+ this.index = null;
21
+ };
22
+ this.prev = () => {
23
+ if (this.index !== null && this.index > 0) this.index--;
24
+ };
25
+ this.next = () => {
26
+ if (this.index !== null && this.index < this.items.length - 1) this.index++;
27
+ };
28
+ this.handlePrevClick = (e) => {
29
+ e.stopPropagation();
30
+ this.prev();
31
+ };
32
+ this.handleNextClick = (e) => {
33
+ e.stopPropagation();
34
+ this.next();
35
+ };
36
+ this.handleKeyDown = (e) => {
37
+ if (this.index === null) return;
38
+ if (e.key === "Escape") this.close();
39
+ else if (e.key === "ArrowLeft") this.prev();
40
+ else if (e.key === "ArrowRight") this.next();
41
+ };
42
+ }
43
+ static {
44
+ this.styles = [super.styles, styles];
45
+ }
46
+ connectedCallback() {
47
+ super.connectedCallback();
48
+ document.addEventListener("keydown", this.handleKeyDown);
49
+ }
50
+ disconnectedCallback() {
51
+ document.removeEventListener("keydown", this.handleKeyDown);
52
+ super.disconnectedCallback();
53
+ }
54
+ render() {
55
+ if (!this.items?.length) return nothing;
56
+ const count = this.items.length;
57
+ return html`
58
+ <u-carousel
59
+ .loop=${false}
60
+ .navigation=${false}
61
+ .pagination=${true}
62
+ .draggable=${true}
63
+ .slidesPerView=${Math.min(count, 3)}
64
+ .gap=${8}
65
+ >
66
+ ${repeat(this.items, (item, i) => html`
67
+ <div class="slide"
68
+ @click=${() => this.open(i)}>
69
+ <img
70
+ src=${item.src}
71
+ alt=${item.alt || ""}
72
+ loading="lazy"
73
+ />
74
+ <div class="caption"
75
+ ?hidden=${!item.caption}>
76
+ ${item.caption}
77
+ </div>
78
+ </div>
79
+ `)}
80
+ </u-carousel>
81
+
82
+ ${this.renderLightbox()}
83
+ `;
84
+ }
85
+ renderLightbox() {
86
+ const idx = this.index;
87
+ if (idx === null) return nothing;
88
+ if (idx < 0 || idx >= this.items.length) return nothing;
89
+ const item = this.items[idx];
90
+ if (!item) return nothing;
91
+ const total = this.items.length;
92
+ const translateX = `calc(15vw - ${idx} * (70vw + 16px))`;
93
+ return html`
94
+ <div class="lb-overlay">
95
+
96
+ <!-- 상단: 카운터(중앙) + 닫기 버튼(우측) -->
97
+ <header class="lb-header">
98
+ <div class="lb-counter" ?hidden=${total <= 1}>
99
+ ${idx + 1} / ${total}
100
+ </div>
101
+ <button class="lb-close" @click=${this.close}>
102
+ <u-icon lib="internal" name="x-lg"></u-icon>
103
+ </button>
104
+ </header>
105
+
106
+ <!-- 중앙: 뷰포트 + 이전/다음 버튼(absolute 오버레이) -->
107
+ <div class="lb-body">
108
+ <div class="lb-viewport">
109
+ <div class="lb-track" style="transform:translateX(${translateX})">
110
+ ${repeat(this.items, (img, i) => html`
111
+ <div class="lb-slide" ?active=${i === idx}>
112
+ <img src=${img.src} alt=${img.alt || ""} />
113
+ </div>
114
+ `)}
115
+ </div>
116
+ </div>
117
+
118
+ <button class="lb-nav prev"
119
+ ?hidden=${idx <= 0}
120
+ @click=${this.handlePrevClick}>
121
+ <u-icon lib="internal" name="chevron-left"></u-icon>
122
+ </button>
123
+
124
+ <button class="lb-nav next"
125
+ ?hidden=${idx >= total - 1}
126
+ @click=${this.handleNextClick}>
127
+ <u-icon lib="internal" name="chevron-right"></u-icon>
128
+ </button>
129
+ </div>
130
+
131
+ <!-- 하단: 캡션 -->
132
+ <footer class="lb-footer" ?hidden=${!item.caption}>
133
+ <p class="lb-caption">${item.caption}</p>
134
+ </footer>
135
+
136
+ </div>
137
+ `;
138
+ }
139
+ };
140
+ __decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UImagesView.prototype, "items", void 0);
141
+ __decorate([state(), __decorateMetadata("design:type", Object)], UImagesView.prototype, "index", void 0);
142
+ UImagesView = __decorate([customElement("u-images-view")], UImagesView);
143
+ //#endregion
144
+ export { UImagesView };
@@ -0,0 +1 @@
1
+ export declare const styles: import('lit').CSSResult;
@@ -0,0 +1,219 @@
1
+ import { css } from "lit";
2
+ //#region src/components/views/UImagesView.styles.ts
3
+ var styles = css`
4
+ :host {
5
+ display: block;
6
+ width: 100%;
7
+ margin: 0.75em 0;
8
+ }
9
+
10
+ .slide {
11
+ position: relative;
12
+ border-radius: 10px;
13
+ overflow: hidden;
14
+ cursor: pointer;
15
+ aspect-ratio: 4 / 3;
16
+ }
17
+ .slide img {
18
+ display: block;
19
+ width: 100%;
20
+ height: 100%;
21
+ object-fit: cover;
22
+ pointer-events: none;
23
+ transition: transform 0.3s ease, filter 0.3s ease;
24
+ }
25
+ .slide:hover img {
26
+ transform: scale(1.05);
27
+ filter: brightness(0.92);
28
+ }
29
+
30
+ .caption {
31
+ position: absolute;
32
+ bottom: 0;
33
+ left: 0;
34
+ right: 0;
35
+ padding: 20px 10px 8px;
36
+ color: white;
37
+ font-size: 0.8em;
38
+ line-height: 1.3;
39
+ background: linear-gradient(transparent, rgba(0, 0, 0, 0.55));
40
+ }
41
+
42
+ /* ─── 라이트박스 UI ─── */
43
+
44
+ /* 루트 오버레이: flex column 전체 화면 */
45
+ .lb-overlay {
46
+ position: fixed;
47
+ inset: 0;
48
+ z-index: 9999;
49
+ display: flex;
50
+ flex-direction: column;
51
+ background: rgba(0, 0, 0, 0.92);
52
+ animation: overlay-fadeIn 0.2s ease;
53
+ }
54
+
55
+ /* 상단 헤더: 카운터(중앙) + 닫기(우측) */
56
+ .lb-header {
57
+ height: 56px;
58
+ position: relative;
59
+ flex-shrink: 0;
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ }
64
+
65
+ .lb-counter {
66
+ color: rgba(255, 255, 255, 0.75);
67
+ font-size: 0.875em;
68
+ font-variant-numeric: tabular-nums;
69
+ background: rgba(0, 0, 0, 0.35);
70
+ padding: 3px 12px;
71
+ border-radius: 20px;
72
+ backdrop-filter: blur(4px);
73
+ }
74
+
75
+ .lb-close {
76
+ position: absolute;
77
+ right: 16px;
78
+ top: 50%;
79
+ transform: translateY(-50%);
80
+ width: 36px;
81
+ height: 36px;
82
+ border: none;
83
+ border-radius: 12px;
84
+ background: transparent;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ cursor: pointer;
89
+ transition: background 0.2s;
90
+ }
91
+ .lb-close:hover {
92
+ background: rgba(255, 255, 255, 0.18);
93
+ }
94
+ .lb-close:active {
95
+ background: rgba(255, 255, 255, 0.28);
96
+ }
97
+
98
+ .lb-close u-icon {
99
+ color: white;
100
+ font-size: 1.25em;
101
+ }
102
+
103
+ /* 중앙 본문: 뷰포트 + 이전/다음 버튼(absolute 오버레이) */
104
+ .lb-body {
105
+ position: relative;
106
+ flex: 1;
107
+ min-height: 0;
108
+ }
109
+
110
+ .lb-viewport {
111
+ position: relative;
112
+ width: 100%;
113
+ height: 100%;
114
+ overflow: hidden;
115
+ }
116
+
117
+ .lb-track {
118
+ position: absolute;
119
+ inset: 0;
120
+ display: flex;
121
+ flex-direction: row;
122
+ align-items: center;
123
+ gap: 16px;
124
+ transition: transform 0.45s cubic-bezier(0.25, 0.1, 0.25, 1);
125
+ will-change: transform;
126
+ }
127
+
128
+ .lb-slide {
129
+ flex: 0 0 70vw;
130
+ height: 100%;
131
+ display: flex;
132
+ align-items: center;
133
+ justify-content: center;
134
+ opacity: 0.5;
135
+ transform: scale(0.9);
136
+ transition: opacity 0.4s ease, transform 0.4s ease;
137
+ }
138
+ .lb-slide[active] {
139
+ opacity: 1;
140
+ transform: scale(1);
141
+ }
142
+ .lb-slide img {
143
+ max-width: 100%;
144
+ max-height: 100%;
145
+ object-fit: contain;
146
+ border-radius: 6px;
147
+ user-select: none;
148
+ pointer-events: none;
149
+ }
150
+
151
+ .lb-nav {
152
+ position: absolute;
153
+ top: 0;
154
+ bottom: 0;
155
+ z-index: 100;
156
+ width: 80px;
157
+ border: none;
158
+ background: transparent;
159
+ display: flex;
160
+ align-items: center;
161
+ justify-content: center;
162
+ cursor: pointer;
163
+ transition: background 0.25s;
164
+ }
165
+ .lb-nav.prev {
166
+ left: 0;
167
+ background: linear-gradient(to right, rgba(0, 0, 0, 0.28), transparent);
168
+ }
169
+ .lb-nav.next {
170
+ right: 0;
171
+ background: linear-gradient(to left, rgba(0, 0, 0, 0.28), transparent);
172
+ }
173
+ .lb-nav.prev:hover {
174
+ background: linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent);
175
+ }
176
+ .lb-nav.next:hover {
177
+ background: linear-gradient(to left, rgba(0, 0, 0, 0.5), transparent);
178
+ }
179
+
180
+ .lb-nav u-icon {
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ color: white;
185
+ font-size: 1.5em;
186
+ padding: 12px;
187
+ border-radius: 50%;
188
+ background: rgba(255, 255, 255, 0.15);
189
+ transition: background 0.2s, transform 0.15s;
190
+ }
191
+ .lb-nav:hover u-icon {
192
+ background: rgba(255, 255, 255, 0.3);
193
+ transform: scale(1.1);
194
+ }
195
+
196
+ /* 하단 푸터: 캡션 */
197
+ .lb-footer {
198
+ position: relative;
199
+ flex-shrink: 0;
200
+ padding: 24px;
201
+ background: linear-gradient(transparent, rgba(0, 0, 0, 0.72));
202
+ }
203
+
204
+ .lb-caption {
205
+ margin: 0;
206
+ color: white;
207
+ font-size: 1.05em;
208
+ line-height: 1.5;
209
+ text-align: center;
210
+ text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
211
+ }
212
+
213
+ @keyframes overlay-fadeIn {
214
+ from { opacity: 0; }
215
+ to { opacity: 1; }
216
+ }
217
+ `;
218
+ //#endregion
219
+ export { styles };