Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit 71d8f99

Browse files
authored
feat(Popup): add 'offset' prop (#606)
* introduce offset prop * correct description of supported values * update changelog
1 parent bf9d3e2 commit 71d8f99

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
4949
- Export `call-recording` SVG icon @Bugaa92 ([#585](https://github.com/stardust-ui/react/pull/585))
5050
- Export `canvas-add-page` SVG icon @priyankar205 ([#601](https://github.com/stardust-ui/react/pull/601))
5151
- Add `sizeModifier` variable (with `x` and `xx` values) to `Icon`'s Teams theme styles @priyankar205 ([#601](https://github.com/stardust-ui/react/pull/601))
52+
- Add `offset` prop to `Popup` to extend set of popup positioning options @kuzhelov ([#606](https://github.com/stardust-ui/react/pull/606))
5253

5354
### Documentation
5455
- Add `prettier` support throughout the docs @levithomason ([#568](https://github.com/stardust-ui/react/pull/568))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react'
2+
import { Button, Grid, Popup, Alignment, Position } from '@stardust-ui/react'
3+
4+
const renderButton = rotateArrowUp => (
5+
<Button
6+
icon={{
7+
name: 'arrow circle up',
8+
styles: { transform: `rotate(${rotateArrowUp})` },
9+
}}
10+
styles={{ height: '80px', minWidth: '80px', padding: 0 }}
11+
/>
12+
)
13+
14+
const triggers = [
15+
{ position: 'above', align: 'start', offset: '-100%p', rotateArrowUp: '-45deg' },
16+
{ position: 'above', align: 'end', offset: '100%p', rotateArrowUp: '45deg' },
17+
{ position: 'below', align: 'start', offset: '-100%p', rotateArrowUp: '-135deg' },
18+
{ position: 'below', align: 'end', offset: '100%p', rotateArrowUp: '135deg' },
19+
]
20+
21+
const PopupExamplePosition = () => (
22+
<Grid columns="repeat(2, 80px)" variables={{ padding: '30px', gridGap: '30px' }}>
23+
{triggers.map(({ position, align, offset, rotateArrowUp }) => (
24+
<Popup
25+
align={align as Alignment}
26+
position={position as Position}
27+
offset={offset}
28+
trigger={renderButton(rotateArrowUp)}
29+
content={{
30+
content: (
31+
<p>
32+
The popup is rendered at {position}-{align}
33+
<br />
34+
corner of the trigger.
35+
</p>
36+
),
37+
}}
38+
key={`${position}-${align}`}
39+
/>
40+
))}
41+
</Grid>
42+
)
43+
44+
export default PopupExamplePosition

docs/src/examples/components/Popup/Variations/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ const Variations = () => (
1010
description="A popup can be positioned around its trigger and aligned relative to the trigger's margins. Click on a button to open a popup on a specific position and alignment."
1111
examplePath="components/Popup/Variations/PopupExamplePosition"
1212
/>
13+
<ComponentExample
14+
title="Offset"
15+
description="Popup position could be further customized by providing offset value. Note that percentage values of both trigger and popup elements' lengths are supported."
16+
examplePath="components/Popup/Variations/PopupExampleOffset"
17+
/>
1318
</ExampleSection>
1419
)
1520

src/components/Popup/Popup.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ export interface PopupProps
5454
/** Initial value for 'open'. */
5555
defaultOpen?: boolean
5656

57+
/** Offset value to apply to rendered popup. Accepts the following units:
58+
* - px or unit-less, interpreted as pixels
59+
* - %, percentage relative to the length of the trigger element
60+
* - %p, percentage relative to the length of the popup element
61+
* - vw, CSS viewport width unit
62+
* - vh, CSS viewport height unit
63+
*/
64+
offset?: string
65+
5766
/** Defines whether popup is displayed. */
5867
open?: boolean
5968

@@ -245,17 +254,23 @@ export default class Popup extends AutoControlledComponent<Extendable<PopupProps
245254
rtl: boolean,
246255
accessibility: AccessibilityBehavior,
247256
): JSX.Element {
248-
const { align, position } = this.props
257+
const { align, position, offset } = this.props
249258
const { target } = this.state
250259

251260
const placement = computePopupPlacement({ align, position, rtl })
252261

262+
const popperModifiers = {
263+
// https://popper.js.org/popper-documentation.html#modifiers..offset
264+
...(offset && { offset: { offset: this.applyRtlToOffset(offset, rtl, position) } }),
265+
}
266+
253267
return (
254268
target && (
255269
<Popper
256270
placement={placement}
257271
referenceElement={target}
258272
children={this.renderPopperChildren.bind(this, popupPositionClasses, rtl, accessibility)}
273+
modifiers={popperModifiers}
259274
/>
260275
)
261276
)
@@ -316,4 +331,14 @@ export default class Popup extends AutoControlledComponent<Extendable<PopupProps
316331
_.invoke(this.props, 'onOpenChange', eventArgs, { ...this.props, ...{ open: newValue } })
317332
}
318333
}
334+
335+
private applyRtlToOffset(offset: string, rtl: boolean, position: Position): string {
336+
if (rtl && (position === 'above' || position === 'below')) {
337+
return offset.trimLeft().startsWith('-')
338+
? offset.trimLeft().replace(/^-\s*/, '')
339+
: `-${offset}`
340+
}
341+
342+
return offset
343+
}
319344
}

0 commit comments

Comments
 (0)