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

Import and Export for overriding MDX HTML defaults #30

Open
jonsage opened this issue Nov 15, 2023 · 5 comments
Open

Import and Export for overriding MDX HTML defaults #30

jonsage opened this issue Nov 15, 2023 · 5 comments
Labels
enhancement New feature or request

Comments

@jonsage
Copy link

jonsage commented Nov 15, 2023

Kizu wrote this https://blog.kizu.dev/astro-mdx-components/ and I recommend he take a look at your integration to simplify things, however the part I think your integration doesn't handle when it comes to overriding default HTML elements in MDX is the export step.

I was wondering whether it would be simple to extend functionality to AutoImport to both import and re-export components for MDX and this way it would possible to provide overrides for HTML elements like <a> and <h1> etc.

@delucis
Copy link
Owner

delucis commented Nov 15, 2023

Interesting idea! Might be possible I think. What do you think the API could look like? I guess we’d need a way to know what HTML elements an auto-imported component should map to.

@delucis delucis added the enhancement New feature or request label Nov 15, 2023
@teinett
Copy link

teinett commented Nov 15, 2023

Something like this:

integrations: [
        AutoImport({
            imports: [
                {
                   blockquote: "@/components/MDXquote.astro"
                },
            ],
        }),
        mdx(),
    ],

@jonsage
Copy link
Author

jonsage commented Nov 16, 2023

Interesting idea! Might be possible I think. What do you think the API could look like? I guess we’d need a way to know what HTML elements an auto-imported component should map to.

This is a bit new to me, but something I'm an interested to see working to streamline working with MDX - AutoImport already helps a lot with that - it might even make a great "built-in" feature of Astro in the future tbh.

So, my naive ideas to avoid breaking changes:

integrations: [
	AutoImport({
		imports: [
			{
				// third item named export
				'./src/components/Link.astro': [['default', 'Link', 'a']],
			},
			// OR
			{
				// second item config object
				'./src/components/Link.astro': [['default', { import_as: 'Link', export_as: 'a' }]],
			},
		]
	}),
	// OR (in a future ideal world)
	mdx({
		components: {
			a: 'Link',
			// OR (to avoid having to previously AutoImport)
			h1: './src/components/Heading.astro',
			// OR (to avoid having to previously AutoImport, and import a named export)
			p: ['./src/components/Paragraph.astro', 'default']
		}
	}),
]

Also, I found this issue https://github.com/orgs/mdx-js/discussions/2271

EDIT: just adding the link to the existing mdx() integration config object https://docs.astro.build/en/guides/integrations-guide/mdx/#options-inherited-from-markdown-config

@endigo9740
Copy link

endigo9740 commented Jan 31, 2024

Hey @delucis, sorry for the ping, but I've been researching this issue all day and your name keeps coming up when it comes to Astro and MDX.

I'm the creator and core maintainer for Skeleton:
https://www.skeleton.dev/

We're currently porting our doc site to Astro and really interested in the prospect of custom HTML components in MDX:
https://docs.astro.build/en/guides/markdown-content/#assigning-custom-components-to-html-elements

The reason being, we use semantic utility classes to assign all our typography styles:
https://www.skeleton.dev/elements/typography

<h1 class="h1">Skeleton H1</h1>
<a class="anchor" href="/">Anchor</a>
<blockquote class="blockquote">Skeleton</blockquote>

Because of this, we'll have dozens of doc pages that will require replacing the MDX output elements. So far, the cleanest solution I've come up with is doing something like this:

/pages/**/index.mdx

---
---

import componentSet from '@components/mdx/index'; // index.ts
export const components = componentSet;

/components/mdx/index.ts

import Blockquote from './Blockquote.astro';
// ...(repeat for every component)...

export const componentSet = {
    blockquote: Blockquote,
    // ...(repeat for every component)...
};

export default componentSet;

I've come across your astro-auto-import tool here. While this can remove one of the two lines per page, that still leave room for error if someone misses this.

So I was curious if you're aware of any movement on the proposal from @jonsage above, or have any sage advice on how I might approach this. Thanks in advance!

@delucis
Copy link
Owner

delucis commented Feb 1, 2024

So I was curious if you're aware of any movement on the proposal from @jonsage above, or have any sage advice on how I might approach this. Thanks in advance!

A couple of people expressed interest in submitting PRs, but nothing has materialised just yet. But I’d be happy to guide a PR if you’re up for trying to implement it!

As a pointer, like you show, we’d need a way to generate the export const components = {}; statement and auto import any required components.

I’d suggest a config API something like:

AutoImport({
  imports: [
    // as currently supported, an array of auto-imported components
  ],
  // a map of components, more or less 1:1 with what ends up in MDX’s `components` export:
  defaultComponents: {
    // quick syntax for default exports
    p: './src/CustomParagraph.astro',
    // some kind of syntax for named exports?
    blockquote: { name: 'CustomBlockquote', from: './src/Components.ts' },
  },
});

Internally we’d then need to build this into a string like:

import p from './src/CustomParagraph.astro';
import { CustomBlockquote as blockquote } from './src/Components.ts';

export const components = {
  p,
  blockquote,
};

A corner case that would need checking would be making sure we don’t have name clashes with anything in import I guess. Or alternatively we insure against that with some namespacing like:

import AUTO_IMPORT_p from './src/CustomParagraph.astro';
import { CustomBlockquote as AUTO_IMPORT_blockquote } from './src/Components.ts';

export const components = {
  p: AUTO_IMPORT_p,
  blockquote: AUTO_IMPORT_blockquote,
};

And inject these imports much like we already do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants