Implement reduced motion mode for Collapsible

This commit is contained in:
Matthias Metelka 2022-09-09 17:40:52 +02:00
parent 26a8c72b4c
commit 654b1db54e
5 changed files with 36 additions and 12 deletions

View file

@ -534,6 +534,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
setColorButtons({}); setColorButtons({});
setTags({}); setTags({});
setMathjaxEnabled({}); setMathjaxEnabled({});
setReducedMotion({});
""".format( """.format(
json.dumps(data), json.dumps(data),
json.dumps(collapsed), json.dumps(collapsed),
@ -545,6 +546,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
json.dumps([text_color, highlight_color]), json.dumps([text_color, highlight_color]),
json.dumps(self.note.tags), json.dumps(self.note.tags),
json.dumps(self.mw.col.get_config("renderMathjax", True)), json.dumps(self.mw.col.get_config("renderMathjax", True)),
json.dumps(self.mw.pm.reduced_motion()),
) )
if self.addMode: if self.addMode:

View file

@ -7,6 +7,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { tweened } from "svelte/motion"; import { tweened } from "svelte/motion";
export let duration = 200; export let duration = 200;
export let animated = true;
function dynamicDuration(height: number, factor: number): number { function dynamicDuration(height: number, factor: number): number {
return 100 + Math.pow(height, 1 / 4) * factor; return 100 + Math.pow(height, 1 / 4) * factor;
@ -33,7 +34,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
await new Promise(requestAnimationFrame); await new Promise(requestAnimationFrame);
expandHeight = collapsibleElement.clientHeight; expandHeight = collapsibleElement.clientHeight;
animating = true; transitioning = true;
size.set(1, { size.set(1, {
duration: duration || dynamicDuration(expandHeight, 25), duration: duration || dynamicDuration(expandHeight, 25),
easing: cubicIn, easing: cubicIn,
@ -42,24 +43,29 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
$: if (collapsibleElement) { $: if (collapsibleElement) {
if (animated) {
doCollapse(collapse); doCollapse(collapse);
} else {
collapsed = collapse;
}
} }
let collapsibleElement: HTMLElement; let collapsibleElement: HTMLElement;
$: collapsed = $size === 0; $: collapsed = $size === 0;
$: expanded = $size === 1; $: expanded = $size === 1;
$: animating = $size > 0 && !(collapsed || expanded); $: transitioning = $size > 0 && !(collapsed || expanded);
$: height = $size * expandHeight; $: height = $size * expandHeight;
$: measuring = !(collapsed || animating || expanded); $: measuring = !(collapsed || transitioning || expanded);
</script> </script>
<div <div
bind:this={collapsibleElement} bind:this={collapsibleElement}
class="collapsible" class="collapsible"
class:measuring class:measuring
class:animating class:animated
class:transitioning
class:expanded class:expanded
style:--height="{height}px" style:--height="{height}px"
> >
@ -72,12 +78,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{/if} {/if}
<style lang="scss"> <style lang="scss">
.collapsible { .collapsible.animated {
&.measuring { &.measuring {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
} }
&.animating { &.transitioning {
overflow: hidden; overflow: hidden;
height: var(--height); height: var(--height);
&.expanded { &.expanded {

View file

@ -42,12 +42,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</script> </script>
<script lang="ts"> <script lang="ts">
import { onDestroy, setContext } from "svelte"; import { getContext, onDestroy, setContext } from "svelte";
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import Collapsible from "../components/Collapsible.svelte"; import Collapsible from "../components/Collapsible.svelte";
import { collapsedKey, directionKey } from "../lib/context-keys"; import { collapsedKey, directionKey, reducedMotionKey } from "../lib/context-keys";
import { promiseWithResolver } from "../lib/promise"; import { promiseWithResolver } from "../lib/promise";
import type { Destroyable } from "./destroyable"; import type { Destroyable } from "./destroyable";
import EditingArea from "./EditingArea.svelte"; import EditingArea from "./EditingArea.svelte";
@ -67,6 +67,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
$: $collapsedStore = collapsed; $: $collapsedStore = collapsed;
const reducedMotion = getContext<Readable<boolean>>(reducedMotionKey);
const editingArea: Partial<EditingAreaAPI> = {}; const editingArea: Partial<EditingAreaAPI> = {};
const [element, elementResolve] = promiseWithResolver<HTMLElement>(); const [element, elementResolve] = promiseWithResolver<HTMLElement>();
@ -88,7 +90,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<div class="field-container"> <div class="field-container">
<slot name="field-label" /> <slot name="field-label" />
<Collapsible collapse={collapsed} let:collapsed={hidden}> <Collapsible collapse={collapsed} animated={!$reducedMotion} let:collapsed={hidden}>
<div <div
use:elementResolve use:elementResolve
class="editor-field" class="editor-field"

View file

@ -39,13 +39,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</script> </script>
<script lang="ts"> <script lang="ts">
import { onMount, tick } from "svelte"; import { onMount, setContext, tick } from "svelte";
import { get, writable } from "svelte/store"; import { get, writable } from "svelte/store";
import Absolute from "../components/Absolute.svelte"; import Absolute from "../components/Absolute.svelte";
import Badge from "../components/Badge.svelte"; import Badge from "../components/Badge.svelte";
import StickyContainer from "../components/StickyContainer.svelte"; import StickyContainer from "../components/StickyContainer.svelte";
import { bridgeCommand } from "../lib/bridgecommand"; import { bridgeCommand } from "../lib/bridgecommand";
import { reducedMotionKey } from "../lib/context-keys";
import { TagEditor } from "../tag-editor"; import { TagEditor } from "../tag-editor";
import { ChangeTimer } from "./change-timer"; import { ChangeTimer } from "./change-timer";
import DecoratedElements from "./DecoratedElements.svelte"; import DecoratedElements from "./DecoratedElements.svelte";
@ -129,6 +130,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
plainTextDefaults = [...richTextsHidden]; plainTextDefaults = [...richTextsHidden];
} }
let reducedMotion = false;
function setReducedMotion(enabled: boolean): void {
reducedMotion = enabled;
}
const reducedMotionStore = writable<boolean>();
setContext(reducedMotionKey, reducedMotionStore);
$: $reducedMotionStore = reducedMotion;
function setMathjaxEnabled(enabled: boolean): void { function setMathjaxEnabled(enabled: boolean): void {
mathjaxConfig.enabled = enabled; mathjaxConfig.enabled = enabled;
} }
@ -277,6 +287,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
setNoteId, setNoteId,
wrap, wrap,
setMathjaxEnabled, setMathjaxEnabled,
setReducedMotion,
...oldEditorAdapter, ...oldEditorAdapter,
}); });
@ -436,6 +447,7 @@ the AddCards dialog) should be implemented in the user of this component.
<svelte:fragment slot="rich-text-input"> <svelte:fragment slot="rich-text-input">
<Collapsible <Collapsible
collapse={richTextsHidden[index]} collapse={richTextsHidden[index]}
animated={!reducedMotion}
let:collapsed={hidden} let:collapsed={hidden}
> >
<RichTextInput <RichTextInput
@ -457,6 +469,7 @@ the AddCards dialog) should be implemented in the user of this component.
<svelte:fragment slot="plain-text-input"> <svelte:fragment slot="plain-text-input">
<Collapsible <Collapsible
collapse={plainTextsHidden[index]} collapse={plainTextsHidden[index]}
animated={!reducedMotion}
let:collapsed={hidden} let:collapsed={hidden}
> >
<PlainTextInput <PlainTextInput

View file

@ -6,3 +6,4 @@ export const fontSizeKey = Symbol("fontSize");
export const directionKey = Symbol("direction"); export const directionKey = Symbol("direction");
export const descriptionKey = Symbol("description"); export const descriptionKey = Symbol("description");
export const collapsedKey = Symbol("collapsed"); export const collapsedKey = Symbol("collapsed");
export const reducedMotionKey = Symbol("reducedMotion");