forked from primer/design
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create MVP React component layout (primer#366)
* Scaffold React component page layout * Render component data in react component layout * Move title and status * Update markdownlint
- Loading branch information
Showing
9 changed files
with
203 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
id: tree_view | ||
--- | ||
|
||
import {ReactComponentLayout} from '~/src/layouts' | ||
export default ReactComponentLayout |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './react-component-layout' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import Code from '@primer/gatsby-theme-doctocat/src/components/code' | ||
import {H2, H3} from '@primer/gatsby-theme-doctocat/src/components/heading' | ||
import DoctocatLayout from '@primer/gatsby-theme-doctocat/src/components/layout' | ||
import Table from '@primer/gatsby-theme-doctocat/src/components/table' | ||
import {Box, Label, Spinner, Text} from '@primer/react' | ||
import {QueryClient, QueryClientProvider, useQuery} from '@tanstack/react-query' | ||
import React from 'react' | ||
|
||
async function fetchPrimerReactData() { | ||
const json = await fetch('https://api.github.com/repos/primer/react/contents/generated/components.json').then( | ||
response => response.json(), | ||
) | ||
// TODO: Handle errors | ||
const content = atob(json.content) | ||
return JSON.parse(content) | ||
} | ||
|
||
function Page({children, ...props}: any) { | ||
const {id = ''} = props.pageContext.frontmatter | ||
// TODO: Fetch inital data at build time, then hydrate | ||
const queryResult = useQuery(['react-component-data'], fetchPrimerReactData) | ||
const componentData = queryResult.data?.components[id] | ||
const importStatement = `import {${componentData?.name}} from '@primer/react${ | ||
componentData?.status === 'draft' ? '/drafts' : '' | ||
}'` | ||
|
||
const tableOfContents = { | ||
items: [ | ||
{url: '#import', title: 'Import'}, | ||
{url: '#props', title: 'Props'}, | ||
], | ||
} | ||
|
||
const frontmatter = { | ||
title: componentData?.name, | ||
status: sentenceCase(componentData?.status || ''), | ||
a11yReviewed: componentData?.a11yReviewed, | ||
} | ||
|
||
const pageContext = deepMerge(props.pageContext, {tableOfContents, frontmatter}) | ||
|
||
return ( | ||
<DoctocatLayout {...deepMerge(props, {pageContext})}> | ||
{queryResult.isLoading ? ( | ||
<Box sx={{display: 'flex', width: '100%', justifyContent: 'center'}}> | ||
<Spinner /> | ||
</Box> | ||
) : null} | ||
{queryResult.isError ? <pre>{JSON.stringify(queryResult.error, null, 2)}</pre> : null} | ||
{queryResult.isSuccess && componentData ? ( | ||
<> | ||
<H2>Import</H2> | ||
{/* @ts-ignore */} | ||
<Code className="language-javascript">{importStatement}</Code> | ||
{/* TODO: Link to source code */} | ||
{/* TODO: Link to storybook */} | ||
<H2>Props</H2> | ||
<H3>{componentData.name}</H3> | ||
<PropsTable props={componentData.props} /> | ||
{componentData.subcomponents.map(subcomponent => ( | ||
<> | ||
<H3>{subcomponent.name}</H3> | ||
<PropsTable props={subcomponent.props} /> | ||
</> | ||
))} | ||
</> | ||
) : null} | ||
</DoctocatLayout> | ||
) | ||
} | ||
|
||
/** Convert a string to sentence case. */ | ||
function sentenceCase(str: string) { | ||
return str.replace(/([A-Z])/g, ' $1').replace(/^./, function (str) { | ||
return str.toUpperCase() | ||
}) | ||
} | ||
|
||
/** Deeply merge two objects */ | ||
function deepMerge(obj1: any, obj2: any): any { | ||
let result = {...obj1} | ||
for (let key in obj2) { | ||
if (obj2.hasOwnProperty(key)) { | ||
if (typeof obj2[key] === 'object' && !Array.isArray(obj2[key])) { | ||
result[key] = deepMerge(result[key], obj2[key]) | ||
} else { | ||
result[key] = obj2[key] | ||
} | ||
} | ||
} | ||
return result | ||
} | ||
|
||
const queryClient = new QueryClient() | ||
|
||
// TODO: Render provider at the root of the app | ||
export function ReactComponentLayout(props) { | ||
return ( | ||
<QueryClientProvider client={queryClient}> | ||
<Page {...props} /> | ||
</QueryClientProvider> | ||
) | ||
} | ||
|
||
function PropsTable({ | ||
props, | ||
}: { | ||
props: Array<{ | ||
name: string | ||
type: string | ||
defaultValue: string | ||
required: boolean | ||
deprecated: boolean | ||
description: string | ||
}> | ||
}) { | ||
return ( | ||
<Table> | ||
<colgroup> | ||
<col style={{width: '20%'}} /> | ||
<col style={{width: '30%'}} /> | ||
<col style={{width: '10%'}} /> | ||
<col style={{width: '40%'}} /> | ||
</colgroup> | ||
<thead> | ||
<tr> | ||
<th align="left">Name</th> | ||
<th align="left">Type</th> | ||
<th align="left">Default</th> | ||
<th align="left">Description</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{props.map(prop => ( | ||
<tr key={prop.name}> | ||
<td valign="top"> | ||
<Box sx={{display: 'flex', gap: 2, alignItems: 'center'}}> | ||
<Text sx={{fontFamily: 'mono', fontSize: 1, whiteSpace: 'nowrap'}}>{prop.name}</Text> | ||
{prop.required ? <Label variant="accent">Required</Label> : null} | ||
{prop.deprecated ? <Label variant="danger">Deprecated</Label> : null} | ||
</Box> | ||
</td> | ||
<td valign="top"> | ||
<Text as="pre" sx={{m: 0, fontFamily: 'mono', fontSize: 1, whiteSpace: 'pre-wrap'}}> | ||
{prop.type} | ||
</Text> | ||
</td> | ||
<td> | ||
<Text sx={{fontFamily: 'mono', fontSize: 1, whiteSpace: 'nowrap'}}>{prop.defaultValue}</Text> | ||
</td> | ||
<td>{prop.description}</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</Table> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1215,10 +1215,10 @@ | |
dependencies: | ||
lodash "^4.17.15" | ||
|
||
"@github/prettier-config@^0.0.4": | ||
version "0.0.4" | ||
resolved "https://registry.yarnpkg.com/@github/prettier-config/-/prettier-config-0.0.4.tgz#cbfddb36a7f29a81c5af155dc5827e95b23b9ccd" | ||
integrity sha512-ZOJ+U771Mw68qp2GPbcqPt2Xg0LEl0YwiIFHXwVLAFm2TgDnsgcCHhXO8PIxOWPqSFO4S7xIMD9CBobfaWGASA== | ||
"@github/prettier-config@^0.0.6": | ||
version "0.0.6" | ||
resolved "https://registry.yarnpkg.com/@github/prettier-config/-/prettier-config-0.0.6.tgz#5118e6e9f67fef9c2cd74574da7a4d86229ffb44" | ||
integrity sha512-Sdb089z+QbGnFF2NivbDeaJ62ooPlD31wE6Fkb/ESjAOXSjNJo+gjqzYYhlM7G3ERJmKFZRUJYMlsqB7Tym8lQ== | ||
|
||
"@graphql-tools/batch-execute@^7.1.2": | ||
version "7.1.2" | ||
|
@@ -2060,6 +2060,19 @@ | |
dependencies: | ||
defer-to-connect "^2.0.0" | ||
|
||
"@tanstack/[email protected]": | ||
version "4.22.4" | ||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.22.4.tgz#aca622d2f8800a147ece5520d956a076ab92f0ea" | ||
integrity sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw== | ||
|
||
"@tanstack/react-query@^4.23.0": | ||
version "4.23.0" | ||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.23.0.tgz#0b9e14269a48cf5a4ffe46c8525cdb9df2ebd9cf" | ||
integrity sha512-cfQsrecZQjYYueiow4WcK8ItokXJnv+b2OrK8Lf5kF7lM9uCo1ilyygFB8wo4MfxchUBVM6Cs8wq4Ed7fouwkA== | ||
dependencies: | ||
"@tanstack/query-core" "4.22.4" | ||
use-sync-external-store "^1.2.0" | ||
|
||
"@testing-library/dom@*": | ||
version "8.16.1" | ||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.16.1.tgz#96e528c9752d60061128f043e2b43566c0aba2d9" | ||
|
@@ -14529,6 +14542,11 @@ use-sidecar@^1.1.2: | |
detect-node-es "^1.1.0" | ||
tslib "^2.0.0" | ||
|
||
use-sync-external-store@^1.2.0: | ||
version "1.2.0" | ||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" | ||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== | ||
|
||
use@^3.1.0: | ||
version "3.1.1" | ||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" | ||
|