From a8564232f7189a01b92e1a37d2b74b9849c8eed6 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 14 Mar 2025 01:36:14 +0300 Subject: [PATCH] fix: make chat arrows work on ios fix: disable annoying in many cases auto correct on ios (more annoying than useful especially in commands) fix: make stats dont overlap with chat fix: fix edgecases when focusing on chat was not possible on mobile --- renderer/viewer/lib/ui/newStats.ts | 2 +- src/index.ts | 1 + src/optionsStorage.ts | 2 +- src/react/Chat.css | 23 +++++++++---- src/react/Chat.tsx | 54 ++++++++++++++++++++---------- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/renderer/viewer/lib/ui/newStats.ts b/renderer/viewer/lib/ui/newStats.ts index fff4d28c..d18ad16c 100644 --- a/renderer/viewer/lib/ui/newStats.ts +++ b/renderer/viewer/lib/ui/newStats.ts @@ -3,7 +3,7 @@ const rightOffset = 0 const stats = {} -let lastY = 20 +let lastY = 40 export const addNewStat = (id: string, width = 80, x = rightOffset, y = lastY) => { const pane = document.createElement('div') pane.style.position = 'fixed' diff --git a/src/index.ts b/src/index.ts index ab055ce6..67187c1c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -829,6 +829,7 @@ export async function connect (connectOptions: ConnectOptions) { if (appStatusState.isError) return const waitForChunks = async () => { + if (appQueryParams.sp === '1') return //todo const waitForChunks = options.waitForChunksRender === 'sp-only' ? !!singleplayer : options.waitForChunksRender if (viewer.world.allChunksFinished || !waitForChunks) { return diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index ef397238..d8d72809 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -165,7 +165,7 @@ const migrateOptions = (options: Partial>) => { export type AppOptions = typeof defaultOptions // when opening html file locally in browser, localStorage is shared between all ever opened html files, so we try to avoid conflicts -const localStorageKey = process.env.SINGLE_FILE_BUILD ? 'minecraftWebClientOptions' : 'options' +const localStorageKey = process.env?.SINGLE_FILE_BUILD ? 'minecraftWebClientOptions' : 'options' export const options: AppOptions = proxy({ ...defaultOptions, ...initialAppConfig.defaultSettings, diff --git a/src/react/Chat.css b/src/react/Chat.css index 141524af..601e4ce3 100644 --- a/src/react/Chat.css +++ b/src/react/Chat.css @@ -29,6 +29,12 @@ div.chat-wrapper { gap: 1px; } +.chat-submit-button { + visibility: hidden; + position: absolute; + pointer-events: none !important; +} + .chat-input-wrapper form { display: flex; } @@ -157,17 +163,22 @@ input[type=text], height: 15px; } -.chat-mobile-hidden { - width: 8px; - height: 0; +.chat-mobile-input-hidden { position: absolute; + width: 8px; + height: 1px !important; display: block !important; opacity: 0; - pointer-events: none; + height: 1px !important; + /* ios: using z-index, pointer-events: none or top below -10px breaks arrows */ } -.chat-mobile-hidden:nth-last-child(1) { - height: 8px; +.chat-mobile-input-hidden-up { + top: -10px; +} + +.chat-mobile-input-hidden-down { + top: -5px; } #chatinput:focus { diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index 129bfee1..78c69bec 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -71,6 +71,8 @@ export default ({ }: Props) => { const sendHistoryRef = useRef(JSON.parse(window.sessionStorage.chatHistory || '[]')) const [isInputFocused, setIsInputFocused] = useState(false) + // const [spellCheckEnabled, setSpellCheckEnabled] = useState(false) + const spellCheckEnabled = false const [completePadText, setCompletePadText] = useState('') const completeRequestValue = useRef('') @@ -107,9 +109,28 @@ export default ({ }, 0) } - const auxInputFocus = (fireKey: string) => { + const handleArrowUp = () => { + if (chatHistoryPos.current === 0) return + if (chatHistoryPos.current === sendHistoryRef.current.length) { // started navigating history + inputCurrentlyEnteredValue.current = chatInput.current.value + } + chatHistoryPos.current-- + updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || '') + } + + const handleArrowDown = () => { + if (chatHistoryPos.current === sendHistoryRef.current.length) return + chatHistoryPos.current++ + updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '') + } + + const auxInputFocus = (direction: 'up' | 'down') => { chatInput.current.focus() - chatInput.current.dispatchEvent(new KeyboardEvent('keydown', { code: fireKey, bubbles: true })) + if (direction === 'up') { + handleArrowUp() + } else { + handleArrowDown() + } } useEffect(() => { @@ -125,6 +146,7 @@ export default ({ if (opened) { updateInputValue(chatInputValueGlobal.value) chatInputValueGlobal.value = '' + chatHistoryPos.current = sendHistoryRef.current.length if (!usingTouch) { chatInput.current.focus() } @@ -167,6 +189,8 @@ export default ({ const onMainInputChange = () => { const completeValue = getCompleteValue() setCompletePadText(completeValue === '/' ? '' : completeValue) + // not sure if enabling would be useful at all (maybe make as a setting in the future?) + // setSpellCheckEnabled(!chatInput.current.value.startsWith('/')) if (completeRequestValue.current === completeValue) { updateFilteredCompleteItems(completionItemsSource) return @@ -271,20 +295,23 @@ export default ({ {isIos && auxInputFocus('ArrowUp')} + onFocus={() => auxInputFocus('up')} onChange={() => { }} />} setIsInputFocused(false)} onKeyDown={(e) => { if (e.code === 'ArrowUp') { - if (chatHistoryPos.current === 0) return - if (chatHistoryPos.current === sendHistoryRef.current.length) { // started navigating history - inputCurrentlyEnteredValue.current = e.currentTarget.value - } - chatHistoryPos.current-- - updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || '') + handleArrowUp() } else if (e.code === 'ArrowDown') { - if (chatHistoryPos.current === sendHistoryRef.current.length) return - chatHistoryPos.current++ - updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '') + handleArrowDown() } if (e.code === 'Tab') { if (completionItemsSource.length) { @@ -327,15 +347,15 @@ export default ({ {isIos && auxInputFocus('ArrowDown')} + onFocus={() => auxInputFocus('down')} onChange={() => { }} />} {/* for some reason this is needed to make Enter work on android chrome */} -