Skip to content

EuiCodeBlock doesn't have a "Copy" button is Safari when rendered in EuiBasicTable's expandable row #6770

@nikitaindik

Description

@nikitaindik

Describe the bug
If you pass an isCopyable prop to EuiCodeBlock it should render a text copy button. However, in Safari, the copy button isn't shown when you use EuiCodeBlock as an expandable table row. But it does work properly in other cases.

Environment and versions

  • EUI version: 77.2.2
  • Kibana version: 8.9.0
  • Browser: Safari 16.4 (18615.1.26.110.1)
  • Operating System: MacOS 13.3.1 (a)

To Reproduce
Steps to reproduce the behavior:

  • Checkout Kibana's branch: https://github.com/nikitaindik/kibana/tree/scrollable-callout (not yet merged, scheduled for v8.9)
  • Run Kibana locally
  • Go to Security Solution Rule Management page in Safari (http://localhost:5601/kbn/app/security/rules/management)
  • Click a button to load prebuilt rules
  • Once the rules are loaded, find Endpoint Security rule and click on it
  • At the top of Endpoint Security rule page you'll see a yellow warning callout, note that it has a copy button
  • Scroll to the bottom of the page and select Execution Results tab
  • There should be an expandable warning, expand it. You'll see the warning message text without the copy button.

Expected behavior
TextBlock's copy button should be visible in Safari when TextBlock is rendered within EuiBasicTable's expandable row.

Screenshots
Safari: Expandable row in Execution log - no copy button
Screenshot 2023-05-11 at 14 16 31

Chrome: Expandable row in Execution log - copy button present
Screenshot 2023-05-11 at 13 17 38

Safari: Warning callout - copy button present
Screenshot 2023-05-11 at 14 15 58

Chrome: Warning callout - copy button present
Screenshot 2023-05-11 at 13 17 13


Additional context
I tried to dig into this bug a little, and here's what I found.

EuiCodeBlock component uses useInnerText hook under the hood. As I understand, useInnerText works like this: you give it a ref, and it reads that ref's .innerText value initially and on every update.

export function useInnerText(

And there's conditional logic: if there's no text to copy (innerText value is falsy) - do not render the button. That's what happens in Safari.

const showCopyButton = isCopyable && textToCopy;

For some reason in Safari, during an initial render, the value of innerText is an empty string (Safari bug?). But if you re-query it within a few moments, you'll get the proper value. useInnerText doesn't get notified when innerText becomes readable, so it thinks the value stays ''. Interestingly, textContent and innerHTML values can be read right away.

I tried logging values of innerText, textContent and innerHTML immediately after expanding the row.

Safari: innerText is empty initially, but has value if you read it a little later. textContent and innerHTML are readable right away.
Screenshot 2023-05-11 at 15 18 01

Chrome: all three properties can be read right away
Screenshot 2023-05-11 at 15 17 00

Safari: If you trigger a text update, useInnerText's observer would fire and you'll see the copy button.

Screen.Recording.2023-05-11.at.15.47.24.mov

I also tried modifying EuiBasicTable code to change how expanded row is rendered. If you remove either EuiTableRow wrapper or EuiTableRowCell wrapper, the copy button is rendered!

Safari: Without EuiTableRow - no opening animation, but copy button is rendered
Screenshot 2023-05-11 at 16 44 02

So maybe it's connected to Safari handling animated elements differently somehow 🤷‍♀️


Possible fix ideas:

  • Use textContent instead of innerText, so that it's compatible with Safari behavior?
  • Remove animation for Safari?
  • Allow passing text to copy as a prop to EuiCodeBlock?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions