Add option to wrap text (#20)
This commit is contained in:
@@ -40,6 +40,12 @@ export default function Editor({
|
|||||||
pref => pref >= 10 && pref <= 22
|
pref => pref >= 10 && pref <= 22
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [wordWrap, setWordWrap] = usePreference<boolean>(
|
||||||
|
'wordwrap',
|
||||||
|
true,
|
||||||
|
() => true
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (contentType) {
|
if (contentType) {
|
||||||
setLanguage(contentType);
|
setLanguage(contentType);
|
||||||
@@ -66,6 +72,8 @@ export default function Editor({
|
|||||||
setReadOnly={setReadOnly}
|
setReadOnly={setReadOnly}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
setTheme={setTheme}
|
setTheme={setTheme}
|
||||||
|
wordWrap={wordWrap}
|
||||||
|
setWordWrap={setWordWrap}
|
||||||
zoom={zoom}
|
zoom={zoom}
|
||||||
/>
|
/>
|
||||||
<EditorTextArea
|
<EditorTextArea
|
||||||
@@ -76,6 +84,7 @@ export default function Editor({
|
|||||||
language={language}
|
language={language}
|
||||||
fontSize={fontSize}
|
fontSize={fontSize}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
|
wordWrap={wordWrap}
|
||||||
resetFunction={resetFunction}
|
resetFunction={resetFunction}
|
||||||
/>
|
/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export interface EditorControlsProps {
|
|||||||
setReadOnly: (value: boolean) => void;
|
setReadOnly: (value: boolean) => void;
|
||||||
theme: keyof Themes;
|
theme: keyof Themes;
|
||||||
setTheme: (value: keyof Themes) => void;
|
setTheme: (value: keyof Themes) => void;
|
||||||
|
wordWrap: boolean;
|
||||||
|
setWordWrap: (value: boolean) => void;
|
||||||
zoom: (delta: number) => void;
|
zoom: (delta: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ export default function EditorControls({
|
|||||||
setReadOnly,
|
setReadOnly,
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
|
wordWrap,
|
||||||
|
setWordWrap,
|
||||||
zoom,
|
zoom,
|
||||||
}: EditorControlsProps) {
|
}: EditorControlsProps) {
|
||||||
const [saving, setSaving] = useState<boolean>(false);
|
const [saving, setSaving] = useState<boolean>(false);
|
||||||
@@ -113,6 +117,9 @@ export default function EditorControls({
|
|||||||
<Section>
|
<Section>
|
||||||
<Button onClick={() => zoom(1)}>[+ </Button>
|
<Button onClick={() => zoom(1)}>[+ </Button>
|
||||||
<Button onClick={() => zoom(-1)}> -]</Button>
|
<Button onClick={() => zoom(-1)}> -]</Button>
|
||||||
|
<Button onClick={() => setWordWrap(!wordWrap)}>
|
||||||
|
[wrap:{wordWrap ? 'on' : 'off'}]
|
||||||
|
</Button>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
label="theme"
|
label="theme"
|
||||||
value={theme}
|
value={theme}
|
||||||
@@ -144,13 +151,15 @@ const Header = styled.header`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Section = styled.div`
|
const Section = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
@media (max-width: 470px) {
|
@media (max-width: 850px) {
|
||||||
.optional {
|
.optional {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export interface EditorTextAreaProps {
|
|||||||
language: string;
|
language: string;
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
|
wordWrap: boolean;
|
||||||
resetFunction: MutableRefObject<ResetFunction | null>;
|
resetFunction: MutableRefObject<ResetFunction | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ export default function EditorTextArea({
|
|||||||
language,
|
language,
|
||||||
fontSize,
|
fontSize,
|
||||||
readOnly,
|
readOnly,
|
||||||
|
wordWrap,
|
||||||
resetFunction,
|
resetFunction,
|
||||||
}: EditorTextAreaProps) {
|
}: EditorTextAreaProps) {
|
||||||
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>();
|
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>();
|
||||||
@@ -166,7 +168,7 @@ export default function EditorTextArea({
|
|||||||
fontFamily: 'JetBrains Mono',
|
fontFamily: 'JetBrains Mono',
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
fontLigatures: true,
|
fontLigatures: true,
|
||||||
wordWrap: 'on',
|
wordWrap: wordWrap ? 'on' : 'off',
|
||||||
renderLineHighlight: 'none',
|
renderLineHighlight: 'none',
|
||||||
renderValidationDecorations: 'off',
|
renderValidationDecorations: 'off',
|
||||||
readOnly,
|
readOnly,
|
||||||
|
|||||||
@@ -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 styled from 'styled-components';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
|
|
||||||
@@ -16,6 +17,11 @@ export default function MenuButton<T extends string>({
|
|||||||
setValue,
|
setValue,
|
||||||
}: MenuButtonProps<T>) {
|
}: MenuButtonProps<T>) {
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
const [menuPosition, setMenuPosition] = useState<{
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
}>({ top: 0, left: 0 });
|
||||||
|
const buttonRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
// close the menu when a click is made elsewhere
|
// close the menu when a click is made elsewhere
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -26,6 +32,16 @@ export default function MenuButton<T extends string>({
|
|||||||
|
|
||||||
function toggleOpen(e: React.MouseEvent) {
|
function toggleOpen(e: React.MouseEvent) {
|
||||||
e.stopPropagation();
|
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);
|
setOpen(!open);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,22 +79,35 @@ export default function MenuButton<T extends string>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button onClick={toggleOpen}>
|
<>
|
||||||
[<span>{label}: </span>
|
<Button onClick={toggleOpen} ref={buttonRef}>
|
||||||
{value}]{open && <Menu>{items}</Menu>}
|
[<span>{label}: </span>
|
||||||
</Button>
|
{value}]
|
||||||
|
</Button>
|
||||||
|
{open &&
|
||||||
|
createPortal(
|
||||||
|
<Menu style={{ top: menuPosition.top, left: menuPosition.left }}>
|
||||||
|
{items}
|
||||||
|
</Menu>,
|
||||||
|
document.body
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Menu = styled.ul`
|
const Menu = styled.ul`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2em;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background-color: ${props => props.theme.highlight};
|
background-color: ${props => props.theme.highlight};
|
||||||
max-height: calc(100vh - 2em);
|
max-height: calc(100vh - 2em);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
z-index: 20;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
> li.title {
|
> li.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default function usePreference<T>(
|
|||||||
const [value, setValue] = useState<T>(() => {
|
const [value, setValue] = useState<T>(() => {
|
||||||
const prefRaw = localStorage.getItem(id);
|
const prefRaw = localStorage.getItem(id);
|
||||||
const pref = prefRaw !== null ? (JSON.parse(prefRaw) as T) : undefined;
|
const pref = prefRaw !== null ? (JSON.parse(prefRaw) as T) : undefined;
|
||||||
if (pref && valid(pref)) {
|
if (pref !== null && pref !== undefined && valid(pref)) {
|
||||||
return pref;
|
return pref;
|
||||||
} else {
|
} else {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|||||||
Reference in New Issue
Block a user