Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Dropdown): use item instead of as={Menu.Item} #659

Merged
merged 1 commit into from
Jan 24, 2017

Conversation

levithomason
Copy link
Member

@levithomason levithomason commented Oct 11, 2016

Update

Augmenting the Dropdown with a Menu.Item is no longer supported. Instead, use the item prop when using a Dropdown as a menu item. See the changes in this PR for more:

Before

<Dropdown as={Menu.Item} />

After

<Dropdown item />

Original Post

Per #628 (comment), this PR checks for this._dropdown.blur() before calling it. When augmented, the ref may be a composite component ref instead of an actual DOM node. Otherwise, we sometimes get: Uncaught TypeError: a._dropdown.blur is not a function.

@codecov-io
Copy link

codecov-io commented Oct 11, 2016

Current coverage is 95.84% (diff: 100%)

Merging #659 into master will decrease coverage by 0.04%

@@             master       #659   diff @@
==========================================
  Files           879        879          
  Lines          4889       4889          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
- Hits           4688       4686     -2   
- Misses          201        203     +2   
  Partials          0          0          

Powered by Codecov. Last update d8045cf...2cab8ba

@levithomason
Copy link
Member Author

Though this stops the error, we still have the bug where clicking an item closes the menu, but then switching tabs and switching back opens the dropdown again. This is because it still has focus.

This PR should be updated to actually blur the composite component use case.

@eXtreme
Copy link

eXtreme commented Oct 12, 2016

@levithomason
BTW. I discovered that it is better to do <Menu.Item as={Dropdown}> instead of <Dropdown as={Menu.Item}> - it does not trigger the error and also generates a correct markup: the first one makes <div> for menu.item with dropdown items as <a>) while the latter makes <a> for menu.item causing nesting of <a> (of dropdown.item) inside <a> of menu.item/dropdown.

@levithomason levithomason mentioned this pull request Oct 13, 2016
@tomitrescak
Copy link
Contributor

tomitrescak commented Oct 13, 2016

@eXtreme would you care to provide a full example? I tried several variants of using menu.item with dropdown but no luck

@eXtreme
Copy link

eXtreme commented Oct 13, 2016

@tomitrescak

<Menu>
    <Menu.Item>
        Foo
    </Menu.Item>
    <Menu.Item as={Dropdown} text="Imma dropdown">
        <Dropdown.Menu>
            <Dropdown.Item>Foo</Dropdown.Item>
            <Dropdown.Item>Bar</Dropdown.Item>
            <Dropdown.Divider />
            <Dropdown.Item>Baz</Dropdown.Item>
        </Dropdown.Menu>
    </Menu.Item>
</Menu>

Also works with custom trigger={<span>bar</span>}

@Chris-R3
Copy link
Contributor

Chris-R3 commented Oct 13, 2016

How about impementing a blur() method on Menu.Item?
Or do you have any suggestions/ideas on how to approach this issue @levithomason?

@levithomason
Copy link
Member Author

We'll mostly likely do away with using augmentation for this use case. The Dropdown can play the role of a MenuItem or Button, but augmentation is not the right tool for the job. See here: #642.

@levithomason
Copy link
Member Author

Note #659 (comment), this PR is invalid as it circumvents the error by simply removing the feature. It not longer blurs when augmenting a functional component. It needs to be updated to blur in all cases.

@giacomorebonato
Copy link

I am trying to guess what the code should do here...
If I replace

_this._dropdown.onBlur();

with

_this._dropdown.props.onBlur()

It isn't what you expect right?

@levithomason
Copy link
Member Author

levithomason commented Oct 26, 2016

No, blur() doesn't exist at all. The reason is that a ref returns a DOM Node. The DOM Node interface has a blur() method, but a React ref does not work for functional components so there is no DOM Node to call blur on. Moreover, a ref on a composite component does not return a DOM Node either, it returns a reference to the underlying component instance.

So, there are 3 possible returns values from the ref this._dropdown, a DOM Node, null, and a function. The current code only handles the DOM Node case. It blindly fails for the null and function cases.

The real hang up here on this is the null case, which is what a stateless functional component will return. We need to blur the Node for the Dropdown to work right, but without a working ref there is no way to do that. So, we're gonna have to do some component wrapping gymnastics to get that to work.

@Maxhodges
Copy link

bump any big reason why this can't be merged? I have a production app which is suffering

@eXtreme
Copy link

eXtreme commented Dec 13, 2016

@Maxhodges have you tried my "workaround" from this comment?

@Maxhodges
Copy link

ah yes, that worked for me. just nicer if I didn't have to workaround ;)
cheers! @eXtreme

@levithomason
Copy link
Member Author

@Maxhodges refer to the comments I've made above for why this isn't yet merged.

@levithomason
Copy link
Member Author

There is a larger issue here that needs solved. We need a consistent and portable way to deal with refs on stateless functional components. The same solution for this issue will solve #1012.

anhpha added a commit to anhpha/Semantic-UI-React that referenced this pull request Dec 27, 2016
@raptoria
Copy link

@eXtreme tried your workaround..but Menu.Item doesn't take a text attribute anymore, it seems. Any work around so that I can see a bit of text associated with the dropdown?

@eXtreme
Copy link

eXtreme commented Jan 13, 2017

@raptoria How is that not working for you? I've tried changing an example on http://react.semantic-ui.com/collections/menu and it works fine with text property.

image

From what I understand, it's RSui's augmentation, which makes the "text" property being actually passed to Dropdown component, as you may see from inspecting with react devtools:

image

"t" is actually the "Dropdown" component, which takes "text" property.

The resulting DOM is almost the same as in original SUI (in RSui it has ui item dropdown classname, while in SUI it is ui dropdown item) but the effect is the same.

Can you provide an example of this workaround not working?

@raptoria
Copy link

raptoria commented Jan 17, 2017

@eXtreme I should clarify. Your workaround works, it just gives me a TypeScript error. I'm a TypeScript n00b so I'm not really sure how to fix it. I guess the problem has to do with the text attribute not being explicitly defined in MenuItem.

ERROR in ./src/components/FileMenu/FileMenu.tsx
(18,32): error TS2339: Property 'text' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<MenuItemProps, ComponentState>> & { chil...'.

this is the code my React component is returning:

      <Menu inverted className={styles.fileMenu}>
      <Menu.Item as={Dropdown} text='File'>
          <Dropdown.Menu className={styles.dropdownMenu}>
            <Dropdown.Item icon='file outline icon' text='New Order Entry' />
            <Dropdown.Item icon='shopping basket icon' text='New Basket' />
            <Dropdown.Item icon='download icon' text='Load Portfolio' />
            <Dropdown.Item icon='file excel outline icon' text='Export to Excel' />
            <Dropdown.Item icon='sign out icon' text='Quit Application' />
          </Dropdown.Menu>
        </Menu.Item>
        <Menu.Item name='Edit'> Edit &nbsp;<Icon name='caret down icon' /></Menu.Item>
        <Menu.Item name='Tools'> Tools &nbsp;<Icon name='caret down icon' /></Menu.Item>
        <Menu.Item name='Views'> Views &nbsp;<Icon name='caret down icon' /></Menu.Item>
      </Menu>

any ideas on how to get rid of the error?

Thanks!!

@levithomason
Copy link
Member Author

@raptoria, and others who come here looking for a solution, it is most likely that using augmentation (the as prop) will not be the recommended solution for this case. A more appropriate workaround, for now, is to simply add className='item' to the Dropdown so it is formatted properly within the Menu.

<Menu attached='top'>
  <Dropdown className='item' icon='wrench' />
</Menu>

This prevents Uncaught TypeError: a._dropdown.blur is not a function since the Dropdown is not attempting to render as a stateless component but remains a class component.

@raptoria
Copy link

@levithomason thanks! it works perfectly now.

@levithomason levithomason mentioned this pull request Jan 21, 2017
@levithomason levithomason changed the title fix(Dropdown): check for blur() before calling it fix(Dropdown): replace as={Menu.Item} usage with item prop Jan 24, 2017
@levithomason levithomason changed the title fix(Dropdown): replace as={Menu.Item} usage with item prop fix(Dropdown): use item instead of as={Menu.Item} Jan 24, 2017
@levithomason levithomason merged commit 10dc982 into master Jan 24, 2017
@levithomason levithomason deleted the fix/dropdown-blur branch January 24, 2017 01:41
@levithomason
Copy link
Member Author

Released in semantic-ui-react@0.64.4.

DomiR added a commit to DomiR/Semantic-UI-React that referenced this pull request Jan 26, 2017
* Semantic-Org/master: (111 commits)
  fix(docs): fix usage of arrow function (Semantic-Org#1228)
  fix(Icon): Incorrect definition in typings (Semantic-Org#1225)
  fix(Button): fix `tabIndex` in typings (Semantic-Org#1224)
  fix(typings): add item prop to the DropdownProps (Semantic-Org#1223)
  docs(examples): add missing `key` props (Semantic-Org#1220)
  docs(changelog): update changelog [ci skip]
  0.64.4
  feat(Form): add `inverted` prop (Semantic-Org#1218)
  fix(ComponentExample): use explicit babel presets (Semantic-Org#1219)
  style(Button): update typings and propTypes usage (Semantic-Org#1216)
  style(Embed): update typings and propTypes usage (Semantic-Org#1217)
  chore(package): support for jsnext:main (Semantic-Org#1210)
  style(Step): update typings, tests and propTypes usage (Semantic-Org#1203)
  fix(Portal): do not take focus after first render (Semantic-Org#1215)
  style(Table|mixed): update typings, tests and propTypes usage (Semantic-Org#1200)
  fix(Dropdown): use `item` instead of `as={Menu.Item}` (Semantic-Org#659)
  fix(Dropdown): respect `closeOnBlur={false}` (Semantic-Org#1148)
  style(Breadcrumb): update typings and propTypes usage (Semantic-Org#1209)
  style(Dimmer): update typings (Semantic-Org#1208)
  fix(Divider|FormInput): fix the broken typings (Semantic-Org#1179)
  ...
harel pushed a commit to harel/Semantic-UI-React that referenced this pull request Feb 18, 2017
fix(Dropdown): use `item` instead of `as={Menu.Item}`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants