diff --git a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss index 813d881b5..1df4b7775 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss +++ b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss @@ -1,5 +1,10 @@ :root { --lexical-ordered-list-left-margin: 16px; + + --checkbox-size: 18px; + @media screen and (max-width: 450px) { + --checkbox-size: 26px; + } } .monospace-font { --lexical-ordered-list-left-margin: 42px; @@ -52,11 +57,19 @@ .Lexical__listItemChecked, .Lexical__listItemUnchecked { position: relative; - padding-left: calc(var(--font-size) + 0.5rem); - padding-right: calc(var(--font-size) + 0.5rem); + padding-left: calc(var(--checkbox-size) + 0.5rem); + padding-right: calc(var(--checkbox-size) + 0.5rem); list-style-type: none; outline: none; vertical-align: middle; + --line-height: calc(var(--checkbox-size) + 0.375rem); + line-height: var(--line-height); + + @media screen and (max-width: 450px) { + &:not(:last-child) { + margin-bottom: 0.15rem; + } + } &:focus, &:focus-within { @@ -70,12 +83,12 @@ } .Lexical__listItemUnchecked:before, .Lexical__listItemChecked:before { + /* checkbox */ content: ''; - --size: 16px; - width: var(--size); - height: var(--size); + width: var(--checkbox-size); + height: var(--checkbox-size); left: 0; - top: calc(var(--line-height, 1) * var(--font-size) / 2); + top: calc(var(--line-height) / 2); transform: translateY(-50%); cursor: pointer; background-size: cover; @@ -97,19 +110,19 @@ background-repeat: no-repeat; } .Lexical__listItemChecked:after { + /* checkmark */ content: ''; cursor: pointer; - border-color: var(--sn-stylekit-info-contrast-color); - border-style: solid; + background-image: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22white%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M17.5001%205.83345L7.50008%2015.8334L2.91675%2011.2501L4.09175%2010.0751L7.50008%2013.4751L16.3251%204.65845L17.5001%205.83345Z%22%2F%3E%3C%2Fsvg%3E%0A'); + background-repeat: no-repeat; position: absolute; + left: 0; + --top: calc(var(--line-height) / 2); + top: var(--top); + transform: translateY(-50%); display: block; - width: 5px; - height: 11px; - --top: calc(var(--line-height, 1) * var(--font-size) / 2); - top: calc(var(--top) - 1px); - left: 5px; - transform: translateY(-50%) rotate(45deg); - border-width: 0 2px 2px 0; + width: var(--checkbox-size); + height: var(--checkbox-size); } .Lexical__nestedListItem { list-style-type: none; diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CheckListPlugin.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CheckListPlugin.tsx index 7809d3fef..f40bf1684 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CheckListPlugin.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CheckListPlugin.tsx @@ -7,6 +7,7 @@ import { $isRangeSelection, COMMAND_PRIORITY_LOW, KEY_ENTER_COMMAND, + SKIP_DOM_SELECTION_TAG, } from 'lexical' import { useEffect } from 'react' import { useApplication } from '../../ApplicationProvider' @@ -53,8 +54,6 @@ export function CheckListPlugin(): null { return } - editor.getRootElement()?.focus() - const rect = target.getBoundingClientRect() const listItemElementStyles = getComputedStyle(target) @@ -81,25 +80,40 @@ export function CheckListPlugin(): null { function handleClick(event: Event) { handleCheckItemEvent(event as PointerEvent, () => { + const isTouchEvent = (event as PointerEvent).pointerType === 'touch' if (!editor.isEditable()) { return } - editor.update(() => { - const domNode = event.target as HTMLElement + editor.update( + () => { + const domNode = event.target + if (!(domNode instanceof HTMLElement)) { + return + } - if (!event.target) { - return - } + const node = $getNearestNodeFromDOMNode(domNode) - const node = $getNearestNodeFromDOMNode(domNode) + if (!$isListItemNode(node)) { + return + } - if (!$isListItemNode(node)) { - return - } + const isFocusWithinEditor = editor.getRootElement()?.contains(document.activeElement) + if (!isTouchEvent && !isFocusWithinEditor) { + // on desktop, we want to focus & select the list item so that if you then press the up or down arrow keys, + // the caret moves in the editor instead of triggering the note navigation shortcuts. + // however on mobile, focusing the editor brings up the keyboard even if you just want to quickly toggle + // an item. the keyboard also causes a layout shift which might end up leading to an incorrect toggle. + node.selectStart() + } - node.toggleChecked() - }) + node.toggleChecked() + }, + { + // without this lexical will reconcile the new selection to the dom and focus the editor causing the keyboard to show up + tag: isTouchEvent ? SKIP_DOM_SELECTION_TAG : undefined, + }, + ) }) }