1ch 0.5.0 → 0.6.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/dist/index.d.ts +17 -1
- package/dist/index.js +136 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
type MediaRef = {
|
|
2
|
+
tag: string;
|
|
3
|
+
src?: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
widthCells: number;
|
|
6
|
+
heightLines: number;
|
|
7
|
+
attrs?: Record<string, string>;
|
|
8
|
+
};
|
|
1
9
|
type Style = {
|
|
2
10
|
text: string;
|
|
3
11
|
color?: string;
|
|
@@ -10,6 +18,7 @@ type Style = {
|
|
|
10
18
|
onClick?: () => void;
|
|
11
19
|
noSelect?: boolean;
|
|
12
20
|
cell?: number;
|
|
21
|
+
media?: MediaRef;
|
|
13
22
|
};
|
|
14
23
|
type Segment = string | Style;
|
|
15
24
|
type Line = Segment[];
|
|
@@ -209,7 +218,6 @@ declare function tabs(names: string[], active: number, opts?: {
|
|
|
209
218
|
separatorColor?: string;
|
|
210
219
|
onSelect?: (index: number) => void;
|
|
211
220
|
onClicks?: ((() => void) | undefined)[];
|
|
212
|
-
interactionIds?: (string | undefined)[];
|
|
213
221
|
theme?: Theme;
|
|
214
222
|
}): LayoutFn;
|
|
215
223
|
declare function badge(label: string, opts?: {
|
|
@@ -482,6 +490,14 @@ type TermIRNode = {
|
|
|
482
490
|
text: string;
|
|
483
491
|
color?: string;
|
|
484
492
|
action: TermAction;
|
|
493
|
+
} | {
|
|
494
|
+
kind: "media";
|
|
495
|
+
tag: string;
|
|
496
|
+
src?: string;
|
|
497
|
+
alt?: string;
|
|
498
|
+
widthCells?: number;
|
|
499
|
+
heightLines?: number;
|
|
500
|
+
attrs?: Record<string, string>;
|
|
485
501
|
};
|
|
486
502
|
|
|
487
503
|
type ActionSeed = {
|
package/dist/index.js
CHANGED
|
@@ -497,20 +497,17 @@ function tabs(names, active, opts) {
|
|
|
497
497
|
const name = names[i];
|
|
498
498
|
const label = " " + (isActive ? name.toUpperCase() : name) + " ";
|
|
499
499
|
const onClick = opts?.onClicks?.[i] ?? (onSelect ? () => onSelect(i) : void 0);
|
|
500
|
-
const interactionId = onClick ? opts?.interactionIds?.[i] : void 0;
|
|
501
500
|
if (isActive) {
|
|
502
501
|
line.push({
|
|
503
502
|
text: label,
|
|
504
503
|
color: opts?.activeColor ?? t?.components.tabs.activeFg,
|
|
505
504
|
bg: opts?.activeBg ?? t?.components.tabs.activeBg,
|
|
506
|
-
interactionId,
|
|
507
505
|
onClick
|
|
508
506
|
});
|
|
509
507
|
} else {
|
|
510
508
|
line.push({
|
|
511
509
|
text: label,
|
|
512
510
|
color: opts?.inactiveColor ?? t?.components.tabs.inactiveFg,
|
|
513
|
-
interactionId,
|
|
514
511
|
onClick
|
|
515
512
|
});
|
|
516
513
|
}
|
|
@@ -1863,6 +1860,49 @@ function registerDefaultCompilers() {
|
|
|
1863
1860
|
action: ctx.actionFromElement(el, { type: "action", id, text })
|
|
1864
1861
|
};
|
|
1865
1862
|
});
|
|
1863
|
+
htmlTagRegistry.set("img", (el) => {
|
|
1864
|
+
const src = el.getAttribute("src")?.trim();
|
|
1865
|
+
if (!src) return null;
|
|
1866
|
+
return {
|
|
1867
|
+
kind: "media",
|
|
1868
|
+
tag: "img",
|
|
1869
|
+
src,
|
|
1870
|
+
alt: el.getAttribute("alt")?.trim() ?? void 0,
|
|
1871
|
+
widthCells: parseIntegerAttrs(el, ["width"]) ?? void 0,
|
|
1872
|
+
heightLines: parseIntegerAttrs(el, ["height"]) ?? void 0
|
|
1873
|
+
};
|
|
1874
|
+
});
|
|
1875
|
+
htmlTagRegistry.set("video", (el) => {
|
|
1876
|
+
const src = el.getAttribute("src")?.trim() ?? void 0;
|
|
1877
|
+
const attrs = {};
|
|
1878
|
+
if (el.hasAttribute("controls")) attrs.controls = "";
|
|
1879
|
+
if (el.hasAttribute("autoplay")) attrs.autoplay = "";
|
|
1880
|
+
if (el.hasAttribute("loop")) attrs.loop = "";
|
|
1881
|
+
if (el.hasAttribute("muted")) attrs.muted = "";
|
|
1882
|
+
const poster = el.getAttribute("poster")?.trim();
|
|
1883
|
+
if (poster) attrs.poster = poster;
|
|
1884
|
+
return {
|
|
1885
|
+
kind: "media",
|
|
1886
|
+
tag: "video",
|
|
1887
|
+
src,
|
|
1888
|
+
widthCells: parseIntegerAttrs(el, ["width"]) ?? void 0,
|
|
1889
|
+
heightLines: parseIntegerAttrs(el, ["height"]) ?? void 0,
|
|
1890
|
+
attrs: Object.keys(attrs).length > 0 ? attrs : void 0
|
|
1891
|
+
};
|
|
1892
|
+
});
|
|
1893
|
+
htmlTagRegistry.set("audio", (el) => {
|
|
1894
|
+
const src = el.getAttribute("src")?.trim() ?? void 0;
|
|
1895
|
+
const attrs = {};
|
|
1896
|
+
if (el.hasAttribute("controls")) attrs.controls = "";
|
|
1897
|
+
if (el.hasAttribute("autoplay")) attrs.autoplay = "";
|
|
1898
|
+
if (el.hasAttribute("loop")) attrs.loop = "";
|
|
1899
|
+
return {
|
|
1900
|
+
kind: "media",
|
|
1901
|
+
tag: "audio",
|
|
1902
|
+
src,
|
|
1903
|
+
attrs: Object.keys(attrs).length > 0 ? attrs : void 0
|
|
1904
|
+
};
|
|
1905
|
+
});
|
|
1866
1906
|
htmlTagRegistry.set("progress", (el, ctx) => compileBarNode(el, ctx));
|
|
1867
1907
|
htmlTagRegistry.set("a", (el, ctx) => {
|
|
1868
1908
|
const text = normalizeHtmlText(el.textContent ?? "");
|
|
@@ -2882,6 +2922,29 @@ function layoutFromIR(node, options) {
|
|
|
2882
2922
|
return buttonLayout(node, options);
|
|
2883
2923
|
case "link":
|
|
2884
2924
|
return linkLayout(node, options);
|
|
2925
|
+
case "media": {
|
|
2926
|
+
const heightLines = node.heightLines ?? 6;
|
|
2927
|
+
return (w) => {
|
|
2928
|
+
const widthCells = node.widthCells != null ? Math.min(node.widthCells, w) : w;
|
|
2929
|
+
const block = [];
|
|
2930
|
+
const markerSeg = {
|
|
2931
|
+
text: " ".repeat(widthCells),
|
|
2932
|
+
media: {
|
|
2933
|
+
tag: node.tag,
|
|
2934
|
+
src: node.src,
|
|
2935
|
+
alt: node.alt,
|
|
2936
|
+
widthCells,
|
|
2937
|
+
heightLines,
|
|
2938
|
+
attrs: node.attrs
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
block.push(padLine([markerSeg], w));
|
|
2942
|
+
for (let i = 1; i < heightLines; i++) {
|
|
2943
|
+
block.push(padLine([" ".repeat(w)], w));
|
|
2944
|
+
}
|
|
2945
|
+
return block;
|
|
2946
|
+
};
|
|
2947
|
+
}
|
|
2885
2948
|
default:
|
|
2886
2949
|
return blank();
|
|
2887
2950
|
}
|
|
@@ -3116,18 +3179,79 @@ function patchScrollRegion(region, lines2, meta, theme, actions, regionKey) {
|
|
|
3116
3179
|
}
|
|
3117
3180
|
}
|
|
3118
3181
|
function patchRoot(target, units, theme, actions) {
|
|
3182
|
+
const existingNonMedia = [];
|
|
3183
|
+
for (const child of Array.from(target.children)) {
|
|
3184
|
+
if (child.classList.contains("termui-media")) continue;
|
|
3185
|
+
existingNonMedia.push(child);
|
|
3186
|
+
}
|
|
3119
3187
|
for (let unitIndex = 0; unitIndex < units.length; unitIndex++) {
|
|
3120
3188
|
const unit = units[unitIndex];
|
|
3121
3189
|
if (unit.kind === "line") {
|
|
3122
|
-
const
|
|
3190
|
+
const existing2 = existingNonMedia[unitIndex];
|
|
3191
|
+
let lineDiv;
|
|
3192
|
+
if (existing2 instanceof HTMLDivElement && existing2.className === "termui-line") {
|
|
3193
|
+
lineDiv = existing2;
|
|
3194
|
+
} else {
|
|
3195
|
+
lineDiv = document.createElement("div");
|
|
3196
|
+
lineDiv.className = "termui-line";
|
|
3197
|
+
if (existing2) target.replaceChild(lineDiv, existing2);
|
|
3198
|
+
else target.insertBefore(lineDiv, target.querySelector(".termui-media"));
|
|
3199
|
+
}
|
|
3123
3200
|
patchLine(lineDiv, unit.line, theme, actions, `u${unitIndex}:l0`);
|
|
3124
3201
|
continue;
|
|
3125
3202
|
}
|
|
3126
|
-
const
|
|
3203
|
+
const existing = existingNonMedia[unitIndex];
|
|
3204
|
+
let region;
|
|
3205
|
+
if (existing instanceof HTMLDivElement && existing.className === "termui-scroll-region") {
|
|
3206
|
+
region = existing;
|
|
3207
|
+
} else {
|
|
3208
|
+
region = document.createElement("div");
|
|
3209
|
+
region.className = "termui-scroll-region";
|
|
3210
|
+
if (existing) target.replaceChild(region, existing);
|
|
3211
|
+
else target.insertBefore(region, target.querySelector(".termui-media"));
|
|
3212
|
+
}
|
|
3127
3213
|
patchScrollRegion(region, unit.lines, unit.meta, theme, actions, `u${unitIndex}`);
|
|
3128
3214
|
}
|
|
3129
|
-
|
|
3130
|
-
|
|
3215
|
+
const nonMediaChildren = Array.from(target.children).filter(
|
|
3216
|
+
(c) => !c.classList.contains("termui-media")
|
|
3217
|
+
);
|
|
3218
|
+
while (nonMediaChildren.length > units.length) {
|
|
3219
|
+
nonMediaChildren.pop().remove();
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
function renderMediaOverlays(target, block) {
|
|
3223
|
+
for (const old of Array.from(target.querySelectorAll(".termui-media"))) {
|
|
3224
|
+
old.remove();
|
|
3225
|
+
}
|
|
3226
|
+
for (let lineIndex = 0; lineIndex < block.length; lineIndex++) {
|
|
3227
|
+
const line = block[lineIndex];
|
|
3228
|
+
let colOffset = 0;
|
|
3229
|
+
for (const seg of line) {
|
|
3230
|
+
if (typeof seg === "string") {
|
|
3231
|
+
colOffset += seg.length;
|
|
3232
|
+
continue;
|
|
3233
|
+
}
|
|
3234
|
+
if (seg.media) {
|
|
3235
|
+
const el = document.createElement(seg.media.tag);
|
|
3236
|
+
if (seg.media.src) el.setAttribute("src", seg.media.src);
|
|
3237
|
+
if (seg.media.alt && seg.media.tag === "img") el.setAttribute("alt", seg.media.alt);
|
|
3238
|
+
if (seg.media.attrs) {
|
|
3239
|
+
for (const [k, v] of Object.entries(seg.media.attrs)) el.setAttribute(k, v);
|
|
3240
|
+
}
|
|
3241
|
+
el.className = "termui-media";
|
|
3242
|
+
el.style.position = "absolute";
|
|
3243
|
+
el.style.top = `calc(${lineIndex} * var(--cell-h))`;
|
|
3244
|
+
el.style.left = `${colOffset}ch`;
|
|
3245
|
+
el.style.width = `${seg.media.widthCells}ch`;
|
|
3246
|
+
el.style.height = `calc(${seg.media.heightLines} * var(--cell-h))`;
|
|
3247
|
+
if (seg.media.tag === "img" || seg.media.tag === "video") {
|
|
3248
|
+
el.style.objectFit = "cover";
|
|
3249
|
+
}
|
|
3250
|
+
el.style.display = "block";
|
|
3251
|
+
target.appendChild(el);
|
|
3252
|
+
}
|
|
3253
|
+
colOffset += seg.text.length;
|
|
3254
|
+
}
|
|
3131
3255
|
}
|
|
3132
3256
|
}
|
|
3133
3257
|
function renderTermBlock(target, block, theme) {
|
|
@@ -3135,6 +3259,7 @@ function renderTermBlock(target, block, theme) {
|
|
|
3135
3259
|
const actions = /* @__PURE__ */ new Map();
|
|
3136
3260
|
const units = buildRenderUnits(block);
|
|
3137
3261
|
patchRoot(target, units, theme, actions);
|
|
3262
|
+
renderMediaOverlays(target, block);
|
|
3138
3263
|
state.actions = actions;
|
|
3139
3264
|
}
|
|
3140
3265
|
|
|
@@ -3162,6 +3287,7 @@ var TERM_UI_CSS = `
|
|
|
3162
3287
|
}
|
|
3163
3288
|
.termui-root {
|
|
3164
3289
|
white-space: pre;
|
|
3290
|
+
position: relative;
|
|
3165
3291
|
}
|
|
3166
3292
|
.termui-line {
|
|
3167
3293
|
line-height: var(--cell-h);
|
|
@@ -3177,6 +3303,9 @@ var TERM_UI_CSS = `
|
|
|
3177
3303
|
.termui-scroll-region {
|
|
3178
3304
|
overflow: hidden;
|
|
3179
3305
|
}
|
|
3306
|
+
.termui-media {
|
|
3307
|
+
pointer-events: auto;
|
|
3308
|
+
}
|
|
3180
3309
|
.termui-probe {
|
|
3181
3310
|
font: inherit;
|
|
3182
3311
|
white-space: pre;
|