a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more shenanigans to make ios focusing play nice

Basically we use a custom input element everywhere we need inputs and on
ios it intercepts clicks and focuses it manually. It also selects all
the text, if the user wants to select a specific text they just click
again but as inputs are used for things like urls and color values this
behavior fits everywhere we use them currently.

+63 -11
+3 -5
components/BlockOptions.tsx
··· 15 15 import { addLinkBlock } from "src/utils/addLinkBlock"; 16 16 import { useEntitySetContext } from "./EntitySetProvider"; 17 17 import { v7 } from "uuid"; 18 + import { Input } from "./Input"; 18 19 19 20 type Props = { 20 21 parent: string; ··· 160 161 onMouseDown={(e) => e.preventDefault()} 161 162 onClick={() => { 162 163 setLinkOpen(!linkOpen); 163 - setTimeout(() => { 164 - document.getElementById("block-link-input")?.focus(); 165 - }, 100); 166 164 }} 167 165 > 168 166 <BlockLinkSmall /> ··· 170 168 {linkOpen && ( 171 169 <> 172 170 <Separator /> 173 - <input 174 - id="block-link-input" 171 + <Input 172 + autoFocus 175 173 type="url" 176 174 className="w-full grow border-none outline-none bg-transparent " 177 175 placeholder="add a link..."
+34
components/Input.tsx
··· 1 + import { isIOS } from "@react-aria/utils"; 2 + import { useCallback, useEffect, useRef } from "react"; 3 + import { onMouseDown } from "src/utils/iosInputMouseDown"; 4 + 5 + export function Input( 6 + props: React.DetailedHTMLProps< 7 + React.InputHTMLAttributes<HTMLInputElement>, 8 + HTMLInputElement 9 + >, 10 + ) { 11 + let ref = useRef<HTMLInputElement>(null); 12 + useEffect(() => { 13 + if (!isIOS()) return; 14 + if (props.autoFocus) { 15 + setTimeout(() => { 16 + if (!ref.current) return; 17 + ref.current.style.transform = "translateY(-2000px)"; 18 + ref.current?.focus(); 19 + requestAnimationFrame(() => { 20 + if (ref.current) ref.current.style.transform = ""; 21 + }); 22 + }, 20); 23 + } 24 + }, [props.autoFocus]); 25 + 26 + return ( 27 + <input 28 + {...props} 29 + autoFocus={isIOS() ? false : props.autoFocus} 30 + ref={ref} 31 + onMouseDown={onMouseDown} 32 + /> 33 + ); 34 + }
-1
components/TextBlock/useHandlePaste.ts
··· 215 215 function flattenHTMLToTextBlocks(element: HTMLElement): HTMLElement[] { 216 216 // Function to recursively collect HTML from nodes 217 217 function collectHTML(node: Node, htmlBlocks: HTMLElement[]): void { 218 - console.log(node); 219 218 if (node.nodeType === Node.ELEMENT_NODE) { 220 219 const elementNode = node as HTMLElement; 221 220 // Collect outer HTML for paragraph-like elements
+8 -1
components/ThemeManager/ThemeSetter.tsx
··· 28 28 import { addImage } from "src/utils/addImage"; 29 29 import { Separator } from "components/Layout"; 30 30 import { useEntitySetContext } from "components/EntitySetProvider"; 31 + import { isIOS, useViewportSize } from "@react-aria/utils"; 32 + import { onMouseDown } from "src/utils/iosInputMouseDown"; 31 33 32 34 export type pickers = 33 35 | "null" ··· 90 92 `radial-gradient(at ${randomPositions[1]}, ${cardValue.toString("hex")}66 2px, transparent 60%)`, 91 93 `radial-gradient(at ${randomPositions[2]}, ${primaryValue.toString("hex")}B3 2px, transparent 100%)`, 92 94 ].join(", "); 95 + let viewheight = useViewportSize().height; 93 96 if (!permission) return null; 94 97 95 98 return ( ··· 108 111 </Popover.Trigger> 109 112 <Popover.Portal> 110 113 <Popover.Content 111 - className="themeSetterWrapper w-80 h-fit max-h-[80vh] bg-white rounded-md border border-border flex" 114 + style={{ maxHeight: viewheight ? viewheight * 0.8 : "80vh" }} 115 + className="themeSetterWrapper w-80 h-fit bg-white rounded-md border border-border flex" 112 116 align="center" 113 117 sideOffset={4} 114 118 collisionPadding={16} ··· 274 278 ) : ( 275 279 <ColorField className="w-fit gap-1"> 276 280 <Input 281 + onMouseDown={onMouseDown} 277 282 onFocus={(e) => { 278 283 e.currentTarget.setSelectionRange( 279 284 1, ··· 297 302 <Separator classname="my-1" /> 298 303 <ColorField className="w-fit pl-[6px]" channel="alpha"> 299 304 <Input 305 + onMouseDown={onMouseDown} 300 306 onFocus={(e) => { 301 307 e.currentTarget.setSelectionRange( 302 308 0, ··· 402 408 ) : ( 403 409 <ColorField className="w-fit gap-1" value={bgColor}> 404 410 <Input 411 + onMouseDown={onMouseDown} 405 412 onFocus={(e) => { 406 413 e.currentTarget.setSelectionRange( 407 414 1,
+2 -1
components/Toolbar/LinkButton.tsx
··· 8 8 import { MarkType } from "prosemirror-model"; 9 9 import { setEditorState, useEditorStates } from "src/state/useEditorState"; 10 10 import { rangeHasMark } from "src/utils/prosemirror/rangeHasMark"; 11 + import { Input } from "components/Input"; 11 12 12 13 export function LinkButton(props: { setToolBarState: (s: "link") => void }) { 13 14 let focusedBlock = useUIState((s) => s.focusedBlock); ··· 72 73 <div className="w-full flex items-center gap-[6px]"> 73 74 <LinkTextToolbarSmall /> 74 75 <Separator classname="h-6" /> 75 - <input 76 + <Input 76 77 autoFocus 77 78 className="w-full grow bg-transparent border-none outline-none " 78 79 placeholder="add a link..."
+3 -3
components/Toolbar/index.tsx
··· 45 45 import { addLinkBlock } from "src/utils/addLinkBlock"; 46 46 import * as Tooltip from "@radix-ui/react-tooltip"; 47 47 import { Separator, ShortcutKey } from "components/Layout"; 48 + import { Input } from "components/Input"; 48 49 49 50 export const TextToolbar = (props: { cardID: string; blockID: string }) => { 50 51 let { rep } = useReplicache(); ··· 203 204 className="hover:text-accent" 204 205 onClick={() => { 205 206 if (toolbarState === "linkBlock") { 206 - setToolbarState("link"); 207 + setToolbarState("block"); 207 208 } else if (toolbarState === "default") { 208 209 useUIState.setState(() => ({ 209 210 focusedBlock: { ··· 262 263 return ( 263 264 <div className={`max-w-sm flex gap-2 rounded-md "text-secondary`}> 264 265 <> 265 - <input 266 + <Input 266 267 autoFocus 267 - id="block-link-input" 268 268 type="url" 269 269 className="w-full grow border-none outline-none bg-transparent " 270 270 placeholder="add a link..."
+13
src/utils/iosInputMouseDown.ts
··· 1 + import { isIOS } from "@react-aria/utils"; 2 + 3 + export function onMouseDown(e: React.MouseEvent<HTMLInputElement>) { 4 + if (!isIOS()) return; 5 + e.preventDefault(); 6 + let target = e.currentTarget; 7 + target.style.transform = "translateY(-2000px)"; 8 + target.setSelectionRange(0, target.value.length); 9 + target.focus(); 10 + requestAnimationFrame(() => { 11 + target.style.transform = ""; 12 + }); 13 + }