@iyulab/chat-components 0.1.1 → 0.2.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 +24 -1
- package/dist/components/blocks/UCodeBlock.component.d.ts +7 -8
- package/dist/components/blocks/UCodeBlock.component.js +32 -21
- package/dist/components/blocks/UCodeBlock.styles.js +7 -6
- package/dist/components/{json-viewer/UJsonViewer.component.d.ts → blocks/UJsonBlock.component.d.ts} +5 -4
- package/dist/components/{json-viewer/UJsonViewer.component.js → blocks/UJsonBlock.component.js} +20 -17
- package/dist/components/blocks/UJsonBlock.d.ts +7 -0
- package/dist/components/blocks/UJsonBlock.js +5 -0
- package/dist/components/blocks/UMarkedBlock.component.d.ts +30 -9
- package/dist/components/blocks/UMarkedBlock.component.js +75 -26
- package/dist/components/blocks/UMarkedBlock.styles.js +288 -949
- package/dist/components/blocks/UThinkBlock.component.d.ts +3 -8
- package/dist/components/blocks/UThinkBlock.component.js +28 -22
- package/dist/components/blocks/UThinkBlock.styles.js +35 -54
- package/dist/components/blocks/UToolBlock.component.d.ts +13 -9
- package/dist/components/blocks/UToolBlock.component.js +30 -76
- package/dist/components/blocks/UToolBlock.styles.js +21 -62
- package/dist/components/buttons/UAttachButton.component.d.ts +3 -5
- package/dist/components/buttons/UAttachButton.component.js +30 -19
- package/dist/components/buttons/UAttachButton.styles.js +5 -12
- package/dist/components/buttons/UCopyButton.component.d.ts +3 -8
- package/dist/components/buttons/UCopyButton.component.js +29 -53
- package/dist/components/buttons/UCopyButton.styles.js +8 -37
- package/dist/components/buttons/UReportButton.component.d.ts +9 -0
- package/dist/components/buttons/UReportButton.component.js +36 -0
- package/dist/components/buttons/UReportButton.d.ts +7 -0
- package/dist/components/buttons/UReportButton.js +5 -0
- package/dist/components/buttons/UReportButton.styles.js +14 -0
- package/dist/components/buttons/URetryButton.component.d.ts +11 -0
- package/dist/components/buttons/URetryButton.component.js +53 -0
- package/dist/components/buttons/URetryButton.d.ts +7 -0
- package/dist/components/buttons/URetryButton.js +5 -0
- package/dist/components/buttons/URetryButton.styles.js +26 -0
- package/dist/components/buttons/UShareButton.component.d.ts +9 -0
- package/dist/components/buttons/UShareButton.component.js +36 -0
- package/dist/components/buttons/UShareButton.d.ts +7 -0
- package/dist/components/buttons/UShareButton.js +5 -0
- package/dist/components/buttons/UShareButton.styles.d.ts +1 -0
- package/dist/components/buttons/UShareButton.styles.js +14 -0
- package/dist/components/buttons/UVoteButton.component.d.ts +15 -0
- package/dist/components/buttons/UVoteButton.component.js +70 -0
- package/dist/components/buttons/UVoteButton.d.ts +8 -0
- package/dist/components/buttons/UVoteButton.js +5 -0
- package/dist/components/buttons/UVoteButton.styles.d.ts +1 -0
- package/dist/components/buttons/UVoteButton.styles.js +19 -0
- package/dist/components/loaders/UDotLoader.component.d.ts +9 -0
- package/dist/components/loaders/UDotLoader.component.js +23 -0
- package/dist/components/loaders/UDotLoader.d.ts +7 -0
- package/dist/components/loaders/UDotLoader.js +5 -0
- package/dist/components/loaders/UDotLoader.styles.d.ts +1 -0
- package/dist/components/loaders/UDotLoader.styles.js +50 -0
- package/dist/components/message/UMessage.component.d.ts +12 -6
- package/dist/components/message/UMessage.component.js +39 -59
- package/dist/components/message/UMessage.d.ts +0 -1
- package/dist/components/message/UMessage.styles.js +30 -49
- package/dist/components/prompt/UPrompt.component.d.ts +25 -0
- package/dist/components/prompt/UPrompt.component.js +113 -0
- package/dist/components/prompt/UPrompt.d.ts +7 -0
- package/dist/components/prompt/UPrompt.js +5 -0
- package/dist/components/prompt/UPrompt.styles.d.ts +1 -0
- package/dist/components/prompt/UPrompt.styles.js +42 -0
- package/dist/components/references/URefCard.component.d.ts +22 -0
- package/dist/components/references/URefCard.component.js +96 -0
- package/dist/components/references/URefCard.d.ts +7 -0
- package/dist/components/references/URefCard.js +5 -0
- package/dist/components/references/URefCard.styles.d.ts +1 -0
- package/dist/components/references/URefCard.styles.js +103 -0
- package/dist/components/references/URefCardGroup.component.d.ts +25 -0
- package/dist/components/references/URefCardGroup.component.js +88 -0
- package/dist/components/references/URefCardGroup.d.ts +7 -0
- package/dist/components/references/URefCardGroup.js +5 -0
- package/dist/components/references/URefCardGroup.styles.d.ts +1 -0
- package/dist/components/references/URefCardGroup.styles.js +69 -0
- package/dist/components/references/URefTag.component.d.ts +11 -0
- package/dist/components/{buttons/USendButton.component.js → references/URefTag.component.js} +17 -14
- package/dist/components/references/URefTag.d.ts +7 -0
- package/dist/components/references/URefTag.js +5 -0
- package/dist/components/references/URefTag.styles.d.ts +1 -0
- package/dist/components/references/URefTag.styles.js +51 -0
- package/dist/events/UCancelEvent.d.ts +6 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.js +20 -6
- package/dist/types/BlockItem.d.ts +36 -0
- package/dist/types/BlockReference.d.ts +32 -0
- package/dist/types/JsonNode.d.ts +20 -0
- package/dist/utilities/converters.d.ts +9 -0
- package/dist/utilities/converters.js +19 -0
- package/package.json +9 -10
- package/dist/components/buttons/USendButton.component.d.ts +0 -13
- package/dist/components/buttons/USendButton.d.ts +0 -7
- package/dist/components/buttons/USendButton.js +0 -5
- package/dist/components/buttons/USendButton.styles.js +0 -23
- package/dist/components/buttons/UThinkButton.component.d.ts +0 -19
- package/dist/components/buttons/UThinkButton.component.js +0 -73
- package/dist/components/buttons/UThinkButton.d.ts +0 -7
- package/dist/components/buttons/UThinkButton.js +0 -5
- package/dist/components/buttons/UThinkButton.styles.js +0 -72
- package/dist/components/json-viewer/UJsonViewer.d.ts +0 -7
- package/dist/components/json-viewer/UJsonViewer.js +0 -5
- package/dist/components/json-viewer/UJsonViewer.lib.d.ts +0 -16
- package/dist/components/json-viewer/UJsonViewer.lib.js +0 -28
- package/dist/components/message/UMessage.types.d.ts +0 -21
- package/dist/events/UStopEvent.d.ts +0 -6
- package/dist/internals/date-helpers.d.ts +0 -8
- package/dist/internals/date-helpers.js +0 -27
- /package/dist/components/{buttons/USendButton.styles.d.ts → blocks/UJsonBlock.styles.d.ts} +0 -0
- /package/dist/components/{json-viewer/UJsonViewer.styles.js → blocks/UJsonBlock.styles.js} +0 -0
- /package/dist/components/buttons/{UThinkButton.styles.d.ts → UReportButton.styles.d.ts} +0 -0
- /package/dist/components/{json-viewer/UJsonViewer.styles.d.ts → buttons/URetryButton.styles.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 (2026-01-16)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- New components: `UPrompt`, `UDotLoader` for enhanced chat UI
|
|
7
|
+
- Reference components: `URefCard`, `URefCardGroup`, `URefTag` for displaying references
|
|
8
|
+
- New button components: `UReportButton`, `URetryButton`, `UShareButton`, `UVoteButton`
|
|
9
|
+
- `UCancelEvent` to replace `UStopEvent`
|
|
10
|
+
- Type definitions: `BlockItem`, `BlockReference`, `JsonNode`
|
|
11
|
+
- Utility converters for data transformation
|
|
12
|
+
- Test utilities: generator.ts, messages.ts
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Renamed UJsonViewer to UJsonBlock for consistency
|
|
16
|
+
- Enhanced styling and functionality across multiple block components
|
|
17
|
+
- Updated button components styling and behavior (UAttachButton, UCopyButton)
|
|
18
|
+
- Improved UMessage component structure and styling
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
- Deprecated buttons: USendButton, UThinkButton
|
|
22
|
+
- UStopEvent (replaced by UCancelEvent)
|
|
23
|
+
- UMessage.types.ts (types moved to dedicated types directory)
|
|
24
|
+
- Internal date-helpers utility
|
|
25
|
+
|
|
3
26
|
## 0.1.1 (2025-12-19)
|
|
4
|
-
Update package.json exports field with correct paths
|
|
27
|
+
- Update package.json exports field with correct paths
|
|
5
28
|
|
|
6
29
|
## 0.1.0 (2025-12-19)
|
|
7
30
|
- Initial library version release
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { nothing } from 'lit';
|
|
2
1
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
3
2
|
/**
|
|
4
3
|
* 코드 블록을 렌더링하는 컴포넌트입니다.
|
|
@@ -7,18 +6,18 @@ import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
|
7
6
|
export declare class UCodeBlock extends BaseElement {
|
|
8
7
|
static styles: import('lit').CSSResultGroup[];
|
|
9
8
|
static dependencies: Record<string, typeof BaseElement>;
|
|
9
|
+
/** 클립보드 복사 상태를 나타내는 플래그입니다. */
|
|
10
|
+
isCopied: boolean;
|
|
10
11
|
/** 코드 블록의 헤더를 숨길지 여부를 지정합니다. */
|
|
11
12
|
headless: boolean;
|
|
12
13
|
/** 코드 언어를 지정합니다. */
|
|
13
|
-
|
|
14
|
+
lang: string;
|
|
14
15
|
/** 표시할 코드 내용입니다. */
|
|
15
16
|
value?: string;
|
|
16
|
-
render(): import('lit-html').TemplateResult<1
|
|
17
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @param lang 코드 언어
|
|
21
|
-
* @returns 구문 강조가 적용된 HTML 문자열
|
|
19
|
+
* slot에 할당된 코드를 value로 설정합니다.
|
|
20
|
+
* 이 기능을 통해 HTML 내에 직접 코드를 작성할 수 있습니다.
|
|
22
21
|
*/
|
|
23
|
-
private
|
|
22
|
+
private handleSlotChange;
|
|
24
23
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { property } from 'lit/decorators.js';
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { state, property } from 'lit/decorators.js';
|
|
3
3
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import hljs from 'highlight.js';
|
|
5
5
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
@@ -18,8 +18,18 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
18
18
|
class UCodeBlock extends BaseElement {
|
|
19
19
|
constructor() {
|
|
20
20
|
super(...arguments);
|
|
21
|
+
this.isCopied = false;
|
|
21
22
|
this.headless = false;
|
|
22
|
-
this.
|
|
23
|
+
this.lang = "plaintext";
|
|
24
|
+
/**
|
|
25
|
+
* slot에 할당된 코드를 value로 설정합니다.
|
|
26
|
+
* 이 기능을 통해 HTML 내에 직접 코드를 작성할 수 있습니다.
|
|
27
|
+
*/
|
|
28
|
+
this.handleSlotChange = (e) => {
|
|
29
|
+
const slot = e.target;
|
|
30
|
+
const nodes = slot.assignedNodes({ flatten: true });
|
|
31
|
+
this.value = nodes.map((node) => node.textContent).join("\n\n");
|
|
32
|
+
};
|
|
23
33
|
}
|
|
24
34
|
static {
|
|
25
35
|
this.styles = [super.styles, styles];
|
|
@@ -30,34 +40,35 @@ class UCodeBlock extends BaseElement {
|
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
42
|
render() {
|
|
33
|
-
|
|
34
|
-
const
|
|
43
|
+
const lang = hljs.getLanguage(this.lang) ? this.lang : "plaintext";
|
|
44
|
+
const value = this.value || "";
|
|
35
45
|
return html`
|
|
36
46
|
<div class="header" ?hidden=${this.headless}>
|
|
37
|
-
<span class="
|
|
38
|
-
|
|
47
|
+
<span class="lang">
|
|
48
|
+
${lang}
|
|
49
|
+
</span>
|
|
50
|
+
<u-copy-button
|
|
51
|
+
.value=${value}
|
|
52
|
+
></u-copy-button>
|
|
39
53
|
</div>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* 코드에 구문 강조를 적용합니다.
|
|
45
|
-
* @param value 코드 문자열
|
|
46
|
-
* @param lang 코드 언어
|
|
47
|
-
* @returns 구문 강조가 적용된 HTML 문자열
|
|
48
|
-
*/
|
|
49
|
-
parse(value, lang) {
|
|
50
|
-
return hljs.highlight(value, {
|
|
54
|
+
|
|
55
|
+
<pre class="hljs">${unsafeHTML(hljs.highlight(value, {
|
|
51
56
|
language: lang
|
|
52
|
-
}).value
|
|
57
|
+
}).value)}</pre>
|
|
58
|
+
|
|
59
|
+
<slot hidden @slotchange=${this.handleSlotChange}></slot>
|
|
60
|
+
`;
|
|
53
61
|
}
|
|
54
62
|
}
|
|
63
|
+
__decorateClass([
|
|
64
|
+
state()
|
|
65
|
+
], UCodeBlock.prototype, "isCopied");
|
|
55
66
|
__decorateClass([
|
|
56
67
|
property({ type: Boolean, reflect: true })
|
|
57
68
|
], UCodeBlock.prototype, "headless");
|
|
58
69
|
__decorateClass([
|
|
59
|
-
property({ type: String })
|
|
60
|
-
], UCodeBlock.prototype, "
|
|
70
|
+
property({ type: String, reflect: true })
|
|
71
|
+
], UCodeBlock.prototype, "lang");
|
|
61
72
|
__decorateClass([
|
|
62
73
|
property({ type: String })
|
|
63
74
|
], UCodeBlock.prototype, "value");
|
|
@@ -39,10 +39,10 @@ const styles = css`
|
|
|
39
39
|
:host {
|
|
40
40
|
display: block;
|
|
41
41
|
width: 100%;
|
|
42
|
+
padding: 8px 16px;
|
|
42
43
|
border: 1px solid var(--u-border-color);
|
|
43
44
|
border-radius: 8px;
|
|
44
45
|
background-color: var(--u-neutral-100);
|
|
45
|
-
padding: 8px 16px;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
.header {
|
|
@@ -51,28 +51,29 @@ const styles = css`
|
|
|
51
51
|
flex-direction: row;
|
|
52
52
|
align-items: center;
|
|
53
53
|
justify-content: space-between;
|
|
54
|
+
margin-bottom: 12px;
|
|
55
|
+
user-select: none;
|
|
56
|
+
}
|
|
57
|
+
.header .lang {
|
|
54
58
|
font-family: Arial, Helvetica, sans-serif;
|
|
55
59
|
font-size: 12px;
|
|
56
60
|
font-weight: 300;
|
|
57
61
|
color: var(--u-txt-color-strong);
|
|
58
|
-
margin-bottom: 12px;
|
|
59
|
-
user-select: none;
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
/* highlight.js styles */
|
|
63
65
|
.hljs {
|
|
64
66
|
display: block;
|
|
65
|
-
overflow-x: auto;
|
|
66
67
|
margin: 0;
|
|
67
68
|
padding: 0;
|
|
68
69
|
color: var(--hljs-text-color);
|
|
69
|
-
font-family:
|
|
70
|
+
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
|
70
71
|
font-size: 14px;
|
|
71
72
|
line-height: 1.45;
|
|
72
73
|
white-space: pre;
|
|
74
|
+
overflow: auto;
|
|
73
75
|
scrollbar-width: thin;
|
|
74
76
|
scrollbar-color: var(--u-scrollbar-color) transparent;
|
|
75
|
-
scrollbar-gutter: stable;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
.hljs-doctag,
|
package/dist/components/{json-viewer/UJsonViewer.component.d.ts → blocks/UJsonBlock.component.d.ts}
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PropertyValues, TemplateResult } from 'lit';
|
|
2
2
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
3
|
-
import { JsonNode } from '
|
|
3
|
+
import { JsonNode } from '../../types/JsonNode.js';
|
|
4
4
|
/**
|
|
5
5
|
* json 데이터를 트리 형태로 시각화하는 컴포넌트입니다.
|
|
6
6
|
*/
|
|
7
|
-
export declare class
|
|
7
|
+
export declare class UJsonBlock extends BaseElement {
|
|
8
8
|
static styles: import('lit').CSSResultGroup[];
|
|
9
9
|
static dependencies: Record<string, typeof BaseElement>;
|
|
10
10
|
state: Record<string, boolean>;
|
|
@@ -37,8 +37,9 @@ export declare class UJsonViewer extends BaseElement {
|
|
|
37
37
|
* @param node - JsonObject 또는 JsonArray
|
|
38
38
|
*/
|
|
39
39
|
private renderPreview;
|
|
40
|
-
/** 노드 확장/축소 클릭 핸들러 */
|
|
41
|
-
private toggle;
|
|
42
40
|
/** JSON 데이터를 순회하며 각 경로의 확장 상태를 설정합니다. */
|
|
43
41
|
private setState;
|
|
42
|
+
private isValueType;
|
|
43
|
+
/** 노드 확장/축소 클릭 핸들러 */
|
|
44
|
+
private handlePropertyKeyClick;
|
|
44
45
|
}
|
package/dist/components/{json-viewer/UJsonViewer.component.js → blocks/UJsonBlock.component.js}
RENAMED
|
@@ -3,8 +3,8 @@ import { state, property } from 'lit/decorators.js';
|
|
|
3
3
|
import { map } from 'lit/directives/map.js';
|
|
4
4
|
import { when } from 'lit/directives/when.js';
|
|
5
5
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
6
|
-
import {
|
|
7
|
-
import { styles } from './
|
|
6
|
+
import { jsonAttrConverter } from '../../utilities/converters.js';
|
|
7
|
+
import { styles } from './UJsonBlock.styles.js';
|
|
8
8
|
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
10
10
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -15,12 +15,15 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
15
15
|
if (result) __defProp(target, key, result);
|
|
16
16
|
return result;
|
|
17
17
|
};
|
|
18
|
-
class
|
|
18
|
+
class UJsonBlock extends BaseElement {
|
|
19
19
|
constructor() {
|
|
20
20
|
super(...arguments);
|
|
21
21
|
this.state = {};
|
|
22
22
|
this.expanded = true;
|
|
23
23
|
this.value = {};
|
|
24
|
+
this.isValueType = (value) => {
|
|
25
|
+
return value !== Object(value);
|
|
26
|
+
};
|
|
24
27
|
}
|
|
25
28
|
static {
|
|
26
29
|
this.styles = [super.styles, styles];
|
|
@@ -51,14 +54,14 @@ class UJsonViewer extends BaseElement {
|
|
|
51
54
|
* @param parent - 부모 노드의 경로
|
|
52
55
|
*/
|
|
53
56
|
renderNode(value, parent = "") {
|
|
54
|
-
return isValueType(value) ? this.renderValue(value) : this.renderObject(value, parent);
|
|
57
|
+
return this.isValueType(value) ? this.renderValue(value) : this.renderObject(value, parent);
|
|
55
58
|
}
|
|
56
59
|
/**
|
|
57
60
|
* JsonValue를 렌더링합니다.
|
|
58
61
|
* @param node - JsonValue (string, number, boolean, null 등)
|
|
59
62
|
*/
|
|
60
63
|
renderValue(node) {
|
|
61
|
-
const type =
|
|
64
|
+
const type = node === null ? "null" : Array.isArray(node) ? "array" : typeof node === "object" ? "object" : typeof node;
|
|
62
65
|
return html`
|
|
63
66
|
<span part="${type}" class="${type}" role="treeitem">
|
|
64
67
|
${JSON.stringify(node)}
|
|
@@ -75,7 +78,7 @@ class UJsonViewer extends BaseElement {
|
|
|
75
78
|
<ul part="object" role="group">
|
|
76
79
|
${map(Object.entries(node), ([key, value]) => {
|
|
77
80
|
const path = parent ? `${parent}.${key}` : key;
|
|
78
|
-
const isValue = isValueType(value);
|
|
81
|
+
const isValue = this.isValueType(value);
|
|
79
82
|
const isExpanded = this.state[path] ?? this.expanded;
|
|
80
83
|
return html`
|
|
81
84
|
<li part="property" role="treeitem"
|
|
@@ -85,7 +88,7 @@ class UJsonViewer extends BaseElement {
|
|
|
85
88
|
class="key"
|
|
86
89
|
?collapsable="${!isValue}"
|
|
87
90
|
?collapsed="${!isValue && !isExpanded}"
|
|
88
|
-
@click=${!isValue ? () => this.
|
|
91
|
+
@click=${!isValue ? () => this.handlePropertyKeyClick(path) : null}>
|
|
89
92
|
${key}:
|
|
90
93
|
${when(!isValue && !isExpanded, () => this.renderPreview(value))}
|
|
91
94
|
</span>
|
|
@@ -107,11 +110,6 @@ class UJsonViewer extends BaseElement {
|
|
|
107
110
|
</span>
|
|
108
111
|
`;
|
|
109
112
|
}
|
|
110
|
-
/** 노드 확장/축소 클릭 핸들러 */
|
|
111
|
-
toggle(path) {
|
|
112
|
-
const isExpanded = this.state[path] ?? false;
|
|
113
|
-
this.state = { ...this.state, [path]: !isExpanded };
|
|
114
|
-
}
|
|
115
113
|
/** JSON 데이터를 순회하며 각 경로의 확장 상태를 설정합니다. */
|
|
116
114
|
setState(value, parent = "") {
|
|
117
115
|
if (typeof value !== "object" || value === null) return {};
|
|
@@ -123,15 +121,20 @@ class UJsonViewer extends BaseElement {
|
|
|
123
121
|
});
|
|
124
122
|
return state2;
|
|
125
123
|
}
|
|
124
|
+
/** 노드 확장/축소 클릭 핸들러 */
|
|
125
|
+
handlePropertyKeyClick(path) {
|
|
126
|
+
const isExpanded = this.state[path] ?? false;
|
|
127
|
+
this.state = { ...this.state, [path]: !isExpanded };
|
|
128
|
+
}
|
|
126
129
|
}
|
|
127
130
|
__decorateClass([
|
|
128
131
|
state()
|
|
129
|
-
],
|
|
132
|
+
], UJsonBlock.prototype, "state");
|
|
130
133
|
__decorateClass([
|
|
131
134
|
property({ type: Boolean })
|
|
132
|
-
],
|
|
135
|
+
], UJsonBlock.prototype, "expanded");
|
|
133
136
|
__decorateClass([
|
|
134
|
-
property({ type: Object, converter:
|
|
135
|
-
],
|
|
137
|
+
property({ type: Object, converter: jsonAttrConverter })
|
|
138
|
+
], UJsonBlock.prototype, "value");
|
|
136
139
|
|
|
137
|
-
export {
|
|
140
|
+
export { UJsonBlock };
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { nothing } from 'lit';
|
|
2
1
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
2
|
+
import { TextBlockReference } from '../../types/BlockReference';
|
|
3
3
|
/**
|
|
4
4
|
* 마크다운 컨텐츠를 렌더링하는 컴포넌트입니다.
|
|
5
|
+
*
|
|
6
|
+
* 주의:
|
|
7
|
+
* - refs로 삽입되는 커스텀 태그(u-ref-*)는 속성/내용을 모두 escape하여 XSS를 방지합니다.
|
|
8
|
+
* - 코드블록 내부는 HTML을 전부 텍스트로 취급(escape)하며, refs 태그는 통째 제거합니다.
|
|
9
|
+
* - 인덱스 기반 삽입(ref.endIndex)이 깨지지 않도록 "normalize(제로폭 제거)"를 insert 전에 1회 수행합니다.
|
|
5
10
|
*/
|
|
6
11
|
export declare class UMarkedBlock extends BaseElement {
|
|
7
12
|
static styles: import('lit').CSSResultGroup[];
|
|
@@ -9,16 +14,32 @@ export declare class UMarkedBlock extends BaseElement {
|
|
|
9
14
|
private parser;
|
|
10
15
|
/** 마크다운 컨텐츠를 렌더링할 때 사용할 값입니다. */
|
|
11
16
|
value?: string;
|
|
12
|
-
|
|
17
|
+
/** 컨텐츠의 인용 출처들입니다. */
|
|
18
|
+
refs?: TextBlockReference[];
|
|
19
|
+
render(): import('lit-html/directive.js').DirectiveResult<typeof import('lit-html/directives/unsafe-html.js').UnsafeHTMLDirective>;
|
|
13
20
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @param value
|
|
16
|
-
* @
|
|
21
|
+
* 인용/출처 참조객체가 있을때 문자열에 출처태그를 삽입합니다.
|
|
22
|
+
* @param value 삽입할 마크다운 문자열
|
|
23
|
+
* @return 삽입된 마크다운 문자열
|
|
17
24
|
*/
|
|
18
|
-
private
|
|
25
|
+
private insert;
|
|
19
26
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @param value 원본 문자열
|
|
27
|
+
* 참조 카드 엘리먼트를 안전하게 빌드합니다.
|
|
22
28
|
*/
|
|
23
|
-
private
|
|
29
|
+
private buildCard;
|
|
30
|
+
/**
|
|
31
|
+
* Zero Width Space, LTR/RTL marks, BOM 등 특수 제어 문자를 제거합니다.
|
|
32
|
+
* (ref.endIndex 기준을 흔들지 않게 insert 전에 1회 수행)
|
|
33
|
+
*/
|
|
34
|
+
private normalizeText;
|
|
35
|
+
/**
|
|
36
|
+
* 코드블록 내부 텍스트를 안전하게 처리합니다.
|
|
37
|
+
* - u-ref-tag는 통째로 제거(코드블록 안에서 UI 태그가 살아남는 것 방지)
|
|
38
|
+
* - 나머지는 전부 HTML escape
|
|
39
|
+
*/
|
|
40
|
+
private sanitizeText;
|
|
41
|
+
/**
|
|
42
|
+
* HTML 텍스트 노드로 안전하게 삽입하기 위해 escape 합니다.
|
|
43
|
+
*/
|
|
44
|
+
private escapeHTML;
|
|
24
45
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { nothing
|
|
1
|
+
import { nothing } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import { Marked } from 'marked';
|
|
5
|
-
import markedAlert from 'marked-alert';
|
|
6
|
-
import markedFootnote from 'marked-footnote';
|
|
7
5
|
import markedKatex from 'marked-katex-extension';
|
|
8
6
|
import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
|
|
7
|
+
import { UTooltip } from '@iyulab/components/dist/components/tooltip/UTooltip.component.js';
|
|
9
8
|
import { UCodeBlock } from './UCodeBlock.component.js';
|
|
9
|
+
import { URefTag } from '../references/URefTag.component.js';
|
|
10
|
+
import { URefCard } from '../references/URefCard.component.js';
|
|
11
|
+
import { URefCardGroup } from '../references/URefCardGroup.component.js';
|
|
10
12
|
import { styles } from './UMarkedBlock.styles.js';
|
|
11
13
|
|
|
12
14
|
var __defProp = Object.defineProperty;
|
|
@@ -23,58 +25,105 @@ class UMarkedBlock extends BaseElement {
|
|
|
23
25
|
super(...arguments);
|
|
24
26
|
this.parser = new Marked({
|
|
25
27
|
pedantic: false,
|
|
26
|
-
// 엄격한 마크다운 규격 준수하지 않음 (markdown.pl을 따르지 않음)
|
|
27
28
|
gfm: true,
|
|
28
|
-
// GitHub Flavored Markdown 사용
|
|
29
29
|
breaks: true,
|
|
30
|
-
// 단순 줄바꿈 또한 <br> 태그로 변환
|
|
31
30
|
silent: true,
|
|
32
|
-
// 파싱 오류 발생 시 예외를 발생시키지 않고 메시지를 출력
|
|
33
31
|
renderer: {
|
|
34
32
|
code: ({ text, lang }) => {
|
|
35
33
|
lang ||= "plaintext";
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
const safeLang = this.escapeHTML(lang);
|
|
35
|
+
const safeText = this.sanitizeText(text);
|
|
36
|
+
return `<u-code-block lang="${safeLang}">${safeText}</u-code-block>`;
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
|
-
}).use(
|
|
39
|
+
}).use(markedKatex({ output: "mathml" }));
|
|
41
40
|
}
|
|
42
41
|
static {
|
|
43
42
|
this.styles = [super.styles, styles];
|
|
44
43
|
}
|
|
45
44
|
static {
|
|
46
45
|
this.dependencies = {
|
|
47
|
-
"u-
|
|
46
|
+
"u-tooltip": UTooltip,
|
|
47
|
+
"u-code-block": UCodeBlock,
|
|
48
|
+
"u-ref-tag": URefTag,
|
|
49
|
+
"u-ref-card": URefCard,
|
|
50
|
+
"u-ref-card-group": URefCardGroup
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
53
|
render() {
|
|
51
54
|
if (!this.value) return nothing;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
let value = this.normalizeText(this.value);
|
|
56
|
+
if (this.refs && this.refs.length > 0) {
|
|
57
|
+
value = this.insert(value, this.refs);
|
|
58
|
+
}
|
|
59
|
+
const html = this.parser.parse(value, { async: false });
|
|
60
|
+
return unsafeHTML(html);
|
|
57
61
|
}
|
|
58
62
|
/**
|
|
59
|
-
*
|
|
60
|
-
* @param value
|
|
61
|
-
* @
|
|
63
|
+
* 인용/출처 참조객체가 있을때 문자열에 출처태그를 삽입합니다.
|
|
64
|
+
* @param value 삽입할 마크다운 문자열
|
|
65
|
+
* @return 삽입된 마크다운 문자열
|
|
62
66
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
insert(value, refs) {
|
|
68
|
+
const reversed = [...refs].sort((a, b) => b.endIndex - a.endIndex);
|
|
69
|
+
reversed.forEach((ref) => {
|
|
70
|
+
const sources = ref.sources ?? [];
|
|
71
|
+
const firstSource = sources.at(0);
|
|
72
|
+
const tagName = this.escapeHTML(ref.name ?? "");
|
|
73
|
+
const tagLink = this.escapeHTML(firstSource?.url ?? "#");
|
|
74
|
+
let tooltip = "";
|
|
75
|
+
if (firstSource && sources.length === 1) {
|
|
76
|
+
tooltip = this.buildCard(firstSource, true);
|
|
77
|
+
}
|
|
78
|
+
if (sources.length > 1) {
|
|
79
|
+
const cards = sources.map((s) => this.buildCard(s, false)).join("");
|
|
80
|
+
tooltip = `<u-ref-card-group slot="tooltip">${cards}</u-ref-card-group>`;
|
|
81
|
+
}
|
|
82
|
+
const tag = `<u-ref-tag href="${tagLink}" title="${tagName}">${tagName}${tooltip}</u-ref-tag>`;
|
|
83
|
+
value = value.slice(0, ref.endIndex) + tag + value.slice(ref.endIndex);
|
|
84
|
+
});
|
|
66
85
|
return value;
|
|
67
86
|
}
|
|
68
87
|
/**
|
|
69
|
-
*
|
|
70
|
-
|
|
88
|
+
* 참조 카드 엘리먼트를 안전하게 빌드합니다.
|
|
89
|
+
*/
|
|
90
|
+
buildCard(source, slot) {
|
|
91
|
+
const type = this.escapeHTML(source.type ?? "");
|
|
92
|
+
const href = this.escapeHTML(source.url ?? "#");
|
|
93
|
+
const heading = this.escapeHTML(source.title ?? "");
|
|
94
|
+
const tags = this.escapeHTML((source.tags ?? []).join(","));
|
|
95
|
+
const snippet = this.escapeHTML(source.snippet ?? "");
|
|
96
|
+
const slotAttr = slot ? ` slot="tooltip"` : "";
|
|
97
|
+
return `<u-ref-card${slotAttr} type="${type}" href="${href}" heading="${heading}" tags="${tags}">${snippet}</u-ref-card>`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Zero Width Space, LTR/RTL marks, BOM 등 특수 제어 문자를 제거합니다.
|
|
101
|
+
* (ref.endIndex 기준을 흔들지 않게 insert 전에 1회 수행)
|
|
102
|
+
*/
|
|
103
|
+
normalizeText(value) {
|
|
104
|
+
return value.replace(/\u200B|\u200C|\u200D|\u200E|\u200F|\uFEFF/g, "");
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 코드블록 내부 텍스트를 안전하게 처리합니다.
|
|
108
|
+
* - u-ref-tag는 통째로 제거(코드블록 안에서 UI 태그가 살아남는 것 방지)
|
|
109
|
+
* - 나머지는 전부 HTML escape
|
|
110
|
+
*/
|
|
111
|
+
sanitizeText(value) {
|
|
112
|
+
value = value.replace(/<u-ref-tag\b[^>]*>[\s\S]*?<\/u-ref-tag>/gi, "");
|
|
113
|
+
return this.escapeHTML(value);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* HTML 텍스트 노드로 안전하게 삽입하기 위해 escape 합니다.
|
|
71
117
|
*/
|
|
72
|
-
|
|
73
|
-
return value.replace(/&/g, "&").replace(
|
|
118
|
+
escapeHTML(value) {
|
|
119
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
74
120
|
}
|
|
75
121
|
}
|
|
76
122
|
__decorateClass([
|
|
77
123
|
property({ type: String })
|
|
78
124
|
], UMarkedBlock.prototype, "value");
|
|
125
|
+
__decorateClass([
|
|
126
|
+
property({ type: Array })
|
|
127
|
+
], UMarkedBlock.prototype, "refs");
|
|
79
128
|
|
|
80
129
|
export { UMarkedBlock };
|