Skip to content

Commit

Permalink
docs(Ref): restore docs for a component (#4039)
Browse files Browse the repository at this point in the history
* docs(Ref): restore docs for a component

* fix description

* add a UT
  • Loading branch information
layershifter authored Aug 17, 2020
1 parent bf87dd2 commit b96e411
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 20 deletions.
14 changes: 8 additions & 6 deletions docs/src/components/ComponentDoc/ComponentDoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,14 @@ class ComponentDoc extends Component {
subheader={_.join(componentInfo.docblock.description, ' ')}
/>
<ComponentDocSee seeTags={seeTags} />
<ComponentDocLinks
displayName={displayName}
parentDisplayName={componentInfo.parentDisplayName}
repoPath={componentInfo.repoPath}
type={componentInfo.type}
/>
{componentInfo.repoPath && (
<ComponentDocLinks
displayName={displayName}
parentDisplayName={componentInfo.parentDisplayName}
repoPath={componentInfo.repoPath}
type={componentInfo.type}
/>
)}
<ComponentProps componentsInfo={componentsInfo} displayName={displayName} />
</Grid.Column>
</Grid.Row>
Expand Down
67 changes: 67 additions & 0 deletions docs/src/examples/addons/Ref/Types/RefExampleRef.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react'
import { Grid, Table, Ref, Segment } from 'semantic-ui-react'

function RefExampleRef() {
const objectRef = React.useRef(null)
const [functionalRef, setFunctionalRef] = React.useState(null)
const [isMounted, setIsMounted] = React.useState(false)

React.useEffect(() => {
setIsMounted(true)
return () => setIsMounted(false)
}, [])

return (
<Grid>
<Grid.Column width={6}>
<Segment.Group>
<Ref innerRef={setFunctionalRef}>
<Segment>An example node with functional ref</Segment>
</Ref>
<Ref innerRef={objectRef}>
<Segment>
An example node with ref via <code>React.useRef()</code>
</Segment>
</Ref>
</Segment.Group>
</Grid.Column>
<Grid.Column width={10}>
{isMounted && (
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>
<code>nodeName</code>
</Table.HeaderCell>
<Table.HeaderCell>
<code>textContent</code>
</Table.HeaderCell>
</Table.Row>
</Table.Header>

<Table.Body>
<Table.Row>
<Table.Cell singleLine>
Functional ref via <code>React.useState()</code> hook
</Table.Cell>
<Table.Cell>{functionalRef.nodeName}</Table.Cell>
<Table.Cell>{functionalRef.textContent}</Table.Cell>
</Table.Row>

<Table.Row>
<Table.Cell singleLine>
From <code>React.useRef()</code> hook
</Table.Cell>
<Table.Cell>{objectRef.current.nodeName}</Table.Cell>
<Table.Cell>{objectRef.current.textContent}</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
)}
</Grid.Column>
</Grid>
)
}

export default RefExampleRef
54 changes: 54 additions & 0 deletions docs/src/examples/addons/Ref/Types/RefForwardingExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react'
import { Grid, Ref, Segment } from 'semantic-ui-react'

const ExampleButton = React.forwardRef((props, ref) => (
<div>
<button {...props} ref={ref} />
</div>
))

function RefForwardingExample() {
const forwardedRef = React.useRef(null)
const [isMounted, setIsMounted] = React.useState(false)

React.useEffect(() => {
setIsMounted(true)
return () => setIsMounted(false)
}, [])

return (
<Grid columns={2}>
<Grid.Column>
<Segment>
<p>
A button below uses <code>React.forwardRef()</code> API.
</p>

<Ref innerRef={forwardedRef}>
<ExampleButton>A button</ExampleButton>
</Ref>
</Segment>
</Grid.Column>

<Grid.Column>
{isMounted && (
<Segment secondary>
<pre>
{JSON.stringify(
{
nodeName: forwardedRef.current.nodeName,
nodeType: forwardedRef.current.nodeType,
textContent: forwardedRef.current.textContent,
},
null,
2,
)}
</pre>
</Segment>
)}
</Grid.Column>
</Grid>
)
}

export default RefForwardingExample
30 changes: 30 additions & 0 deletions docs/src/examples/addons/Ref/Types/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'

import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'

const RefTypesExamples = () => (
<ExampleSection title='Types'>
<ComponentExample
title='Ref'
description={
<span>
A component exposes the <code>innerRef</code> prop that always returns
the DOM node of both functional and class component children.
</span>
}
examplePath='addons/Ref/Types/RefExampleRef'
/>
<ComponentExample
title='Forward Ref'
description={
<span>
<code>React.forwardRef()</code> API is also handled by this component.
</span>
}
examplePath='addons/Ref/Types/RefForwardingExample'
/>
</ExampleSection>
)

export default RefTypesExamples
28 changes: 28 additions & 0 deletions docs/src/examples/addons/Ref/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'
import { Message } from 'semantic-ui-react'

import Types from './Types'

const RefExamples = () => (
<>
<Message info>
<p>
Currently, it's recommended to use <code>Ref</code> component to get
refs to HTML elements from Semantic UI React components as not all
components support native ref forwarding via{' '}
<code>React.forwardRef()</code>.
</p>
<p>
As it uses deprecated <code>ReactDOM.findDOMNode()</code> you may
receive warnings in React's StrictMode. We are working on it in{' '}
<a href='https://github.com/Semantic-Org/Semantic-UI-React/issues/3819'>
Semantic-Org/Semantic-UI-React#3819
</a>
.
</p>
</Message>
<Types />
</>
)

export default RefExamples
14 changes: 13 additions & 1 deletion docs/static/utils/getComponentMenu.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import _ from 'lodash'
import componentMenu from '../../src/componentMenu'

const getComponentMenu = () => componentMenu
const getComponentMenu = () =>
_.sortBy(
[
...componentMenu,
{
displayName: 'Ref',
type: 'addon',
external: true,
},
],
'displayName',
)

export default getComponentMenu
4 changes: 2 additions & 2 deletions src/modules/Popup/lib/createReferenceProxy.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isRefObject, toRefObject } from '@fluentui/react-component-ref'
import { isRefObject } from '@fluentui/react-component-ref'
import _ from 'lodash'

class ReferenceProxy {
Expand Down Expand Up @@ -31,7 +31,7 @@ class ReferenceProxy {
* @see https://popper.js.org/popper-documentation.html#referenceObject
*/
const createReferenceProxy = _.memoize(
(reference) => new ReferenceProxy(isRefObject(reference) ? reference : toRefObject(reference)),
(reference) => new ReferenceProxy(isRefObject(reference) ? reference : { current: reference }),
)

export default createReferenceProxy
77 changes: 66 additions & 11 deletions static.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,82 @@ export default async () => {
})),

// Routes for components, i.e. /element/button
..._.map(getComponentMenu(), (baseInfo) => ({
path: getComponentPathname(baseInfo),
..._.map(
_.filter(getComponentMenu(), (baseInfo) => !baseInfo.external),
(baseInfo) => ({
path: getComponentPathname(baseInfo),
component: 'docs/src/components/ComponentDoc',
priority: 0.8,
getData: async () => {
const componentsInfo = getComponentGroupInfo(baseInfo.displayName)
const sidebarSections = getSidebarSections(baseInfo.displayName)

return {
componentsInfo,
exampleSources,
sidebarSections,
displayName: baseInfo.displayName,
deprecated: !!_.find(
_.get(componentsInfo[baseInfo.displayName], 'docblock.tags'),
(tag) => tag.title === 'deprecated',
),
seeTags: getInfoForSeeTags(componentsInfo[baseInfo.displayName]),
}
},
}),
),

{
path: `/addons/ref/`,
component: 'docs/src/components/ComponentDoc',
priority: 0.8,
getData: async () => {
const componentsInfo = getComponentGroupInfo(baseInfo.displayName)
const sidebarSections = getSidebarSections(baseInfo.displayName)
const componentsInfo = {
Ref: {
displayName: 'Ref',
props: [
{
description: ['Called when a child component will be mounted or updated.'],
name: 'innerRef',
type: 'func',
required: true,
tags: [
{
title: 'param',
description: 'Referred node.',
type: {
type: 'NameExpression',
name: 'HTMLElement',
},
name: 'node',
},
],
},
],
type: 'addon',
isParent: true,
subcomponents: [],
docblock: {
tags: [],
description: [
'This component exposes the `innerRef` prop that supports functional and React.createRef()/React.useRef() API and returns the DOM node of both functional and class component children.',
],
},
examplesExist: true,
},
}
const sidebarSections = getSidebarSections('Ref')

return {
componentsInfo,
exampleSources,
sidebarSections,
displayName: baseInfo.displayName,
deprecated: !!_.find(
_.get(componentsInfo[baseInfo.displayName], 'docblock.tags'),
(tag) => tag.title === 'deprecated',
),
seeTags: getInfoForSeeTags(componentsInfo[baseInfo.displayName]),
displayName: 'Ref',
deprecated: false,
seeTags: [],
}
},
})),
},

// Routes for layouts, i.e. /layouts/theming
..._.map(await getLayoutPaths(), ({ routeName, componentFilename }) => ({
Expand Down
19 changes: 19 additions & 0 deletions test/specs/modules/Popup/lib/createReferenceProxy-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import createReferenceProxy from 'src/modules/Popup/lib/createReferenceProxy'

describe('createReferenceProxy', () => {
it('handles nodes', () => {
const node = document.createElement('div')
const proxy = createReferenceProxy(node)

expect(proxy.getBoundingClientRect()).to.include({ height: 0, width: 0 })
})

it('handles ref objects', () => {
const ref = React.createRef()
const proxy = createReferenceProxy(ref)

ref.current = document.createElement('div')
expect(proxy.getBoundingClientRect()).to.include({ height: 0, width: 0 })
})
})

0 comments on commit b96e411

Please # to comment.