diff --git a/packages/components/src/components/code-snippet/_code-snippet.scss b/packages/components/src/components/code-snippet/_code-snippet.scss
index 3ac103267cd7..1580e8bbaa8c 100644
--- a/packages/components/src/components/code-snippet/_code-snippet.scss
+++ b/packages/components/src/components/code-snippet/_code-snippet.scss
@@ -11,6 +11,8 @@
@import '../../globals/scss/vendor/@carbon/elements/scss/import-once/import-once';
@import '../../globals/scss/css--reset';
@import '../../globals/scss/theme-tokens';
+@import '../../globals/scss/tooltip';
+@import '../../globals/scss/keyframes';
@import 'mixins';
/// Code snippet styles
@@ -50,6 +52,37 @@
outline: none;
border: 2px solid $focus;
}
+
+ &::before {
+ @include tooltip--caret;
+ display: none;
+ }
+
+ .#{$prefix}--copy-btn__feedback {
+ @include tooltip--content('icon');
+ clip: auto;
+ margin: auto;
+ overflow: visible;
+ display: none;
+ }
+ @include tooltip--placement('icon', 'bottom', 'center');
+
+ &.#{$prefix}--copy-btn--animating::before,
+ &.#{$prefix}--copy-btn--animating .#{$prefix}--copy-btn__feedback {
+ display: block;
+ }
+
+ &.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-out::before,
+ &.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-out
+ .#{$prefix}--copy-btn__feedback {
+ animation: $duration--fast-02 motion(standard, productive) hide-feedback;
+ }
+
+ &.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-in::before,
+ &.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-in
+ .#{$prefix}--copy-btn__feedback {
+ animation: $duration--fast-02 motion(standard, productive) show-feedback;
+ }
}
.#{$prefix}--snippet--inline code {
@@ -213,6 +246,16 @@
border: none;
}
+ // TODO: remove copy button styles above
+ .#{$prefix}--snippet .#{$prefix}--copy-btn {
+ position: absolute;
+ top: 0;
+ right: 0;
+ @include carbon--font-family(
+ 'sans'
+ ); // Override inherited rule in code snippet
+ }
+
// Show more / less button
button.#{$prefix}--btn.#{$prefix}--snippet-btn--expand {
display: inline-flex;
diff --git a/packages/components/src/components/code-snippet/code-snippet.hbs b/packages/components/src/components/code-snippet/code-snippet.hbs
index d1edd202be79..89c38c8be32e 100644
--- a/packages/components/src/components/code-snippet/code-snippet.hbs
+++ b/packages/components/src/components/code-snippet/code-snippet.hbs
@@ -7,17 +7,19 @@
{{#is variant "inline"}}
Here is an example of a text that a user would be reading. In this paragraph would be
-
that the user could look at and copy in to their code editor.
{{else}}
-
+ data-code-snippet{{/is}}>
+
+
@mixin grid-container {
width: 100%;
padding-right: padding(mobile);
@@ -40,22 +42,24 @@
floating: 10000
);
-
-
-{{#is variant "multi"}}
-
+
+ {{#is variant "multi"}}
+
-{{/is}}
+
+ {{/is}}
{{/is}}
diff --git a/packages/components/src/components/copy-button/_copy-button.scss b/packages/components/src/components/copy-button/_copy-button.scss
index 1aa410bd0604..eeeaefe3fa14 100644
--- a/packages/components/src/components/copy-button/_copy-button.scss
+++ b/packages/components/src/components/copy-button/_copy-button.scss
@@ -12,7 +12,8 @@
@import '../../globals/scss/vendor/@carbon/elements/scss/import-once/import-once';
@import '../../globals/scss/css--reset';
@import '../button/button';
-@import 'keyframes';
+@import '../../globals/scss/tooltip';
+@import '../../globals/scss/keyframes';
@include exports('copy-button') {
.#{$prefix}--btn--copy {
@@ -85,6 +86,11 @@
height: $carbon--spacing-08;
width: $carbon--spacing-08;
background-color: $ui-01;
+ cursor: pointer;
+
+ &:hover {
+ background-color: $hover-ui;
+ }
&::before {
@include tooltip--caret;
diff --git a/packages/components/src/components/copy-button/_keyframes.scss b/packages/components/src/globals/scss/_keyframes.scss
similarity index 100%
rename from packages/components/src/components/copy-button/_keyframes.scss
rename to packages/components/src/globals/scss/_keyframes.scss
diff --git a/packages/react/src/components/CodeSnippet/CodeSnippet.js b/packages/react/src/components/CodeSnippet/CodeSnippet.js
index 5710e02bddba..3dd581309e00 100644
--- a/packages/react/src/components/CodeSnippet/CodeSnippet.js
+++ b/packages/react/src/components/CodeSnippet/CodeSnippet.js
@@ -78,7 +78,6 @@ function CodeSnippet({
{
it('Should be able to specify the feedback message', () => {
const feedbackWrapper = mount();
expect(
- feedbackWrapper.find(`.${prefix}--btn--copy__feedback`).props()[
- 'data-feedback'
- ]
+ feedbackWrapper.find(`.${prefix}--copy-btn__feedback`).text()
).toBe('Copied!');
});
});
@@ -62,28 +60,24 @@ describe('Copy', () => {
describe('Renders feedback as expected', () => {
it('Should make the feedback visible', () => {
const feedbackWrapper = mount();
- const feedback = () =>
- feedbackWrapper.find(`.${prefix}--btn--copy__feedback`);
- expect(
- feedback().hasClass(`${prefix}--btn--copy__feedback--displayed`)
- ).toBe(false);
- feedbackWrapper.setState({ showFeedback: true });
- expect(
- feedback().hasClass(`${prefix}--btn--copy__feedback--displayed`)
- ).toBe(true);
+ const feedback = feedbackWrapper.find(`.${prefix}--copy-btn__feedback`);
+ expect(feedback).toBeFalsy;
+ feedbackWrapper.simulate('click');
+ expect(feedback).toBeTruthy;
});
it('Should show feedback for a limited amount of time', () => {
const feedbackWrapper = mount(
);
- expect(feedbackWrapper.state().showFeedback).toBe(false);
feedbackWrapper.simulate('click');
- expect(feedbackWrapper.state().showFeedback).toBe(true);
- expect(setTimeout.mock.calls.length).toBe(2);
- expect(setTimeout.mock.calls[1][1]).toBe(5000);
- jest.runAllTimers();
- expect(feedbackWrapper.state().showFeedback).toBe(false);
+ const copyButton = feedbackWrapper.find('button');
+ expect(copyButton.hasClass(`${prefix}--copy-btn--animating`)).toBe(true);
+ setTimeout(() => {
+ expect(copyButton.hasClass(`${prefix}--copy-btn--animating`)).toBe(
+ false
+ );
+ }, 5220); // 5000 + 2 * 110 (transition duration)
});
});
diff --git a/packages/react/src/components/Copy/Copy.js b/packages/react/src/components/Copy/Copy.js
index e4dda68b1ef7..c722ea6f5df8 100644
--- a/packages/react/src/components/Copy/Copy.js
+++ b/packages/react/src/components/Copy/Copy.js
@@ -6,91 +6,101 @@
*/
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
+import debounce from 'lodash.debounce';
import classnames from 'classnames';
import { settings } from 'carbon-components';
+import { composeEventHandlers } from '../../tools/events';
const { prefix } = settings;
-export default class Copy extends Component {
- static propTypes = {
- /**
- * Pass in content to be rendred in the underlying