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

[Transition experiment] Follow up the latest spec of API #457

Merged
merged 5 commits into from
Jun 4, 2022
Merged
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
2 changes: 1 addition & 1 deletion .stylelintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ rules:
property-no-unknown:
- true
- ignoreProperties:
- content-visibility
- page-transition-tag
selector-pseudo-element-no-unknown:
- true
- ignorePseudoElements:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- [Experimental transition] A basic support of transition with shared elements (just like PowerPoint Morph and Keynote Magic Move) ([#457](https://github.com/marp-team/marp-cli/pull/457))

## v2.0.1 - 2022-06-01

### Fixed
Expand Down
31 changes: 29 additions & 2 deletions src/templates/bespoke/_transition.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,27 @@

@mixin transition {
@at-root {
::page-transition-container(*) {
animation-duration: var(
--marp-bespoke-transition-animation-duration,
0.5s
);
animation-timing-function: ease;
}

::page-transition-outgoing-image(*),
::page-transition-incoming-image(*) {
animation-name: var(
--marp-bespoke-transition-animation-name,
__bespoke_marp_transition_no_animation__
var(
--marp-bespoke-transition-animation-name-fallback,
__bespoke_marp_transition_no_animation__
)
);
animation-duration: var(
--marp-bespoke-transition-animation-duration,
0.5s
);
animation-timing-function: linear;
animation-delay: 0s;
animation-fill-mode: both;
animation-direction: var(
Expand All @@ -43,6 +53,23 @@
mix-blend-mode: normal;
}

::page-transition-outgoing-image(*) {
--marp-bespoke-transition-animation-name-fallback: __bespoke_marp_transition_reduced_outgoing__;

animation-timing-function: ease;
}

::page-transition-incoming-image(*) {
--marp-bespoke-transition-animation-name-fallback: __bespoke_marp_transition_reduced_incoming__;

animation-timing-function: ease;
}

::page-transition-outgoing-image(root),
::page-transition-incoming-image(root) {
animation-timing-function: linear;
}

::page-transition-outgoing-image(__bespoke_marp_transition_osc__),
::page-transition-incoming-image(__bespoke_marp_transition_osc__) {
animation-name: __bespoke_marp_transition_osc__ !important; /* no animation */
Expand Down
17 changes: 17 additions & 0 deletions src/templates/bespoke/bespoke.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ $progress-height: 5px;
pointer-events: none;
opacity: 0;

&:not(.bespoke-marp-active) {
* {
/* Unset page-transition-tag in inactive pages because it must be unique for a document */
page-transition-tag: none !important;
}
}

&.bespoke-marp-active {
content-visibility: visible;
z-index: 0;
Expand All @@ -58,6 +65,13 @@ $progress-height: 5px;
}
}
}

@media (prefers-reduced-motion: reduce) {
* {
/* Disable shared element transition declared by users */
page-transition-tag: none !important;
}
}
}

[data-bespoke-marp-fragment='inactive'] {
Expand Down Expand Up @@ -98,6 +112,9 @@ $progress-height: 5px;
/* Hack for Chrome to show OSC overlay onto video correctly */
will-change: transform;

/* Page transition API */
page-transition-tag: __bespoke_marp_transition_osc__;

> * {
margin-left: 6px;

Expand Down
24 changes: 9 additions & 15 deletions src/templates/bespoke/transition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { classPrefix } from './utils'
import {
getMarpTransitionKeyframes,
resolveAnimationStyles,
Expand All @@ -22,7 +21,6 @@ export const transitionStyleId = '_tSId' as const

const transitionApply = '_tA' as const
const transitionDuring = '_tD' as const
const transitionKeyOSC = '__bespoke_marp_transition_osc__' as const
const transitionWarmUpClass = 'bespoke-marp-transition-warming-up' as const

const prefersReducedMotion = window.matchMedia(
Expand Down Expand Up @@ -166,29 +164,25 @@ const bespokeTransition = (deck) => {

try {
// Start transition
const setSharedElements = (transition: DocumentTransition) => {
const osc = document.querySelector(`.${classPrefix}osc`)
if (osc) transition.setElement(osc, transitionKeyOSC)
}

const transition: DocumentTransition =
document['createDocumentTransition']()
setSharedElements(transition)

const rootClassList = document.documentElement.classList
rootClassList.add(transitionWarmUpClass)

doTransition(transition, async () => {
await transition
.start(async () => {
try {
await transition.start(() => {
fn(e)
setSharedElements(transition)
rootClassList.remove(transitionWarmUpClass)
})
.finally(() => {
style.remove()
rootClassList.remove(transitionWarmUpClass)
})
} catch (err) {
console.error(err)
fn(e)
} finally {
style.remove()
rootClassList.remove(transitionWarmUpClass)
}
})
} catch (e) {
transitionDuringState(false)
Expand Down
16 changes: 10 additions & 6 deletions src/templates/bespoke/utils/transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,12 @@ const resolveAnimationVariables = (
): Record<ReturnType<typeof animCSSVar>, string> | undefined => {
const target = keyframes[backward ? 'backward' : 'forward']
const resolved = (() => {
const _default = duration
? ({ [animCSSVar('duration')]: duration } as const)
: ({} as Record<string, never>)

const detailedKeyframe = target[type]

if (typeof detailedKeyframe === 'string') {
return { ..._default, [animCSSVar('name')]: detailedKeyframe } as const
return { [animCSSVar('name')]: detailedKeyframe } as const
} else if (target.both) {
const style = { ..._default, [animCSSVar('name')]: target.both } as const
const style = { [animCSSVar('name')]: target.both } as const

return type === 'incoming'
? ({ ...style, [animCSSVar('direction')]: 'reverse' } as const)
Expand Down Expand Up @@ -180,6 +176,14 @@ export const resolveAnimationStyles = (
`:root{${publicCSSVar('direction')}:${opts.backward ? -1 : 1};}`,
]

if (opts.duration !== undefined) {
rules.push(
`::page-transition-container(*){${animCSSVar('duration')}:${
opts.duration
};}`
)
}

const incomingVars = resolveAnimationVariables(keyframes, {
...opts,
type: 'incoming',
Expand Down