diff --git a/packages/icons/src/Icons/ic-backspace.svg b/packages/icons/src/Icons/ic-backspace.svg
new file mode 100644
index 000000000..7b1116608
--- /dev/null
+++ b/packages/icons/src/Icons/ic-backspace.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/packages/icons/src/Icons/index.ts b/packages/icons/src/Icons/index.ts
index 63a0a3678..5a32917e5 100644
--- a/packages/icons/src/Icons/index.ts
+++ b/packages/icons/src/Icons/index.ts
@@ -6,6 +6,7 @@ import AccountVariantIcon from './ic-account-variant.svg'
import AddBoldIcon from './ic-add-bold.svg'
import AddIcon from './ic-add.svg'
import AddTextIcon from './ic-add-text.svg'
+import AegisIcon from './ic-aegis.svg'
import ArchiveIcon from './ic-archive.svg'
import ArrowDownCheckmarkIcon from './arrow-down-checkmark.svg'
import ArrowDownIcon from './ic-arrow-down.svg'
@@ -21,6 +22,7 @@ import AttachmentFileIcon from './ic-attachment-file.svg'
import AuthenticatorIcon from './ic-authenticator.svg'
import AuthenticatorVariantIcon from './ic-authenticator-variant.svg'
import BackIosIcon from './ic-back-ios.svg'
+import BackspaceIcon from './ic-backspace.svg'
import BlockIcon from './ic-block.svg'
import BlueDotIcon from './blue-dot.svg'
import BoldIcon from './ic-bold.svg'
@@ -57,6 +59,7 @@ import EditorIcon from './ic-editor.svg'
import EmailFilledIcon from './ic-email-filled.svg'
import EmailIcon from './ic-email.svg'
import EnterIcon from './ic-enter.svg'
+import EvernoteIcon from './ic-evernote.svg'
import EyeFilledIcon from './ic-eye-filled.svg'
import EyeIcon from './ic-eye.svg'
import EyeOffFilledIcon from './ic-eye-off-filled.svg'
@@ -87,6 +90,7 @@ import ForwardIosIcon from './ic-forward-ios.svg'
import FullscreenExitIcon from './ic-fullscreen-exit.svg'
import FullscreenIcon from './ic-fullscreen.svg'
import GiftOutlineIcon from './ic-gift-outline.svg'
+import GoogleKeepIcon from './ic-gkeep.svg'
import HashtagFilledIcon from './ic-hashtag-filled.svg'
import HashtagIcon from './ic-hashtag.svg'
import HashtagOffIcon from './ic-hashtag-off.svg'
@@ -112,9 +116,9 @@ import LineWidthIcon from './ic-line-width.svg'
import LinkIcon from './ic-link.svg'
import LinkOffIcon from './ic-link-off.svg'
import ListBulleted from './ic-list-bulleted.svg'
-import ListNumbered from './ic-list-numbered.svg'
import ListedFilledIcon from './ic-listed-filled.svg'
import ListedIcon from './ic-listed.svg'
+import ListNumbered from './ic-list-numbered.svg'
import LockFilledIcon from './ic-lock-filled.svg'
import LockIcon from './ic-lock.svg'
import MarkdownIcon from './ic-markdown.svg'
@@ -146,6 +150,8 @@ import PrintIcon from './ic-print.svg'
import ProtectedIllustration from './il-protected.svg'
import RedoIcon from './ic-redo.svg'
import ReorderIcon from './ic-reorder.svg'
+import ReplaceAllIcon from './ic-replace-all.svg'
+import ReplaceIcon from './ic-replace.svg'
import RestoreIcon from './ic-restore.svg'
import RichTextIcon from './ic-text-rich.svg'
import SafeIcon from './ic-safe.svg'
@@ -164,6 +170,7 @@ import ShareIcon from './ic-share.svg'
import ShortcutButtonIcon from './ic-shortcut-button.svg'
import SignInIcon from './ic-signin.svg'
import SignOutIcon from './ic-signout.svg'
+import SimplenoteIcon from './ic-simplenote.svg'
import SNLogoAltIcon from './ic-standard-notes-2.svg'
import SNLogoFull from './ic-sn-logo-full.svg'
import SNLogoIcon from './ic-standard-notes.svg'
@@ -201,12 +208,6 @@ import UserSwitch from './ic-user-switch.svg'
import ViewIcon from './ic-view.svg'
import WarningIcon from './ic-warning.svg'
import WindowIcon from './ic-window.svg'
-import EvernoteIcon from './ic-evernote.svg'
-import GoogleKeepIcon from './ic-gkeep.svg'
-import SimplenoteIcon from './ic-simplenote.svg'
-import AegisIcon from './ic-aegis.svg'
-import ReplaceIcon from './ic-replace.svg'
-import ReplaceAllIcon from './ic-replace-all.svg'
export {
AccessibilityIcon,
@@ -232,6 +233,7 @@ export {
AuthenticatorIcon,
AuthenticatorVariantIcon,
BackIosIcon,
+ BackspaceIcon,
BlockIcon,
BlueDotIcon,
BoldIcon,
diff --git a/packages/styles/src/Alert/Alert.ts b/packages/styles/src/Alert/Alert.ts
index e9de199a5..8d796f117 100644
--- a/packages/styles/src/Alert/Alert.ts
+++ b/packages/styles/src/Alert/Alert.ts
@@ -41,7 +41,7 @@ const getColorsForPrimaryVariant = (style: AlertButtonStyle) => {
type AlertButton = {
text: string
style: AlertButtonStyle
- action: () => void
+ action?: () => void
primary?: boolean
}
@@ -168,7 +168,9 @@ export class SKAlert {
this.buttons.forEach((buttonDesc, index) => {
const buttonElem = this.element.querySelector(`#button-${index}`) as HTMLButtonElement
buttonElem.onclick = () => {
- buttonDesc.action && buttonDesc.action()
+ if (buttonDesc.action) {
+ buttonDesc.action()
+ }
this.dismiss()
}
if (index === 0) {
diff --git a/packages/web/src/javascripts/Components/Icon/IconNameToSvgMapping.tsx b/packages/web/src/javascripts/Components/Icon/IconNameToSvgMapping.tsx
index c8d382ade..7312642ba 100644
--- a/packages/web/src/javascripts/Components/Icon/IconNameToSvgMapping.tsx
+++ b/packages/web/src/javascripts/Components/Icon/IconNameToSvgMapping.tsx
@@ -73,6 +73,7 @@ export const IconNameToSvgMapping = {
archive: icons.ArchiveIcon,
asterisk: icons.AsteriskIcon,
authenticator: icons.AuthenticatorIcon,
+ backspace: icons.BackspaceIcon,
bold: icons.BoldIcon,
camera: icons.CameraIcon,
check: icons.CheckIcon,
diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/MobileToolbarPlugin/MobileToolbarPlugin.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/MobileToolbarPlugin/MobileToolbarPlugin.tsx
index daddda25d..050ee6149 100644
--- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/MobileToolbarPlugin/MobileToolbarPlugin.tsx
+++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/MobileToolbarPlugin/MobileToolbarPlugin.tsx
@@ -4,7 +4,7 @@ import useModal from '../../Lexical/Hooks/useModal'
import { InsertTableDialog } from '../../Plugins/TablePlugin'
import { getSelectedNode } from '../../Lexical/Utils/getSelectedNode'
import { sanitizeUrl } from '../../Lexical/Utils/sanitizeUrl'
-import { $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical'
+import { $getSelection, $isRangeSelection, DELETE_CHARACTER_COMMAND, FORMAT_TEXT_COMMAND } from 'lexical'
import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { GetAlignmentBlocks } from '../Blocks/Alignment'
@@ -23,11 +23,14 @@ import { GetPasswordBlock } from '../Blocks/Password'
import { GetQuoteBlock } from '../Blocks/Quote'
import { GetTableBlock } from '../Blocks/Table'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
-import { classNames } from '@standardnotes/snjs'
+import { classNames, Platform } from '@standardnotes/snjs'
import { SUPER_TOGGLE_SEARCH } from '@standardnotes/ui-services'
import { useApplication } from '@/Components/ApplicationProvider'
import { GetRemoteImageBlock } from '../Blocks/RemoteImage'
import { InsertRemoteImageDialog } from '../RemoteImagePlugin/RemoteImagePlugin'
+import { SKAlert } from '@standardnotes/styles'
+
+const DontShowSuperAndroidBackspaceAlertKey = 'dontShowSuperAndroidBackspaceAlert'
const MobileToolbarPlugin = () => {
const application = useApplication()
@@ -37,8 +40,10 @@ const MobileToolbarPlugin = () => {
const [isInEditor, setIsInEditor] = useState(false)
const [isInToolbar, setIsInToolbar] = useState(false)
const isMobile = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
+ const isAndroid = application.platform === Platform.Android
const toolbarRef = useRef(null)
+ const backspaceButtonRef = useRef(null)
const insertLink = useCallback(() => {
const selection = $getSelection()
@@ -156,7 +161,8 @@ const MobileToolbarPlugin = () => {
const handleFocus = () => setIsInEditor(true)
const handleBlur = (event: FocusEvent) => {
- if (toolbarRef.current?.contains(event.relatedTarget as Node)) {
+ const elementToBeFocused = event.relatedTarget as Node
+ if (toolbarRef.current?.contains(elementToBeFocused) || elementToBeFocused === backspaceButtonRef.current) {
return
}
setIsInEditor(false)
@@ -179,7 +185,13 @@ const MobileToolbarPlugin = () => {
const toolbar = toolbarRef.current
const handleFocus = () => setIsInToolbar(true)
- const handleBlur = () => setIsInToolbar(false)
+ const handleBlur = (event: FocusEvent) => {
+ const elementToBeFocused = event.relatedTarget as Node
+ if (elementToBeFocused === backspaceButtonRef.current) {
+ return
+ }
+ setIsInToolbar(false)
+ }
toolbar.addEventListener('focus', handleFocus)
toolbar.addEventListener('blur', handleBlur)
@@ -190,6 +202,38 @@ const MobileToolbarPlugin = () => {
}
}, [])
+ useEffect(() => {
+ if (!isAndroid) {
+ return
+ }
+
+ const dontShowAgain = application.getValue(DontShowSuperAndroidBackspaceAlertKey)
+
+ if (dontShowAgain) {
+ return
+ }
+
+ const alert = new SKAlert({
+ title: 'Android backspace issue',
+ text: 'There is a known issue with Super on Android where pressing the backspace will also delete the character after the cursor. We are working on a fix for this. Please use the backspace button in the toolbar as a workaround.',
+ buttons: [
+ {
+ text: 'OK',
+ style: 'default',
+ },
+ {
+ text: "Don't show again",
+ style: 'default',
+ action: () => {
+ application.setValue(DontShowSuperAndroidBackspaceAlertKey, true)
+ },
+ },
+ ],
+ })
+
+ alert.present()
+ }, [application, isAndroid])
+
const isFocusInEditorOrToolbar = isInEditor || isInToolbar
if (!isMobile || !isFocusInEditorOrToolbar) {
return null
@@ -223,6 +267,20 @@ const MobileToolbarPlugin = () => {
>
+ {isAndroid && (
+
+ )}
>
)