123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- import classNames from 'classnames';
- import Clipboard from 'clipboard';
- import React from 'react';
- import { INTERACTIVE_TOOLTIP_DELAY } from '../helpers/constants';
- import { translate } from '../helpers/l10n';
- import { ButtonSecondary } from './buttons';
- import CopyIcon from './icons/CopyIcon';
- import { IconProps } from './icons/Icon';
- import { DiscreetInteractiveIcon, InteractiveIcon, InteractiveIconSize } from './InteractiveIcon';
- import Tooltip from './Tooltip';
-
- const COPY_SUCCESS_NOTIFICATION_LIFESPAN = 1000;
-
- export interface State {
- copySuccess: boolean;
- }
-
- interface RenderProps {
- copySuccess: boolean;
- setCopyButton: (node: HTMLElement | null) => void;
- }
-
- interface BaseProps {
- children: (props: RenderProps) => React.ReactNode;
- }
-
- export class ClipboardBase extends React.PureComponent<BaseProps, State> {
- private clipboard?: Clipboard;
- private copyButton?: HTMLElement | null;
- mounted = false;
- state: State = { copySuccess: false };
-
- componentDidMount() {
- this.mounted = true;
- if (this.copyButton) {
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.handleSuccessCopy);
- }
- }
-
- componentDidUpdate() {
- if (this.clipboard) {
- this.clipboard.destroy();
- }
- if (this.copyButton) {
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.handleSuccessCopy);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- if (this.clipboard) {
- this.clipboard.destroy();
- }
- }
-
- setCopyButton = (node: HTMLElement | null) => {
- this.copyButton = node;
- };
-
- handleSuccessCopy = () => {
- if (this.mounted) {
- this.setState({ copySuccess: true });
- setTimeout(() => {
- if (this.mounted) {
- this.setState({ copySuccess: false });
- }
- }, COPY_SUCCESS_NOTIFICATION_LIFESPAN);
- }
- };
-
- render() {
- return this.props.children({
- setCopyButton: this.setCopyButton,
- copySuccess: this.state.copySuccess,
- });
- }
- }
-
- interface ButtonProps {
- children?: React.ReactNode;
- className?: string;
- copyValue: string;
- icon?: React.ReactNode;
- }
-
- export function ClipboardButton({
- icon = <CopyIcon />,
- className,
- children,
- copyValue,
- }: ButtonProps) {
- return (
- <ClipboardBase>
- {({ setCopyButton, copySuccess }) => (
- <Tooltip overlay={translate('copied_action')} visible={copySuccess}>
- <ButtonSecondary
- className={classNames('sw-select-none', className)}
- data-clipboard-text={copyValue}
- icon={icon}
- innerRef={setCopyButton}
- >
- {children || translate('copy')}
- </ButtonSecondary>
- </Tooltip>
- )}
- </ClipboardBase>
- );
- }
-
- interface IconButtonProps {
- Icon?: React.ComponentType<IconProps>;
- 'aria-label'?: string;
- className?: string;
- copyValue: string;
- discreet?: boolean;
- size?: InteractiveIconSize;
- }
-
- export function ClipboardIconButton(props: IconButtonProps) {
- const { className, copyValue, discreet, size = 'small', Icon = CopyIcon } = props;
- const InteractiveIconComponent = discreet ? DiscreetInteractiveIcon : InteractiveIcon;
-
- return (
- <ClipboardBase>
- {({ setCopyButton, copySuccess }) => {
- return (
- <Tooltip
- mouseEnterDelay={INTERACTIVE_TOOLTIP_DELAY}
- overlay={
- <div className="sw-w-abs-150 sw-text-center">
- {translate(copySuccess ? 'copied_action' : 'copy_to_clipboard')}
- </div>
- }
- {...(copySuccess ? { visible: copySuccess } : undefined)}
- >
- <InteractiveIconComponent
- Icon={Icon}
- aria-label={props['aria-label'] ?? translate('copy_to_clipboard')}
- className={className}
- data-clipboard-text={copyValue}
- innerRef={setCopyButton}
- size={size}
- />
- </Tooltip>
- );
- }}
- </ClipboardBase>
- );
- }
|