@electerm/electerm-react 5.1.23 → 5.1.25

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.
@@ -43,9 +43,10 @@ export default auto(function Layout (props) {
43
43
  rightPanelWidth,
44
44
  resizeTrigger,
45
45
  inActiveTerminal,
46
- shortcutBarVisible
46
+ shortcutBarVisible,
47
+ shortcutBarKbOffset
47
48
  } = props.store
48
- const h = height - footerHeight - (inActiveTerminal && pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight : 0) + resizeTrigger
49
+ const h = height - footerHeight - (inActiveTerminal && pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight + shortcutBarKbOffset : 0) + resizeTrigger
49
50
  const l = pinned ? leftSideBarWidth + leftSidePanelWidth : leftSideBarWidth
50
51
  const r = rightPanelVisible && rightPanelPinned ? rightPanelWidth : 0
51
52
  return {
@@ -68,14 +69,15 @@ export default auto(function Layout (props) {
68
69
  rightPanelPinned,
69
70
  rightPanelWidth,
70
71
  pinned,
71
- shortcutBarVisible
72
+ shortcutBarVisible,
73
+ shortcutBarKbOffset
72
74
  } = props.store
73
75
  const l = pinned ? leftSidePanelWidth : 0
74
76
  const r = rightPanelPinned && rightPanelVisible ? rightPanelWidth : 0
75
77
  // account for the far-left icon bar (sidebarWidth - 1px border on desktop;
76
78
  // 0 when the bar is hidden on mobile)
77
79
  const w = width - l - r - (leftSideBarWidth > 0 ? leftSideBarWidth - 1 : 0)
78
- const h = height - footerHeight - (pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight : 0)
80
+ const h = height - footerHeight - (pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight + shortcutBarKbOffset : 0)
79
81
  return layoutAlg(layout, w, h)
80
82
  }
81
83
  const layoutSize = calcLayoutStyle()
@@ -31,7 +31,9 @@ const ShortcutBar = lazy(() => import('./shortcut-bar'))
31
31
  // minimum height (px) the visual viewport must lose for us to treat it as
32
32
  // "the soft keyboard is now covering part of the screen". A soft keyboard is
33
33
  // typically ≥150px; a browser address-bar show/hide is well under this.
34
- const KEYBOARD_HEIGHT = 120
34
+ // Shared with shortcut-bar.jsx, which uses it to decide how far to lift the
35
+ // bar above a keyboard that overlays the page (iOS / HarmonyOS).
36
+ export const KEYBOARD_MIN = 120
35
37
 
36
38
  // kept as a coarse capability fallback for engines without visualViewport.
37
39
  // Modern Chromium (Electron) always exposes window.visualViewport, so this is
@@ -87,7 +89,7 @@ export default function ShortcutBarEntry (props) {
87
89
  // ignore viewport changes that also changed width (rotation / split) —
88
90
  // a keyboard changes height only.
89
91
  const sameWidth = Math.abs(vv.width - baseline.width) < 20
90
- if (sameWidth && baseline.height - vv.height > KEYBOARD_HEIGHT) {
92
+ if (sameWidth && baseline.height - vv.height > KEYBOARD_MIN) {
91
93
  setKeyboardSeen(true)
92
94
  // The user is focused in a terminal with the keyboard up — they need
93
95
  // the bar right now. Set visibility here rather than waiting for the
@@ -10,18 +10,22 @@
10
10
  * - first (fixed) button collapses the bar
11
11
  * - second (fixed) button opens the edit modal (shortcut-bar-edit.jsx)
12
12
  * - tapping a shortcut sends it to the active terminal via runQuickCommand
13
+ * - while the system input panel overlays the page without resizing the
14
+ * layout viewport (iOS / HarmonyOS do this, Android resizes instead), the
15
+ * bar lifts itself above the panel — see the visualViewport effect below
13
16
  *
14
17
  * Only loaded on touch devices — see shortcut-bar-entry.jsx.
15
18
  * Data + persistence live in shortcut-bar-defs.js.
16
19
  */
17
20
 
18
21
  import { auto } from 'manate/react'
19
- import { useEffect, useState } from 'react'
22
+ import { useEffect, useRef, useState } from 'react'
20
23
  import { createPortal } from 'react-dom'
21
24
  import { DownOutlined, EditOutlined } from '@ant-design/icons'
22
25
  import { refs } from '../common/ref'
23
26
  import { shortcutBarHeight } from '../../common/constants'
24
27
  import ShortcutBarEdit from './shortcut-bar-edit'
28
+ import { KEYBOARD_MIN } from './shortcut-bar-entry'
25
29
  import { candidates, loadActive, saveActive, ESC } from './shortcut-bar-defs'
26
30
  import './shortcut-bar.styl'
27
31
 
@@ -89,6 +93,55 @@ function ShortcutBar (props) {
89
93
  }
90
94
  }, [])
91
95
 
96
+ // On Android the soft keyboard resizes the layout viewport, so a
97
+ // `position: fixed; bottom: 0` bar is pushed up automatically. iOS and
98
+ // HarmonyOS instead keep the layout viewport full-size and let the keyboard
99
+ // overlay it — there the bar sits underneath the keyboard. visualViewport
100
+ // always tracks the *visible* area on every platform, so the gap between it
101
+ // and the layout viewport is exactly the covered height: lift the bar by
102
+ // that much so it rides just above the keyboard.
103
+ const [kbOffset, setKbOffset] = useState(0)
104
+ const kbBaselineRef = useRef({ height: 0, width: 0 })
105
+
106
+ useEffect(() => {
107
+ const vv = window.visualViewport
108
+ if (!vv) {
109
+ return
110
+ }
111
+ // while no keyboard is up, layout viewport == visual viewport (offsetTop
112
+ // 0); keep refreshing the baseline so a later comparison is accurate.
113
+ function sync () {
114
+ if (vv.offsetTop <= 1) {
115
+ kbBaselineRef.current = { height: window.innerHeight, width: vv.width }
116
+ }
117
+ const { height, width } = kbBaselineRef.current
118
+ // a keyboard changes height only — ignore rotation / pinch-zoom, which
119
+ // change width too.
120
+ const sameWidth = Math.abs(vv.width - width) < 20
121
+ const covered = sameWidth ? height - vv.height - vv.offsetTop : 0
122
+ setKbOffset(covered > KEYBOARD_MIN ? Math.ceil(covered) : 0)
123
+ }
124
+ sync()
125
+ vv.addEventListener('resize', sync)
126
+ vv.addEventListener('scroll', sync)
127
+ window.addEventListener('resize', sync)
128
+ return () => {
129
+ vv.removeEventListener('resize', sync)
130
+ vv.removeEventListener('scroll', sync)
131
+ window.removeEventListener('resize', sync)
132
+ }
133
+ }, [])
134
+
135
+ // keep the offset in a CSS var consumed by shortcut-bar.styl, and expose the
136
+ // lifted height so layout.jsx can shrink the terminal accordingly.
137
+ useEffect(() => {
138
+ document.documentElement.style.setProperty(
139
+ '--shortcut-bar-kb-offset',
140
+ kbOffset ? kbOffset + 'px' : '0px'
141
+ )
142
+ store.shortcutBarKbOffset = kbOffset
143
+ }, [kbOffset])
144
+
92
145
  // reserve layout space + lift the footer while the bar is shown.
93
146
  // expose the bar height as a CSS var so the .styl + footer-lift rule stay
94
147
  // in sync with the shortcutBarHeight constant consumed by layout.jsx.
@@ -135,7 +188,11 @@ function ShortcutBar (props) {
135
188
  }
136
189
 
137
190
  return createPortal(
138
- <div className='shortcut-bar' role='toolbar'>
191
+ <div
192
+ className='shortcut-bar'
193
+ role='toolbar'
194
+ style={kbOffset ? { bottom: kbOffset + 'px' } : undefined}
195
+ >
139
196
  <div className='shortcut-bar-fixed'>
140
197
  <button
141
198
  type='button'
@@ -73,10 +73,12 @@
73
73
  color var(--text-light)
74
74
 
75
75
  // while the bar is visible, lift the footer + reserve space so nothing is
76
- // covered (terminal area is shrunk by layout.jsx via store.shortcutBarVisible)
76
+ // covered (terminal area is shrunk by layout.jsx via store.shortcutBarVisible;
77
+ // --shortcut-bar-kb-offset raises both bar + footer above a page-overlaying
78
+ // system input panel on iOS / HarmonyOS)
77
79
  .shortcut-bar-on
78
80
  .main-footer
79
- bottom var(--shortcut-bar-h, 44px)
81
+ bottom calc(var(--shortcut-bar-h, 44px) + var(--shortcut-bar-kb-offset, 0px))
80
82
 
81
83
  // --- edit modal -----------------------------------------------------------
82
84
 
@@ -169,6 +169,9 @@ export default () => {
169
169
 
170
170
  // touch-only shortcut bar (see components/terminal/shortcut-bar-entry.jsx)
171
171
  shortcutBarVisible: false,
172
+ // px the bar is lifted above a page-overlaying system input panel
173
+ // (iOS / HarmonyOS) — see shortcut-bar.jsx
174
+ shortcutBarKbOffset: 0,
172
175
 
173
176
  // sidebar
174
177
  openedSideBar: ls.getItem(openedSidebarKey) || '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "5.1.23",
3
+ "version": "5.1.25",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",