@mantine/code-highlight 7.0.0-alpha.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 (70) hide show
  1. package/README.md +21 -0
  2. package/cjs/CodeHighlight.js +126 -0
  3. package/cjs/CodeHighlight.js.map +1 -0
  4. package/cjs/CodeHighlight.module.css.js +8 -0
  5. package/cjs/CodeHighlight.module.css.js.map +1 -0
  6. package/cjs/CodeHighlight.theme.module.css.js +8 -0
  7. package/cjs/CodeHighlight.theme.module.css.js.map +1 -0
  8. package/cjs/CodeHighlightTabs.js +196 -0
  9. package/cjs/CodeHighlightTabs.js.map +1 -0
  10. package/cjs/CopyIcon.js +70 -0
  11. package/cjs/CopyIcon.js.map +1 -0
  12. package/cjs/ExpandIcon.js +83 -0
  13. package/cjs/ExpandIcon.js.map +1 -0
  14. package/cjs/FileIcon.js +22 -0
  15. package/cjs/FileIcon.js.map +1 -0
  16. package/cjs/InlineCodeHighlight.js +78 -0
  17. package/cjs/InlineCodeHighlight.js.map +1 -0
  18. package/cjs/index.css +326 -0
  19. package/cjs/index.js +14 -0
  20. package/cjs/index.js.map +1 -0
  21. package/cjs/use-highlight.js +27 -0
  22. package/cjs/use-highlight.js.map +1 -0
  23. package/esm/CodeHighlight.js +117 -0
  24. package/esm/CodeHighlight.js.map +1 -0
  25. package/esm/CodeHighlight.module.css.js +4 -0
  26. package/esm/CodeHighlight.module.css.js.map +1 -0
  27. package/esm/CodeHighlight.theme.module.css.js +4 -0
  28. package/esm/CodeHighlight.theme.module.css.js.map +1 -0
  29. package/esm/CodeHighlightTabs.js +186 -0
  30. package/esm/CodeHighlightTabs.js.map +1 -0
  31. package/esm/CopyIcon.js +62 -0
  32. package/esm/CopyIcon.js.map +1 -0
  33. package/esm/ExpandIcon.js +75 -0
  34. package/esm/ExpandIcon.js.map +1 -0
  35. package/esm/FileIcon.js +14 -0
  36. package/esm/FileIcon.js.map +1 -0
  37. package/esm/InlineCodeHighlight.js +68 -0
  38. package/esm/InlineCodeHighlight.js.map +1 -0
  39. package/esm/index.css +326 -0
  40. package/esm/index.js +4 -0
  41. package/esm/index.js.map +1 -0
  42. package/esm/use-highlight.js +19 -0
  43. package/esm/use-highlight.js.map +1 -0
  44. package/lib/CodeHighlight.d.ts +29 -0
  45. package/lib/CodeHighlightTabs.d.ts +55 -0
  46. package/lib/CopyIcon.d.ts +9 -0
  47. package/lib/ExpandIcon.d.ts +6 -0
  48. package/lib/FileIcon.d.ts +8 -0
  49. package/lib/InlineCodeHighlight.d.ts +19 -0
  50. package/lib/index.d.ts +6 -0
  51. package/lib/use-highlight.d.ts +15 -0
  52. package/package.json +42 -0
  53. package/src/CodeHighlight.module.css +153 -0
  54. package/src/CodeHighlight.story.tsx +218 -0
  55. package/src/CodeHighlight.test.tsx +30 -0
  56. package/src/CodeHighlight.theme.module.css +95 -0
  57. package/src/CodeHighlight.tsx +123 -0
  58. package/src/CodeHighlightTabs.test.tsx +39 -0
  59. package/src/CodeHighlightTabs.tsx +252 -0
  60. package/src/CopyIcon.tsx +37 -0
  61. package/src/ExpandIcon.tsx +42 -0
  62. package/src/FileIcon.tsx +19 -0
  63. package/src/InlineCodeHighlight.test.tsx +25 -0
  64. package/src/InlineCodeHighlight.tsx +72 -0
  65. package/src/index.ts +23 -0
  66. package/src/use-highlight.ts +30 -0
  67. package/styles.css +326 -0
  68. package/tsconfig.build.json +23 -0
  69. package/tsconfig.build.tsbuildinfo +1 -0
  70. package/tsconfig.json +23 -0
@@ -0,0 +1,153 @@
1
+ .code {
2
+ display: inline-block;
3
+ padding: rem(1px) rem(3px);
4
+ font-size: rem(13px);
5
+ border-radius: var(--mantine-radius-xs);
6
+ line-height: var(--_code-line-height, var(--mantine-line-height));
7
+ font-family: var(--mantine-font-family-monospace);
8
+ }
9
+
10
+ .pre {
11
+ display: block;
12
+ padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);
13
+ margin: 0;
14
+ --_code-line-height: 1.7;
15
+ }
16
+
17
+ .header {
18
+ display: flex;
19
+ align-items: flex-start;
20
+ justify-content: space-between;
21
+ }
22
+
23
+ .controls {
24
+ display: flex;
25
+ margin-top: rem(7px);
26
+ margin-right: rem(7px);
27
+ }
28
+
29
+ .copy,
30
+ .control {
31
+ background-color: transparent;
32
+ opacity: 0.8;
33
+ margin: 0;
34
+
35
+ @mixin hover {
36
+ opacity: 1;
37
+ }
38
+
39
+ @media (max-width: 40em) {
40
+ display: none;
41
+ }
42
+ }
43
+
44
+ .copy {
45
+ position: absolute;
46
+ top: rem(5px);
47
+ right: rem(5px);
48
+ z-index: 1;
49
+ }
50
+
51
+ .file {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ font-size: var(--mantine-font-size-xs);
56
+ gap: rem(7px);
57
+ padding: rem(7px) rem(12px);
58
+ font-family: var(--mantine-font-family-monospace);
59
+ font-weight: 700;
60
+ line-height: 1;
61
+ user-select: none;
62
+ cursor: var(--_file-cursor);
63
+ border: rem(1px) solid var(--_file-bd);
64
+ border-top: 0;
65
+ border-left: 0;
66
+ color: var(--_file-color);
67
+ opacity: var(--_file-opacity);
68
+ background-color: var(--_file-bg);
69
+
70
+ @mixin hover {
71
+ --_file-opacity: 1;
72
+ }
73
+
74
+ &:last-of-type {
75
+ border-bottom-right-radius: var(--mantine-radius-sm);
76
+ }
77
+
78
+ &:only-child {
79
+ --_file-cursor: default;
80
+ }
81
+
82
+ &[data-active] {
83
+ --_file-opacity: 1;
84
+ --_file-color: var(--_file-active-color) !important;
85
+ --_file-bg: var(--_file-active-bg);
86
+ }
87
+
88
+ --_file-opacity: 0.8;
89
+ --_file-cursor: pointer;
90
+
91
+ @mixin light {
92
+ --_file-color: var(--mantine-color-gray-8);
93
+ --_file-bd: var(--mantine-color-gray-2);
94
+ --_file-active-bg: var(--mantine-color-white);
95
+ --_file-active-color: var(--mantine-color-black);
96
+ }
97
+
98
+ @mixin dark {
99
+ --_file-color: var(--mantine-color-dark-0);
100
+ --_file-bd: var(--mantine-color-dark-4);
101
+ --_file-active-bg: var(--mantine-color-dark-6);
102
+ --_file-active-color: var(--mantine-color-white);
103
+ }
104
+ }
105
+
106
+ .files {
107
+ display: flex;
108
+ }
109
+
110
+ .codeWrapper {
111
+ max-height: var(--ch-max-collapsed-height);
112
+ overflow: hidden;
113
+ position: relative;
114
+
115
+ &::before {
116
+ content: '';
117
+ position: absolute;
118
+ inset: 0;
119
+ pointer-events: none;
120
+ background-image: linear-gradient(0deg, var(--_background) 16%, rgba(0, 0, 0, 0) 100%);
121
+ border-radius: calc(var(--mantine-radius-md) - rem(1px));
122
+ }
123
+
124
+ &[data-expanded] {
125
+ max-height: none;
126
+
127
+ &::before {
128
+ display: none;
129
+ }
130
+ }
131
+ }
132
+
133
+ .showCodeButton {
134
+ position: absolute;
135
+ bottom: 0;
136
+ left: 50%;
137
+ transform: translateX(-50%);
138
+ font-size: var(--mantine-font-size-sm);
139
+ color: var(--mantine-color-anchor);
140
+ width: 100%;
141
+ text-align: center;
142
+ padding-top: var(--mantine-spacing-xs);
143
+ padding-bottom: var(--mantine-spacing-xs);
144
+
145
+ &[data-hidden] {
146
+ display: none;
147
+ }
148
+ }
149
+
150
+ .root {
151
+ margin-top: 0;
152
+ position: relative;
153
+ }
@@ -0,0 +1,218 @@
1
+ import React from 'react';
2
+ import { CodeHighlightTabs } from './CodeHighlightTabs';
3
+ import { CodeHighlight } from './CodeHighlight';
4
+ import { InlineCodeHighlight } from './InlineCodeHighlight';
5
+
6
+ export default { title: 'CodeHighlight' };
7
+
8
+ const tsxCode = `
9
+ import { forwardRef } from 'react';
10
+ import { Group, Avatar, Text, Select } from '@mantine/core';
11
+
12
+ // Data for select
13
+ // You can use any data structure you want
14
+
15
+ const data = [
16
+ {
17
+ image: 'https://img.icons8.com/clouds/256/000000/futurama-bender.png',
18
+ label: 'Bender Bending Rodríguez',
19
+ value: 'Bender Bending Rodríguez',
20
+ description: 'Fascinated with cooking',
21
+ },
22
+
23
+ {
24
+ image: 'https://img.icons8.com/clouds/256/000000/futurama-mom.png',
25
+ label: 'Carol Miller',
26
+ value: 'Carol Miller',
27
+ description: 'One of the richest people on Earth',
28
+ },
29
+ {
30
+ image: 'https://img.icons8.com/clouds/256/000000/homer-simpson.png',
31
+ label: 'Homer Simpson',
32
+ value: 'Homer Simpson',
33
+ description: 'Overweight, lazy, and often ignorant',
34
+ },
35
+ {
36
+ image: 'https://img.icons8.com/clouds/256/000000/spongebob-squarepants.png',
37
+ label: 'Spongebob Squarepants',
38
+ value: 'Spongebob Squarepants',
39
+ description: 'Not just a sponge',
40
+ },
41
+ ];
42
+
43
+ interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
44
+ image: string;
45
+ label: string;
46
+ description: string;
47
+ }
48
+
49
+ const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
50
+ ({ image, label, description, ...others }: ItemProps, ref) => (
51
+ <div ref={ref} {...others}>
52
+ <Group noWrap>
53
+ <Avatar src={image} />
54
+
55
+ <div>
56
+ <Text size="sm">{label}</Text>
57
+ <Text size="xs" opacity={0.65}>
58
+ {description}
59
+ </Text>
60
+ </div>
61
+ </Group>
62
+ </div>
63
+ )
64
+ );
65
+
66
+ function Demo() {
67
+ return (
68
+ <Select
69
+ label="Choose employee of the month"
70
+ placeholder="Pick one"
71
+ itemComponent={SelectItem}
72
+ data={data}
73
+ searchable
74
+ maxDropdownHeight={400}
75
+ nothingFound="Nobody here"
76
+ filter={(value, item) =>
77
+ item.label.toLowerCase().includes(value.toLowerCase().trim()) ||
78
+ item.description.toLowerCase().includes(value.toLowerCase().trim())
79
+ }
80
+ />
81
+ );
82
+ }
83
+ `;
84
+
85
+ const cssCode = `.root {
86
+ --ai-size-xs: rem(18px);
87
+ --ai-size-sm: rem(22px);
88
+ --ai-size-md: rem(28px);
89
+ --ai-size-lg: rem(34px);
90
+ --ai-size-xl: rem(44px);
91
+
92
+ --_bg: var(--ai-bg);
93
+ --_color: var(--ai-color);
94
+ --_cursor: pointer;
95
+
96
+ line-height: 1;
97
+ display: inline-flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ position: relative;
101
+ user-select: none;
102
+
103
+ width: var(--ai-size);
104
+ height: var(--ai-size);
105
+ min-width: var(--ai-size);
106
+ min-height: var(--ai-size);
107
+ border-radius: var(--ai-radius);
108
+ background: var(--_bg);
109
+ color: var(--_color);
110
+ border: var(--ai-bd);
111
+ cursor: var(--_cursor);
112
+
113
+ @mixin hover {
114
+ &:not([data-loading]):not(:disabled):not([data-disabled]) {
115
+ --_bg: var(--ai-hover);
116
+ }
117
+ }
118
+
119
+ @mixin light {
120
+ --_loading-overlay-bg: rgba(255, 255, 255, 0.35);
121
+ --_disabled-bg: var(--mantine-color-gray-1);
122
+ --_disabled-color: var(--mantine-color-gray-5);
123
+ }
124
+
125
+ @mixin dark {
126
+ --_loading-overlay-bg: rgba(0, 0, 0, 0.35);
127
+ --_disabled-bg: var(--mantine-color-dark-6);
128
+ --_disabled-color: var(--mantine-color-dark-3);
129
+ }
130
+
131
+ &[data-loading] {
132
+ --_cursor: not-allowed;
133
+
134
+ &::before {
135
+ content: '';
136
+ position: absolute;
137
+ inset: rem(-1px);
138
+ border-radius: var(--ai-radius);
139
+ background-color: var(--_loading-overlay_bg);
140
+ }
141
+ }
142
+
143
+ &:disabled:not([data-loading]),
144
+ &[data-disabled]:not([data-loading]) {
145
+ --_cursor: not-allowed;
146
+ --_bg: var(--_disabled-bg);
147
+ --_color: var(--_disabled-color);
148
+ }
149
+ }
150
+
151
+ .loader {
152
+ z-index: 1;
153
+ }
154
+ `;
155
+
156
+ function TsIcon(props: React.ComponentProps<'svg'>) {
157
+ return (
158
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width={18} height={18} {...props}>
159
+ <path fill="#1976d2" d="M6 6h36v36H6z" />
160
+ <path
161
+ fill="#fff"
162
+ d="M27.49 22H14.227v3.264h4.757V40h3.769V25.264h4.737zM39.194 26.084s-1.787-1.192-3.807-1.192-2.747.96-2.747 1.986c0 2.648 7.381 2.383 7.381 7.712 0 8.209-11.254 4.568-11.254 4.568V35.22s2.152 1.622 4.733 1.622 2.483-1.688 2.483-1.92c0-2.449-7.315-2.449-7.315-7.878 0-7.381 10.658-4.469 10.658-4.469l-.132 3.509z"
163
+ />
164
+ </svg>
165
+ );
166
+ }
167
+
168
+ function CSSIcon(props: React.ComponentProps<'svg'>) {
169
+ return (
170
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width={18} height={18} {...props}>
171
+ <path fill="#0277BD" d="M41 5H7l3 34 14 4 14-4 3-34z" />
172
+ <path fill="#039BE5" d="M24 8v31.9l11.2-3.2L37.7 8z" />
173
+ <path fill="#FFF" d="M33.1 13H24v4h4.9l-.3 4H24v4h4.4l-.3 4.5-4.1 1.4v4.2l7.9-2.6.7-11.5z" />
174
+ <path
175
+ fill="#EEE"
176
+ d="M24 13v4h-8.9l-.3-4H24zm-4.6 8l.2 4H24v-4h-4.6zm.4 6h-4l.3 5.5 7.9 2.6v-4.2l-4.1-1.4-.1-2.5z"
177
+ />
178
+ </svg>
179
+ );
180
+ }
181
+
182
+ export function Usage() {
183
+ return (
184
+ <div style={{ padding: 40 }}>
185
+ <CodeHighlight code={tsxCode} highlightOnClient />
186
+ </div>
187
+ );
188
+ }
189
+
190
+ export function Tabs() {
191
+ return (
192
+ <div style={{ padding: 40 }}>
193
+ <CodeHighlightTabs
194
+ code={[
195
+ { code: tsxCode, language: 'tsx', icon: <TsIcon />, fileName: 'Component.tsx' },
196
+ { code: cssCode, language: 'css', icon: <CSSIcon />, fileName: 'Component.module.css' },
197
+ ]}
198
+ defaultExpanded={false}
199
+ >
200
+ {tsxCode}
201
+ </CodeHighlightTabs>
202
+ </div>
203
+ );
204
+ }
205
+
206
+ export function Inline() {
207
+ return (
208
+ <div style={{ padding: 40 }}>
209
+ <p>
210
+ Hello there! this is{' '}
211
+ <InlineCodeHighlight code="import React from 'react';" language="tsx" /> some code Lorem
212
+ ipsum dolor sit amet consectetur adipisicing elit. Aliquid reiciendis, facilis repudiandae
213
+ vero mollitia non dolorum cupiditate assumenda odio unde quaerat beatae explicabo veritatis
214
+ nam temporibus! Quibusdam quod enim voluptatibus?
215
+ </p>
216
+ </div>
217
+ );
218
+ }
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { render, tests } from '@mantine/tests';
3
+ import { CodeHighlight, CodeHighlightProps, CodeHighlightStylesNames } from './CodeHighlight';
4
+
5
+ const defaultProps: CodeHighlightProps = {
6
+ code: 'test-code',
7
+ };
8
+
9
+ describe('@mantine/code-highlight/CodeHighlight', () => {
10
+ tests.itSupportsSystemProps<CodeHighlightProps, CodeHighlightStylesNames>({
11
+ component: CodeHighlight,
12
+ props: defaultProps,
13
+ polymorphic: true,
14
+ styleProps: true,
15
+ extend: true,
16
+ variant: true,
17
+ size: true,
18
+ refType: HTMLDivElement,
19
+ displayName: '@mantine/core/CodeHighlight',
20
+ stylesApiSelectors: ['root', 'code', 'copy', 'pre'],
21
+ });
22
+
23
+ it('renders copy button based on withCopyButton prop', () => {
24
+ const { container, rerender } = render(<CodeHighlight {...defaultProps} withCopyButton />);
25
+ expect(container.querySelector('.mantine-CodeHighlight-copy')).toBeInTheDocument();
26
+
27
+ rerender(<CodeHighlight {...defaultProps} withCopyButton={false} />);
28
+ expect(container.querySelector('.mantine-CodeHighlight-copy')).not.toBeInTheDocument();
29
+ });
30
+ });
@@ -0,0 +1,95 @@
1
+ .theme {
2
+ color: var(--_color);
3
+ background: var(--_background);
4
+
5
+ @mixin light {
6
+ --_color: var(--mantine-color-gray-7);
7
+ --_background: var(--mantine-color-gray-0);
8
+ --code-comment-color: var(--mantine-color-gray-6);
9
+ --code-keyword-color: var(--mantine-color-violet-8);
10
+ --code-tag-color: var(--mantine-color-red-9);
11
+ --code-literal-color: var(--mantine-color-blue-6);
12
+ --code-string-color: var(--mantine-color-blue-9);
13
+ --code-variable-color: var(--mantine-color-lime-9);
14
+ --code-class-color: var(--mantine-color-orange-9);
15
+ }
16
+
17
+ @mixin dark {
18
+ --_color: var(--mantine-color-dark-1);
19
+ --_background: var(--mantine-color-dark-8);
20
+ --code-comment-color: var(--mantine-color-dark-3);
21
+ --code-keyword-color: var(--mantine-color-violet-3);
22
+ --code-tag-color: var(--mantine-color-yellow-4);
23
+ --code-literal-color: var(--mantine-color-blue-4);
24
+ --code-string-color: var(--mantine-color-green-6);
25
+ --code-variable-color: var(--mantine-color-blue-2);
26
+ --code-class-color: var(--mantine-color-orange-5);
27
+ }
28
+
29
+ :global(.hljs-comment),
30
+ :global(.hljs-quote) {
31
+ font-style: italic;
32
+ color: var(--code-comment-color);
33
+ }
34
+
35
+ :global(.hljs-doctag),
36
+ :global(.hljs-formula),
37
+ :global(.hljs-keyword) {
38
+ color: var(--code-keyword-color);
39
+ }
40
+
41
+ :global(.hljs-deletion),
42
+ :global(.hljs-name),
43
+ :global(.hljs-section),
44
+ :global(.hljs-selector-tag),
45
+ :global(.hljs-subst) {
46
+ color: var(--code-tag-color);
47
+ }
48
+
49
+ :global(.hljs-literal) {
50
+ color: var(--code-literal-color);
51
+ }
52
+
53
+ :global(.hljs-addition),
54
+ :global(.hljs-attribute),
55
+ :global(.hljs-meta .hljs-string),
56
+ :global(.hljs-regexp),
57
+ :global(.hljs-string) {
58
+ color: var(--code-string-color);
59
+ }
60
+
61
+ :global(.hljs-attr),
62
+ :global(.hljs-number),
63
+ :global(.hljs-selector-attr),
64
+ :global(.hljs-selector-class),
65
+ :global(.hljs-selector-pseudo),
66
+ :global(.hljs-template-variable),
67
+ :global(.hljs-type),
68
+ :global(.hljs-variable) {
69
+ color: var(--code-variable-color);
70
+ }
71
+
72
+ :global(.hljs-bullet),
73
+ :global(.hljs-link),
74
+ :global(.hljs-meta),
75
+ :global(.hljs-selector-id),
76
+ :global(.hljs-symbol),
77
+ :global(.hljs-title),
78
+ :global(.hljs-built_in),
79
+ :global(.hljs-class .hljs-title),
80
+ :global(.hljs-title.class_) {
81
+ color: var(--code-class-color);
82
+ }
83
+
84
+ :global(.hljs-emphasis) {
85
+ font-style: italic;
86
+ }
87
+
88
+ :global(.hljs-strong) {
89
+ font-weight: 700;
90
+ }
91
+
92
+ :global(.hljs-link) {
93
+ text-decoration: underline;
94
+ }
95
+ }
@@ -0,0 +1,123 @@
1
+ import React from 'react';
2
+ import cx from 'clsx';
3
+ import {
4
+ Box,
5
+ BoxProps,
6
+ StylesApiProps,
7
+ factory,
8
+ ElementProps,
9
+ useProps,
10
+ useStyles,
11
+ CopyButton,
12
+ Tooltip,
13
+ ActionIcon,
14
+ ScrollArea,
15
+ Factory,
16
+ } from '@mantine/core';
17
+ import { useHighlight } from './use-highlight';
18
+ import { CopyIcon } from './CopyIcon';
19
+ import _classes from './CodeHighlight.module.css';
20
+ import themeClasses from './CodeHighlight.theme.module.css';
21
+
22
+ const classes = { ..._classes, root: cx(_classes.root, themeClasses.theme) };
23
+
24
+ export type CodeHighlightStylesNames = 'root' | 'code' | 'pre' | 'copy';
25
+ export type CodeHighlightVariant = string;
26
+
27
+ export interface CodeHighlightProps
28
+ extends BoxProps,
29
+ StylesApiProps<CodeHighlightFactory>,
30
+ ElementProps<'div'> {
31
+ /** Code to highlight */
32
+ code: string;
33
+
34
+ /** Code language, `'tsx'` by default */
35
+ language?: string;
36
+
37
+ /** Determines whether copy button should be displayed, `true` by default */
38
+ withCopyButton?: boolean;
39
+
40
+ /** Copy tooltip label, `'Copy code'` by default */
41
+ copyLabel?: string;
42
+
43
+ /** Copied tooltip label, `'Copied'` by default */
44
+ copiedLabel?: string;
45
+
46
+ /** Determines whether code should be highlighted only after component is mounted to the dom (disables code highlight on server), `false` by default */
47
+ highlightOnClient?: boolean;
48
+ }
49
+
50
+ export type CodeHighlightFactory = Factory<{
51
+ props: CodeHighlightProps;
52
+ ref: HTMLDivElement;
53
+ stylesNames: CodeHighlightStylesNames;
54
+ variant: CodeHighlightVariant;
55
+ }>;
56
+
57
+ const defaultProps: Partial<CodeHighlightProps> = {
58
+ copyLabel: 'Copy code',
59
+ copiedLabel: 'Copied',
60
+ language: 'tsx',
61
+ withCopyButton: true,
62
+ };
63
+
64
+ export const CodeHighlight = factory<CodeHighlightFactory>((_props, ref) => {
65
+ const props = useProps('CodeHighlight', defaultProps, _props);
66
+ const {
67
+ classNames,
68
+ className,
69
+ style,
70
+ styles,
71
+ unstyled,
72
+ vars,
73
+ children,
74
+ code,
75
+ copiedLabel,
76
+ copyLabel,
77
+ language,
78
+ withCopyButton,
79
+ highlightOnClient,
80
+ ...others
81
+ } = props;
82
+
83
+ const getStyles = useStyles<CodeHighlightFactory>({
84
+ name: 'CodeHighlight',
85
+ props,
86
+ classes,
87
+ className,
88
+ style,
89
+ classNames,
90
+ styles,
91
+ unstyled,
92
+ });
93
+
94
+ const getCodeProps = useHighlight({
95
+ code,
96
+ language: language!,
97
+ highlightOnClient,
98
+ });
99
+
100
+ return (
101
+ <Box {...getStyles('root')} ref={ref} {...others} dir="ltr">
102
+ {withCopyButton && (
103
+ <CopyButton value={code.trim()}>
104
+ {({ copied, copy }) => (
105
+ <Tooltip label={copied ? copiedLabel : copyLabel} fz="sm" position="left">
106
+ <ActionIcon onClick={copy} variant="none" {...getStyles('copy')}>
107
+ <CopyIcon copied={copied} />
108
+ </ActionIcon>
109
+ </Tooltip>
110
+ )}
111
+ </CopyButton>
112
+ )}
113
+
114
+ <ScrollArea type="auto" dir="ltr" offsetScrollbars={false}>
115
+ <pre {...getStyles('pre')}>
116
+ <code {...getStyles('code')} {...getCodeProps()} />
117
+ </pre>
118
+ </ScrollArea>
119
+ </Box>
120
+ );
121
+ });
122
+
123
+ CodeHighlight.displayName = '@mantine/core/CodeHighlight';
@@ -0,0 +1,39 @@
1
+ import { tests } from '@mantine/tests';
2
+ import {
3
+ CodeHighlightTabs,
4
+ CodeHighlightTabsProps,
5
+ CodeHighlightTabsStylesNames,
6
+ } from './CodeHighlightTabs';
7
+
8
+ const defaultProps: CodeHighlightTabsProps = {
9
+ code: [
10
+ { fileName: 'Demo.tsx', language: 'tsx', code: 'test-tsx' },
11
+ { fileName: 'Demo.module.css', language: 'css', code: 'test-css' },
12
+ ],
13
+ };
14
+
15
+ describe('@mantine/code-highlight/CodeHighlightTabs', () => {
16
+ tests.itSupportsSystemProps<CodeHighlightTabsProps, CodeHighlightTabsStylesNames>({
17
+ component: CodeHighlightTabs,
18
+ props: defaultProps,
19
+ polymorphic: true,
20
+ styleProps: true,
21
+ extend: true,
22
+ variant: true,
23
+ size: true,
24
+ refType: HTMLDivElement,
25
+ displayName: '@mantine/core/CodeHighlightTabs',
26
+ stylesApiSelectors: [
27
+ 'root',
28
+ 'code',
29
+ 'codeWrapper',
30
+ 'control',
31
+ 'controls',
32
+ 'file',
33
+ 'files',
34
+ 'header',
35
+ 'pre',
36
+ 'showCodeButton',
37
+ ],
38
+ });
39
+ });