From aee1fbfb6d1bf929ada0df0614267fd1b2347bc7 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Mon, 20 Mar 2023 23:24:44 +0800 Subject: [PATCH] feat(console): add line number and disable line wrapper (#3546) --------- Co-authored-by: Charles Zhao --- .../components/CodeEditor/index.module.scss | 14 +++-- .../src/components/CodeEditor/index.tsx | 58 ++++++++++++++----- .../src/components/CodeEditor/utils.ts | 44 ++++++++++++++ .../src/components/FormCard/index.module.scss | 1 + .../tabs/Branding/CustomCssForm.module.scss | 1 - 5 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 packages/console/src/components/CodeEditor/utils.ts diff --git a/packages/console/src/components/CodeEditor/index.module.scss b/packages/console/src/components/CodeEditor/index.module.scss index 22aa851fd..d752e4842 100644 --- a/packages/console/src/components/CodeEditor/index.module.scss +++ b/packages/console/src/components/CodeEditor/index.module.scss @@ -1,11 +1,12 @@ @use '@/scss/underscore' as _; .container { - padding: _.unit(6); + padding: _.unit(6) _.unit(6) _.unit(6) _.unit(4); border-radius: 16px; // Force dark theme on the code editor background: #34353f; position: relative; + overflow-y: auto; .placeholder { position: absolute; @@ -36,6 +37,7 @@ .editor { position: relative; + overflow-x: auto; textarea { width: 100%; @@ -46,15 +48,15 @@ font-size: 14px; line-height: 1.5; font-family: 'Roboto Mono', monospace; - white-space: pre-wrap; - word-break: break-all; + white-space: nowrap; + word-break: normal; position: absolute; inset: 0; resize: none; color: #fefefe; - overflow: hidden; -webkit-text-fill-color: transparent; outline: none; + overflow: hidden; } textarea, @@ -63,6 +65,10 @@ min-height: 80px; } } + + .editor::-webkit-scrollbar { + display: none; + } } .errorMessage { diff --git a/packages/console/src/components/CodeEditor/index.tsx b/packages/console/src/components/CodeEditor/index.tsx index 8218d011e..2e2b53f74 100644 --- a/packages/console/src/components/CodeEditor/index.tsx +++ b/packages/console/src/components/CodeEditor/index.tsx @@ -1,12 +1,13 @@ import classNames from 'classnames'; import type { ChangeEvent, KeyboardEvent } from 'react'; -import { useMemo, useRef } from 'react'; +import { useLayoutEffect, useMemo, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { a11yDark as theme } from 'react-syntax-highlighter/dist/esm/styles/prism'; +import { a11yDark as a11yDarkTheme } from 'react-syntax-highlighter/dist/esm/styles/prism'; import CopyToClipboard from '../CopyToClipboard'; import * as styles from './index.module.scss'; +import { lineNumberContainerStyle, lineNumberStyle, customStyle } from './utils'; type Props = { className?: string; @@ -32,8 +33,19 @@ const CodeEditor = ({ placeholder, }: Props) => { const textareaRef = useRef(null); + const editorRef = useRef(null); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + useLayoutEffect(() => { + // Update textarea width according to its scroll width + const { current } = textareaRef; + + if (current && current.style.width !== `${current.scrollWidth}px`) { + // eslint-disable-next-line @silverhand/fp/no-mutation + current.style.width = `${current.scrollWidth}px`; + } + }, [value]); + const handleChange = (event: ChangeEvent) => { const { value } = event.currentTarget; onChange?.(value); @@ -54,6 +66,15 @@ const CodeEditor = ({ onChange?.(newText); } + + /** + * Since lineNumber container could cover leftmost part of the editor, + * when user is clicking on "Enter", should manually scroll to the leftmost. + */ + if (event.key === 'Enter' && editorRef.current && editorRef.current.scrollLeft !== 0) { + // eslint-disable-next-line @silverhand/fp/no-mutation + editorRef.current.scrollLeft = 0; + } }; // TODO @sijie temp solution for required error (the errorMessage is an empty string) @@ -65,12 +86,15 @@ const CodeEditor = ({ return t('general.required'); }, [errorMessage, t]); + const maxLineNumberDigits = ((value ?? '').split('\n').length + 1).toString().length; + const isShowingPlaceholder = !value; + return ( <>
- {!value &&
{placeholder}
} + {isShowingPlaceholder &&
{placeholder}
} -
+
{/* SyntaxHighlighter is a readonly component, so a transparent