@arraypress/extension-kit 1.10.0 → 1.11.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/README.md +103 -21
- package/bin/extension-kit.js +2 -1
- package/package.json +1 -1
- package/src/ai/host.d.ts +183 -0
- package/src/ai/host.js +225 -0
- package/src/ai/model.d.ts +2 -1
- package/src/ai/model.js +10 -2
- package/src/build/vendor.d.ts +29 -8
- package/src/build/vendor.js +136 -40
- package/src/content/highlight.d.ts +15 -6
- package/src/content/highlight.js +42 -17
- package/src/content/overlay.d.ts +19 -4
- package/src/content/overlay.js +44 -6
- package/src/content/slices.d.ts +3 -1
- package/src/content/slices.js +29 -14
- package/src/content/watch.d.ts +4 -2
- package/src/content/watch.js +17 -3
- package/src/dom/focus.d.ts +11 -0
- package/src/dom/focus.js +15 -0
- package/src/frame/window.d.ts +1 -1
- package/src/frame/window.js +8 -7
- package/src/index.d.ts +10 -3
- package/src/index.js +8 -3
- package/src/panel/show-on-page.d.ts +82 -0
- package/src/panel/show-on-page.js +83 -0
- package/src/scripting/call.d.ts +29 -9
- package/src/scripting/call.js +35 -11
- package/src/scripting/context-menus.d.ts +45 -0
- package/src/scripting/context-menus.js +53 -0
- package/src/scripting/registration.d.ts +2 -1
- package/src/scripting/registration.js +2 -1
- package/src/scripting/tab.d.ts +17 -5
- package/src/scripting/tab.js +15 -7
- package/src/settings/saver.js +16 -6
- package/src/settings/storage.d.ts +33 -2
- package/src/settings/storage.js +73 -3
- package/src/settings/store.d.ts +17 -0
- package/src/settings/store.js +87 -20
- package/src/sites/sites.d.ts +6 -1
- package/src/sites/sites.js +20 -3
- package/src/styles/chrome-ui.css +59 -30
- package/src/testing/e2e.d.ts +35 -4
- package/src/testing/e2e.js +67 -5
- package/src/testing/fake-model.d.ts +9 -1
- package/src/testing/fake-model.js +44 -23
- package/src/testing/fake-storage.d.ts +41 -13
- package/src/testing/fake-storage.js +163 -51
- package/src/testing/index.d.ts +3 -3
- package/src/testing/index.js +5 -3
- package/src/testing/live-run.d.ts +23 -2
- package/src/testing/live-run.js +64 -18
- package/src/testing/messages.d.ts +7 -3
- package/src/testing/messages.js +50 -9
- package/src/testing/package.d.ts +56 -7
- package/src/testing/package.js +57 -18
- package/src/testing/prompt.d.ts +4 -2
- package/src/testing/prompt.js +7 -3
- package/src/time/pool.d.ts +2 -1
- package/src/time/pool.js +4 -2
- package/src/toolbar/theme.d.ts +10 -2
- package/src/toolbar/theme.js +12 -4
- package/src/ui/menu.d.ts +13 -3
- package/src/ui/menu.js +48 -11
- package/src/ui/model-row.js +5 -1
- package/src/ui/site-list.js +12 -3
- package/src/ui/text-dialog.d.ts +3 -2
- package/src/ui/text-dialog.js +10 -3
- package/src/ui/toast.d.ts +3 -0
- package/src/ui/toast.js +23 -1
package/src/ui/text-dialog.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* folder's name (`askText`); several, as chrome://settings/searchEngines asks
|
|
5
5
|
* for a site search (`askFields`). The action button stays disabled while a
|
|
6
6
|
* field is blank or isn't valid, with the reason under that field. Enter
|
|
7
|
-
* means the action button, Esc and Cancel cancel
|
|
8
|
-
*
|
|
7
|
+
* means the action button, Esc and Cancel cancel (as does the dialog being
|
|
8
|
+
* closed any other way), and the focus goes back to what opened it. A reason
|
|
9
|
+
* is announced as it appears, and its field marked invalid. The page needs no markup: the dialog (`#text-dialog`) is
|
|
9
10
|
* made the first time, its fields each time it's asked.
|
|
10
11
|
*
|
|
11
12
|
* @module ui/text-dialog
|
|
@@ -178,7 +179,7 @@ function fieldFor(doc, request, only) {
|
|
|
178
179
|
input.value = typeof request.value === 'string' ? request.value : '';
|
|
179
180
|
if (request.placeholder) input.placeholder = request.placeholder;
|
|
180
181
|
if (request.maxLength !== undefined) input.maxLength = request.maxLength;
|
|
181
|
-
const error = element(doc, 'span', { id: ids.error, class: 'hint error' });
|
|
182
|
+
const error = element(doc, 'span', { id: ids.error, class: 'hint error', 'aria-live': 'polite' });
|
|
182
183
|
error.hidden = true;
|
|
183
184
|
const hint = element(doc, 'span', { id: ids.hint, class: 'hint secondary' });
|
|
184
185
|
hint.hidden = true;
|
|
@@ -226,6 +227,9 @@ export function askFields({
|
|
|
226
227
|
const { reason } = waiting ? { reason: '' } : checkText(input.value, request.validate);
|
|
227
228
|
error.textContent = reason;
|
|
228
229
|
error.hidden = !reason;
|
|
230
|
+
// Said to a screen reader as it appears, and the field marked (the stylesheet turns its underline red).
|
|
231
|
+
if (reason) input.setAttribute('aria-invalid', 'true');
|
|
232
|
+
else input.removeAttribute('aria-invalid');
|
|
229
233
|
hint.textContent = waiting ? request.waiting ?? '' : typeof request.hint === 'function' ? request.hint(input.value) : request.hint ?? '';
|
|
230
234
|
hint.hidden = !hint.textContent;
|
|
231
235
|
};
|
|
@@ -291,6 +295,9 @@ export function askFields({
|
|
|
291
295
|
event.preventDefault();
|
|
292
296
|
settle(null);
|
|
293
297
|
}, { signal });
|
|
298
|
+
// Closed any other way (the browser's own close after a second Esc, another script): cancelled, not left unanswered.
|
|
299
|
+
// (The event comes a task after the closing: one from the ask before this, already answered, finds the dialog open again.)
|
|
300
|
+
parts.dialog.addEventListener('close', () => { if (!parts.dialog.open) settle(null); }, { signal });
|
|
294
301
|
|
|
295
302
|
parts.dialog.showModal();
|
|
296
303
|
// The first field still to fill in, or the first, its text selected to type over.
|
package/src/ui/toast.d.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Chrome's toast (cr-toast), bottom left, as chrome://bookmarks shows one
|
|
3
3
|
* after a delete: "Deleted “Research” Undo". One per page, made by
|
|
4
4
|
* {@link createToast}; a new message replaces the last and restarts the wait.
|
|
5
|
+
* While the keyboard focus is on Undo, or the pointer is over the toast, it
|
|
6
|
+
* stays, and the wait starts again in full once they leave (cr-toast stops
|
|
7
|
+
* its timer on `focusin` and restarts it on `focusout`).
|
|
5
8
|
*
|
|
6
9
|
* It's a manual `popover`, so it shows in the top layer: over anything the
|
|
7
10
|
* page stacks (a content script's toast over a site's own fixed bars), and
|
package/src/ui/toast.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Chrome's toast (cr-toast), bottom left, as chrome://bookmarks shows one
|
|
3
3
|
* after a delete: "Deleted “Research” Undo". One per page, made by
|
|
4
4
|
* {@link createToast}; a new message replaces the last and restarts the wait.
|
|
5
|
+
* While the keyboard focus is on Undo, or the pointer is over the toast, it
|
|
6
|
+
* stays, and the wait starts again in full once they leave (cr-toast stops
|
|
7
|
+
* its timer on `focusin` and restarts it on `focusout`).
|
|
5
8
|
*
|
|
6
9
|
* It's a manual `popover`, so it shows in the top layer: over anything the
|
|
7
10
|
* page stacks (a content script's toast over a site's own fixed bars), and
|
|
@@ -75,11 +78,27 @@ export function createToast({ undoLabel = 'Undo', duration = TOAST_MS, undoDurat
|
|
|
75
78
|
/** @type {(() => unknown) | null} */
|
|
76
79
|
let undoLast = null;
|
|
77
80
|
|
|
81
|
+
/** How long the toast showing now stays, once nothing holds it. */
|
|
82
|
+
let stay = duration;
|
|
83
|
+
|
|
78
84
|
const hide = () => {
|
|
79
85
|
clearTimeout(timer);
|
|
80
86
|
toast.togglePopover(false);
|
|
81
87
|
undoLast = null;
|
|
82
88
|
};
|
|
89
|
+
/** Whether the keyboard focus is in the toast (on Undo) or the pointer over it: it stays while either is. */
|
|
90
|
+
const held = () => toast.matches(':focus-within, :hover');
|
|
91
|
+
/** The wait starts again, in full, unless the toast is held: as cr-toast's, whose focusout restarts it. */
|
|
92
|
+
const wait = () => {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
if (!held() && toast.matches(':popover-open')) timer = setTimeout(hide, stay);
|
|
95
|
+
};
|
|
96
|
+
// cr-toast stops its timer on focusin and restarts it on focusout, so Undo can't go from under
|
|
97
|
+
// the keyboard; the pointer over it holds it the same way (WCAG 2.2.1, Timing Adjustable).
|
|
98
|
+
toast.addEventListener('focusin', () => clearTimeout(timer));
|
|
99
|
+
toast.addEventListener('pointerenter', () => clearTimeout(timer));
|
|
100
|
+
toast.addEventListener('focusout', () => queueMicrotask(wait));
|
|
101
|
+
toast.addEventListener('pointerleave', wait);
|
|
83
102
|
undoButton.addEventListener('click', () => {
|
|
84
103
|
const undo = undoLast;
|
|
85
104
|
hide();
|
|
@@ -93,10 +112,13 @@ export function createToast({ undoLabel = 'Undo', duration = TOAST_MS, undoDurat
|
|
|
93
112
|
text.textContent = message;
|
|
94
113
|
undoButton.hidden = !undo;
|
|
95
114
|
undoLast = undo;
|
|
115
|
+
// Taken off the page since (a single-page site replaced its body): put back, or showing it would throw.
|
|
116
|
+
if (!toast.isConnected) (root?.isConnected === false ? doc.body : root ?? doc.body).append(toast);
|
|
96
117
|
// Hidden and shown again, so it's the newest in the top layer (over a popover since).
|
|
97
118
|
toast.togglePopover(false);
|
|
98
119
|
toast.togglePopover(true);
|
|
99
|
-
|
|
120
|
+
stay = undo ? undoDuration : duration;
|
|
121
|
+
wait();
|
|
100
122
|
},
|
|
101
123
|
hide,
|
|
102
124
|
};
|