@blario/react-native 0.1.5 → 0.1.6
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 +4 -2
- package/dist/BlarProvider.d.ts +2 -0
- package/dist/actions/select.d.ts +1 -1
- package/dist/actions/text-input.d.ts +1 -0
- package/dist/agent/compose.d.ts +1 -0
- package/dist/agent-mode/keyboard-guard.d.ts +13 -0
- package/dist/snapshot/capture.d.ts +1 -0
- package/dist/snapshot/visibility.d.ts +1 -1
- package/dist/snapshot/wrappers.d.ts +0 -2
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/BlarProvider.tsx +13 -0
- package/src/actions/executor.ts +6 -3
- package/src/actions/select.ts +16 -2
- package/src/actions/text-input.ts +30 -1
- package/src/agent/compose.ts +2 -0
- package/src/agent/controller.ts +3 -1
- package/src/agent-mode/keyboard-guard.ts +33 -0
- package/src/chat/ChatSheet.tsx +29 -9
- package/src/chat/ChatView.tsx +1 -1
- package/src/chat/widget-bundle.generated.ts +2 -2
- package/src/snapshot/capture.ts +8 -6
- package/src/snapshot/render.ts +1 -1
- package/src/snapshot/visibility.ts +11 -10
- package/src/snapshot/wrappers.ts +0 -13
- package/src/version.ts +1 -1
package/src/snapshot/capture.ts
CHANGED
|
@@ -12,8 +12,8 @@ import { describeScrollDirections } from './scroll.ts';
|
|
|
12
12
|
import { groupIntoLines, limitCharacters, type PositionedText } from './text-layout.ts';
|
|
13
13
|
import { orderForReading } from './ordering.ts';
|
|
14
14
|
import { buildView } from './view.ts';
|
|
15
|
-
import { classifyVisibility, keepInTextTree, measureScrollGeometries, type ScrollGeometries } from './visibility.ts';
|
|
16
|
-
import { dropWrapperDuplicates,
|
|
15
|
+
import { classifyVisibility, keepInTextTree, markOffscreenText, measureScrollGeometries, type ScrollGeometries } from './visibility.ts';
|
|
16
|
+
import { dropWrapperDuplicates, type MeasuredCandidate } from './wrappers.ts';
|
|
17
17
|
|
|
18
18
|
export interface Snapshot {
|
|
19
19
|
screen: string;
|
|
@@ -27,6 +27,7 @@ export interface SnapshotDependencies {
|
|
|
27
27
|
getAnchorFiber: () => Fiber | null;
|
|
28
28
|
registry: ElementRegistry;
|
|
29
29
|
getViewport: () => Size;
|
|
30
|
+
getWindow: () => Size;
|
|
30
31
|
getExtraRoutes: () => string[];
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -77,7 +78,7 @@ export class SnapshotCapturer {
|
|
|
77
78
|
return null;
|
|
78
79
|
}
|
|
79
80
|
const visibility = classifyVisibility(rect, viewport, block.scrollContainers, geometries);
|
|
80
|
-
return keepInTextTree(visibility, rect, viewport, options.viewportOnly) ? { rect, text: block.text, heading: block.heading } : null;
|
|
81
|
+
return keepInTextTree(visibility, rect, viewport, options.viewportOnly) ? { rect, text: markOffscreenText(visibility, block.text), heading: block.heading } : null;
|
|
81
82
|
}),
|
|
82
83
|
);
|
|
83
84
|
const lines = limitCharacters(groupIntoLines(measured.filter((entry): entry is PositionedText => entry !== null)), options.maxChars);
|
|
@@ -91,8 +92,9 @@ export class SnapshotCapturer {
|
|
|
91
92
|
return root === null ? [] : collect(root).focusedScreens;
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
// The whole window, not the part above the keyboard: what the keyboard covers is still pressable.
|
|
94
96
|
private async measureVisible(kept: Candidate[], geometries: ScrollGeometries): Promise<MeasuredCandidate[]> {
|
|
95
|
-
const viewport = this.dependencies.
|
|
97
|
+
const viewport = this.dependencies.getWindow();
|
|
96
98
|
const measured = await Promise.all(
|
|
97
99
|
kept.map(async (candidate): Promise<MeasuredCandidate | null> => {
|
|
98
100
|
const rect = await measureHost(candidate.host);
|
|
@@ -104,10 +106,10 @@ export class SnapshotCapturer {
|
|
|
104
106
|
return null;
|
|
105
107
|
}
|
|
106
108
|
const offscreen = visibility.kind === 'offscreen' ? visibility : null;
|
|
107
|
-
return { candidate, rect, offscreen: offscreen?.direction ?? null
|
|
109
|
+
return { candidate, rect, offscreen: offscreen?.direction ?? null };
|
|
108
110
|
}),
|
|
109
111
|
);
|
|
110
|
-
return
|
|
112
|
+
return measured.filter((entry): entry is MeasuredCandidate => entry !== null);
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
private assemble(
|
package/src/snapshot/render.ts
CHANGED
|
@@ -17,7 +17,7 @@ function flag(name: string, enabled: boolean): Attribute {
|
|
|
17
17
|
function renderAttributes(attributes: Attribute[]): string {
|
|
18
18
|
return attributes
|
|
19
19
|
.filter((attribute): attribute is readonly [string, string] => attribute[1] !== null)
|
|
20
|
-
.map(([name, value]) => (value === '' ? name : `${name}=${clip(value, ATTRIBUTE_LIMIT)}`))
|
|
20
|
+
.map(([name, value]) => (value === '' ? name : `${name}=${name === 'list' ? value : clip(value, ATTRIBUTE_LIMIT)}`))
|
|
21
21
|
.filter((rendered) => rendered.length > 0)
|
|
22
22
|
.join(' ');
|
|
23
23
|
}
|
|
@@ -16,7 +16,7 @@ export type Offscreen = 'above' | 'below' | 'left' | 'right';
|
|
|
16
16
|
|
|
17
17
|
export type Visibility =
|
|
18
18
|
| { kind: 'visible' }
|
|
19
|
-
| { kind: 'offscreen'; direction: Offscreen
|
|
19
|
+
| { kind: 'offscreen'; direction: Offscreen }
|
|
20
20
|
| { kind: 'hidden' };
|
|
21
21
|
|
|
22
22
|
const VISIBLE: Visibility = { kind: 'visible' };
|
|
@@ -25,13 +25,9 @@ const HIDDEN: Visibility = { kind: 'hidden' };
|
|
|
25
25
|
function offscreenAgainst(rect: Rect, geometry: ScrollGeometry): Visibility {
|
|
26
26
|
const { viewport, horizontal } = geometry;
|
|
27
27
|
if (horizontal) {
|
|
28
|
-
return rect.x >= viewport.x + viewport.width
|
|
29
|
-
? { kind: 'offscreen', direction: 'right', distance: rect.x - (viewport.x + viewport.width) }
|
|
30
|
-
: { kind: 'offscreen', direction: 'left', distance: viewport.x - (rect.x + rect.width) };
|
|
28
|
+
return { kind: 'offscreen', direction: rect.x >= viewport.x + viewport.width ? 'right' : 'left' };
|
|
31
29
|
}
|
|
32
|
-
return rect.y >= viewport.y + viewport.height
|
|
33
|
-
? { kind: 'offscreen', direction: 'below', distance: rect.y - (viewport.y + viewport.height) }
|
|
34
|
-
: { kind: 'offscreen', direction: 'above', distance: viewport.y - (rect.y + rect.height) };
|
|
30
|
+
return { kind: 'offscreen', direction: rect.y >= viewport.y + viewport.height ? 'below' : 'above' };
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
export function classifyVisibility(rect: Rect, window: Size, containers: Fiber[], geometries: ScrollGeometries): Visibility {
|
|
@@ -52,10 +48,15 @@ function isBeyondWindowEdge(rect: Rect, window: Size): boolean {
|
|
|
52
48
|
return rect.x >= window.width || rect.x + rect.width <= 0;
|
|
53
49
|
}
|
|
54
50
|
|
|
51
|
+
const OFFSCREEN_MARK = '[off-screen]';
|
|
52
|
+
|
|
53
|
+
// Text off to the side can be another page of a pager or another day of a calendar, so it can't read as what's on screen.
|
|
54
|
+
export function markOffscreenText(visibility: Visibility, text: string): string {
|
|
55
|
+
const sideways = visibility.kind === 'offscreen' && (visibility.direction === 'left' || visibility.direction === 'right');
|
|
56
|
+
return sideways ? `${OFFSCREEN_MARK} ${text}` : text;
|
|
57
|
+
}
|
|
58
|
+
|
|
55
59
|
export function keepInTextTree(visibility: Visibility, rect: Rect, window: Size, viewportOnly: boolean): boolean {
|
|
56
|
-
if (visibility.kind === 'offscreen' && (visibility.direction === 'left' || visibility.direction === 'right')) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
60
|
if (visibility.kind === 'hidden' && isBeyondWindowEdge(rect, window)) {
|
|
60
61
|
return false;
|
|
61
62
|
}
|
package/src/snapshot/wrappers.ts
CHANGED
|
@@ -7,7 +7,6 @@ export interface MeasuredCandidate {
|
|
|
7
7
|
candidate: Candidate;
|
|
8
8
|
rect: Rect;
|
|
9
9
|
offscreen: Offscreen | null;
|
|
10
|
-
distance: number;
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
const RECT_TOLERANCE = 1;
|
|
@@ -56,15 +55,3 @@ export function dropWrapperDuplicates(measured: MeasuredCandidate[]): MeasuredCa
|
|
|
56
55
|
}
|
|
57
56
|
return measured.filter((entry) => !wrappers.has(entry));
|
|
58
57
|
}
|
|
59
|
-
|
|
60
|
-
const OFFSCREEN_LIMIT = 30;
|
|
61
|
-
|
|
62
|
-
export function limitOffscreen(measured: MeasuredCandidate[]): MeasuredCandidate[] {
|
|
63
|
-
// Every option of a wheel stays listed: one dropped here could never be selected.
|
|
64
|
-
const hidden = measured.filter((entry) => entry.offscreen !== null && entry.candidate.kind !== 'scroll' && entry.candidate.wheelOption !== true);
|
|
65
|
-
if (hidden.length <= OFFSCREEN_LIMIT) {
|
|
66
|
-
return measured;
|
|
67
|
-
}
|
|
68
|
-
const dropped = new Set(hidden.sort((left, right) => left.distance - right.distance).slice(OFFSCREEN_LIMIT));
|
|
69
|
-
return measured.filter((entry) => !dropped.has(entry));
|
|
70
|
-
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '0.1.
|
|
1
|
+
export const SDK_VERSION = '0.1.6';
|