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 + ); +} - /* istanbul ignore next */ - componentWillUnmount() { - if (typeof this.timeoutId !== 'undefined') { - clearTimeout(this.timeoutId); - delete this.timeoutId; - } - } +Copy.propTypes = { + /** + * Pass in content to be rendred in the underlying - ); - } -} + /** + * Specify an optional `onClick` handler that is called when the underlying + * ); } + CopyButton.propTypes = { /** * Specify an optional className to be applied to the underlying