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

Appear component does not function when placed in an MDX file #870

Open
antonwintergerst opened this issue Apr 1, 2020 · 3 comments
Open
Assignees
Labels
🐛 Bug Issues or PRs that report or fix a bug ✓ Verified Org member or multiple community members can reproduce a given bug

Comments

@antonwintergerst
Copy link

Describe Your Environment

What version of Spectacle are you using?
spectacle@6.0.1

What version of React are you using?
react@16.13.1

What browser are you using?
Chrome 80.0.3987.149

What machine are you on?
MacBook Pro (15-inch 2017)

Describe the Problem

Appear component does not function when placed in an MDX file.

Expected behavior:
Slide navigation should step through Appear steps before moving to next slide.

Actual behavior:
Slide navigation skips Appear steps and moves to next slide.

Additional Information

These were the steps I took to setup a project:

  1. Install global dependencies
    npm i typescript spectacle-cli -g

  2. Create a new presentation
    spectacle-boilerplate --mode mdx --dir "some-presentation"

  3. Add TypeScript support

yarn add typescript @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-typescript -D
tsc --init --declaration --allowSyntheticDefaultImports --target esnext --outDir lib
  1. Add a .babelrc file
{
  "presets": ["@babel/env", "@babel/typescript", "@babel/preset-react"],
  "plugins": ["@babel/proposal-class-properties"]
}
  1. Update webpack.config.js
// Add this to module.exports
resolve: {
    extensions: ['.ts', '.tsx', '.js', '.json']
}
// Change test: /\.(jsx)?$/, to
test: /\.(ts|js)x?$/,

How was I able to even render an Appear component in MDX?

By updating the mdxComponentMap to include the Appear tag and then mapping this to the Appear component:

const Presentation = () => (
  <MDXProvider
    components={{
      ...mdxComponentMap,
      Appear: props => <Appear {...props} />
    }}
  >
    <Deck loop theme={theme} template={template}>
      {slides
        .map((MDXSlide, i) => [MDXSlide, notes[i]])
        .map(([MDXSlide, MDXNote], i) => (
          <Slide key={`slide-${i}`} slideNum={i}>
            <MDXSlide />
            <Notes>
              <MDXNote />
            </Notes>
          </Slide>
        ))}
    </Deck>
  </MDXProvider>
);

This allows markdown to be written like so:

<Appear elementNum={1}>

- Lorem ipsum
- Lorem ipsum
- Lorem ipsum

</Appear>

And it is correctly rendering the expected HTML

<div style="opacity: 0;">
  <ul color="primary" font-family="text" font-size="text" class="sc-bZQynM fHBYr">
    <li class="sc-gzVnrw eGyYYk">Lorem ipsum</li>
    <li class="sc-gzVnrw eGyYYk">Lorem ipsum</li>
    <li class="sc-gzVnrw eGyYYk">Lorem ipsum</li>
  </ul>
</div>

However, the component is not detected by the searchChildrenForAppear function and this results in the navigator not being able to step through these Appear steps. Here's where that function gets called:

const appearElements = searchChildrenForAppear(slide.props.children);

Any assistance would be greatly appreciated 🙌

@antonwintergerst
Copy link
Author

I've found a work around which is a bit hacky but at least it functions:

const Presentation = () => (
  <MDXProvider
    components={{
      ...mdxComponentMap,
      Appear: props => <Appear {...props} />
    }}
  >
    <Deck loop theme={theme} template={template}>
      {slides
        .map((MDXSlide, i) => [MDXSlide, notes[i]])
        .map(([MDXSlide, MDXNote], i) => {
          // find the number of appear elements on this slide
          const appearElementCount = (
            MDXSlide.toString().match(/\[\"mdx\"\]\)\(Appear/g) || []
          ).length;

          // render new empty Appear elements that will get picked up by the `searchChildrenForAppear` function
          // mdx Appear markdowns should have the same elementNum prop values and this will trick the navigator into making both appear
          return (
            <Slide key={`slide-${i}`} slideNum={i + 1}>
              <MDXSlide />
              <div>
                {Array(appearElementCount)
                  .fill(0)
                  .map((_, a) => (
                    <Appear elementNum={a} key={`slide-${i}-appear-${a}`} />
                  ))}
              </div>
              <Notes>
                <MDXNote />
              </Notes>
            </Slide>
          );
        })}
    </Deck>
  </MDXProvider>
);

@kale-stew kale-stew added 🐛 Bug Issues or PRs that report or fix a bug ✓ Verified Org member or multiple community members can reproduce a given bug labels Apr 2, 2020
@ryan-roemer
Copy link
Member

ryan-roemer commented Apr 2, 2020

Great find!

The MDX loader's main job is translating MD in MDX file to JSX and allowing existing JSX to work. The Appear element isn't really something first class in MDX, it's more of something that should be supported via a normal import, so I really think we're looking at supporting something like:

---

import { Appear } from 'spectacle';

## Use Spectacle Appear Tag!

<Appear elementNum={0}>
Should appear later!
</Appear>

The above does not work, so I think our best starting point is adding the above slide to https://github.com/FormidableLabs/spectacle-mdx-loader/blob/master/examples/mdx/slides.mdx and getting that working with some combination of work in spectacle and spectacle-mdx-loader repositories.

@ryan-roemer
Copy link
Member

It's looking more like something that may be primarily in spectacle-mdx-loader. As a debugging helper, here's what is currently generated for the above slide:

function MDXContentWrapperSlide1(props) {
/* @jsx mdx */
const makeShortcode = name => function MDXDefaultShortcode(props) {
  console.warn("Component " + name + " was not imported, exported, or provided by MDXProvider as global scope")
  return <div {...props}/>
};

const layoutProps = {
  testProp
};

const MDXLayout = "wrapper";

function MDXContent({
  components,
  ...props
}) {
  return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
    <h2>{`Use Spectacle Appear Tag!`}</h2>
    <Appear elementNum={0} mdxType="Appear">
Should appear later!
    </Appear>
  </MDXLayout>;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 Bug Issues or PRs that report or fix a bug ✓ Verified Org member or multiple community members can reproduce a given bug
Projects
None yet
Development

No branches or pull requests

4 participants