@iyulab/chat-components 0.14.1 → 0.16.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 +35 -0
- package/README.md +3 -0
- package/dist/components/references/URefCard.js +2 -0
- package/dist/components/references/URefCard.styles.js +12 -0
- package/dist/components/references/URefTag.js +2 -0
- package/dist/components/references/URefTag.styles.js +12 -0
- package/dist/components-extra/UChartBlock.d.ts +5 -2
- package/dist/components-extra/UChartBlock.js +119 -20
- package/dist/components-extra/UMapBlock.js +2 -0
- package/dist/components-extra/UMapBlock.styles.js +12 -0
- package/dist/components-extra/UVideoBlock.d.ts +14 -0
- package/dist/components-extra/UVideoBlock.js +10 -1
- package/dist/components-extra/UVideoBlock.schema.js +38 -0
- package/dist/utilities/messages.d.ts +1 -1
- package/dist/utilities/messages.js +4 -2
- package/package.json +4 -4
- package/skills/iyulab-chat-components/references/components/chart-block.md +18 -0
- package/skills/iyulab-chat-components/references/components/video-block.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.16.0] - 2026-09-30
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`u-video-block` takes subtitle / caption tracks** — `tracks: VideoTrack[]`
|
|
8
|
+
(`{ src, kind?, srclang?, label?, default? }`, WebVTT) for a direct video file. The `<video>` is
|
|
9
|
+
drawn inside the shadow tree, so an app had no way to add a `<track>`. Also in the block schema, so
|
|
10
|
+
block JSON can carry them. YouTube and Vimeo keep their own player's captions.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Links that open a new tab now say so to screen readers.** `u-ref-tag`, `u-ref-card` and the
|
|
15
|
+
`u-map-block` caption open in a new tab; their accessible name now ends with a localized
|
|
16
|
+
"(opens in a new tab)" (`opensInNewTab` in the message registry). The text is visually hidden —
|
|
17
|
+
the external-link icon already shows it on screen.
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- README: the Accessibility section links the KWCAG 2.2 table in `@iyulab/components`.
|
|
22
|
+
|
|
23
|
+
## [0.15.0] - 2026-09-30
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`u-chart-block` no longer changes Chart.js global defaults.** Its theme colors (text, ticks,
|
|
28
|
+
grid, tooltip) used to be written to `Chart.defaults`, which also recolored any other Chart.js chart
|
|
29
|
+
on the page. They are now options of that chart instance, merged under the `options` you pass —
|
|
30
|
+
your values win, down to a single key.
|
|
31
|
+
- **`u-chart-block` uses the design-token chart palette.** Datasets that set no `backgroundColor` or
|
|
32
|
+
`borderColor` take `--u-chart-color-1..N` (one color per slice for `pie`, `doughnut`, and
|
|
33
|
+
`polarArea`), matching dashboards and `@iyulab/u-widgets`. Colors you set are kept, and the `data`
|
|
34
|
+
object you pass is not modified. Without the token sheet, Chart.js defaults apply as before.
|
|
35
|
+
- **Peer ranges promise only tested majors:** `chart.js` is `^4.5.1` (was `>=4.5.1`), `@lit/react`
|
|
36
|
+
`^1.0.8` (was `>=1.0.8`), and `react` `^18.0.0 || ^19.0.0` (was `>=18.0.0`).
|
|
37
|
+
|
|
3
38
|
## [0.14.1] - 2026-09-30
|
|
4
39
|
|
|
5
40
|
### Fixed
|
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ conformance claim for the success criteria it does not list.
|
|
|
121
121
|
|---|---|---|
|
|
122
122
|
| SC 2.5.8 Target Size (Minimum) | Every pointer target inside the registered blocks (`.` and `./extra` entries) is at least 24×24 CSS px or meets the spacing exception (24px between centers), and is actually hit at that position | `tests/browser/target-size.browser.test.ts` (real Chromium) |
|
|
123
123
|
| SC 2.1.1 Keyboard (pointer-cursor check) | Nothing a block renders shows a pointer cursor without being an interactive element — table sort headers, image thumbnails and previewable file cards are buttons | `tests/browser/target-size.browser.test.ts` · `tests/browser/table-block-sort-keyboard.browser.test.ts` |
|
|
124
|
+
| SC 3.2.5 Change on Request (new tabs) | Links that open a new tab — `u-ref-tag`, `u-ref-card`, the `u-map-block` caption — end their accessible name with a localized "(opens in a new tab)" | `tests/browser/new-tab-link-name.browser.test.ts` |
|
|
124
125
|
|
|
125
126
|
`u-ref-tag` uses the SC's **inline exception** — it is a citation badge set inside a sentence, where
|
|
126
127
|
growing it to 24px would push the line height. It is still measured and reported.
|
|
@@ -128,6 +129,8 @@ growing it to 24px would push the line height. It is still measured and reported
|
|
|
128
129
|
Color contrast comes from the `@iyulab/components` tokens this package renders with — see that
|
|
129
130
|
package's Accessibility section.
|
|
130
131
|
|
|
132
|
+
For **KWCAG 2.2** (the Korean web accessibility standard), the `@iyulab/components` README has a table of all 33 check items — which are guaranteed by a test across the sibling packages, which are shared with the app, and which do not apply: [KWCAG 2.2 대응표](https://github.com/iyulab/node-components#kwcag-22-대응표).
|
|
133
|
+
|
|
131
134
|
## Documentation
|
|
132
135
|
|
|
133
136
|
| File | Description |
|
|
@@ -3,6 +3,7 @@ import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.151.0/hel
|
|
|
3
3
|
import __decorate from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.js";
|
|
4
4
|
import { sanitizeHref } from "../../utilities/sanitizers.js";
|
|
5
5
|
import { UDataElement } from "../UDataElement.js";
|
|
6
|
+
import { messages } from "../../utilities/messages.js";
|
|
6
7
|
import { styles } from "./URefCard.styles.js";
|
|
7
8
|
import { html, nothing } from "lit";
|
|
8
9
|
import { customElement, property } from "lit/decorators.js";
|
|
@@ -64,6 +65,7 @@ var URefCard = class URefCard extends UDataElement {
|
|
|
64
65
|
<div class="footer" ?hidden=${!this.tags || this.tags.length === 0}>
|
|
65
66
|
${this.tags?.map((tag) => html`<span class="tag">${tag}</span>`)}
|
|
66
67
|
</div>
|
|
68
|
+
<span class="new-tab-hint">${messages.text("opensInNewTab")}</span>
|
|
67
69
|
</a>
|
|
68
70
|
`;
|
|
69
71
|
}
|
|
@@ -98,6 +98,18 @@ var styles = css`
|
|
|
98
98
|
border-radius: 4px;
|
|
99
99
|
white-space: nowrap;
|
|
100
100
|
}
|
|
101
|
+
/* 새 창 알림 — 화면에는 없고 접근성 이름에만 붙는다(KWCAG 7.2.1). */
|
|
102
|
+
.new-tab-hint {
|
|
103
|
+
position: absolute;
|
|
104
|
+
width: 1px;
|
|
105
|
+
height: 1px;
|
|
106
|
+
margin: -1px;
|
|
107
|
+
padding: 0;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
clip-path: inset(50%);
|
|
110
|
+
white-space: nowrap;
|
|
111
|
+
border: 0;
|
|
112
|
+
}
|
|
101
113
|
`;
|
|
102
114
|
//#endregion
|
|
103
115
|
export { styles };
|
|
@@ -2,6 +2,7 @@ import "../../utilities/icons.js";
|
|
|
2
2
|
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
|
|
3
3
|
import __decorate from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.js";
|
|
4
4
|
import { sanitizeHref } from "../../utilities/sanitizers.js";
|
|
5
|
+
import { messages } from "../../utilities/messages.js";
|
|
5
6
|
import { styles } from "./URefTag.styles.js";
|
|
6
7
|
import { html } from "lit";
|
|
7
8
|
import { customElement, property } from "lit/decorators.js";
|
|
@@ -19,6 +20,7 @@ var URefTag = class URefTag extends UElement {
|
|
|
19
20
|
<a href="${ifDefined(this.href ? sanitizeHref(this.href) : void 0)}" target="_blank" rel="noopener noreferrer"
|
|
20
21
|
@click=${this.handleAnchorClick}>
|
|
21
22
|
<slot></slot>
|
|
23
|
+
<span class="new-tab-hint">${messages.text("opensInNewTab")}</span>
|
|
22
24
|
</a>
|
|
23
25
|
|
|
24
26
|
<u-icon lib="internal-chat" name="external-link"></u-icon>
|
|
@@ -46,6 +46,18 @@ var styles = css`
|
|
|
46
46
|
u-tooltip[visible] {
|
|
47
47
|
opacity: 1;
|
|
48
48
|
}
|
|
49
|
+
/* 새 창 알림 — 화면에는 없고 접근성 이름에만 붙는다(KWCAG 7.2.1). */
|
|
50
|
+
.new-tab-hint {
|
|
51
|
+
position: absolute;
|
|
52
|
+
width: 1px;
|
|
53
|
+
height: 1px;
|
|
54
|
+
margin: -1px;
|
|
55
|
+
padding: 0;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
clip-path: inset(50%);
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
border: 0;
|
|
60
|
+
}
|
|
49
61
|
`;
|
|
50
62
|
//#endregion
|
|
51
63
|
export { styles };
|
|
@@ -26,8 +26,11 @@ export declare class UChartBlock extends UElement {
|
|
|
26
26
|
private createChart;
|
|
27
27
|
/** 기존 차트 인스턴스 제거 */
|
|
28
28
|
private destroyChart;
|
|
29
|
-
/**
|
|
30
|
-
|
|
29
|
+
/**
|
|
30
|
+
* 현재 테마의 CSS 변수를 읽는다. ⚠`Chart.defaults` 를 바꾸지 않는다 — 전역이라 같은 페이지에서
|
|
31
|
+
* 소비자가 직접 만든 chart.js 차트의 색까지 바꿨다. 값은 이 인스턴스의 옵션으로만 들어간다.
|
|
32
|
+
*/
|
|
33
|
+
private readTheme;
|
|
31
34
|
private handleDownloadPNG;
|
|
32
35
|
private handleDownloadJSON;
|
|
33
36
|
private handleFullscreen;
|
|
@@ -85,15 +85,15 @@ var UChartBlock = class UChartBlock extends UElement {
|
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
try {
|
|
88
|
-
this.
|
|
88
|
+
const theme = this.readTheme();
|
|
89
89
|
this.chartjs = new Chart(ctx, {
|
|
90
90
|
type: this.type,
|
|
91
|
-
data: this.data,
|
|
92
|
-
options: {
|
|
91
|
+
data: paintDatasets(this.type, this.data, theme),
|
|
92
|
+
options: mergeOptions(themeOptions(this.type, this.data, this.options, theme), {
|
|
93
93
|
responsive: true,
|
|
94
94
|
maintainAspectRatio: true,
|
|
95
95
|
...this.options
|
|
96
|
-
}
|
|
96
|
+
})
|
|
97
97
|
});
|
|
98
98
|
} catch (e) {
|
|
99
99
|
this.error = e instanceof Error ? e.message : String(e);
|
|
@@ -106,22 +106,26 @@ var UChartBlock = class UChartBlock extends UElement {
|
|
|
106
106
|
this.chartjs = null;
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
/**
|
|
110
|
+
* 현재 테마의 CSS 변수를 읽는다. ⚠`Chart.defaults` 를 바꾸지 않는다 — 전역이라 같은 페이지에서
|
|
111
|
+
* 소비자가 직접 만든 chart.js 차트의 색까지 바꿨다. 값은 이 인스턴스의 옵션으로만 들어간다.
|
|
112
|
+
*/
|
|
113
|
+
readTheme() {
|
|
114
|
+
const style = getComputedStyle(this);
|
|
115
|
+
const css = (v) => style.getPropertyValue(v).trim();
|
|
116
|
+
const palette = [];
|
|
117
|
+
for (let i = 1; i <= PALETTE_MAX; i++) {
|
|
118
|
+
const c = css(`--u-chart-color-${i}`);
|
|
119
|
+
if (!c) break;
|
|
120
|
+
palette.push(c);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
text: css("--u-txt-color"),
|
|
124
|
+
weak: css("--u-txt-color-weak"),
|
|
125
|
+
border: css("--u-border-color"),
|
|
126
|
+
background: css("--u-bg-color"),
|
|
127
|
+
palette
|
|
128
|
+
};
|
|
125
129
|
}
|
|
126
130
|
handleDownloadPNG() {
|
|
127
131
|
if (!this.chartjs) return;
|
|
@@ -155,5 +159,100 @@ __decorate([query("canvas"), __decorateMetadata("design:type", typeof HTMLCanvas
|
|
|
155
159
|
__decorate([query(".viewport"), __decorateMetadata("design:type", typeof HTMLElement === "undefined" ? Object : HTMLElement)], UChartBlock.prototype, "viewport", void 0);
|
|
156
160
|
__decorate([state(), __decorateMetadata("design:type", Object)], UChartBlock.prototype, "error", void 0);
|
|
157
161
|
UChartBlock = __decorate([customElement("u-chart-block")], UChartBlock);
|
|
162
|
+
/** 읽어 볼 팔레트 토큰의 상한 — 시트는 여덟을 선언한다. 비어 있는 첫 번호에서 멈춘다. */
|
|
163
|
+
var PALETTE_MAX = 12;
|
|
164
|
+
function isPlain(v) {
|
|
165
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
166
|
+
}
|
|
167
|
+
/** `base` 위에 `over` 를 깊게 덮는다 — 소비자가 준 값이 항상 이긴다. 입력은 바꾸지 않는다. */
|
|
168
|
+
function mergeOptions(base, over) {
|
|
169
|
+
const out = { ...base };
|
|
170
|
+
for (const [k, v] of Object.entries(over)) out[k] = isPlain(v) && isPlain(out[k]) ? mergeOptions(out[k], v) : v;
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
var CARTESIAN = /* @__PURE__ */ new Set([
|
|
174
|
+
"bar",
|
|
175
|
+
"line",
|
|
176
|
+
"scatter",
|
|
177
|
+
"bubble"
|
|
178
|
+
]);
|
|
179
|
+
var RADIAL = /* @__PURE__ */ new Set(["radar", "polarArea"]);
|
|
180
|
+
var PER_POINT = /* @__PURE__ */ new Set([
|
|
181
|
+
"pie",
|
|
182
|
+
"doughnut",
|
|
183
|
+
"polarArea"
|
|
184
|
+
]);
|
|
185
|
+
/**
|
|
186
|
+
* 테마 색을 담은 인스턴스 옵션. 축은 «이 차트에 실제로 생길 축» 에만 준다 — 원형 차트에 `x`/`y`
|
|
187
|
+
* 설정을 주면 축이 생길 수 있어서다. 축 id 는 차트 종류의 기본 축 · 소비자가 선언한 축 · 데이터셋이
|
|
188
|
+
* 가리키는 축의 합집합이다.
|
|
189
|
+
*/
|
|
190
|
+
function themeOptions(type, data, options, t) {
|
|
191
|
+
const tooltip = {
|
|
192
|
+
backgroundColor: t.background,
|
|
193
|
+
titleColor: t.text,
|
|
194
|
+
bodyColor: t.weak,
|
|
195
|
+
borderColor: t.border,
|
|
196
|
+
borderWidth: 1
|
|
197
|
+
};
|
|
198
|
+
const ids = new Set(Object.keys(options?.scales ?? {}));
|
|
199
|
+
if (CARTESIAN.has(type)) {
|
|
200
|
+
ids.add("x");
|
|
201
|
+
ids.add("y");
|
|
202
|
+
}
|
|
203
|
+
if (RADIAL.has(type)) ids.add("r");
|
|
204
|
+
for (const ds of data.datasets ?? []) {
|
|
205
|
+
const d = ds;
|
|
206
|
+
for (const key of [
|
|
207
|
+
"xAxisID",
|
|
208
|
+
"yAxisID",
|
|
209
|
+
"rAxisID"
|
|
210
|
+
]) if (typeof d[key] === "string") ids.add(d[key]);
|
|
211
|
+
}
|
|
212
|
+
const scales = {};
|
|
213
|
+
for (const id of ids) scales[id] = {
|
|
214
|
+
ticks: { color: t.weak },
|
|
215
|
+
grid: { color: t.border },
|
|
216
|
+
...RADIAL.has(type) && id === "r" ? {
|
|
217
|
+
angleLines: { color: t.border },
|
|
218
|
+
pointLabels: { color: t.text }
|
|
219
|
+
} : {}
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
color: t.text,
|
|
223
|
+
borderColor: t.border,
|
|
224
|
+
plugins: {
|
|
225
|
+
tooltip,
|
|
226
|
+
legend: { labels: { color: t.text } }
|
|
227
|
+
},
|
|
228
|
+
...ids.size ? { scales } : {}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 색을 지정하지 않은 데이터셋에 팔레트를 입힌다. 소비자가 준 `backgroundColor`/`borderColor` 는
|
|
233
|
+
* 건드리지 않고, 입력 객체도 바꾸지 않는다(사본을 돌려준다). 원형 차트는 조각마다 한 색이다.
|
|
234
|
+
*/
|
|
235
|
+
function paintDatasets(type, data, t) {
|
|
236
|
+
const p = t.palette;
|
|
237
|
+
if (!p.length || !data.datasets) return data;
|
|
238
|
+
const datasets = data.datasets.map((ds, i) => {
|
|
239
|
+
const d = { ...ds };
|
|
240
|
+
const has = (k) => d[k] !== void 0;
|
|
241
|
+
if (PER_POINT.has(type)) {
|
|
242
|
+
const n = Array.isArray(d.data) ? d.data.length : 0;
|
|
243
|
+
if (!has("backgroundColor")) d.backgroundColor = Array.from({ length: n }, (_, j) => p[j % p.length]);
|
|
244
|
+
if (!has("borderColor") && t.background) d.borderColor = t.background;
|
|
245
|
+
} else {
|
|
246
|
+
const c = p[i % p.length];
|
|
247
|
+
if (!has("borderColor")) d.borderColor = c;
|
|
248
|
+
if (!has("backgroundColor")) d.backgroundColor = c;
|
|
249
|
+
}
|
|
250
|
+
return d;
|
|
251
|
+
});
|
|
252
|
+
return {
|
|
253
|
+
...data,
|
|
254
|
+
datasets
|
|
255
|
+
};
|
|
256
|
+
}
|
|
158
257
|
//#endregion
|
|
159
258
|
export { UChartBlock };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
|
|
2
2
|
import __decorate from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.js";
|
|
3
3
|
import { registerElementBlock } from "../utilities/ElementRegistry.js";
|
|
4
|
+
import { messages } from "../utilities/messages.js";
|
|
4
5
|
import { styles } from "./UMapBlock.styles.js";
|
|
5
6
|
import schema from "./UMapBlock.schema.js";
|
|
6
7
|
import { html, nothing } from "lit";
|
|
@@ -34,6 +35,7 @@ var UMapBlock = class UMapBlock extends UElement {
|
|
|
34
35
|
>
|
|
35
36
|
<strong>${this.label}</strong>
|
|
36
37
|
<span>${this.description}</span>
|
|
38
|
+
<span class="new-tab-hint">${messages.text("opensInNewTab")}</span>
|
|
37
39
|
</a>
|
|
38
40
|
`;
|
|
39
41
|
}
|
|
@@ -52,6 +52,18 @@ var styles = css`
|
|
|
52
52
|
font-size: 0.7em;
|
|
53
53
|
opacity: 0.8;
|
|
54
54
|
}
|
|
55
|
+
/* 새 창 알림 — 화면에는 없고 접근성 이름에만 붙는다(KWCAG 7.2.1). */
|
|
56
|
+
.new-tab-hint {
|
|
57
|
+
position: absolute;
|
|
58
|
+
width: 1px;
|
|
59
|
+
height: 1px;
|
|
60
|
+
margin: -1px;
|
|
61
|
+
padding: 0;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
clip-path: inset(50%);
|
|
64
|
+
white-space: nowrap;
|
|
65
|
+
border: 0;
|
|
66
|
+
}
|
|
55
67
|
`;
|
|
56
68
|
//#endregion
|
|
57
69
|
export { styles };
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { nothing, PropertyValues } from 'lit';
|
|
2
2
|
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
3
|
+
/** 자막·캡션 트랙(WebVTT) 하나. */
|
|
4
|
+
export interface VideoTrack {
|
|
5
|
+
src: string;
|
|
6
|
+
/** 기본 `subtitles` */
|
|
7
|
+
kind?: 'subtitles' | 'captions' | 'descriptions' | 'chapters' | 'metadata';
|
|
8
|
+
srclang?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
default?: boolean;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* 비디오 플레이어 블록 컴포넌트
|
|
5
14
|
*/
|
|
@@ -11,6 +20,11 @@ export declare class UVideoBlock extends UElement {
|
|
|
11
20
|
poster?: string;
|
|
12
21
|
/** 비디오 비율 */
|
|
13
22
|
ratio: '16:9' | '4:3' | '1:1';
|
|
23
|
+
/**
|
|
24
|
+
* 직접 파일 영상의 자막·캡션 트랙(WebVTT). 영상이 섀도 안에 그려지므로 앱이 `<track>` 을
|
|
25
|
+
* 넣을 수 없다 — 이 속성이 유일한 자리다. YouTube·Vimeo 는 그 플레이어가 자막을 다룬다.
|
|
26
|
+
*/
|
|
27
|
+
tracks: VideoTrack[];
|
|
14
28
|
protected updated(changedProperties: PropertyValues): void;
|
|
15
29
|
render(): typeof nothing | import('lit-html').TemplateResult<1>;
|
|
16
30
|
private isYouTube;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
|
|
2
2
|
import __decorate from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.js";
|
|
3
|
+
import { sanitizeHref } from "../utilities/sanitizers.js";
|
|
3
4
|
import { registerElementBlock } from "../utilities/ElementRegistry.js";
|
|
4
5
|
import { styles } from "./UVideoBlock.styles.js";
|
|
5
6
|
import schema from "./UVideoBlock.schema.js";
|
|
@@ -13,6 +14,7 @@ var UVideoBlock = class UVideoBlock extends UElement {
|
|
|
13
14
|
constructor(..._args) {
|
|
14
15
|
super(..._args);
|
|
15
16
|
this.ratio = "16:9";
|
|
17
|
+
this.tracks = [];
|
|
16
18
|
}
|
|
17
19
|
static {
|
|
18
20
|
this.styles = [super.styles, styles];
|
|
@@ -55,7 +57,13 @@ var UVideoBlock = class UVideoBlock extends UElement {
|
|
|
55
57
|
poster=${ifDefined(this.poster)}
|
|
56
58
|
controls
|
|
57
59
|
playsinline
|
|
58
|
-
|
|
60
|
+
>${this.tracks.filter((t) => t && typeof t.src === "string" && sanitizeHref(t.src) !== "#").map((t) => html`<track
|
|
61
|
+
src=${sanitizeHref(t.src)}
|
|
62
|
+
kind=${t.kind ?? "subtitles"}
|
|
63
|
+
srclang=${ifDefined(t.srclang)}
|
|
64
|
+
label=${ifDefined(t.label)}
|
|
65
|
+
?default=${t.default === true}
|
|
66
|
+
/>`)}</video>
|
|
59
67
|
`;
|
|
60
68
|
}
|
|
61
69
|
isYouTube(url) {
|
|
@@ -79,6 +87,7 @@ var UVideoBlock = class UVideoBlock extends UElement {
|
|
|
79
87
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UVideoBlock.prototype, "src", void 0);
|
|
80
88
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UVideoBlock.prototype, "poster", void 0);
|
|
81
89
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UVideoBlock.prototype, "ratio", void 0);
|
|
90
|
+
__decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UVideoBlock.prototype, "tracks", void 0);
|
|
82
91
|
UVideoBlock = __decorate([customElement("u-video-block")], UVideoBlock);
|
|
83
92
|
//#endregion
|
|
84
93
|
export { UVideoBlock };
|
|
@@ -20,6 +20,44 @@ var schema = {
|
|
|
20
20
|
],
|
|
21
21
|
default: "16:9",
|
|
22
22
|
description: "Video aspect ratio"
|
|
23
|
+
},
|
|
24
|
+
tracks: {
|
|
25
|
+
type: "array",
|
|
26
|
+
items: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
src: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "WebVTT file URL"
|
|
32
|
+
},
|
|
33
|
+
kind: {
|
|
34
|
+
type: "string",
|
|
35
|
+
enum: [
|
|
36
|
+
"subtitles",
|
|
37
|
+
"captions",
|
|
38
|
+
"descriptions",
|
|
39
|
+
"chapters",
|
|
40
|
+
"metadata"
|
|
41
|
+
],
|
|
42
|
+
default: "subtitles",
|
|
43
|
+
description: "Track kind"
|
|
44
|
+
},
|
|
45
|
+
srclang: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "Language of the track text (BCP 47, e.g. ko)"
|
|
48
|
+
},
|
|
49
|
+
label: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Name shown in the player's track menu"
|
|
52
|
+
},
|
|
53
|
+
default: {
|
|
54
|
+
type: "boolean",
|
|
55
|
+
description: "Show this track by default"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
required: ["src"]
|
|
59
|
+
},
|
|
60
|
+
description: "Subtitle / caption tracks for a direct video file (ignored for YouTube and Vimeo)"
|
|
23
61
|
}
|
|
24
62
|
},
|
|
25
63
|
required: ["src"]
|
|
@@ -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' | 'openImage' | 'previewFile' | 'imageBlocked' | 'imageBlockedNamed';
|
|
8
|
+
export type ChatMessageKey = 'canvasUnavailable' | 'previousReference' | 'nextReference' | 'closePreview' | 'closeLightbox' | 'previousImage' | 'nextImage' | 'sendMessage' | 'stopGenerating' | 'fullScreen' | 'remove' | 'pngDownload' | 'jsonDownload' | 'search' | 'rowCount' | 'excelDownload' | 'csvDownload' | 'openImage' | 'previewFile' | 'imageBlocked' | 'imageBlockedNamed' | 'opensInNewTab';
|
|
9
9
|
export declare const messages: import('@iyulab/components/dist/utilities/Locale.js').LocaleNamespace<ChatMessageKey>;
|
|
@@ -22,7 +22,8 @@ messages.register("en", {
|
|
|
22
22
|
openImage: "Open image {index}",
|
|
23
23
|
previewFile: "Preview {name}",
|
|
24
24
|
imageBlocked: "Image blocked",
|
|
25
|
-
imageBlockedNamed: "Image blocked: {name}"
|
|
25
|
+
imageBlockedNamed: "Image blocked: {name}",
|
|
26
|
+
opensInNewTab: "(opens in a new tab)"
|
|
26
27
|
});
|
|
27
28
|
messages.register("ko", {
|
|
28
29
|
canvasUnavailable: "Canvas 2D context를 가져올 수 없습니다.",
|
|
@@ -45,7 +46,8 @@ messages.register("ko", {
|
|
|
45
46
|
openImage: "이미지 {index} 열기",
|
|
46
47
|
previewFile: "{name} 미리보기",
|
|
47
48
|
imageBlocked: "차단된 이미지",
|
|
48
|
-
imageBlockedNamed: "차단된 이미지: {name}"
|
|
49
|
+
imageBlockedNamed: "차단된 이미지: {name}",
|
|
50
|
+
opensInNewTab: "(새 창에서 열림)"
|
|
49
51
|
});
|
|
50
52
|
//#endregion
|
|
51
53
|
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.16.0",
|
|
5
5
|
"author": "iyulab",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"@iyulab/components": ">=1.51.0",
|
|
73
|
-
"@lit/react": "
|
|
74
|
-
"chart.js": "
|
|
75
|
-
"react": "
|
|
73
|
+
"@lit/react": "^1.0.8",
|
|
74
|
+
"chart.js": "^4.5.1",
|
|
75
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
76
76
|
},
|
|
77
77
|
"peerDependenciesMeta": {
|
|
78
78
|
"@lit/react": {
|
|
@@ -65,6 +65,23 @@ of it was clipped by the block's `overflow: hidden` with no scrollbar left to re
|
|
|
65
65
|
|
|
66
66
|
There is no size property or custom property for this — the host is the lever.
|
|
67
67
|
|
|
68
|
+
## Colors and theme
|
|
69
|
+
|
|
70
|
+
Text, tick, grid, and tooltip colors come from the design tokens (`--u-txt-color`,
|
|
71
|
+
`--u-txt-color-weak`, `--u-border-color`, `--u-bg-color`), and dataset colors from the chart palette
|
|
72
|
+
`--u-chart-color-1..N` — the same palette dashboards and `@iyulab/u-widgets` use. Both apply to **this
|
|
73
|
+
chart only**: `Chart.defaults` is not modified, so other Chart.js charts on the page keep their own
|
|
74
|
+
look.
|
|
75
|
+
|
|
76
|
+
Anything you pass wins: a dataset's own `backgroundColor`/`borderColor` is kept, and `options` are
|
|
77
|
+
merged over the theme (`options.scales.x.ticks.color` overrides just that value). Without the token
|
|
78
|
+
sheet the palette is empty and Chart.js defaults apply.
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* Recolour the palette for one area */
|
|
82
|
+
.report u-chart-block { --u-chart-color-1: #0b6e4f; }
|
|
83
|
+
```
|
|
84
|
+
|
|
68
85
|
## Properties
|
|
69
86
|
|
|
70
87
|
| Property | Type | Default | Description |
|
|
@@ -80,6 +97,7 @@ There is no size property or custom property for this — the host is the lever.
|
|
|
80
97
|
| Download | Export chart as PNG or raw JSON data |
|
|
81
98
|
| Full screen | Toggle the chart viewport into full-screen mode |
|
|
82
99
|
| Theme sync | Watches `document.documentElement[theme]` and re-renders on change |
|
|
100
|
+
| Palette | Datasets without `backgroundColor`/`borderColor` take `--u-chart-color-1..N` from the design-token sheet (per slice for `pie`/`doughnut`/`polarArea`) |
|
|
83
101
|
|
|
84
102
|
## Requires
|
|
85
103
|
|
|
@@ -55,6 +55,7 @@ reason as the image block: vertical squeezing would break the aspect ratio. The
|
|
|
55
55
|
| `src` | `string` | `undefined` | Video URL: YouTube, Vimeo, or direct file |
|
|
56
56
|
| `poster` | `string` | `undefined` | Poster image URL for direct video files |
|
|
57
57
|
| `ratio` | `'16:9'\|'4:3'\|'1:1'` | `'16:9'` | Aspect ratio |
|
|
58
|
+
| `tracks` | `VideoTrack[]` | `[]` | Subtitle / caption tracks (WebVTT) for a direct video file — `{ src, kind?, srclang?, label?, default? }`, `kind` defaults to `'subtitles'`. The video is inside the shadow tree, so this is the only way to add a `<track>`. Ignored for YouTube and Vimeo. Track files on another origin load only when that server allows CORS for the page |
|
|
58
59
|
|
|
59
60
|
## Supported Platforms
|
|
60
61
|
|