@iyulab/chat-components 0.1.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 +4 -0
- package/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/components/blocks/UCodeBlock.component.d.ts +24 -0
- package/dist/components/blocks/UCodeBlock.component.js +65 -0
- package/dist/components/blocks/UCodeBlock.d.ts +7 -0
- package/dist/components/blocks/UCodeBlock.js +5 -0
- package/dist/components/blocks/UCodeBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UCodeBlock.styles.js +175 -0
- package/dist/components/blocks/UMarkedBlock.component.d.ts +24 -0
- package/dist/components/blocks/UMarkedBlock.component.js +80 -0
- package/dist/components/blocks/UMarkedBlock.d.ts +7 -0
- package/dist/components/blocks/UMarkedBlock.js +5 -0
- package/dist/components/blocks/UMarkedBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UMarkedBlock.styles.js +1240 -0
- package/dist/components/blocks/UTextBlock.component.d.ts +37 -0
- package/dist/components/blocks/UTextBlock.component.js +123 -0
- package/dist/components/blocks/UTextBlock.d.ts +7 -0
- package/dist/components/blocks/UTextBlock.js +5 -0
- package/dist/components/blocks/UTextBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UTextBlock.styles.js +71 -0
- package/dist/components/blocks/UThinkBlock.component.d.ts +28 -0
- package/dist/components/blocks/UThinkBlock.component.js +84 -0
- package/dist/components/blocks/UThinkBlock.d.ts +7 -0
- package/dist/components/blocks/UThinkBlock.js +5 -0
- package/dist/components/blocks/UThinkBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UThinkBlock.styles.js +93 -0
- package/dist/components/blocks/UToolBlock.component.d.ts +16 -0
- package/dist/components/blocks/UToolBlock.component.js +126 -0
- package/dist/components/blocks/UToolBlock.d.ts +7 -0
- package/dist/components/blocks/UToolBlock.js +5 -0
- package/dist/components/blocks/UToolBlock.styles.d.ts +1 -0
- package/dist/components/blocks/UToolBlock.styles.js +107 -0
- package/dist/components/buttons/UAttachButton.component.d.ts +24 -0
- package/dist/components/buttons/UAttachButton.component.js +78 -0
- package/dist/components/buttons/UAttachButton.d.ts +7 -0
- package/dist/components/buttons/UAttachButton.js +5 -0
- package/dist/components/buttons/UAttachButton.styles.d.ts +1 -0
- package/dist/components/buttons/UAttachButton.styles.js +21 -0
- package/dist/components/buttons/UCopyButton.component.d.ts +25 -0
- package/dist/components/buttons/UCopyButton.component.js +105 -0
- package/dist/components/buttons/UCopyButton.d.ts +7 -0
- package/dist/components/buttons/UCopyButton.js +5 -0
- package/dist/components/buttons/UCopyButton.styles.d.ts +1 -0
- package/dist/components/buttons/UCopyButton.styles.js +47 -0
- package/dist/components/buttons/USendButton.component.d.ts +13 -0
- package/dist/components/buttons/USendButton.component.js +46 -0
- package/dist/components/buttons/USendButton.d.ts +7 -0
- package/dist/components/buttons/USendButton.js +5 -0
- package/dist/components/buttons/USendButton.styles.d.ts +1 -0
- package/dist/components/buttons/USendButton.styles.js +23 -0
- package/dist/components/buttons/UThinkButton.component.d.ts +19 -0
- package/dist/components/buttons/UThinkButton.component.js +73 -0
- package/dist/components/buttons/UThinkButton.d.ts +7 -0
- package/dist/components/buttons/UThinkButton.js +5 -0
- package/dist/components/buttons/UThinkButton.styles.d.ts +1 -0
- package/dist/components/buttons/UThinkButton.styles.js +72 -0
- package/dist/components/json-viewer/UJsonViewer.component.d.ts +44 -0
- package/dist/components/json-viewer/UJsonViewer.component.js +137 -0
- package/dist/components/json-viewer/UJsonViewer.d.ts +7 -0
- package/dist/components/json-viewer/UJsonViewer.js +5 -0
- package/dist/components/json-viewer/UJsonViewer.lib.d.ts +16 -0
- package/dist/components/json-viewer/UJsonViewer.lib.js +28 -0
- package/dist/components/json-viewer/UJsonViewer.styles.d.ts +1 -0
- package/dist/components/json-viewer/UJsonViewer.styles.js +115 -0
- package/dist/components/message/UMessage.component.d.ts +13 -0
- package/dist/components/message/UMessage.component.js +104 -0
- package/dist/components/message/UMessage.d.ts +8 -0
- package/dist/components/message/UMessage.js +5 -0
- package/dist/components/message/UMessage.styles.d.ts +1 -0
- package/dist/components/message/UMessage.styles.js +72 -0
- package/dist/components/message/UMessage.types.d.ts +21 -0
- package/dist/events/UStopEvent.d.ts +6 -0
- package/dist/events/USubmitEvent.d.ts +6 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +22 -0
- package/dist/internals/date-helpers.d.ts +8 -0
- package/dist/internals/date-helpers.js +27 -0
- package/package.json +65 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
position: relative;
|
|
6
|
+
padding: 8px;
|
|
7
|
+
font-size: 16px;
|
|
8
|
+
border-radius: 8px;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
user-select: none;
|
|
11
|
+
}
|
|
12
|
+
:host(:hover) {
|
|
13
|
+
background-color: var(--u-neutral-100);
|
|
14
|
+
}
|
|
15
|
+
:host([disabled]) {
|
|
16
|
+
opacity: 0.5;
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
background-color: transparent;
|
|
19
|
+
cursor: not-allowed;
|
|
20
|
+
}
|
|
21
|
+
/* u-icon 스타일 */
|
|
22
|
+
:host([value="low"]) u-icon {
|
|
23
|
+
filter: brightness(0.8);
|
|
24
|
+
color: var(--u-yellow-700);
|
|
25
|
+
}
|
|
26
|
+
:host([value="medium"]) u-icon {
|
|
27
|
+
color: var(--u-yellow-700);
|
|
28
|
+
}
|
|
29
|
+
:host([value="high"]) u-icon {
|
|
30
|
+
color: var(--u-yellow-700);
|
|
31
|
+
}
|
|
32
|
+
/* indicators 스타일 */
|
|
33
|
+
:host([value="low"]) .indicators > span:last-child {
|
|
34
|
+
background-color: var(--u-yellow-700);
|
|
35
|
+
}
|
|
36
|
+
:host([value="medium"]) .indicators > span:nth-last-child(-n+2) {
|
|
37
|
+
background-color: var(--u-yellow-700);
|
|
38
|
+
}
|
|
39
|
+
:host([value="high"]) .indicators > span {
|
|
40
|
+
background-color: var(--u-yellow-700);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.container {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: row;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 4px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
u-icon {
|
|
51
|
+
font-size: inherit;
|
|
52
|
+
color: #e0e0e0;
|
|
53
|
+
transition: color 0.3s ease, filter 0.3s ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.indicators {
|
|
57
|
+
height: 1em;
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
}
|
|
63
|
+
.indicators > span {
|
|
64
|
+
width: 0.5em;
|
|
65
|
+
height: 0.2em;
|
|
66
|
+
border-radius: 2px;
|
|
67
|
+
background-color: #e0e0e0;
|
|
68
|
+
transition: background-color 0.3s ease;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
export { styles };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PropertyValues, TemplateResult } from 'lit';
|
|
2
|
+
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
3
|
+
import { JsonNode } from './UJsonViewer.lib.js';
|
|
4
|
+
/**
|
|
5
|
+
* json 데이터를 트리 형태로 시각화하는 컴포넌트입니다.
|
|
6
|
+
*/
|
|
7
|
+
export declare class UJsonViewer extends BaseElement {
|
|
8
|
+
static styles: import('lit').CSSResultGroup[];
|
|
9
|
+
static dependencies: Record<string, typeof BaseElement>;
|
|
10
|
+
state: Record<string, boolean>;
|
|
11
|
+
/** 초기 확장 상태를 관리하는 속성입니다. */
|
|
12
|
+
expanded: boolean;
|
|
13
|
+
/** JSON 데이터 (속성으로 전달 가능) */
|
|
14
|
+
value: JsonNode;
|
|
15
|
+
connectedCallback(): void;
|
|
16
|
+
protected willUpdate(changedProperties: PropertyValues): void;
|
|
17
|
+
render(): TemplateResult<1>;
|
|
18
|
+
/**
|
|
19
|
+
* JsonNode를 렌더링합니다.
|
|
20
|
+
* @param value - JsonNode (JsonObject, JsonArray, 또는 JsonValue)
|
|
21
|
+
* @param parent - 부모 노드의 경로
|
|
22
|
+
*/
|
|
23
|
+
private renderNode;
|
|
24
|
+
/**
|
|
25
|
+
* JsonValue를 렌더링합니다.
|
|
26
|
+
* @param node - JsonValue (string, number, boolean, null 등)
|
|
27
|
+
*/
|
|
28
|
+
private renderValue;
|
|
29
|
+
/**
|
|
30
|
+
* JsonObject 또는 JsonArray를 렌더링합니다.
|
|
31
|
+
* @param node - JsonObject 또는 JsonArray
|
|
32
|
+
* @param depth - 현재 깊이
|
|
33
|
+
*/
|
|
34
|
+
private renderObject;
|
|
35
|
+
/**
|
|
36
|
+
* 노드의 미리보기를 렌더링합니다.
|
|
37
|
+
* @param node - JsonObject 또는 JsonArray
|
|
38
|
+
*/
|
|
39
|
+
private renderPreview;
|
|
40
|
+
/** 노드 확장/축소 클릭 핸들러 */
|
|
41
|
+
private toggle;
|
|
42
|
+
/** JSON 데이터를 순회하며 각 경로의 확장 상태를 설정합니다. */
|
|
43
|
+
private setState;
|
|
44
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { state, property } from 'lit/decorators.js';
|
|
3
|
+
import { map } from 'lit/directives/map.js';
|
|
4
|
+
import { when } from 'lit/directives/when.js';
|
|
5
|
+
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
6
|
+
import { isValueType, getNodeName, jsonConverter } from './UJsonViewer.lib.js';
|
|
7
|
+
import { styles } from './UJsonViewer.styles.js';
|
|
8
|
+
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
11
|
+
var result = void 0 ;
|
|
12
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
13
|
+
if (decorator = decorators[i])
|
|
14
|
+
result = (decorator(target, key, result) ) || result;
|
|
15
|
+
if (result) __defProp(target, key, result);
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
class UJsonViewer extends BaseElement {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.state = {};
|
|
22
|
+
this.expanded = true;
|
|
23
|
+
this.value = {};
|
|
24
|
+
}
|
|
25
|
+
static {
|
|
26
|
+
this.styles = [super.styles, styles];
|
|
27
|
+
}
|
|
28
|
+
static {
|
|
29
|
+
this.dependencies = {};
|
|
30
|
+
}
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
super.connectedCallback();
|
|
33
|
+
this.setAttribute("tabindex", "0");
|
|
34
|
+
}
|
|
35
|
+
willUpdate(changedProperties) {
|
|
36
|
+
super.willUpdate(changedProperties);
|
|
37
|
+
if (changedProperties.has("value") || changedProperties.has("expanded")) {
|
|
38
|
+
this.state = this.setState(this.value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
render() {
|
|
42
|
+
return html`
|
|
43
|
+
<div part="base">
|
|
44
|
+
${this.renderNode(this.value)}
|
|
45
|
+
</div>
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* JsonNode를 렌더링합니다.
|
|
50
|
+
* @param value - JsonNode (JsonObject, JsonArray, 또는 JsonValue)
|
|
51
|
+
* @param parent - 부모 노드의 경로
|
|
52
|
+
*/
|
|
53
|
+
renderNode(value, parent = "") {
|
|
54
|
+
return isValueType(value) ? this.renderValue(value) : this.renderObject(value, parent);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* JsonValue를 렌더링합니다.
|
|
58
|
+
* @param node - JsonValue (string, number, boolean, null 등)
|
|
59
|
+
*/
|
|
60
|
+
renderValue(node) {
|
|
61
|
+
const type = getNodeName(node);
|
|
62
|
+
return html`
|
|
63
|
+
<span part="${type}" class="${type}" role="treeitem">
|
|
64
|
+
${JSON.stringify(node)}
|
|
65
|
+
</span>
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* JsonObject 또는 JsonArray를 렌더링합니다.
|
|
70
|
+
* @param node - JsonObject 또는 JsonArray
|
|
71
|
+
* @param depth - 현재 깊이
|
|
72
|
+
*/
|
|
73
|
+
renderObject(node, parent) {
|
|
74
|
+
return html`
|
|
75
|
+
<ul part="object" role="group">
|
|
76
|
+
${map(Object.entries(node), ([key, value]) => {
|
|
77
|
+
const path = parent ? `${parent}.${key}` : key;
|
|
78
|
+
const isValue = isValueType(value);
|
|
79
|
+
const isExpanded = this.state[path] ?? this.expanded;
|
|
80
|
+
return html`
|
|
81
|
+
<li part="property" role="treeitem"
|
|
82
|
+
data-path="${path}"
|
|
83
|
+
aria-expanded="${isExpanded ? "true" : "false"}">
|
|
84
|
+
<span part="key"
|
|
85
|
+
class="key"
|
|
86
|
+
?collapsable="${!isValue}"
|
|
87
|
+
?collapsed="${!isValue && !isExpanded}"
|
|
88
|
+
@click=${!isValue ? () => this.toggle(path) : null}>
|
|
89
|
+
${key}:
|
|
90
|
+
${when(!isValue && !isExpanded, () => this.renderPreview(value))}
|
|
91
|
+
</span>
|
|
92
|
+
|
|
93
|
+
${when(isValue || isExpanded, () => this.renderNode(value, path))}
|
|
94
|
+
</li>`;
|
|
95
|
+
})}
|
|
96
|
+
</ul>
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 노드의 미리보기를 렌더링합니다.
|
|
101
|
+
* @param node - JsonObject 또는 JsonArray
|
|
102
|
+
*/
|
|
103
|
+
renderPreview(node) {
|
|
104
|
+
return html`
|
|
105
|
+
<span part="preview" class="preview">
|
|
106
|
+
${Array.isArray(node) ? node.length === 0 ? "[ ]" : `[ ${node.length} items ]` : Object.keys(node).length === 0 ? "{ }" : `{ ${Object.keys(node).length} properties }`}
|
|
107
|
+
</span>
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
/** 노드 확장/축소 클릭 핸들러 */
|
|
111
|
+
toggle(path) {
|
|
112
|
+
const isExpanded = this.state[path] ?? false;
|
|
113
|
+
this.state = { ...this.state, [path]: !isExpanded };
|
|
114
|
+
}
|
|
115
|
+
/** JSON 데이터를 순회하며 각 경로의 확장 상태를 설정합니다. */
|
|
116
|
+
setState(value, parent = "") {
|
|
117
|
+
if (typeof value !== "object" || value === null) return {};
|
|
118
|
+
const state2 = {};
|
|
119
|
+
Object.entries(value).forEach(([key, item]) => {
|
|
120
|
+
const path = parent ? `${parent}.${key}` : key;
|
|
121
|
+
state2[path] = this.expanded;
|
|
122
|
+
Object.assign(state2, this.setState(item, path));
|
|
123
|
+
});
|
|
124
|
+
return state2;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
__decorateClass([
|
|
128
|
+
state()
|
|
129
|
+
], UJsonViewer.prototype, "state");
|
|
130
|
+
__decorateClass([
|
|
131
|
+
property({ type: Boolean })
|
|
132
|
+
], UJsonViewer.prototype, "expanded");
|
|
133
|
+
__decorateClass([
|
|
134
|
+
property({ type: Object, converter: jsonConverter })
|
|
135
|
+
], UJsonViewer.prototype, "value");
|
|
136
|
+
|
|
137
|
+
export { UJsonViewer };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type JsonValue = string | number | boolean | null;
|
|
2
|
+
export type JsonObject = {
|
|
3
|
+
[x: string]: JsonNode;
|
|
4
|
+
};
|
|
5
|
+
export type JsonArray = Array<JsonNode>;
|
|
6
|
+
export type JsonNode = JsonValue | JsonObject | JsonArray;
|
|
7
|
+
/**
|
|
8
|
+
* 이 컨버터는 JsonNode 타입을 사용하여 JSON 데이터를 처리합니다.
|
|
9
|
+
* 문자열 어트리뷰트로 전달된 JSON 문자열을 객체로 변환/직렬화합니다.
|
|
10
|
+
*/
|
|
11
|
+
export declare const jsonConverter: {
|
|
12
|
+
fromAttribute: (value: string | null) => JsonNode;
|
|
13
|
+
toAttribute: (value: JsonNode) => string;
|
|
14
|
+
};
|
|
15
|
+
export declare const isValueType: (value: JsonNode) => boolean;
|
|
16
|
+
export declare const getNodeName: (value: JsonNode) => string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const jsonConverter = {
|
|
2
|
+
fromAttribute: (value) => {
|
|
3
|
+
if (!value || !value.trim()) return {};
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(value);
|
|
6
|
+
} catch {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
toAttribute: (value) => {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.stringify(value);
|
|
13
|
+
} catch {
|
|
14
|
+
return "{}";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const isValueType = (value) => {
|
|
19
|
+
return value !== Object(value);
|
|
20
|
+
};
|
|
21
|
+
const getNodeName = (value) => {
|
|
22
|
+
if (value === null) return "null";
|
|
23
|
+
if (Array.isArray(value)) return "array";
|
|
24
|
+
if (typeof value === "object") return "object";
|
|
25
|
+
return typeof value;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { getNodeName, isValueType, jsonConverter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import('lit').CSSResult;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
--indent-size: 2em;
|
|
6
|
+
|
|
7
|
+
--json-property-color: #0451a5;
|
|
8
|
+
--json-string-color: #a31515;
|
|
9
|
+
--json-number-color: #098658;
|
|
10
|
+
--json-boolean-color: #0000ff;
|
|
11
|
+
--json-null-color: #0000ff;
|
|
12
|
+
--json-preview-color: #999999;
|
|
13
|
+
--json-arrow-color: #666968;
|
|
14
|
+
--json-guide-color: #c0c0c0;
|
|
15
|
+
}
|
|
16
|
+
:host-context([theme="dark"]) {
|
|
17
|
+
--json-property-color: #9cdcfe;
|
|
18
|
+
--json-string-color: #ce9178;
|
|
19
|
+
--json-number-color: #b5cea8;
|
|
20
|
+
--json-boolean-color: #569cd6;
|
|
21
|
+
--json-null-color: #569CD6;
|
|
22
|
+
--json-preview-color: #999999;
|
|
23
|
+
--json-arrow-color: #d4d4d4;
|
|
24
|
+
--json-guide-color: #3c3c3c;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:host {
|
|
28
|
+
display: block;
|
|
29
|
+
font-family: inherit;
|
|
30
|
+
font-size: inherit;
|
|
31
|
+
line-height: 1.5;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.key {
|
|
35
|
+
color: var(--json-property-color);
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
}
|
|
39
|
+
.key[collapsable] {
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
user-select: none;
|
|
42
|
+
}
|
|
43
|
+
.key[collapsable]::before {
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
font-size: 0.5em;
|
|
46
|
+
content: '▶';
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
|
|
50
|
+
transform: rotate(90deg);
|
|
51
|
+
transition: transform 0.2s ease-out;
|
|
52
|
+
margin-right: 0.5em;
|
|
53
|
+
|
|
54
|
+
color: var(--json-arrow-color);
|
|
55
|
+
}
|
|
56
|
+
.key[collapsable][collapsed]::before {
|
|
57
|
+
transform: rotate(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.preview {
|
|
61
|
+
color: var(--json-preview-color);
|
|
62
|
+
margin-left: 0.5em;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.string {
|
|
66
|
+
color: var(--json-string-color);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.number {
|
|
70
|
+
color: var(--json-number-color);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.boolean {
|
|
74
|
+
color: var(--json-boolean-color);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.null {
|
|
78
|
+
color: var(--json-null-color);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* object styles */
|
|
82
|
+
ul {
|
|
83
|
+
position: relative;
|
|
84
|
+
list-style: none;
|
|
85
|
+
margin: 0;
|
|
86
|
+
padding: 0;
|
|
87
|
+
clear: both;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* property styles */
|
|
91
|
+
li {
|
|
92
|
+
position: relative;
|
|
93
|
+
list-style: none;
|
|
94
|
+
outline: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* nested property styles */
|
|
98
|
+
li ul > li {
|
|
99
|
+
position: relative;
|
|
100
|
+
margin-left: var(--indent-size);
|
|
101
|
+
padding-left: 0px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* guide line styles */
|
|
105
|
+
ul ul::before {
|
|
106
|
+
content: '';
|
|
107
|
+
border-left: 1px solid var(--json-guide-color);
|
|
108
|
+
position: absolute;
|
|
109
|
+
left: calc(1.5em / 2 - 1px);
|
|
110
|
+
top: 0.2em;
|
|
111
|
+
bottom: 0.2em;
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
export { styles };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
2
|
+
import { BlockItem } from './UMessage.types.js';
|
|
3
|
+
export declare class UMessage extends BaseElement {
|
|
4
|
+
static styles: import('lit').CSSResultGroup[];
|
|
5
|
+
static dependencies: Record<string, typeof BaseElement>;
|
|
6
|
+
items?: BlockItem[];
|
|
7
|
+
timestamp?: string;
|
|
8
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
9
|
+
/**
|
|
10
|
+
* 텍스트 및 마크다운 블록의 내용을 모아서 하나의 문자열로 반환합니다.
|
|
11
|
+
*/
|
|
12
|
+
private getTextValue;
|
|
13
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { nothing, html } from 'lit';
|
|
2
|
+
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
4
|
+
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
5
|
+
import { UCopyButton } from '../buttons/UCopyButton.component.js';
|
|
6
|
+
import { UTextBlock } from '../blocks/UTextBlock.component.js';
|
|
7
|
+
import { UMarkedBlock } from '../blocks/UMarkedBlock.component.js';
|
|
8
|
+
import { UThinkBlock } from '../blocks/UThinkBlock.component.js';
|
|
9
|
+
import { UToolBlock } from '../blocks/UToolBlock.component.js';
|
|
10
|
+
import { format } from '../../internals/date-helpers.js';
|
|
11
|
+
import { styles } from './UMessage.styles.js';
|
|
12
|
+
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
15
|
+
var result = void 0 ;
|
|
16
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
17
|
+
if (decorator = decorators[i])
|
|
18
|
+
result = (decorator(target, key, result) ) || result;
|
|
19
|
+
if (result) __defProp(target, key, result);
|
|
20
|
+
return result;
|
|
21
|
+
};
|
|
22
|
+
class UMessage extends BaseElement {
|
|
23
|
+
constructor() {
|
|
24
|
+
super(...arguments);
|
|
25
|
+
/**
|
|
26
|
+
* 텍스트 및 마크다운 블록의 내용을 모아서 하나의 문자열로 반환합니다.
|
|
27
|
+
*/
|
|
28
|
+
this.getTextValue = (items) => {
|
|
29
|
+
if (!items) return "";
|
|
30
|
+
return items.reduce((acc, item) => {
|
|
31
|
+
if (item.type === "text" || item.type === "markdown") {
|
|
32
|
+
return acc ? acc + "\n" + (item.value || "") : item.value || "";
|
|
33
|
+
}
|
|
34
|
+
return acc;
|
|
35
|
+
}, "");
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
static {
|
|
39
|
+
this.styles = [super.styles, styles];
|
|
40
|
+
}
|
|
41
|
+
static {
|
|
42
|
+
this.dependencies = {
|
|
43
|
+
"u-text-block": UTextBlock,
|
|
44
|
+
"u-marked-block": UMarkedBlock,
|
|
45
|
+
"u-think-block": UThinkBlock,
|
|
46
|
+
"u-tool-block": UToolBlock,
|
|
47
|
+
"u-copy-button": UCopyButton
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
render() {
|
|
51
|
+
return html`
|
|
52
|
+
<div class="container">
|
|
53
|
+
<div class="header" part="header">
|
|
54
|
+
<slot name="header"></slot>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="body" part="body">
|
|
57
|
+
${this.items && this.items.length > 0 ? repeat(this.items, (_, idx) => idx, (item, idx) => {
|
|
58
|
+
return item.type === "text" ? html`
|
|
59
|
+
<u-text-block
|
|
60
|
+
.value=${item.value}
|
|
61
|
+
></u-text-block>` : item.type === "markdown" ? html`
|
|
62
|
+
<u-marked-block
|
|
63
|
+
.value=${item.value}
|
|
64
|
+
></u-marked-block>` : item.type === "thinking" ? html`
|
|
65
|
+
<u-think-block
|
|
66
|
+
?loading=${this.items?.length === (idx || 0) + 1}
|
|
67
|
+
.value=${item.value}
|
|
68
|
+
></u-think-block>` : item.type === "tool" ? html`
|
|
69
|
+
<u-tool-block
|
|
70
|
+
.index=${idx}
|
|
71
|
+
.status=${item.status}
|
|
72
|
+
.name=${item.name}
|
|
73
|
+
.input=${item.input}
|
|
74
|
+
.output=${item.output}
|
|
75
|
+
></u-tool-block>` : nothing;
|
|
76
|
+
}) : html`
|
|
77
|
+
<svg class="loader" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
78
|
+
<circle class="dot" cx="4" cy="12" r="3"/>
|
|
79
|
+
<circle class="dot d1" cx="12" cy="12" r="3"/>
|
|
80
|
+
<circle class="dot d2" cx="20" cy="12" r="3"/>
|
|
81
|
+
</svg>`}
|
|
82
|
+
</div>
|
|
83
|
+
<div class="footer" part="footer">
|
|
84
|
+
<u-copy-button
|
|
85
|
+
.value=${this.getTextValue(this.items)}
|
|
86
|
+
></u-copy-button>
|
|
87
|
+
<slot name="footer"></slot>
|
|
88
|
+
<div style="flex:1;"></div>
|
|
89
|
+
<div class="timestamp">
|
|
90
|
+
${format(this.timestamp)}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
__decorateClass([
|
|
98
|
+
property({ type: Array })
|
|
99
|
+
], UMessage.prototype, "items");
|
|
100
|
+
__decorateClass([
|
|
101
|
+
property({ type: String })
|
|
102
|
+
], UMessage.prototype, "timestamp");
|
|
103
|
+
|
|
104
|
+
export { UMessage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import('lit').CSSResult;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
display: block;
|
|
6
|
+
font-family: 'Roboto', sans-serif;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
line-height: 1.5;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.container {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.header {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: row;
|
|
19
|
+
align-items: center;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.body {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
gap: 12px;
|
|
26
|
+
padding: 8px;
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: 8px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.footer {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: row;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: space-between;
|
|
36
|
+
padding: 8px 0px;
|
|
37
|
+
gap: 12px;
|
|
38
|
+
font-size: 12px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.loader {
|
|
42
|
+
width: 1em;
|
|
43
|
+
height: 1em;
|
|
44
|
+
fill: currentColor;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.dot {
|
|
48
|
+
animation: bounce_action 1.05s infinite
|
|
49
|
+
}
|
|
50
|
+
.d1 {
|
|
51
|
+
animation-delay:.1s
|
|
52
|
+
}
|
|
53
|
+
.d2 {
|
|
54
|
+
animation-delay:.2s
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes bounce_action {
|
|
58
|
+
0%,57.14% {
|
|
59
|
+
animation-timing-function: cubic-bezier(0.33,.66,.66,1);
|
|
60
|
+
transform: translate(0);
|
|
61
|
+
}
|
|
62
|
+
28.57% {
|
|
63
|
+
animation-timing-function: cubic-bezier(0.33,0,.66,.33);
|
|
64
|
+
transform: translateY(-6px);
|
|
65
|
+
}
|
|
66
|
+
100% {
|
|
67
|
+
transform: translate(0);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
export { styles };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface TextBlockItem {
|
|
2
|
+
type: "text";
|
|
3
|
+
value?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface MarkdownBlockItem {
|
|
6
|
+
type: "markdown";
|
|
7
|
+
value?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ThinkingBlockItem {
|
|
10
|
+
type: "thinking";
|
|
11
|
+
value?: string;
|
|
12
|
+
}
|
|
13
|
+
export type ToolBlockStatus = ("pending" | "paused" | "inProgress" | "success" | "failure");
|
|
14
|
+
export interface ToolBlockItem {
|
|
15
|
+
type: "tool";
|
|
16
|
+
status: ToolBlockStatus;
|
|
17
|
+
name?: string;
|
|
18
|
+
input?: string;
|
|
19
|
+
output?: string;
|
|
20
|
+
}
|
|
21
|
+
export type BlockItem = (TextBlockItem | MarkdownBlockItem | ThinkingBlockItem | ToolBlockItem);
|