Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Features
- Add `inline` prop in the `Popup` for rendering the content next to the trigger element @mnajdova ([#1017](https://github.com/stardust-ui/react/pull/1017))

<!--------------------------------[ v0.23.0 ]------------------------------- -->
## [v0.23.0](https://github.com/stardust-ui/react/tree/v0.23.0) (2019-03-06)
[Compare changes](https://github.com/stardust-ui/react/compare/v0.22.1...v0.23.0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react'
import { Button, Popup } from '@stardust-ui/react'

const PopupExampleInline = () => (
<Popup
trigger={<Button icon="expand" />}
content="This popup is rendered next to the trigger."
inline
/>
)

export default PopupExampleInline
10 changes: 10 additions & 0 deletions docs/src/examples/components/Popup/Types/PopupExampleInline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from 'react'
import { Button, Popup } from '@stardust-ui/react'

const PopupExampleInline = () => (
<Popup content="This popup is rendered next to the trigger." inline>
<Button icon="expand" />
</Popup>
)

export default PopupExampleInline
5 changes: 5 additions & 0 deletions docs/src/examples/components/Popup/Types/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const Types = () => (
description="By default Popup uses trigger element as the one it is displayed for, but it is possible to provide any DOM element as popup's target."
examplePath="components/Popup/Types/PopupCustomTargetExample"
/>
<ComponentExample
title="Inline"
description="The content of the popup can be rendered next to the trigger element instead of the body."
examplePath="components/Popup/Types/PopupExampleInline"
/>
</ExampleSection>
)

Expand Down
7 changes: 6 additions & 1 deletion packages/react/src/components/Popup/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export interface PopupProps
/** Initial value for 'open'. */
defaultOpen?: boolean

/** Whether the Popup should be rendered inline with the trigger or in the body. */
inline?: boolean

/** Delay in ms for the mouse leave event, before the popup will be closed. */
mouseLeaveDelay?: number

Expand Down Expand Up @@ -147,6 +150,7 @@ export default class Popup extends AutoControlledComponent<ReactProps<PopupProps
align: PropTypes.oneOf(ALIGNMENTS),
defaultOpen: PropTypes.bool,
defaultTarget: PropTypes.any,
inline: PropTypes.bool,
mouseLeaveDelay: PropTypes.number,
on: PropTypes.oneOfType([
PropTypes.oneOf(['hover', 'click', 'focus']),
Expand Down Expand Up @@ -225,6 +229,7 @@ export default class Popup extends AutoControlledComponent<ReactProps<PopupProps
rtl,
accessibility,
}: RenderResultConfig<PopupProps>): React.ReactNode {
const { inline } = this.props
const popupContent = this.renderPopupContent(classes.popup, rtl, accessibility)

return (
Expand All @@ -234,7 +239,7 @@ export default class Popup extends AutoControlledComponent<ReactProps<PopupProps
{this.state.open &&
Popup.isBrowserContext &&
popupContent &&
ReactDOM.createPortal(popupContent, document.body)}
(inline ? popupContent : ReactDOM.createPortal(popupContent, document.body))}
</>
)
}
Expand Down
19 changes: 19 additions & 0 deletions packages/react/test/specs/components/Popup/Popup-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,23 @@ describe('Popup', () => {
document.body.removeChild(attachTo)
})
})

describe('inline', () => {
test('renders the content in the document body the inline prop is not provided', () => {
mountWithProvider(<Popup trigger={<button />} content="Content" open={true} />)
const contentElement = document.body.firstElementChild

expect(contentElement.classList.contains(Popup.Content.className)).toEqual(true)
})

test('renders the content next to the trigger element if the inline prop is provided', () => {
const wrapper = mountWithProvider(
<Popup trigger={<button id={triggerId} />} inline content="Content" open={true} />,
)
const contentElement = wrapper.getDOMNode().nextSibling as HTMLDivElement

expect(wrapper.find(Popup.Content).exists()).toEqual(true)
expect(contentElement.classList.contains(Popup.Content.className)).toEqual(true)
})
})
})