From 2ca28166f9db44bb5a95d73b214b7aca74c91d68 Mon Sep 17 00:00:00 2001 From: Isaac - The456 Date: Sun, 24 Mar 2024 22:14:27 +0000 Subject: [PATCH] Add option to wrap text --- src/components/Editor.tsx | 9 +++++++ src/components/EditorControls.tsx | 11 ++++++++- src/components/EditorTextArea.tsx | 4 ++- src/components/MenuButton.tsx | 41 ++++++++++++++++++++++++++----- src/hooks/usePreference.ts | 2 +- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 0cb0b7c..5684aca 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -40,6 +40,12 @@ export default function Editor({ pref => pref >= 10 && pref <= 22 ); + const [wordWrap, setWordWrap] = usePreference( + 'wordwrap', + true, + () => true + ); + useEffect(() => { if (contentType) { setLanguage(contentType); @@ -66,6 +72,8 @@ export default function Editor({ setReadOnly={setReadOnly} theme={theme} setTheme={setTheme} + wordWrap={wordWrap} + setWordWrap={setWordWrap} zoom={zoom} /> diff --git a/src/components/EditorControls.tsx b/src/components/EditorControls.tsx index 0d3db40..eb68c3e 100644 --- a/src/components/EditorControls.tsx +++ b/src/components/EditorControls.tsx @@ -19,6 +19,8 @@ export interface EditorControlsProps { setReadOnly: (value: boolean) => void; theme: keyof Themes; setTheme: (value: keyof Themes) => void; + wordWrap: boolean; + setWordWrap: (value: boolean) => void; zoom: (delta: number) => void; } @@ -31,6 +33,8 @@ export default function EditorControls({ setReadOnly, theme, setTheme, + wordWrap, + setWordWrap, zoom, }: EditorControlsProps) { const [saving, setSaving] = useState(false); @@ -113,6 +117,9 @@ export default function EditorControls({
+ ; } @@ -73,6 +74,7 @@ export default function EditorTextArea({ language, fontSize, readOnly, + wordWrap, resetFunction, }: EditorTextAreaProps) { const [editor, setEditor] = useState(); @@ -166,7 +168,7 @@ export default function EditorTextArea({ fontFamily: 'JetBrains Mono', fontSize: fontSize, fontLigatures: true, - wordWrap: 'on', + wordWrap: wordWrap ? 'on' : 'off', renderLineHighlight: 'none', renderValidationDecorations: 'off', readOnly, diff --git a/src/components/MenuButton.tsx b/src/components/MenuButton.tsx index 977325b..bb87c10 100644 --- a/src/components/MenuButton.tsx +++ b/src/components/MenuButton.tsx @@ -1,4 +1,5 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; import styled from 'styled-components'; import Button from './Button'; @@ -16,6 +17,11 @@ export default function MenuButton({ setValue, }: MenuButtonProps) { const [open, setOpen] = useState(false); + const [menuPosition, setMenuPosition] = useState<{ + top: number; + left: number; + }>({ top: 0, left: 0 }); + const buttonRef = useRef(null); // close the menu when a click is made elsewhere useEffect(() => { @@ -26,6 +32,16 @@ export default function MenuButton({ function toggleOpen(e: React.MouseEvent) { e.stopPropagation(); + if (!buttonRef.current) { + return; + } + if (!open) { + const rect = buttonRef.current.getBoundingClientRect(); + setMenuPosition({ + top: rect.bottom + window.scrollY, + left: rect.left + window.scrollX, + }); + } setOpen(!open); } @@ -63,22 +79,35 @@ export default function MenuButton({ } return ( - + <> + + {open && + createPortal( + + {items} + , + document.body + )} + ); } const Menu = styled.ul` position: absolute; - top: 2em; margin: 0; padding: 0; list-style: none; background-color: ${props => props.theme.highlight}; max-height: calc(100vh - 2em); overflow: auto; + z-index: 20; + + > li { + cursor: pointer; + } > li.title { text-align: center; diff --git a/src/hooks/usePreference.ts b/src/hooks/usePreference.ts index 737c0df..7d93905 100644 --- a/src/hooks/usePreference.ts +++ b/src/hooks/usePreference.ts @@ -9,7 +9,7 @@ export default function usePreference( const [value, setValue] = useState(() => { const prefRaw = localStorage.getItem(id); const pref = prefRaw !== null ? (JSON.parse(prefRaw) as T) : undefined; - if (pref && valid(pref)) { + if (pref !== null && pref !== undefined && valid(pref)) { return pref; } else { return defaultValue;