- {docs.displayName} | React Common
+ {docs.displayName} | {pkg['title'] || pkg.name}
+
{docs.displayName}
diff --git a/packages/react-common-docs/src/components/Nav/Nav.tsx b/packages/react-common-docs/src/components/Nav/Nav.tsx
index 8fd4ffe..65e31ad 100644
--- a/packages/react-common-docs/src/components/Nav/Nav.tsx
+++ b/packages/react-common-docs/src/components/Nav/Nav.tsx
@@ -18,6 +18,9 @@ const Container = styled('span')({
const HeaderContainer = styled(Container)({
marginTop: '2rem',
+ fontSize: '0.75rem',
+ fontWeight: 'bolder',
+ textTransform: 'uppercase',
})
const propTypes = {
diff --git a/packages/react-common-docs/src/components/NavLink/NavLink.tsx b/packages/react-common-docs/src/components/NavLink/NavLink.tsx
index e70bbd5..92af171 100644
--- a/packages/react-common-docs/src/components/NavLink/NavLink.tsx
+++ b/packages/react-common-docs/src/components/NavLink/NavLink.tsx
@@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types'
import styled from 'styled-components'
import { Icon } from '../../../../react-common/src'
import MenuGraphics, { propTypes as menuGraphicsPropTypes } from '../MenuGraphics/MenuGraphics'
+import { useRouter } from 'next/router'
const Link = styled('a')({
display: 'block',
@@ -41,6 +42,15 @@ const Link = styled('a')({
},
})
+const ActiveLink = styled(Link)({
+ '::before': {
+ opacity: 0.25,
+ },
+ '::after': {
+ opacity: 0.5,
+ },
+})
+
const LinkText = styled('span')({
alignSelf: 'center',
display: 'block',
@@ -102,55 +112,60 @@ const NavLink = React.forwardRef((
onClick,
},
ref
-) => (
- any}
- >
- {
- // @ts-ignore
-
- {
- graphics as object
- && (
-
- {
- // @ts-ignore
-
- }
-
- )
- }
-
-
- {title}
-
+) => {
+ const router = useRouter()
+ const active = router.basePath + router.route === href
+ const Component = active ? ActiveLink : Link
+ return (
+ any}
+ >
+ {
+ // @ts-ignore
+
{
- subtitle as string
+ graphics as object
&& (
-
- {subtitle}
-
+
+ {
+ // @ts-ignore
+
+ }
+
)
}
-
- {
- indicator as string
- && (
-
-
-
- )
- }
-
- }
-
-))
+
+
+ {title}
+
+ {
+ subtitle as string
+ && (
+
+ {subtitle}
+
+ )
+ }
+
+ {
+ indicator as string
+ && (
+
+
+
+ )
+ }
+
+ }
+
+ )
+})
NavLink.propTypes = propTypes
diff --git a/packages/react-common-docs/src/components/Playground/Playground.tsx b/packages/react-common-docs/src/components/Playground/Playground.tsx
index 68ca3a9..11d4d79 100644
--- a/packages/react-common-docs/src/components/Playground/Playground.tsx
+++ b/packages/react-common-docs/src/components/Playground/Playground.tsx
@@ -1,5 +1,6 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
+import PrismTheme from '../../utilities/prism-themes/dark'
import {
LiveProvider,
LiveEditor,
@@ -8,13 +9,42 @@ import {
import styled from 'styled-components'
const Figure = styled('figure')({
- margin: 0,
+ margin: '0 -1rem',
+ padding: '1rem',
+ boxSizing: 'border-box',
+ position: 'relative',
+ '::before': {
+ position: 'absolute',
+ content: "''",
+ zIndex: -1,
+ backgroundColor: 'black',
+ opacity: 0.125,
+ top: 0,
+ left: 0,
+ width: '100%',
+ height: '100%',
+ },
+})
+
+const Caption = styled('figcaption')({
+ fontSize: '0.75rem',
+ fontWeight: 'bolder',
+ textTransform: 'uppercase',
+ marginBottom: '1rem',
+ marginTop: '-0.5rem',
})
const StyledLiveEditor = styled(LiveEditor)({
lineHeight: 1.125,
fontFamily: 'var(--font-family-monospace), monospace !important',
marginTop: '1rem',
+ 'textarea': {
+ padding: '0 !important',
+ outline: 0,
+ },
+ 'pre': {
+ padding: '0 !important',
+ },
})
const propTypes = {
@@ -42,9 +72,17 @@ const Playground: React.FC = ({
{
label as string
&& (
-
- {label}
-
+
+ Playground - {label}
+
+ )
+ }
+ {
+ !label
+ && (
+
+ Playground
+
)
}
@@ -52,7 +90,9 @@ const Playground: React.FC
= ({
...components,
}}>
-
+
diff --git a/packages/react-common-docs/src/components/Props/Props.tsx b/packages/react-common-docs/src/components/Props/Props.tsx
index 784d711..c5c2b4f 100644
--- a/packages/react-common-docs/src/components/Props/Props.tsx
+++ b/packages/react-common-docs/src/components/Props/Props.tsx
@@ -1,6 +1,7 @@
import * as React from 'react'
import * as PropTypes from 'prop-types'
import styled from 'styled-components'
+import PrismTheme from '../../utilities/prism-themes/dark'
import docgen from '../../docgen.json'
const Base = styled('table')({
@@ -114,6 +115,150 @@ type Docs = {
}
}
+const getPropName = (name, def) => def.required ? name : name + '?'
+
+const getPropType = def => {
+ switch (def.type.name) {
+ case '(...args: any[]) => any':
+ return 'Function'
+ case 'enum':
+ return def.type.value.map(v => v.value).join(' | ')
+ default:
+ break
+ }
+ return def.type.name
+}
+
+const getPropDefaultValue = def => {
+ return def.defaultValue
+ ? JSON.stringify(def.defaultValue.value)
+ : undefined
+}
+
+const getPrismStyle = style => PrismTheme.styles.find(s => s.types.includes(style)) || PrismTheme.plain
+
+const getPropNameHtml = (propName, propType) => {
+ const variable = getPrismStyle('variable')
+ const operator = getPrismStyle('operator')
+ const fn = getPrismStyle('function')
+ const isFunction = propType === 'Function'
+ const trueStyle = isFunction ? fn : variable
+ return (
+ propName.endsWith('?')
+ ? (
+
+
+ {propName.slice(0, -1)}
+
+
+ {propName.slice(-1)}
+
+
+ )
+ : (
+
+ {propName}
+
+ )
+ )
+}
+
+const getPropTypeHtml = propType => {
+ if (!propType) {
+ return undefined
+ }
+ const punctuation = getPrismStyle('punctuation')
+ const string = getPrismStyle('string')
+ const operator = getPrismStyle('operator')
+ const keyword = getPrismStyle('keyword')
+ const boolean = getPrismStyle('boolean')
+ const number = getPrismStyle('number')
+ const type = getPrismStyle('type')
+ const tokens = propType.split('|')
+ return tokens.reduce(
+ (tt, t, i) => {
+ let currentToken
+ if (t.trim().startsWith('"') && t.trim().endsWith('"')) {
+ currentToken = (
+
+
+ {t.slice(0, t.indexOf('"') + 1)}
+
+
+ {t.slice(t.indexOf('"') + 1, t.lastIndexOf('"'))}
+
+
+ {t.slice(t.lastIndexOf('"'))}
+
+
+ )
+ } else if ('any string boolean number symbol unknown object bigint'.split(' ').includes(t)) {
+ currentToken = (
+
+ {t}
+
+ )
+ } else if ('null'.split(' ').includes(t)) {
+ currentToken = (
+
+ {t}
+
+ )
+ } else if ('true false'.split(' ').includes(t)) {
+ currentToken = (
+
+ {t}
+
+ )
+ } else if (!isNaN(Number(t))) {
+ currentToken = (
+
+ {t}
+
+ )
+ } else {
+ currentToken = (
+
+ {t}
+
+ )
+ }
+ return [
+ ...tt,
+ i > 0 &&
+ |
+ ,
+ currentToken,
+ ]
+ },
+ []
+ )
+}
+
const Props: React.FC = ({ of: ofAttr }) => {
const docs = (docgen as unknown as Docs[]).find(d => d.displayName === ofAttr)
@@ -147,50 +292,37 @@ const Props: React.FC = ({ of: ofAttr }) => {
{
- Object.entries((docs as Docs).props).map(([name, def]) => (
-
-
-
- {def.required ? name : name + '?'}
-
-
-
- {
- def.type.name === 'enum'
- && (
-
- {def.type.value.map(v => v.value).join(' | ')}
-
- )
- }
- {
- def.type.name !== 'enum'
- && (
-
- {def.type.name}
-
- )
- }
-
-
- {
- def.defaultValue
- && (
-
- {JSON.stringify(def.defaultValue.value)}
-
- )
- }
-
-
- {def.description}
-
-
- ))
+ Object.entries((docs as Docs).props).map(([name, prop]) => {
+ const propName = getPropName(name, prop)
+ const propDefaultValue = getPropDefaultValue(prop)
+ const propType = getPropType(prop)
+ return (
+
+
+
+ {getPropNameHtml(propName, propType)}
+
+
+
+
+ {getPropTypeHtml(propType)}
+
+
+
+
+ {getPropTypeHtml(propDefaultValue)}
+
+
+
+ {prop.description}
+
+
+ )
+ })
}
diff --git a/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx b/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx
index daf9e6c..7786482 100644
--- a/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx
+++ b/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx
@@ -6,6 +6,7 @@ import styled from 'styled-components'
import Link from 'next/link'
import Nav from '../Nav/Nav'
import { MouseEventHandler } from 'react'
+import ThemeToggle from '../ThemeToggle/ThemeToggle'
const StyledLink = styled('a')({
display: 'block',
@@ -82,21 +83,6 @@ const Actions = styled('div')({
alignItems: 'center',
})
-const ToggleWrapper = styled('label')({
- cursor: 'pointer',
- color: 'var(--color-accent)',
- display: 'inline-block',
-})
-
-const ToggleIcon = styled('span')({
-
-})
-
-const ToggleInput = styled('input')({
- position: 'absolute',
- left: -999999,
-})
-
const NavWrapper = styled('nav')({
'--size-link': '3rem',
marginBottom: '4rem',
@@ -122,82 +108,39 @@ type Props = PropTypes.InferProps
const Sidebar: React.FC = ({
data,
brand: BrandRaw,
- initialTheme = 'Dark',
+ initialTheme,
}) => {
- const [theme, setTheme] = React.useState(initialTheme)
const [sidebar, setSidebar] = React.useState(false)
const navRef = React.useRef(null)
const Brand = BrandRaw!
- const toggleDarkMode = (b: string) => () => {
- setTheme(b)
- }
-
const toggleSidebar = (b: boolean): MouseEventHandler => (e) => {
e.preventDefault()
setSidebar(b)
}
- React.useEffect(() => {
- let storageTheme = window.localStorage.getItem('tesseract-theme')
- || (
- window.matchMedia('(prefers-color-scheme: dark)').matches
- ? 'Dark'
- : 'Light'
- )
- window.localStorage.setItem('tesseract-theme', storageTheme)
- setTimeout(() => {
- setTheme(storageTheme)
- })
- }, [])
-
- React.useEffect(() => {
- const eventListener = (e: MouseEvent) => {
- let currentElement = e.target as HTMLElement
- while (currentElement !== e.currentTarget) {
- if (currentElement.tagName === 'A') {
- setSidebar(false)
- break
- }
- const { parentElement } = currentElement
- if (parentElement as HTMLElement === null) {
- break
- }
- currentElement = parentElement as HTMLElement
+ const handleSidebarClose = (e: MouseEvent) => {
+ let currentElement = e.target as HTMLElement
+ while (currentElement !== e.currentTarget) {
+ if (currentElement.tagName === 'A') {
+ setSidebar(false)
+ break
}
+ const { parentElement } = currentElement
+ if (parentElement as HTMLElement === null) {
+ break
+ }
+ currentElement = parentElement as HTMLElement
}
+ }
- if (navRef.current === null) {
- return
- }
-
- navRef.current.addEventListener('click', eventListener, { capture: true })
+ React.useEffect(() => {
+ navRef.current.addEventListener('click', handleSidebarClose, { capture: true })
return () => {
- if (navRef.current === null) {
- return
- }
-
- navRef.current.removeEventListener('click', eventListener, { capture: true })
+ navRef.current.removeEventListener('click', handleSidebarClose, { capture: true })
}
}, [])
- React.useEffect(() => {
- window.localStorage.setItem('tesseract-theme', theme as string)
- }, [theme])
-
- React.useEffect(() => {
- const stylesheets = Array.from(window.document.querySelectorAll('link[title]')) as HTMLLinkElement[]
- stylesheets.forEach(s => {
- const enabled = s.title === theme
- s.setAttribute('rel', enabled ? 'stylesheet' : 'alternate stylesheet')
- if (enabled) {
- s.removeAttribute('disabled')
- } else {
- s.setAttribute('disabled', 'disabled')
- }
- })
- }, [theme])
-
return (
= ({
-
-
-
- {
- theme === 'Dark'
- && (
-
- )
- }
- {
- theme === 'Light'
- && (
-
- )
- }
-
-
+
(
+ window.matchMedia('(prefers-color-scheme: dark)').matches
+ ? 'Dark'
+ : 'Light'
+)
+
+const getTheme = () => window.localStorage.getItem('tesseract-theme') || getAutoDetectTheme()
+
+const applyStyles = (theme) => {
+ const stylesheets = Array.from(window.document.querySelectorAll('link[title]')) as HTMLLinkElement[]
+ stylesheets.forEach(s => {
+ const enabled = s.title === theme
+ if (enabled) {
+ s.removeAttribute('disabled')
+ } else {
+ s.setAttribute('disabled', 'disabled')
+ }
+ })
+}
+
+const handleInitializeTheme = (initialTheme: string) => () => {
+ applyStyles(getTheme() || initialTheme)
+}
+
+const ThemeToggle = ({
+ initialTheme,
+}) => {
+ const [theme, setTheme] = React.useState(initialTheme!)
+
+ const handleSetTheme = (t: string) => () => {
+ setTheme(t)
+ }
+
+ React.useEffect(() => {
+ window.localStorage.setItem('tesseract-theme', theme as string)
+ }, [theme])
+
+ React.useEffect(() => {
+ applyStyles(theme)
+ }, [theme])
+
+ React.useEffect(() => {
+ const handler = handleInitializeTheme(initialTheme)
+ window.addEventListener('load', handler)
+ return () => {
+ window.removeEventListener('load', handler)
+ }
+ }, [initialTheme])
+
+ return (
+
+
+
+ {
+ theme === 'Dark'
+ && (
+
+ )
+ }
+ {
+ theme === 'Light'
+ && (
+
+ )
+ }
+
+
+ )
+}
+
+export default ThemeToggle
diff --git a/packages/react-common-docs/src/docgen.json b/packages/react-common-docs/src/docgen.json
index f4799ff..842e6b2 100644
--- a/packages/react-common-docs/src/docgen.json
+++ b/packages/react-common-docs/src/docgen.json
@@ -251,7 +251,7 @@
"defaultValue": {
"value": null
},
- "description": "Describe of what the component represents.",
+ "description": "Description of what the component represents.",
"name": "label",
"required": false,
"type": {
diff --git a/packages/react-common-docs/src/pages/_app.tsx b/packages/react-common-docs/src/pages/_app.tsx
index d44e01e..1a2e1d7 100644
--- a/packages/react-common-docs/src/pages/_app.tsx
+++ b/packages/react-common-docs/src/pages/_app.tsx
@@ -1,10 +1,12 @@
import * as React from 'react'
+import { MDXProvider } from '@mdx-js/react'
+import Head from 'next/head'
import styled from 'styled-components'
import sidebar from '../sidebar.json'
import brand from '../../brand'
import Sidebar from '../components/Sidebar/Sidebar'
-import '../../public/global.css'
-import '../../public/theme/dark.css'
+import pkg from '../../../../package.json'
+import CodeBlock from '../components/CodeBlock/CodeBlock'
const Container = styled('div')({
maxWidth: 720,
@@ -27,15 +29,26 @@ const App: React.FC = ({
pageProps,
}) => (
+
+ {pkg['title'] || pkg.name}
+
+
-
+
+
+
diff --git a/packages/react-common-docs/src/pages/_document.tsx b/packages/react-common-docs/src/pages/_document.tsx
index 51d6aff..447a5ce 100644
--- a/packages/react-common-docs/src/pages/_document.tsx
+++ b/packages/react-common-docs/src/pages/_document.tsx
@@ -1,12 +1,14 @@
-import pkg from '../../../../package.json'
import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
+import pkg from '../../../../package.json'
+import config from '../../next.config'
+
+const publicUrl = process.env.NODE_ENV === 'production' ? pkg.homepage : config.basePath
export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
- const publicUrl = process.env.NODE_ENV === 'production' ? pkg.homepage : ''
try {
ctx.renderPage = () =>
diff --git a/packages/react-common-docs/src/pages/components/TextInput.mdx b/packages/react-common-docs/src/pages/components/TextInput.mdx
index f168bc8..28b9bfa 100644
--- a/packages/react-common-docs/src/pages/components/TextInput.mdx
+++ b/packages/react-common-docs/src/pages/components/TextInput.mdx
@@ -38,7 +38,7 @@ act as guide to the user on how long the expected input values are.
components={{ TextInput }}
code={`
`}
/>
@@ -50,6 +50,7 @@ element specified as `grid`. This is to be able to add complementing content to
some content that is best displayed outside the component instead of putting in the `hint` prop.
(
fontSize: SECONDARY_TEXT_SIZES[size!],
}}
>
- ({stringify(hint)})
+ {stringify(hint)}
)}
{!multiple && (
diff --git a/packages/react-common/src/components/TextInput/TextInput.tsx b/packages/react-common/src/components/TextInput/TextInput.tsx
index d0977ff..14bdb50 100644
--- a/packages/react-common/src/components/TextInput/TextInput.tsx
+++ b/packages/react-common/src/components/TextInput/TextInput.tsx
@@ -351,7 +351,7 @@ const TextInput = React.forwardRef
- ({stringify(hint)})
+ {stringify(hint)}
)}
{(indicator as PropTypes.ReactComponentLike) && (