@redocly/theme 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/lib/components/CodeBlock/CodeBlock.d.ts +29 -1
  2. package/lib/components/CodeBlock/CodeBlock.js +56 -94
  3. package/lib/components/CodeBlock/CodeBlockContainer.d.ts +3 -0
  4. package/lib/components/CodeBlock/CodeBlockContainer.js +120 -0
  5. package/lib/components/CodeBlock/CodeBlockControlButton.d.ts +5 -0
  6. package/lib/components/CodeBlock/CodeBlockControlButton.js +63 -0
  7. package/lib/components/CodeBlock/CodeBlockControls.d.ts +33 -0
  8. package/lib/components/CodeBlock/CodeBlockControls.js +56 -0
  9. package/lib/components/CodeBlock/index.d.ts +3 -0
  10. package/lib/components/CodeBlock/index.js +3 -0
  11. package/lib/components/CopyButton/CopyButton.d.ts +12 -3
  12. package/lib/components/CopyButton/CopyButton.js +30 -26
  13. package/lib/components/CopyButton/index.d.ts +0 -1
  14. package/lib/components/CopyButton/index.js +0 -1
  15. package/lib/components/Feedback/useReportDialog.d.ts +12 -6
  16. package/lib/components/Feedback/useReportDialog.js +13 -5
  17. package/lib/components/JsonViewer/JsonViewer.d.ts +0 -1
  18. package/lib/components/JsonViewer/JsonViewer.js +100 -119
  19. package/lib/components/Markdown/MarkdownWrapper.d.ts +5 -1
  20. package/lib/components/Markdown/MarkdownWrapper.js +59 -53
  21. package/lib/components/Menu/MobileMenu.js +2 -2
  22. package/lib/components/Menu/MobileMenuGroup.js +1 -1
  23. package/lib/components/Panel/PanelHeader.js +0 -1
  24. package/lib/components/Tooltip/Tooltip.js +2 -0
  25. package/lib/components/index.d.ts +0 -3
  26. package/lib/components/index.js +0 -3
  27. package/lib/config.d.ts +30 -23
  28. package/lib/config.js +16 -3
  29. package/lib/globalStyle.js +50 -7
  30. package/lib/icons/ArrowIcon/ArrowIcon.d.ts +3 -3
  31. package/lib/icons/ArrowIcon/ArrowIcon.js +33 -6
  32. package/lib/icons/CollapseIcon/CollapseIcon.d.ts +7 -0
  33. package/lib/icons/CollapseIcon/CollapseIcon.js +22 -0
  34. package/lib/icons/CollapseIcon/index.d.ts +1 -0
  35. package/lib/{components/SourceCode → icons/CollapseIcon}/index.js +1 -1
  36. package/lib/icons/CopyIcon/CopyIcon.d.ts +7 -0
  37. package/lib/icons/CopyIcon/CopyIcon.js +17 -0
  38. package/lib/icons/CopyIcon/index.d.ts +1 -0
  39. package/lib/{components/CodeSample → icons/CopyIcon}/index.js +1 -1
  40. package/lib/icons/DeselectIcon/DeselectIcon.d.ts +7 -0
  41. package/lib/icons/DeselectIcon/DeselectIcon.js +19 -0
  42. package/lib/icons/DeselectIcon/index.d.ts +1 -0
  43. package/lib/{components/SamplesPanelControls → icons/DeselectIcon}/index.js +1 -1
  44. package/lib/icons/ExpandIcon/ExpandIcon.d.ts +5 -6
  45. package/lib/icons/ExpandIcon/ExpandIcon.js +10 -19
  46. package/lib/icons/FileIcon/FileIcon.d.ts +7 -0
  47. package/lib/icons/FileIcon/FileIcon.js +17 -0
  48. package/lib/icons/FileIcon/index.d.ts +1 -0
  49. package/lib/icons/FileIcon/index.js +18 -0
  50. package/lib/icons/ReportIcon/ReportIcon.d.ts +7 -0
  51. package/lib/icons/ReportIcon/ReportIcon.js +19 -0
  52. package/lib/icons/ReportIcon/index.d.ts +1 -0
  53. package/lib/icons/ReportIcon/index.js +18 -0
  54. package/lib/icons/SelectIcon/SelectIcon.d.ts +7 -0
  55. package/lib/icons/SelectIcon/SelectIcon.js +19 -0
  56. package/lib/icons/SelectIcon/index.d.ts +1 -0
  57. package/lib/icons/SelectIcon/index.js +18 -0
  58. package/lib/icons/index.d.ts +7 -1
  59. package/lib/icons/index.js +7 -1
  60. package/lib/layouts/Forbidden.js +2 -2
  61. package/lib/utils/highlight.d.ts +1 -0
  62. package/lib/utils/highlight.js +1 -0
  63. package/package.json +1 -1
  64. package/src/components/CodeBlock/CodeBlock.tsx +100 -0
  65. package/src/components/CodeBlock/{CodeBlock.ts → CodeBlockContainer.tsx} +23 -6
  66. package/src/components/CodeBlock/CodeBlockControlButton.tsx +38 -0
  67. package/src/components/CodeBlock/CodeBlockControls.tsx +182 -0
  68. package/src/components/CodeBlock/index.ts +3 -0
  69. package/src/components/CopyButton/CopyButton.tsx +71 -19
  70. package/src/components/CopyButton/index.ts +0 -1
  71. package/src/components/Feedback/useReportDialog.ts +24 -14
  72. package/src/components/JsonViewer/JsonViewer.tsx +112 -142
  73. package/src/components/Markdown/MarkdownWrapper.tsx +65 -54
  74. package/src/components/Menu/MobileMenu.tsx +3 -3
  75. package/src/components/Menu/MobileMenuGroup.tsx +4 -2
  76. package/src/components/Panel/PanelHeader.ts +0 -1
  77. package/src/components/Tooltip/Tooltip.tsx +2 -0
  78. package/src/components/index.ts +0 -3
  79. package/src/config.ts +18 -7
  80. package/src/globalStyle.ts +50 -7
  81. package/src/icons/ArrowIcon/ArrowIcon.tsx +37 -14
  82. package/src/icons/CollapseIcon/CollapseIcon.tsx +40 -0
  83. package/src/icons/CollapseIcon/index.tsx +1 -0
  84. package/src/icons/CopyIcon/CopyIcon.tsx +26 -0
  85. package/src/icons/CopyIcon/index.ts +1 -0
  86. package/src/icons/DeselectIcon/DeselectIcon.tsx +28 -0
  87. package/src/icons/DeselectIcon/index.ts +1 -0
  88. package/src/icons/ExpandIcon/ExpandIcon.tsx +28 -34
  89. package/src/icons/FileIcon/FileIcon.tsx +29 -0
  90. package/src/icons/FileIcon/index.ts +1 -0
  91. package/src/icons/ReportIcon/ReportIcon.tsx +36 -0
  92. package/src/icons/ReportIcon/index.ts +1 -0
  93. package/src/icons/SelectIcon/SelectIcon.tsx +31 -0
  94. package/src/icons/SelectIcon/index.ts +1 -0
  95. package/src/icons/index.ts +7 -1
  96. package/src/layouts/Forbidden.tsx +1 -1
  97. package/src/utils/highlight.ts +1 -0
  98. package/lib/components/CodeSample/CodeSample.d.ts +0 -10
  99. package/lib/components/CodeSample/CodeSample.js +0 -226
  100. package/lib/components/CodeSample/index.d.ts +0 -1
  101. package/lib/components/CopyButton/CopyButtonWrapper.d.ts +0 -11
  102. package/lib/components/CopyButton/CopyButtonWrapper.js +0 -53
  103. package/lib/components/SamplesPanelControls/SamplesPanelControls.d.ts +0 -4
  104. package/lib/components/SamplesPanelControls/SamplesPanelControls.js +0 -76
  105. package/lib/components/SamplesPanelControls/index.d.ts +0 -1
  106. package/lib/components/SourceCode/SourceCode.d.ts +0 -33
  107. package/lib/components/SourceCode/SourceCode.js +0 -60
  108. package/lib/components/SourceCode/index.d.ts +0 -1
  109. package/src/components/CodeSample/CodeSample.tsx +0 -257
  110. package/src/components/CodeSample/index.ts +0 -1
  111. package/src/components/CopyButton/CopyButtonWrapper.tsx +0 -55
  112. package/src/components/SamplesPanelControls/SamplesPanelControls.ts +0 -76
  113. package/src/components/SamplesPanelControls/index.ts +0 -1
  114. package/src/components/SourceCode/SourceCode.tsx +0 -128
  115. package/src/components/SourceCode/index.ts +0 -1
@@ -0,0 +1,100 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { highlight, addLineNumbers } from '@theme/utils';
5
+ import type { ReportDialogProps } from '@theme/components/Feedback';
6
+ import { ReportDialog, useReportDialog } from '@theme/components/Feedback';
7
+ import type { CodeBlockControlsProps } from '@theme/components/CodeBlock';
8
+ import { CodeBlockContainer, CodeBlockControls } from '@theme/components/CodeBlock';
9
+
10
+ export interface CodeBlockProps {
11
+ lang?: string;
12
+ source?: string;
13
+ externalSource?: ExternalSource;
14
+ header?: CodeBlockControlsProps;
15
+ dataTestId?: string;
16
+ className?: string;
17
+
18
+ withLineNumbers?: boolean;
19
+ startLineNumber?: number;
20
+ highlightedHtml?: string;
21
+ codeBlockRef?: (instance: HTMLPreElement | null) => void;
22
+ }
23
+
24
+ export interface Sample {
25
+ lang: string;
26
+ label?: string;
27
+ }
28
+
29
+ export type UnstableExternalCodeSample = Sample & {
30
+ get: (source: ExternalSource) => string;
31
+ };
32
+
33
+ export interface ExternalSource {
34
+ sample: UnstableExternalCodeSample;
35
+ exampleName?: string;
36
+ pathParams?: any;
37
+ properties?: any;
38
+ operation?: any;
39
+ }
40
+
41
+ export function CodeBlock({
42
+ lang,
43
+ source,
44
+ externalSource,
45
+ header,
46
+ dataTestId = 'source-code',
47
+ codeBlockRef,
48
+ highlightedHtml,
49
+ withLineNumbers,
50
+ startLineNumber,
51
+ className,
52
+ }: CodeBlockProps): JSX.Element {
53
+ const [sourceCode, setSourceCode] = useState<string>(source ?? '');
54
+
55
+ const highlightedCode = highlightedHtml || highlight(sourceCode, lang);
56
+
57
+ // The same initial value should be returned for ssr and frontend to avoid issues
58
+ // Because we don't have session storage in ssr and can't get the security details there
59
+ // Issue for more details https://github.com/Redocly/reference-docs/issues/888
60
+ useEffect(() => {
61
+ const _source = source || externalSource?.sample?.get?.(externalSource);
62
+ if (_source) {
63
+ setSourceCode(_source);
64
+ }
65
+ }, [source, externalSource]);
66
+
67
+ const { reportDialog, reportButton } = useReportDialog();
68
+ const controls = {
69
+ ...header?.controls,
70
+ report: header?.controls?.report
71
+ ? { ...header.controls.report, props: reportButton.props }
72
+ : { props: reportButton.props },
73
+ };
74
+
75
+ if (controls.copy && !controls.copy.handleOutside) {
76
+ controls.copy.data = sourceCode;
77
+ }
78
+
79
+ return (
80
+ <Wrapper data-component-name="CodeBlock/CodeBlock" className={className}>
81
+ <CodeBlockControls className={header?.className} title={header?.title} controls={controls} />
82
+ <CodeBlockContainer
83
+ ref={codeBlockRef}
84
+ className={withLineNumbers ? 'line-numbers' : ''}
85
+ dangerouslySetInnerHTML={{
86
+ __html: withLineNumbers
87
+ ? addLineNumbers(highlightedCode, startLineNumber)
88
+ : highlightedCode,
89
+ }}
90
+ data-cy={dataTestId}
91
+ withControls={true}
92
+ />
93
+ {reportDialog.visible && (
94
+ <ReportDialog {...(reportDialog.props as ReportDialogProps)} location={sourceCode} />
95
+ )}
96
+ </Wrapper>
97
+ );
98
+ }
99
+
100
+ const Wrapper = styled.div``;
@@ -2,12 +2,30 @@ import styled from 'styled-components';
2
2
 
3
3
  import { generateCodeBlockTokens } from '@theme/utils';
4
4
 
5
- export const CodeBlock = styled.div.attrs<{ className?: string }>(({ className }) => ({
6
- 'data-component-name': 'CodeBlock/CodeBlock',
5
+ export const CodeBlockContainer = styled.pre.attrs<{ className?: string }>(({ className }) => ({
6
+ 'data-component-name': 'CodeBlock/CodeBlockContainer',
7
7
  className,
8
- }))`
9
- max-height: var(--code-block-max-height, 600px);
10
- word-break: var(--code-block-word-break, initial);
8
+ }))<{ withControls?: boolean }>`
9
+ && {
10
+ overflow-x: auto;
11
+ max-height: var(--code-block-max-height);
12
+ font-family: var(--code-block-font-family);
13
+ line-height: var(--code-line-height);
14
+ padding: var(--code-block-padding);
15
+ margin: var(--code-block-margin);
16
+ border-radius: ${(withControls) =>
17
+ withControls
18
+ ? '0 0 var(--code-block-border-radius) var(--code-block-border-radius)'
19
+ : 'var(--code-block-border-radius)'};
20
+ background-color: var(--code-block-background-color);
21
+ color: var(--code-block-text-color);
22
+ font-size: var(--code-font-size);
23
+ white-space: var(--code-wrap, pre);
24
+ max-height: var(--code-block-max-height, 600px);
25
+ word-break: var(--code-block-word-break, initial);
26
+ border: none;
27
+ }
28
+
11
29
  /**
12
30
  * Based on prism-dark.css
13
31
  */
@@ -15,7 +33,6 @@ export const CodeBlock = styled.div.attrs<{ className?: string }>(({ className }
15
33
  pre[class*='language-'] {
16
34
  text-shadow: 0 -0.1em 0.2em black;
17
35
  text-align: left;
18
- white-space: pre;
19
36
  word-spacing: normal;
20
37
  word-break: normal;
21
38
  word-wrap: normal;
@@ -0,0 +1,38 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export const CodeBlockControlButton = styled.button.attrs(() => ({
4
+ 'data-component-name': 'CodeBlockControls/CodeBlockControlButton',
5
+ }))<{ asIcon?: boolean }>`
6
+ border: 0;
7
+ outline: 0;
8
+ border-radius: var(--border-radius);
9
+ height: 20px;
10
+ font-size: 12px;
11
+ line-height: 12px;
12
+ cursor: pointer;
13
+ padding: 1px 6px;
14
+ color: var(--panel-samples-controls-text-color);
15
+
16
+ ${({ asIcon }) =>
17
+ asIcon
18
+ ? css`
19
+ background-color: var(--panel-samples-icon-controls-background-color);
20
+ `
21
+ : css`
22
+ min-width: 90px;
23
+ background-color: var(--panel-samples-text-controls-background-color);
24
+ `}
25
+
26
+ ${({ theme }) => theme.mediaQueries?.small} {
27
+ padding: ${({ asIcon }) => (asIcon ? '2px 10px' : '2px 20px')};
28
+ }
29
+
30
+ :not(:first-child) {
31
+ margin-left: 5px;
32
+ }
33
+
34
+ :hover,
35
+ :focus {
36
+ background-color: var(--panel-samples-controls-hover-background-color);
37
+ }
38
+ `;
@@ -0,0 +1,182 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { CodeBlockControlButton } from '@theme/components/CodeBlock';
5
+ import { CollapseIcon, DeselectIcon, ExpandIcon, ReportIcon, SelectIcon } from '@theme/icons';
6
+ import { useThemeConfig } from '@theme/hooks';
7
+
8
+ import { CopyButton } from '../CopyButton';
9
+
10
+ export interface CodeBlockControlsProps {
11
+ children?: React.ReactNode;
12
+ className?: string;
13
+ title?: React.ReactNode | string;
14
+ controls?: ControlItems;
15
+ }
16
+
17
+ interface ControlItems {
18
+ copy?: CopyControlProps;
19
+ expand?: ControlProps;
20
+ collapse?: ControlProps;
21
+ report?: ControlProps;
22
+ select?: ControlProps;
23
+ deselect?: ControlProps;
24
+ }
25
+
26
+ interface ControlProps {
27
+ label?: string;
28
+ tooltipText?: string;
29
+ onClick?: () => void;
30
+ props?: Record<string, any>;
31
+ }
32
+
33
+ interface CopyControlProps extends ControlProps {
34
+ data?: string;
35
+ dataSource?: string;
36
+ dataHash?: string;
37
+ toasterPlacement?: 'left' | 'right' | 'top' | 'bottom';
38
+ toasterText?: string;
39
+ toasterDuration?: number;
40
+ handleOutside?: boolean;
41
+ }
42
+
43
+ export type ControlItemType = 'text' | 'icon';
44
+
45
+ export function CodeBlockControls({
46
+ children,
47
+ className,
48
+ title,
49
+ controls,
50
+ }: CodeBlockControlsProps): JSX.Element | null {
51
+ const { codeSnippet } = useThemeConfig();
52
+ const controlsType = (codeSnippet?.controlsStyle as ControlItemType) || 'icon';
53
+ const { copy, expand, collapse, select, deselect, report } = controls
54
+ ? controls
55
+ : { copy: null, expand: null, collapse: null, select: null, deselect: null, report: null };
56
+
57
+ const defaultControls = controls ? (
58
+ <>
59
+ <Title>{title}</Title>
60
+ <ControlsWrapper>
61
+ {copy && !codeSnippet?.copy?.hide ? (
62
+ <CopyButton
63
+ data={copy.data}
64
+ data-source={copy.dataSource}
65
+ data-hash={copy.dataHash}
66
+ type={controlsType}
67
+ toasterPlacement={copy.toasterPlacement}
68
+ toasterDuration={copy.toasterDuration}
69
+ buttonText={copy.label}
70
+ tooltipText={copy.tooltipText}
71
+ onCopyClick={copy?.onClick}
72
+ />
73
+ ) : null}
74
+
75
+ {expand && !codeSnippet?.expand?.hide ? (
76
+ <CodeBlockControlButton
77
+ data-cy="expand-all"
78
+ data-testid="expand-all"
79
+ asIcon={controlsType === 'icon'}
80
+ onClick={expand?.onClick}
81
+ title={expand?.tooltipText || 'Expand all'}
82
+ >
83
+ {controlsType === 'icon' ? <ExpandIcon /> : expand?.label ? expand.label : 'Expand all'}
84
+ </CodeBlockControlButton>
85
+ ) : null}
86
+
87
+ {collapse && !codeSnippet?.collapse?.hide ? (
88
+ <CodeBlockControlButton
89
+ data-cy="collapse-all"
90
+ data-testid="collapse-all"
91
+ asIcon={controlsType === 'icon'}
92
+ onClick={collapse?.onClick}
93
+ title={collapse?.tooltipText || 'Collapse all'}
94
+ >
95
+ {controlsType === 'icon' ? (
96
+ <CollapseIcon />
97
+ ) : collapse?.label ? (
98
+ collapse.label
99
+ ) : (
100
+ 'Collapse all'
101
+ )}
102
+ </CodeBlockControlButton>
103
+ ) : null}
104
+
105
+ {select ? (
106
+ <CodeBlockControlButton
107
+ data-cy="select-all"
108
+ data-testid="select-all"
109
+ asIcon={controlsType === 'icon'}
110
+ onClick={select?.onClick}
111
+ title={select?.tooltipText}
112
+ >
113
+ {controlsType === 'icon' ? <SelectIcon /> : select?.label ? select.label : 'Select all'}
114
+ </CodeBlockControlButton>
115
+ ) : null}
116
+
117
+ {deselect ? (
118
+ <CodeBlockControlButton
119
+ data-cy="clear-all"
120
+ data-testid="clear-all"
121
+ asIcon={controlsType === 'icon'}
122
+ onClick={deselect?.onClick}
123
+ title={deselect?.tooltipText}
124
+ >
125
+ {controlsType === 'icon' ? (
126
+ <DeselectIcon />
127
+ ) : deselect?.label ? (
128
+ deselect.label
129
+ ) : (
130
+ 'Clear all'
131
+ )}
132
+ </CodeBlockControlButton>
133
+ ) : null}
134
+
135
+ {report && report?.props?.visible ? (
136
+ <CodeBlockControlButton
137
+ data-cy="report-button"
138
+ data-testid="report-button"
139
+ asIcon={controlsType === 'icon'}
140
+ title={report.tooltipText}
141
+ {...report.props}
142
+ >
143
+ {controlsType === 'icon' ? <ReportIcon /> : report.props?.buttonText || 'Report'}
144
+ </CodeBlockControlButton>
145
+ ) : null}
146
+ </ControlsWrapper>
147
+ </>
148
+ ) : null;
149
+
150
+ return children || controls ? (
151
+ <ContainerWraper data-component-name="CodeBlock/CodeBlockControls" className={className}>
152
+ {children ? children : defaultControls}
153
+ </ContainerWraper>
154
+ ) : null;
155
+ }
156
+
157
+ const ContainerWraper = styled.div`
158
+ display: flex;
159
+ justify-content: space-between;
160
+ padding: 5px 10px;
161
+ min-height: 30px;
162
+ background-color: var(--panel-samples-controls-background-color);
163
+ border-bottom: var(--panel-samples-controls-border);
164
+ border-radius: var(--border-radius) var(--border-radius) 0 0;
165
+ margin-top: 10px;
166
+ `;
167
+
168
+ const Title = styled.span`
169
+ display: flex;
170
+ align-items: center;
171
+ color: var(--panel-samples-controls-text-color);
172
+ `;
173
+
174
+ const ControlsWrapper = styled.div`
175
+ opacity: 0.7;
176
+ transition: opacity 0.3s ease;
177
+ text-align: right;
178
+
179
+ &:focus-within {
180
+ opacity: 1;
181
+ }
182
+ `;
@@ -1 +1,4 @@
1
1
  export * from '@theme/components/CodeBlock/CodeBlock';
2
+ export * from '@theme/components/CodeBlock/CodeBlockContainer';
3
+ export * from '@theme/components/CodeBlock/CodeBlockControls';
4
+ export * from '@theme/components/CodeBlock/CodeBlockControlButton';
@@ -1,31 +1,83 @@
1
- import React, { useState } from 'react';
2
- import copy from 'copy-to-clipboard';
3
- import { Button } from '@theme';
1
+ import React, { memo } from 'react';
2
+
3
+ import type { ControlItemType } from '@theme/components/CodeBlock';
4
+ import { CodeBlockControlButton } from '@theme/components/CodeBlock';
5
+ import { Tooltip } from '@theme/components/Tooltip';
6
+ import { useControl } from '@theme/hooks';
7
+ import { ClipboardService } from '@theme/utils';
8
+ import type { TooltipProps } from '@theme/components/Tooltip';
9
+ import { CopyIcon } from '@theme/icons';
10
+ import { useTranslate } from '@portal/hooks';
4
11
 
5
12
  export interface CopyButtonProps {
6
- text: string;
13
+ data: unknown;
14
+ type?: ControlItemType;
15
+ toasterPlacement?: TooltipProps['placement'];
16
+ toasterText?: TooltipProps['tip'];
17
+ toasterDuration?: number;
18
+ buttonText?: string;
19
+ tooltipText?: string;
20
+ onCopyClick?: () => void;
7
21
  dataTestId?: string;
8
22
  }
9
23
 
10
- export const CopyButton = ({ text, dataTestId = 'copy-button' }: CopyButtonProps): JSX.Element => {
11
- const [title, setTitle] = useState('Copy');
24
+ function CopyButtonComponent({
25
+ data,
26
+ type = 'icon',
27
+ toasterPlacement = 'top',
28
+ toasterText,
29
+ toasterDuration,
30
+ buttonText,
31
+ tooltipText,
32
+ onCopyClick,
33
+ dataTestId = 'copy-button',
34
+ }: CopyButtonProps): JSX.Element {
35
+ const tooltip = useControl();
36
+ const { translate } = useTranslate();
37
+ const translationKeys = {
38
+ buttonText: 'theme.codeSnippet.copy.buttonText',
39
+ tooltipText: 'theme.codeSnippet.copy.tooltipText',
40
+ toasterText: 'theme.codeSnippet.copy.toasterText',
41
+ };
42
+
43
+ const showTooltip = (duration: number = 1500): void => {
44
+ tooltip.handleOpen();
12
45
 
13
- async function write() {
14
- await copy(text);
46
+ setTimeout(() => {
47
+ tooltip.handleClose();
48
+ }, duration);
49
+ };
15
50
 
16
- setTitle('Copied!');
51
+ const copy = (duration?: number): void => {
52
+ const content = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
53
+ ClipboardService.copyCustom(content);
54
+ showTooltip(duration);
17
55
 
18
- setTimeout(() => setTitle('Copy'), 1500);
19
- }
56
+ onCopyClick?.();
57
+ };
20
58
 
21
59
  return (
22
- <Button
23
- color="secondary"
24
- onClick={write}
25
- data-cy={dataTestId}
26
- data-component-name="CopyButton/CopyButton"
60
+ <Tooltip
61
+ className="copy-button"
62
+ tip={translate(translationKeys.toasterText, toasterText || 'Copied!')}
63
+ isOpen={tooltip.isOpened}
64
+ placement={toasterPlacement}
27
65
  >
28
- {title}
29
- </Button>
66
+ <CodeBlockControlButton
67
+ onClick={() => copy(toasterDuration)}
68
+ data-cy={dataTestId}
69
+ asIcon={type === 'icon'}
70
+ title={translate(translationKeys.tooltipText, tooltipText || 'Copy to clipboard')}
71
+ data-testid={dataTestId}
72
+ >
73
+ {type === 'icon' ? (
74
+ <CopyIcon />
75
+ ) : (
76
+ translate(translationKeys.buttonText, buttonText || 'Copy')
77
+ )}
78
+ </CodeBlockControlButton>
79
+ </Tooltip>
30
80
  );
31
- };
81
+ }
82
+
83
+ export const CopyButton = memo<CopyButtonProps>(CopyButtonComponent);
@@ -1,2 +1 @@
1
- export * from '@theme/components/CopyButton/CopyButtonWrapper';
2
1
  export * from '@theme/components/CopyButton/CopyButton';
@@ -2,18 +2,26 @@ import { useState } from 'react';
2
2
 
3
3
  import type { ReportDialogProps } from '@theme/components/Feedback/types';
4
4
  import { useTranslate } from '@portal/hooks';
5
+ import { useThemeConfig } from '@theme/hooks';
5
6
 
6
- type ReportSettings = {
7
- hide?: boolean;
8
- label?: string;
9
- tooltipText?: string;
10
- };
7
+ export interface ReportButtonProps {
8
+ onClick: () => void;
9
+ buttonText: string;
10
+ tooltip: string;
11
+ visible: boolean;
12
+ }
13
+ interface ReportComponentsProps {
14
+ visible?: boolean;
15
+ props: Partial<ReportDialogProps> | ReportButtonProps;
16
+ }
11
17
 
12
- export function useReportDialog(reportSettings: ReportSettings): Record<string, any> {
18
+ export function useReportDialog(): Record<string, ReportComponentsProps> {
19
+ const { codeSnippet: { report = {} } = {} } = useThemeConfig();
13
20
  const [isReportDialogShown, setIsReportDialogShown] = useState(false);
14
- const isReportButtonShown = reportSettings.hide === false; // TODO: report temporary disabled by default
21
+ const isReportButtonShown = report?.hide === false; // TODO: report temporary disabled by default
15
22
  const { translate } = useTranslate();
16
23
  const translationKeys = {
24
+ buttonText: 'theme.codeSnippet.report.buttonText',
17
25
  tooltipText: 'theme.codeSnippet.report.tooltipText',
18
26
  label: 'theme.codeSnippet.report.label',
19
27
  };
@@ -24,20 +32,22 @@ export function useReportDialog(reportSettings: ReportSettings): Record<string,
24
32
  const hideReportDialog = () => {
25
33
  setIsReportDialogShown(false);
26
34
  };
27
- const reportButtonProps = {
35
+ const reportButtonProps: ReportButtonProps = {
28
36
  onClick: showReportDialog,
29
- title: translate(translationKeys.tooltipText, reportSettings.tooltipText || 'Report a problem'),
37
+ buttonText: translate(translationKeys.buttonText, 'Report'),
38
+ tooltip: translate(translationKeys.tooltipText, 'Report a problem'),
39
+ visible: isReportButtonShown,
30
40
  };
31
41
  const reportDialogProps: Partial<ReportDialogProps> = {
32
42
  settings: {
33
- label: translate(
34
- translationKeys.label,
35
- reportSettings.label || 'What is wrong with this code?',
36
- ),
43
+ label: translate(translationKeys.label, 'What is wrong with this code?'),
37
44
  },
38
45
  onSubmit: hideReportDialog,
39
46
  onCancel: hideReportDialog,
40
47
  };
41
48
 
42
- return { isReportDialogShown, isReportButtonShown, reportButtonProps, reportDialogProps };
49
+ return {
50
+ reportDialog: { visible: isReportDialogShown, props: reportDialogProps },
51
+ reportButton: { props: reportButtonProps },
52
+ };
43
53
  }