Closed sneakers-the-rat closed 3 years ago
Or, i guess more generally, what i'm trying to do is step through an animation of an SVG, and i want to hook into the keypress event so that the slide doesn't change but the animation proceeds.
I see: https://github.com/FormidableLabs/spectacle/blob/main/src/hooks/use-steps.js and https://github.com/FormidableLabs/spectacle/blob/main/src/hooks/use-keyboard-controls.js as being potentially relevant, but not sure how to use them? I see notes to expand documentation there, if you point me in a general direction with a basic example I can give it a shot and try and write some docs?
from what i can tell from the PR that removed it, the functionality seems to have moved to hooks/use-steps.js
and a lot of the Stepper
docs were removed: https://github.com/FormidableLabs/spectacle/pull/980/
Taking a look at components/code-pane.js
is useful for understanding how to implement 'sub-steps' within a slide https://github.com/FormidableLabs/spectacle/blob/main/src/components/code-pane.js and so I think I could figure it out from there. I know docs are a continual challenge so not faulting y'all there, but it seems like once you get the hooks documented the package will become a whole hell of a lot more powerful! happy to submit what i come up with as an example if it's useful -- i'll be making a component to step through svg animations by exposing the anime.js API as a list of substeps, if something like that sounds like something that could be an extension.
Ok figured out how to step through an .svg (using anime.js), and generally how to add custom step logic to slides, definitely worth documenting bc you can do stuff like this which is good:
Here's what i've been making, for reference (no roastin' allowed): https://github.com/sneakers-the-rat/infrastructure-presentation/blob/2e23e79d9b65ed583a4bd13f501d226ed3e27673/src/components/svg_animator.js
After exporting the hooks and contexts (see https://github.com/FormidableLabs/spectacle/pull/1019 and https://github.com/sneakers-the-rat/spectacle/commits/export_context ) the way it seems to work is like this --- probably messing something up b/c still not sure intended use, but hey if it works...
useSteps
useSteps
seems to add steps to a slide, it takes a stepIndex
param but not quite sure what it does, and returns a few props, most important of which is the placeholder
. So to add steps to a slide, in some component do something like this:
import { useSteps } from "spectacle";
export default function SvgAnimator({
steps = [],
nSteps,
stepIndex
}){
const { stepId, isActive, stepNum, placeholder } = useSteps(numberOfSteps, {
stepIndex,
});
and then make sure the placeholder is included in your render
/return
method
return(
<>
{placeholder}
{...other_stuff}
</>
)
SlideContext
SlideContext
seems to have the notion of the current step in it, so you can use it in a component eg. as state or with useEffect
like this, eg. with the material ui collapse component in the above gif:
import React, { useState, useEffect } from "react";
import { SlideContext } from "spectacle";
import Collapse from '@material-ui/core/Collapse'
export default function Collapser({
openStep=0,
children
}){
const { activeStepIndex, isSlideActive } = React.useContext(SlideContext);
return(
<Collapse in={activeStepIndex>=openStep}>
{children}
</Collapse>
)
A really hacky way of using it is to do something like ^^ with another component that just adds steps to a slide like this:
import { useSteps } from "spectacle";
export default function Stepper(
{nSteps= 1}){
const { stepId, isActive, stepNum, placeholder } = useSteps(nSteps);
return(<>{placeholder}</>)
}
so eg. you could do something like this in an .mdx
slide:
---
<Stepper nSteps={3}/>
<Collapser openStep={1}>Hey</Collapser>
<Collapser openStep={2}>What</Collapser>
<Collapser openStep={3}>Up</Collapser>
---
Yeah, similarly, v5 rendered left/right arrows in a <Controls>
component, and I'm not seeing any arrows in a v8 test presentation.
@markerikson for that I think you would use one of these: https://github.com/FormidableLabs/spectacle/blob/86ebff9bfc00f91d68ba8f7130236abb1c9453cb/src/hooks/use-deck-state.js#L87
in the use deck state hook, but it's not exported in the current version (hence PR above) and can't be used by importing from the library using relative paths. if you made a component that used the hook and then had an onClick event that called the callback it would probably work. i respect the fact that this team seems to have rewritten the whole library to use react hooks so just trying to make it easier to PR these things back in
would b cool to have some response from the devs on this bc this is a basic function of the library & trying to contribute in good faith, even happy to write docs if I get some input on intended usage/behavior, but will just fork and diverge otherwise
I ended up writing my own logic to handle this, using the slide index values and the advanceSlide/regressSlide
callbacks inside of DeckContext
.
Upgrading from ^6.0.0
is not possible at the moment as with 8.2.0
export 'Stepper' was not found in 'spectacle'
@sneakers-the-rat hi there! Sorry this has taken so long. I actually wrote the majority of the new code, so here's the 411.
Your analysis of the useSteps
hook is more or less accurate. Essentially, this is the mechanism which allows you to write components which "participate" in the presentation flow by rendering the placeholder
return value in addition to other components. ("placeholder divs" are how the Deck
component detects slides, and how Slide
components detect steps.)
The idea is to allow exactly the kind of behavior you're looking for without the need to use render props. Here's some example code:
const Rotator = ({
angle,
children,
}) => {
const springStyle = useSpring({
transform: `rotate(${angle}deg)`
});
return (
<animated.div style={{
...springStyle,
width: '10rem',
height: '10rem',
background: 'blue',
}}>
{children}
</animated.div>
);
};
const ANGLES_FOR_DEMO = [30, 60, 90];
const RotatorDemo = () => {
const { isActive, step, placeholder } = useSteps(ANGLES_FOR_DEMO.length);
const angle = isActive ? ANGLES_FOR_DEMO[step] : 0;
return (
<>
<Rotator angle={angle}>
{isActive ?? <p>`Rotated ${angle}°`</p>}
</Rotator>
{placeholder}
</>
);
};
Which you'll notice is very similar to what you wrote!
All that being said, there is an actual bug here: the <Appear />
component was intended to replace <Stepper>
, but after looking into it a bit it seems like its "multiple step" functionality was removed for some reason. I'm going to open a PR to add that back, and to add additional documentation for the various hooks.
lovely, thank you for getting to this :)
Prerequisites
Feel free to delete this section if you have checked off all of the following.
^8.0.1
] I am using the latest version of SpectacleDescribe Your Environment
What version of Spectacle are you using? (can be found by running
npm list spectacle
):8.0.1
What version of React are you using? (can be found by running
npm list react
):17.0.2
What browser are you using? Firefox
What machine are you on? macOS
Describe the Problem
Stepper is advertised on the docs, and is mentioned in the changelog, which links to PR https://github.com/FormidableLabs/spectacle/pull/843 which seems to add a
components/stepper.js
file, but that never made it to themain
branch. Did this functionality get merged into some other object? In any case there's a mismatch between the docs and the code.Expected behavior: [What you expect to happen]
import { Stepper } from 'spectacle';
then i guess being able to use it...
Actual behavior: [What actually happens]
export 'Stepper' (imported as 'Stepper') was not found in 'spectacle' (possible exports: Appear, Box, CodePane, CodeSpan, Deck, DeckContext, FlexBox, FullScreen, FullSizeImage, Grid, Heading, Image, Link, ListItem, Markdown, MarkdownPreHelper, MarkdownSlide, MarkdownSlideSet, Notes, OrderedList, Progress, Quote, Slide, SlideContext, SpectacleLogo, Table, TableBody, TableCell, TableHeader, TableRow, Text, UnorderedList, defaultTheme, indentNormalizer, isolateNotes, mdxComponentMap, removeNotes)