@spotpatch/runtime 1.15.2 → 1.15.3
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/chunk-ELCIEQGT.js +183 -0
- package/dist/chunk-ELCIEQGT.js.map +1 -0
- package/dist/contextual-ask-panel.cjs +100 -92
- package/dist/contextual-ask-panel.cjs.map +1 -1
- package/dist/contextual-ask-panel.js +74 -235
- package/dist/contextual-ask-panel.js.map +1 -1
- package/dist/data-flow-panel.cjs +28 -28
- package/dist/data-flow-panel.cjs.map +1 -1
- package/dist/data-flow-panel.js +28 -28
- package/dist/data-flow-panel.js.map +1 -1
- package/dist/external-handoff-panel.cjs +296 -109
- package/dist/external-handoff-panel.cjs.map +1 -1
- package/dist/external-handoff-panel.js +127 -109
- package/dist/external-handoff-panel.js.map +1 -1
- package/dist/index.cjs +284 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +284 -284
- package/dist/index.js.map +1 -1
- package/dist/motion.cjs +2 -2
- package/dist/motion.cjs.map +1 -1
- package/dist/motion.js +2 -2
- package/dist/motion.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createButton,
|
|
3
|
+
createMarkedElement
|
|
4
|
+
} from "./chunk-P6X75LO5.js";
|
|
5
|
+
|
|
6
|
+
// src/ui/ask-picker.ts
|
|
7
|
+
var SELECT_PICKER_STYLES = `
|
|
8
|
+
.spotpatch-select-picker { position: relative; display: grid; gap: 5px; min-width: 0; }
|
|
9
|
+
.spotpatch-select-trigger { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); cursor: pointer; font: inherit; outline: none; text-align: left; }
|
|
10
|
+
.spotpatch-select-trigger > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
11
|
+
.spotpatch-select-trigger[data-expandable="true"]::after { width: 7px; height: 7px; flex: 0 0 auto; border-right: 1.5px solid #8f96a3; border-bottom: 1.5px solid #8f96a3; content: ""; transform: translateY(-2px) rotate(45deg); }
|
|
12
|
+
.spotpatch-select-trigger[aria-expanded="true"]::after { transform: translateY(2px) rotate(225deg); }
|
|
13
|
+
.spotpatch-select-trigger:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
14
|
+
.spotpatch-select-trigger:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }
|
|
15
|
+
.spotpatch-select-trigger[data-empty="true"]:disabled { color: var(--spotpatch-text-muted); }
|
|
16
|
+
.spotpatch-select-menu { position: relative; z-index: 1; display: grid; gap: 3px; max-height: 224px; overflow-y: auto; overscroll-behavior: contain; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); box-shadow: 0 10px 28px rgb(0 0 0 / 28%); scrollbar-width: thin; }
|
|
17
|
+
.spotpatch-select-menu[hidden] { display: none; }
|
|
18
|
+
.spotpatch-select-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; overflow-wrap: anywhere; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; }
|
|
19
|
+
.spotpatch-select-option[data-active="true"], .spotpatch-select-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }
|
|
20
|
+
.spotpatch-select-option[aria-selected="true"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }
|
|
21
|
+
.spotpatch-select-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
22
|
+
`;
|
|
23
|
+
function createSelectPicker(document, onViewChange) {
|
|
24
|
+
const root = createMarkedElement(document, "div");
|
|
25
|
+
root.className = "spotpatch-select-picker";
|
|
26
|
+
const trigger = createButton(document, "", "spotpatch-select-trigger");
|
|
27
|
+
trigger.id = `spotpatch-select-picker-${Math.random().toString(36).slice(2)}`;
|
|
28
|
+
trigger.setAttribute("role", "combobox");
|
|
29
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
30
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
31
|
+
const text = createMarkedElement(document, "span");
|
|
32
|
+
trigger.append(text);
|
|
33
|
+
const menu = createMarkedElement(document, "div");
|
|
34
|
+
menu.id = `${trigger.id}-menu`;
|
|
35
|
+
menu.className = "spotpatch-select-menu";
|
|
36
|
+
menu.setAttribute("role", "listbox");
|
|
37
|
+
menu.hidden = true;
|
|
38
|
+
trigger.setAttribute("aria-controls", menu.id);
|
|
39
|
+
const select = createMarkedElement(document, "select");
|
|
40
|
+
select.className = "spotpatch-select-native";
|
|
41
|
+
select.tabIndex = -1;
|
|
42
|
+
select.setAttribute("aria-hidden", "true");
|
|
43
|
+
root.append(trigger, menu, select);
|
|
44
|
+
function close(focus = false) {
|
|
45
|
+
if (menu.hidden) return;
|
|
46
|
+
menu.hidden = true;
|
|
47
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
48
|
+
trigger.removeAttribute("aria-activedescendant");
|
|
49
|
+
if (focus) trigger.focus({ preventScroll: true });
|
|
50
|
+
onViewChange();
|
|
51
|
+
}
|
|
52
|
+
function activate(index) {
|
|
53
|
+
const options = [...menu.children];
|
|
54
|
+
const active = options[index];
|
|
55
|
+
if (active === void 0) return;
|
|
56
|
+
for (const option of options) option.dataset.active = String(option === active);
|
|
57
|
+
trigger.setAttribute("aria-activedescendant", active.id);
|
|
58
|
+
const itemRect = active.getBoundingClientRect();
|
|
59
|
+
const menuRect = menu.getBoundingClientRect();
|
|
60
|
+
if (itemRect.top < menuRect.top) menu.scrollTop -= menuRect.top - itemRect.top;
|
|
61
|
+
else if (itemRect.bottom > menuRect.bottom)
|
|
62
|
+
menu.scrollTop += itemRect.bottom - menuRect.bottom;
|
|
63
|
+
}
|
|
64
|
+
function open() {
|
|
65
|
+
if (trigger.disabled || !menu.hidden) return;
|
|
66
|
+
menu.hidden = false;
|
|
67
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
68
|
+
activate(Math.max(0, select.selectedIndex));
|
|
69
|
+
onViewChange();
|
|
70
|
+
}
|
|
71
|
+
function sync() {
|
|
72
|
+
text.textContent = select.selectedOptions[0]?.textContent ?? "";
|
|
73
|
+
trigger.title = text.textContent;
|
|
74
|
+
trigger.dataset.empty = String(select.value.length === 0);
|
|
75
|
+
for (const option of [...menu.children]) {
|
|
76
|
+
option.setAttribute(
|
|
77
|
+
"aria-selected",
|
|
78
|
+
String(option.dataset.value === select.value)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function choose(value) {
|
|
83
|
+
if (trigger.disabled) return;
|
|
84
|
+
select.value = value;
|
|
85
|
+
sync();
|
|
86
|
+
close(true);
|
|
87
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
88
|
+
}
|
|
89
|
+
function rebuild() {
|
|
90
|
+
const expanded = !menu.hidden;
|
|
91
|
+
const nativeOptions = [...select.options];
|
|
92
|
+
menu.replaceChildren();
|
|
93
|
+
for (const [index, option] of nativeOptions.entries()) {
|
|
94
|
+
const item = createMarkedElement(document, "div");
|
|
95
|
+
item.id = `${menu.id}-${String(index)}`;
|
|
96
|
+
item.className = "spotpatch-select-option";
|
|
97
|
+
item.setAttribute("role", "option");
|
|
98
|
+
item.dataset.value = option.value;
|
|
99
|
+
item.textContent = option.textContent;
|
|
100
|
+
item.title = option.textContent;
|
|
101
|
+
item.addEventListener("pointerdown", (event) => {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
});
|
|
104
|
+
item.addEventListener("click", () => {
|
|
105
|
+
choose(option.value);
|
|
106
|
+
});
|
|
107
|
+
menu.append(item);
|
|
108
|
+
}
|
|
109
|
+
sync();
|
|
110
|
+
if (expanded) {
|
|
111
|
+
activate(Math.max(0, select.selectedIndex));
|
|
112
|
+
onViewChange();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
trigger.addEventListener("click", () => {
|
|
116
|
+
if (menu.hidden) open();
|
|
117
|
+
else close();
|
|
118
|
+
});
|
|
119
|
+
trigger.addEventListener("keydown", (event) => {
|
|
120
|
+
if (event.key === "Escape" && !menu.hidden) {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
event.stopPropagation();
|
|
123
|
+
close();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (event.key === "Tab") {
|
|
127
|
+
close();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (["Enter", " "].includes(event.key) && !menu.hidden) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
const active = [...menu.children].find(
|
|
133
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
134
|
+
);
|
|
135
|
+
if (active?.dataset.value !== void 0) choose(active.dataset.value);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
if (menu.hidden) {
|
|
141
|
+
open();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const options = [...menu.children];
|
|
145
|
+
const index = options.findIndex(
|
|
146
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
147
|
+
);
|
|
148
|
+
activate(
|
|
149
|
+
event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + options.length) % options.length
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
root.addEventListener("focusout", (event) => {
|
|
153
|
+
if (!(event.relatedTarget instanceof Node) || !root.contains(event.relatedTarget))
|
|
154
|
+
close();
|
|
155
|
+
});
|
|
156
|
+
const outside = (event) => {
|
|
157
|
+
if (!event.composedPath().includes(root)) close();
|
|
158
|
+
};
|
|
159
|
+
document.addEventListener("pointerdown", outside);
|
|
160
|
+
select.addEventListener("change", sync);
|
|
161
|
+
return {
|
|
162
|
+
root,
|
|
163
|
+
trigger,
|
|
164
|
+
select,
|
|
165
|
+
rebuild,
|
|
166
|
+
close,
|
|
167
|
+
setDisabled(disabled) {
|
|
168
|
+
select.disabled = disabled;
|
|
169
|
+
trigger.disabled = disabled || select.options.length < 2;
|
|
170
|
+
trigger.dataset.expandable = String(!trigger.disabled);
|
|
171
|
+
if (trigger.disabled) close();
|
|
172
|
+
},
|
|
173
|
+
dispose() {
|
|
174
|
+
document.removeEventListener("pointerdown", outside);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export {
|
|
180
|
+
SELECT_PICKER_STYLES,
|
|
181
|
+
createSelectPicker
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=chunk-ELCIEQGT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/ask-picker.ts"],"sourcesContent":["import { createButton, createMarkedElement } from \"./dom.js\";\n\nexport const SELECT_PICKER_STYLES = `\n .spotpatch-select-picker { position: relative; display: grid; gap: 5px; min-width: 0; }\n .spotpatch-select-trigger { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); cursor: pointer; font: inherit; outline: none; text-align: left; }\n .spotpatch-select-trigger > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .spotpatch-select-trigger[data-expandable=\"true\"]::after { width: 7px; height: 7px; flex: 0 0 auto; border-right: 1.5px solid #8f96a3; border-bottom: 1.5px solid #8f96a3; content: \"\"; transform: translateY(-2px) rotate(45deg); }\n .spotpatch-select-trigger[aria-expanded=\"true\"]::after { transform: translateY(2px) rotate(225deg); }\n .spotpatch-select-trigger:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }\n .spotpatch-select-trigger:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }\n .spotpatch-select-trigger[data-empty=\"true\"]:disabled { color: var(--spotpatch-text-muted); }\n .spotpatch-select-menu { position: relative; z-index: 1; display: grid; gap: 3px; max-height: 224px; overflow-y: auto; overscroll-behavior: contain; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); box-shadow: 0 10px 28px rgb(0 0 0 / 28%); scrollbar-width: thin; }\n .spotpatch-select-menu[hidden] { display: none; }\n .spotpatch-select-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; overflow-wrap: anywhere; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; }\n .spotpatch-select-option[data-active=\"true\"], .spotpatch-select-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }\n .spotpatch-select-option[aria-selected=\"true\"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }\n .spotpatch-select-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }\n`;\n\n/** Shared select-only picker: native value contract, one accessible custom control. */\nexport function createSelectPicker(document: Document, onViewChange: () => void) {\n const root = createMarkedElement(document, \"div\");\n root.className = \"spotpatch-select-picker\";\n const trigger = createButton(document, \"\", \"spotpatch-select-trigger\");\n trigger.id = `spotpatch-select-picker-${Math.random().toString(36).slice(2)}`;\n trigger.setAttribute(\"role\", \"combobox\");\n trigger.setAttribute(\"aria-haspopup\", \"listbox\");\n trigger.setAttribute(\"aria-expanded\", \"false\");\n const text = createMarkedElement(document, \"span\");\n trigger.append(text);\n const menu = createMarkedElement(document, \"div\");\n menu.id = `${trigger.id}-menu`;\n menu.className = \"spotpatch-select-menu\";\n menu.setAttribute(\"role\", \"listbox\");\n menu.hidden = true;\n trigger.setAttribute(\"aria-controls\", menu.id);\n const select = createMarkedElement(document, \"select\");\n select.className = \"spotpatch-select-native\";\n select.tabIndex = -1;\n select.setAttribute(\"aria-hidden\", \"true\");\n root.append(trigger, menu, select);\n\n function close(focus = false): void {\n if (menu.hidden) return;\n menu.hidden = true;\n trigger.setAttribute(\"aria-expanded\", \"false\");\n trigger.removeAttribute(\"aria-activedescendant\");\n if (focus) trigger.focus({ preventScroll: true });\n onViewChange();\n }\n\n function activate(index: number): void {\n const options = [...menu.children] as HTMLElement[];\n const active = options[index];\n if (active === undefined) return;\n for (const option of options) option.dataset.active = String(option === active);\n trigger.setAttribute(\"aria-activedescendant\", active.id);\n const itemRect = active.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n if (itemRect.top < menuRect.top) menu.scrollTop -= menuRect.top - itemRect.top;\n else if (itemRect.bottom > menuRect.bottom)\n menu.scrollTop += itemRect.bottom - menuRect.bottom;\n }\n\n function open(): void {\n if (trigger.disabled || !menu.hidden) return;\n menu.hidden = false;\n trigger.setAttribute(\"aria-expanded\", \"true\");\n activate(Math.max(0, select.selectedIndex));\n onViewChange();\n }\n\n function sync(): void {\n text.textContent = select.selectedOptions[0]?.textContent ?? \"\";\n trigger.title = text.textContent;\n trigger.dataset.empty = String(select.value.length === 0);\n for (const option of [...menu.children] as HTMLElement[]) {\n option.setAttribute(\n \"aria-selected\",\n String(option.dataset.value === select.value),\n );\n }\n }\n\n function choose(value: string): void {\n if (trigger.disabled) return;\n select.value = value;\n sync();\n close(true);\n select.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n\n function rebuild(): void {\n const expanded = !menu.hidden;\n const nativeOptions = [...select.options];\n menu.replaceChildren();\n for (const [index, option] of nativeOptions.entries()) {\n const item = createMarkedElement(document, \"div\");\n item.id = `${menu.id}-${String(index)}`;\n item.className = \"spotpatch-select-option\";\n item.setAttribute(\"role\", \"option\");\n item.dataset.value = option.value;\n item.textContent = option.textContent;\n item.title = option.textContent;\n item.addEventListener(\"pointerdown\", (event) => {\n event.preventDefault();\n });\n item.addEventListener(\"click\", () => {\n choose(option.value);\n });\n menu.append(item);\n }\n sync();\n if (expanded) {\n activate(Math.max(0, select.selectedIndex));\n onViewChange();\n }\n }\n\n trigger.addEventListener(\"click\", () => {\n if (menu.hidden) open();\n else close();\n });\n trigger.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\" && !menu.hidden) {\n event.preventDefault();\n event.stopPropagation();\n close();\n return;\n }\n if (event.key === \"Tab\") {\n close();\n return;\n }\n if ([\"Enter\", \" \"].includes(event.key) && !menu.hidden) {\n event.preventDefault();\n const active = [...menu.children].find(\n (item) => item.id === trigger.getAttribute(\"aria-activedescendant\"),\n ) as HTMLElement | undefined;\n if (active?.dataset.value !== undefined) choose(active.dataset.value);\n return;\n }\n if (![\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"].includes(event.key)) return;\n event.preventDefault();\n if (menu.hidden) {\n open();\n return;\n }\n const options = [...menu.children];\n const index = options.findIndex(\n (item) => item.id === trigger.getAttribute(\"aria-activedescendant\"),\n );\n activate(\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? options.length - 1\n : (index + (event.key === \"ArrowDown\" ? 1 : -1) + options.length) %\n options.length,\n );\n });\n root.addEventListener(\"focusout\", (event) => {\n if (!(event.relatedTarget instanceof Node) || !root.contains(event.relatedTarget))\n close();\n });\n const outside = (event: PointerEvent): void => {\n if (!event.composedPath().includes(root)) close();\n };\n document.addEventListener(\"pointerdown\", outside);\n select.addEventListener(\"change\", sync);\n return {\n root,\n trigger,\n select,\n rebuild,\n close,\n setDisabled(disabled: boolean): void {\n select.disabled = disabled;\n trigger.disabled = disabled || select.options.length < 2;\n trigger.dataset.expandable = String(!trigger.disabled);\n if (trigger.disabled) close();\n },\n dispose(): void {\n document.removeEventListener(\"pointerdown\", outside);\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -806,11 +806,27 @@ function createButton(document, label, className = "") {
|
|
|
806
806
|
}
|
|
807
807
|
|
|
808
808
|
// src/ui/ask-picker.ts
|
|
809
|
-
|
|
809
|
+
var SELECT_PICKER_STYLES = `
|
|
810
|
+
.spotpatch-select-picker { position: relative; display: grid; gap: 5px; min-width: 0; }
|
|
811
|
+
.spotpatch-select-trigger { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); cursor: pointer; font: inherit; outline: none; text-align: left; }
|
|
812
|
+
.spotpatch-select-trigger > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
813
|
+
.spotpatch-select-trigger[data-expandable="true"]::after { width: 7px; height: 7px; flex: 0 0 auto; border-right: 1.5px solid #8f96a3; border-bottom: 1.5px solid #8f96a3; content: ""; transform: translateY(-2px) rotate(45deg); }
|
|
814
|
+
.spotpatch-select-trigger[aria-expanded="true"]::after { transform: translateY(2px) rotate(225deg); }
|
|
815
|
+
.spotpatch-select-trigger:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
816
|
+
.spotpatch-select-trigger:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }
|
|
817
|
+
.spotpatch-select-trigger[data-empty="true"]:disabled { color: var(--spotpatch-text-muted); }
|
|
818
|
+
.spotpatch-select-menu { position: relative; z-index: 1; display: grid; gap: 3px; max-height: 224px; overflow-y: auto; overscroll-behavior: contain; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); box-shadow: 0 10px 28px rgb(0 0 0 / 28%); scrollbar-width: thin; }
|
|
819
|
+
.spotpatch-select-menu[hidden] { display: none; }
|
|
820
|
+
.spotpatch-select-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; overflow-wrap: anywhere; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; }
|
|
821
|
+
.spotpatch-select-option[data-active="true"], .spotpatch-select-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }
|
|
822
|
+
.spotpatch-select-option[aria-selected="true"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }
|
|
823
|
+
.spotpatch-select-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
824
|
+
`;
|
|
825
|
+
function createSelectPicker(document, onViewChange) {
|
|
810
826
|
const root = createMarkedElement(document, "div");
|
|
811
|
-
root.className = "spotpatch-
|
|
812
|
-
const trigger = createButton(document, "", "spotpatch-
|
|
813
|
-
trigger.id = `spotpatch-
|
|
827
|
+
root.className = "spotpatch-select-picker";
|
|
828
|
+
const trigger = createButton(document, "", "spotpatch-select-trigger");
|
|
829
|
+
trigger.id = `spotpatch-select-picker-${Math.random().toString(36).slice(2)}`;
|
|
814
830
|
trigger.setAttribute("role", "combobox");
|
|
815
831
|
trigger.setAttribute("aria-haspopup", "listbox");
|
|
816
832
|
trigger.setAttribute("aria-expanded", "false");
|
|
@@ -818,12 +834,12 @@ function createAskPicker(document, onViewChange) {
|
|
|
818
834
|
trigger.append(text);
|
|
819
835
|
const menu = createMarkedElement(document, "div");
|
|
820
836
|
menu.id = `${trigger.id}-menu`;
|
|
821
|
-
menu.className = "spotpatch-
|
|
837
|
+
menu.className = "spotpatch-select-menu";
|
|
822
838
|
menu.setAttribute("role", "listbox");
|
|
823
839
|
menu.hidden = true;
|
|
824
840
|
trigger.setAttribute("aria-controls", menu.id);
|
|
825
841
|
const select = createMarkedElement(document, "select");
|
|
826
|
-
select.className = "spotpatch-
|
|
842
|
+
select.className = "spotpatch-select-native";
|
|
827
843
|
select.tabIndex = -1;
|
|
828
844
|
select.setAttribute("aria-hidden", "true");
|
|
829
845
|
root.append(trigger, menu, select);
|
|
@@ -873,12 +889,13 @@ function createAskPicker(document, onViewChange) {
|
|
|
873
889
|
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
874
890
|
}
|
|
875
891
|
function rebuild() {
|
|
876
|
-
|
|
892
|
+
const expanded = !menu.hidden;
|
|
893
|
+
const nativeOptions = [...select.options];
|
|
877
894
|
menu.replaceChildren();
|
|
878
|
-
for (const [index, option] of
|
|
895
|
+
for (const [index, option] of nativeOptions.entries()) {
|
|
879
896
|
const item = createMarkedElement(document, "div");
|
|
880
897
|
item.id = `${menu.id}-${String(index)}`;
|
|
881
|
-
item.className = "spotpatch-
|
|
898
|
+
item.className = "spotpatch-select-option";
|
|
882
899
|
item.setAttribute("role", "option");
|
|
883
900
|
item.dataset.value = option.value;
|
|
884
901
|
item.textContent = option.textContent;
|
|
@@ -892,6 +909,10 @@ function createAskPicker(document, onViewChange) {
|
|
|
892
909
|
menu.append(item);
|
|
893
910
|
}
|
|
894
911
|
sync();
|
|
912
|
+
if (expanded) {
|
|
913
|
+
activate(Math.max(0, select.selectedIndex));
|
|
914
|
+
onViewChange();
|
|
915
|
+
}
|
|
895
916
|
}
|
|
896
917
|
trigger.addEventListener("click", () => {
|
|
897
918
|
if (menu.hidden) open();
|
|
@@ -972,12 +993,12 @@ var EN = Object.freeze({
|
|
|
972
993
|
]),
|
|
973
994
|
executorLabel: "Read-only executor",
|
|
974
995
|
modelLabel: "Model",
|
|
975
|
-
loadingExecutors: "Checking available executors
|
|
996
|
+
loadingExecutors: "Checking available executors…",
|
|
976
997
|
noExecutor: "No verified read-only executor is available.",
|
|
977
998
|
unavailable: "unavailable",
|
|
978
999
|
consent: "Allow the selected source snapshot to be sent to this provider for this answer.",
|
|
979
|
-
dataSummary: (targets, sources) => `${String(targets)} selected element${targets === 1 ? "" : "s"}
|
|
980
|
-
safety: "Single turn
|
|
1000
|
+
dataSummary: (targets, sources) => `${String(targets)} selected element${targets === 1 ? "" : "s"} · ${String(sources)} source-backed`,
|
|
1001
|
+
safety: "Single turn · read-only · no history",
|
|
981
1002
|
submit: "Ask",
|
|
982
1003
|
cancel: "Cancel",
|
|
983
1004
|
newQuestion: "Start over",
|
|
@@ -997,7 +1018,7 @@ var EN = Object.freeze({
|
|
|
997
1018
|
cancelled: "Cancelled",
|
|
998
1019
|
failed: "Could not answer"
|
|
999
1020
|
}),
|
|
1000
|
-
sourceLabel: (path, start, end) => `${path}:${String(start)}${end === start ? "" :
|
|
1021
|
+
sourceLabel: (path, start, end) => `${path}:${String(start)}${end === start ? "" : `–${String(end)}`}`,
|
|
1001
1022
|
readSource: (path) => `Reading ${path}`,
|
|
1002
1023
|
readFiles: (bucket) => `Reading ${bucket} files`,
|
|
1003
1024
|
copied: "Answer copied.",
|
|
@@ -1029,74 +1050,74 @@ var EN = Object.freeze({
|
|
|
1029
1050
|
warning: (code) => code === "insufficient-evidence" ? "The selected source did not contain enough evidence for a complete answer." : "Some source references were omitted because they could not be verified."
|
|
1030
1051
|
});
|
|
1031
1052
|
var ZH = Object.freeze({
|
|
1032
|
-
mode: Object.freeze({ ask: "
|
|
1033
|
-
title: "
|
|
1034
|
-
subtitle: "
|
|
1035
|
-
questionLabel: "
|
|
1036
|
-
questionPlaceholder: "
|
|
1037
|
-
suggestionsLabel: "
|
|
1053
|
+
mode: Object.freeze({ ask: "问答", change: "修改", label: "任务模式" }),
|
|
1054
|
+
title: "询问所选元素",
|
|
1055
|
+
subtitle: "一次提问,一次带源码引用的回答;SpotPatch 不会写入代码。",
|
|
1056
|
+
questionLabel: "问题",
|
|
1057
|
+
questionPlaceholder: "这个组件是做什么的?",
|
|
1058
|
+
suggestionsLabel: "推荐问题",
|
|
1038
1059
|
suggestions: Object.freeze([
|
|
1039
|
-
"
|
|
1040
|
-
"
|
|
1041
|
-
"
|
|
1060
|
+
"这个组件是做什么的?",
|
|
1061
|
+
"它的数据从哪里来?",
|
|
1062
|
+
"为什么要这样实现?"
|
|
1042
1063
|
]),
|
|
1043
|
-
executorLabel: "
|
|
1044
|
-
modelLabel: "
|
|
1045
|
-
loadingExecutors: "
|
|
1046
|
-
noExecutor: "
|
|
1047
|
-
unavailable: "
|
|
1048
|
-
consent: "
|
|
1049
|
-
dataSummary: (targets, sources) => `${String(targets)}
|
|
1050
|
-
safety: "
|
|
1051
|
-
submit: "
|
|
1052
|
-
cancel: "
|
|
1053
|
-
newQuestion: "
|
|
1054
|
-
copy: "
|
|
1055
|
-
convert: "
|
|
1056
|
-
answerTitle: "
|
|
1057
|
-
sourcesTitle: "
|
|
1058
|
-
stale: "
|
|
1059
|
-
convertedTitle: "
|
|
1060
|
-
convertedBody: "
|
|
1064
|
+
executorLabel: "只读执行器",
|
|
1065
|
+
modelLabel: "模型",
|
|
1066
|
+
loadingExecutors: "正在检查可用执行器…",
|
|
1067
|
+
noExecutor: "目前没有通过只读验证的执行器。",
|
|
1068
|
+
unavailable: "不可用",
|
|
1069
|
+
consent: "允许本次回答将所选源码快照发送给该提供商。",
|
|
1070
|
+
dataSummary: (targets, sources) => `${String(targets)} 个已选元素 · ${String(sources)} 个具备源码上下文`,
|
|
1071
|
+
safety: "单轮 · 只读 · 不保存历史",
|
|
1072
|
+
submit: "提问",
|
|
1073
|
+
cancel: "取消",
|
|
1074
|
+
newQuestion: "重新开始",
|
|
1075
|
+
copy: "复制回答",
|
|
1076
|
+
convert: "转成修改请求",
|
|
1077
|
+
answerTitle: "回答",
|
|
1078
|
+
sourcesTitle: "源码引用",
|
|
1079
|
+
stale: "回答后选择已发生变化。请重新提问后再采信此回答。",
|
|
1080
|
+
convertedTitle: "来自上下文问答",
|
|
1081
|
+
convertedBody: "回答与源码引用仅作为本地上下文保留,尚未发起任何修改。",
|
|
1061
1082
|
status: Object.freeze({
|
|
1062
|
-
queued: "
|
|
1063
|
-
authorizing: "
|
|
1064
|
-
running: "
|
|
1065
|
-
cancelling: "
|
|
1066
|
-
answered: "
|
|
1067
|
-
cancelled: "
|
|
1068
|
-
failed: "
|
|
1083
|
+
queued: "已排队",
|
|
1084
|
+
authorizing: "正在验证只读权限",
|
|
1085
|
+
running: "正在分析所选源码",
|
|
1086
|
+
cancelling: "正在取消",
|
|
1087
|
+
answered: "回答已就绪",
|
|
1088
|
+
cancelled: "已取消",
|
|
1089
|
+
failed: "无法回答"
|
|
1069
1090
|
}),
|
|
1070
|
-
sourceLabel: (path, start, end) => `${path}:${String(start)}${end === start ? "" :
|
|
1071
|
-
readSource: (path) =>
|
|
1072
|
-
readFiles: (bucket) =>
|
|
1073
|
-
copied: "
|
|
1074
|
-
copyFailed: "
|
|
1075
|
-
sourceOpenFailed: "
|
|
1076
|
-
converted: "
|
|
1091
|
+
sourceLabel: (path, start, end) => `${path}:${String(start)}${end === start ? "" : `–${String(end)}`}`,
|
|
1092
|
+
readSource: (path) => `正在读取 ${path}`,
|
|
1093
|
+
readFiles: (bucket) => `正在读取 ${bucket} 个文件`,
|
|
1094
|
+
copied: "回答已复制。",
|
|
1095
|
+
copyFailed: "无法复制回答。",
|
|
1096
|
+
sourceOpenFailed: "无法打开源码。",
|
|
1097
|
+
converted: "已切换到修改模式,并把回答作为本地上下文附带。",
|
|
1077
1098
|
error: (code) => {
|
|
1078
1099
|
const errors = {
|
|
1079
|
-
INVALID_TOKEN: "
|
|
1080
|
-
ORIGIN_NOT_ALLOWED: "
|
|
1081
|
-
ASK_DISABLED: "
|
|
1082
|
-
ASK_SELECTION_REQUIRED: "
|
|
1083
|
-
ASK_SELECTION_STALE: "
|
|
1084
|
-
ASK_QUESTION_INVALID: "
|
|
1085
|
-
ASK_EXECUTOR_UNAVAILABLE: "
|
|
1086
|
-
ASK_TIMEOUT: "
|
|
1087
|
-
ASK_CONSENT_REQUIRED: "
|
|
1088
|
-
ASK_BUSY: "
|
|
1089
|
-
ASK_CANCELLED: "
|
|
1090
|
-
ASK_RESULT_EXPIRED: "
|
|
1091
|
-
ASK_WRITE_ATTEMPTED: "
|
|
1092
|
-
ASK_ANSWER_INVALID: "
|
|
1093
|
-
ASK_PROTOCOL_INCOMPATIBLE: "
|
|
1094
|
-
ASK_LIMIT_EXCEEDED: "
|
|
1095
|
-
ASK_SOURCE_SCOPE_DENIED: "
|
|
1100
|
+
INVALID_TOKEN: "本地 SpotPatch 会话已失效,请刷新页面。",
|
|
1101
|
+
ORIGIN_NOT_ALLOWED: "本地请求未通过同源安全校验,请刷新页面或重启开发服务。",
|
|
1102
|
+
ASK_DISABLED: "上下文问答未启用。",
|
|
1103
|
+
ASK_SELECTION_REQUIRED: "请先选择至少一个元素。",
|
|
1104
|
+
ASK_SELECTION_STALE: "所选源码已经变化,请刷新选择后重新提问。",
|
|
1105
|
+
ASK_QUESTION_INVALID: "请输入一个有效的问题。",
|
|
1106
|
+
ASK_EXECUTOR_UNAVAILABLE: "所选只读执行器当前不可用。",
|
|
1107
|
+
ASK_TIMEOUT: "只读执行器未能在限定时间内返回回答,请重新提问。",
|
|
1108
|
+
ASK_CONSENT_REQUIRED: "请确认本次回答的提供商数据访问。",
|
|
1109
|
+
ASK_BUSY: "工作区正在执行其他任务,请稍后重试。",
|
|
1110
|
+
ASK_CANCELLED: "本次提问已取消。",
|
|
1111
|
+
ASK_RESULT_EXPIRED: "回答已过期,请重新提问。",
|
|
1112
|
+
ASK_WRITE_ATTEMPTED: "执行器尝试写入,已被阻止。",
|
|
1113
|
+
ASK_ANSWER_INVALID: "执行器返回的带引用回答无效。",
|
|
1114
|
+
ASK_PROTOCOL_INCOMPATIBLE: "执行器协议不兼容。",
|
|
1115
|
+
ASK_LIMIT_EXCEEDED: "所选上下文过大。",
|
|
1116
|
+
ASK_SOURCE_SCOPE_DENIED: "请求的源码超出了授权快照范围。"
|
|
1096
1117
|
};
|
|
1097
|
-
return code === void 0 ? "SpotPatch
|
|
1118
|
+
return code === void 0 ? "SpotPatch 未能完成本次提问。" : errors[code] ?? "SpotPatch 未能完成本次提问。";
|
|
1098
1119
|
},
|
|
1099
|
-
warning: (code) => code === "insufficient-evidence" ? "
|
|
1120
|
+
warning: (code) => code === "insufficient-evidence" ? "所选源码不足以支持完整回答。" : "部分源码引用因无法验证而被省略。"
|
|
1100
1121
|
});
|
|
1101
1122
|
function contextualAskMessages(locale) {
|
|
1102
1123
|
return locale === "zh-CN" ? ZH : EN;
|
|
@@ -1106,6 +1127,7 @@ function contextualAskMessages(locale) {
|
|
|
1106
1127
|
function createStyles(document) {
|
|
1107
1128
|
const style = document.createElement("style");
|
|
1108
1129
|
style.textContent = `
|
|
1130
|
+
${SELECT_PICKER_STYLES}
|
|
1109
1131
|
.spotpatch-ask-mode { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin-bottom: 14px; padding: 4px; border: 1px solid var(--spotpatch-border-subtle); border-radius: 10px; background: #0a0a0e; }
|
|
1110
1132
|
.spotpatch-ask-mode button { min-height: 34px; border: 0; border-radius: 7px; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; }
|
|
1111
1133
|
.spotpatch-ask-mode button[aria-selected="true"] { color: #f7f7ff; background: linear-gradient(135deg, rgb(139 123 255 / 25%), rgb(82 168 255 / 14%)); box-shadow: inset 0 0 0 1px rgb(139 123 255 / 24%); }
|
|
@@ -1118,20 +1140,6 @@ function createStyles(document) {
|
|
|
1118
1140
|
.spotpatch-ask-suggestions { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
1119
1141
|
.spotpatch-ask-suggestions button { border: 1px solid var(--spotpatch-border-subtle); border-radius: 999px; padding: 5px 9px; color: var(--spotpatch-text-secondary); background: rgb(255 255 255 / 2%); cursor: pointer; font-size: 10.5px; }
|
|
1120
1142
|
.spotpatch-ask-suggestions button:hover { border-color: rgb(139 123 255 / 42%); color: #fff; }
|
|
1121
|
-
.spotpatch-ask-executor-picker { display: grid; gap: 5px; min-width: 0; }
|
|
1122
|
-
.spotpatch-ask-executor { box-sizing: border-box; display: flex; width: 100%; min-height: 38px; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 0 11px; overflow: hidden; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); cursor: pointer; font: inherit; outline: none; text-align: left; }
|
|
1123
|
-
.spotpatch-ask-executor > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1124
|
-
.spotpatch-ask-executor[data-expandable="true"]::after { width: 7px; height: 7px; flex: 0 0 auto; border-right: 1.5px solid #8f96a3; border-bottom: 1.5px solid #8f96a3; content: ""; transform: translateY(-2px) rotate(45deg); }
|
|
1125
|
-
.spotpatch-ask-executor[aria-expanded="true"]::after { transform: translateY(2px) rotate(225deg); }
|
|
1126
|
-
.spotpatch-ask-executor:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
1127
|
-
.spotpatch-ask-executor:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }
|
|
1128
|
-
.spotpatch-ask-executor[data-empty="true"]:disabled { color: var(--spotpatch-text-muted); }
|
|
1129
|
-
.spotpatch-ask-executor-menu { display: grid; gap: 3px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); max-height: 224px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; box-shadow: 0 10px 28px rgb(0 0 0 / 28%); }
|
|
1130
|
-
.spotpatch-ask-executor-menu[hidden] { display: none; }
|
|
1131
|
-
.spotpatch-ask-executor-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; overflow-wrap: anywhere; }
|
|
1132
|
-
.spotpatch-ask-executor-option[data-active="true"], .spotpatch-ask-executor-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }
|
|
1133
|
-
.spotpatch-ask-executor-option[aria-selected="true"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }
|
|
1134
|
-
.spotpatch-ask-executor-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
1135
1143
|
.spotpatch-ask-executor-status { margin: 0; border-left: 2px solid var(--spotpatch-warning); padding-left: 8px; color: #d8b66c; font-size: 10.5px; line-height: 1.45; }
|
|
1136
1144
|
.spotpatch-ask-safety { display: grid; gap: 8px; border: 1px solid rgb(82 168 255 / 16%); border-radius: 10px; padding: 10px 11px; background: rgb(82 168 255 / 4%); }
|
|
1137
1145
|
.spotpatch-ask-data { display: flex; justify-content: space-between; gap: 10px; color: #aab3c2; font-size: 10.5px; }
|
|
@@ -1230,13 +1238,13 @@ function createContextualAskPanel(input) {
|
|
|
1230
1238
|
const executorField = createMarkedElement(document, "div");
|
|
1231
1239
|
executorField.className = "spotpatch-ask-field";
|
|
1232
1240
|
const executorLabel = createMarkedElement(document, "label");
|
|
1233
|
-
const executorPicker =
|
|
1241
|
+
const executorPicker = createSelectPicker(document, input.onViewChange);
|
|
1234
1242
|
const executorSelect = executorPicker.select;
|
|
1235
1243
|
executorLabel.htmlFor = executorPicker.trigger.id;
|
|
1236
1244
|
const modelField = createMarkedElement(document, "div");
|
|
1237
1245
|
modelField.className = "spotpatch-ask-field";
|
|
1238
1246
|
const modelLabel = createMarkedElement(document, "label");
|
|
1239
|
-
const modelPicker =
|
|
1247
|
+
const modelPicker = createSelectPicker(document, input.onViewChange);
|
|
1240
1248
|
modelLabel.htmlFor = modelPicker.trigger.id;
|
|
1241
1249
|
modelField.append(modelLabel, modelPicker.root);
|
|
1242
1250
|
let modelExecutorId;
|
|
@@ -1440,7 +1448,7 @@ function createContextualAskPanel(input) {
|
|
|
1440
1448
|
for (const executor of readyExecutors) {
|
|
1441
1449
|
const option = document.createElement("option");
|
|
1442
1450
|
option.value = executor.executorId;
|
|
1443
|
-
option.textContent = executor.models === void 0 ? `${executor.label}
|
|
1451
|
+
option.textContent = executor.models === void 0 ? `${executor.label} · ${executor.effectiveModelLabel}` : executor.label;
|
|
1444
1452
|
executorSelect.append(option);
|
|
1445
1453
|
}
|
|
1446
1454
|
if (readyExecutors.length === 0) {
|
|
@@ -1477,7 +1485,7 @@ function createContextualAskPanel(input) {
|
|
|
1477
1485
|
expandedHeadline: messages.status[snapshot.status],
|
|
1478
1486
|
action: messages.safety,
|
|
1479
1487
|
expandedAction: messages.safety,
|
|
1480
|
-
meta: `${snapshot.executor.label}
|
|
1488
|
+
meta: `${snapshot.executor.label} · ${snapshot.executor.modelLabel}`,
|
|
1481
1489
|
recentActivities: Object.freeze([]),
|
|
1482
1490
|
startedAt: snapshot.createdAt
|
|
1483
1491
|
});
|
|
@@ -1504,7 +1512,7 @@ function createContextualAskPanel(input) {
|
|
|
1504
1512
|
expandedHeadline: messages.status.running,
|
|
1505
1513
|
action: activityLabel,
|
|
1506
1514
|
expandedAction: activityLabel,
|
|
1507
|
-
meta: `${currentJob.executor.label}
|
|
1515
|
+
meta: `${currentJob.executor.label} · ${currentJob.executor.modelLabel}`,
|
|
1508
1516
|
activity: {
|
|
1509
1517
|
key: `ask:${String(event.sequence)}`,
|
|
1510
1518
|
kind: "read",
|