@oxvo/ai-live-assist 7.4.37 → 7.4.49
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/cjs/AiLiveAssist.d.ts +10 -1
- package/cjs/AiLiveAssist.js +792 -193
- package/cjs/context.d.ts +2 -0
- package/cjs/context.js +213 -22
- package/cjs/index.js +2 -2
- package/cjs/media.js +3 -2
- package/cjs/preview.d.ts +1 -1
- package/cjs/preview.js +2 -1
- package/cjs/types.d.ts +1 -0
- package/cjs/ui.d.ts +9 -0
- package/cjs/ui.js +478 -141
- package/cjs/version.d.ts +1 -1
- package/cjs/version.js +1 -1
- package/lib/AiLiveAssist.d.ts +10 -1
- package/lib/AiLiveAssist.js +792 -193
- package/lib/context.d.ts +2 -0
- package/lib/context.js +213 -22
- package/lib/index.js +2 -2
- package/lib/media.js +3 -2
- package/lib/preview.d.ts +1 -1
- package/lib/preview.js +2 -1
- package/lib/types.d.ts +1 -0
- package/lib/ui.d.ts +9 -0
- package/lib/ui.js +478 -141
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -2
package/lib/context.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class PageContextCollector {
|
|
|
24
24
|
private captureTimer;
|
|
25
25
|
private mutationCaptureTimer;
|
|
26
26
|
private targetIds;
|
|
27
|
+
private navigationTargetBindings;
|
|
27
28
|
private textIds;
|
|
28
29
|
private optionIds;
|
|
29
30
|
private targets;
|
|
@@ -69,6 +70,7 @@ export declare class PageContextCollector {
|
|
|
69
70
|
private beginNavigationSettlement;
|
|
70
71
|
private observeCausalNavigationAfterMutation;
|
|
71
72
|
private reportCausalNavigationObservation;
|
|
73
|
+
private resetBoundTargetIds;
|
|
72
74
|
private installNavigationHooks;
|
|
73
75
|
private restoreNavigationHooks;
|
|
74
76
|
private reducedMotion;
|
package/lib/context.js
CHANGED
|
@@ -7,6 +7,9 @@ const MAX_SELECTED_TEXT = 2000;
|
|
|
7
7
|
const SELECTION_RETENTION_MS = 120000;
|
|
8
8
|
const CAPTURE_SETTLE_MS = 250;
|
|
9
9
|
const MUTATION_CAPTURE_DEBOUNCE_MS = 350;
|
|
10
|
+
const FRAMER_TOGGLE_ROOT_SELECTOR = '[data-framer-name="Toggle"]';
|
|
11
|
+
const FRAMER_TOGGLE_CONTROL_SELECTOR = 'div[name="Toggle Switch"][data-highlight="true"][tabindex]';
|
|
12
|
+
const MAX_FRAMER_TOGGLE_LABEL = 120;
|
|
10
13
|
const PRIVATE_SELECTOR = [
|
|
11
14
|
'[data-oxvo-ai-live-assist-root]',
|
|
12
15
|
'[data-oxvo-private]',
|
|
@@ -37,6 +40,8 @@ const EXPLICIT_SENSITIVITIES = new Set([
|
|
|
37
40
|
'api_secret',
|
|
38
41
|
]);
|
|
39
42
|
const id = (prefix) => `${prefix}_${crypto.randomUUID()}`;
|
|
43
|
+
// The runtime may rebind only IDs whose navigation identity this collector rotates.
|
|
44
|
+
const BOUND_NAVIGATION_TARGET_PREFIX = 'target_bound';
|
|
40
45
|
const normalize = (value, maximum) => value
|
|
41
46
|
.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, '')
|
|
42
47
|
.replace(/\s+/g, ' ')
|
|
@@ -55,6 +60,31 @@ const canonicalJson = (value) => {
|
|
|
55
60
|
};
|
|
56
61
|
return JSON.stringify(sort(value));
|
|
57
62
|
};
|
|
63
|
+
const navigationTargetGeometry = (element) => {
|
|
64
|
+
const rect = element.getBoundingClientRect();
|
|
65
|
+
return {
|
|
66
|
+
x: Math.round(rect.left + window.scrollX),
|
|
67
|
+
y: Math.round(rect.top + window.scrollY),
|
|
68
|
+
width: Math.round(rect.width),
|
|
69
|
+
height: Math.round(rect.height),
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
const navigationTargetBinding = (element, target) => canonicalJson({
|
|
73
|
+
role: target.role,
|
|
74
|
+
name: target.name,
|
|
75
|
+
inputType: target.inputType ?? null,
|
|
76
|
+
autocomplete: target.autocomplete ?? null,
|
|
77
|
+
semanticRegion: target.semanticRegion ?? null,
|
|
78
|
+
destinationPath: target.destinationPath ?? null,
|
|
79
|
+
sensitivity: target.sensitivity,
|
|
80
|
+
protectedRegion: target.protectedRegion ?? null,
|
|
81
|
+
frameOrigin: target.frameOrigin ?? null,
|
|
82
|
+
consequence: target.consequence ?? null,
|
|
83
|
+
regionAssessment: target.regionAssessment ?? null,
|
|
84
|
+
state: target.state,
|
|
85
|
+
options: target.options ?? null,
|
|
86
|
+
geometry: navigationTargetGeometry(element),
|
|
87
|
+
});
|
|
58
88
|
export const actionTargetFingerprint = async (target, subtle = globalThis.crypto?.subtle) => {
|
|
59
89
|
if (!subtle)
|
|
60
90
|
return null;
|
|
@@ -177,6 +207,8 @@ const sensitivityFor = (element, name) => {
|
|
|
177
207
|
return 'none';
|
|
178
208
|
};
|
|
179
209
|
const roleFor = (element) => {
|
|
210
|
+
if (framerToggleDescriptor(element))
|
|
211
|
+
return 'checkbox';
|
|
180
212
|
const explicit = normalize(element.getAttribute('role') ?? '', 64);
|
|
181
213
|
if (explicit)
|
|
182
214
|
return explicit;
|
|
@@ -205,6 +237,9 @@ const roleFor = (element) => {
|
|
|
205
237
|
return tag.slice(0, 64);
|
|
206
238
|
};
|
|
207
239
|
const nameFor = (element) => {
|
|
240
|
+
const framerToggle = framerToggleDescriptor(element);
|
|
241
|
+
if (framerToggle)
|
|
242
|
+
return framerToggle.name;
|
|
208
243
|
const input = element instanceof HTMLInputElement ? element : null;
|
|
209
244
|
const formControl = element instanceof HTMLInputElement ||
|
|
210
245
|
element instanceof HTMLSelectElement ||
|
|
@@ -316,6 +351,131 @@ const safeAccessibleNameText = (element, maximum) => {
|
|
|
316
351
|
const text = safeDescendantText(element, maximum, true);
|
|
317
352
|
return text && sensitivityFor(element, text) === 'none' ? text : '';
|
|
318
353
|
};
|
|
354
|
+
const safeFramerToggleLabel = (element) => {
|
|
355
|
+
if (!isVisible(element) ||
|
|
356
|
+
element.closest(PRIVATE_SELECTOR) ||
|
|
357
|
+
element.querySelector(PRIVATE_SELECTOR) ||
|
|
358
|
+
element.matches('a[href],button,input,select,textarea,summary,form,[contenteditable="true"],[role],[tabindex]') ||
|
|
359
|
+
element.querySelector('a[href],button,input,select,textarea,summary,form,[contenteditable="true"],[role],[tabindex]')) {
|
|
360
|
+
return '';
|
|
361
|
+
}
|
|
362
|
+
const label = safeDescendantText(element, MAX_FRAMER_TOGGLE_LABEL + 1);
|
|
363
|
+
if (!label ||
|
|
364
|
+
label.length > MAX_FRAMER_TOGGLE_LABEL ||
|
|
365
|
+
sensitivityFor(element, label) !== 'none') {
|
|
366
|
+
return '';
|
|
367
|
+
}
|
|
368
|
+
return label;
|
|
369
|
+
};
|
|
370
|
+
function framerToggleDescriptor(element) {
|
|
371
|
+
if (element.tagName !== 'DIV' ||
|
|
372
|
+
element.getAttribute('name') !== 'Toggle Switch' ||
|
|
373
|
+
element.getAttribute('data-highlight') !== 'true' ||
|
|
374
|
+
!element.hasAttribute('tabindex') ||
|
|
375
|
+
!(element instanceof HTMLElement) ||
|
|
376
|
+
element.tabIndex < 0) {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
const state = element.getAttribute('data-framer-name');
|
|
380
|
+
if (state !== 'Off' && state !== 'On')
|
|
381
|
+
return null;
|
|
382
|
+
const root = element.closest(FRAMER_TOGGLE_ROOT_SELECTOR);
|
|
383
|
+
if (!root || root === element || root.closest(PRIVATE_SELECTOR))
|
|
384
|
+
return null;
|
|
385
|
+
const controls = Array.from(root.querySelectorAll(FRAMER_TOGGLE_CONTROL_SELECTOR));
|
|
386
|
+
if (controls.length !== 1 || controls[0] !== element)
|
|
387
|
+
return null;
|
|
388
|
+
let controlBranch = element;
|
|
389
|
+
while (controlBranch.parentElement && controlBranch.parentElement !== root) {
|
|
390
|
+
controlBranch = controlBranch.parentElement;
|
|
391
|
+
}
|
|
392
|
+
if (controlBranch.parentElement !== root)
|
|
393
|
+
return null;
|
|
394
|
+
const labels = [controlBranch.previousElementSibling, controlBranch.nextElementSibling]
|
|
395
|
+
.flatMap((candidate) => (candidate ? [safeFramerToggleLabel(candidate)] : []))
|
|
396
|
+
.filter(Boolean);
|
|
397
|
+
if (labels.length !== 1)
|
|
398
|
+
return null;
|
|
399
|
+
return { checked: state === 'On', name: labels[0] };
|
|
400
|
+
}
|
|
401
|
+
const checkedStateFor = (element) => {
|
|
402
|
+
if (element instanceof HTMLInputElement && ['checkbox', 'radio'].includes(element.type)) {
|
|
403
|
+
return element.checked;
|
|
404
|
+
}
|
|
405
|
+
return framerToggleDescriptor(element)?.checked;
|
|
406
|
+
};
|
|
407
|
+
const dispatchFramerTogglePrimaryPointer = (element) => {
|
|
408
|
+
if (!framerToggleDescriptor(element) || typeof window.PointerEvent !== 'function') {
|
|
409
|
+
throw new Error('Framer toggle pointer interaction is unavailable.');
|
|
410
|
+
}
|
|
411
|
+
const rect = element.getBoundingClientRect();
|
|
412
|
+
const clientX = rect.left + rect.width / 2;
|
|
413
|
+
const clientY = rect.top + rect.height / 2;
|
|
414
|
+
const shared = {
|
|
415
|
+
view: window,
|
|
416
|
+
bubbles: true,
|
|
417
|
+
cancelable: true,
|
|
418
|
+
composed: true,
|
|
419
|
+
clientX,
|
|
420
|
+
clientY,
|
|
421
|
+
};
|
|
422
|
+
const pointer = (type, init) => {
|
|
423
|
+
element.dispatchEvent(new window.PointerEvent(type, {
|
|
424
|
+
...shared,
|
|
425
|
+
pointerId: 1,
|
|
426
|
+
pointerType: 'mouse',
|
|
427
|
+
width: 1,
|
|
428
|
+
height: 1,
|
|
429
|
+
isPrimary: true,
|
|
430
|
+
...init,
|
|
431
|
+
}));
|
|
432
|
+
};
|
|
433
|
+
const mouse = (type, init) => {
|
|
434
|
+
element.dispatchEvent(new MouseEvent(type, { ...shared, ...init }));
|
|
435
|
+
};
|
|
436
|
+
pointer('pointerover', { button: -1, buttons: 0 });
|
|
437
|
+
element.dispatchEvent(new window.PointerEvent('pointerenter', {
|
|
438
|
+
...shared,
|
|
439
|
+
bubbles: false,
|
|
440
|
+
cancelable: false,
|
|
441
|
+
pointerId: 1,
|
|
442
|
+
pointerType: 'mouse',
|
|
443
|
+
width: 1,
|
|
444
|
+
height: 1,
|
|
445
|
+
isPrimary: true,
|
|
446
|
+
button: -1,
|
|
447
|
+
buttons: 0,
|
|
448
|
+
}));
|
|
449
|
+
mouse('mouseover', { button: 0, buttons: 0, detail: 0 });
|
|
450
|
+
element.dispatchEvent(new MouseEvent('mouseenter', {
|
|
451
|
+
...shared,
|
|
452
|
+
bubbles: false,
|
|
453
|
+
cancelable: false,
|
|
454
|
+
button: 0,
|
|
455
|
+
buttons: 0,
|
|
456
|
+
detail: 0,
|
|
457
|
+
}));
|
|
458
|
+
pointer('pointermove', { button: -1, buttons: 0 });
|
|
459
|
+
mouse('mousemove', { button: 0, buttons: 0, detail: 0 });
|
|
460
|
+
pointer('pointerdown', { button: 0, buttons: 1 });
|
|
461
|
+
mouse('mousedown', { button: 0, buttons: 1, detail: 1 });
|
|
462
|
+
element.focus({ preventScroll: true });
|
|
463
|
+
pointer('pointerup', { button: 0, buttons: 0 });
|
|
464
|
+
mouse('mouseup', { button: 0, buttons: 0, detail: 1 });
|
|
465
|
+
// Chromium's trusted mouse sequence keeps pointerId 1 on click but reports
|
|
466
|
+
// isPrimary false; these fields are trace-bound rather than normalized.
|
|
467
|
+
element.dispatchEvent(new window.PointerEvent('click', {
|
|
468
|
+
...shared,
|
|
469
|
+
pointerId: 1,
|
|
470
|
+
pointerType: 'mouse',
|
|
471
|
+
width: 1,
|
|
472
|
+
height: 1,
|
|
473
|
+
isPrimary: false,
|
|
474
|
+
button: 0,
|
|
475
|
+
buttons: 0,
|
|
476
|
+
detail: 1,
|
|
477
|
+
}));
|
|
478
|
+
};
|
|
319
479
|
const semanticSourceSensitivity = (source) => {
|
|
320
480
|
if (source.closest(PRIVATE_SELECTOR) || source.querySelector(PRIVATE_SELECTOR)) {
|
|
321
481
|
return 'private';
|
|
@@ -478,6 +638,7 @@ export class PageContextCollector {
|
|
|
478
638
|
this.captureTimer = null;
|
|
479
639
|
this.mutationCaptureTimer = null;
|
|
480
640
|
this.targetIds = new WeakMap();
|
|
641
|
+
this.navigationTargetBindings = new WeakMap();
|
|
481
642
|
this.textIds = new WeakMap();
|
|
482
643
|
this.optionIds = new WeakMap();
|
|
483
644
|
this.targets = new Map();
|
|
@@ -561,6 +722,7 @@ export class PageContextCollector {
|
|
|
561
722
|
this.pageId = id('page');
|
|
562
723
|
this.revision += 1;
|
|
563
724
|
this.targets.clear();
|
|
725
|
+
this.resetBoundTargetIds();
|
|
564
726
|
this.recentSelection = null;
|
|
565
727
|
if (this.executingActionId) {
|
|
566
728
|
this.pendingNavigation = {
|
|
@@ -636,6 +798,7 @@ export class PageContextCollector {
|
|
|
636
798
|
'aria-pressed',
|
|
637
799
|
'aria-live',
|
|
638
800
|
'class',
|
|
801
|
+
'data-framer-name',
|
|
639
802
|
'disabled',
|
|
640
803
|
'href',
|
|
641
804
|
'hidden',
|
|
@@ -731,8 +894,6 @@ export class PageContextCollector {
|
|
|
731
894
|
const name = nameFor(element);
|
|
732
895
|
if (!name && !['form', 'textbox'].includes(role))
|
|
733
896
|
continue;
|
|
734
|
-
const targetId = this.targetIds.get(element) ?? id('target');
|
|
735
|
-
this.targetIds.set(element, targetId);
|
|
736
897
|
const optionMap = new Map();
|
|
737
898
|
let options;
|
|
738
899
|
if (element instanceof HTMLSelectElement) {
|
|
@@ -777,9 +938,8 @@ export class PageContextCollector {
|
|
|
777
938
|
const destinationPath = safeDestinationPath(element);
|
|
778
939
|
const expanded = literalBooleanAttribute(element, 'aria-expanded');
|
|
779
940
|
const pressed = literalBooleanAttribute(element, 'aria-pressed');
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
revision,
|
|
941
|
+
const checked = checkedStateFor(element);
|
|
942
|
+
const targetIdentity = {
|
|
783
943
|
role,
|
|
784
944
|
name,
|
|
785
945
|
...(element instanceof HTMLInputElement || element instanceof HTMLButtonElement
|
|
@@ -803,14 +963,38 @@ export class PageContextCollector {
|
|
|
803
963
|
visible,
|
|
804
964
|
enabled: enabled(element),
|
|
805
965
|
covered: visible ? isCovered(element, this.trustedGuideRoot) : false,
|
|
806
|
-
...(
|
|
807
|
-
? { checked: element.checked }
|
|
808
|
-
: {}),
|
|
966
|
+
...(checked !== undefined ? { checked } : {}),
|
|
809
967
|
...(this.statefulButtonActionProof && expanded !== undefined ? { expanded } : {}),
|
|
810
968
|
...(this.statefulButtonActionProof && pressed !== undefined ? { pressed } : {}),
|
|
811
969
|
},
|
|
812
970
|
...(options ? { options } : {}),
|
|
813
971
|
};
|
|
972
|
+
const priorTargetId = this.targetIds.get(element);
|
|
973
|
+
const boundNavigation = targetIdentity.consequence === 'navigation' &&
|
|
974
|
+
typeof targetIdentity.destinationPath === 'string';
|
|
975
|
+
const binding = boundNavigation
|
|
976
|
+
? navigationTargetBinding(element, targetIdentity)
|
|
977
|
+
: null;
|
|
978
|
+
const priorBinding = this.navigationTargetBindings.get(element);
|
|
979
|
+
const targetId = binding
|
|
980
|
+
? priorTargetId?.startsWith(`${BOUND_NAVIGATION_TARGET_PREFIX}_`) &&
|
|
981
|
+
priorBinding === binding
|
|
982
|
+
? priorTargetId
|
|
983
|
+
: id(BOUND_NAVIGATION_TARGET_PREFIX)
|
|
984
|
+
: priorTargetId &&
|
|
985
|
+
!priorTargetId.startsWith(`${BOUND_NAVIGATION_TARGET_PREFIX}_`)
|
|
986
|
+
? priorTargetId
|
|
987
|
+
: id('target');
|
|
988
|
+
this.targetIds.set(element, targetId);
|
|
989
|
+
if (binding)
|
|
990
|
+
this.navigationTargetBindings.set(element, binding);
|
|
991
|
+
else
|
|
992
|
+
this.navigationTargetBindings.delete(element);
|
|
993
|
+
const target = {
|
|
994
|
+
targetId,
|
|
995
|
+
revision,
|
|
996
|
+
...targetIdentity,
|
|
997
|
+
};
|
|
814
998
|
targetValues.push(target);
|
|
815
999
|
nextTargets.set(targetId, { element, revision, options: optionMap, target });
|
|
816
1000
|
}
|
|
@@ -1015,8 +1199,7 @@ export class PageContextCollector {
|
|
|
1015
1199
|
const sensitivity = sensitivityFor(element, nameFor(element));
|
|
1016
1200
|
const canRevealDesiredStateTarget = grant.action === 'click' &&
|
|
1017
1201
|
grant.desiredChecked !== undefined &&
|
|
1018
|
-
element
|
|
1019
|
-
['checkbox', 'radio'].includes(element.type);
|
|
1202
|
+
checkedStateFor(element) !== undefined;
|
|
1020
1203
|
if (sensitivity !== 'none' ||
|
|
1021
1204
|
handle.target.protectedRegion !== false ||
|
|
1022
1205
|
!isRendered(element) ||
|
|
@@ -1123,6 +1306,7 @@ export class PageContextCollector {
|
|
|
1123
1306
|
const pressed = attached
|
|
1124
1307
|
? literalBooleanAttribute(element, 'aria-pressed')
|
|
1125
1308
|
: undefined;
|
|
1309
|
+
const checked = attached ? checkedStateFor(element) : undefined;
|
|
1126
1310
|
this.callbacks.onHighlight(attached ? element : null, 'success');
|
|
1127
1311
|
return {
|
|
1128
1312
|
...base,
|
|
@@ -1144,9 +1328,7 @@ export class PageContextCollector {
|
|
|
1144
1328
|
: grant.desiredExpanded !== undefined || grant.desiredPressed !== undefined
|
|
1145
1329
|
? 'The requested button state was applied.'
|
|
1146
1330
|
: `${grant.action} executed on the approved ${roleFor(element)} target.`,
|
|
1147
|
-
...(
|
|
1148
|
-
? { checked: element.checked }
|
|
1149
|
-
: {}),
|
|
1331
|
+
...(checked !== undefined ? { checked } : {}),
|
|
1150
1332
|
...(this.statefulButtonActionProof && expanded !== undefined ? { expanded } : {}),
|
|
1151
1333
|
...(this.statefulButtonActionProof && pressed !== undefined ? { pressed } : {}),
|
|
1152
1334
|
},
|
|
@@ -1210,11 +1392,15 @@ export class PageContextCollector {
|
|
|
1210
1392
|
}
|
|
1211
1393
|
const desiredStates = [];
|
|
1212
1394
|
if (desiredChecked !== undefined) {
|
|
1213
|
-
|
|
1395
|
+
const checked = checkedStateFor(element);
|
|
1396
|
+
if (checked === undefined) {
|
|
1214
1397
|
throw new Error('Desired checked state requires a checkbox or radio target.');
|
|
1215
1398
|
}
|
|
1216
|
-
desiredStates.push(
|
|
1217
|
-
if (element
|
|
1399
|
+
desiredStates.push(checked === desiredChecked);
|
|
1400
|
+
if (element instanceof HTMLInputElement &&
|
|
1401
|
+
element.type === 'radio' &&
|
|
1402
|
+
!desiredChecked &&
|
|
1403
|
+
element.checked !== desiredChecked) {
|
|
1218
1404
|
throw new Error('A radio target cannot be cleared by clicking it.');
|
|
1219
1405
|
}
|
|
1220
1406
|
}
|
|
@@ -1234,6 +1420,10 @@ export class PageContextCollector {
|
|
|
1234
1420
|
}
|
|
1235
1421
|
if (desiredStates.length > 0 && desiredStates.every(Boolean))
|
|
1236
1422
|
return;
|
|
1423
|
+
if (desiredChecked !== undefined && framerToggleDescriptor(element)) {
|
|
1424
|
+
dispatchFramerTogglePrimaryPointer(element);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1237
1427
|
if (element instanceof HTMLAnchorElement) {
|
|
1238
1428
|
const target = new URL(element.href, window.location.href);
|
|
1239
1429
|
if (expectedDestinationPath !== undefined &&
|
|
@@ -1352,18 +1542,14 @@ export class PageContextCollector {
|
|
|
1352
1542
|
disabled: !enabled(element),
|
|
1353
1543
|
expanded: element.getAttribute('aria-expanded'),
|
|
1354
1544
|
pressed: element.getAttribute('aria-pressed'),
|
|
1355
|
-
checked:
|
|
1356
|
-
? element.checked
|
|
1357
|
-
: undefined,
|
|
1545
|
+
checked: checkedStateFor(element),
|
|
1358
1546
|
selectedIndex: element instanceof HTMLSelectElement ? element.selectedIndex : undefined,
|
|
1359
1547
|
path: window.location.pathname,
|
|
1360
1548
|
});
|
|
1361
1549
|
}
|
|
1362
1550
|
actionApplied(grant, element, handle) {
|
|
1363
1551
|
if (grant.desiredChecked !== undefined) {
|
|
1364
|
-
return (element
|
|
1365
|
-
['checkbox', 'radio'].includes(element.type) &&
|
|
1366
|
-
element.checked === grant.desiredChecked);
|
|
1552
|
+
return checkedStateFor(element) === grant.desiredChecked;
|
|
1367
1553
|
}
|
|
1368
1554
|
if (grant.desiredExpanded !== undefined &&
|
|
1369
1555
|
literalBooleanAttribute(element, 'aria-expanded') !== grant.desiredExpanded) {
|
|
@@ -1518,6 +1704,7 @@ export class PageContextCollector {
|
|
|
1518
1704
|
this.pageId = id('page');
|
|
1519
1705
|
this.revision += 1;
|
|
1520
1706
|
this.targets.clear();
|
|
1707
|
+
this.resetBoundTargetIds();
|
|
1521
1708
|
this.recentSelection = null;
|
|
1522
1709
|
this.pendingNavigation = {
|
|
1523
1710
|
pageId: this.pageId,
|
|
@@ -1537,6 +1724,10 @@ export class PageContextCollector {
|
|
|
1537
1724
|
navigation.causalObservationReported = true;
|
|
1538
1725
|
this.callbacks.onCausalNavigationObserved?.(navigation.pageId, navigation.revision, navigation.url, navigation.causalActionId);
|
|
1539
1726
|
}
|
|
1727
|
+
resetBoundTargetIds() {
|
|
1728
|
+
this.targetIds = new WeakMap();
|
|
1729
|
+
this.navigationTargetBindings = new WeakMap();
|
|
1730
|
+
}
|
|
1540
1731
|
installNavigationHooks() {
|
|
1541
1732
|
this.originalPushState = history.pushState;
|
|
1542
1733
|
this.originalReplaceState = history.replaceState;
|
package/lib/index.js
CHANGED
|
@@ -12,8 +12,8 @@ export default function aiLiveAssist(options = {}) {
|
|
|
12
12
|
if (document.querySelector('[data-oxvo-ai-live-assist-root]')) {
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
|
-
if (!app.checkRequiredVersion?.('7.4.
|
|
16
|
-
console.warn('OXVO AI Guide requires @oxvo/browser version 7.4.
|
|
15
|
+
if (!app.checkRequiredVersion?.('7.4.49')) {
|
|
16
|
+
console.warn('OXVO AI Guide requires @oxvo/browser version 7.4.49 or newer.');
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
19
|
const instance = new AiLiveAssist(app, options);
|
package/lib/media.js
CHANGED
|
@@ -154,8 +154,9 @@ export class RealtimeMedia {
|
|
|
154
154
|
switchToTextOnly() {
|
|
155
155
|
this.revokeLocalAudioCapture();
|
|
156
156
|
for (const sender of this.connection?.getSenders() ?? []) {
|
|
157
|
-
if (sender.track?.kind === "audio")
|
|
158
|
-
void sender.replaceTrack(null);
|
|
157
|
+
if (sender.track?.kind === "audio") {
|
|
158
|
+
void sender.replaceTrack(null).catch(() => undefined);
|
|
159
|
+
}
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
close() {
|
package/lib/preview.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AiGuidePreviewBridge, AiGuidePreviewController, AiGuidePreviewCont
|
|
|
2
2
|
export declare const AI_GUIDE_PREVIEW_PARENT_SOURCE = "oxvo-ai-guide-settings-preview";
|
|
3
3
|
export declare const AI_GUIDE_PREVIEW_WIDGET_SOURCE = "oxvo-ai-guide-widget-preview";
|
|
4
4
|
export declare const AI_GUIDE_PREVIEW_PROTOCOL_VERSION = 1;
|
|
5
|
-
export declare const AI_GUIDE_PREVIEW_RENDERER_VERSION = "1.0.
|
|
5
|
+
export declare const AI_GUIDE_PREVIEW_RENDERER_VERSION = "1.0.48";
|
|
6
6
|
export declare const buildAiGuidePreviewBootstrap: (draft: unknown, assetOrigin?: string | null) => BootstrapConfig;
|
|
7
7
|
export declare class AiGuidePreviewControllerImpl implements AiGuidePreviewController {
|
|
8
8
|
private readonly port;
|
package/lib/preview.js
CHANGED
|
@@ -6,7 +6,7 @@ import { VoicePresenceView } from "./voicePresenceUi.js";
|
|
|
6
6
|
export const AI_GUIDE_PREVIEW_PARENT_SOURCE = "oxvo-ai-guide-settings-preview";
|
|
7
7
|
export const AI_GUIDE_PREVIEW_WIDGET_SOURCE = "oxvo-ai-guide-widget-preview";
|
|
8
8
|
export const AI_GUIDE_PREVIEW_PROTOCOL_VERSION = 1;
|
|
9
|
-
export const AI_GUIDE_PREVIEW_RENDERER_VERSION = "1.0.
|
|
9
|
+
export const AI_GUIDE_PREVIEW_RENDERER_VERSION = "1.0.48";
|
|
10
10
|
const DEFAULT_COMPANION = {
|
|
11
11
|
enabled: true,
|
|
12
12
|
title: "AI Guide",
|
|
@@ -266,6 +266,7 @@ export const buildAiGuidePreviewBootstrap = (draft, assetOrigin = typeof window
|
|
|
266
266
|
customDisclosureEnabled,
|
|
267
267
|
welcomeMessage: boundedNullableString(source.welcomeMessage, 1000),
|
|
268
268
|
conversationStartersEnabled: booleanValue(appearance.conversationStartersEnabled, true),
|
|
269
|
+
compactEntryEnabled: booleanValue(appearance.compactEntryEnabled, false),
|
|
269
270
|
suggestedPrompts: boundedStringList(appearance.suggestedPrompts, 5),
|
|
270
271
|
proactiveEngagement: {
|
|
271
272
|
enabled: booleanValue(proactive.enabled, false),
|
package/lib/types.d.ts
CHANGED
|
@@ -189,6 +189,7 @@ export type BootstrapConfig = {
|
|
|
189
189
|
customDisclosureEnabled?: boolean;
|
|
190
190
|
welcomeMessage: string | null;
|
|
191
191
|
conversationStartersEnabled?: boolean;
|
|
192
|
+
compactEntryEnabled?: boolean;
|
|
192
193
|
suggestedPrompts?: string[];
|
|
193
194
|
proactiveEngagement?: ProactiveEngagementConfig;
|
|
194
195
|
voicePresence?: VoicePresenceConfig;
|
package/lib/ui.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ export declare class WidgetView {
|
|
|
96
96
|
private currentHandoffContextRequest;
|
|
97
97
|
private handoffRequestPreparing;
|
|
98
98
|
private currentPageAssistanceRequest;
|
|
99
|
+
private pageAssistancePresentationSnapshot;
|
|
99
100
|
private safetyInteractionIdentity;
|
|
100
101
|
private introComposing;
|
|
101
102
|
private legalOpenedPanel;
|
|
@@ -110,6 +111,7 @@ export declare class WidgetView {
|
|
|
110
111
|
private tooltipTarget;
|
|
111
112
|
private tooltipTimer;
|
|
112
113
|
private ambientHideTimer;
|
|
114
|
+
private voiceCardEffectSettleTimer;
|
|
113
115
|
private attributionTimer;
|
|
114
116
|
private feedbackExitTimer;
|
|
115
117
|
private assistantReadyVisualTimer;
|
|
@@ -155,6 +157,7 @@ export declare class WidgetView {
|
|
|
155
157
|
setRemoteStream(stream: MediaStream): void;
|
|
156
158
|
private playRemoteAudio;
|
|
157
159
|
private invalidateRemotePlayback;
|
|
160
|
+
private pauseRemotePlayback;
|
|
158
161
|
private resetRemotePlayback;
|
|
159
162
|
private onPlaybackActivation;
|
|
160
163
|
private playbackEventIsCurrent;
|
|
@@ -167,6 +170,10 @@ export declare class WidgetView {
|
|
|
167
170
|
updatePreviewConfig(config: BootstrapConfig): boolean;
|
|
168
171
|
private disablePreviewNavigation;
|
|
169
172
|
private applyActivity;
|
|
173
|
+
private effectActivityIsBusy;
|
|
174
|
+
private beginVoiceCardEffectSettle;
|
|
175
|
+
private clearVoiceCardEffectSettle;
|
|
176
|
+
private voiceCardEffectElements;
|
|
170
177
|
private effectsCanRun;
|
|
171
178
|
private isReducedMotionRequested;
|
|
172
179
|
private syncEffectMotion;
|
|
@@ -228,6 +235,7 @@ export declare class WidgetView {
|
|
|
228
235
|
dismissHandoffContextRequest(): void;
|
|
229
236
|
showHandoffContextResult(status: HandoffContextStatus): void;
|
|
230
237
|
showPageAssistanceRequest(value: PageAssistanceRequest): void;
|
|
238
|
+
private syncPageAssistancePresentation;
|
|
231
239
|
private syncPageAssistanceFooter;
|
|
232
240
|
dismissPageAssistanceRequest(): void;
|
|
233
241
|
setPageAssistancePersistentAllowed(value: boolean): void;
|
|
@@ -356,6 +364,7 @@ export declare class WidgetView {
|
|
|
356
364
|
private removeStoredPanelVisibility;
|
|
357
365
|
private clearPanelSessionState;
|
|
358
366
|
private syncLauncherState;
|
|
367
|
+
private compactEntryEnabled;
|
|
359
368
|
cancelPendingConfirmation(): boolean;
|
|
360
369
|
resolvePendingConfirmation(approved: boolean, expected?: {
|
|
361
370
|
actionId: string;
|