@iyulab/chat-components 0.11.9 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +16 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/components/blocks/UCodeBlock.js +2 -2
- package/dist/components/blocks/UElementBlock.js +2 -2
- package/dist/components/blocks/UFileBlock.d.ts +2 -0
- package/dist/components/blocks/UFileBlock.js +21 -18
- package/dist/components/blocks/UFileBlock.styles.js +24 -4
- package/dist/components/blocks/UMarkedBlock.js +3 -3
- package/dist/components/blocks/URefBlock.js +2 -2
- package/dist/components/blocks/UTableBlock.js +13 -9
- package/dist/components/blocks/UTableBlock.styles.js +30 -3
- package/dist/components/blocks/UTextBlock.js +2 -2
- package/dist/components/message/UMessage.js +2 -2
- package/dist/components/prompt/UPrompt.js +2 -2
- package/dist/components/references/URefCard.js +2 -2
- package/dist/components/references/URefCardGroup.js +2 -2
- package/dist/components/references/URefCardGroup.styles.js +5 -0
- package/dist/components/references/URefTag.js +2 -2
- package/dist/components-extra/UChartBlock.js +2 -2
- package/dist/components-extra/UChartBlock.styles.js +15 -1
- package/dist/components-extra/UImagesBlock.js +9 -6
- package/dist/components-extra/UImagesBlock.styles.js +13 -0
- package/dist/components-extra/UMapBlock.js +2 -2
- package/dist/components-extra/UMapBlock.styles.js +11 -1
- package/dist/components-extra/UVideoBlock.js +2 -2
- package/dist/node_modules/katex/dist/katex.js +26367 -0
- package/dist/utilities/markedKatex.d.ts +10 -0
- package/dist/utilities/markedKatex.js +106 -0
- package/dist/utilities/messages.d.ts +1 -1
- package/dist/utilities/messages.js +6 -2
- package/package.json +10 -11
- package/skills/iyulab-chat-components/references/components/chart-block.md +17 -0
- package/skills/iyulab-chat-components/references/components/code-block.md +12 -0
- package/skills/iyulab-chat-components/references/components/images-block.md +10 -0
- package/skills/iyulab-chat-components/references/components/map-block.md +15 -0
- package/skills/iyulab-chat-components/references/components/marked-block.md +8 -0
- package/skills/iyulab-chat-components/references/components/message.md +8 -0
- package/skills/iyulab-chat-components/references/components/prompt.md +11 -0
- package/skills/iyulab-chat-components/references/components/table-block.md +15 -0
- package/skills/iyulab-chat-components/references/components/video-block.md +10 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KatexOptions } from 'katex';
|
|
2
|
+
import { MarkedExtension } from 'marked';
|
|
3
|
+
/** `marked` 확장이 받는 옵션 — `displayMode` 는 구분자가 정하므로 소비자가 줄 수 없다. */
|
|
4
|
+
export type MarkedKatexOptions = Omit<KatexOptions, "displayMode">;
|
|
5
|
+
/**
|
|
6
|
+
* `marked.use()` 에 넘길 수식 확장을 만든다.
|
|
7
|
+
*
|
|
8
|
+
* @param options KaTeX 렌더 옵션(`displayMode` 제외 — 구분자가 정한다).
|
|
9
|
+
*/
|
|
10
|
+
export declare function markedKatex(options?: MarkedKatexOptions): MarkedExtension;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import katex from "../node_modules/katex/dist/katex.js";
|
|
2
|
+
//#region src/utilities/markedKatex.ts
|
|
3
|
+
/**
|
|
4
|
+
* `marked` 에 TeX 수식 렌더를 붙이는 확장.
|
|
5
|
+
*
|
|
6
|
+
* 알고리즘(구분자 규칙과 토크나이저 구성)은 `marked-katex-extension`(MIT, © 2021 @markedjs)에서
|
|
7
|
+
* 왔고, 타입·옵션 표면은 이 패키지의 필요에 맞춰 다시 썼다.
|
|
8
|
+
*
|
|
9
|
+
* ## 두 가지 «모드»가 있고, 서로 다른 축이다
|
|
10
|
+
*
|
|
11
|
+
* - **`displayMode`** — KaTeX 에게 *"큰 조판으로 그려라"* 라고 말하는 것(`$$…$$`).
|
|
12
|
+
* - **블록 배치** — 수식이 문단 «밖»에 서는 것. `$$` 가 **자기 줄에 혼자** 있을 때만 일어난다.
|
|
13
|
+
*
|
|
14
|
+
* ⚠**둘은 함께 가지 않는다**: 한 줄 안의 `$$x$$` 는 `displayMode` 이면서 문단 «안»에 남는다.
|
|
15
|
+
* 두 축을 하나로 합치면 기존 문서의 조판이 바뀐다.
|
|
16
|
+
*
|
|
17
|
+
* ## 구분자 규칙
|
|
18
|
+
*
|
|
19
|
+
* - 인라인 `$…$` / `$$…$$` — 여는 구분자 뒤에 `$` 가 바로 오지 않아야 하고(빈 수식 방지),
|
|
20
|
+
* 내용은 **줄을 넘지 못하며**, 닫는 구분자 뒤에는 공백·구두점·문장 끝이 와야 한다.
|
|
21
|
+
* - 블록 `$$\n…\n$$` — 여는·닫는 `$$` 가 각각 자기 줄에 있을 때.
|
|
22
|
+
*
|
|
23
|
+
* 🔴**«수식이 아닌 것을 수식으로 만들지 않는 것»이 이 규칙의 목적이다.** 가장 흔한 오탐
|
|
24
|
+
* 경로는 통화 표기 둘(`from $5 to $10`)이고, 그것을 막는 것이 ⑴내용에서 개행을 배제하고
|
|
25
|
+
* ⑵닫는 구분자 뒤 문맥을 요구하는 두 조건이다. 규칙을 느슨하게 하면 본문이 통째로 한
|
|
26
|
+
* 수식으로 삼켜진다.
|
|
27
|
+
*/
|
|
28
|
+
/** 여는 구분자 뒤에 `$` 가 오지 않고, 내용이 줄을 넘지 않으며, 닫는 뒤가 공백·구두점·끝. */
|
|
29
|
+
var INLINE_RULE = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\1(?=[\s?!.,:?!。,:]|$)/;
|
|
30
|
+
/** `$$` 가 각각 자기 줄에 있는 형태. */
|
|
31
|
+
var BLOCK_RULE = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;
|
|
32
|
+
function render(options, token, newlineAfter) {
|
|
33
|
+
const html = katex.renderToString(token.text, {
|
|
34
|
+
...options,
|
|
35
|
+
displayMode: token.displayMode
|
|
36
|
+
});
|
|
37
|
+
return newlineAfter ? `${html}\n` : html;
|
|
38
|
+
}
|
|
39
|
+
function inlineKatex(options) {
|
|
40
|
+
return {
|
|
41
|
+
name: "inlineKatex",
|
|
42
|
+
level: "inline",
|
|
43
|
+
/**
|
|
44
|
+
* `marked` 가 «인라인 텍스트를 어디서 끊을지» 고르는 힌트.
|
|
45
|
+
*
|
|
46
|
+
* ⚠**이것은 규칙이 아니라 힌트다** — 여기서 걸러도 토크나이저는 그 뒤 위치에서 다시
|
|
47
|
+
* 호출되므로, 여는 `$` 앞에 공백이 없는 `a$x$` 도 결국 파싱된다. 문서의 조판을 바꾸지
|
|
48
|
+
* 않으려면 이 성질을 그대로 두어야 한다.
|
|
49
|
+
*/
|
|
50
|
+
start(src) {
|
|
51
|
+
let indexSrc = src;
|
|
52
|
+
let consumed = 0;
|
|
53
|
+
while (indexSrc) {
|
|
54
|
+
const index = indexSrc.indexOf("$");
|
|
55
|
+
if (index === -1) return;
|
|
56
|
+
if ((index === 0 || indexSrc.charAt(index - 1) === " ") && INLINE_RULE.test(indexSrc.substring(index))) return consumed + index;
|
|
57
|
+
const skipped = indexSrc.substring(index + 1);
|
|
58
|
+
const trimmed = skipped.replace(/^\$+/, "");
|
|
59
|
+
consumed += index + 1 + (skipped.length - trimmed.length);
|
|
60
|
+
indexSrc = trimmed;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
tokenizer(src) {
|
|
64
|
+
const match = src.match(INLINE_RULE);
|
|
65
|
+
if (!match) return void 0;
|
|
66
|
+
return {
|
|
67
|
+
type: "inlineKatex",
|
|
68
|
+
raw: match[0],
|
|
69
|
+
text: match[2].trim(),
|
|
70
|
+
displayMode: match[1].length === 2
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
renderer(token) {
|
|
74
|
+
return render(options, token, false);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function blockKatex(options) {
|
|
79
|
+
return {
|
|
80
|
+
name: "blockKatex",
|
|
81
|
+
level: "block",
|
|
82
|
+
tokenizer(src) {
|
|
83
|
+
const match = src.match(BLOCK_RULE);
|
|
84
|
+
if (!match) return void 0;
|
|
85
|
+
return {
|
|
86
|
+
type: "blockKatex",
|
|
87
|
+
raw: match[0],
|
|
88
|
+
text: match[2].trim(),
|
|
89
|
+
displayMode: match[1].length === 2
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
renderer(token) {
|
|
93
|
+
return render(options, token, true);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* `marked.use()` 에 넘길 수식 확장을 만든다.
|
|
99
|
+
*
|
|
100
|
+
* @param options KaTeX 렌더 옵션(`displayMode` 제외 — 구분자가 정한다).
|
|
101
|
+
*/
|
|
102
|
+
function markedKatex(options = {}) {
|
|
103
|
+
return { extensions: [inlineKatex(options), blockKatex(options)] };
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { markedKatex };
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* 이 리포가 채택한 표준이 *"영어 기본 **+ 레지스트리**"* 이기 때문이다 — 영어 리터럴만으로는
|
|
6
6
|
* 한국어 앱이 그 문구를 되돌릴 방법이 없다. 다음 문자열은 여기로 온다.
|
|
7
7
|
*/
|
|
8
|
-
export type ChatMessageKey = 'canvasUnavailable' | 'previousReference' | 'nextReference' | 'closePreview' | 'closeLightbox' | 'previousImage' | 'nextImage' | 'sendMessage' | 'stopGenerating' | 'fullScreen' | 'remove' | 'pngDownload' | 'jsonDownload' | 'search' | 'rowCount' | 'excelDownload' | 'csvDownload';
|
|
8
|
+
export type ChatMessageKey = 'canvasUnavailable' | 'previousReference' | 'nextReference' | 'closePreview' | 'closeLightbox' | 'previousImage' | 'nextImage' | 'sendMessage' | 'stopGenerating' | 'fullScreen' | 'remove' | 'pngDownload' | 'jsonDownload' | 'search' | 'rowCount' | 'excelDownload' | 'csvDownload' | 'openImage' | 'previewFile';
|
|
9
9
|
export declare const messages: import('@iyulab/components/dist/utilities/Locale.js').LocaleNamespace<ChatMessageKey>;
|
|
@@ -18,7 +18,9 @@ messages.register("en", {
|
|
|
18
18
|
search: "Search...",
|
|
19
19
|
rowCount: "{shown} / {total} Rows",
|
|
20
20
|
excelDownload: "Excel Download",
|
|
21
|
-
csvDownload: "CSV Download"
|
|
21
|
+
csvDownload: "CSV Download",
|
|
22
|
+
openImage: "Open image {index}",
|
|
23
|
+
previewFile: "Preview {name}"
|
|
22
24
|
});
|
|
23
25
|
messages.register("ko", {
|
|
24
26
|
canvasUnavailable: "Canvas 2D context를 가져올 수 없습니다.",
|
|
@@ -37,7 +39,9 @@ messages.register("ko", {
|
|
|
37
39
|
search: "검색...",
|
|
38
40
|
rowCount: "{shown} / {total} 행",
|
|
39
41
|
excelDownload: "Excel 다운로드",
|
|
40
|
-
csvDownload: "CSV 다운로드"
|
|
42
|
+
csvDownload: "CSV 다운로드",
|
|
43
|
+
openImage: "이미지 {index} 열기",
|
|
44
|
+
previewFile: "{name} 미리보기"
|
|
41
45
|
});
|
|
42
46
|
//#endregion
|
|
43
47
|
export { messages };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/chat-components",
|
|
3
3
|
"description": "llm chat components for building chat interfaces",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.1",
|
|
5
5
|
"author": "iyulab",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -61,14 +61,13 @@
|
|
|
61
61
|
"typecheck": "tsc --noEmit"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@iyulab/components": "^1.23.0",
|
|
65
64
|
"highlight.js": "^11.11.1",
|
|
66
|
-
"katex": "^0.
|
|
65
|
+
"katex": "^0.18.7",
|
|
67
66
|
"lit": "^3.3.3",
|
|
68
|
-
"marked": "^18.0.6"
|
|
69
|
-
"marked-katex-extension": "5.1.10"
|
|
67
|
+
"marked": "^18.0.6"
|
|
70
68
|
},
|
|
71
69
|
"peerDependencies": {
|
|
70
|
+
"@iyulab/components": ">=1.23.0",
|
|
72
71
|
"@lit/react": ">=1.0.8",
|
|
73
72
|
"chart.js": ">=4.5.1",
|
|
74
73
|
"react": ">=18.0.0"
|
|
@@ -85,19 +84,19 @@
|
|
|
85
84
|
}
|
|
86
85
|
},
|
|
87
86
|
"devDependencies": {
|
|
88
|
-
"@eslint/js": "^
|
|
87
|
+
"@eslint/js": "^10.0.1",
|
|
89
88
|
"@types/node": "^26.1.1",
|
|
90
|
-
"@vitest/browser-playwright": "^
|
|
89
|
+
"@vitest/browser-playwright": "^5.0.0",
|
|
91
90
|
"chart.js": "^4.5.1",
|
|
92
|
-
"eslint": "^
|
|
91
|
+
"eslint": "^10.1.0",
|
|
93
92
|
"eslint-plugin-lit": "^2.3.1",
|
|
94
93
|
"glob": "^13.0.6",
|
|
95
94
|
"globals": "^17.7.0",
|
|
96
|
-
"openai": "^
|
|
97
|
-
"typescript": "^
|
|
95
|
+
"openai": "^7.15.0",
|
|
96
|
+
"typescript": "^6.0.2",
|
|
98
97
|
"typescript-eslint": "^8.64.0",
|
|
99
98
|
"vite": "^8.1.4",
|
|
100
99
|
"vite-plugin-dts": "^5.0.3",
|
|
101
|
-
"vitest": "^
|
|
100
|
+
"vitest": "^5.0.0"
|
|
102
101
|
}
|
|
103
102
|
}
|
|
@@ -48,6 +48,23 @@ LLM output example (`block-json` code fence, rendered via `u-element-block`):
|
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
51
|
+
## Sizing
|
|
52
|
+
|
|
53
|
+
Content-sized by default: the toolbar plus the chart area. Measured at 600px wide with a small
|
|
54
|
+
bar chart, that is ~368px.
|
|
55
|
+
|
|
56
|
+
**A `max-height` (or `height`) on the host wins.** The toolbar keeps its height and the chart area
|
|
57
|
+
takes the rest, so nothing is clipped away:
|
|
58
|
+
|
|
59
|
+
```css
|
|
60
|
+
u-chart-block { max-height: 200px; }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Before this was fixed, the chart area kept its own height regardless — against a 120px host, 248px
|
|
64
|
+
of it was clipped by the block's `overflow: hidden` with no scrollbar left to reach it.
|
|
65
|
+
|
|
66
|
+
There is no size property or custom property for this — the host is the lever.
|
|
67
|
+
|
|
51
68
|
## Properties
|
|
52
69
|
|
|
53
70
|
| Property | Type | Default | Description |
|
|
@@ -23,6 +23,18 @@ Syntax-highlighted code block powered by Highlight.js. Shows a language label an
|
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
|
+
## Sizing
|
|
27
|
+
|
|
28
|
+
**There is no vertical cap.** Long code grows to its content rather than folding — measured: 200
|
|
29
|
+
lines render about 4,100px tall, with no vertical scrollbar of its own. Only long *lines* scroll,
|
|
30
|
+
horizontally, inside the code area.
|
|
31
|
+
|
|
32
|
+
That is deliberate, and it differs from [`u-table-block`](table-block.md), which caps at 480px:
|
|
33
|
+
folded code cannot be read, and the conversation the block sits in already scrolls.
|
|
34
|
+
|
|
35
|
+
Fenced code inside [`u-marked-block`](marked-block.md) renders as a nested `u-code-block`, so it
|
|
36
|
+
follows this same contract.
|
|
37
|
+
|
|
26
38
|
## Properties
|
|
27
39
|
|
|
28
40
|
| Property | Type | Default | Reflect | Description |
|
|
@@ -38,6 +38,16 @@ LLM output example (`block-json` code fence):
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
+
## Sizing
|
|
42
|
+
|
|
43
|
+
Height comes from width: each slide is `4 / 3`, so the block is as tall as its column is wide.
|
|
44
|
+
Measured at 600px wide, that is ~222px.
|
|
45
|
+
|
|
46
|
+
⚠**A `max-height` on the host does *not* shrink the images, and that is deliberate.** Squeezing them
|
|
47
|
+
vertically would break the aspect ratio and distort the picture, so the block overflows **visibly**
|
|
48
|
+
instead — it never clips, and nothing becomes unreachable. To make it shorter, give it a narrower
|
|
49
|
+
column rather than a shorter host.
|
|
50
|
+
|
|
41
51
|
## Properties
|
|
42
52
|
|
|
43
53
|
| Property | Type | Default | Description |
|
|
@@ -41,6 +41,21 @@ LLM output example (`block-json` code fence, rendered via `u-element-block`):
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
+
## Sizing
|
|
45
|
+
|
|
46
|
+
The map is **300px tall when nothing constrains it** — that is a default, not a fixed height.
|
|
47
|
+
|
|
48
|
+
**A `max-height` (or `height`) on the host wins**, and the map frame shrinks to fit it:
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
u-map-block { max-height: 200px; }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Before this was fixed, the frame stayed at 300px regardless — against a 120px host, 180px of the map
|
|
55
|
+
was clipped by the block's `overflow: hidden` with no scrollbar left to reach it.
|
|
56
|
+
|
|
57
|
+
There is no size property or custom property for this — the host is the lever.
|
|
58
|
+
|
|
44
59
|
## Properties
|
|
45
60
|
|
|
46
61
|
| Property | Type | Default | Description |
|
|
@@ -35,6 +35,14 @@ Tracks a `streaming` state internally (resets a 1500ms idle timer on every `valu
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
+
## Sizing
|
|
39
|
+
|
|
40
|
+
The block grows with its content — there is no cap, and the conversation around it does the
|
|
41
|
+
scrolling.
|
|
42
|
+
|
|
43
|
+
**Fenced code becomes a nested [`u-code-block`](code-block.md)**, not a plain `<pre>`, so fenced
|
|
44
|
+
code follows that component's contract (no vertical cap; long lines scroll horizontally).
|
|
45
|
+
|
|
38
46
|
## Properties
|
|
39
47
|
|
|
40
48
|
| Property | Type | Default | Description |
|
|
@@ -36,6 +36,14 @@ Chat message wrapper component. Arranges content blocks via slots, shows a loadi
|
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
+
## Sizing
|
|
40
|
+
|
|
41
|
+
Content-sized: the bubble is as tall as what you put in it.
|
|
42
|
+
|
|
43
|
+
⚠**A `max-height` on the host does *not* fold the content, and that is deliberate.** A message that
|
|
44
|
+
hides part of itself cannot be read, and the conversation stream around it already scrolls. The
|
|
45
|
+
block overflows **visibly** rather than clipping. Constrain the stream, not the message.
|
|
46
|
+
|
|
39
47
|
## Slots
|
|
40
48
|
|
|
41
49
|
| Name | Description |
|
|
@@ -47,6 +47,17 @@ prompt.submit();
|
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
+
## Sizing
|
|
51
|
+
|
|
52
|
+
The prompt does not grow with its value. `minRows`/`maxRows` bound the inner `u-text-block`, and the
|
|
53
|
+
text scrolls **inside** that box — so the component stays short no matter how long the value is.
|
|
54
|
+
Measured at 600px wide with a 40-line value and `maxRows: 40`, the whole block is 72px tall.
|
|
55
|
+
|
|
56
|
+
⚠**Its behaviour under a host `max-height` is therefore untested.** A 200px or 120px constraint never
|
|
57
|
+
engages, because the natural height is already below both. That is not the same as "it behaves
|
|
58
|
+
correctly under a constraint" — it means the question has not been answered. Use `minRows`/`maxRows`
|
|
59
|
+
to size this component.
|
|
60
|
+
|
|
50
61
|
## Slots
|
|
51
62
|
|
|
52
63
|
| Name | Description |
|
|
@@ -37,6 +37,21 @@ Extends `UDataElement`, so data can also be injected via a `<script type="applic
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
+
## Sizing
|
|
41
|
+
|
|
42
|
+
The table area caps at **480px** and scrolls inside that cap; below it the block is content-sized.
|
|
43
|
+
Measured at 600px wide: 40 rows give a 480px table area with ~1,000px to scroll, 2 rows give ~108px
|
|
44
|
+
and no scrollbar. That default keeps a long table from swallowing the conversation.
|
|
45
|
+
|
|
46
|
+
**A `max-height` (or `height`) on the host wins.** The table area shrinks to fit it and still
|
|
47
|
+
scrolls, so no rows become unreachable:
|
|
48
|
+
|
|
49
|
+
```css
|
|
50
|
+
u-table-block { max-height: 200px; }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
There is no size property or custom property for this — the host is the lever.
|
|
54
|
+
|
|
40
55
|
## Properties
|
|
41
56
|
|
|
42
57
|
| Property | Type | Default | Description |
|
|
@@ -38,6 +38,16 @@ LLM output example (`block-json` code fence, rendered via `u-element-block`):
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
+
## Sizing
|
|
42
|
+
|
|
43
|
+
Height comes from width through `ratio` (`16:9` by default), capped at `max-width: 800px`. Measured
|
|
44
|
+
at 600px wide, a 16:9 video is ~342px tall. This holds for both branches — the embed iframe
|
|
45
|
+
(YouTube/Vimeo) and the native `<video>` element.
|
|
46
|
+
|
|
47
|
+
⚠**A `max-height` on the host does *not* shrink the video, and that is deliberate** — the same
|
|
48
|
+
reason as the image block: vertical squeezing would break the aspect ratio. The block overflows
|
|
49
|
+
**visibly** rather than clipping. Use `ratio`, or a narrower column, to change its height.
|
|
50
|
+
|
|
41
51
|
## Properties
|
|
42
52
|
|
|
43
53
|
| Property | Type | Default | Description |
|