Skip to content

Commit

Permalink
feat(Popup): add pinned and popperModifiers prop (Semantic-Org#3654)
Browse files Browse the repository at this point in the history
* feat(Popup): add pinned and popperModifiers prop

* add on='click'

* fix typings

* fix prop

* remove missing example, disable `keepTogether` with offset, update merge order
  • Loading branch information
layershifter authored and mbakiev committed Jun 17, 2019
1 parent 1aaad2e commit a5508f2
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ const Wrapper = (props) => {
{...rest}
/* eslint-disable-next-line react/prop-types */
sourceCode={sourceCode}
/>
>
{/* eslint-disable-next-line react/prop-types */}
{props.children}
</ComponentExample>
)
}

Expand Down
13 changes: 13 additions & 0 deletions docs/src/examples/modules/Popup/States/PopupExamplePinned.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import { Button, Popup } from 'semantic-ui-react'

const PopupExamplePinned = () => (
<Popup
content='I will not flip!'
on='click'
pinned
trigger={<Button content='Button' />}
/>
)

export default PopupExamplePinned
5 changes: 5 additions & 0 deletions docs/src/examples/modules/Popup/States/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ const PopupStatesExamples = () => (
description='A disabled popup only renders its trigger.'
examplePath='modules/Popup/States/PopupExampleDisabled'
/>
<ComponentExample
title='Pinned'
description='Disables automatic repositioning of the component, it will always be placed according to the position value.'
examplePath='modules/Popup/States/PopupExamplePinned'
/>
</ExampleSection>
)

Expand Down
6 changes: 6 additions & 0 deletions src/modules/Popup/Popup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export interface StrictPopupProps extends StrictPortalProps {
*/
onUnmount?: (nothing: null, data: PopupProps) => void

/** Disables automatic repositioning of the component, it will always be placed according to the position value. */
pinned?: boolean

/** Position for the popover. */
position?:
| 'top left'
Expand All @@ -101,6 +104,9 @@ export interface StrictPopupProps extends StrictPortalProps {
| 'top center'
| 'bottom center'

/** An object containing custom settings for the Popper.js modifiers. */
popperModifiers?: object

/** Popup size. */
size?: 'mini' | 'tiny' | 'small' | 'large' | 'huge'

Expand Down
24 changes: 19 additions & 5 deletions src/modules/Popup/Popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,15 @@ export default class Popup extends Component {
*/
onUnmount: PropTypes.func,

/** Disables automatic repositioning of the component, it will always be placed according to the position value. */
pinned: PropTypes.bool,

/** Position for the popover. */
position: PropTypes.oneOf(positions),

/** An object containing custom settings for the Popper.js modifiers. */
popperModifiers: PropTypes.object,

/** Popup size. */
size: PropTypes.oneOf(_.without(SUI.SIZES, 'medium', 'big', 'massive')),

Expand All @@ -137,6 +143,7 @@ export default class Popup extends Component {
disabled: false,
offset: 0,
on: 'hover',
pinned: false,
position: 'top left',
}

Expand Down Expand Up @@ -285,15 +292,22 @@ export default class Popup extends Component {
}

render() {
const { context, disabled, offset, position, trigger } = this.props
const { context, disabled, offset, pinned, popperModifiers, position, trigger } = this.props
const { closed, portalRestProps } = this.state

if (closed || disabled) return trigger

const modifiers = {
arrow: { enabled: false },
offset: { offset },
}
const modifiers = _.merge(
{
arrow: { enabled: false },
flip: { enabled: !pinned },
// There are issues with `keepTogether` and `offset`
// https://github.com/FezVrasta/popper.js/issues/557
keepTogether: { enabled: !!offset },
offset: { offset },
},
popperModifiers,
)
const referenceElement = createReferenceProxy(_.isNil(context) ? this.triggerRef : context)

const mergedPortalProps = { ...this.getPortalProps(), ...portalRestProps }
Expand Down
43 changes: 42 additions & 1 deletion test/specs/modules/Popup/Popup-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,16 +239,57 @@ describe('Popup', () => {
})
})

describe('pinned', () => {
it(`is "false" by default`, () => {
wrapperMount(<Popup open />)

wrapper.should.have.prop('pinned', false)
})

it(`disables "flip" modifier in PopperJS when is "true"`, () => {
wrapperMount(<Popup open pinned />)

wrapper
.find('Popper')
.should.have.prop('modifiers')
.deep.include({ flip: { enabled: false } })
})

it(`enables "flip" modifier in PopperJS when is "false"`, () => {
wrapperMount(<Popup open pinned={false} />)

wrapper
.find('Popper')
.should.have.prop('modifiers')
.deep.include({ flip: { enabled: true } })
})
})

describe('position', () => {
_.forEach(positionsMapping, (placement, position) => {
it(`passes the "${position}" as "${placement}" to Popper`, () => {
wrapperMount(<Popup open position={position} />)

wrapper.find('Popper').prop('placement', placement)
wrapper.find('Popper').should.have.prop('placement', placement)
})
})
})

describe('popperModifiers', () => {
it(`are passed to Popper`, () => {
const modifiers = {
keepTogether: { enabled: false },
preventOverflow: { padding: 0 },
}
wrapperMount(<Popup popperModifiers={modifiers} open />)

wrapper
.find('Popper')
.should.have.prop('modifiers')
.deep.include(modifiers)
})
})

describe('size', () => {
const sizes = _.without(SUI.SIZES, 'medium', 'big', 'massive')

Expand Down

0 comments on commit a5508f2

Please sign in to comment.