Files
orca/mobile/app/h/[hostId]/session/mobile-session-command-input-styles.ts
60037d60ab feat(mobile): add explicit keyboard dismiss control to terminal command dock (#5917)
* feat(mobile): add explicit keyboard dismiss control to terminal command dock

Add a fixed Hide control at the left of the terminal command dock accessory
bar whenever the software keyboard is open (keyboardHeight > 0). Tapping it
clears any pending live-input focus timer, blurs the live and buffered command
inputs, and dismisses the keyboard without sending bytes, switching input mode,
or clearing typed text.

The dismiss behavior lives in a dedicated, unit-tested terminal-keyboard-dismiss
module rather than the customizable accessory-key path, so the escape hatch
cannot be hidden by user shortcut customization. Available on every platform
where the IME covers the app (iOS and Android).

* review: harden keyboard dismiss control per adversarial review

- document the load-bearing clear-before-blur order in dismissTerminalKeyboard
- cover the both-handles-missing case in unit tests (5/5)
- move the #5106 first-tap comment onto the accessory ScrollView and add a
  why-comment for the fixed Hide control
- add accessibilityRole=button and hitSlop to the Hide control for a larger,
  semantically-correct touch target

* fix(mobile): harden hide button visibility and scroll layout

* refactor(mobile): use stacked keyboard+chevron glyph for dismiss control

Replace the icon+'Hide' text with the iOS-native dismiss glyph (keyboard
with a chevron-down beneath it). Narrower in the accessory row, removes the
icon/word redundancy, and reads as distinct from the >> input-mode toggle.
Accessibility label/hint/role unchanged.

* fix(mobile): align keyboard dismiss accessory height

* test(mobile): align vitest transform with Vite 8

---------

Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-07-08 17:18:16 -07:00

223 lines
4.9 KiB
TypeScript

import { StyleSheet } from 'react-native'
import { colors, spacing, radii, typography } from '../../../../src/theme/mobile-theme'
export const mobileSessionCommandInputStyles = StyleSheet.create({
createWarningBanner: {
flexDirection: 'row',
alignItems: 'flex-start',
gap: spacing.sm,
backgroundColor: colors.bgPanel,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: colors.borderSubtle,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm
},
createWarningText: {
flex: 1,
color: colors.textPrimary,
fontSize: 12,
lineHeight: 16
},
createWarningDismiss: {
width: 24,
height: 24,
alignItems: 'center',
justifyContent: 'center',
marginTop: -4
},
emptyState: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: spacing.xl
},
emptyText: {
color: colors.textSecondary,
fontSize: typography.bodySize,
marginBottom: spacing.lg
},
createError: {
color: colors.statusRed,
fontSize: 13,
marginBottom: spacing.sm
},
emptyActions: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
gap: spacing.sm
},
createButton: {
backgroundColor: colors.bgRaised,
borderWidth: 1,
borderColor: colors.borderSubtle,
paddingHorizontal: spacing.xl,
paddingVertical: spacing.sm + 2,
borderRadius: radii.button
},
createButtonDisabled: {
opacity: 0.5
},
createButtonText: {
color: colors.textPrimary,
fontSize: typography.bodySize,
fontWeight: '600'
},
commandDock: {
zIndex: 20
},
accessoryBar: {
flexDirection: 'row',
alignItems: 'center',
borderTopWidth: 1,
borderTopColor: colors.borderSubtle,
backgroundColor: colors.bgPanel
},
accessoryScroll: {
flex: 1,
minWidth: 0
},
accessoryContent: {
paddingHorizontal: spacing.sm,
paddingVertical: spacing.xs,
gap: spacing.xs
},
accessoryKey: {
backgroundColor: colors.bgRaised,
paddingHorizontal: spacing.sm + 2,
paddingVertical: spacing.xs,
borderRadius: radii.button,
minWidth: 36,
alignItems: 'center'
},
accessoryKeyPressed: {
backgroundColor: colors.borderSubtle
},
accessoryKeyActive: {
backgroundColor: colors.textPrimary
},
customAccessoryKey: {
borderWidth: 1,
borderColor: colors.borderSubtle
},
accessoryKeyDisabled: {
opacity: 0.35
},
accessoryKeyText: {
color: colors.textSecondary,
fontSize: 12,
fontFamily: typography.monoFamily
},
accessoryKeyTextActive: {
color: colors.bgBase,
fontWeight: '700'
},
accessoryKeyTextDisabled: {
color: colors.textMuted
},
keyboardDismissKey: {
alignItems: 'center',
justifyContent: 'center',
marginLeft: spacing.sm,
marginVertical: spacing.xs,
backgroundColor: colors.bgRaised,
paddingHorizontal: spacing.sm + 2,
paddingVertical: 0,
borderRadius: radii.button,
minWidth: 36,
height: 28
},
keyboardDismissGlyph: {
alignItems: 'center',
height: 18,
justifyContent: 'flex-start',
position: 'relative',
width: 18
},
keyboardDismissChevron: {
bottom: -2,
position: 'absolute'
},
inputBar: {
flexDirection: 'row',
alignItems: 'center',
minHeight: 46,
paddingVertical: spacing.xs + 2,
paddingHorizontal: spacing.md,
borderTopWidth: 1,
borderTopColor: colors.borderSubtle,
backgroundColor: colors.bgPanel
},
textInput: {
flex: 1,
height: 34,
backgroundColor: colors.bgRaised,
color: colors.textPrimary,
borderRadius: radii.input,
paddingHorizontal: spacing.md,
paddingVertical: 0,
fontSize: 14,
fontFamily: typography.monoFamily,
marginRight: spacing.sm
},
liveInputBar: {
gap: spacing.sm
},
liveInputFocusTarget: {
flex: 1,
minHeight: 34,
flexDirection: 'row',
alignItems: 'center',
gap: spacing.sm,
backgroundColor: colors.bgRaised,
borderWidth: 1,
borderColor: colors.borderSubtle,
borderRadius: radii.input,
paddingHorizontal: spacing.sm + 2
},
liveInputFocusTargetPressed: {
backgroundColor: colors.borderSubtle
},
liveInputFocusTargetDisabled: {
opacity: 0.45
},
liveInputCapture: {
position: 'absolute',
opacity: 0,
width: 1,
height: 1,
color: colors.textPrimary
},
sendButton: {
backgroundColor: colors.bgRaised,
width: 34,
height: 34,
borderRadius: 17,
alignItems: 'center',
justifyContent: 'center'
},
dictationButton: {
backgroundColor: colors.bgRaised,
width: 34,
height: 34,
borderRadius: 17,
borderWidth: 1,
borderColor: 'transparent',
alignItems: 'center',
justifyContent: 'center',
marginRight: spacing.sm
},
dictationButtonActive: {
backgroundColor: colors.bgPanel,
borderColor: colors.textSecondary
},
sendButtonDisabled: {
opacity: 0.35
}
})