mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-21 07:27:51 +08:00
fix(popover): 🔪 deprecated popover
This commit is contained in:
parent
a95c17bce3
commit
5e7c1ad518
2 changed files with 0 additions and 304 deletions
|
@ -1,222 +0,0 @@
|
|||
React = require 'react'
|
||||
ReactDOM = require 'react-dom'
|
||||
_ = require 'underscore'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
|
||||
###
|
||||
Public: The Popover component makes it easy to display a sheet or popup menu when the
|
||||
user clicks the React element provided as `buttonComponent`. In N1, the Popover
|
||||
component is used to create rich dropdown menus, detail popups, etc. with consistent
|
||||
look and feel and behavior.
|
||||
|
||||
The Popover component handles:
|
||||
|
||||
- Rendering it's children when you click `buttonComponent`, and dismissing it's
|
||||
children when you click outside the popover or press the Escape key.
|
||||
|
||||
- Automatically focusing the item with the lowest tabIndex inside the popover
|
||||
|
||||
## Input Focus
|
||||
|
||||
If your Popover contains an input, like a search bar, give it a tabIndex and
|
||||
Popover will automatically focus it when the popover is opened.
|
||||
|
||||
## Advanced Use
|
||||
|
||||
If you don't want to use the Popover in conjunction with a triggering button,
|
||||
you can manually call `open()` and `close()` to display it. A typical scenario
|
||||
looks like this:
|
||||
|
||||
```coffeescript
|
||||
render: =>
|
||||
<Popover ref="myPopover"> Popover Contents </Popover>
|
||||
|
||||
showMyPopover: =>
|
||||
@refs.myPopover.open()
|
||||
|
||||
```
|
||||
|
||||
Section: Component Kit
|
||||
###
|
||||
class Popover extends React.Component
|
||||
|
||||
###
|
||||
Public: React `props` supported by Popover:
|
||||
|
||||
- `buttonComponent` The React element that will be rendered in place of the
|
||||
Popover and trigger it to appear. This is typically a button or call-to-action for
|
||||
opening the popover. Popover wraps this item in a <div> with an onClick handler.
|
||||
|
||||
- `children` The React elements that should appear when the Popover is opened.
|
||||
They're automatically wrapped in a `<div class="popover">`, which applies standard
|
||||
shadowing and styles.
|
||||
|
||||
- `direction` Defaults to 'up'. You can also pass 'down' to make the Popover float beneath
|
||||
the button component.
|
||||
|
||||
- `pointerStyle` Additional styles to apply to the pointer
|
||||
|
||||
- `popoverStyle` Additional styles to apply to the popover
|
||||
|
||||
Events
|
||||
|
||||
- `onOpened` A {Function} that will be called when the popover is opened.
|
||||
|
||||
###
|
||||
@propTypes =
|
||||
buttonComponent: React.PropTypes.element
|
||||
direction: React.PropTypes.string
|
||||
popoverStyle: React.PropTypes.object
|
||||
pointerStyle: React.PropTypes.object
|
||||
|
||||
@defaultProps =
|
||||
direction: 'up'
|
||||
|
||||
constructor: (@props) ->
|
||||
@state =
|
||||
showing: false
|
||||
offset: 0
|
||||
dimensions: {}
|
||||
|
||||
componentDidMount: =>
|
||||
window.addEventListener("resize", @_resetPositionState)
|
||||
@_resetPositionState()
|
||||
|
||||
componentWillUnmount: =>
|
||||
window.removeEventListener("resize", @_resetPositionState)
|
||||
|
||||
componentDidUpdate: =>
|
||||
if @_focusOnOpen
|
||||
@_focusImportantElement()
|
||||
@_focusOnOpen = false
|
||||
@_resetPositionState()
|
||||
|
||||
open: =>
|
||||
@_focusOnOpen = true
|
||||
@setState
|
||||
showing: true
|
||||
@props.onOpened?()
|
||||
|
||||
close: =>
|
||||
@setState
|
||||
showing: false
|
||||
@props.onClosed?()
|
||||
|
||||
# We need to make sure that we're not rendered off the edge of the
|
||||
# browser window.
|
||||
_resetPositionState: =>
|
||||
return unless @state.showing
|
||||
rect = ReactDOM.findDOMNode(@refs.popover).getBoundingClientRect()
|
||||
dimensions =
|
||||
left: rect.left
|
||||
right: rect.right
|
||||
docWidth: document.body.clientWidth
|
||||
|
||||
return if _.isEqual dimensions, @state.dimensions
|
||||
|
||||
padding = 11.25
|
||||
|
||||
origRight = dimensions.right - @state.offset
|
||||
origLeft = dimensions.left - @state.offset
|
||||
|
||||
offset = Math.min((dimensions.docWidth - padding - origRight), 0) - Math.min(origLeft - padding, 0)
|
||||
@setState {offset, dimensions}
|
||||
|
||||
_focusImportantElement: =>
|
||||
# Automatically focus the element inside us with the lowest tab index
|
||||
node = ReactDOM.findDOMNode(@refs.popover)
|
||||
|
||||
# _.sortBy ranks in ascending numerical order.
|
||||
matches = _.sortBy node.querySelectorAll("[tabIndex], input"), (node) =>
|
||||
if node.tabIndex > 0
|
||||
return node.tabIndex
|
||||
else if node.nodeName is "INPUT"
|
||||
return 1000000
|
||||
else return 1000001
|
||||
matches[0]?.focus()
|
||||
|
||||
render: =>
|
||||
wrappedButtonComponent = []
|
||||
if @props.buttonComponent
|
||||
wrappedButtonComponent = <div onClick={@_onClick}>{@props.buttonComponent}</div>
|
||||
|
||||
popoverComponent = []
|
||||
|
||||
if @state.showing
|
||||
popoverStyle =
|
||||
'position': 'absolute'
|
||||
'left': "calc(50% + #{@state.offset}px)"
|
||||
'zIndex': 40
|
||||
pointerStyle =
|
||||
'position': 'absolute'
|
||||
'marginLeft': '50%'
|
||||
'zoom': 0.5
|
||||
'width': 45
|
||||
'height': 20
|
||||
'zIndex': 40
|
||||
|
||||
if @props.direction is 'up'
|
||||
popoverStyle = _.extend popoverStyle,
|
||||
'transform': 'translate(-50%,-100%)'
|
||||
'top': -10,
|
||||
pointerStyle = _.extend pointerStyle,
|
||||
'transform': 'translateX(-50%)'
|
||||
'bottom': 48
|
||||
|
||||
else if @props.direction is 'down'
|
||||
popoverStyle = _.extend popoverStyle,
|
||||
'transform': 'translate(-50%, 15px)'
|
||||
'top': '100%'
|
||||
pointerStyle = _.extend pointerStyle,
|
||||
'transform': 'rotateX(180deg)'
|
||||
'top': 71
|
||||
'left':-12
|
||||
|
||||
if @props.direction is "down-align-left"
|
||||
popoverStyle = _.extend popoverStyle,
|
||||
'transform': 'translate(0, 2px)'
|
||||
'top': '100%'
|
||||
'left': 0 + @state.offset
|
||||
pointerStyle = _.extend pointerStyle,
|
||||
'transform': 'rotateX(180deg)'
|
||||
'top': 71
|
||||
'display': 'none'
|
||||
|
||||
popoverStyle = _.extend({}, popoverStyle, @props.popoverStyle) if @props.popoverStyle
|
||||
pointerStyle = _.extend({}, pointerStyle, @props.pointerStyle) if @props.pointerStyle
|
||||
|
||||
popoverComponent = (
|
||||
<div ref="popover" className={"popover popover-"+@props.direction} style={popoverStyle}>
|
||||
{@props.children}
|
||||
</div>
|
||||
)
|
||||
|
||||
<div className={"popover-container "+@props.className}
|
||||
onBlur={@_onBlur}
|
||||
onKeyDown={@_onKeyDown}
|
||||
style={(@props.style ? {})} ref="popoverContainer">
|
||||
{wrappedButtonComponent}
|
||||
{popoverComponent}
|
||||
<div className="popover-pointer" style={pointerStyle} />
|
||||
<div className="popover-pointer shadow" style={pointerStyle} />
|
||||
</div>
|
||||
|
||||
_onKeyDown: (event) =>
|
||||
if event.key is "Escape"
|
||||
@close()
|
||||
|
||||
_onClick: (e) =>
|
||||
e.stopPropagation()
|
||||
if not @state.showing
|
||||
@open()
|
||||
else
|
||||
@close()
|
||||
|
||||
_onBlur: (event) =>
|
||||
target = event.nativeEvent.relatedTarget
|
||||
if target? and ReactDOM.findDOMNode(@refs.popoverContainer).contains(target)
|
||||
return
|
||||
@setState
|
||||
showing:false
|
||||
|
||||
module.exports = Popover
|
|
@ -1,82 +0,0 @@
|
|||
@import "ui-variables";
|
||||
@header-color: #afafaf;
|
||||
|
||||
.popover-container {
|
||||
display:inline-block;
|
||||
position:relative;
|
||||
white-space: nowrap; // prevent dropdown arrow from wrapping when space constrained
|
||||
}
|
||||
|
||||
.popover {
|
||||
background-color: @background-secondary;
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: 0 0.5px 0 rgba(0, 0, 0, 0.15), 0 -0.5px 0 rgba(0, 0, 0, 0.15), 0.5px 0 0 rgba(0, 0, 0, 0.15), -0.5px 0 0 rgba(0, 0, 0, 0.15), 0 4px 7px rgba(0,0,0,0.15);
|
||||
|
||||
min-width: 200px;
|
||||
|
||||
.menu {
|
||||
z-index:1;
|
||||
position: relative;
|
||||
.content-container {
|
||||
background: none;
|
||||
}
|
||||
.header-container {
|
||||
border-top-left-radius: @border-radius-base;
|
||||
border-top-right-radius: @border-radius-base;
|
||||
background: none;
|
||||
color: @header-color;
|
||||
font-weight: bold;
|
||||
border-bottom: none;
|
||||
overflow: hidden;
|
||||
padding: @padding-base-vertical * 1.5 @padding-base-horizontal;
|
||||
}
|
||||
.footer-container {
|
||||
border-bottom-left-radius: @border-radius-base;
|
||||
border-bottom-right-radius: @border-radius-base;
|
||||
background: none;
|
||||
|
||||
.item:last-child:hover {
|
||||
border-bottom-left-radius: @border-radius-base;
|
||||
border-bottom-right-radius: @border-radius-base;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
input[type=text] {
|
||||
border: 1px solid darken(@background-secondary, 10%);
|
||||
border-radius: 3px;
|
||||
background-color: @background-primary;
|
||||
box-shadow: inset 0 1px 0 rgba(0,0,0,0.05), 0 1px 0 rgba(0,0,0,0.05);
|
||||
color: @text-color;
|
||||
|
||||
&.search {
|
||||
padding-left: 0;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("../static/images/search/searchloupe@2x.png");
|
||||
background-size: 15px 15px;
|
||||
background-position: 7px 4px;
|
||||
text-indent: 31px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popover-pointer {
|
||||
-webkit-mask-image: url('images/tooltip/tooltip-bg-pointer@2x.png');
|
||||
background-color: @background-secondary;
|
||||
}
|
||||
.popover-pointer.shadow {
|
||||
-webkit-mask-image: url('images/tooltip/tooltip-bg-pointer-shadow@2x.png');
|
||||
background-color: fade(@black, 22%);
|
||||
}
|
||||
|
||||
body.platform-win32 {
|
||||
.popover {
|
||||
border-radius: 0;
|
||||
}
|
||||
.menu {
|
||||
.header-container,
|
||||
.footer-container {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue