@rose42/t3-feedback 0.1.1 → 0.1.2
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/README.md +62 -28
- package/dist/bridge/http.d.ts +7 -2
- package/dist/bridge/http.js +41 -1
- package/dist/bridge/index.d.ts +5 -3
- package/dist/bridge/index.js +4 -2
- package/dist/bridge/launchEditor.d.ts +21 -0
- package/dist/bridge/launchEditor.js +139 -0
- package/dist/bridge/paths.d.ts +2 -0
- package/dist/bridge/paths.js +2 -0
- package/dist/bridge/readSource.js +2 -0
- package/dist/bridge/sendFeedback.d.ts +17 -1
- package/dist/bridge/sendFeedback.js +23 -6
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/mount.js +50 -12
- package/dist/client/ui/backdropAway.d.ts +2 -0
- package/dist/client/ui/backdropAway.js +12 -0
- package/dist/client/ui/elementTargetChip.d.ts +13 -4
- package/dist/client/ui/elementTargetChip.js +21 -7
- package/dist/client/ui/elementTargetPanelSession.js +6 -4
- package/dist/client/ui/screenshotPanelSession.js +36 -28
- package/dist/client/ui/sourcePathPrefix.d.ts +12 -0
- package/dist/client/ui/sourcePathPrefix.js +39 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/plugin.d.ts +6 -1
- package/dist/plugin.js +71 -4
- package/dist/types.d.ts +49 -3
- package/dist/types.js +47 -0
- package/docs/devcontainer.md +2 -0
- package/package.json +11 -3
package/dist/client/mount.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { captureFrameBurst, captureScreenshot, createSourceResolver, initFeedbackCapture, } from "@rose42/feedback-capture";
|
|
2
2
|
import { T3_FEEDBACK_CLOSE_EVENT, T3_FEEDBACK_OPEN_EVENT } from "../controls.js";
|
|
3
3
|
import { splitThreadTitleReportType } from "../bridge/format.js";
|
|
4
|
-
import { formatShortcutLabel, resolveActivePlugins, resolveFabConfig, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, } from "../types.js";
|
|
4
|
+
import { formatShortcutLabel, resolveActivePlugins, resolveFabConfig, resolveOpenInEditorEndpointForApi, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, } from "../types.js";
|
|
5
5
|
import { openInT3Seamless, shouldBypassSeamlessOpen } from "./openInT3.js";
|
|
6
6
|
import { ACTIVE_THREAD_POLL_MS, clearActiveThreads, listActiveThreads, removeActiveThread, removeActiveThreads, upsertActiveThread, } from "./activeThreads.js";
|
|
7
7
|
import { abortScreenshotRegions } from "./cropScreenshot.js";
|
|
@@ -14,6 +14,7 @@ import { createActionRegistry, createAfterPickRegistry, createBusyRegistry, crea
|
|
|
14
14
|
import { createCommentPanelPlugin, createReportTypePanelPlugin } from "./ui/commentPanelPlugin.js";
|
|
15
15
|
import { createCollectOnlyBuiltinPlugins, resolveAllPanelUiContributions, } from "./ui/defaultPlugins.js";
|
|
16
16
|
import { createElementTargetPanelPlugin } from "./ui/elementTargetPanelPlugin.js";
|
|
17
|
+
import { prefixSourceEnrichment } from "./ui/sourcePathPrefix.js";
|
|
17
18
|
import { asPluginsWithUi } from "./ui/resolveContributions.js";
|
|
18
19
|
import { createScreenshotPanelPlugin } from "./ui/screenshotPanelPlugin.js";
|
|
19
20
|
import { mountSlotContributions } from "./ui/slots.js";
|
|
@@ -275,6 +276,9 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
275
276
|
display: flex; align-items: center; justify-content: center;
|
|
276
277
|
padding: 16px;
|
|
277
278
|
}
|
|
279
|
+
/* Author display:flex beats UA [hidden]; pick/capture set hidden while the overlay is down. */
|
|
280
|
+
#${rootId} .t3f-backdrop[hidden],
|
|
281
|
+
#${rootId} .t3f-backdrop.t3f-away { display: none !important; }
|
|
278
282
|
#${rootId} .t3f-panel {
|
|
279
283
|
position: relative;
|
|
280
284
|
z-index: 1;
|
|
@@ -367,6 +371,8 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
367
371
|
#${rootId} .t3f-section {
|
|
368
372
|
display: grid; gap: 8px; min-width: 0; max-width: 100%;
|
|
369
373
|
}
|
|
374
|
+
/* Author display:grid beats UA [hidden] — sections start closed and clear must hide them. */
|
|
375
|
+
#${rootId} .t3f-section[hidden] { display: none !important; }
|
|
370
376
|
#${rootId} .t3f-section-head {
|
|
371
377
|
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
372
378
|
min-width: 0;
|
|
@@ -457,6 +463,7 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
457
463
|
display: flex; flex-wrap: nowrap; align-items: center; gap: 10px;
|
|
458
464
|
min-width: 0;
|
|
459
465
|
}
|
|
466
|
+
#${rootId} .t3f-clipboard-offer[hidden] { display: none !important; }
|
|
460
467
|
#${rootId} .t3f-clipboard-preview-btn {
|
|
461
468
|
flex: 0 0 auto;
|
|
462
469
|
padding: 0; margin: 0; border: none; background: transparent;
|
|
@@ -487,6 +494,7 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
487
494
|
#${rootId} .t3f-preview-wrap {
|
|
488
495
|
display: grid; gap: 8px; min-width: 0;
|
|
489
496
|
}
|
|
497
|
+
#${rootId} .t3f-preview-wrap[hidden] { display: none !important; }
|
|
490
498
|
#${rootId} .t3f-gallery {
|
|
491
499
|
display: flex; flex-wrap: nowrap; gap: 8px; min-width: 0;
|
|
492
500
|
}
|
|
@@ -523,12 +531,21 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
523
531
|
}
|
|
524
532
|
#${rootId} .t3f-thumb-tools {
|
|
525
533
|
position: absolute; top: 2px; right: 2px; display: flex; gap: 2px;
|
|
526
|
-
opacity: 0;
|
|
534
|
+
opacity: 0;
|
|
527
535
|
transition: opacity 0.12s ease;
|
|
528
536
|
}
|
|
529
537
|
#${rootId} .t3f-thumb:hover .t3f-thumb-tools,
|
|
530
538
|
#${rootId} .t3f-thumb:focus-within .t3f-thumb-tools {
|
|
531
|
-
opacity: 1;
|
|
539
|
+
opacity: 1;
|
|
540
|
+
}
|
|
541
|
+
/* Keep tools clickable while the pointer moves onto them (avoid pointer-events:none traps). */
|
|
542
|
+
#${rootId} .t3f-thumb-tools {
|
|
543
|
+
pointer-events: none;
|
|
544
|
+
}
|
|
545
|
+
#${rootId} .t3f-thumb:hover .t3f-thumb-tools,
|
|
546
|
+
#${rootId} .t3f-thumb:focus-within .t3f-thumb-tools,
|
|
547
|
+
#${rootId} .t3f-thumb-tools:focus-within {
|
|
548
|
+
pointer-events: auto;
|
|
532
549
|
}
|
|
533
550
|
@media (hover: none) {
|
|
534
551
|
#${rootId} .t3f-thumb-tools {
|
|
@@ -786,6 +803,8 @@ ${mobileOnly}#${rootId} .t3f-backdrop {
|
|
|
786
803
|
min-width: 0;
|
|
787
804
|
transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
|
788
805
|
}
|
|
806
|
+
/* Author display:inline-flex beats UA [hidden] — send XOR (solo vs New/Continue). */
|
|
807
|
+
#${rootId} button.t3f-btn[hidden] { display: none !important; }
|
|
789
808
|
#${rootId} button.t3f-btn:hover:not(:disabled) {
|
|
790
809
|
background: #334155; border-color: #38bdf8;
|
|
791
810
|
}
|
|
@@ -941,10 +960,16 @@ export function mountT3Feedback(options = {}) {
|
|
|
941
960
|
return noopHandle();
|
|
942
961
|
const rootId = options.rootId ?? "t3-feedback-root";
|
|
943
962
|
const shortcut = resolveShortcut(options.shortcut, options.shortcutKey);
|
|
944
|
-
const
|
|
963
|
+
const endpoint = options.endpoint ?? "/__t3-feedback";
|
|
964
|
+
const pickConfig = (() => {
|
|
965
|
+
const resolved = resolvePickConfig(options.pick);
|
|
966
|
+
return {
|
|
967
|
+
...resolved,
|
|
968
|
+
openInEditor: resolveOpenInEditorEndpointForApi(resolved.openInEditor, endpoint),
|
|
969
|
+
};
|
|
970
|
+
})();
|
|
945
971
|
const screenshotConfig = resolveScreenshotConfig(options.screenshot, pickConfig.cropPaddingPx);
|
|
946
972
|
const recordConfig = resolveRecordConfig(options.record);
|
|
947
|
-
const endpoint = options.endpoint ?? "/__t3-feedback";
|
|
948
973
|
const activePluginSet = resolveActivePlugins(options.activePlugins, options.includeConsoleLogs);
|
|
949
974
|
const pageContextActive = activePluginSet.has("pageContext");
|
|
950
975
|
const consoleLogsActive = activePluginSet.has("consoleLogs");
|
|
@@ -1030,13 +1055,20 @@ export function mountT3Feedback(options = {}) {
|
|
|
1030
1055
|
}
|
|
1031
1056
|
return hostRef.current;
|
|
1032
1057
|
};
|
|
1033
|
-
const
|
|
1058
|
+
const resolveSourceBase = createSourceResolver({
|
|
1034
1059
|
framework: pickConfig.sourceFramework,
|
|
1035
1060
|
sourceEndpoint: endpoint,
|
|
1036
1061
|
...(options.pick && "resolveSource" in options.pick && options.pick.resolveSource
|
|
1037
1062
|
? { resolveSource: options.pick.resolveSource }
|
|
1038
1063
|
: {}),
|
|
1039
1064
|
});
|
|
1065
|
+
const sourcePathPrefix = pickConfig.sourcePathPrefix;
|
|
1066
|
+
const resolveSource = resolveSourceBase && sourcePathPrefix
|
|
1067
|
+
? async (el) => {
|
|
1068
|
+
const hit = await resolveSourceBase(el);
|
|
1069
|
+
return hit ? prefixSourceEnrichment(hit, sourcePathPrefix) : hit;
|
|
1070
|
+
}
|
|
1071
|
+
: resolveSourceBase;
|
|
1040
1072
|
const commentPanel = createCommentPanelPlugin({ copy });
|
|
1041
1073
|
const reportTypeHintCaps = {
|
|
1042
1074
|
pageContext: pageContextActive,
|
|
@@ -2382,14 +2414,20 @@ export function mountT3FeedbackFromConfig(config, customPlugins = []) {
|
|
|
2382
2414
|
maxInnerHTMLLength: config.pick.maxInnerHTMLLength,
|
|
2383
2415
|
styles: config.pick.styles,
|
|
2384
2416
|
sourceFramework: config.pick.sourceFramework,
|
|
2417
|
+
...(config.pick.sourcePathPrefix ? { sourcePathPrefix: config.pick.sourcePathPrefix } : {}),
|
|
2385
2418
|
openInEditor: config.pick.openInEditor === null
|
|
2386
2419
|
? false
|
|
2387
|
-
:
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2420
|
+
: (() => {
|
|
2421
|
+
const rewritten = resolveOpenInEditorEndpointForApi(config.pick.openInEditor, config.endpoint);
|
|
2422
|
+
if (!rewritten)
|
|
2423
|
+
return false;
|
|
2424
|
+
return rewritten.urlTemplate
|
|
2425
|
+
? {
|
|
2426
|
+
endpoint: rewritten.endpoint,
|
|
2427
|
+
urlTemplate: rewritten.urlTemplate,
|
|
2428
|
+
}
|
|
2429
|
+
: { endpoint: rewritten.endpoint };
|
|
2430
|
+
})(),
|
|
2393
2431
|
},
|
|
2394
2432
|
screenshot: {
|
|
2395
2433
|
...(config.screenshot.shortcut === null
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Hide/show the compose backdrop during pick / capture / record. */
|
|
2
|
+
export function setBackdropAway(backdrop, away) {
|
|
3
|
+
backdrop.hidden = away;
|
|
4
|
+
backdrop.classList.toggle("t3f-away", away);
|
|
5
|
+
// Inline !important — author `display:flex` on `.t3f-backdrop` otherwise wins over UA [hidden].
|
|
6
|
+
if (away) {
|
|
7
|
+
backdrop.style.setProperty("display", "none", "important");
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
backdrop.style.removeProperty("display");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -29,23 +29,31 @@ export declare function formatComponentLocation(loc: {
|
|
|
29
29
|
}): string;
|
|
30
30
|
/**
|
|
31
31
|
* Build the URL used to open a source location.
|
|
32
|
-
* - `urlTemplate` → navigate (IDE protocol / custom)
|
|
33
|
-
* - else →
|
|
32
|
+
* - `urlTemplate` → navigate (IDE protocol / custom); uses the displayed path
|
|
33
|
+
* - else → GET endpoint with `?file=` (Vite `/__open-in-editor` or the bridge
|
|
34
|
+
* `/open-editor`). Strips `sourcePathPrefix` only for Vite's native endpoint,
|
|
35
|
+
* which resolves against the app cwd; the bridge expects workspace-relative paths.
|
|
34
36
|
*/
|
|
35
37
|
export declare function buildOpenInEditorUrl(loc: {
|
|
36
38
|
fileName: string;
|
|
37
39
|
line: number;
|
|
38
40
|
column?: number;
|
|
39
|
-
}, config: T3FeedbackOpenInEditorConfig
|
|
41
|
+
}, config: T3FeedbackOpenInEditorConfig, options?: {
|
|
42
|
+
sourcePathPrefix?: string;
|
|
43
|
+
}): {
|
|
40
44
|
kind: "navigate" | "fetch";
|
|
41
45
|
url: string;
|
|
42
46
|
};
|
|
47
|
+
/** True for Vite's built-in launcher (resolves paths against the Vite project root). */
|
|
48
|
+
export declare function isViteNativeOpenInEditorEndpoint(endpoint: string): boolean;
|
|
43
49
|
/** Open a resolved component location in the IDE (best-effort; never throws). */
|
|
44
50
|
export declare function openSourceInEditor(loc: {
|
|
45
51
|
fileName: string;
|
|
46
52
|
line: number;
|
|
47
53
|
column?: number;
|
|
48
|
-
}, config: T3FeedbackOpenInEditorConfig, fetchFn?: typeof fetch
|
|
54
|
+
}, config: T3FeedbackOpenInEditorConfig, fetchFn?: typeof fetch, options?: {
|
|
55
|
+
sourcePathPrefix?: string;
|
|
56
|
+
}): Promise<void>;
|
|
49
57
|
/** Split a `>`-joined CSS path into segments (trim empties). */
|
|
50
58
|
export declare function splitCssSelectorParts(selector: string): string[];
|
|
51
59
|
/**
|
|
@@ -61,4 +69,5 @@ export declare function formatElementChip(target: ElementChipTarget): string;
|
|
|
61
69
|
export declare function buildTargetChipHtml(target: ElementChipTarget, options?: {
|
|
62
70
|
openInEditor?: T3FeedbackOpenInEditorConfig | null;
|
|
63
71
|
openInEditorLabel?: string;
|
|
72
|
+
sourcePathPrefix?: string;
|
|
64
73
|
}): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { rankSourceHierarchy } from "@rose42/feedback-capture";
|
|
2
2
|
import { escapeHtml } from "./html.js";
|
|
3
|
+
import { stripSourcePathPrefix } from "./sourcePathPrefix.js";
|
|
3
4
|
function asLoc(loc) {
|
|
4
5
|
return loc;
|
|
5
6
|
}
|
|
@@ -57,10 +58,12 @@ export function formatComponentLocation(loc) {
|
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
59
60
|
* Build the URL used to open a source location.
|
|
60
|
-
* - `urlTemplate` → navigate (IDE protocol / custom)
|
|
61
|
-
* - else →
|
|
61
|
+
* - `urlTemplate` → navigate (IDE protocol / custom); uses the displayed path
|
|
62
|
+
* - else → GET endpoint with `?file=` (Vite `/__open-in-editor` or the bridge
|
|
63
|
+
* `/open-editor`). Strips `sourcePathPrefix` only for Vite's native endpoint,
|
|
64
|
+
* which resolves against the app cwd; the bridge expects workspace-relative paths.
|
|
62
65
|
*/
|
|
63
|
-
export function buildOpenInEditorUrl(loc, config) {
|
|
66
|
+
export function buildOpenInEditorUrl(loc, config, options) {
|
|
64
67
|
const column = typeof loc.column === "number" && Number.isFinite(loc.column)
|
|
65
68
|
? Math.max(1, Math.floor(loc.column))
|
|
66
69
|
: 1;
|
|
@@ -72,16 +75,25 @@ export function buildOpenInEditorUrl(loc, config) {
|
|
|
72
75
|
.replaceAll("{column}", String(column));
|
|
73
76
|
return { kind: "navigate", url };
|
|
74
77
|
}
|
|
75
|
-
const
|
|
78
|
+
const stripForViteNative = Boolean(options?.sourcePathPrefix) && isViteNativeOpenInEditorEndpoint(config.endpoint);
|
|
79
|
+
const fileForEditor = stripForViteNative && options?.sourcePathPrefix
|
|
80
|
+
? stripSourcePathPrefix(loc.fileName, options.sourcePathPrefix)
|
|
81
|
+
: loc.fileName;
|
|
82
|
+
const fileParam = `${fileForEditor}:${line}:${column}`;
|
|
76
83
|
const sep = config.endpoint.includes("?") ? "&" : "?";
|
|
77
84
|
return {
|
|
78
85
|
kind: "fetch",
|
|
79
86
|
url: `${config.endpoint}${sep}file=${encodeURIComponent(fileParam)}`,
|
|
80
87
|
};
|
|
81
88
|
}
|
|
89
|
+
/** True for Vite's built-in launcher (resolves paths against the Vite project root). */
|
|
90
|
+
export function isViteNativeOpenInEditorEndpoint(endpoint) {
|
|
91
|
+
const pathOnly = endpoint.split("?")[0] ?? endpoint;
|
|
92
|
+
return pathOnly === "/__open-in-editor" || pathOnly.endsWith("/__open-in-editor");
|
|
93
|
+
}
|
|
82
94
|
/** Open a resolved component location in the IDE (best-effort; never throws). */
|
|
83
|
-
export async function openSourceInEditor(loc, config, fetchFn = fetch) {
|
|
84
|
-
const built = buildOpenInEditorUrl(loc, config);
|
|
95
|
+
export async function openSourceInEditor(loc, config, fetchFn = fetch, options) {
|
|
96
|
+
const built = buildOpenInEditorUrl(loc, config, options);
|
|
85
97
|
try {
|
|
86
98
|
if (built.kind === "navigate") {
|
|
87
99
|
window.location.href = built.url;
|
|
@@ -136,7 +148,9 @@ function buildOpenableLocHtml(loc, options) {
|
|
|
136
148
|
? { column: loc.column }
|
|
137
149
|
: {}),
|
|
138
150
|
};
|
|
139
|
-
const built = buildOpenInEditorUrl(locAttrs, openConfig
|
|
151
|
+
const built = buildOpenInEditorUrl(locAttrs, openConfig, {
|
|
152
|
+
...(options?.sourcePathPrefix ? { sourcePathPrefix: options.sourcePathPrefix } : {}),
|
|
153
|
+
});
|
|
140
154
|
if (built.kind === "navigate") {
|
|
141
155
|
return `<a class="t3f-target-file" href="${escapeHtml(built.url)}" title="${openLabel}" aria-label="${openLabel}: ${text}">${text}</a>`;
|
|
142
156
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { collectElementTargetAsync, createElementTargetPlugin, } from "@rose42/feedback-capture";
|
|
2
|
+
import { setBackdropAway } from "./backdropAway.js";
|
|
2
3
|
import { buildTargetChipHtml, formatElementChip, openSourceInEditor, selectorAtAncestorDepth, } from "./elementTargetChip.js";
|
|
3
4
|
const PICK_DETAILS_STORAGE_KEY = "t3-feedback:pick-details";
|
|
4
5
|
export function readPickDetailsPrefs(fallback) {
|
|
@@ -99,6 +100,7 @@ export function bindElementTargetPanelSession(options) {
|
|
|
99
100
|
targetChip.innerHTML = buildTargetChipHtml(target, {
|
|
100
101
|
openInEditor: pickConfig.openInEditor,
|
|
101
102
|
openInEditorLabel: copy.openInEditorLabel,
|
|
103
|
+
...(pickConfig.sourcePathPrefix ? { sourcePathPrefix: pickConfig.sourcePathPrefix } : {}),
|
|
102
104
|
});
|
|
103
105
|
targetChip.title = chip;
|
|
104
106
|
targetBlock.hidden = false;
|
|
@@ -171,7 +173,7 @@ export function bindElementTargetPanelSession(options) {
|
|
|
171
173
|
fileName,
|
|
172
174
|
line,
|
|
173
175
|
...(typeof column === "number" && Number.isFinite(column) ? { column } : {}),
|
|
174
|
-
}, pickConfig.openInEditor);
|
|
176
|
+
}, pickConfig.openInEditor, fetch, pickConfig.sourcePathPrefix ? { sourcePathPrefix: pickConfig.sourcePathPrefix } : undefined);
|
|
175
177
|
});
|
|
176
178
|
targetChip.addEventListener("pointerover", (event) => {
|
|
177
179
|
const target = elementPlugin.getTarget();
|
|
@@ -213,7 +215,7 @@ export function bindElementTargetPanelSession(options) {
|
|
|
213
215
|
});
|
|
214
216
|
const runPickFlow = async () => {
|
|
215
217
|
const releasePicking = registerBusy("picking");
|
|
216
|
-
backdrop
|
|
218
|
+
setBackdropAway(backdrop, true);
|
|
217
219
|
setStatus(copy.pickingStatus);
|
|
218
220
|
try {
|
|
219
221
|
const details = readPickDetailsFromUi();
|
|
@@ -225,7 +227,7 @@ export function bindElementTargetPanelSession(options) {
|
|
|
225
227
|
});
|
|
226
228
|
if (!isOpen())
|
|
227
229
|
return;
|
|
228
|
-
backdrop
|
|
230
|
+
setBackdropAway(backdrop, false);
|
|
229
231
|
if (!picked) {
|
|
230
232
|
setStatus(copy.pickCancelledStatus);
|
|
231
233
|
focusComment();
|
|
@@ -243,7 +245,7 @@ export function bindElementTargetPanelSession(options) {
|
|
|
243
245
|
finally {
|
|
244
246
|
releasePicking();
|
|
245
247
|
if (isOpen())
|
|
246
|
-
backdrop
|
|
248
|
+
setBackdropAway(backdrop, false);
|
|
247
249
|
}
|
|
248
250
|
};
|
|
249
251
|
form.querySelector('[data-act="clear-pick"]')?.addEventListener("click", () => {
|
|
@@ -2,6 +2,7 @@ import { attachImagePasteHandler, captureFrameBurst, captureScreenshot, cropData
|
|
|
2
2
|
import { selectScreenshotRegion } from "../cropScreenshot.js";
|
|
3
3
|
import { readClipboardImageDataUrl } from "../readClipboardImage.js";
|
|
4
4
|
import { selectBurstFrames } from "../selectBurstFrames.js";
|
|
5
|
+
import { setBackdropAway } from "./backdropAway.js";
|
|
5
6
|
import { CLOSE_ICON_SVG, CROP_ICON_SVG, escapeHtml } from "./html.js";
|
|
6
7
|
function loadImageNaturalSize(dataUrl) {
|
|
7
8
|
return new Promise((resolve, reject) => {
|
|
@@ -252,7 +253,7 @@ export function bindScreenshotPanelSession(options) {
|
|
|
252
253
|
return;
|
|
253
254
|
}
|
|
254
255
|
const releaseRecording = registerBusy("recording");
|
|
255
|
-
backdrop
|
|
256
|
+
setBackdropAway(backdrop, true);
|
|
256
257
|
setStatus(copy.recordingStatus);
|
|
257
258
|
hideClipboardOffer();
|
|
258
259
|
const overlay = document.createElement("div");
|
|
@@ -280,7 +281,7 @@ export function bindScreenshotPanelSession(options) {
|
|
|
280
281
|
overlay.remove();
|
|
281
282
|
if (!isOpen())
|
|
282
283
|
return;
|
|
283
|
-
backdrop
|
|
284
|
+
setBackdropAway(backdrop, false);
|
|
284
285
|
if (!frames || frames.length === 0) {
|
|
285
286
|
setStatus(copy.recordFailedStatus, "err");
|
|
286
287
|
return;
|
|
@@ -315,7 +316,7 @@ export function bindScreenshotPanelSession(options) {
|
|
|
315
316
|
overlay.remove();
|
|
316
317
|
releaseRecording();
|
|
317
318
|
if (isOpen())
|
|
318
|
-
backdrop
|
|
319
|
+
setBackdropAway(backdrop, false);
|
|
319
320
|
}
|
|
320
321
|
};
|
|
321
322
|
const insertClipboardOffer = async () => {
|
|
@@ -325,34 +326,40 @@ export function bindScreenshotPanelSession(options) {
|
|
|
325
326
|
hideClipboardOffer();
|
|
326
327
|
await attachScreenshot(dataUrl, copy.pastedAttachedStatus, "direct");
|
|
327
328
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
329
|
+
// Delegate so clear/dismiss keep working if slot hosts remount or icons swallow hits.
|
|
330
|
+
const onFormClick = (event) => {
|
|
331
|
+
const hit = event.target?.closest?.("[data-act]");
|
|
332
|
+
if (!hit || !form.contains(hit))
|
|
333
|
+
return;
|
|
334
|
+
const act = hit.getAttribute("data-act");
|
|
335
|
+
if (act === "clear-shot") {
|
|
336
|
+
event.preventDefault();
|
|
337
|
+
clearGallery();
|
|
338
|
+
setStatus("");
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (act === "clipboard-dismiss") {
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
hideClipboardOffer();
|
|
344
|
+
syncGallery();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (act === "shot") {
|
|
348
|
+
event.preventDefault();
|
|
334
349
|
void runShotFlow();
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (act === "record") {
|
|
353
|
+
event.preventDefault();
|
|
339
354
|
void runRecordFlow();
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
form.querySelector('[data-act="clipboard-dismiss"]')?.addEventListener("click", () => {
|
|
343
|
-
hideClipboardOffer();
|
|
344
|
-
});
|
|
345
|
-
form.querySelectorAll('[data-act="clipboard-insert"]').forEach((el) => {
|
|
346
|
-
el.addEventListener("click", () => {
|
|
347
|
-
void insertClipboardOffer();
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
galleryEl.addEventListener("click", (event) => {
|
|
351
|
-
const hit = event.target?.closest?.("button.t3f-thumb-clipboard");
|
|
352
|
-
if (!hit || !galleryEl.contains(hit))
|
|
353
355
|
return;
|
|
354
|
-
|
|
355
|
-
|
|
356
|
+
}
|
|
357
|
+
if (act === "clipboard-insert") {
|
|
358
|
+
event.preventDefault();
|
|
359
|
+
void insertClipboardOffer();
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
form.addEventListener("click", onFormClick);
|
|
356
363
|
const detachPaste = attachImagePasteHandler(form, (dataUrl) => {
|
|
357
364
|
hideClipboardOffer();
|
|
358
365
|
void attachScreenshot(dataUrl, copy.pastedAttachedStatus, "direct");
|
|
@@ -429,6 +436,7 @@ export function bindScreenshotPanelSession(options) {
|
|
|
429
436
|
}
|
|
430
437
|
return {
|
|
431
438
|
dispose: () => {
|
|
439
|
+
form.removeEventListener("click", onFormClick);
|
|
432
440
|
detachAfterPick?.();
|
|
433
441
|
detachPaste();
|
|
434
442
|
},
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ElementSourceEnrichment } from "@rose42/feedback-capture";
|
|
2
|
+
import { normalizePickSourcePathPrefix } from "../../types.js";
|
|
3
|
+
export { normalizePickSourcePathPrefix as normalizeSourcePathPrefix };
|
|
4
|
+
/** Prefix an app-relative file path when it is not already under `prefix`. */
|
|
5
|
+
export declare function prefixSourceFileName(fileName: string, prefix: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Strip a previously applied prefix (for Vite `/__open-in-editor`, which resolves
|
|
8
|
+
* against the app cwd rather than the monorepo / workspace root).
|
|
9
|
+
*/
|
|
10
|
+
export declare function stripSourcePathPrefix(fileName: string, prefix: string): string;
|
|
11
|
+
/** Prefix component / leaf / owners file names on a source enrichment. */
|
|
12
|
+
export declare function prefixSourceEnrichment(enrichment: ElementSourceEnrichment, prefix: string): ElementSourceEnrichment;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { normalizePickSourcePathPrefix } from "../../types.js";
|
|
2
|
+
export { normalizePickSourcePathPrefix as normalizeSourcePathPrefix };
|
|
3
|
+
/** Prefix an app-relative file path when it is not already under `prefix`. */
|
|
4
|
+
export function prefixSourceFileName(fileName, prefix) {
|
|
5
|
+
const file = fileName.replace(/\\/g, "/").trim();
|
|
6
|
+
if (!file || file.startsWith("/") || /^[a-zA-Z]:\//.test(file))
|
|
7
|
+
return fileName;
|
|
8
|
+
if (file === prefix || file.startsWith(`${prefix}/`))
|
|
9
|
+
return file;
|
|
10
|
+
return `${prefix}/${file.replace(/^\/+/, "")}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Strip a previously applied prefix (for Vite `/__open-in-editor`, which resolves
|
|
14
|
+
* against the app cwd rather than the monorepo / workspace root).
|
|
15
|
+
*/
|
|
16
|
+
export function stripSourcePathPrefix(fileName, prefix) {
|
|
17
|
+
const file = fileName.replace(/\\/g, "/");
|
|
18
|
+
const p = prefix.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
19
|
+
if (file === p)
|
|
20
|
+
return fileName;
|
|
21
|
+
if (file.startsWith(`${p}/`))
|
|
22
|
+
return file.slice(p.length + 1);
|
|
23
|
+
return fileName;
|
|
24
|
+
}
|
|
25
|
+
function mapLoc(loc, prefix) {
|
|
26
|
+
return { ...loc, fileName: prefixSourceFileName(loc.fileName, prefix) };
|
|
27
|
+
}
|
|
28
|
+
/** Prefix component / leaf / owners file names on a source enrichment. */
|
|
29
|
+
export function prefixSourceEnrichment(enrichment, prefix) {
|
|
30
|
+
const out = { ...enrichment };
|
|
31
|
+
if (enrichment.component)
|
|
32
|
+
out.component = mapLoc(enrichment.component, prefix);
|
|
33
|
+
if (enrichment.leaf)
|
|
34
|
+
out.leaf = mapLoc(enrichment.leaf, prefix);
|
|
35
|
+
if (enrichment.owners) {
|
|
36
|
+
out.owners = enrichment.owners.map((loc) => mapLoc(loc, prefix));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { t3FeedbackPlugin, T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, default, } from "./plugin.js";
|
|
2
|
-
export type { FeedbackSendResult, ThreadListItem, ThreadProbeResult, ThreadProbeState, ThreadSettleResult, ThreadsListResponse, ThreadsProbeResponse, ThreadsSettleResponse, T3BuiltinPluginId, T3FeedbackAfterPick, T3FeedbackBuiltinPluginOptions, T3FeedbackClientConfig, T3FeedbackFabConfig, T3FeedbackFabOptions, T3FeedbackFabPosition, T3FeedbackFabVisibility, T3FeedbackOpenHandoff, T3FeedbackOpenInEditorConfig, T3FeedbackOpenInEditorOptions, T3FeedbackPickConfig, T3FeedbackPickOptions, T3FeedbackPluginOptions, T3FeedbackRecordConfig, T3FeedbackRecordOptions, T3FeedbackReportTypeGlyph, T3FeedbackReportTypeGlyphCustom, T3FeedbackReportTypeGlyphMap, T3FeedbackReportTypeGlyphResolved, T3FeedbackScreenshotConfig, T3FeedbackScreenshotCrop, T3FeedbackScreenshotOptions, T3FeedbackShortcutConfig, T3FeedbackShortcutOptions, T3FeedbackThreadReuse, } from "./types.js";
|
|
3
|
-
export { DEFAULT_FAB_CONFIG, DEFAULT_OPEN_IN_EDITOR_ENDPOINT, DEFAULT_PICK_SHORTCUT, DEFAULT_RECORD_SHORTCUT, DEFAULT_REPORT_TYPE_EMOJIS, DEFAULT_REPORT_TYPE_GLYPH, DEFAULT_SCREENSHOT_SHORTCUT, DEFAULT_SHORTCUT, T3_BUILTIN_PLUGIN_IDS, formatShortcutLabel, isEditableKeyboardTarget, matchesBareKeyOverride, matchesShortcut, resolveActivePluginList, resolveActivePlugins, resolveFabConfig, resolveOpenInEditorConfig, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, shortcutRequiresModifier, shouldOpenFromShortcut, } from "./types.js";
|
|
1
|
+
export { t3FeedbackPlugin, T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_OPEN_EDITOR_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, default, } from "./plugin.js";
|
|
2
|
+
export type { FeedbackSendResult, ThreadListItem, ThreadProbeResult, ThreadProbeState, ThreadSettleResult, ThreadsListResponse, ThreadsProbeResponse, ThreadsSettleResponse, T3BuiltinPluginId, T3FeedbackAfterPick, T3FeedbackBuiltinPluginOptions, T3FeedbackClientConfig, T3FeedbackFabConfig, T3FeedbackFabOptions, T3FeedbackFabPosition, T3FeedbackFabVisibility, T3FeedbackModelSelection, T3FeedbackOpenHandoff, T3FeedbackOpenInEditorConfig, T3FeedbackOpenInEditorOptions, T3FeedbackPickConfig, T3FeedbackPickOptions, T3FeedbackPluginOptions, T3FeedbackRecordConfig, T3FeedbackRecordOptions, T3FeedbackReportTypeGlyph, T3FeedbackReportTypeGlyphCustom, T3FeedbackReportTypeGlyphMap, T3FeedbackReportTypeGlyphResolved, T3FeedbackScreenshotConfig, T3FeedbackScreenshotCrop, T3FeedbackScreenshotOptions, T3FeedbackShortcutConfig, T3FeedbackShortcutOptions, T3FeedbackThreadReuse, } from "./types.js";
|
|
3
|
+
export { DEFAULT_FAB_CONFIG, DEFAULT_MODEL_SELECTION, DEFAULT_OPEN_IN_EDITOR_ENDPOINT, DEFAULT_PICK_SHORTCUT, DEFAULT_RECORD_SHORTCUT, DEFAULT_REPORT_TYPE_EMOJIS, DEFAULT_REPORT_TYPE_GLYPH, DEFAULT_SCREENSHOT_SHORTCUT, DEFAULT_SHORTCUT, T3_BUILTIN_PLUGIN_IDS, formatShortcutLabel, isEditableKeyboardTarget, matchesBareKeyOverride, matchesShortcut, normalizeModelSelection, resolveActivePluginList, resolveActivePlugins, resolveFabConfig, resolveOpenInEditorConfig, resolveOpenInEditorEndpointForApi, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, shortcutRequiresModifier, shouldOpenFromShortcut, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { t3FeedbackPlugin, T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, default, } from "./plugin.js";
|
|
2
|
-
export { DEFAULT_FAB_CONFIG, DEFAULT_OPEN_IN_EDITOR_ENDPOINT, DEFAULT_PICK_SHORTCUT, DEFAULT_RECORD_SHORTCUT, DEFAULT_REPORT_TYPE_EMOJIS, DEFAULT_REPORT_TYPE_GLYPH, DEFAULT_SCREENSHOT_SHORTCUT, DEFAULT_SHORTCUT, T3_BUILTIN_PLUGIN_IDS, formatShortcutLabel, isEditableKeyboardTarget, matchesBareKeyOverride, matchesShortcut, resolveActivePluginList, resolveActivePlugins, resolveFabConfig, resolveOpenInEditorConfig, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, shortcutRequiresModifier, shouldOpenFromShortcut, } from "./types.js";
|
|
1
|
+
export { t3FeedbackPlugin, T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_OPEN_EDITOR_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, default, } from "./plugin.js";
|
|
2
|
+
export { DEFAULT_FAB_CONFIG, DEFAULT_MODEL_SELECTION, DEFAULT_OPEN_IN_EDITOR_ENDPOINT, DEFAULT_PICK_SHORTCUT, DEFAULT_RECORD_SHORTCUT, DEFAULT_REPORT_TYPE_EMOJIS, DEFAULT_REPORT_TYPE_GLYPH, DEFAULT_SCREENSHOT_SHORTCUT, DEFAULT_SHORTCUT, T3_BUILTIN_PLUGIN_IDS, formatShortcutLabel, isEditableKeyboardTarget, matchesBareKeyOverride, matchesShortcut, normalizeModelSelection, resolveActivePluginList, resolveActivePlugins, resolveFabConfig, resolveOpenInEditorConfig, resolveOpenInEditorEndpointForApi, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, shortcutRequiresModifier, shouldOpenFromShortcut, } from "./types.js";
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import { type T3FeedbackPluginOptions } from "./types.js";
|
|
3
|
-
export { T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, } from "./bridge/paths.js";
|
|
3
|
+
export { T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_OPEN_EDITOR_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, } from "./bridge/paths.js";
|
|
4
4
|
export { parseFeedbackPost, parseOpenHandoffRequest, parseSettlePost, parseThreadProbeIds, } from "./bridge/parse.js";
|
|
5
5
|
/** Resolve a `customPlugins` entry against the Vite project root (bare ids stay bare). */
|
|
6
6
|
export declare function resolveCustomPluginModuleId(entry: string, root: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* When Vite root sits under a workspace hint, return the relative prefix
|
|
9
|
+
* (e.g. hint=`/repo`, root=`/repo/examples/vite-react` → `examples/vite-react`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function deriveSourcePathPrefix(viteRoot: string, workspaceRootHints: readonly string[] | undefined): string | undefined;
|
|
7
12
|
/** Vite plugin that exposes POST /__t3-feedback and bridges envelopes to T3. */
|
|
8
13
|
export declare function t3FeedbackPlugin(options?: T3FeedbackPluginOptions): Plugin;
|
|
9
14
|
export default t3FeedbackPlugin;
|
package/dist/plugin.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { normalizePath } from "vite";
|
|
3
4
|
import { handleT3FeedbackRequest } from "./bridge/http.js";
|
|
4
5
|
import { T3_FEEDBACK_API_PATH } from "./bridge/paths.js";
|
|
5
|
-
import { resolveActivePluginList, resolveFabConfig, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, } from "./types.js";
|
|
6
|
-
export { T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, } from "./bridge/paths.js";
|
|
6
|
+
import { resolveActivePluginList, resolveFabConfig, resolvePickConfig, resolveRecordConfig, resolveReportTypeGlyph, resolveScreenshotConfig, resolveShortcut, normalizePickSourcePathPrefix, } from "./types.js";
|
|
7
|
+
export { T3_FEEDBACK_API_PATH, T3_FEEDBACK_OPEN_PATH, T3_FEEDBACK_OPEN_EDITOR_PATH, T3_FEEDBACK_SETTLE_PATH, T3_FEEDBACK_THREADS_PATH, } from "./bridge/paths.js";
|
|
7
8
|
export { parseFeedbackPost, parseOpenHandoffRequest, parseSettlePost, parseThreadProbeIds, } from "./bridge/parse.js";
|
|
8
9
|
/** Resolve a `customPlugins` entry against the Vite project root (bare ids stay bare). */
|
|
9
10
|
export function resolveCustomPluginModuleId(entry, root) {
|
|
@@ -17,6 +18,25 @@ export function resolveCustomPluginModuleId(entry, root) {
|
|
|
17
18
|
}
|
|
18
19
|
return trimmed;
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* When Vite root sits under a workspace hint, return the relative prefix
|
|
23
|
+
* (e.g. hint=`/repo`, root=`/repo/examples/vite-react` → `examples/vite-react`).
|
|
24
|
+
*/
|
|
25
|
+
export function deriveSourcePathPrefix(viteRoot, workspaceRootHints) {
|
|
26
|
+
if (!workspaceRootHints?.length)
|
|
27
|
+
return undefined;
|
|
28
|
+
const rootResolved = path.resolve(viteRoot);
|
|
29
|
+
for (const hint of workspaceRootHints) {
|
|
30
|
+
if (typeof hint !== "string" || !hint.trim())
|
|
31
|
+
continue;
|
|
32
|
+
const hintResolved = path.resolve(hint.trim());
|
|
33
|
+
const rel = path.relative(hintResolved, rootResolved);
|
|
34
|
+
if (!rel || rel.startsWith("..") || path.isAbsolute(rel))
|
|
35
|
+
continue;
|
|
36
|
+
return normalizePickSourcePathPrefix(rel.replace(/\\/g, "/"));
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
20
40
|
function resolvePluginOptions(options) {
|
|
21
41
|
if (!options)
|
|
22
42
|
return undefined;
|
|
@@ -104,23 +124,70 @@ export function t3FeedbackPlugin(options = {}) {
|
|
|
104
124
|
const customPluginEntries = (options.customPlugins ?? [])
|
|
105
125
|
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
|
|
106
126
|
.filter(Boolean);
|
|
127
|
+
// Absolute dist entry. Prefer a real filesystem id (not `/@fs/...`) so Vite still
|
|
128
|
+
// runs import-analysis and rewrites bare deps like `@rose42/feedback-capture`.
|
|
129
|
+
// Combined with `link:` example installs, `tsc --watch` updates are visible without
|
|
130
|
+
// a stale optimizeDeps prebundle of this package.
|
|
131
|
+
const clientEntry = normalizePath(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "client/index.js"));
|
|
132
|
+
// `dist/client/index.js` → package root (must be fs-allowed when linked from an example).
|
|
133
|
+
const packageRoot = normalizePath(path.resolve(path.dirname(clientEntry), "../.."));
|
|
107
134
|
const bridgeServerOptions = {
|
|
108
135
|
basePath: T3_FEEDBACK_API_PATH,
|
|
109
136
|
...(options.origin ? { origin: options.origin } : {}),
|
|
110
137
|
...(options.openOrigin ? { openOrigin: options.openOrigin } : {}),
|
|
111
138
|
...(workspaceRootHints ? { workspaceRootHints } : {}),
|
|
112
139
|
...(threadTitlePrefix ? { threadTitlePrefix } : {}),
|
|
140
|
+
...(options.modelSelection ? { modelSelection: options.modelSelection } : {}),
|
|
113
141
|
reportTypeGlyph,
|
|
114
142
|
};
|
|
115
143
|
return {
|
|
116
144
|
name: "t3-feedback",
|
|
117
145
|
apply: "serve",
|
|
146
|
+
enforce: "pre",
|
|
147
|
+
config() {
|
|
148
|
+
return {
|
|
149
|
+
resolve: {
|
|
150
|
+
alias: {
|
|
151
|
+
"@rose42/t3-feedback/client": clientEntry,
|
|
152
|
+
},
|
|
153
|
+
// qwikVite sets `resolve.conditions: []` in DEV, which drops Vite's
|
|
154
|
+
// default "development" export condition. `@builder.io/qwik` then
|
|
155
|
+
// resolves to `core.prod.mjs` (qInspector hard-disabled), so
|
|
156
|
+
// `data-qwik-inspector` is never written and element pick can't
|
|
157
|
+
// resolve components. Restoring "development" is a no-op for other
|
|
158
|
+
// frameworks (Vite's client default already includes it).
|
|
159
|
+
conditions: ["development"],
|
|
160
|
+
},
|
|
161
|
+
optimizeDeps: {
|
|
162
|
+
// Keep the linked client out of the deps cache; prebundle its runtime dep.
|
|
163
|
+
exclude: ["@rose42/t3-feedback", "@rose42/t3-feedback/client"],
|
|
164
|
+
include: ["@rose42/feedback-capture"],
|
|
165
|
+
},
|
|
166
|
+
server: {
|
|
167
|
+
fs: {
|
|
168
|
+
allow: [packageRoot],
|
|
169
|
+
},
|
|
170
|
+
watch: {
|
|
171
|
+
ignored: ["!**/node_modules/@rose42/t3-feedback/**"],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
},
|
|
118
176
|
configResolved(config) {
|
|
119
177
|
viteRoot = config.root;
|
|
178
|
+
// Nested app under a monorepo / T3 workspace: prefix chip + agent paths.
|
|
179
|
+
if (!clientConfig.pick.sourcePathPrefix) {
|
|
180
|
+
const derived = deriveSourcePathPrefix(config.root, workspaceRootHints);
|
|
181
|
+
if (derived) {
|
|
182
|
+
clientConfig.pick = { ...clientConfig.pick, sourcePathPrefix: derived };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
120
185
|
},
|
|
121
186
|
resolveId(id) {
|
|
122
187
|
if (id === VIRTUAL_CLIENT_ID)
|
|
123
188
|
return RESOLVED_VIRTUAL_CLIENT_ID;
|
|
189
|
+
if (id === "@rose42/t3-feedback/client")
|
|
190
|
+
return clientEntry;
|
|
124
191
|
},
|
|
125
192
|
load(id) {
|
|
126
193
|
if (id !== RESOLVED_VIRTUAL_CLIENT_ID)
|
|
@@ -135,8 +202,8 @@ export function t3FeedbackPlugin(options = {}) {
|
|
|
135
202
|
.map((_, i) => ` ...normalizeCustomPluginExport(custom${i})`)
|
|
136
203
|
.join(",\n")}\n]`;
|
|
137
204
|
const clientImports = resolvedCustoms.length === 0
|
|
138
|
-
? `import { mountT3FeedbackFromConfig } from
|
|
139
|
-
: `import { mountT3FeedbackFromConfig, normalizeCustomPluginExport } from
|
|
205
|
+
? `import { mountT3FeedbackFromConfig } from ${JSON.stringify(clientEntry)};`
|
|
206
|
+
: `import { mountT3FeedbackFromConfig, normalizeCustomPluginExport } from ${JSON.stringify(clientEntry)};`;
|
|
140
207
|
return `
|
|
141
208
|
${clientImports}
|
|
142
209
|
${customImports}
|