Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
34 changes: 34 additions & 0 deletions convertToMDX.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env ts-node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this if we are using tsx instead of ts-node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nope I don't think so, good catch


import { readFile, writeFile } from 'fs/promises'
import { glob } from 'glob'

async function main() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this should be part of the cli.

const files = await glob('./testContent/react/examples/*.md')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a way to have this be passed in via the command line.

files.forEach(async (file) => {
const fileContent = await readFile(file, 'utf-8')

//regex link: https://regexr.com/8f0er
const importRegex = /(?<!```no[lL]ive\n)import {?[\w\s,\n]*}?.*\n/g

//removes all top level imports from the md file that the old docs framework used to determine what imports are needed
const withoutImports = fileContent.replace(importRegex, '')

//regex link: https://regexr.com/8f0bu
const ExampleBlockRegex = /```[tj]s file=['"]\.?\/?(\w*)\.(\w*)['"]\s*\n```/g

//the first capture group is the example file name without the extension or path, the second is the extension
const replacementString = `\nimport $1 from "./$1.$2?raw"\n\n<LiveExample src={$1} />`
const examplesConvertedToMDX = withoutImports.replace(
ExampleBlockRegex,
replacementString,
)

//we want to strip the nolive/noLive tags from codeblocks as that was custom to the old docs framework
const noLiveRemoved = examplesConvertedToMDX.replace(/```no[lL]ive/g, '```')

await writeFile(file + 'x', noLiveRemoved)
})
}

main()
18 changes: 16 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/node": "^9.1.3",
"@astrojs/mdx": "^4.2.6",
"@astrojs/node": "^9.1.3",
"@astrojs/react": "^4.2.1",
"@nanostores/react": "^0.8.0",
"@patternfly/ast-helpers": "^1.4.0-alpha.190",
"@patternfly/patternfly": "^6.0.0",
"@patternfly/react-code-editor": "^6.2.2",
"@patternfly/react-core": "^6.0.0",
"@patternfly/react-icons": "^6.0.0",
"@patternfly/react-styles": "^6.0.0",
"@patternfly/react-table": "^6.0.0",
"@patternfly/react-tokens": "^6.0.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"astro": "^5.4.1",
Expand All @@ -60,6 +63,7 @@
"react": "^18.3.1",
"react-docgen": "^7.1.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^6.0.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this package as a quick and easy error boundary to wrap the examples in so that errors encountered when trying to render them don't crash the UI while I fine tuned the conversion. It has a few million weekly downloads on NPM so it's probably fine, but I have no strong feeling about keeping it in for the real PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've used it and liked it in the past fwiw.

"sass": "^1.81.0",
"typescript": "^5.6.3"
},
Expand Down
27 changes: 23 additions & 4 deletions src/components/LiveExample.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import React, { useState } from 'react'
import React, { useState, Fragment, useRef, useEffect, createRef, useReducer } from 'react'
import { convertToReactComponent } from '@patternfly/ast-helpers'
import { ErrorBoundary } from 'react-error-boundary'
import * as reactCoreModule from '@patternfly/react-core'
import * as reactIconsModule from '@patternfly/react-icons'
import styles from "@patternfly/react-styles/css/components/_index"
import * as reactTokensModule from "@patternfly/react-tokens"
Comment on lines +5 to +7
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll want to refactor this so that we pass all of these modules via the config, but for now just doing this works. What do yall think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be opposed to that being done in a followup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made this issue to address #72

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine for now.

import { ExampleToolbar } from './ExampleToolbar'
interface LiveExampleProps {
src: string
}

function fallbackRender({ error }: any) {
return (
<div role="alert">
<p>Something went wrong:</p>
<pre style={{ color: 'red' }}>{error.message}</pre>
</div>
)
}

function getLivePreview(editorCode: string) {
const scope = { ...reactCoreModule, ...{ useState } }
const scope = {
...reactCoreModule,
...reactIconsModule,
styles,
...reactTokensModule,
...{ useState, Fragment, useRef, useEffect, createRef, useReducer },
}
const { code: transformedCode } = convertToReactComponent(editorCode)

const componentNames = Object.keys(scope)
Expand All @@ -28,7 +47,7 @@ export const LiveExample = ({ src }: LiveExampleProps) => {
const livePreview = getLivePreview(code)

return (
<>
<ErrorBoundary fallbackRender={fallbackRender}>
{livePreview}
<ExampleToolbar
originalCode={src}
Expand All @@ -37,6 +56,6 @@ export const LiveExample = ({ src }: LiveExampleProps) => {
lang="ts"
isFullscreen={false}
/>
</>
</ErrorBoundary>
)
}
2 changes: 1 addition & 1 deletion src/content.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const content = [
{ base: 'textContent', pattern: '*.{md,mdx}', name: 'textContent' },
{ base: 'textContent', pattern: 'examples/*/*.mdx', name: 'examples' },
{ base: 'textContent', pattern: 'examples/*/*.mdx', name: 'examples' }
// TODO: Remove. Uncomment for local testing.
// {
// "packageName":"@patternfly/react-core",
Expand Down
71 changes: 57 additions & 14 deletions src/pages/[section]/[...page].astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ import { componentTabs } from '../../globals'
import PropsTables from '../../components/PropsTables.astro'
import CSSTable from '../../components/CSSTable.astro'
import SectionGallery from '../../components/section-gallery/SectionGallery.astro'
import LiveExample from '../../components/LiveExample.astro'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file were needed because by default the examples are rendering at this endpoint rather than /[...tab], though I'm not sure why off hand.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its because the nav links to components/alert (hitting page.astro and then rewriting to tab.astro) and not components/alert/react? Though it should be ultimately only hitting tab.astro though so I'm not sure either.

import {
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
small,
blockquote,
pre,
hr,
ul,
ol,
dl,
li,
dt,
dd,
} from '../../components/Content'

export async function getStaticPaths() {
const collections = await Promise.all(
Expand All @@ -31,8 +52,9 @@ const { entry, propComponents, cssPrefix } = Astro.props
const { title, id, section } = entry.data
const { Content } = await render(entry)

if(section === 'components' && componentTabs[id]) { // if section is components & tab exists, rewrite to first tab content
return Astro.rewrite(`/components/${kebabCase(id)}/${componentTabs[id][0]}`);
if (section === 'components' && componentTabs[id]) {
// if section is components & tab exists, rewrite to first tab content
return Astro.rewrite(`/components/${kebabCase(id)}/${componentTabs[id][0]}`)
}
---

Expand All @@ -44,17 +66,38 @@ if(section === 'components' && componentTabs[id]) { // if section is components
</Title>
)
}
<PageSection id="main-content" isFilled>
<Content components={{
SectionGallery
}}/>
<Stack hasGutter>
<StackItem>
<PropsTables propComponents={propComponents} server:defer />
</StackItem>
<StackItem>
<CSSTable cssPrefix={cssPrefix} server:defer />
</StackItem>
</Stack>
<PageSection id="main-content" isFilled>
<Content
components={{
SectionGallery,
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
small,
blockquote,
pre,
hr,
ul,
ol,
dl,
li,
dt,
dd,
LiveExample,
}}
/>
<Stack hasGutter>
<StackItem>
<PropsTables propComponents={propComponents} server:defer />
</StackItem>
<StackItem>
<CSSTable cssPrefix={cssPrefix} server:defer />
</StackItem>
</Stack>
</PageSection>
</MainLayout>