mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-01 09:30:01 +08:00
fix(ios): stabilize keyboard toolbar, image picker, and scrolling (#15182)
## Summary - keep the editor active when iOS keyboard toolbar interactions move focus into range-sync excluded widgets - use the native iOS image picker/source sheet and sync native presentation with the app theme - pin `ListViewKit` to `1.1.6` so the iOS workspace resolves with Xcode 16.3 - restore vertical scrolling in the iOS `WKWebView` by removing the global `contentOffset` reset while preserving zoom prevention ## Test plan - [x] `yarn vitest --run --config \"vitest.config.ts\" --browser.enabled=false \"src/__tests__/inline/active.unit.spec.ts\"` - [x] `LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 xcodebuild -resolvePackageDependencies -workspace \"packages/frontend/apps/ios/App/App.xcworkspace\" -scheme \"App\"` - [x] `xcodebuild -workspace \"App.xcworkspace\" -scheme \"App\" -destination \"generic/platform=iOS Simulator\" build CODE_SIGNING_ALLOWED=NO ONLY_ACTIVE_ARCH=YES ARCHS=arm64` - [x] Xcode build validation for the updated PR branch
This commit is contained in:
@@ -1,4 +1,46 @@
|
||||
import { RANGE_SYNC_EXCLUDE_ATTR } from './consts';
|
||||
import { RANGE_SYNC_EXCLUDE_ATTR } from './consts.js';
|
||||
|
||||
function getClosestElement(target: EventTarget | null) {
|
||||
if (target instanceof Element) {
|
||||
return target;
|
||||
}
|
||||
|
||||
if (target instanceof Node) {
|
||||
return target.parentElement;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isRangeSyncExcludedTarget(target: EventTarget | null) {
|
||||
return !!getClosestElement(target)?.closest(
|
||||
`[${RANGE_SYNC_EXCLUDE_ATTR}="true"]`
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldDeactivateEditorOnFocusOut(
|
||||
editorHost: HTMLElement,
|
||||
relatedTarget: EventTarget | null
|
||||
) {
|
||||
// A missing or non-DOM `relatedTarget` means focus is not moving to a
|
||||
// trackable element (e.g. block-level selection or a keyboard action). The
|
||||
// document `focusout` handler must keep the editor active in this case so the
|
||||
// current block selection is preserved; leaving-to-nowhere is handled
|
||||
// explicitly by the host `blur` handler instead.
|
||||
if (!relatedTarget || !(relatedTarget instanceof Node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (editorHost.contains(relatedTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isRangeSyncExcludedTarget(relatedTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the active element is in the editor host.
|
||||
@@ -11,8 +53,7 @@ export function isActiveInEditor(editorHost: HTMLElement) {
|
||||
const currentActiveElement = document.activeElement;
|
||||
if (!currentActiveElement) return false;
|
||||
// The input or textarea in the widget should be ignored.
|
||||
if (currentActiveElement.closest(`[${RANGE_SYNC_EXCLUDE_ATTR}="true"]`))
|
||||
return false;
|
||||
if (isRangeSyncExcludedTarget(currentActiveElement)) return false;
|
||||
const currentEditorHost = currentActiveElement?.closest('editor-host');
|
||||
if (!currentEditorHost) return false;
|
||||
return currentEditorHost === editorHost;
|
||||
|
||||
Reference in New Issue
Block a user