Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve EditorToolBar UX for iOS #9

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,9 @@ li.ProseMirror-selectednode:after {
border: 2px solid #8cf;
pointer-events: none;
}

#toolbar {
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 100ms;
}
62 changes: 57 additions & 5 deletions src/lib/components/EditorControls.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>
import { activeEditorView } from '$lib/stores';
import { onDestroy } from 'svelte';
import { onDestroy, onMount } from 'svelte';
import ToggleMark from './tools/ToggleMark.svelte';
import ToggleBulletList from './tools/ToggleBulletList.svelte';
import ToggleBlockquote from './tools/ToggleBlockquote.svelte';
Expand All @@ -11,6 +11,7 @@
import ToggleHeading from './tools/ToggleHeading.svelte';
import InsertImage from './tools/InsertImage.svelte';
import CreateLink from './tools/CreateLink.svelte';
import { debounce } from '$lib/helpers.js';

export let currentUser = undefined;

Expand Down Expand Up @@ -42,13 +43,64 @@
e.stopPropagation();
}
}

// Solution: https://www.codemzy.com/blog/sticky-fixed-header-ios-keyboard-fix
let fixPosition = 0; // the fix
let scrollY; // the last scroll position
let toolbarWrap; // the toolbar wrap
let toolbar; // the toolbar

// function to set the margin to show the toolbar if hidden
const setMargin = function () {
if (!toolbarWrap) return;
const newPosition = toolbarWrap.getBoundingClientRect().top;

// if toolbar wrap is hidden
if (newPosition < -1) {
// add a margin to show the toolbar
toolbar.classList.add('down'); // add class so toolbar can be animated
fixPosition = Math.abs(newPosition); // this is new position we need to fix the toolbar in the display
// if at the bottom of the page take a couple of pixels off due to gap
if (window.innerHeight + scrollY >= document.body.offsetHeight) {
fixPosition -= 2;
}
// set the margin to the new fixed position
toolbar.style['margin-top'] = fixPosition + 'px';
}
};

const debounceMargin = debounce(setMargin, 300);

const handleScroll = function () {
// remove animation and put toolbar back in default position
if (fixPosition > 0) {
toolbar.classList.remove('down');
fixPosition = 0;
toolbar.style['margin-top'] = 0 + 'px';
}
debounceMargin();
};

onMount(() => {
// add event listeners for when focusing from editor
window.addEventListener('focusout', handleScroll);
window.addEventListener('focusin', handleScroll);
return () => {
window.removeEventListener('focusout', handleScroll);
window.removeEventListener('focusin', handleScroll);
};
});
</script>

<div class="sticky top-0 z-10 sm:py-4 sm:px-4">
<div class="sticky top-0 z-10 w-full" bind:this={toolbarWrap}>
<div
class="max-w-screen-lg mx-auto px-2 backdrop-blur-sm bg-white bg-opacity-95 border-b border-t sm:border sm:rounded-full border-gray-100 shadow"
class="absolute left-1/2 transform -translate-x-1/2 top-0 sm:py-4 sm:px-4"
bind:this={toolbar}
id="toolbar"
>
<div>
<div
class="max-w-screen-lg mx-auto px-2 backdrop-blur-sm bg-white bg-opacity-95 border-b border-t sm:border sm:rounded-full border-gray-100 shadow"
>
<div class="flex items-center overflow-x-auto py-3 px-1">
{#if editorState}
<div class="flex">
Expand Down Expand Up @@ -163,4 +215,4 @@
</div>
</div>

<svelte:window on:keydown={onKeyDown} />
<svelte:window on:keydown={onKeyDown} bind:scrollY on:wheel={handleScroll} />
32 changes: 32 additions & 0 deletions src/lib/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export function debounce(fn, delay, atStart, guarantee) {
let timeout;
let args;
let self;

return function debounced() {
self = this;
args = Array.prototype.slice.call(arguments);

if (timeout && (atStart || guarantee)) {
return;
} else if (!atStart) {
clear();

timeout = setTimeout(run, delay);
return timeout;
}

timeout = setTimeout(clear, delay);
fn.apply(self, args);

function run() {
clear();
fn.apply(self, args);
}

function clear() {
clearTimeout(timeout);
timeout = null;
}
};
}