@snack-uikit/code-editor 0.4.7 → 0.5.1-preview-d4775873.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +16 -0
  3. package/dist/cjs/components/CodeEditor.d.ts +3 -3
  4. package/dist/cjs/components/CodeEditor.js +14 -6
  5. package/dist/cjs/components/constants.d.ts +6 -0
  6. package/dist/cjs/components/constants.js +8 -2
  7. package/dist/cjs/components/hooks.d.ts +8 -0
  8. package/dist/cjs/components/hooks.js +97 -3
  9. package/dist/cjs/components/index.d.ts +1 -0
  10. package/dist/cjs/components/index.js +2 -1
  11. package/dist/cjs/components/types.d.ts +32 -0
  12. package/dist/cjs/components/types.js +5 -0
  13. package/dist/cjs/components/utils.d.ts +3 -0
  14. package/dist/cjs/components/utils.js +8 -1
  15. package/dist/cjs/index.d.ts +1 -1
  16. package/dist/cjs/index.js +7 -1
  17. package/dist/esm/components/CodeEditor.d.ts +3 -3
  18. package/dist/esm/components/CodeEditor.js +7 -5
  19. package/dist/esm/components/constants.d.ts +6 -0
  20. package/dist/esm/components/constants.js +6 -0
  21. package/dist/esm/components/hooks.d.ts +8 -0
  22. package/dist/esm/components/hooks.js +85 -2
  23. package/dist/esm/components/index.d.ts +1 -0
  24. package/dist/esm/components/index.js +1 -0
  25. package/dist/esm/components/types.d.ts +32 -0
  26. package/dist/esm/components/types.js +1 -0
  27. package/dist/esm/components/utils.d.ts +3 -0
  28. package/dist/esm/components/utils.js +2 -0
  29. package/dist/esm/index.d.ts +1 -1
  30. package/dist/esm/index.js +1 -1
  31. package/package.json +4 -3
  32. package/src/components/CodeEditor.tsx +17 -4
  33. package/src/components/constants.ts +8 -0
  34. package/src/components/hooks.ts +103 -2
  35. package/src/components/index.ts +1 -0
  36. package/src/components/types.ts +42 -0
  37. package/src/components/utils.ts +7 -0
  38. package/src/index.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 0.5.0 (2025-02-07)
7
+
8
+
9
+ ### Features
10
+
11
+ * **PDS-1445:** support json schema for yaml, json languages ([a709fe5](https://git.sbercloud.tech/sbercloud-ui/tokens-design-system/snack-uikit/commits/a709fe5e061917c5017de1bd1b6f01c15f4b3002))
12
+
13
+
14
+
15
+
16
+
6
17
  ## 0.4.7 (2025-01-23)
7
18
 
8
19
  ### Only dependencies have been changed
package/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
  ### Props
13
13
  | name | type | default value | description |
14
14
  |------|------|---------------|-------------|
15
+ | jsonSchema* | `JsonSchema` | - | Схема для валидации |
15
16
  | themeName | `string` | - | Название текущей темы. Значение не важно, важно что смена значения запускает пересчет стилей. |
16
17
  | hasBackground | `boolean` | true | Включение/отключение псевдобекграунда |
17
18
  | defaultValue | `string` | - | Default value of the current model |
@@ -35,6 +36,21 @@
35
36
  | onMount | `OnMount` | - | Signature: function(editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => void An event is emitted when the editor is mounted It gets the editor instance as a first argument and the monaco instance as a second Defaults to "noop" |
36
37
  | onChange | `OnChange` | - | Signature: function(value: string \| undefined, ev: monaco.editor.IModelContentChangedEvent) => void An event is emitted when the content of the current model is changed |
37
38
  | onValidate | `OnValidate` | - | Signature: function(markers: monaco.editor.IMarker[]) => void An event is emitted when the content of the current model is changed and the current model markers are ready Defaults to "noop" |
39
+ | hoverDescription | `HoverDescription` | - | |
38
40
 
39
41
 
40
42
  [//]: DOCUMENTATION_SECTION_END
43
+
44
+ ### Поддержка YAML
45
+ Для обеспечения полноценной работы YAML Monaco Editor необходимо подключить `yaml.worker`. Это можно сделать следующими способами: с использованием [`window.MonacoEnvironment`](https://www.npmjs.com/package/monaco-yaml#usage) или с помощью плагина [`MonacoWebpackPlugin`](https://www.npmjs.com/package/monaco-yaml#using-monaco-webpack-loader-plugin) . Подробнее с `monaco-yaml` можно ознакомиться [тут]((https://www.npmjs.com/package/monaco-yaml))
46
+
47
+ ### Как редактор загружает worker?
48
+ Плагин создает новые точки входа каждого build-in воркера и для каждого дабавленного отдельно. Плагин создат глобальную переменную, используя которую редкатор будет загружать нужный воркер на основе текущего `language`.
49
+
50
+ Чтобы управлять конфигурацией загрузчика Monaco Editor, добавьте
51
+ ```typescript
52
+ import * as monaco from 'monaco-editor';
53
+ import { loader } from '@snack-uikit/code-editor';
54
+ loader.config({ monaco });
55
+ ```
56
+ Это позволяет динамически настраивать пути и другие параметры при инициализации редактора.
@@ -1,5 +1,5 @@
1
- import { EditorProps } from '@monaco-editor/react';
2
1
  import { WithSupportProps } from '@snack-uikit/utils';
2
+ import { EditorBaseProps, EditorWithJsonSchemaProps } from './types';
3
3
  export type CodeEditorProps = WithSupportProps<{
4
4
  /**
5
5
  * Название текущей темы. Значение не важно, важно что смена значения запускает пересчет стилей.
@@ -9,5 +9,5 @@ export type CodeEditorProps = WithSupportProps<{
9
9
  * Включение/отключение псевдобекграунда
10
10
  */
11
11
  hasBackground?: boolean;
12
- }> & EditorProps;
13
- export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
12
+ }> & (EditorBaseProps | EditorWithJsonSchemaProps);
13
+ export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, hoverDescription, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
@@ -36,11 +36,18 @@ function CodeEditor(_a) {
36
36
  options,
37
37
  loading,
38
38
  hasBackground = true,
39
- onMount
39
+ onMount,
40
+ language,
41
+ hoverDescription
40
42
  } = _a,
41
- props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount"]);
43
+ props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language", "hoverDescription"]);
42
44
  const monaco = (0, react_1.useMonaco)();
43
45
  const [wrapperElement, setWrapperElement] = (0, react_2.useState)(null);
46
+ const {
47
+ jsonSchemaProps,
48
+ jsonSchemaOptions
49
+ } = (0, hooks_1.useApplyJsonSchema)(language, 'jsonSchema' in props ? props.jsonSchema : undefined);
50
+ (0, hooks_1.useHoverProvider)(language, hoverDescription);
44
51
  const onEditorMount = (0, react_2.useCallback)((editor, monaco) => {
45
52
  var _a;
46
53
  monaco && (0, utils_1.isBrowser)() && ((_a = document === null || document === void 0 ? void 0 : document.fonts) === null || _a === void 0 ? void 0 : _a.ready.finally(monaco.editor.remeasureFonts));
@@ -101,23 +108,24 @@ function CodeEditor(_a) {
101
108
  monaco === null || monaco === void 0 ? void 0 : monaco.editor.defineTheme('snack', Object.assign(Object.assign({}, themeDataWithoutBase), {
102
109
  base: 'vs'
103
110
  }));
104
- const mergedOptions = (0, react_2.useMemo)(() => Object.assign(Object.assign(Object.assign({}, constants_1.CODE_EDITOR_OPTIONS), (themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono) ? {
111
+ const mergedOptions = (0, react_2.useMemo)(() => Object.assign(Object.assign(Object.assign(Object.assign({}, constants_1.CODE_EDITOR_OPTIONS), jsonSchemaOptions), (themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono) ? {
105
112
  fontSize: Number.parseFloat(themeValues.mono.body.s['font-size']),
106
113
  fontWeight: themeValues.mono.body.s['font-weight'],
107
114
  fontFamily: themeValues.mono.body.s['font-family']
108
- } : constants_1.DEFAULT_THEME_OPTIONS.mono.s), options), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono]);
115
+ } : constants_1.DEFAULT_THEME_OPTIONS.mono.s), options), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono, jsonSchemaOptions]);
109
116
  return (0, jsx_runtime_1.jsx)("div", Object.assign({
110
117
  className: className
111
118
  }, (0, utils_1.extractSupportProps)(props), {
112
119
  ref: setWrapperElement,
113
- children: (0, jsx_runtime_1.jsx)(react_1.Editor, Object.assign({}, props, {
120
+ children: (0, jsx_runtime_1.jsx)(react_1.Editor, Object.assign({}, props, jsonSchemaProps, {
114
121
  theme: theme !== null && theme !== void 0 ? theme : dark ? 'snackDark' : 'snack',
115
122
  className: (0, classnames_1.default)({
116
123
  [styles_module_scss_1.default.editor]: hasBackground
117
124
  }),
118
125
  loading: loading !== null && loading !== void 0 ? loading : (0, jsx_runtime_1.jsx)(loaders_1.Spinner, {}),
119
126
  options: mergedOptions,
120
- onMount: onEditorMount
127
+ onMount: onEditorMount,
128
+ language: language
121
129
  }))
122
130
  }));
123
131
  }
@@ -99,3 +99,9 @@ export declare const CODE_EDITOR_OPTIONS: {
99
99
  indentation: boolean;
100
100
  };
101
101
  };
102
+ export declare const YAML_CODE_EDITOR_OPTIONS: {
103
+ quickSuggestions: {
104
+ strings: boolean;
105
+ };
106
+ };
107
+ export declare const DEFAULT_SCHEMA_URI = "schema://editor-schema";
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.CODE_EDITOR_OPTIONS = exports.THEME_VARS = exports.DEFAULT_THEME_OPTIONS = exports.DEFAULT_THEME_VALUES = void 0;
6
+ exports.DEFAULT_SCHEMA_URI = exports.YAML_CODE_EDITOR_OPTIONS = exports.CODE_EDITOR_OPTIONS = exports.THEME_VARS = exports.DEFAULT_THEME_OPTIONS = exports.DEFAULT_THEME_VALUES = void 0;
7
7
  exports.DEFAULT_THEME_VALUES = {
8
8
  semanticTokenColors: {
9
9
  enumMember: {
@@ -113,4 +113,10 @@ exports.CODE_EDITOR_OPTIONS = {
113
113
  guides: {
114
114
  indentation: false
115
115
  }
116
- };
116
+ };
117
+ exports.YAML_CODE_EDITOR_OPTIONS = {
118
+ quickSuggestions: {
119
+ strings: true
120
+ }
121
+ };
122
+ exports.DEFAULT_SCHEMA_URI = 'schema://editor-schema';
@@ -1,3 +1,4 @@
1
+ import { HoverDescription, JsonSchema } from './types';
1
2
  type UseCalculatedThemeValuesProps = {
2
3
  stylesOriginNode: HTMLDivElement | null;
3
4
  themeName?: string;
@@ -41,4 +42,11 @@ export declare function useCalculatedThemeValues({ stylesOriginNode, themeName }
41
42
  };
42
43
  };
43
44
  } | undefined;
45
+ export declare function useApplyJsonSchema(language?: string, jsonSchema?: JsonSchema): {
46
+ jsonSchemaProps: {
47
+ path: string | undefined;
48
+ };
49
+ jsonSchemaOptions: import("monaco-editor").editor.IStandaloneEditorConstructionOptions | undefined;
50
+ };
51
+ export declare function useHoverProvider(language?: string, hoverDescription?: HoverDescription): void;
44
52
  export {};
@@ -4,9 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.useCalculatedThemeValues = useCalculatedThemeValues;
7
- const react_1 = require("react");
7
+ exports.useApplyJsonSchema = useApplyJsonSchema;
8
+ exports.useHoverProvider = useHoverProvider;
9
+ const react_1 = require("@monaco-editor/react");
10
+ const monaco_yaml_1 = require("monaco-yaml");
11
+ const react_2 = require("react");
8
12
  const utils_1 = require("@snack-uikit/utils");
9
13
  const constants_1 = require("./constants");
14
+ const utils_2 = require("./utils");
10
15
  function getThemeVars(styles) {
11
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
17
  return function mapComputedTree(tree) {
@@ -25,16 +30,105 @@ function useCalculatedThemeValues(_ref) {
25
30
  stylesOriginNode,
26
31
  themeName
27
32
  } = _ref;
28
- const [values, setValues] = (0, react_1.useState)(undefined);
33
+ const [values, setValues] = (0, react_2.useState)(undefined);
29
34
  const {
30
35
  themeClassName
31
36
  } = (0, utils_1.useThemeContext)();
32
37
  const trigger = themeName !== null && themeName !== void 0 ? themeName : themeClassName;
33
- (0, react_1.useEffect)(() => {
38
+ (0, react_2.useEffect)(() => {
34
39
  if (stylesOriginNode) {
35
40
  const styles = getComputedStyle(stylesOriginNode);
36
41
  setValues(getThemeVars(styles)(constants_1.THEME_VARS));
37
42
  }
38
43
  }, [stylesOriginNode, trigger]);
39
44
  return values;
45
+ }
46
+ function useApplyJsonSchema(language, jsonSchema) {
47
+ const monaco = (0, react_1.useMonaco)();
48
+ const [jsonSchemaOptions, setJsonSchemaOptions] = (0, react_2.useState)({});
49
+ const modelPath = jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.fileMatch;
50
+ const preparedJsonSchema = (0, react_2.useMemo)(() => (0, utils_2.getJsonSchema)(jsonSchema), [jsonSchema]);
51
+ const configureYamlLanguage = (0, react_2.useCallback)(() => {
52
+ if (!monaco || !preparedJsonSchema) {
53
+ return;
54
+ }
55
+ const model = (0, monaco_yaml_1.configureMonacoYaml)(monaco, {
56
+ enableSchemaRequest: true,
57
+ schemas: [preparedJsonSchema]
58
+ });
59
+ return {
60
+ options: constants_1.YAML_CODE_EDITOR_OPTIONS,
61
+ dispose: model.dispose
62
+ };
63
+ }, [monaco, preparedJsonSchema]);
64
+ const configureJsonLanguage = (0, react_2.useCallback)(() => {
65
+ if (!monaco || !preparedJsonSchema) {
66
+ return;
67
+ }
68
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
69
+ validate: true,
70
+ schemas: [preparedJsonSchema]
71
+ });
72
+ }, [monaco, preparedJsonSchema]);
73
+ const configureJsonSchema = (0, react_2.useCallback)(() => {
74
+ switch (language) {
75
+ case 'yaml':
76
+ return configureYamlLanguage();
77
+ case 'json':
78
+ return configureJsonLanguage();
79
+ default:
80
+ break;
81
+ }
82
+ }, [language, configureYamlLanguage, configureJsonLanguage]);
83
+ (0, react_2.useEffect)(() => {
84
+ var _a;
85
+ const jsonSchemaSettings = configureJsonSchema();
86
+ setJsonSchemaOptions((_a = jsonSchemaSettings === null || jsonSchemaSettings === void 0 ? void 0 : jsonSchemaSettings.options) !== null && _a !== void 0 ? _a : {});
87
+ return () => {
88
+ var _a;
89
+ setJsonSchemaOptions({});
90
+ (_a = jsonSchemaSettings === null || jsonSchemaSettings === void 0 ? void 0 : jsonSchemaSettings.dispose) === null || _a === void 0 ? void 0 : _a.call(jsonSchemaSettings);
91
+ };
92
+ }, [configureJsonSchema]);
93
+ return (0, react_2.useMemo)(() => ({
94
+ jsonSchemaProps: {
95
+ path: modelPath
96
+ },
97
+ jsonSchemaOptions
98
+ }), [jsonSchemaOptions, modelPath]);
99
+ }
100
+ function useHoverProvider(language, hoverDescription) {
101
+ const monaco = (0, react_1.useMonaco)();
102
+ const configureHoverProvider = (0, react_2.useCallback)(() => {
103
+ if (!monaco || !language || !hoverDescription) {
104
+ return;
105
+ }
106
+ return monaco.languages.registerHoverProvider(language, {
107
+ provideHover: (model, position) => {
108
+ var _a;
109
+ const wordInfo = model.getWordAtPosition(position);
110
+ const hoveredDescription = hoverDescription[(_a = wordInfo === null || wordInfo === void 0 ? void 0 : wordInfo.word) !== null && _a !== void 0 ? _a : ''];
111
+ if (wordInfo && hoveredDescription) {
112
+ const {
113
+ startColumn,
114
+ endColumn
115
+ } = wordInfo;
116
+ return {
117
+ range: new monaco.Range(position.lineNumber, startColumn, position.lineNumber, endColumn),
118
+ contents: [{
119
+ value: hoveredDescription
120
+ }]
121
+ };
122
+ }
123
+ return null;
124
+ }
125
+ });
126
+ }, [monaco, language, hoverDescription]);
127
+ (0, react_2.useEffect)(() => {
128
+ var _a;
129
+ const {
130
+ dispose
131
+ } = (_a = configureHoverProvider()) !== null && _a !== void 0 ? _a : {};
132
+ return dispose;
133
+ }, [configureHoverProvider]);
40
134
  }
@@ -1 +1,2 @@
1
1
  export * from './CodeEditor';
2
+ export * from './types';
@@ -22,4 +22,5 @@ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
22
22
  Object.defineProperty(exports, "__esModule", {
23
23
  value: true
24
24
  });
25
- __exportStar(require("./CodeEditor"), exports);
25
+ __exportStar(require("./CodeEditor"), exports);
26
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,32 @@
1
+ import { EditorProps as MonacoEditorProps } from '@monaco-editor/react';
2
+ import { JSONSchema } from 'monaco-yaml';
3
+ export type HoverDescription = {
4
+ [word: string]: string;
5
+ };
6
+ export type EditorBaseProps = MonacoEditorProps & {
7
+ hoverDescription?: HoverDescription;
8
+ };
9
+ export type SupportedSchemaLanguage = 'json' | 'yaml';
10
+ export type JsonSchema = {
11
+ uri?: string;
12
+ schema: JSONSchema;
13
+ fileMatch: string;
14
+ };
15
+ export type WithJsonSchema = {
16
+ /**
17
+ * Схема для валидации
18
+ */
19
+ jsonSchema: JsonSchema;
20
+ path?: never;
21
+ };
22
+ type WithoutJsonSchema = Pick<MonacoEditorProps, 'path'>;
23
+ export type EditorWithJsonSchemaProps = Omit<EditorBaseProps, 'language' | 'path'> & {
24
+ language: SupportedSchemaLanguage;
25
+ } & (WithJsonSchema | WithoutJsonSchema);
26
+ export type Dispose = {
27
+ dispose?: () => void;
28
+ };
29
+ export type ConfigureJsonSchemaReturn = ({
30
+ options?: MonacoEditorProps['options'];
31
+ } & Dispose) | undefined;
32
+ export {};
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -1,3 +1,6 @@
1
+ import { SchemasSettings } from 'monaco-yaml';
2
+ import { JsonSchema } from './types';
1
3
  export declare function rgb2hsl(HTMLcolor: string): number[];
2
4
  export declare function isDark(color: string): boolean;
3
5
  export declare function initLoaderConfig(): void;
6
+ export declare const getJsonSchema: (jsonSchema?: JsonSchema) => SchemasSettings | undefined;
@@ -8,11 +8,13 @@ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
8
8
  Object.defineProperty(exports, "__esModule", {
9
9
  value: true
10
10
  });
11
+ exports.getJsonSchema = void 0;
11
12
  exports.rgb2hsl = rgb2hsl;
12
13
  exports.isDark = isDark;
13
14
  exports.initLoaderConfig = initLoaderConfig;
14
15
  const react_1 = require("@monaco-editor/react");
15
16
  const chroma_js_1 = __importDefault(require("chroma-js"));
17
+ const constants_1 = require("./constants");
16
18
  function rgb2hsl(HTMLcolor) {
17
19
  const [r, g, b] = chroma_js_1.default.valid(HTMLcolor) ? (0, chroma_js_1.default)(HTMLcolor).rgb().map(c => c / 255) : [0, 0, 0];
18
20
  const max = Math.max(r, g, b),
@@ -53,4 +55,9 @@ function initLoaderConfig() {
53
55
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54
56
  // @ts-ignore
55
57
  window['__snack-code-editor-loader-config__'] && react_1.loader.config(window['__snack-code-editor-loader-config__']);
56
- }
58
+ }
59
+ const getJsonSchema = jsonSchema => jsonSchema && Object.assign(Object.assign({}, jsonSchema), {
60
+ uri: (jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.uri) || constants_1.DEFAULT_SCHEMA_URI,
61
+ fileMatch: [jsonSchema.fileMatch]
62
+ });
63
+ exports.getJsonSchema = getJsonSchema;
@@ -2,5 +2,5 @@
2
2
  Monaco loader defines the way how monaco will be loaded.
3
3
  @see https://github.com/suren-atoyan/monaco-react/tree/master?tab=readme-ov-file#loader-config
4
4
  */
5
- export { loader } from '@monaco-editor/react';
5
+ export { loader, useMonaco } from '@monaco-editor/react';
6
6
  export * from './components';
package/dist/cjs/index.js CHANGED
@@ -22,7 +22,7 @@ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
22
22
  Object.defineProperty(exports, "__esModule", {
23
23
  value: true
24
24
  });
25
- exports.loader = void 0;
25
+ exports.useMonaco = exports.loader = void 0;
26
26
  /**
27
27
  Monaco loader defines the way how monaco will be loaded.
28
28
  @see https://github.com/suren-atoyan/monaco-react/tree/master?tab=readme-ov-file#loader-config
@@ -34,4 +34,10 @@ Object.defineProperty(exports, "loader", {
34
34
  return react_1.loader;
35
35
  }
36
36
  });
37
+ Object.defineProperty(exports, "useMonaco", {
38
+ enumerable: true,
39
+ get: function () {
40
+ return react_1.useMonaco;
41
+ }
42
+ });
37
43
  __exportStar(require("./components"), exports);
@@ -1,5 +1,5 @@
1
- import { EditorProps } from '@monaco-editor/react';
2
1
  import { WithSupportProps } from '@snack-uikit/utils';
2
+ import { EditorBaseProps, EditorWithJsonSchemaProps } from './types';
3
3
  export type CodeEditorProps = WithSupportProps<{
4
4
  /**
5
5
  * Название текущей темы. Значение не важно, важно что смена значения запускает пересчет стилей.
@@ -9,5 +9,5 @@ export type CodeEditorProps = WithSupportProps<{
9
9
  * Включение/отключение псевдобекграунда
10
10
  */
11
11
  hasBackground?: boolean;
12
- }> & EditorProps;
13
- export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
12
+ }> & (EditorBaseProps | EditorWithJsonSchemaProps);
13
+ export declare function CodeEditor({ themeName, className, theme, options, loading, hasBackground, onMount, language, hoverDescription, ...props }: CodeEditorProps): import("react/jsx-runtime").JSX.Element;
@@ -16,14 +16,16 @@ import { useCallback, useMemo, useState } from 'react';
16
16
  import { Spinner } from '@snack-uikit/loaders';
17
17
  import { extractSupportProps, isBrowser } from '@snack-uikit/utils';
18
18
  import { CODE_EDITOR_OPTIONS, DEFAULT_THEME_OPTIONS, DEFAULT_THEME_VALUES } from './constants';
19
- import { useCalculatedThemeValues } from './hooks';
19
+ import { useApplyJsonSchema, useCalculatedThemeValues, useHoverProvider } from './hooks';
20
20
  import styles from './styles.module.css';
21
21
  import { initLoaderConfig, isDark } from './utils';
22
22
  initLoaderConfig();
23
23
  export function CodeEditor(_a) {
24
- var { themeName, className, theme, options, loading, hasBackground = true, onMount } = _a, props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount"]);
24
+ var { themeName, className, theme, options, loading, hasBackground = true, onMount, language, hoverDescription } = _a, props = __rest(_a, ["themeName", "className", "theme", "options", "loading", "hasBackground", "onMount", "language", "hoverDescription"]);
25
25
  const monaco = useMonaco();
26
26
  const [wrapperElement, setWrapperElement] = useState(null);
27
+ const { jsonSchemaProps, jsonSchemaOptions } = useApplyJsonSchema(language, 'jsonSchema' in props ? props.jsonSchema : undefined);
28
+ useHoverProvider(language, hoverDescription);
27
29
  const onEditorMount = useCallback((editor, monaco) => {
28
30
  var _a;
29
31
  monaco && isBrowser() && ((_a = document === null || document === void 0 ? void 0 : document.fonts) === null || _a === void 0 ? void 0 : _a.ready.finally(monaco.editor.remeasureFonts));
@@ -79,12 +81,12 @@ export function CodeEditor(_a) {
79
81
  const dark = useMemo(() => { var _a; return isDark((_a = themeValues === null || themeValues === void 0 ? void 0 : themeValues.sys.available.complementary) !== null && _a !== void 0 ? _a : ''); }, [themeValues === null || themeValues === void 0 ? void 0 : themeValues.sys.available.complementary]);
80
82
  monaco === null || monaco === void 0 ? void 0 : monaco.editor.defineTheme('snackDark', Object.assign(Object.assign({}, themeDataWithoutBase), { base: 'vs-dark' }));
81
83
  monaco === null || monaco === void 0 ? void 0 : monaco.editor.defineTheme('snack', Object.assign(Object.assign({}, themeDataWithoutBase), { base: 'vs' }));
82
- const mergedOptions = useMemo(() => (Object.assign(Object.assign(Object.assign({}, CODE_EDITOR_OPTIONS), ((themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono)
84
+ const mergedOptions = useMemo(() => (Object.assign(Object.assign(Object.assign(Object.assign({}, CODE_EDITOR_OPTIONS), jsonSchemaOptions), ((themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono)
83
85
  ? {
84
86
  fontSize: Number.parseFloat(themeValues.mono.body.s['font-size']),
85
87
  fontWeight: themeValues.mono.body.s['font-weight'],
86
88
  fontFamily: themeValues.mono.body.s['font-family'],
87
89
  }
88
- : DEFAULT_THEME_OPTIONS.mono.s)), options)), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono]);
89
- return (_jsx("div", Object.assign({ className: className }, extractSupportProps(props), { ref: setWrapperElement, children: _jsx(Editor, Object.assign({}, 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 })) })));
90
+ : DEFAULT_THEME_OPTIONS.mono.s)), options)), [options, themeValues === null || themeValues === void 0 ? void 0 : themeValues.mono, jsonSchemaOptions]);
91
+ return (_jsx("div", Object.assign({ className: className }, extractSupportProps(props), { ref: setWrapperElement, children: _jsx(Editor, Object.assign({}, props, jsonSchemaProps, { 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 })) })));
90
92
  }
@@ -99,3 +99,9 @@ export declare const CODE_EDITOR_OPTIONS: {
99
99
  indentation: boolean;
100
100
  };
101
101
  };
102
+ export declare const YAML_CODE_EDITOR_OPTIONS: {
103
+ quickSuggestions: {
104
+ strings: boolean;
105
+ };
106
+ };
107
+ export declare const DEFAULT_SCHEMA_URI = "schema://editor-schema";
@@ -95,3 +95,9 @@ export const CODE_EDITOR_OPTIONS = {
95
95
  indentation: false,
96
96
  },
97
97
  };
98
+ export const YAML_CODE_EDITOR_OPTIONS = {
99
+ quickSuggestions: {
100
+ strings: true,
101
+ },
102
+ };
103
+ export const DEFAULT_SCHEMA_URI = 'schema://editor-schema';
@@ -1,3 +1,4 @@
1
+ import { HoverDescription, JsonSchema } from './types';
1
2
  type UseCalculatedThemeValuesProps = {
2
3
  stylesOriginNode: HTMLDivElement | null;
3
4
  themeName?: string;
@@ -41,4 +42,11 @@ export declare function useCalculatedThemeValues({ stylesOriginNode, themeName }
41
42
  };
42
43
  };
43
44
  } | undefined;
45
+ export declare function useApplyJsonSchema(language?: string, jsonSchema?: JsonSchema): {
46
+ jsonSchemaProps: {
47
+ path: string | undefined;
48
+ };
49
+ jsonSchemaOptions: import("monaco-editor").editor.IStandaloneEditorConstructionOptions | undefined;
50
+ };
51
+ export declare function useHoverProvider(language?: string, hoverDescription?: HoverDescription): void;
44
52
  export {};
@@ -1,6 +1,9 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useMonaco } from '@monaco-editor/react';
2
+ import { configureMonacoYaml } from 'monaco-yaml';
3
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
4
  import { useThemeContext } from '@snack-uikit/utils';
3
- import { THEME_VARS } from './constants';
5
+ import { THEME_VARS, YAML_CODE_EDITOR_OPTIONS } from './constants';
6
+ import { getJsonSchema } from './utils';
4
7
  function getThemeVars(styles) {
5
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
9
  return function mapComputedTree(tree) {
@@ -26,3 +29,83 @@ export function useCalculatedThemeValues({ stylesOriginNode, themeName }) {
26
29
  }, [stylesOriginNode, trigger]);
27
30
  return values;
28
31
  }
32
+ export function useApplyJsonSchema(language, jsonSchema) {
33
+ const monaco = useMonaco();
34
+ const [jsonSchemaOptions, setJsonSchemaOptions] = useState({});
35
+ const modelPath = jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.fileMatch;
36
+ const preparedJsonSchema = useMemo(() => getJsonSchema(jsonSchema), [jsonSchema]);
37
+ const configureYamlLanguage = useCallback(() => {
38
+ if (!monaco || !preparedJsonSchema) {
39
+ return;
40
+ }
41
+ const model = configureMonacoYaml(monaco, {
42
+ enableSchemaRequest: true,
43
+ schemas: [preparedJsonSchema],
44
+ });
45
+ return {
46
+ options: YAML_CODE_EDITOR_OPTIONS,
47
+ dispose: model.dispose,
48
+ };
49
+ }, [monaco, preparedJsonSchema]);
50
+ const configureJsonLanguage = useCallback(() => {
51
+ if (!monaco || !preparedJsonSchema) {
52
+ return;
53
+ }
54
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
55
+ validate: true,
56
+ schemas: [preparedJsonSchema],
57
+ });
58
+ }, [monaco, preparedJsonSchema]);
59
+ const configureJsonSchema = useCallback(() => {
60
+ switch (language) {
61
+ case 'yaml':
62
+ return configureYamlLanguage();
63
+ case 'json':
64
+ return configureJsonLanguage();
65
+ default:
66
+ break;
67
+ }
68
+ }, [language, configureYamlLanguage, configureJsonLanguage]);
69
+ useEffect(() => {
70
+ var _a;
71
+ const jsonSchemaSettings = configureJsonSchema();
72
+ setJsonSchemaOptions((_a = jsonSchemaSettings === null || jsonSchemaSettings === void 0 ? void 0 : jsonSchemaSettings.options) !== null && _a !== void 0 ? _a : {});
73
+ return () => {
74
+ var _a;
75
+ setJsonSchemaOptions({});
76
+ (_a = jsonSchemaSettings === null || jsonSchemaSettings === void 0 ? void 0 : jsonSchemaSettings.dispose) === null || _a === void 0 ? void 0 : _a.call(jsonSchemaSettings);
77
+ };
78
+ }, [configureJsonSchema]);
79
+ return useMemo(() => ({
80
+ jsonSchemaProps: { path: modelPath },
81
+ jsonSchemaOptions,
82
+ }), [jsonSchemaOptions, modelPath]);
83
+ }
84
+ export function useHoverProvider(language, hoverDescription) {
85
+ const monaco = useMonaco();
86
+ const configureHoverProvider = useCallback(() => {
87
+ if (!monaco || !language || !hoverDescription) {
88
+ return;
89
+ }
90
+ return monaco.languages.registerHoverProvider(language, {
91
+ provideHover: (model, position) => {
92
+ var _a;
93
+ const wordInfo = model.getWordAtPosition(position);
94
+ const hoveredDescription = hoverDescription[(_a = wordInfo === null || wordInfo === void 0 ? void 0 : wordInfo.word) !== null && _a !== void 0 ? _a : ''];
95
+ if (wordInfo && hoveredDescription) {
96
+ const { startColumn, endColumn } = wordInfo;
97
+ return {
98
+ range: new monaco.Range(position.lineNumber, startColumn, position.lineNumber, endColumn),
99
+ contents: [{ value: hoveredDescription }],
100
+ };
101
+ }
102
+ return null;
103
+ },
104
+ });
105
+ }, [monaco, language, hoverDescription]);
106
+ useEffect(() => {
107
+ var _a;
108
+ const { dispose } = (_a = configureHoverProvider()) !== null && _a !== void 0 ? _a : {};
109
+ return dispose;
110
+ }, [configureHoverProvider]);
111
+ }
@@ -1 +1,2 @@
1
1
  export * from './CodeEditor';
2
+ export * from './types';
@@ -1 +1,2 @@
1
1
  export * from './CodeEditor';
2
+ export * from './types';
@@ -0,0 +1,32 @@
1
+ import { EditorProps as MonacoEditorProps } from '@monaco-editor/react';
2
+ import { JSONSchema } from 'monaco-yaml';
3
+ export type HoverDescription = {
4
+ [word: string]: string;
5
+ };
6
+ export type EditorBaseProps = MonacoEditorProps & {
7
+ hoverDescription?: HoverDescription;
8
+ };
9
+ export type SupportedSchemaLanguage = 'json' | 'yaml';
10
+ export type JsonSchema = {
11
+ uri?: string;
12
+ schema: JSONSchema;
13
+ fileMatch: string;
14
+ };
15
+ export type WithJsonSchema = {
16
+ /**
17
+ * Схема для валидации
18
+ */
19
+ jsonSchema: JsonSchema;
20
+ path?: never;
21
+ };
22
+ type WithoutJsonSchema = Pick<MonacoEditorProps, 'path'>;
23
+ export type EditorWithJsonSchemaProps = Omit<EditorBaseProps, 'language' | 'path'> & {
24
+ language: SupportedSchemaLanguage;
25
+ } & (WithJsonSchema | WithoutJsonSchema);
26
+ export type Dispose = {
27
+ dispose?: () => void;
28
+ };
29
+ export type ConfigureJsonSchemaReturn = ({
30
+ options?: MonacoEditorProps['options'];
31
+ } & Dispose) | undefined;
32
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,6 @@
1
+ import { SchemasSettings } from 'monaco-yaml';
2
+ import { JsonSchema } from './types';
1
3
  export declare function rgb2hsl(HTMLcolor: string): number[];
2
4
  export declare function isDark(color: string): boolean;
3
5
  export declare function initLoaderConfig(): void;
6
+ export declare const getJsonSchema: (jsonSchema?: JsonSchema) => SchemasSettings | undefined;
@@ -1,5 +1,6 @@
1
1
  import { loader } from '@monaco-editor/react';
2
2
  import chroma from 'chroma-js';
3
+ import { DEFAULT_SCHEMA_URI } from './constants';
3
4
  export function rgb2hsl(HTMLcolor) {
4
5
  const [r, g, b] = chroma.valid(HTMLcolor)
5
6
  ? chroma(HTMLcolor)
@@ -45,3 +46,4 @@ export function initLoaderConfig() {
45
46
  // @ts-ignore
46
47
  window['__snack-code-editor-loader-config__'] && loader.config(window['__snack-code-editor-loader-config__']);
47
48
  }
49
+ 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] });
@@ -2,5 +2,5 @@
2
2
  Monaco loader defines the way how monaco will be loaded.
3
3
  @see https://github.com/suren-atoyan/monaco-react/tree/master?tab=readme-ov-file#loader-config
4
4
  */
5
- export { loader } from '@monaco-editor/react';
5
+ export { loader, useMonaco } from '@monaco-editor/react';
6
6
  export * from './components';
package/dist/esm/index.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Monaco loader defines the way how monaco will be loaded.
3
3
  @see https://github.com/suren-atoyan/monaco-react/tree/master?tab=readme-ov-file#loader-config
4
4
  */
5
- export { loader } from '@monaco-editor/react';
5
+ export { loader, useMonaco } from '@monaco-editor/react';
6
6
  export * from './components';
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.4.7",
7
+ "version": "0.5.1-preview-d4775873.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -40,10 +40,11 @@
40
40
  "@snack-uikit/loaders": "0.9.1",
41
41
  "@snack-uikit/utils": "3.7.0",
42
42
  "chroma-js": "3.1.2",
43
- "classnames": "2.5.1"
43
+ "classnames": "2.5.1",
44
+ "monaco-yaml": "5.2.3"
44
45
  },
45
46
  "devDependencies": {
46
47
  "@types/chroma-js": "2.4.4"
47
48
  },
48
- "gitHead": "3528e78aec23804dca44d311947c1dcd4ed3792b"
49
+ "gitHead": "1db3ab2954a7d659a5bd2cb7a8403d5500cecd31"
49
50
  }
@@ -1,4 +1,4 @@
1
- import { Editor, EditorProps, OnMount, useMonaco } from '@monaco-editor/react';
1
+ import { Editor, OnMount, useMonaco } from '@monaco-editor/react';
2
2
  import cn from 'classnames';
3
3
  import { useCallback, useMemo, useState } from 'react';
4
4
 
@@ -6,8 +6,9 @@ import { Spinner } from '@snack-uikit/loaders';
6
6
  import { extractSupportProps, isBrowser, WithSupportProps } from '@snack-uikit/utils';
7
7
 
8
8
  import { CODE_EDITOR_OPTIONS, DEFAULT_THEME_OPTIONS, DEFAULT_THEME_VALUES } from './constants';
9
- import { useCalculatedThemeValues } from './hooks';
9
+ import { useApplyJsonSchema, useCalculatedThemeValues, useHoverProvider } from './hooks';
10
10
  import styles from './styles.module.scss';
11
+ import { EditorBaseProps, EditorWithJsonSchemaProps } from './types';
11
12
  import { initLoaderConfig, isDark } from './utils';
12
13
 
13
14
  initLoaderConfig();
@@ -22,7 +23,7 @@ export type CodeEditorProps = WithSupportProps<{
22
23
  */
23
24
  hasBackground?: boolean;
24
25
  }> &
25
- EditorProps;
26
+ (EditorBaseProps | EditorWithJsonSchemaProps);
26
27
 
27
28
  export function CodeEditor({
28
29
  themeName,
@@ -32,11 +33,20 @@ export function CodeEditor({
32
33
  loading,
33
34
  hasBackground = true,
34
35
  onMount,
36
+ language,
37
+ hoverDescription,
35
38
  ...props
36
39
  }: CodeEditorProps) {
37
40
  const monaco = useMonaco();
38
41
  const [wrapperElement, setWrapperElement] = useState<HTMLDivElement | null>(null);
39
42
 
43
+ const { jsonSchemaProps, jsonSchemaOptions } = useApplyJsonSchema(
44
+ language,
45
+ 'jsonSchema' in props ? props.jsonSchema : undefined,
46
+ );
47
+
48
+ useHoverProvider(language, hoverDescription);
49
+
40
50
  const onEditorMount = useCallback<OnMount>(
41
51
  (editor, monaco) => {
42
52
  monaco && isBrowser() && document?.fonts?.ready.finally(monaco.editor.remeasureFonts);
@@ -111,6 +121,7 @@ export function CodeEditor({
111
121
  const mergedOptions = useMemo(
112
122
  () => ({
113
123
  ...CODE_EDITOR_OPTIONS,
124
+ ...jsonSchemaOptions,
114
125
  ...(themeValues?.mono
115
126
  ? {
116
127
  fontSize: Number.parseFloat(themeValues.mono.body.s['font-size']),
@@ -120,18 +131,20 @@ export function CodeEditor({
120
131
  : DEFAULT_THEME_OPTIONS.mono.s),
121
132
  ...options,
122
133
  }),
123
- [options, themeValues?.mono],
134
+ [options, themeValues?.mono, jsonSchemaOptions],
124
135
  );
125
136
 
126
137
  return (
127
138
  <div className={className} {...extractSupportProps(props)} ref={setWrapperElement}>
128
139
  <Editor
129
140
  {...props}
141
+ {...jsonSchemaProps}
130
142
  theme={theme ?? (dark ? 'snackDark' : 'snack')}
131
143
  className={cn({ [styles.editor]: hasBackground })}
132
144
  loading={loading ?? <Spinner />}
133
145
  options={mergedOptions}
134
146
  onMount={onEditorMount}
147
+ language={language}
135
148
  />
136
149
  </div>
137
150
  );
@@ -98,3 +98,11 @@ export const CODE_EDITOR_OPTIONS = {
98
98
  indentation: false,
99
99
  },
100
100
  };
101
+
102
+ export const YAML_CODE_EDITOR_OPTIONS = {
103
+ quickSuggestions: {
104
+ strings: true,
105
+ },
106
+ };
107
+
108
+ export const DEFAULT_SCHEMA_URI = 'schema://editor-schema';
@@ -1,8 +1,12 @@
1
- import { useEffect, useState } from 'react';
1
+ import { EditorProps as MonacoEditorProps, useMonaco } from '@monaco-editor/react';
2
+ import { configureMonacoYaml, SchemasSettings } from 'monaco-yaml';
3
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
4
 
3
5
  import { useThemeContext } from '@snack-uikit/utils';
4
6
 
5
- import { THEME_VARS } from './constants';
7
+ import { THEME_VARS, YAML_CODE_EDITOR_OPTIONS } from './constants';
8
+ import { ConfigureJsonSchemaReturn, Dispose, HoverDescription, JsonSchema } from './types';
9
+ import { getJsonSchema } from './utils';
6
10
 
7
11
  function getThemeVars(styles: CSSStyleDeclaration) {
8
12
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -42,3 +46,100 @@ export function useCalculatedThemeValues({ stylesOriginNode, themeName }: UseCal
42
46
 
43
47
  return values;
44
48
  }
49
+
50
+ export function useApplyJsonSchema(language?: string, jsonSchema?: JsonSchema) {
51
+ const monaco = useMonaco();
52
+
53
+ const [jsonSchemaOptions, setJsonSchemaOptions] = useState<MonacoEditorProps['options']>({});
54
+ const modelPath = jsonSchema?.fileMatch;
55
+
56
+ const preparedJsonSchema: SchemasSettings | undefined = useMemo(() => getJsonSchema(jsonSchema), [jsonSchema]);
57
+
58
+ const configureYamlLanguage = useCallback((): ConfigureJsonSchemaReturn => {
59
+ if (!monaco || !preparedJsonSchema) {
60
+ return;
61
+ }
62
+
63
+ const model = configureMonacoYaml(monaco, {
64
+ enableSchemaRequest: true,
65
+ schemas: [preparedJsonSchema],
66
+ });
67
+
68
+ return {
69
+ options: YAML_CODE_EDITOR_OPTIONS,
70
+ dispose: model.dispose,
71
+ };
72
+ }, [monaco, preparedJsonSchema]);
73
+
74
+ const configureJsonLanguage = useCallback((): ConfigureJsonSchemaReturn => {
75
+ if (!monaco || !preparedJsonSchema) {
76
+ return;
77
+ }
78
+
79
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
80
+ validate: true,
81
+ schemas: [preparedJsonSchema],
82
+ });
83
+ }, [monaco, preparedJsonSchema]);
84
+
85
+ const configureJsonSchema = useCallback(() => {
86
+ switch (language) {
87
+ case 'yaml':
88
+ return configureYamlLanguage();
89
+ case 'json':
90
+ return configureJsonLanguage();
91
+ default:
92
+ break;
93
+ }
94
+ }, [language, configureYamlLanguage, configureJsonLanguage]);
95
+
96
+ useEffect(() => {
97
+ const jsonSchemaSettings = configureJsonSchema();
98
+ setJsonSchemaOptions(jsonSchemaSettings?.options ?? {});
99
+
100
+ return () => {
101
+ setJsonSchemaOptions({});
102
+ jsonSchemaSettings?.dispose?.();
103
+ };
104
+ }, [configureJsonSchema]);
105
+
106
+ return useMemo(
107
+ () => ({
108
+ jsonSchemaProps: { path: modelPath } satisfies MonacoEditorProps,
109
+ jsonSchemaOptions,
110
+ }),
111
+ [jsonSchemaOptions, modelPath],
112
+ );
113
+ }
114
+
115
+ export function useHoverProvider(language?: string, hoverDescription?: HoverDescription) {
116
+ const monaco = useMonaco();
117
+
118
+ const configureHoverProvider = useCallback((): Dispose | undefined => {
119
+ if (!monaco || !language || !hoverDescription) {
120
+ return;
121
+ }
122
+
123
+ return monaco.languages.registerHoverProvider(language, {
124
+ provideHover: (model, position) => {
125
+ const wordInfo = model.getWordAtPosition(position);
126
+ const hoveredDescription = hoverDescription[wordInfo?.word ?? ''];
127
+
128
+ if (wordInfo && hoveredDescription) {
129
+ const { startColumn, endColumn } = wordInfo;
130
+
131
+ return {
132
+ range: new monaco.Range(position.lineNumber, startColumn, position.lineNumber, endColumn),
133
+ contents: [{ value: hoveredDescription }],
134
+ };
135
+ }
136
+ return null;
137
+ },
138
+ });
139
+ }, [monaco, language, hoverDescription]);
140
+
141
+ useEffect(() => {
142
+ const { dispose } = configureHoverProvider() ?? {};
143
+ return dispose;
144
+ }, [configureHoverProvider]);
145
+ }
@@ -1 +1,2 @@
1
1
  export * from './CodeEditor';
2
+ export * from './types';
@@ -0,0 +1,42 @@
1
+ import { EditorProps as MonacoEditorProps } from '@monaco-editor/react';
2
+ import { JSONSchema } from 'monaco-yaml';
3
+
4
+ export type HoverDescription = {
5
+ [word: string]: string;
6
+ };
7
+
8
+ export type EditorBaseProps = MonacoEditorProps & {
9
+ hoverDescription?: HoverDescription;
10
+ };
11
+
12
+ export type SupportedSchemaLanguage = 'json' | 'yaml';
13
+
14
+ export type JsonSchema = {
15
+ uri?: string;
16
+ schema: JSONSchema;
17
+ fileMatch: string;
18
+ };
19
+
20
+ export type WithJsonSchema = {
21
+ /**
22
+ * Схема для валидации
23
+ */
24
+ jsonSchema: JsonSchema;
25
+ path?: never;
26
+ };
27
+
28
+ type WithoutJsonSchema = Pick<MonacoEditorProps, 'path'>;
29
+
30
+ export type EditorWithJsonSchemaProps = Omit<EditorBaseProps, 'language' | 'path'> & {
31
+ language: SupportedSchemaLanguage;
32
+ } & (WithJsonSchema | WithoutJsonSchema);
33
+
34
+ export type Dispose = {
35
+ dispose?: () => void;
36
+ };
37
+
38
+ export type ConfigureJsonSchemaReturn =
39
+ | ({
40
+ options?: MonacoEditorProps['options'];
41
+ } & Dispose)
42
+ | undefined;
@@ -1,5 +1,9 @@
1
1
  import { loader } from '@monaco-editor/react';
2
2
  import chroma from 'chroma-js';
3
+ import { SchemasSettings } from 'monaco-yaml';
4
+
5
+ import { DEFAULT_SCHEMA_URI } from './constants';
6
+ import { JsonSchema } from './types';
3
7
 
4
8
  export function rgb2hsl(HTMLcolor: string) {
5
9
  const [r, g, b] = chroma.valid(HTMLcolor)
@@ -60,3 +64,6 @@ export function initLoaderConfig() {
60
64
  // @ts-ignore
61
65
  window['__snack-code-editor-loader-config__'] && loader.config(window['__snack-code-editor-loader-config__']);
62
66
  }
67
+
68
+ export const getJsonSchema = (jsonSchema?: JsonSchema): SchemasSettings | undefined =>
69
+ jsonSchema && { ...jsonSchema, uri: jsonSchema?.uri || DEFAULT_SCHEMA_URI, fileMatch: [jsonSchema.fileMatch] };
package/src/index.ts CHANGED
@@ -2,5 +2,5 @@
2
2
  Monaco loader defines the way how monaco will be loaded.
3
3
  @see https://github.com/suren-atoyan/monaco-react/tree/master?tab=readme-ov-file#loader-config
4
4
  */
5
- export { loader } from '@monaco-editor/react';
5
+ export { loader, useMonaco } from '@monaco-editor/react';
6
6
  export * from './components';