@iyulab/chat-components 0.2.0 → 0.4.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.
- package/CHANGELOG.md +50 -0
- package/dist/assets/action-prompt.md.js +3 -0
- package/dist/assets/widget-prompt.md.js +3 -0
- package/dist/components/actions/UQuestionAction.component.d.ts +18 -0
- package/dist/components/actions/UQuestionAction.component.js +58 -0
- package/dist/components/actions/UQuestionAction.d.ts +7 -0
- package/dist/components/actions/UQuestionAction.js +5 -0
- package/dist/components/actions/UQuestionAction.styles.js +45 -0
- package/dist/components/blocks/UCodeBlock.component.d.ts +5 -3
- package/dist/components/blocks/UCodeBlock.component.js +14 -2
- package/dist/components/blocks/UCodeBlock.styles.js +6 -0
- package/dist/components/blocks/UFilesBlock.component.d.ts +22 -0
- package/dist/components/blocks/UFilesBlock.component.js +192 -0
- package/dist/components/blocks/UFilesBlock.d.ts +7 -0
- package/dist/components/blocks/UFilesBlock.js +5 -0
- package/dist/components/blocks/UFilesBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UFilesBlock.styles.js +206 -0
- package/dist/components/blocks/UJsonBlock.component.d.ts +3 -3
- package/dist/components/blocks/UJsonBlock.component.js +2 -2
- package/dist/components/blocks/UMarkedBlock.component.d.ts +19 -24
- package/dist/components/blocks/UMarkedBlock.component.js +92 -62
- package/dist/components/blocks/URefBlock.component.d.ts +17 -0
- package/dist/components/blocks/URefBlock.component.js +73 -0
- package/dist/components/blocks/URefBlock.d.ts +7 -0
- package/dist/components/blocks/URefBlock.js +5 -0
- package/dist/components/blocks/URefBlock.styles.d.ts +1 -0
- package/dist/components/blocks/URefBlock.styles.js +75 -0
- package/dist/components/blocks/UTableBlock.component.d.ts +49 -0
- package/dist/components/blocks/UTableBlock.component.js +228 -0
- package/dist/components/blocks/UTableBlock.d.ts +7 -0
- package/dist/components/blocks/UTableBlock.js +5 -0
- package/dist/components/blocks/UTableBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UTableBlock.styles.js +134 -0
- package/dist/components/blocks/UTextBlock.component.d.ts +3 -3
- package/dist/components/blocks/UTextBlock.component.js +2 -2
- package/dist/components/blocks/UThinkBlock.component.d.ts +3 -3
- package/dist/components/blocks/UThinkBlock.component.js +2 -2
- package/dist/components/blocks/UToolBlock.component.d.ts +3 -3
- package/dist/components/blocks/UToolBlock.component.js +2 -2
- package/dist/components/buttons/UAttachButton.component.d.ts +3 -3
- package/dist/components/buttons/UAttachButton.component.js +2 -2
- package/dist/components/buttons/UCopyButton.component.d.ts +3 -3
- package/dist/components/buttons/UCopyButton.component.js +2 -2
- package/dist/components/buttons/UReportButton.component.d.ts +3 -3
- package/dist/components/buttons/UReportButton.component.js +2 -2
- package/dist/components/buttons/URetryButton.component.d.ts +3 -3
- package/dist/components/buttons/URetryButton.component.js +2 -2
- package/dist/components/buttons/UShareButton.component.d.ts +3 -3
- package/dist/components/buttons/UShareButton.component.js +2 -2
- package/dist/components/buttons/UVoteButton.component.d.ts +3 -3
- package/dist/components/buttons/UVoteButton.component.js +7 -4
- package/dist/components/message/UMessage.component.d.ts +7 -7
- package/dist/components/message/UMessage.component.js +16 -44
- package/dist/components/message/UMessage.styles.js +38 -11
- package/dist/components/prompt/UPrompt.component.d.ts +3 -3
- package/dist/components/prompt/UPrompt.component.js +2 -2
- package/dist/components/prompt/UPrompt.styles.js +28 -0
- package/dist/components/references/URefCard.component.d.ts +12 -7
- package/dist/components/references/URefCard.component.js +25 -12
- package/dist/components/references/URefCardGroup.component.d.ts +4 -3
- package/dist/components/references/URefCardGroup.component.js +3 -3
- package/dist/components/references/URefTag.component.d.ts +6 -4
- package/dist/components/references/URefTag.component.js +12 -7
- package/dist/components/widgets/UChartWidget.component.d.ts +36 -0
- package/dist/components/widgets/UChartWidget.component.js +180 -0
- package/dist/components/widgets/UChartWidget.d.ts +7 -0
- package/dist/components/widgets/UChartWidget.js +5 -0
- package/dist/components/widgets/UChartWidget.styles.d.ts +1 -0
- package/dist/components/widgets/UChartWidget.styles.js +86 -0
- package/dist/components/widgets/UImagesWidget.component.d.ts +30 -0
- package/dist/components/widgets/UImagesWidget.component.js +164 -0
- package/dist/components/widgets/UImagesWidget.d.ts +7 -0
- package/dist/components/widgets/UImagesWidget.js +5 -0
- package/dist/components/widgets/UImagesWidget.styles.d.ts +1 -0
- package/dist/components/widgets/UImagesWidget.styles.js +218 -0
- package/dist/components/widgets/UMapWidget.component.d.ts +20 -0
- package/dist/components/widgets/UMapWidget.component.js +65 -0
- package/dist/components/widgets/UMapWidget.d.ts +7 -0
- package/dist/components/widgets/UMapWidget.js +5 -0
- package/dist/components/widgets/UMapWidget.styles.d.ts +1 -0
- package/dist/components/widgets/UMapWidget.styles.js +47 -0
- package/dist/components/widgets/UVideoWidget.component.d.ts +21 -0
- package/dist/components/widgets/UVideoWidget.component.js +106 -0
- package/dist/components/widgets/UVideoWidget.d.ts +7 -0
- package/dist/components/widgets/UVideoWidget.js +5 -0
- package/dist/components/widgets/UVideoWidget.styles.d.ts +1 -0
- package/dist/components/widgets/UVideoWidget.styles.js +36 -0
- package/dist/components/widgets/UWidget.component.d.ts +43 -0
- package/dist/components/widgets/UWidget.component.js +140 -0
- package/dist/components/widgets/UWidget.d.ts +7 -0
- package/dist/components/widgets/UWidget.js +5 -0
- package/dist/components/widgets/UWidget.styles.d.ts +1 -0
- package/dist/components/widgets/UWidget.styles.js +33 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +32 -12
- package/dist/types/Actions.d.ts +24 -0
- package/dist/types/Actions.js +34 -0
- package/dist/types/BlockItem.d.ts +41 -4
- package/dist/types/JsonSchema.d.ts +59 -0
- package/dist/types/{BlockReference.d.ts → References.d.ts} +6 -10
- package/dist/types/Widgets.d.ts +34 -0
- package/dist/types/Widgets.js +115 -0
- package/dist/utilities/ActionPromptBuilder.d.ts +40 -0
- package/dist/utilities/ActionPromptBuilder.js +93 -0
- package/dist/utilities/WidgetPromptBuilder.d.ts +28 -0
- package/dist/utilities/WidgetPromptBuilder.js +87 -0
- package/package.json +13 -13
- package/dist/components/loaders/UDotLoader.component.d.ts +0 -9
- package/dist/components/loaders/UDotLoader.component.js +0 -23
- package/dist/components/loaders/UDotLoader.d.ts +0 -7
- package/dist/components/loaders/UDotLoader.js +0 -5
- package/dist/components/loaders/UDotLoader.styles.js +0 -50
- /package/dist/components/{loaders/UDotLoader.styles.d.ts → actions/UQuestionAction.styles.d.ts} +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
width: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* 헤더 영역 */
|
|
11
|
+
.header {
|
|
12
|
+
all: unset;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: row;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
gap: 0.5em;
|
|
18
|
+
color: var(--u-txt-color-strong);
|
|
19
|
+
user-select: none;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
}
|
|
22
|
+
.header:hover {
|
|
23
|
+
color: var(--u-txt-color-hover);
|
|
24
|
+
}
|
|
25
|
+
.header:focus-visible {
|
|
26
|
+
outline: 2px solid rgba(100, 150, 250, 0.6);
|
|
27
|
+
outline-offset: 2px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
u-icon {
|
|
31
|
+
color: inherit;
|
|
32
|
+
font-size: 1em;
|
|
33
|
+
transition: transform 0.2s ease-in-out;
|
|
34
|
+
}
|
|
35
|
+
u-icon[collapsed] {
|
|
36
|
+
transform: rotate(-90deg);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.title {
|
|
40
|
+
color: inherit;
|
|
41
|
+
font-size: 1em;
|
|
42
|
+
line-height: 1.5;
|
|
43
|
+
font-weight: 600;
|
|
44
|
+
color: var(--u-text-color-weak);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.count {
|
|
48
|
+
color: inherit;
|
|
49
|
+
font-size: 0.75em;
|
|
50
|
+
font-weight: 400;
|
|
51
|
+
line-height: 2em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* 바디 영역 */
|
|
55
|
+
.body {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: 0.75em;
|
|
59
|
+
margin-top: 0.75em;
|
|
60
|
+
transition: all 0.3s ease-in-out;
|
|
61
|
+
}
|
|
62
|
+
.body[collapsed] {
|
|
63
|
+
height: 0;
|
|
64
|
+
opacity: 0;
|
|
65
|
+
margin: 0;
|
|
66
|
+
padding: 0;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.body u-ref-card {
|
|
71
|
+
width: 100%;
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export { styles };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
2
|
+
import { UJsonElement } from '@iyulab/components/dist/components/UJsonElement.js';
|
|
3
|
+
/** 테이블 셀 데이터 타입 */
|
|
4
|
+
export interface TableCell {
|
|
5
|
+
/** 셀에 표시할 텍스트 내용 */
|
|
6
|
+
text: string;
|
|
7
|
+
/** 셀 내용의 정렬 방식. 기본값은 "left" */
|
|
8
|
+
align: "left" | "center" | "right" | null;
|
|
9
|
+
}
|
|
10
|
+
/** 테이블 정렬 상태 */
|
|
11
|
+
export interface SortState {
|
|
12
|
+
/** 현재 정렬 기준이 되는 컬럼 인덱스. -1이면 정렬 안 된 상태 */
|
|
13
|
+
index: number;
|
|
14
|
+
/** 정렬 방향. "asc"는 오름차순, "desc"는 내림차순 */
|
|
15
|
+
dir: "asc" | "desc";
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 마크다운 테이블 데이터를 렌더링하는 컴포넌트입니다.
|
|
19
|
+
* 컬럼 정렬, CSV 다운로드 기능을 지원합니다.
|
|
20
|
+
* light DOM 내 `<script type="application/json">` 에서 데이터를 자동으로 읽어냅니다.
|
|
21
|
+
*/
|
|
22
|
+
export declare class UTableBlock extends UJsonElement {
|
|
23
|
+
static styles: (import('lit').CSSResult | import('lit').CSSResultGroup[])[];
|
|
24
|
+
static dependencies: Record<string, typeof UElement>;
|
|
25
|
+
/** 테이블 헤더 목록. 각 헤더는 { text, align } 형식입니다. */
|
|
26
|
+
headers: TableCell[];
|
|
27
|
+
/** 테이블 행 목록. 각 행은 셀 배열입니다. */
|
|
28
|
+
rows: TableCell[][];
|
|
29
|
+
private loading;
|
|
30
|
+
private sort;
|
|
31
|
+
private search;
|
|
32
|
+
private searchCache;
|
|
33
|
+
private searchTimer;
|
|
34
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
35
|
+
/**
|
|
36
|
+
* 하이라이트 렌더링: search 기준으로 매칭되는 부분을 <mark>로 감쌉니다.
|
|
37
|
+
* 내부적으로 안전하게 escape한 뒤 매칭을 위해 RegExp를 사용합니다.
|
|
38
|
+
*/
|
|
39
|
+
private renderHighlightedText;
|
|
40
|
+
/**
|
|
41
|
+
* 현재 검색어와 정렬 상태에 따라 필터링 및 정렬된 행 목록을 반환합니다.
|
|
42
|
+
*/
|
|
43
|
+
private getFilteredSortedRows;
|
|
44
|
+
private handleSearchInput;
|
|
45
|
+
private handleSortColumn;
|
|
46
|
+
private handleDownloadCSV;
|
|
47
|
+
private handleDownloadXLS;
|
|
48
|
+
private triggerDownload;
|
|
49
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { property, state } from 'lit/decorators.js';
|
|
3
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
4
|
+
import { UJsonElement } from '@iyulab/components/dist/components/UJsonElement.js';
|
|
5
|
+
import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
|
|
6
|
+
import { UInput } from '@iyulab/components/dist/components/input/UInput.component.js';
|
|
7
|
+
import { UButton } from '@iyulab/components/dist/components/button/UButton.component.js';
|
|
8
|
+
import { USkeleton } from '@iyulab/components/dist/components/skeleton/USkeleton.component.js';
|
|
9
|
+
import { styles } from './UTableBlock.styles.js';
|
|
10
|
+
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
13
|
+
var result = void 0 ;
|
|
14
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
15
|
+
if (decorator = decorators[i])
|
|
16
|
+
result = (decorator(target, key, result) ) || result;
|
|
17
|
+
if (result) __defProp(target, key, result);
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
class UTableBlock extends UJsonElement {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
this.headers = [];
|
|
24
|
+
this.rows = [];
|
|
25
|
+
this.loading = false;
|
|
26
|
+
this.sort = { index: -1, dir: "asc" };
|
|
27
|
+
this.search = "";
|
|
28
|
+
this.searchCache = "";
|
|
29
|
+
this.searchTimer = null;
|
|
30
|
+
}
|
|
31
|
+
static {
|
|
32
|
+
this.styles = [super.styles, styles];
|
|
33
|
+
}
|
|
34
|
+
static {
|
|
35
|
+
this.dependencies = {
|
|
36
|
+
"u-icon": UIcon,
|
|
37
|
+
"u-input": UInput,
|
|
38
|
+
"u-button": UButton,
|
|
39
|
+
"u-skeleton": USkeleton
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
render() {
|
|
43
|
+
const rows = this.getFilteredSortedRows();
|
|
44
|
+
return html`
|
|
45
|
+
<div class="toolbar">
|
|
46
|
+
<div class="toolbar-left">
|
|
47
|
+
<u-input
|
|
48
|
+
class="toolbar-search"
|
|
49
|
+
type="search"
|
|
50
|
+
placeholder="Search..."
|
|
51
|
+
.value=${this.search}
|
|
52
|
+
@input=${this.handleSearchInput}
|
|
53
|
+
>
|
|
54
|
+
<u-icon slot="prefix" lib="internal" name="search"></u-icon>
|
|
55
|
+
</u-input>
|
|
56
|
+
<span class="toolbar-count">
|
|
57
|
+
${rows.length} / ${this.rows.length} Rows
|
|
58
|
+
</span>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="toolbar-right">
|
|
61
|
+
<u-button @click=${this.handleDownloadXLS} title="Excel Download">
|
|
62
|
+
XLS
|
|
63
|
+
<u-icon slot="suffix" lib="internal" name="download"></u-icon>
|
|
64
|
+
</u-button>
|
|
65
|
+
<u-button @click=${this.handleDownloadCSV} title="CSV Download">
|
|
66
|
+
CSV
|
|
67
|
+
<u-icon slot="suffix" lib="internal" name="download"></u-icon>
|
|
68
|
+
</u-button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="table-wrapper" scrollable>
|
|
72
|
+
<table>
|
|
73
|
+
<thead ?hidden=${!this.headers.length}>
|
|
74
|
+
<tr>
|
|
75
|
+
${repeat(this.headers, (_, i) => i, (h, i) => {
|
|
76
|
+
const isActive = this.sort.index === i;
|
|
77
|
+
return html`
|
|
78
|
+
<th
|
|
79
|
+
?active=${isActive}
|
|
80
|
+
align=${h.align ?? "left"}
|
|
81
|
+
@click=${() => this.handleSortColumn(i)}
|
|
82
|
+
>
|
|
83
|
+
${h.text}
|
|
84
|
+
<u-icon
|
|
85
|
+
class="sort-icon"
|
|
86
|
+
lib="internal"
|
|
87
|
+
name=${isActive ? this.sort.dir === "asc" ? "sort-alpha-up" : "sort-alpha-down" : "arrow-down-up"}
|
|
88
|
+
></u-icon>
|
|
89
|
+
</th>
|
|
90
|
+
`;
|
|
91
|
+
})}
|
|
92
|
+
</tr>
|
|
93
|
+
</thead>
|
|
94
|
+
<tbody>
|
|
95
|
+
${this.loading ? html`
|
|
96
|
+
<tr>
|
|
97
|
+
<td colspan=${this.headers.length || 1}>
|
|
98
|
+
<u-skeleton width="80%" height="1.2em"></u-skeleton>
|
|
99
|
+
<u-skeleton width="60%" height="1.2em"></u-skeleton>
|
|
100
|
+
<u-skeleton width="70%" height="1.2em"></u-skeleton>
|
|
101
|
+
<u-skeleton width="50%" height="1.2em"></u-skeleton>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
` : repeat(rows, (_, i) => i, (row) => html`
|
|
105
|
+
<tr>
|
|
106
|
+
${repeat(row, (_, j) => j, (cell) => html`
|
|
107
|
+
<td align=${cell.align ?? "left"}>
|
|
108
|
+
${this.renderHighlightedText(cell.text)}
|
|
109
|
+
</td>
|
|
110
|
+
`)}
|
|
111
|
+
</tr>
|
|
112
|
+
`)}
|
|
113
|
+
</tbody>
|
|
114
|
+
</table>
|
|
115
|
+
</div>
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 하이라이트 렌더링: search 기준으로 매칭되는 부분을 <mark>로 감쌉니다.
|
|
120
|
+
* 내부적으로 안전하게 escape한 뒤 매칭을 위해 RegExp를 사용합니다.
|
|
121
|
+
*/
|
|
122
|
+
renderHighlightedText(text) {
|
|
123
|
+
const q = this.search.trim();
|
|
124
|
+
if (!q) return text;
|
|
125
|
+
const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126
|
+
const re = new RegExp(`(${escaped})`, "gi");
|
|
127
|
+
const parts = String(text).split(re);
|
|
128
|
+
if (parts.length === 1) return text;
|
|
129
|
+
return html`${parts.map(
|
|
130
|
+
(p, idx) => idx % 2 === 1 ? html`<mark>${p}</mark>` : p
|
|
131
|
+
)}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 현재 검색어와 정렬 상태에 따라 필터링 및 정렬된 행 목록을 반환합니다.
|
|
135
|
+
*/
|
|
136
|
+
getFilteredSortedRows() {
|
|
137
|
+
let rows = this.rows;
|
|
138
|
+
const q = this.search.trim();
|
|
139
|
+
if (q) {
|
|
140
|
+
const qLower = q.toLowerCase();
|
|
141
|
+
rows = rows.filter((row) => row.some((cell) => cell.text.toLowerCase().includes(qLower)));
|
|
142
|
+
}
|
|
143
|
+
const { index, dir } = this.sort;
|
|
144
|
+
if (index < 0) return rows;
|
|
145
|
+
return [...rows].sort((a, b) => {
|
|
146
|
+
const av = a[index]?.text ?? "";
|
|
147
|
+
const bv = b[index]?.text ?? "";
|
|
148
|
+
const an = Number(av);
|
|
149
|
+
const bn = Number(bv);
|
|
150
|
+
const cmp = !isNaN(an) && !isNaN(bn) ? an - bn : av.localeCompare(bv, void 0, { sensitivity: "base" });
|
|
151
|
+
return dir === "asc" ? cmp : -cmp;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/* 250ms 디바운스되어 검색어가 업데이트되는 핸들러. */
|
|
155
|
+
handleSearchInput(e) {
|
|
156
|
+
const input = e.target;
|
|
157
|
+
this.searchCache = input.value;
|
|
158
|
+
if (this.searchTimer !== null) window.clearTimeout(this.searchTimer);
|
|
159
|
+
this.loading = true;
|
|
160
|
+
this.searchTimer = window.setTimeout(() => {
|
|
161
|
+
this.search = this.searchCache;
|
|
162
|
+
this.loading = false;
|
|
163
|
+
this.searchTimer = null;
|
|
164
|
+
}, 250);
|
|
165
|
+
}
|
|
166
|
+
/* 컬럼 헤더 클릭 시 정렬 상태를 토글하는 핸들러 */
|
|
167
|
+
handleSortColumn(index) {
|
|
168
|
+
if (this.sort.index === index) {
|
|
169
|
+
this.sort = { ...this.sort, dir: this.sort.dir === "asc" ? "desc" : "asc" };
|
|
170
|
+
} else {
|
|
171
|
+
this.sort = { index, dir: "asc" };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/* CSV 다운로드 핸들러 */
|
|
175
|
+
handleDownloadCSV() {
|
|
176
|
+
const escCsv = (v) => v.includes(",") || v.includes('"') || v.includes("\n") ? `"${v.replace(/"/g, '""')}"` : v;
|
|
177
|
+
const lines = [
|
|
178
|
+
this.headers.map((h) => escCsv(h.text)).join(","),
|
|
179
|
+
...this.rows.map((row) => row.map((cell) => escCsv(cell.text)).join(","))
|
|
180
|
+
];
|
|
181
|
+
const blob = new Blob([lines.join("\n")], { type: "text/csv;charset=utf-8;" });
|
|
182
|
+
this.triggerDownload("table.csv", blob);
|
|
183
|
+
}
|
|
184
|
+
/* XLS 다운로드 핸들러 */
|
|
185
|
+
handleDownloadXLS() {
|
|
186
|
+
const escXml = (v) => v.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
187
|
+
const cell = (v) => `<Cell><Data ss:Type="String">${escXml(v)}</Data></Cell>`;
|
|
188
|
+
const row = (cells) => `<Row>${cells.map(cell).join("")}</Row>`;
|
|
189
|
+
const xml = [
|
|
190
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
191
|
+
`<?mso-application progid="Excel.Sheet"?>`,
|
|
192
|
+
`<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"`,
|
|
193
|
+
` xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">`,
|
|
194
|
+
`<Worksheet ss:Name="Sheet1"><Table>`,
|
|
195
|
+
row(this.headers.map((h) => h.text)),
|
|
196
|
+
...this.rows.map((r) => row(r.map((c) => c.text))),
|
|
197
|
+
`</Table></Worksheet></Workbook>`
|
|
198
|
+
].join("\n");
|
|
199
|
+
const blob = new Blob([xml], { type: "application/vnd.ms-excel;charset=utf-8;" });
|
|
200
|
+
this.triggerDownload("table.xls", blob);
|
|
201
|
+
}
|
|
202
|
+
/* 파일 다운로드 트리거 */
|
|
203
|
+
triggerDownload(filename, blob) {
|
|
204
|
+
const url = URL.createObjectURL(blob);
|
|
205
|
+
const a = document.createElement("a");
|
|
206
|
+
a.href = url;
|
|
207
|
+
a.download = filename;
|
|
208
|
+
a.click();
|
|
209
|
+
URL.revokeObjectURL(url);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
__decorateClass([
|
|
213
|
+
property({ type: Array })
|
|
214
|
+
], UTableBlock.prototype, "headers");
|
|
215
|
+
__decorateClass([
|
|
216
|
+
property({ type: Array })
|
|
217
|
+
], UTableBlock.prototype, "rows");
|
|
218
|
+
__decorateClass([
|
|
219
|
+
state()
|
|
220
|
+
], UTableBlock.prototype, "loading");
|
|
221
|
+
__decorateClass([
|
|
222
|
+
state()
|
|
223
|
+
], UTableBlock.prototype, "sort");
|
|
224
|
+
__decorateClass([
|
|
225
|
+
state()
|
|
226
|
+
], UTableBlock.prototype, "search");
|
|
227
|
+
|
|
228
|
+
export { UTableBlock };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import('lit').CSSResult;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
display: block;
|
|
6
|
+
width: 100%;
|
|
7
|
+
margin: 8px 0;
|
|
8
|
+
border: 1px solid var(--u-border-color);
|
|
9
|
+
border-radius: 8px;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.toolbar {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
padding: 6px 12px;
|
|
18
|
+
background-color: var(--u-neutral-100);
|
|
19
|
+
border-bottom: 1px solid var(--u-border-color);
|
|
20
|
+
gap: 8px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.toolbar-left {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 8px;
|
|
27
|
+
flex: 1;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.toolbar-search {
|
|
32
|
+
flex: 1;
|
|
33
|
+
max-width: 200px;
|
|
34
|
+
font-size: 12px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.toolbar-count {
|
|
38
|
+
font-size: 12px;
|
|
39
|
+
color: var(--u-txt-color-weak);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.toolbar-right {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: 8px;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.toolbar-right u-button {
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
padding: 0.25em 0.5em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.table-wrapper {
|
|
55
|
+
overflow-x: auto;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
max-height: 480px;
|
|
58
|
+
width: 100%;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
table {
|
|
62
|
+
width: 100%;
|
|
63
|
+
border-collapse: collapse;
|
|
64
|
+
font-size: 14px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
thead {
|
|
68
|
+
position: sticky;
|
|
69
|
+
z-index: 10;
|
|
70
|
+
top: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
thead tr {
|
|
74
|
+
background-color: var(--u-neutral-100);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
th {
|
|
78
|
+
padding: 8px 12px;
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
text-align: left;
|
|
81
|
+
border-bottom: 2px solid var(--u-border-color);
|
|
82
|
+
white-space: nowrap;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
user-select: none;
|
|
85
|
+
}
|
|
86
|
+
th:hover {
|
|
87
|
+
background-color: var(--u-neutral-200);
|
|
88
|
+
}
|
|
89
|
+
th:hover .sort-icon {
|
|
90
|
+
opacity: 0.7;
|
|
91
|
+
}
|
|
92
|
+
th[active] {
|
|
93
|
+
color: var(--u-primary, #4a90e2);
|
|
94
|
+
}
|
|
95
|
+
th[active] .sort-icon {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
th .sort-icon {
|
|
100
|
+
display: inline-flex;
|
|
101
|
+
margin-left: 4px;
|
|
102
|
+
font-size: 12px;
|
|
103
|
+
opacity: 0.3;
|
|
104
|
+
transition: opacity 0.15s;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
tbody tr {
|
|
108
|
+
background-color: var(--u-neutral-0);
|
|
109
|
+
}
|
|
110
|
+
tbody tr:hover td {
|
|
111
|
+
background-color: var(--u-neutral-50, rgba(0,0,0,0.02));
|
|
112
|
+
}
|
|
113
|
+
tbody tr:last-child td {
|
|
114
|
+
border-bottom: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
td {
|
|
118
|
+
padding: 8px 12px;
|
|
119
|
+
border-bottom: 1px solid var(--u-border-color);
|
|
120
|
+
vertical-align: top;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
th[align="left"], td[align="left"] {
|
|
124
|
+
text-align: left;
|
|
125
|
+
}
|
|
126
|
+
th[align="center"], td[align="center"] {
|
|
127
|
+
text-align: center;
|
|
128
|
+
}
|
|
129
|
+
th[align="right"], td[align="right"] {
|
|
130
|
+
text-align: right;
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
export { styles };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
|
-
import {
|
|
2
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
3
3
|
/**
|
|
4
4
|
* 텍스트를 표시하거나 편집할 수 있는 블록 컴포넌트입니다.
|
|
5
5
|
*/
|
|
6
|
-
export declare class UTextBlock extends
|
|
6
|
+
export declare class UTextBlock extends UElement {
|
|
7
7
|
static styles: import('lit').CSSResultGroup[];
|
|
8
|
-
static dependencies: Record<string, typeof
|
|
8
|
+
static dependencies: Record<string, typeof UElement>;
|
|
9
9
|
textareaEl: HTMLTextAreaElement;
|
|
10
10
|
preEl: HTMLPreElement;
|
|
11
11
|
/** 편집 가능 여부 */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { query, property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
4
4
|
import { styles } from './UTextBlock.styles.js';
|
|
5
5
|
|
|
6
6
|
var __defProp = Object.defineProperty;
|
|
@@ -12,7 +12,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
12
12
|
if (result) __defProp(target, key, result);
|
|
13
13
|
return result;
|
|
14
14
|
};
|
|
15
|
-
class UTextBlock extends
|
|
15
|
+
class UTextBlock extends UElement {
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
18
18
|
this.editable = false;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
|
-
import {
|
|
2
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
3
3
|
/**
|
|
4
4
|
* 추론 내용을 표시하는 블록입니다.
|
|
5
5
|
* 로딩 중일 때는 "Thinking..." 메시지를 표시하고, 내용 펼치기/접기 기능을 제공합니다.
|
|
6
6
|
*/
|
|
7
|
-
export declare class UThinkBlock extends
|
|
7
|
+
export declare class UThinkBlock extends UElement {
|
|
8
8
|
static styles: import('lit').CSSResultGroup[];
|
|
9
|
-
static dependencies: Record<string, typeof
|
|
9
|
+
static dependencies: Record<string, typeof UElement>;
|
|
10
10
|
bodyEl: HTMLDivElement;
|
|
11
11
|
/** 컨텐츠가 로딩 중인지 여부 */
|
|
12
12
|
loading: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { query, property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
4
4
|
import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
|
|
5
5
|
import { UMarkedBlock } from './UMarkedBlock.component.js';
|
|
6
6
|
import { styles } from './UThinkBlock.styles.js';
|
|
@@ -14,7 +14,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
14
14
|
if (result) __defProp(target, key, result);
|
|
15
15
|
return result;
|
|
16
16
|
};
|
|
17
|
-
class UThinkBlock extends
|
|
17
|
+
class UThinkBlock extends UElement {
|
|
18
18
|
constructor() {
|
|
19
19
|
super(...arguments);
|
|
20
20
|
this.loading = false;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
2
2
|
import { JsonNode } from '../../types/JsonNode.js';
|
|
3
3
|
/**
|
|
4
4
|
* 툴 사용 블록 컴포넌트입니다.
|
|
5
5
|
*/
|
|
6
|
-
export declare class UToolBlock extends
|
|
6
|
+
export declare class UToolBlock extends UElement {
|
|
7
7
|
static styles: import('lit').CSSResultGroup[];
|
|
8
|
-
static dependencies: Record<string, typeof
|
|
8
|
+
static dependencies: Record<string, typeof UElement>;
|
|
9
9
|
/** 로딩 상태 */
|
|
10
10
|
loading: boolean;
|
|
11
11
|
/** 블록 접힘 여부 */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
4
4
|
import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
|
|
5
5
|
import { USpinner } from '@iyulab/components/dist/components/spinner/USpinner.component.js';
|
|
6
6
|
import { UJsonBlock } from './UJsonBlock.component.js';
|
|
@@ -16,7 +16,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
16
16
|
if (result) __defProp(target, key, result);
|
|
17
17
|
return result;
|
|
18
18
|
};
|
|
19
|
-
class UToolBlock extends
|
|
19
|
+
class UToolBlock extends UElement {
|
|
20
20
|
constructor() {
|
|
21
21
|
super(...arguments);
|
|
22
22
|
this.loading = false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
2
2
|
/**
|
|
3
3
|
* 파일 첨부 버튼 컴포넌트입니다.
|
|
4
4
|
*/
|
|
5
|
-
export declare class UAttachButton extends
|
|
5
|
+
export declare class UAttachButton extends UElement {
|
|
6
6
|
static styles: import('lit').CSSResultGroup[];
|
|
7
|
-
static dependencies: Record<string, typeof
|
|
7
|
+
static dependencies: Record<string, typeof UElement>;
|
|
8
8
|
input?: HTMLInputElement;
|
|
9
9
|
/** 첨부 파일 유형 제한, 컴마로 구분된 MIME 타입 문자열 (예: "image/*,application/pdf") */
|
|
10
10
|
accept?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { query, property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
4
4
|
import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
|
|
5
5
|
import { UButton } from '@iyulab/components/dist/components/button/UButton.component.js';
|
|
6
6
|
import { UTooltip } from '@iyulab/components/dist/components/tooltip/UTooltip.component.js';
|
|
@@ -15,7 +15,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
15
15
|
if (result) __defProp(target, key, result);
|
|
16
16
|
return result;
|
|
17
17
|
};
|
|
18
|
-
class UAttachButton extends
|
|
18
|
+
class UAttachButton extends UElement {
|
|
19
19
|
constructor() {
|
|
20
20
|
super(...arguments);
|
|
21
21
|
this.multiple = false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
2
2
|
/**
|
|
3
3
|
* 클릭 시 클립보드에 텍스트를 복사하는 버튼입니다. 복사 상태를 표시하기 위해 아이콘이 변경됩니다.
|
|
4
4
|
*/
|
|
5
|
-
export declare class UCopyButton extends
|
|
5
|
+
export declare class UCopyButton extends UElement {
|
|
6
6
|
static styles: import('lit').CSSResultGroup[];
|
|
7
|
-
static dependencies: Record<string, typeof
|
|
7
|
+
static dependencies: Record<string, typeof UElement>;
|
|
8
8
|
/** 클립보드 복사 상태를 나타내는 플래그입니다. */
|
|
9
9
|
isCopied: boolean;
|
|
10
10
|
/** 클립보드 복사 후 재사용 대기 시간 (ms) */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { state, property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
4
4
|
import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
|
|
5
5
|
import { UButton } from '@iyulab/components/dist/components/button/UButton.component.js';
|
|
6
6
|
import { UTooltip } from '@iyulab/components/dist/components/tooltip/UTooltip.component.js';
|
|
@@ -15,7 +15,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
15
15
|
if (result) __defProp(target, key, result);
|
|
16
16
|
return result;
|
|
17
17
|
};
|
|
18
|
-
class UCopyButton extends
|
|
18
|
+
class UCopyButton extends UElement {
|
|
19
19
|
constructor() {
|
|
20
20
|
super(...arguments);
|
|
21
21
|
this.isCopied = false;
|