Skip to content

Commit b96e411

Browse files
authored
docs(Ref): restore docs for a component (#4039)
* docs(Ref): restore docs for a component * fix description * add a UT
1 parent bf87dd2 commit b96e411

File tree

9 files changed

+287
-20
lines changed

9 files changed

+287
-20
lines changed

docs/src/components/ComponentDoc/ComponentDoc.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,14 @@ class ComponentDoc extends Component {
7373
subheader={_.join(componentInfo.docblock.description, ' ')}
7474
/>
7575
<ComponentDocSee seeTags={seeTags} />
76-
<ComponentDocLinks
77-
displayName={displayName}
78-
parentDisplayName={componentInfo.parentDisplayName}
79-
repoPath={componentInfo.repoPath}
80-
type={componentInfo.type}
81-
/>
76+
{componentInfo.repoPath && (
77+
<ComponentDocLinks
78+
displayName={displayName}
79+
parentDisplayName={componentInfo.parentDisplayName}
80+
repoPath={componentInfo.repoPath}
81+
type={componentInfo.type}
82+
/>
83+
)}
8284
<ComponentProps componentsInfo={componentsInfo} displayName={displayName} />
8385
</Grid.Column>
8486
</Grid.Row>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React from 'react'
2+
import { Grid, Table, Ref, Segment } from 'semantic-ui-react'
3+
4+
function RefExampleRef() {
5+
const objectRef = React.useRef(null)
6+
const [functionalRef, setFunctionalRef] = React.useState(null)
7+
const [isMounted, setIsMounted] = React.useState(false)
8+
9+
React.useEffect(() => {
10+
setIsMounted(true)
11+
return () => setIsMounted(false)
12+
}, [])
13+
14+
return (
15+
<Grid>
16+
<Grid.Column width={6}>
17+
<Segment.Group>
18+
<Ref innerRef={setFunctionalRef}>
19+
<Segment>An example node with functional ref</Segment>
20+
</Ref>
21+
<Ref innerRef={objectRef}>
22+
<Segment>
23+
An example node with ref via <code>React.useRef()</code>
24+
</Segment>
25+
</Ref>
26+
</Segment.Group>
27+
</Grid.Column>
28+
<Grid.Column width={10}>
29+
{isMounted && (
30+
<Table>
31+
<Table.Header>
32+
<Table.Row>
33+
<Table.HeaderCell>Type</Table.HeaderCell>
34+
<Table.HeaderCell>
35+
<code>nodeName</code>
36+
</Table.HeaderCell>
37+
<Table.HeaderCell>
38+
<code>textContent</code>
39+
</Table.HeaderCell>
40+
</Table.Row>
41+
</Table.Header>
42+
43+
<Table.Body>
44+
<Table.Row>
45+
<Table.Cell singleLine>
46+
Functional ref via <code>React.useState()</code> hook
47+
</Table.Cell>
48+
<Table.Cell>{functionalRef.nodeName}</Table.Cell>
49+
<Table.Cell>{functionalRef.textContent}</Table.Cell>
50+
</Table.Row>
51+
52+
<Table.Row>
53+
<Table.Cell singleLine>
54+
From <code>React.useRef()</code> hook
55+
</Table.Cell>
56+
<Table.Cell>{objectRef.current.nodeName}</Table.Cell>
57+
<Table.Cell>{objectRef.current.textContent}</Table.Cell>
58+
</Table.Row>
59+
</Table.Body>
60+
</Table>
61+
)}
62+
</Grid.Column>
63+
</Grid>
64+
)
65+
}
66+
67+
export default RefExampleRef
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from 'react'
2+
import { Grid, Ref, Segment } from 'semantic-ui-react'
3+
4+
const ExampleButton = React.forwardRef((props, ref) => (
5+
<div>
6+
<button {...props} ref={ref} />
7+
</div>
8+
))
9+
10+
function RefForwardingExample() {
11+
const forwardedRef = React.useRef(null)
12+
const [isMounted, setIsMounted] = React.useState(false)
13+
14+
React.useEffect(() => {
15+
setIsMounted(true)
16+
return () => setIsMounted(false)
17+
}, [])
18+
19+
return (
20+
<Grid columns={2}>
21+
<Grid.Column>
22+
<Segment>
23+
<p>
24+
A button below uses <code>React.forwardRef()</code> API.
25+
</p>
26+
27+
<Ref innerRef={forwardedRef}>
28+
<ExampleButton>A button</ExampleButton>
29+
</Ref>
30+
</Segment>
31+
</Grid.Column>
32+
33+
<Grid.Column>
34+
{isMounted && (
35+
<Segment secondary>
36+
<pre>
37+
{JSON.stringify(
38+
{
39+
nodeName: forwardedRef.current.nodeName,
40+
nodeType: forwardedRef.current.nodeType,
41+
textContent: forwardedRef.current.textContent,
42+
},
43+
null,
44+
2,
45+
)}
46+
</pre>
47+
</Segment>
48+
)}
49+
</Grid.Column>
50+
</Grid>
51+
)
52+
}
53+
54+
export default RefForwardingExample
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react'
2+
3+
import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
4+
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'
5+
6+
const RefTypesExamples = () => (
7+
<ExampleSection title='Types'>
8+
<ComponentExample
9+
title='Ref'
10+
description={
11+
<span>
12+
A component exposes the <code>innerRef</code> prop that always returns
13+
the DOM node of both functional and class component children.
14+
</span>
15+
}
16+
examplePath='addons/Ref/Types/RefExampleRef'
17+
/>
18+
<ComponentExample
19+
title='Forward Ref'
20+
description={
21+
<span>
22+
<code>React.forwardRef()</code> API is also handled by this component.
23+
</span>
24+
}
25+
examplePath='addons/Ref/Types/RefForwardingExample'
26+
/>
27+
</ExampleSection>
28+
)
29+
30+
export default RefTypesExamples
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
import { Message } from 'semantic-ui-react'
3+
4+
import Types from './Types'
5+
6+
const RefExamples = () => (
7+
<>
8+
<Message info>
9+
<p>
10+
Currently, it's recommended to use <code>Ref</code> component to get
11+
refs to HTML elements from Semantic UI React components as not all
12+
components support native ref forwarding via{' '}
13+
<code>React.forwardRef()</code>.
14+
</p>
15+
<p>
16+
As it uses deprecated <code>ReactDOM.findDOMNode()</code> you may
17+
receive warnings in React's StrictMode. We are working on it in{' '}
18+
<a href='https://github.com/Semantic-Org/Semantic-UI-React/issues/3819'>
19+
Semantic-Org/Semantic-UI-React#3819
20+
</a>
21+
.
22+
</p>
23+
</Message>
24+
<Types />
25+
</>
26+
)
27+
28+
export default RefExamples
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
import _ from 'lodash'
12
import componentMenu from '../../src/componentMenu'
23

3-
const getComponentMenu = () => componentMenu
4+
const getComponentMenu = () =>
5+
_.sortBy(
6+
[
7+
...componentMenu,
8+
{
9+
displayName: 'Ref',
10+
type: 'addon',
11+
external: true,
12+
},
13+
],
14+
'displayName',
15+
)
416

517
export default getComponentMenu

src/modules/Popup/lib/createReferenceProxy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isRefObject, toRefObject } from '@fluentui/react-component-ref'
1+
import { isRefObject } from '@fluentui/react-component-ref'
22
import _ from 'lodash'
33

44
class ReferenceProxy {
@@ -31,7 +31,7 @@ class ReferenceProxy {
3131
* @see https://popper.js.org/popper-documentation.html#referenceObject
3232
*/
3333
const createReferenceProxy = _.memoize(
34-
(reference) => new ReferenceProxy(isRefObject(reference) ? reference : toRefObject(reference)),
34+
(reference) => new ReferenceProxy(isRefObject(reference) ? reference : { current: reference }),
3535
)
3636

3737
export default createReferenceProxy

static.routes.js

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,82 @@ export default async () => {
3636
})),
3737

3838
// Routes for components, i.e. /element/button
39-
..._.map(getComponentMenu(), (baseInfo) => ({
40-
path: getComponentPathname(baseInfo),
39+
..._.map(
40+
_.filter(getComponentMenu(), (baseInfo) => !baseInfo.external),
41+
(baseInfo) => ({
42+
path: getComponentPathname(baseInfo),
43+
component: 'docs/src/components/ComponentDoc',
44+
priority: 0.8,
45+
getData: async () => {
46+
const componentsInfo = getComponentGroupInfo(baseInfo.displayName)
47+
const sidebarSections = getSidebarSections(baseInfo.displayName)
48+
49+
return {
50+
componentsInfo,
51+
exampleSources,
52+
sidebarSections,
53+
displayName: baseInfo.displayName,
54+
deprecated: !!_.find(
55+
_.get(componentsInfo[baseInfo.displayName], 'docblock.tags'),
56+
(tag) => tag.title === 'deprecated',
57+
),
58+
seeTags: getInfoForSeeTags(componentsInfo[baseInfo.displayName]),
59+
}
60+
},
61+
}),
62+
),
63+
64+
{
65+
path: `/addons/ref/`,
4166
component: 'docs/src/components/ComponentDoc',
4267
priority: 0.8,
4368
getData: async () => {
44-
const componentsInfo = getComponentGroupInfo(baseInfo.displayName)
45-
const sidebarSections = getSidebarSections(baseInfo.displayName)
69+
const componentsInfo = {
70+
Ref: {
71+
displayName: 'Ref',
72+
props: [
73+
{
74+
description: ['Called when a child component will be mounted or updated.'],
75+
name: 'innerRef',
76+
type: 'func',
77+
required: true,
78+
tags: [
79+
{
80+
title: 'param',
81+
description: 'Referred node.',
82+
type: {
83+
type: 'NameExpression',
84+
name: 'HTMLElement',
85+
},
86+
name: 'node',
87+
},
88+
],
89+
},
90+
],
91+
type: 'addon',
92+
isParent: true,
93+
subcomponents: [],
94+
docblock: {
95+
tags: [],
96+
description: [
97+
'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.',
98+
],
99+
},
100+
examplesExist: true,
101+
},
102+
}
103+
const sidebarSections = getSidebarSections('Ref')
46104

47105
return {
48106
componentsInfo,
49107
exampleSources,
50108
sidebarSections,
51-
displayName: baseInfo.displayName,
52-
deprecated: !!_.find(
53-
_.get(componentsInfo[baseInfo.displayName], 'docblock.tags'),
54-
(tag) => tag.title === 'deprecated',
55-
),
56-
seeTags: getInfoForSeeTags(componentsInfo[baseInfo.displayName]),
109+
displayName: 'Ref',
110+
deprecated: false,
111+
seeTags: [],
57112
}
58113
},
59-
})),
114+
},
60115

61116
// Routes for layouts, i.e. /layouts/theming
62117
..._.map(await getLayoutPaths(), ({ routeName, componentFilename }) => ({
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react'
2+
import createReferenceProxy from 'src/modules/Popup/lib/createReferenceProxy'
3+
4+
describe('createReferenceProxy', () => {
5+
it('handles nodes', () => {
6+
const node = document.createElement('div')
7+
const proxy = createReferenceProxy(node)
8+
9+
expect(proxy.getBoundingClientRect()).to.include({ height: 0, width: 0 })
10+
})
11+
12+
it('handles ref objects', () => {
13+
const ref = React.createRef()
14+
const proxy = createReferenceProxy(ref)
15+
16+
ref.current = document.createElement('div')
17+
expect(proxy.getBoundingClientRect()).to.include({ height: 0, width: 0 })
18+
})
19+
})

0 commit comments

Comments
 (0)