@snack-uikit/code-editor 0.6.4 → 0.6.5-preview-6c5a9bc3.0
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.
- package/README.md +2 -0
- package/dist/cjs/components/CodeEditor.d.ts +9 -1
- package/dist/cjs/components/CodeEditor.js +18 -5
- package/dist/cjs/components/CopyButton/CopyButton.d.ts +9 -0
- package/dist/cjs/components/CopyButton/CopyButton.js +69 -0
- package/dist/cjs/components/CopyButton/index.d.ts +1 -0
- package/dist/cjs/components/CopyButton/index.js +25 -0
- package/dist/cjs/components/CopyButton/styles.module.css +3 -0
- package/dist/cjs/components/styles.module.css +11 -0
- package/dist/cjs/components/utils.d.ts +1 -0
- package/dist/cjs/components/utils.js +10 -1
- package/dist/esm/components/CodeEditor.d.ts +9 -1
- package/dist/esm/components/CodeEditor.js +6 -4
- package/dist/esm/components/CopyButton/CopyButton.d.ts +9 -0
- package/dist/esm/components/CopyButton/CopyButton.js +41 -0
- package/dist/esm/components/CopyButton/index.d.ts +1 -0
- package/dist/esm/components/CopyButton/index.js +1 -0
- package/dist/esm/components/CopyButton/styles.module.css +3 -0
- package/dist/esm/components/styles.module.css +11 -0
- package/dist/esm/components/utils.d.ts +1 -0
- package/dist/esm/components/utils.js +8 -0
- package/package.json +8 -2
- package/src/components/CodeEditor.tsx +19 -1
- package/src/components/CopyButton/CopyButton.tsx +56 -0
- package/src/components/CopyButton/index.ts +1 -0
- package/src/components/CopyButton/styles.module.scss +6 -0
- package/src/components/styles.module.scss +17 -3
- package/src/components/utils.ts +10 -0
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
| jsonSchema* | `JsonSchema` | - | Схема для валидации |
|
|
16
16
|
| themeName | `string` | - | Название текущей темы. Значение не важно, важно что смена значения запускает пересчет стилей. |
|
|
17
17
|
| hasBackground | `boolean` | true | Включение/отключение псевдобекграунда |
|
|
18
|
+
| hasCopyHeader | `boolean` | - | Включение/отключение шапки с кнопкой копирования |
|
|
19
|
+
| onCopyClick | `() => void` | - | Клик по кнопке копирования |
|
|
18
20
|
| defaultValue | `string` | - | Default value of the current model |
|
|
19
21
|
| defaultLanguage | `string` | - | Default language of the current model |
|
|
20
22
|
| defaultPath | `string` | - | Default path of the current model Will be passed as the third argument to `.createModel` method `monaco.editor.createModel(..., ..., monaco.Uri.parse(defaultPath))` |
|
|
@@ -9,5 +9,13 @@ export type CodeEditorProps = WithSupportProps<{
|
|
|
9
9
|
* Включение/отключение псевдобекграунда
|
|
10
10
|
*/
|
|
11
11
|
hasBackground?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Включение/отключение шапки с кнопкой копирования
|
|
14
|
+
*/
|
|
15
|
+
hasCopyHeader?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Клик по кнопке копирования
|
|
18
|
+
*/
|
|
19
|
+
onCopyClick?(): void;
|
|
12
20
|
}> & (EditorBaseProps | EditorWithJsonSchemaProps);
|
|
13
|
-
export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, onCopyClick, hasCopyHeader, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -22,8 +22,10 @@ const react_1 = require("@monaco-editor/react");
|
|
|
22
22
|
const classnames_1 = __importDefault(require("classnames"));
|
|
23
23
|
const react_2 = require("react");
|
|
24
24
|
const loaders_1 = require("@snack-uikit/loaders");
|
|
25
|
+
const typography_1 = require("@snack-uikit/typography");
|
|
25
26
|
const utils_1 = require("@snack-uikit/utils");
|
|
26
27
|
const constants_1 = require("./constants");
|
|
28
|
+
const CopyButton_1 = require("./CopyButton");
|
|
27
29
|
const hooks_1 = require("./hooks");
|
|
28
30
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
29
31
|
const utils_2 = require("./utils");
|
|
@@ -36,9 +38,11 @@ function CodeEditor(_a) {
|
|
|
36
38
|
loading,
|
|
37
39
|
hasBackground = true,
|
|
38
40
|
onMount,
|
|
39
|
-
language
|
|
41
|
+
language,
|
|
42
|
+
onCopyClick,
|
|
43
|
+
hasCopyHeader
|
|
40
44
|
} = _a,
|
|
41
|
-
props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language"]);
|
|
45
|
+
props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language", "onCopyClick", "hasCopyHeader"]);
|
|
42
46
|
const monaco = (0, react_1.useMonaco)();
|
|
43
47
|
const [wrapperElement, setWrapperElement] = (0, react_2.useState)(null);
|
|
44
48
|
const {
|
|
@@ -111,11 +115,20 @@ function CodeEditor(_a) {
|
|
|
111
115
|
fontWeight: themeValues.mono.body.s['font-weight'],
|
|
112
116
|
fontFamily: themeValues.mono.body.s['font-family']
|
|
113
117
|
} : constants_1.DEFAULT_THEME_OPTIONS.mono.s), options), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono, jsonSchemaOptions]);
|
|
114
|
-
return (0, jsx_runtime_1.
|
|
118
|
+
return (0, jsx_runtime_1.jsxs)("div", Object.assign({
|
|
115
119
|
className: className
|
|
116
120
|
}, (0, utils_1.extractSupportProps)(props), {
|
|
117
121
|
ref: setWrapperElement,
|
|
118
|
-
children: (0, jsx_runtime_1.
|
|
122
|
+
children: [hasCopyHeader && (0, jsx_runtime_1.jsxs)("div", {
|
|
123
|
+
className: styles_module_scss_1.default.headline,
|
|
124
|
+
children: [language && (0, jsx_runtime_1.jsx)(typography_1.Typography.SansLabelS, {
|
|
125
|
+
children: (0, utils_2.toTitleCase)(language)
|
|
126
|
+
}), (0, jsx_runtime_1.jsx)(CopyButton_1.CopyButton, {
|
|
127
|
+
valueToCopy: props.value || '',
|
|
128
|
+
size: 's',
|
|
129
|
+
onClick: onCopyClick
|
|
130
|
+
})]
|
|
131
|
+
}), (0, jsx_runtime_1.jsx)(react_1.Editor, Object.assign({}, jsonSchemaProps, props, {
|
|
119
132
|
theme: theme !== null && theme !== void 0 ? theme : dark ? 'snackDark' : 'snack',
|
|
120
133
|
className: (0, classnames_1.default)({
|
|
121
134
|
[styles_module_scss_1.default.editor]: hasBackground
|
|
@@ -124,6 +137,6 @@ function CodeEditor(_a) {
|
|
|
124
137
|
options: mergedOptions,
|
|
125
138
|
onMount: onEditorMount,
|
|
126
139
|
language: language
|
|
127
|
-
}))
|
|
140
|
+
}))]
|
|
128
141
|
}));
|
|
129
142
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ButtonFunctionProps } from '@snack-uikit/button';
|
|
2
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
3
|
+
export type CopyButtonProps = WithSupportProps<{
|
|
4
|
+
valueToCopy: string | number;
|
|
5
|
+
size?: ButtonFunctionProps['size'];
|
|
6
|
+
className?: string;
|
|
7
|
+
onClick?: ButtonFunctionProps['onClick'];
|
|
8
|
+
}>;
|
|
9
|
+
export declare function CopyButton({ valueToCopy, size, className, onClick, ...rest }: CopyButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var __rest = void 0 && (void 0).__rest || function (s, e) {
|
|
4
|
+
var t = {};
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
|
|
12
|
+
return mod && mod.__esModule ? mod : {
|
|
13
|
+
"default": mod
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", {
|
|
17
|
+
value: true
|
|
18
|
+
});
|
|
19
|
+
exports.CopyButton = CopyButton;
|
|
20
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
21
|
+
const react_1 = require("react");
|
|
22
|
+
const frontend_tools_copy_to_clipboard_1 = require("@cloud-ru/frontend-tools-copy-to-clipboard");
|
|
23
|
+
const button_1 = require("@snack-uikit/button");
|
|
24
|
+
const icons_1 = require("@snack-uikit/icons");
|
|
25
|
+
const locale_1 = require("@snack-uikit/locale");
|
|
26
|
+
const tooltip_1 = require("@snack-uikit/tooltip");
|
|
27
|
+
const utils_1 = require("@snack-uikit/utils");
|
|
28
|
+
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
29
|
+
function CopyButton(_a) {
|
|
30
|
+
var {
|
|
31
|
+
valueToCopy,
|
|
32
|
+
size = 's',
|
|
33
|
+
className,
|
|
34
|
+
onClick
|
|
35
|
+
} = _a,
|
|
36
|
+
rest = __rest(_a, ["valueToCopy", "size", "className", "onClick"]);
|
|
37
|
+
const {
|
|
38
|
+
t
|
|
39
|
+
} = (0, locale_1.useLocale)();
|
|
40
|
+
const [isChecked, setIsCheckedOpen] = (0, react_1.useState)(false);
|
|
41
|
+
const timerId = (0, react_1.useRef)();
|
|
42
|
+
const openChecked = () => setIsCheckedOpen(true);
|
|
43
|
+
const closeChecked = () => setIsCheckedOpen(false);
|
|
44
|
+
const handleClick = event => {
|
|
45
|
+
event.stopPropagation();
|
|
46
|
+
valueToCopy && (0, frontend_tools_copy_to_clipboard_1.copyToClipboard)(String(valueToCopy));
|
|
47
|
+
openChecked();
|
|
48
|
+
clearTimeout(timerId.current);
|
|
49
|
+
timerId.current = setTimeout(closeChecked, 1000);
|
|
50
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
51
|
+
};
|
|
52
|
+
(0, react_1.useEffect)(() => () => {
|
|
53
|
+
closeChecked();
|
|
54
|
+
clearTimeout(timerId.current);
|
|
55
|
+
}, []);
|
|
56
|
+
return (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, {
|
|
57
|
+
tip: t('CodeEditor.copyButtonToolTip'),
|
|
58
|
+
children: (0, jsx_runtime_1.jsx)(button_1.ButtonFunction, Object.assign({}, (0, utils_1.extractSupportProps)(rest), {
|
|
59
|
+
onClick: handleClick,
|
|
60
|
+
className: className,
|
|
61
|
+
"data-test-id": 'button-copy-value',
|
|
62
|
+
type: 'button',
|
|
63
|
+
icon: isChecked ? (0, jsx_runtime_1.jsx)(icons_1.CheckSVG, {
|
|
64
|
+
className: styles_module_scss_1.default.checkIcon
|
|
65
|
+
}) : (0, jsx_runtime_1.jsx)(icons_1.CopySVG, {}),
|
|
66
|
+
size: size
|
|
67
|
+
}))
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return m[k];
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
} : function (o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
});
|
|
19
|
+
var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", {
|
|
23
|
+
value: true
|
|
24
|
+
});
|
|
25
|
+
__exportStar(require("./CopyButton"), exports);
|
|
@@ -10,4 +10,15 @@
|
|
|
10
10
|
width:100%;
|
|
11
11
|
opacity:var(--opacity-a004, 0.04);
|
|
12
12
|
background-color:var(--sys-neutral-accent-default, #787b8a);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.headline{
|
|
16
|
+
min-height:var(--size-markdown-code-editor-headline-min-height, 36px);
|
|
17
|
+
padding-left:var(--space-markdown-code-editor-headline-horizontal-padding, 12px);
|
|
18
|
+
padding-right:var(--space-markdown-code-editor-headline-horizontal-padding, 12px);
|
|
19
|
+
display:flex;
|
|
20
|
+
align-items:center;
|
|
21
|
+
justify-content:space-between;
|
|
22
|
+
background-color:var(--sys-neutral-background, #eeeff3);
|
|
23
|
+
border-color:var(--sys-neutral-decor-default, #dde0ea);
|
|
13
24
|
}
|
|
@@ -3,3 +3,4 @@ import { JsonSchema } from './types';
|
|
|
3
3
|
export declare function rgb2hsl(HTMLcolor: string): number[];
|
|
4
4
|
export declare function isDark(color: string): boolean;
|
|
5
5
|
export declare const getJsonSchema: (jsonSchema?: JsonSchema) => SchemasSettings | undefined;
|
|
6
|
+
export declare function toTitleCase(value: string): string;
|
|
@@ -11,6 +11,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
11
11
|
exports.getJsonSchema = void 0;
|
|
12
12
|
exports.rgb2hsl = rgb2hsl;
|
|
13
13
|
exports.isDark = isDark;
|
|
14
|
+
exports.toTitleCase = toTitleCase;
|
|
14
15
|
const chroma_js_1 = __importDefault(require("chroma-js"));
|
|
15
16
|
const constants_1 = require("./constants");
|
|
16
17
|
function rgb2hsl(HTMLcolor) {
|
|
@@ -50,4 +51,12 @@ const getJsonSchema = jsonSchema => jsonSchema && Object.assign(Object.assign({}
|
|
|
50
51
|
uri: (jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.uri) || constants_1.DEFAULT_SCHEMA_URI,
|
|
51
52
|
fileMatch: [jsonSchema.fileMatch]
|
|
52
53
|
});
|
|
53
|
-
exports.getJsonSchema = getJsonSchema;
|
|
54
|
+
exports.getJsonSchema = getJsonSchema;
|
|
55
|
+
function toTitleCase(value) {
|
|
56
|
+
if (value.trim().length === 0) {
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
const valueLetters = value.trim().split('');
|
|
60
|
+
valueLetters[0] = valueLetters[0].toUpperCase();
|
|
61
|
+
return valueLetters.join('');
|
|
62
|
+
}
|
|
@@ -9,5 +9,13 @@ export type CodeEditorProps = WithSupportProps<{
|
|
|
9
9
|
* Включение/отключение псевдобекграунда
|
|
10
10
|
*/
|
|
11
11
|
hasBackground?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Включение/отключение шапки с кнопкой копирования
|
|
14
|
+
*/
|
|
15
|
+
hasCopyHeader?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Клик по кнопке копирования
|
|
18
|
+
*/
|
|
19
|
+
onCopyClick?(): void;
|
|
12
20
|
}> & (EditorBaseProps | EditorWithJsonSchemaProps);
|
|
13
|
-
export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, onCopyClick, hasCopyHeader, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,18 +9,20 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { Editor, useMonaco } from '@monaco-editor/react';
|
|
14
14
|
import cn from 'classnames';
|
|
15
15
|
import { useCallback, useMemo, useState } from 'react';
|
|
16
16
|
import { Spinner } from '@snack-uikit/loaders';
|
|
17
|
+
import { Typography } from '@snack-uikit/typography';
|
|
17
18
|
import { extractSupportProps, isBrowser } from '@snack-uikit/utils';
|
|
18
19
|
import { CODE_EDITOR_OPTIONS, DEFAULT_THEME_OPTIONS, DEFAULT_THEME_VALUES } from './constants';
|
|
20
|
+
import { CopyButton } from './CopyButton';
|
|
19
21
|
import { useApplyJsonSchema, useCalculatedThemeValues } from './hooks';
|
|
20
22
|
import styles from './styles.module.css';
|
|
21
|
-
import { isDark } from './utils';
|
|
23
|
+
import { isDark, toTitleCase } from './utils';
|
|
22
24
|
export function CodeEditor(_a) {
|
|
23
|
-
var { themeName, className, theme, options, loading, hasBackground = true, onMount, language } = _a, props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language"]);
|
|
25
|
+
var { themeName, className, theme, options, loading, hasBackground = true, onMount, language, onCopyClick, hasCopyHeader } = _a, props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language", "onCopyClick", "hasCopyHeader"]);
|
|
24
26
|
const monaco = useMonaco();
|
|
25
27
|
const [wrapperElement, setWrapperElement] = useState(null);
|
|
26
28
|
const { jsonSchemaProps, jsonSchemaOptions } = useApplyJsonSchema(language, 'jsonSchema' in props ? props.jsonSchema : undefined);
|
|
@@ -87,5 +89,5 @@ export function CodeEditor(_a) {
|
|
|
87
89
|
fontFamily: themeValues.mono.body.s['font-family'],
|
|
88
90
|
}
|
|
89
91
|
: DEFAULT_THEME_OPTIONS.mono.s)), options)), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono, jsonSchemaOptions]);
|
|
90
|
-
return (
|
|
92
|
+
return (_jsxs("div", Object.assign({ className: className }, extractSupportProps(props), { ref: setWrapperElement, children: [hasCopyHeader && (_jsxs("div", { className: styles.headline, children: [language && _jsx(Typography.SansLabelS, { children: toTitleCase(language) }), _jsx(CopyButton, { valueToCopy: props.value || '', size: 's', onClick: onCopyClick })] })), _jsx(Editor, Object.assign({}, jsonSchemaProps, props, { theme: theme !== null && theme !== void 0 ? theme : (dark ? 'snackDark' : 'snack'), className: cn({ [styles.editor]: hasBackground }), loading: loading !== null && loading !== void 0 ? loading : _jsx(Spinner, {}), options: mergedOptions, onMount: onEditorMount, language: language }))] })));
|
|
91
93
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ButtonFunctionProps } from '@snack-uikit/button';
|
|
2
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
3
|
+
export type CopyButtonProps = WithSupportProps<{
|
|
4
|
+
valueToCopy: string | number;
|
|
5
|
+
size?: ButtonFunctionProps['size'];
|
|
6
|
+
className?: string;
|
|
7
|
+
onClick?: ButtonFunctionProps['onClick'];
|
|
8
|
+
}>;
|
|
9
|
+
export declare function CopyButton({ valueToCopy, size, className, onClick, ...rest }: CopyButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { copyToClipboard } from '@cloud-ru/frontend-tools-copy-to-clipboard';
|
|
15
|
+
import { ButtonFunction } from '@snack-uikit/button';
|
|
16
|
+
import { CheckSVG, CopySVG } from '@snack-uikit/icons';
|
|
17
|
+
import { useLocale } from '@snack-uikit/locale';
|
|
18
|
+
import { Tooltip } from '@snack-uikit/tooltip';
|
|
19
|
+
import { extractSupportProps } from '@snack-uikit/utils';
|
|
20
|
+
import styles from './styles.module.css';
|
|
21
|
+
export function CopyButton(_a) {
|
|
22
|
+
var { valueToCopy, size = 's', className, onClick } = _a, rest = __rest(_a, ["valueToCopy", "size", "className", "onClick"]);
|
|
23
|
+
const { t } = useLocale();
|
|
24
|
+
const [isChecked, setIsCheckedOpen] = useState(false);
|
|
25
|
+
const timerId = useRef();
|
|
26
|
+
const openChecked = () => setIsCheckedOpen(true);
|
|
27
|
+
const closeChecked = () => setIsCheckedOpen(false);
|
|
28
|
+
const handleClick = event => {
|
|
29
|
+
event.stopPropagation();
|
|
30
|
+
valueToCopy && copyToClipboard(String(valueToCopy));
|
|
31
|
+
openChecked();
|
|
32
|
+
clearTimeout(timerId.current);
|
|
33
|
+
timerId.current = setTimeout(closeChecked, 1000);
|
|
34
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
35
|
+
};
|
|
36
|
+
useEffect(() => () => {
|
|
37
|
+
closeChecked();
|
|
38
|
+
clearTimeout(timerId.current);
|
|
39
|
+
}, []);
|
|
40
|
+
return (_jsx(Tooltip, { tip: t('CodeEditor.copyButtonToolTip'), children: _jsx(ButtonFunction, Object.assign({}, extractSupportProps(rest), { onClick: handleClick, className: className, "data-test-id": 'button-copy-value', type: 'button', icon: isChecked ? _jsx(CheckSVG, { className: styles.checkIcon }) : _jsx(CopySVG, {}), size: size })) }));
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -10,4 +10,15 @@
|
|
|
10
10
|
width:100%;
|
|
11
11
|
opacity:var(--opacity-a004, 0.04);
|
|
12
12
|
background-color:var(--sys-neutral-accent-default, #787b8a);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.headline{
|
|
16
|
+
min-height:var(--size-markdown-code-editor-headline-min-height, 36px);
|
|
17
|
+
padding-left:var(--space-markdown-code-editor-headline-horizontal-padding, 12px);
|
|
18
|
+
padding-right:var(--space-markdown-code-editor-headline-horizontal-padding, 12px);
|
|
19
|
+
display:flex;
|
|
20
|
+
align-items:center;
|
|
21
|
+
justify-content:space-between;
|
|
22
|
+
background-color:var(--sys-neutral-background, #eeeff3);
|
|
23
|
+
border-color:var(--sys-neutral-decor-default, #dde0ea);
|
|
13
24
|
}
|
|
@@ -3,3 +3,4 @@ import { JsonSchema } from './types';
|
|
|
3
3
|
export declare function rgb2hsl(HTMLcolor: string): number[];
|
|
4
4
|
export declare function isDark(color: string): boolean;
|
|
5
5
|
export declare const getJsonSchema: (jsonSchema?: JsonSchema) => SchemasSettings | undefined;
|
|
6
|
+
export declare function toTitleCase(value: string): string;
|
|
@@ -38,3 +38,11 @@ export function isDark(color) {
|
|
|
38
38
|
return (h < 0.55 && l >= 0.5) || (h >= 0.55 && l >= 0.75);
|
|
39
39
|
}
|
|
40
40
|
export const getJsonSchema = (jsonSchema) => jsonSchema && Object.assign(Object.assign({}, jsonSchema), { uri: (jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.uri) || DEFAULT_SCHEMA_URI, fileMatch: [jsonSchema.fileMatch] });
|
|
41
|
+
export function toTitleCase(value) {
|
|
42
|
+
if (value.trim().length === 0) {
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
const valueLetters = value.trim().split('');
|
|
46
|
+
valueLetters[0] = valueLetters[0].toUpperCase();
|
|
47
|
+
return valueLetters.join('');
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.6.
|
|
7
|
+
"version": "0.6.5-preview-6c5a9bc3.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -36,8 +36,14 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"scripts": {},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"@cloud-ru/frontend-tools-copy-to-clipboard": "0.0.1-preview-8188049.0",
|
|
39
40
|
"@monaco-editor/react": "4.6.0",
|
|
41
|
+
"@snack-uikit/button": "0.19.11",
|
|
42
|
+
"@snack-uikit/icons": "0.26.3",
|
|
40
43
|
"@snack-uikit/loaders": "0.9.5",
|
|
44
|
+
"@snack-uikit/locale": "0.14.1-preview-6c5a9bc3.0",
|
|
45
|
+
"@snack-uikit/tooltip": "0.17.2",
|
|
46
|
+
"@snack-uikit/typography": "0.8.7",
|
|
41
47
|
"@snack-uikit/utils": "3.8.2",
|
|
42
48
|
"chroma-js": "3.1.2",
|
|
43
49
|
"classnames": "2.5.1",
|
|
@@ -46,5 +52,5 @@
|
|
|
46
52
|
"devDependencies": {
|
|
47
53
|
"@types/chroma-js": "2.4.4"
|
|
48
54
|
},
|
|
49
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "f7b20fc5008846a7aaddf93c2cbeb6197978e97f"
|
|
50
56
|
}
|
|
@@ -3,13 +3,15 @@ import cn from 'classnames';
|
|
|
3
3
|
import { useCallback, useMemo, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { Spinner } from '@snack-uikit/loaders';
|
|
6
|
+
import { Typography } from '@snack-uikit/typography';
|
|
6
7
|
import { extractSupportProps, isBrowser, WithSupportProps } from '@snack-uikit/utils';
|
|
7
8
|
|
|
8
9
|
import { CODE_EDITOR_OPTIONS, DEFAULT_THEME_OPTIONS, DEFAULT_THEME_VALUES } from './constants';
|
|
10
|
+
import { CopyButton } from './CopyButton';
|
|
9
11
|
import { useApplyJsonSchema, useCalculatedThemeValues } from './hooks';
|
|
10
12
|
import styles from './styles.module.scss';
|
|
11
13
|
import { EditorBaseProps, EditorWithJsonSchemaProps } from './types';
|
|
12
|
-
import { isDark } from './utils';
|
|
14
|
+
import { isDark, toTitleCase } from './utils';
|
|
13
15
|
|
|
14
16
|
export type CodeEditorProps = WithSupportProps<{
|
|
15
17
|
/**
|
|
@@ -20,6 +22,14 @@ export type CodeEditorProps = WithSupportProps<{
|
|
|
20
22
|
* Включение/отключение псевдобекграунда
|
|
21
23
|
*/
|
|
22
24
|
hasBackground?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Включение/отключение шапки с кнопкой копирования
|
|
27
|
+
*/
|
|
28
|
+
hasCopyHeader?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Клик по кнопке копирования
|
|
31
|
+
*/
|
|
32
|
+
onCopyClick?(): void;
|
|
23
33
|
}> &
|
|
24
34
|
(EditorBaseProps | EditorWithJsonSchemaProps);
|
|
25
35
|
|
|
@@ -32,6 +42,8 @@ export function CodeEditor({
|
|
|
32
42
|
hasBackground = true,
|
|
33
43
|
onMount,
|
|
34
44
|
language,
|
|
45
|
+
onCopyClick,
|
|
46
|
+
hasCopyHeader,
|
|
35
47
|
...props
|
|
36
48
|
}: CodeEditorProps) {
|
|
37
49
|
const monaco = useMonaco();
|
|
@@ -132,6 +144,12 @@ export function CodeEditor({
|
|
|
132
144
|
|
|
133
145
|
return (
|
|
134
146
|
<div className={className} {...extractSupportProps(props)} ref={setWrapperElement}>
|
|
147
|
+
{hasCopyHeader && (
|
|
148
|
+
<div className={styles.headline}>
|
|
149
|
+
{language && <Typography.SansLabelS>{toTitleCase(language)}</Typography.SansLabelS>}
|
|
150
|
+
<CopyButton valueToCopy={props.value || ''} size={'s'} onClick={onCopyClick} />
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
135
153
|
<Editor
|
|
136
154
|
{...jsonSchemaProps}
|
|
137
155
|
{...props}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MouseEventHandler, useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { copyToClipboard } from '@cloud-ru/frontend-tools-copy-to-clipboard';
|
|
4
|
+
import { ButtonFunction, ButtonFunctionProps } from '@snack-uikit/button';
|
|
5
|
+
import { CheckSVG, CopySVG } from '@snack-uikit/icons';
|
|
6
|
+
import { useLocale } from '@snack-uikit/locale';
|
|
7
|
+
import { Tooltip } from '@snack-uikit/tooltip';
|
|
8
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
9
|
+
|
|
10
|
+
import styles from './styles.module.scss';
|
|
11
|
+
|
|
12
|
+
export type CopyButtonProps = WithSupportProps<{
|
|
13
|
+
valueToCopy: string | number;
|
|
14
|
+
size?: ButtonFunctionProps['size'];
|
|
15
|
+
className?: string;
|
|
16
|
+
onClick?: ButtonFunctionProps['onClick'];
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export function CopyButton({ valueToCopy, size = 's', className, onClick, ...rest }: CopyButtonProps) {
|
|
20
|
+
const { t } = useLocale();
|
|
21
|
+
const [isChecked, setIsCheckedOpen] = useState(false);
|
|
22
|
+
const timerId = useRef<NodeJS.Timeout>();
|
|
23
|
+
const openChecked = () => setIsCheckedOpen(true);
|
|
24
|
+
const closeChecked = () => setIsCheckedOpen(false);
|
|
25
|
+
|
|
26
|
+
const handleClick: MouseEventHandler<HTMLButtonElement> = event => {
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
valueToCopy && copyToClipboard(String(valueToCopy));
|
|
29
|
+
openChecked();
|
|
30
|
+
clearTimeout(timerId.current);
|
|
31
|
+
timerId.current = setTimeout(closeChecked, 1000);
|
|
32
|
+
onClick?.(event);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
useEffect(
|
|
36
|
+
() => () => {
|
|
37
|
+
closeChecked();
|
|
38
|
+
clearTimeout(timerId.current);
|
|
39
|
+
},
|
|
40
|
+
[],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Tooltip tip={t('CodeEditor.copyButtonToolTip')}>
|
|
45
|
+
<ButtonFunction
|
|
46
|
+
{...extractSupportProps(rest)}
|
|
47
|
+
onClick={handleClick}
|
|
48
|
+
className={className}
|
|
49
|
+
data-test-id='button-copy-value'
|
|
50
|
+
type='button'
|
|
51
|
+
icon={isChecked ? <CheckSVG className={styles.checkIcon} /> : <CopySVG />}
|
|
52
|
+
size={size}
|
|
53
|
+
/>
|
|
54
|
+
</Tooltip>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CopyButton';
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
@use '@snack-uikit/figma-tokens/build/scss/styles-theme-variables';
|
|
1
|
+
@use '@snack-uikit/figma-tokens/build/scss/styles-theme-variables' as var;
|
|
2
|
+
@use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-markdown' as stm;
|
|
3
|
+
|
|
4
|
+
|
|
2
5
|
|
|
3
6
|
.editor {
|
|
4
7
|
background-color: inherit;
|
|
@@ -13,7 +16,18 @@
|
|
|
13
16
|
|
|
14
17
|
width: 100%;
|
|
15
18
|
|
|
16
|
-
opacity:
|
|
17
|
-
background-color:
|
|
19
|
+
opacity: var.$opacity-a004;
|
|
20
|
+
background-color: var.$sys-neutral-accent-default;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
23
|
+
|
|
24
|
+
.headline {
|
|
25
|
+
@include stm.composite-var(stm.$markdown-syntax-code-editor-headline);
|
|
26
|
+
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
|
|
31
|
+
background-color: stm.$sys-neutral-background;
|
|
32
|
+
border-color: stm.$sys-neutral-decor-default;
|
|
33
|
+
}
|
package/src/components/utils.ts
CHANGED
|
@@ -56,3 +56,13 @@ export function isDark(color: string) {
|
|
|
56
56
|
|
|
57
57
|
export const getJsonSchema = (jsonSchema?: JsonSchema): SchemasSettings | undefined =>
|
|
58
58
|
jsonSchema && { ...jsonSchema, uri: jsonSchema?.uri || DEFAULT_SCHEMA_URI, fileMatch: [jsonSchema.fileMatch] };
|
|
59
|
+
|
|
60
|
+
export function toTitleCase(value: string) {
|
|
61
|
+
if (value.trim().length === 0) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const valueLetters = value.trim().split('');
|
|
66
|
+
valueLetters[0] = valueLetters[0].toUpperCase();
|
|
67
|
+
return valueLetters.join('');
|
|
68
|
+
}
|