mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-23 04:42:24 +03:00
fix(mobile): incorrect height of keyboard toolbar in ios (#8653)
### What Changes: - Fix keyboard height calculation with the `KeyboardToolBarConfig.useScreenHeight = true`. More detials in: https://github.com/toeverything/blocksuite/pull/8645 - Add safe bottom padding for shrinked keyboard toolbar - Add `VirtualKeyboard` polyfill. Close [AF-1573](https://linear.app/affine-design/issue/AF-1573/virtualkeyboard-polyfill-with-capacitor) - Since the `@capacitor/keyboard` dose not implement the `Keyboard.show()` method, this polyfill is not enabled now.
This commit is contained in:
parent
10b1f233d9
commit
1973cea035
@ -13,6 +13,7 @@ def capacitor_pods
|
||||
pod 'CapacitorCordova', :path => '../../../../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorApp', :path => '../../../../../node_modules/@capacitor/app'
|
||||
pod 'CapacitorBrowser', :path => '../../../../../node_modules/@capacitor/browser'
|
||||
pod 'CapacitorKeyboard', :path => '../../../../../node_modules/@capacitor/keyboard'
|
||||
end
|
||||
|
||||
target 'App' do
|
||||
|
@ -6,6 +6,8 @@ PODS:
|
||||
- CapacitorBrowser (6.0.3):
|
||||
- Capacitor
|
||||
- CapacitorCordova (6.1.2)
|
||||
- CapacitorKeyboard (6.0.2):
|
||||
- Capacitor
|
||||
- CryptoSwift (1.8.3)
|
||||
|
||||
DEPENDENCIES:
|
||||
@ -13,6 +15,7 @@ DEPENDENCIES:
|
||||
- "CapacitorApp (from `../../../../../node_modules/@capacitor/app`)"
|
||||
- "CapacitorBrowser (from `../../../../../node_modules/@capacitor/browser`)"
|
||||
- "CapacitorCordova (from `../../../../../node_modules/@capacitor/ios`)"
|
||||
- "CapacitorKeyboard (from `../../../../../node_modules/@capacitor/keyboard`)"
|
||||
- CryptoSwift (~> 1.8.3)
|
||||
|
||||
SPEC REPOS:
|
||||
@ -28,14 +31,17 @@ EXTERNAL SOURCES:
|
||||
:path: "../../../../../node_modules/@capacitor/browser"
|
||||
CapacitorCordova:
|
||||
:path: "../../../../../node_modules/@capacitor/ios"
|
||||
CapacitorKeyboard:
|
||||
:path: "../../../../../node_modules/@capacitor/keyboard"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2
|
||||
CapacitorApp: 0bc633b4eae40a1f32cd2834788fad3bc42da6a1
|
||||
CapacitorBrowser: aab1ed943b01c0365c4810538a8b3477e2d9f72e
|
||||
CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd
|
||||
CapacitorKeyboard: 2700f9b18687be021e28b5a09b59eb151a46d5e0
|
||||
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483
|
||||
|
||||
PODFILE CHECKSUM: 763e3dac392c17bcf42dab97a9225ea234e8416a
|
||||
PODFILE CHECKSUM: 1b0d3fe81862c0e9ce712ddd0c5a0accd0097698
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
COCOAPODS: 1.16.1
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { CapacitorConfig } from '@capacitor/cli';
|
||||
import { KeyboardResize } from '@capacitor/keyboard';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'app.affine.pro',
|
||||
@ -17,6 +18,9 @@ const config: CapacitorConfig = {
|
||||
CapacitorHttp: {
|
||||
enabled: true,
|
||||
},
|
||||
Keyboard: {
|
||||
resize: KeyboardResize.Native,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
"@capacitor/browser": "^6.0.3",
|
||||
"@capacitor/core": "^6.1.2",
|
||||
"@capacitor/ios": "^6.1.2",
|
||||
"@capacitor/keyboard": "^6.0.2",
|
||||
"@sentry/react": "^8.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -1,3 +1,6 @@
|
||||
import '@affine/core/bootstrap/browser';
|
||||
import '@affine/component/theme';
|
||||
import '@affine/core/mobile/styles/mobile.css';
|
||||
|
||||
// TODO(@L-Sun) Uncomment this when the `show` method implement by `@capacitor/keyboard` in ios
|
||||
// import './virtual-keyboard';
|
||||
|
152
packages/frontend/apps/ios/src/virtual-keyboard.ts
Normal file
152
packages/frontend/apps/ios/src/virtual-keyboard.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import type { PluginListenerHandle } from '@capacitor/core/types/definitions';
|
||||
import { Keyboard } from '@capacitor/keyboard';
|
||||
|
||||
type VirtualKeyboardCallback =
|
||||
| (<K extends keyof VirtualKeyboardEventMap>(
|
||||
this: VirtualKeyboard,
|
||||
ev: VirtualKeyboardEventMap[K]
|
||||
) => any)
|
||||
| EventListenerOrEventListenerObject;
|
||||
|
||||
class NavigatorVirtualKeyboard implements VirtualKeyboard {
|
||||
private readonly _boundingRect = new DOMRect();
|
||||
|
||||
private readonly _overlaysContent = false;
|
||||
|
||||
private _listeners = new Map<
|
||||
string,
|
||||
Set<{
|
||||
cb: VirtualKeyboardCallback;
|
||||
options?: boolean | AddEventListenerOptions;
|
||||
}>
|
||||
>();
|
||||
|
||||
private _capacitorListenerHandles: PluginListenerHandle[] = [];
|
||||
|
||||
private async _bindListener() {
|
||||
const updateBoundingRect = (info?: { keyboardHeight: number }) => {
|
||||
this.boundingRect.x = 0;
|
||||
this.boundingRect.y = info ? window.innerHeight - info.keyboardHeight : 0;
|
||||
this.boundingRect.width = window.innerWidth;
|
||||
this.boundingRect.height = info ? info.keyboardHeight : 0;
|
||||
this.dispatchEvent(new Event('geometrychange'));
|
||||
};
|
||||
|
||||
this._capacitorListenerHandles = [
|
||||
await Keyboard.addListener('keyboardDidShow', updateBoundingRect),
|
||||
await Keyboard.addListener('keyboardDidHide', updateBoundingRect),
|
||||
];
|
||||
}
|
||||
|
||||
dispatchEvent = (event: Event) => {
|
||||
const listeners = this._listeners.get(event.type);
|
||||
if (listeners) {
|
||||
for (const l of listeners) {
|
||||
if (typeof l.cb === 'function') {
|
||||
l.cb.call(this, event);
|
||||
} else {
|
||||
l.cb.handleEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
return !(event.cancelable && event.defaultPrevented);
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this._bindListener();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._capacitorListenerHandles.forEach(handle => handle.remove());
|
||||
}
|
||||
|
||||
get boundingRect(): DOMRect {
|
||||
return this._boundingRect;
|
||||
}
|
||||
|
||||
get overlaysContent(): boolean {
|
||||
return this._overlaysContent;
|
||||
}
|
||||
|
||||
set overlaysContent(_: boolean) {
|
||||
console.warn(
|
||||
'overlaysContent is read-only in polyfill based on @capacitor/keyboard'
|
||||
);
|
||||
}
|
||||
|
||||
hide() {
|
||||
Keyboard.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
Keyboard.show();
|
||||
}
|
||||
|
||||
ongeometrychange: ((this: VirtualKeyboard, ev: Event) => any) | null = null;
|
||||
|
||||
addEventListener<K extends keyof VirtualKeyboardEventMap>(
|
||||
type: K,
|
||||
listener: VirtualKeyboardCallback,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
) {
|
||||
if (!this._listeners.has(type)) {
|
||||
this._listeners.set(type, new Set());
|
||||
}
|
||||
|
||||
const listeners = this._listeners.get(type);
|
||||
if (!listeners) return;
|
||||
|
||||
listeners.add({ cb: listener, options });
|
||||
}
|
||||
|
||||
removeEventListener<K extends keyof VirtualKeyboardEventMap>(
|
||||
type: K,
|
||||
listener: VirtualKeyboardCallback,
|
||||
options?: boolean | EventListenerOptions
|
||||
) {
|
||||
const listeners = this._listeners.get(type);
|
||||
if (!listeners) return;
|
||||
|
||||
const sameCapture = (
|
||||
a?: boolean | AddEventListenerOptions,
|
||||
b?: boolean | EventListenerOptions
|
||||
) => {
|
||||
if (a === undefined && b === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof a === 'boolean' && typeof b === 'boolean') {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
if (typeof a === 'object' && typeof b === 'object') {
|
||||
return a.capture === b.capture;
|
||||
}
|
||||
|
||||
if (typeof a === 'object' && typeof b === 'boolean') {
|
||||
return a.capture === b;
|
||||
}
|
||||
|
||||
if (typeof a === 'boolean' && typeof b === 'object') {
|
||||
return a === b.capture;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
let target = null;
|
||||
for (const l of listeners) {
|
||||
if (l.cb === listener && sameCapture(l.options, options)) {
|
||||
target = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target) {
|
||||
listeners.delete(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error polyfill
|
||||
navigator.virtualKeyboard = new NavigatorVirtualKeyboard();
|
@ -10,6 +10,11 @@ import {
|
||||
LifeCycleWatcher,
|
||||
StdIdentifier,
|
||||
} from '@blocksuite/affine/block-std';
|
||||
import type {
|
||||
RootBlockConfig,
|
||||
TelemetryEventMap,
|
||||
ThemeExtension,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import {
|
||||
ColorScheme,
|
||||
EdgelessBuiltInManager,
|
||||
@ -18,9 +23,7 @@ import {
|
||||
EditorSettingExtension,
|
||||
FontLoaderService,
|
||||
PageRootBlockSpec,
|
||||
type TelemetryEventMap,
|
||||
TelemetryProvider,
|
||||
type ThemeExtension,
|
||||
ThemeExtensionIdentifier,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import {
|
||||
@ -39,6 +42,7 @@ import { combineLatest, map } from 'rxjs';
|
||||
|
||||
import { getFontConfigExtension } from '../font-extension';
|
||||
import { createDatabaseOptionsConfig } from './database-block';
|
||||
import { createKeyboardToolbarConfig } from './widgets/keyboard-toolbar';
|
||||
import { createLinkedWidgetConfig } from './widgets/linked';
|
||||
import { createToolbarMoreMenuConfig } from './widgets/toolbar';
|
||||
|
||||
@ -144,7 +148,8 @@ function getEditorConfigExtension(
|
||||
linkedWidget: createLinkedWidgetConfig(framework),
|
||||
toolbarMoreMenu: createToolbarMoreMenuConfig(framework),
|
||||
databaseOptions: createDatabaseOptionsConfig(framework),
|
||||
}),
|
||||
keyboardToolbar: createKeyboardToolbarConfig(),
|
||||
} satisfies RootBlockConfig),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { globalVars } from '@affine/core/mobile/styles/mobile.css';
|
||||
import { type KeyboardToolbarConfig } from '@blocksuite/affine/blocks';
|
||||
|
||||
export function createKeyboardToolbarConfig(): Partial<KeyboardToolbarConfig> {
|
||||
return {
|
||||
// TODO(@L-Sun): check android following the PR
|
||||
// https://github.com/toeverything/blocksuite/pull/8645
|
||||
useScreenHeight: BUILD_CONFIG.isIOS,
|
||||
safeBottomPadding: BUILD_CONFIG.isIOS ? globalVars.appTabHeight : '0px',
|
||||
};
|
||||
}
|
10
yarn.lock
10
yarn.lock
@ -606,6 +606,7 @@ __metadata:
|
||||
"@capacitor/cli": "npm:^6.1.2"
|
||||
"@capacitor/core": "npm:^6.1.2"
|
||||
"@capacitor/ios": "npm:^6.1.2"
|
||||
"@capacitor/keyboard": "npm:^6.0.2"
|
||||
"@sentry/react": "npm:^8.0.0"
|
||||
"@types/react": "npm:^18.2.75"
|
||||
"@types/react-dom": "npm:^18.2.24"
|
||||
@ -2991,6 +2992,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@capacitor/keyboard@npm:^6.0.2":
|
||||
version: 6.0.2
|
||||
resolution: "@capacitor/keyboard@npm:6.0.2"
|
||||
peerDependencies:
|
||||
"@capacitor/core": ^6.0.0
|
||||
checksum: 10/cef4cce5c703fd67ceed3f04736a6513e05423006a5b4571d88d07a5849b79fc9f1ec98759606b7498ec1b604e5ee7987e5e30e61e9835538a29238ffbe3b036
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@chromatic-com/storybook@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "@chromatic-com/storybook@npm:3.0.0"
|
||||
|
Loading…
Reference in New Issue
Block a user