Explorar o código

Fix dropdown tip issue when list has scroll

If the searchable dropdown has a scroll the tip shapes appears as a
diamond. Switched to SVG to represent the tip as a triangle instead and
disable switching its background to the primary blue color if a scroll
is present.
Sergiu Miclea %!s(int64=8) %!d(string=hai) anos
pai
achega
a934bd2d3c

+ 23 - 0
src/components/molecules/AutocompleteDropdown/images/tip.js

@@ -0,0 +1,23 @@
+const image = `<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
+    <title>Combined Shape</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Coriolis" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Project/Add-Member/Existing" transform="translate(-262.000000, -337.000000)">
+            <g id="Dropdown-List-Copy" transform="translate(33.000000, 337.000000)">
+                <g id="Group" transform="translate(229.000000, 0.000000)">
+                    <g id="Combined-Shape">
+                        <g>
+                            <path id="path" d="M8,0.707106781 L0.707106781,8 L8,15.2928932 L15.2928932,8 L8,0.707106781 Z" stroke="#A4AAB5" fill="#FFFFFF"></path>
+                            <rect id="Rectangle" stroke="white" fill="white" x="0.5" y="8.5" width="15" height="7"></rect>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>`
+
+export default image

+ 33 - 10
src/components/molecules/AutocompleteDropdown/index.jsx

@@ -25,6 +25,8 @@ import Palette from '../../styleUtils/Palette'
 import DomUtils from '../../../utils/DomUtils'
 import StyleProps from '../../styleUtils/StyleProps'
 
+import tipImage from './images/tip'
+
 const getWidth = props => {
   if (props.width) {
     return props.width - 2
@@ -55,18 +57,19 @@ const ListItems = styled.div`
 `
 const Tip = styled.div`
   position: absolute;
-  width: 10px;
-  height: 10px;
-  background: ${props => props.primary ? Palette.primary : 'white'};
-  border-top: 1px solid ${Palette.grayscale[3]};
-  border-left: 1px solid ${Palette.grayscale[3]};
-  border-bottom: 1px solid ${props => props.primary ? Palette.primary : 'white'};
-  border-right: 1px solid ${props => props.primary ? Palette.primary : 'white'};
-  transform: rotate(45deg);
+  width: 16px;
+  height: 8px;
   right: 8px;
-  top: -6px;
+  top: -8px;
   z-index: 11;
   transition: all ${StyleProps.animations.swift};
+  overflow: hidden;
+  svg {
+    #path {
+      transition: all ${StyleProps.animations.swift};
+      fill: ${props => props.primary ? Palette.primary : 'white'};
+    }
+  }
 `
 const SearchNotFound = styled.div`
   padding: 8px;
@@ -135,6 +138,7 @@ class AutocompleteDropdown extends React.Component<Props, State> {
   listRef: HTMLElement
   listItemsRef: HTMLElement
   tipRef: HTMLElement
+  firstItemRef: HTMLElement
   scrollableParent: HTMLElement
   buttonRect: ClientRect
   itemMouseDown: boolean
@@ -338,6 +342,20 @@ class AutocompleteDropdown extends React.Component<Props, State> {
 
     if (this.listItemsRef) {
       this.listItemsRef.style.maxHeight = `${listHeight}px`
+      if (this.tipRef && this.firstItemRef) {
+        let svgPath = this.tipRef.querySelector('#path')
+        if (svgPath) {
+          if (this.listItemsRef.clientHeight < this.listItemsRef.scrollHeight) {
+            // $FlowIssue
+            svgPath.style.fill = 'white'
+            this.firstItemRef.style.borderTopRightRadius = '0'
+          } else {
+            // $FlowIssue
+            svgPath.style.fill = ''
+            this.firstItemRef.style.borderTopRightRadius = ''
+          }
+        }
+      }
     }
   }
 
@@ -366,6 +384,7 @@ class AutocompleteDropdown extends React.Component<Props, State> {
           let listItem = (
             <ListItem
               key={value}
+              innerRef={ref => { if (i === 0) { this.firstItemRef = ref } }}
               onMouseDown={() => { this.itemMouseDown = true }}
               onMouseUp={() => { this.itemMouseDown = false }}
               onMouseEnter={() => { this.handleItemMouseEnter(i) }}
@@ -411,7 +430,11 @@ class AutocompleteDropdown extends React.Component<Props, State> {
 
     let list = ReactDOM.createPortal((
       <List {...this.props} innerRef={ref => { this.listRef = ref }}>
-        <Tip innerRef={ref => { this.tipRef = ref }} primary={this.state.firstItemHover || isFirstItemSelected} />
+        <Tip
+          innerRef={ref => { this.tipRef = ref }}
+          primary={this.state.firstItemHover || isFirstItemSelected}
+          dangerouslySetInnerHTML={{ __html: tipImage }}
+        />
         {this.renderItems()}
         {this.renderSearchNotFound()}
       </List>

+ 28 - 5
src/components/molecules/AutocompleteDropdown/story.jsx

@@ -25,7 +25,7 @@ const generateItem = (item: string, value?: string) => {
   }
 }
 
-const items = [
+const itemsLong = [
   generateItem('Item 1'),
   generateItem('Item 2'),
   generateItem('Item 3'),
@@ -35,13 +35,33 @@ const items = [
   generateItem('Item 7'),
   generateItem('Item 8'),
   generateItem('Item 8', 'item_8_2'),
+  generateItem('Item 9'),
+  generateItem('Item 10'),
+  generateItem('Item 11'),
+  generateItem('Item 12'),
+  generateItem('Item 13'),
+  generateItem('Item 14'),
+  generateItem('Item 15'),
+  generateItem('Item 16'),
+  generateItem('Item 17'),
+  generateItem('Item 18'),
+  generateItem('Item 19'),
+  generateItem('Item 20'),
+]
+
+const itemsShort = [
+  generateItem('Item 1'),
+  generateItem('Item 2'),
+  generateItem('Item 3'),
 ]
 
 type State = {
   selectedItem: string,
 }
-
-class Wrapper extends React.Component<{}, State> {
+type Props = {
+  items: { value: string, label: string }[],
+}
+class Wrapper extends React.Component<Props, State> {
   state = {
     selectedItem: '',
   }
@@ -49,7 +69,7 @@ class Wrapper extends React.Component<{}, State> {
   render() {
     return (
       <AutocompleteDropdown
-        items={items}
+        items={this.props.items}
         selectedItem={this.state.selectedItem}
         onChange={selectedItem => { this.setState({ selectedItem }) }}
         onInputChange={(value, filteredItems) => {
@@ -64,5 +84,8 @@ class Wrapper extends React.Component<{}, State> {
 
 storiesOf('AutocompleteDropdown', module)
   .add('default', () => (
-    <Wrapper />
+    <Wrapper items={itemsLong} />
+  ))
+  .add('short list', () => (
+    <Wrapper items={itemsShort} />
   ))