@saifymatteo/pi-extensions 0.0.0-stage → 0.1.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/LICENSE +661 -0
- package/NOTICE.md +20 -0
- package/README.md +151 -2
- package/inventory.json +73 -0
- package/package.json +74 -4
- package/packages/pi-bg-bash/LICENSE +661 -0
- package/packages/pi-bg-bash/NOTICE.md +3 -0
- package/packages/pi-bg-bash/README.md +41 -0
- package/packages/pi-bg-bash/examples/settings.example.json +6 -0
- package/packages/pi-bg-bash/package.json +38 -0
- package/packages/pi-bg-bash/src/index.ts +969 -0
- package/packages/pi-bg-bash/src/lib/async-work.ts +27 -0
- package/packages/pi-bg-bash/test/bg-bash.test.mjs +34 -0
- package/packages/pi-claude-usage/LICENSE +661 -0
- package/packages/pi-claude-usage/NOTICE.md +3 -0
- package/packages/pi-claude-usage/README.md +27 -0
- package/packages/pi-claude-usage/package.json +35 -0
- package/packages/pi-claude-usage/src/index.ts +130 -0
- package/packages/pi-clipboard-image/LICENSE +661 -0
- package/packages/pi-clipboard-image/NOTICE.md +3 -0
- package/packages/pi-clipboard-image/README.md +27 -0
- package/packages/pi-clipboard-image/package.json +36 -0
- package/packages/pi-clipboard-image/src/index.ts +527 -0
- package/packages/pi-codeblock-borders/LICENSE +661 -0
- package/packages/pi-codeblock-borders/NOTICE.md +3 -0
- package/packages/pi-codeblock-borders/README.md +30 -0
- package/packages/pi-codeblock-borders/package.json +35 -0
- package/packages/pi-codeblock-borders/src/index.ts +302 -0
- package/packages/pi-codegraph/LICENSE +661 -0
- package/packages/pi-codegraph/NOTICE.md +5 -0
- package/packages/pi-codegraph/README.md +35 -0
- package/packages/pi-codegraph/examples/codegraph.example.json +4 -0
- package/packages/pi-codegraph/package.json +37 -0
- package/packages/pi-codegraph/src/index.ts +573 -0
- package/packages/pi-codegraph/test/codegraph.test.mjs +21 -0
- package/packages/pi-compact-tools/LICENSE +661 -0
- package/packages/pi-compact-tools/NOTICE.md +3 -0
- package/packages/pi-compact-tools/README.md +27 -0
- package/packages/pi-compact-tools/package.json +36 -0
- package/packages/pi-compact-tools/src/index.ts +1161 -0
- package/packages/pi-decisions/LICENSE +661 -0
- package/packages/pi-decisions/NOTICE.md +3 -0
- package/packages/pi-decisions/README.md +37 -0
- package/packages/pi-decisions/examples/service-models.example.json +27 -0
- package/packages/pi-decisions/package.json +37 -0
- package/packages/pi-decisions/src/index.ts +364 -0
- package/packages/pi-decisions/src/lib/service-models.ts +95 -0
- package/packages/pi-decisions/test/service-models.test.mjs +71 -0
- package/packages/pi-load-pi-dotenv/LICENSE +661 -0
- package/packages/pi-load-pi-dotenv/NOTICE.md +3 -0
- package/packages/pi-load-pi-dotenv/README.md +27 -0
- package/packages/pi-load-pi-dotenv/package.json +32 -0
- package/packages/pi-load-pi-dotenv/src/index.ts +66 -0
- package/packages/pi-model-go/LICENSE +661 -0
- package/packages/pi-model-go/NOTICE.md +5 -0
- package/packages/pi-model-go/README.md +33 -0
- package/packages/pi-model-go/package.json +36 -0
- package/packages/pi-model-go/src/index.ts +171 -0
- package/packages/pi-model-go/src/lib/dialog.ts +31 -0
- package/packages/pi-model-go/src/lib/model-go.ts +239 -0
- package/packages/pi-model-go/test/behavior.test.mjs +17 -0
- package/packages/pi-prestart-working/LICENSE +661 -0
- package/packages/pi-prestart-working/NOTICE.md +3 -0
- package/packages/pi-prestart-working/README.md +25 -0
- package/packages/pi-prestart-working/package.json +35 -0
- package/packages/pi-prestart-working/src/index.ts +86 -0
- package/packages/pi-prestart-working/test/behavior.test.mjs +56 -0
- package/packages/pi-root-guard/LICENSE +661 -0
- package/packages/pi-root-guard/NOTICE.md +3 -0
- package/packages/pi-root-guard/README.md +27 -0
- package/packages/pi-root-guard/package.json +32 -0
- package/packages/pi-root-guard/src/index.ts +202 -0
- package/packages/pi-session-finder/LICENSE +661 -0
- package/packages/pi-session-finder/NOTICE.md +3 -0
- package/packages/pi-session-finder/README.md +33 -0
- package/packages/pi-session-finder/package.json +36 -0
- package/packages/pi-session-finder/src/index.ts +306 -0
- package/packages/pi-session-finder/src/lib/dialog.ts +31 -0
- package/packages/pi-session-finder/test/behavior.test.mjs +18 -0
- package/packages/pi-session-id/LICENSE +661 -0
- package/packages/pi-session-id/NOTICE.md +3 -0
- package/packages/pi-session-id/README.md +31 -0
- package/packages/pi-session-id/package.json +35 -0
- package/packages/pi-session-id/src/index.ts +20 -0
- package/packages/pi-session-id/test/behavior.test.mjs +25 -0
- package/packages/pi-session-nav/LICENSE +661 -0
- package/packages/pi-session-nav/NOTICE.md +3 -0
- package/packages/pi-session-nav/README.md +32 -0
- package/packages/pi-session-nav/package.json +36 -0
- package/packages/pi-session-nav/src/index.ts +203 -0
- package/packages/pi-session-nav/src/lib/dialog.ts +31 -0
- package/packages/pi-session-nav/test/behavior.test.mjs +36 -0
- package/packages/pi-session-rename/LICENSE +661 -0
- package/packages/pi-session-rename/NOTICE.md +3 -0
- package/packages/pi-session-rename/README.md +31 -0
- package/packages/pi-session-rename/package.json +35 -0
- package/packages/pi-session-rename/src/index.ts +456 -0
- package/packages/pi-session-rename/test/behavior.test.mjs +10 -0
- package/packages/pi-session-retention/LICENSE +661 -0
- package/packages/pi-session-retention/NOTICE.md +3 -0
- package/packages/pi-session-retention/README.md +62 -0
- package/packages/pi-session-retention/package.json +36 -0
- package/packages/pi-session-retention/src/README.md +42 -0
- package/packages/pi-session-retention/src/core.ts +333 -0
- package/packages/pi-session-retention/src/dialog.ts +118 -0
- package/packages/pi-session-retention/src/index.ts +311 -0
- package/packages/pi-session-retention/src/lib/dialog.ts +31 -0
- package/packages/pi-session-retention/src/safety.ts +50 -0
- package/packages/pi-session-retention/test/behavior.test.mjs +42 -0
- package/packages/pi-skill-usage-log/LICENSE +661 -0
- package/packages/pi-skill-usage-log/NOTICE.md +3 -0
- package/packages/pi-skill-usage-log/README.md +32 -0
- package/packages/pi-skill-usage-log/package.json +36 -0
- package/packages/pi-skill-usage-log/src/index.ts +316 -0
- package/packages/pi-skill-usage-log/src/lib/dialog.ts +31 -0
- package/packages/pi-skill-usage-log/src/lib/usage-log.ts +62 -0
- package/packages/pi-skill-usage-log/test/behavior.test.mjs +34 -0
- package/packages/pi-tool-usage-log/LICENSE +661 -0
- package/packages/pi-tool-usage-log/NOTICE.md +5 -0
- package/packages/pi-tool-usage-log/README.md +32 -0
- package/packages/pi-tool-usage-log/package.json +36 -0
- package/packages/pi-tool-usage-log/src/index.ts +233 -0
- package/packages/pi-tool-usage-log/src/lib/dialog.ts +31 -0
- package/packages/pi-tool-usage-log/src/lib/usage-log.ts +62 -0
- package/packages/pi-tool-usage-log/src/skill-usage-log.ts +316 -0
- package/packages/pi-tool-usage-log/test/behavior.test.mjs +23 -0
- package/packages/pi-tts/LICENSE +661 -0
- package/packages/pi-tts/NOTICE.md +3 -0
- package/packages/pi-tts/README.md +37 -0
- package/packages/pi-tts/examples/service-models.example.json +27 -0
- package/packages/pi-tts/package.json +37 -0
- package/packages/pi-tts/src/index.ts +135 -0
- package/packages/pi-tts/src/lib/service-models.ts +95 -0
- package/packages/pi-tts/test/tts-output.test.mjs +47 -0
- package/packages/pi-tts/test/tts.test.mjs +57 -0
- package/packages/pi-user-image-previews/LICENSE +661 -0
- package/packages/pi-user-image-previews/NOTICE.md +3 -0
- package/packages/pi-user-image-previews/README.md +27 -0
- package/packages/pi-user-image-previews/package.json +36 -0
- package/packages/pi-user-image-previews/src/index.ts +168 -0
- package/packages/pi-vision/LICENSE +661 -0
- package/packages/pi-vision/NOTICE.md +5 -0
- package/packages/pi-vision/README.md +43 -0
- package/packages/pi-vision/examples/vision-toolkit.example.json +12 -0
- package/packages/pi-vision/package.json +38 -0
- package/packages/pi-vision/skills/vision-tools/LICENSE +21 -0
- package/packages/pi-vision/skills/vision-tools/SKILL.md +134 -0
- package/packages/pi-vision/skills/vision-tools/agents/openai.yaml +4 -0
- package/packages/pi-vision/skills/vision-tools/bin/crop +94 -0
- package/packages/pi-vision/skills/vision-tools/bin/detect +18 -0
- package/packages/pi-vision/skills/vision-tools/bin/glance +98 -0
- package/packages/pi-vision/skills/vision-tools/bin/ground +18 -0
- package/packages/pi-vision/skills/vision-tools/bin/trace +134 -0
- package/packages/pi-vision/skills/vision-tools/bin/vision-doctor +168 -0
- package/packages/pi-vision/skills/vision-tools/detect.py +56 -0
- package/packages/pi-vision/skills/vision-tools/ground.py +216 -0
- package/packages/pi-vision/skills/vision-tools/references/gui.md +93 -0
- package/packages/pi-vision/skills/vision-tools/references/long-screenshot-ocr.md +103 -0
- package/packages/pi-vision/skills/vision-tools/references/restore-graphic.md +92 -0
- package/packages/pi-vision/skills/vision-tools/references/restore-structure.md +47 -0
- package/packages/pi-vision/skills/vision-tools/references/restore-ui.md +200 -0
- package/packages/pi-vision/skills/vision-tools/scripts/dominant_colors.py +224 -0
- package/packages/pi-vision/skills/vision-tools/scripts/extract_fg.py +278 -0
- package/packages/pi-vision/skills/vision-tools/scripts/html_shot.py +111 -0
- package/packages/pi-vision/skills/vision-tools/scripts/long_screenshot_ocr.py +1245 -0
- package/packages/pi-vision/skills/vision-tools/scripts/pixel_diff.py +88 -0
- package/packages/pi-vision/skills/vision-tools/vision_client.py +581 -0
- package/packages/pi-vision/src/index.ts +728 -0
- package/packages/pi-vision/test/vision.test.mjs +30 -0
- package/packages/pi-wait/LICENSE +661 -0
- package/packages/pi-wait/NOTICE.md +3 -0
- package/packages/pi-wait/README.md +37 -0
- package/packages/pi-wait/package.json +37 -0
- package/packages/pi-wait/src/index.ts +88 -0
- package/packages/pi-wait/src/lib/async-work.ts +27 -0
- package/packages/pi-wait/test/wait.test.mjs +43 -0
- package/packages/pi-zvec/LICENSE +661 -0
- package/packages/pi-zvec/NOTICE.md +3 -0
- package/packages/pi-zvec/README.md +37 -0
- package/packages/pi-zvec/examples/zvec.example.json +5 -0
- package/packages/pi-zvec/package.json +37 -0
- package/packages/pi-zvec/src/index.ts +754 -0
- package/packages/pi-zvec/test/zvec.test.mjs +19 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Inline user image previews
|
|
2
|
+
|
|
3
|
+
Adds collapsible UI-only previews for newly submitted image attachments.
|
|
4
|
+
|
|
5
|
+
## Try locally
|
|
6
|
+
|
|
7
|
+
From the repository root:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pi -e ./packages/pi-user-image-previews
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This uses your normal personal resources unless you isolate the agent home. Follow the [root README](../../README.md#isolated-sessions) to avoid loading an existing copy of the extension. Nothing is installed globally.
|
|
14
|
+
|
|
15
|
+
## Configuration and requirements
|
|
16
|
+
|
|
17
|
+
No config files. Ctrl+O expands/collapses previews. References original messages without inserting duplicate model image payloads.
|
|
18
|
+
|
|
19
|
+
## Compatibility and safety
|
|
20
|
+
|
|
21
|
+
Source targets Pi 1.3+ and uses host transcript/layout details. Requires an image-capable terminal for graphics. No independent image upload or model request is made by this package.
|
|
22
|
+
|
|
23
|
+
Imported host APIs are declared as peer dependencies and supplied by the Pi host. A `*` peer range describes host resolution, not a guarantee of compatibility with every release. See root verification notes for what was actually exercised.
|
|
24
|
+
|
|
25
|
+
## Status
|
|
26
|
+
|
|
27
|
+
Part of the [pi-extensions](../../README.md) collection. No personal settings or credentials are included; see [NOTICE.md](NOTICE.md) for licensing and provenance.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@saifymatteo/pi-user-image-previews",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Adds collapsible UI-only previews for newly submitted image attachments.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "AGPL-3.0-only",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"pi-package"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"README.md",
|
|
13
|
+
"NOTICE.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"pi": {
|
|
17
|
+
"extensions": [
|
|
18
|
+
"./src/index.ts"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=24"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
26
|
+
"@earendil-works/pi-tui": "*"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/saifymatteo/pi-extensions.git",
|
|
34
|
+
"directory": "packages/pi-user-image-previews"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapsible inline previews for newly submitted user attachments (Pi 1.3+).
|
|
3
|
+
* Independent borderless image rows; Ctrl+O expands/collapses all previews.
|
|
4
|
+
* UI-only entries reference the original message: no duplicate image payloads,
|
|
5
|
+
* model messages, tool calls, or dependence on clipboard temp files.
|
|
6
|
+
*/
|
|
7
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import { getCellDimensions, getImageDimensions, Image, truncateToWidth } from "@earendil-works/pi-tui";
|
|
9
|
+
import type { Component, TuiMouseEvent } from "@earendil-works/pi-tui";
|
|
10
|
+
|
|
11
|
+
const PREVIEW_TYPE = "user-image-preview";
|
|
12
|
+
|
|
13
|
+
function messageId(data: unknown): string | undefined {
|
|
14
|
+
return data !== null && typeof data === "object" && "messageId" in data && typeof data.messageId === "string"
|
|
15
|
+
? data.messageId : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default function (pi: ExtensionAPI) {
|
|
19
|
+
let retired = false;
|
|
20
|
+
let sessionManager: ExtensionContext["sessionManager"] | undefined;
|
|
21
|
+
const disclosures = new Map<string, { images: Set<number>; expanded: boolean }>();
|
|
22
|
+
// undefined = no new prompt; null = the prompt started an empty branch.
|
|
23
|
+
let pendingAfter: string | null | undefined;
|
|
24
|
+
|
|
25
|
+
pi.on("session_start", (_event, ctx) => {
|
|
26
|
+
retired = false;
|
|
27
|
+
sessionManager = ctx.sessionManager;
|
|
28
|
+
disclosures.clear();
|
|
29
|
+
pendingAfter = undefined;
|
|
30
|
+
});
|
|
31
|
+
pi.on("session_shutdown", () => {
|
|
32
|
+
// The TUI may still render/rebuild old rows while /reload is replacing
|
|
33
|
+
// the runtime. Those callbacks must not touch its now-stale pi or ctx.
|
|
34
|
+
retired = true;
|
|
35
|
+
sessionManager = undefined;
|
|
36
|
+
pendingAfter = undefined;
|
|
37
|
+
disclosures.clear();
|
|
38
|
+
});
|
|
39
|
+
pi.on("agent_settled", () => { pendingAfter = undefined; });
|
|
40
|
+
|
|
41
|
+
pi.on("message_end", (event, ctx) => {
|
|
42
|
+
if (ctx.mode === "tui" && event.message.role === "user" && pendingAfter === undefined) {
|
|
43
|
+
pendingAfter = ctx.sessionManager.getLeafId();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
pi.on("context", (_event, ctx) => {
|
|
48
|
+
if (ctx.mode !== "tui" || pendingAfter === undefined) return;
|
|
49
|
+
sessionManager = ctx.sessionManager;
|
|
50
|
+
const branch = sessionManager.getBranch();
|
|
51
|
+
const start = pendingAfter === null ? 0 : branch.findIndex((entry) => entry.id === pendingAfter) + 1;
|
|
52
|
+
if (pendingAfter !== null && start === 0) {
|
|
53
|
+
pendingAfter = undefined; // The branch changed; never backfill unrelated history.
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const previewed = new Set(branch.flatMap((entry) =>
|
|
57
|
+
entry.type === "custom" && entry.customType === PREVIEW_TYPE ? [messageId(entry.data)] : [],
|
|
58
|
+
));
|
|
59
|
+
// In Pi 1.3, message_end precedes persistence. At this boundary the
|
|
60
|
+
// finalized user message is saved and displayed, but the LLM has not started.
|
|
61
|
+
// Use entry IDs, not message object identity: other extensions can replace messages.
|
|
62
|
+
for (const entry of branch.slice(start)) {
|
|
63
|
+
if (entry.type !== "message" || entry.message.role !== "user") continue;
|
|
64
|
+
const content = entry.message.content;
|
|
65
|
+
if (Array.isArray(content) && content.some((block) => block.type === "image") &&
|
|
66
|
+
!previewed.has(entry.id) && pi.getSettings().terminal?.showImages !== false) {
|
|
67
|
+
pi.appendEntry(PREVIEW_TYPE, { messageId: entry.id });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
pendingAfter = undefined;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pi.registerEntryRenderer(PREVIEW_TYPE, function renderPreview(entry, options, theme): Component | undefined {
|
|
74
|
+
if (retired) return;
|
|
75
|
+
const id = messageId(entry.data);
|
|
76
|
+
const terminal = pi.getSettings().terminal;
|
|
77
|
+
if (!id || terminal?.showImages === false) return;
|
|
78
|
+
if (!sessionManager) {
|
|
79
|
+
// /reload rebuilds history before session_start. Returning undefined
|
|
80
|
+
// here makes Pi discard this entry; retain it and resolve on render.
|
|
81
|
+
let content: Component | undefined;
|
|
82
|
+
return {
|
|
83
|
+
render(width) {
|
|
84
|
+
if (retired) return [];
|
|
85
|
+
if (sessionManager) content ??= renderPreview(entry, options, theme);
|
|
86
|
+
return content?.render(width) ?? [];
|
|
87
|
+
},
|
|
88
|
+
handleMouse: (event) => retired ? undefined : content?.handleMouse?.(event),
|
|
89
|
+
invalidate: () => { if (!retired) content?.invalidate(); },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const source = sessionManager.getEntry(id);
|
|
93
|
+
if (source?.type !== "message" || source.message.role !== "user") return;
|
|
94
|
+
const content = source.message.content;
|
|
95
|
+
const images = Array.isArray(content) ? content.filter((block) => block.type === "image") : [];
|
|
96
|
+
if (images.length === 0) return;
|
|
97
|
+
|
|
98
|
+
// Keep UI state outside the component: Pi recreates it on invalidation and Ctrl+O.
|
|
99
|
+
let state = disclosures.get(entry.id);
|
|
100
|
+
if (!state) {
|
|
101
|
+
state = { images: new Set(), expanded: options.expanded };
|
|
102
|
+
disclosures.set(entry.id, state);
|
|
103
|
+
if (options.expanded) images.forEach((_image, index) => state!.images.add(index));
|
|
104
|
+
} else if (state.expanded !== options.expanded) {
|
|
105
|
+
state.expanded = options.expanded;
|
|
106
|
+
state.images.clear();
|
|
107
|
+
if (options.expanded) images.forEach((_image, index) => state!.images.add(index));
|
|
108
|
+
}
|
|
109
|
+
const disclosure = state;
|
|
110
|
+
const previews = images.map((image) => {
|
|
111
|
+
const dimensions = getImageDimensions(image.data, image.mimeType);
|
|
112
|
+
// Native Image fits to available columns; cap at natural width to avoid upscaling.
|
|
113
|
+
const naturalWidth = dimensions
|
|
114
|
+
? Math.max(1, Math.floor(dimensions.widthPx / getCellDimensions().widthPx)) : 60;
|
|
115
|
+
return {
|
|
116
|
+
dimensions,
|
|
117
|
+
image: new Image(image.data, image.mimeType, {
|
|
118
|
+
fallbackColor: (text) => theme.fg("dim", text),
|
|
119
|
+
}, {
|
|
120
|
+
maxWidthCells: Math.min(naturalWidth, terminal?.imageWidthCells ?? naturalWidth),
|
|
121
|
+
maxHeightCells: Number.MAX_SAFE_INTEGER, // Do not shrink tall images into a square.
|
|
122
|
+
}, dimensions ?? undefined),
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
let headers = new Map<number, number>();
|
|
126
|
+
let renderedWidth = 0;
|
|
127
|
+
let renderedHeight = 0;
|
|
128
|
+
const preview = {
|
|
129
|
+
render(width: number): string[] {
|
|
130
|
+
headers = new Map();
|
|
131
|
+
renderedWidth = width;
|
|
132
|
+
renderedHeight = 0;
|
|
133
|
+
if (retired || width < 1 || pi.getSettings().terminal?.showImages === false) return [];
|
|
134
|
+
const lines: string[] = [];
|
|
135
|
+
for (const [index, child] of previews.entries()) {
|
|
136
|
+
const open = disclosure.images.has(index);
|
|
137
|
+
const size = child.dimensions;
|
|
138
|
+
headers.set(lines.length, index);
|
|
139
|
+
// nf-fa-file_image
|
|
140
|
+
lines.push(theme.fg("dim", truncateToWidth(`${open ? "\uf0d7" : "\uf0da"} \uf1c5 Image #${index + 1}${size ? ` · ${size.widthPx}×${size.heightPx}` : ""}`, width, "")));
|
|
141
|
+
// Native Image owns sizing, colors, protocol payloads and cursor positioning.
|
|
142
|
+
if (open) lines.push(...child.image.render(width));
|
|
143
|
+
}
|
|
144
|
+
renderedHeight = lines.length;
|
|
145
|
+
return lines;
|
|
146
|
+
},
|
|
147
|
+
handleMouse(event: TuiMouseEvent) {
|
|
148
|
+
if (retired || event.type !== "click" || event.button !== "left" ||
|
|
149
|
+
event.x < 0 || event.x >= renderedWidth || event.y < 0 || event.y >= renderedHeight) return;
|
|
150
|
+
const index = headers.get(event.y);
|
|
151
|
+
if (index !== undefined) {
|
|
152
|
+
if (disclosure.images.has(index)) disclosure.images.delete(index);
|
|
153
|
+
else disclosure.images.add(index);
|
|
154
|
+
}
|
|
155
|
+
if (index !== undefined) preview.invalidate();
|
|
156
|
+
// EntryRenderer has no injected TUI context. The mouse-result contract
|
|
157
|
+
// asks the host to requestRender without capturing selection drags/wheels.
|
|
158
|
+
return { handled: true, render: index !== undefined };
|
|
159
|
+
},
|
|
160
|
+
invalidate() {
|
|
161
|
+
headers.clear();
|
|
162
|
+
renderedHeight = 0;
|
|
163
|
+
if (!retired) for (const child of previews) child.image.invalidate();
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
return preview;
|
|
167
|
+
});
|
|
168
|
+
}
|