4

I have a styled component like such:

import styled from 'styled-components';
const TagIcon = styled(Icon).attrs({
  name: 'tag',
})`
  cursor: pointer;
  font-size: 14px !important;
`

If I use this in a semantic-ui-react layout, it works fine in most cases. However, if I use it as a trigger for a SUI Popup component, it causes a crash:

<Popup content="Test Popup" trigger={<TagIcon />} />
Load Page = ... Unhandled Rejection (TypeError): Cannot read property 'left' of undefined
getBoundingClientRect
src/utils/getBoundingClientRect.js:38
  35 | catch(e){}
  36 | 
  37 | const result = {
> 38 |   left: rect.left,
     | ^  39 |   top: rect.top,
  40 |   width: rect.right - rect.left,
  41 |   height: rect.bottom - rect.top,
...
Popper.update$$1
src/index.js:94
  91 | // We can't use class properties because they don't get listed in the
  92 | // class prototype and break stuff like Sinon stubs
  93 | update() {
> 94 |   return update.call(this);
     | ^  95 | }
  96 | destroy() {
  97 |   return destroy.call(this);

If I replace the "TagIcon" styled component with an equivalent(ish) component, it works fine:

<Popup content="Test Popup" trigger={<Icon name="tag">} />

Anyone come across this and have a solution? I'm not sure which git project to report this in if it's an issue, because it seems that there's probably just a conflict with how things are done under the hood between styled components and semantic-ui-react (or possibly also semantic-ui).

reactive-core
  • 1,071
  • 1
  • 7
  • 15
  • Where do you set the variable rect that you use in result (rect.left, rect.top, etc). The error message "Cannot read property 'left' of undefined" indicates that rect is undefined, which is why it is crashing. – peteredhead Jan 12 '20 at 18:18
  • @peteredhead it's not in my code. That is in the Popper and semantic-ui-react code. From what I can tell, the variable rect is supposed to be set to the bounds of the popup window or maybe the parent window, not sure. It calls getBoundingClientRect which handles this, but returns a null rect. It gets fuzzy above that. – reactive-core Jan 13 '20 at 19:09
  • did you found a fix for this I'm experiencing the same issue with Semantic UI and popup, might this be caused because of styling the component with style components? – jayM Jan 31 '20 at 02:10
  • @jayM Unfortunately I didn't. It does appear to be related to using styled components, so you can get around it by not using them for the popup. I ended up creating my own popup anyway, because I needed more variation in the layout. – reactive-core Feb 01 '20 at 04:13
  • @jayM I have posted a fix below that offers two different solutions – Cameron Apr 14 '20 at 18:00

2 Answers2

3

Updated: Option 1

An alternative solution that is probably the simplest fix here is to wrap your trigger element with a plain HTML tag and add a ref to that to use as a context for the Popup, like so:

import React, { createRef } from 'react';
import { Button, Popup } from 'semantic-ui-react';

const StyledButton = styled(Button)`
  color: purple;
`

class PopupUser extends React.Component {
  contextRef = createRef()

  render() {
    return <Popup
          trigger={<span ref={this.contextRef}>
            <StyledButton content='Trigger Popup' />
            </span>}
          context={this.contextRef}
          content='Hello'
          position='top center'
        />;
  }
}

Note: This may not always be an option, depending on the trigger you are using, but should work for most use cases - be sure to swap a span for a div if wrapping block elements.


Option 2

Similar to Patrick's answer, you will need to wrap the trigger component for it to function properly within a Semantic UI Popup.

If you are planning on using the Semantic UI Icon component, you would wrap it like so:

const Icon = forwardRef(
    ({className, name, ...props}, ref) =>
        <i
            aria-hidden="true"
            className={`${name} icon ${className}`}
            {...props}
            ref={ref}
        />

);

And again, after that just use it normally:

const TagIcon = styled(Icon)`
  width: 40px;
`

} />

Note: I tried to wrap the Icon component directly instead of recreating a small version of the component, but it didn't play nicely.

Cameron
  • 1,524
  • 11
  • 21
  • GitHub issue related to this error message: https://github.com/Semantic-Org/Semantic-UI-React/issues/3896 – Cameron Apr 08 '20 at 17:39
2

I had the same problem and debuged it for a few hours, after finally discovering that its actually simple to solve! The problem is that for some reason popper.js is not receiving the DOM ref to calculate the left/top/width/height, so you need to pass it down "manually" using forwardRef and ref, example:

// Your Icon component 
const Icon = forwardRef(
  (props, ref) => (
    <img
      src={props.url}
      ref={ref}
    />
  )
);

After that just use it normally:

const TagIcon = styled(Icon)`
  width: 40px;
`

<Popup content="Test Popup" trigger={<TagIcon url="https://test-image.com">} />

I hope it helps someone!