@elice/material-exercise 1.221228.0 → 1.230111.0-mobexercise.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.
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { MaterialExerciseCommonProps } from './context';
3
+ declare type PickedMaterialExerciseCommonProps = Pick<MaterialExerciseCommonProps, 'materialExerciseId' | 'exerciseRoomId' | 'readOnlyEditor' | 'onExerciseRoomIdChange' | 'onDefaultExerciseRoomIdSet' | 'onError'>;
4
+ export interface MaterialExerciseMobileProps extends PickedMaterialExerciseCommonProps {
5
+ filename: string;
6
+ }
7
+ declare const _default: React.VFC<MaterialExerciseMobileProps & import("@elice/material-shared-utils").MaterialCommponentCommonProps>;
8
+ export default _default;
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var apiClient = require('@elice/api-client');
5
+ var materialSharedUtils = require('@elice/material-shared-utils');
6
+ var recoil = require('recoil');
7
+ var recoil$1 = require('./context/recoil.js');
8
+ require('./context/context.js');
9
+ require('./context/recoilTypes.js');
10
+ require('./context/subjects.js');
11
+ var ExerciseProvider = require('./context/ExerciseProvider.js');
12
+ var ExerciseFile = require('./exercise-file/ExerciseFile.js');
13
+
14
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
15
+
16
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
17
+
18
+ //
19
+ //
20
+
21
+ /**
22
+ * Material exercise.
23
+ */
24
+
25
+ const MaterialExerciseMobile = ({
26
+ filename
27
+ }) => {
28
+ const setExerciseActiveFilename = recoil.useSetRecoilState(recoil$1.exerciseActiveFilenameState);
29
+ React__default["default"].useEffect(() => setExerciseActiveFilename(filename), // eslint-disable-next-line react-hooks/exhaustive-deps
30
+ [filename]); //
31
+ //
32
+ //
33
+
34
+ return React__default["default"].createElement(ExerciseFile, null);
35
+ }; //
36
+ //
37
+ //
38
+
39
+
40
+ var MaterialExerciseMobile$1 = materialSharedUtils.withMaterial(props => React__default["default"].createElement(ExerciseProvider, Object.assign({}, props), React__default["default"].createElement(MaterialExerciseMobile, Object.assign({}, props))), apiClient.config.init, {
41
+ overrideRecoilScope: true
42
+ });
43
+
44
+ module.exports = MaterialExerciseMobile$1;
@@ -1,3 +1,5 @@
1
1
  export { default as MaterialExercise } from './MaterialExercise';
2
2
  export type { MaterialExerciseProps, MaterialExerciseApis, } from './MaterialExercise';
3
+ export { default as MaterialExerciseMobile } from './MaterialExerciseMobile';
4
+ export type { MaterialExerciseMobileProps } from './MaterialExerciseMobile';
3
5
  export type { MaterialExerciseCommonApis, MaterialExerciseCommonApiSendTextToTerminal, MaterialExerciseCommonProps, MaterialExerciseCommonPropExerciseImageEmptyOptions, MaterialExerciseCommonPropOnCodeHelpRequest, MaterialExerciseCommonPropOnDefaultExerciseRoomIdSet, MaterialExerciseCommonPropOnExerciseRoomIdChange, MaterialExerciseCommonPropOnRunningDone, MaterialExerciseCommonPropOnSubmit, MaterialExerciseCommonPropOnError, } from './context/types';
@@ -15,9 +15,11 @@ declare type MonacoEditorApiGetValueInRange = (from: number, to: number) => stri
15
15
  /** Set (overwrite) value to editor. */
16
16
  declare type MonacoEditorApiSetValue = (value: string) => void;
17
17
  /** Insert value at specific position. */
18
- declare type MonacoEditorApiInsertValue = (index: number, value: string) => void;
18
+ declare type MonacoEditorApiInsertValue = (offset: number, value: string) => void;
19
19
  /** Remove value at specific range. */
20
20
  declare type MonacoEditorApiRemoveValue = (from: number, to: number) => void;
21
+ /** Get offset of current cursor position. */
22
+ declare type MonacoEditorApiGetPositionOffset = () => number;
21
23
  /** Set selection of editor with specific range. */
22
24
  declare type MonacoEditorApiSetSelection = (from: number, to: number) => void;
23
25
  /** Scroll editor to specific `scrollTop`. */
@@ -33,6 +35,7 @@ export interface MonacoEditorApis {
33
35
  setValue: MonacoEditorApiSetValue;
34
36
  insertValue: MonacoEditorApiInsertValue;
35
37
  removeValue: MonacoEditorApiRemoveValue;
38
+ getPositionOffset: MonacoEditorApiGetPositionOffset;
36
39
  setSelection: MonacoEditorApiSetSelection;
37
40
  scrollTo: MonacoEditorApiScrollTo;
38
41
  }
@@ -210,7 +210,7 @@ const MonacoEditor = React.forwardRef(({
210
210
  */
211
211
 
212
212
 
213
- const insertValue = (index, newValue) => {
213
+ const insertValue = (offset, newValue) => {
214
214
  if (!editor.current) {
215
215
  return;
216
216
  } // Replace value EOL as LF.
@@ -220,7 +220,7 @@ const MonacoEditor = React.forwardRef(({
220
220
  const model = getMonacoModel();
221
221
 
222
222
  if (model) {
223
- const position = model.getPositionAt(index);
223
+ const position = model.getPositionAt(offset);
224
224
  suppress.current = true;
225
225
  editor.current.pushUndoStop();
226
226
  model.pushEditOperations([], [{
@@ -259,6 +259,23 @@ const MonacoEditor = React.forwardRef(({
259
259
  suppress.current = false;
260
260
  }
261
261
  };
262
+ /**
263
+ * Get offset of current cursor position.
264
+ * @public
265
+ */
266
+
267
+
268
+ const getPositionOffset = () => {
269
+ var _a;
270
+
271
+ const model = getMonacoModel();
272
+
273
+ if (!editor.current || !model) {
274
+ return 0;
275
+ }
276
+
277
+ return model.getOffsetAt((_a = editor.current.getPosition()) !== null && _a !== void 0 ? _a : new monaco__namespace.Position(0, 0));
278
+ };
262
279
  /**
263
280
  * Set selection of editor with specific range.
264
281
  * @public
@@ -363,6 +380,7 @@ const MonacoEditor = React.forwardRef(({
363
380
  editorApis.current.setValue = setValue;
364
381
  editorApis.current.insertValue = insertValue;
365
382
  editorApis.current.removeValue = removeValue;
383
+ editorApis.current.getPositionOffset = getPositionOffset;
366
384
  editorApis.current.setSelection = setSelection;
367
385
  editorApis.current.scrollTo = scrollTo;
368
386
  React__default["default"].useImperativeHandle(ref, () => editorApis.current, [editorApis]); //
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
+ var utils = require('@elice/utils');
4
5
  var ExerciseFileShimmer = require('../exercise-shimmer/ExerciseFileShimmer.js');
5
6
  require('../exercise-shimmer/ExerciseFileTabsShimmer.js');
6
7
  require('../exercise-shimmer/ExerciseFileTabShimmer.js');
@@ -13,7 +14,13 @@ function _interopNamespaceDefaultOnly (e) { return Object.freeze({ __proto__: nu
13
14
 
14
15
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
15
16
 
16
- const AsyncMonacoEditor = React__default["default"].lazy(() => Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('./MonacoEditor.js')); }));
17
+ //
18
+ //
19
+
20
+ const AsyncMonacoEditor = React__default["default"].lazy(() => utils.FlutterApp.checkWebview() ? Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('./MonacoEditorMobile.js')); }) : Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('./MonacoEditor.js')); })); //
21
+ //
22
+ //
23
+
17
24
  const MonacoEditorLazy = React.forwardRef((props, ref) => {
18
25
  return React__default["default"].createElement(React__default["default"].Suspense, {
19
26
  fallback: React__default["default"].createElement(ExerciseFileShimmer, null)
@@ -0,0 +1,3 @@
1
+ import MonacoEditor from './MonacoEditor';
2
+ declare const MonacoEditorMobile: typeof MonacoEditor;
3
+ export default MonacoEditorMobile;
@@ -0,0 +1,169 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var reactUse = require('react-use');
5
+ var utils = require('@elice/utils');
6
+ var monaco = require('monaco-editor/esm/vs/editor/editor.api');
7
+ var MonacoEditor = require('./MonacoEditor.js');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n["default"] = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
30
+ var monaco__namespace = /*#__PURE__*/_interopNamespace(monaco);
31
+
32
+ //
33
+ //
34
+
35
+ const MOBILE_EDITOR_PREFERENCE = Object.freeze({
36
+ autoClosingBrackets: 'always',
37
+ cursorSmoothCaretAnimation: false,
38
+ detectIndentation: true,
39
+ fontSize: 16,
40
+ minimap: {
41
+ enabled: false
42
+ },
43
+ renderWhitespace: 'all',
44
+ tabSize: 4,
45
+ theme: 'elice',
46
+ wordWrap: 'on'
47
+ });
48
+ const IS_IOS = ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) || navigator.userAgent.includes('Mac') && 'ontouchend' in document; //
49
+ //
50
+ //
51
+
52
+ const MonacoEditorMobile = React.forwardRef((props, ref) => {
53
+ const editorApiRef = reactUse.useEnsuredForwardedRef(ref);
54
+ const [preference, setPreference] = React__default["default"].useState(MOBILE_EDITOR_PREFERENCE);
55
+ /**
56
+ * Add a button to show keyboard on non-Apple devices.
57
+ */
58
+
59
+ const addKeyboardButtonOverlayWidget = editor => {
60
+ if (IS_IOS) {
61
+ return;
62
+ }
63
+
64
+ editor.addOverlayWidget({
65
+ getId: () => {
66
+ return 'editor.contrib.ShowKeyboardWidget';
67
+ },
68
+ getDomNode: () => {
69
+ const domNode = document.createElement('textarea');
70
+ domNode.className = 'iPadShowKeyboard';
71
+ domNode.addEventListener('touchstart', () => editor.focus());
72
+ domNode.addEventListener('focus', () => editor.focus());
73
+ return domNode;
74
+ },
75
+ getPosition: () => {
76
+ return {
77
+ preference: monaco__namespace.editor.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER
78
+ };
79
+ }
80
+ });
81
+ };
82
+ /**
83
+ * Export window-level event functions for mobile app.
84
+ */
85
+
86
+
87
+ const exposeWindowGlobalEvents = editor => {
88
+ const editorApi = editorApiRef.current;
89
+
90
+ if (!editorApi) {
91
+ return;
92
+ }
93
+
94
+ window.cursorCharLeft = () => {
95
+ var _a;
96
+
97
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco__namespace.Position(0, 0);
98
+ editor.setPosition(new monaco__namespace.Position(pos.lineNumber, pos.column - 1));
99
+ };
100
+
101
+ window.cursorCharRight = () => {
102
+ var _a;
103
+
104
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco__namespace.Position(0, 0);
105
+ editor.setPosition(new monaco__namespace.Position(pos.lineNumber, pos.column + 1));
106
+ };
107
+
108
+ window.cursorLineUp = () => {
109
+ var _a;
110
+
111
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco__namespace.Position(0, 0);
112
+ editor.setPosition(new monaco__namespace.Position(pos.lineNumber - 1, pos.column));
113
+ };
114
+
115
+ window.cursorLineDown = () => {
116
+ var _a;
117
+
118
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco__namespace.Position(0, 0);
119
+ editor.setPosition(new monaco__namespace.Position(pos.lineNumber + 1, pos.column));
120
+ };
121
+
122
+ window.dispatchReconfigureFontSize = fontSize => {
123
+ setPreference(prev => Object.assign(Object.assign({}, prev), {
124
+ fontSize
125
+ }));
126
+ };
127
+
128
+ window.dispatchChangeInsert = insert => {
129
+ editorApi.insertValue(editorApi.getPositionOffset(), insert);
130
+ };
131
+
132
+ window.insertTab = () => {
133
+ const model = editorApi.getMonacoModel();
134
+
135
+ if (model) {
136
+ const modelOptions = model.getOptions();
137
+ editorApi.insertValue(editorApi.getPositionOffset(), modelOptions.insertSpaces ? ' '.repeat(modelOptions.tabSize) : '\t');
138
+ }
139
+ };
140
+ };
141
+ /**
142
+ *
143
+ */
144
+
145
+
146
+ const handleLoad = editor => {
147
+ if (typeof props.onLoad === 'function') {
148
+ props.onLoad(editor);
149
+ }
150
+
151
+ addKeyboardButtonOverlayWidget(editor);
152
+ exposeWindowGlobalEvents(editor);
153
+ editor.onDidChangeModelContent(() => {
154
+ utils.FlutterApp.onDidChangeContent();
155
+ });
156
+ }; //
157
+ //
158
+ //
159
+
160
+
161
+ return React__default["default"].createElement(MonacoEditor, Object.assign({}, props, {
162
+ noLanguageIntellisense: true,
163
+ preference: preference,
164
+ onLoad: handleLoad,
165
+ ref: editorApiRef
166
+ }));
167
+ });
168
+
169
+ module.exports = MonacoEditorMobile;
package/cjs/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var MaterialExercise = require('./components/material-exercise/MaterialExercise.js');
6
+ var MaterialExerciseMobile = require('./components/material-exercise/MaterialExerciseMobile.js');
6
7
  var MonacoEditorLazy = require('./components/shared/monaco-editor/MonacoEditorLazy.js');
7
8
  var MonacoEditorPerferenceForm = require('./components/shared/monaco-editor/MonacoEditorPerferenceForm.js');
8
9
  var monacoLanguage = require('./components/shared/monaco-editor/utils/monacoLanguage.js');
@@ -13,6 +14,7 @@ var preferences = require('./components/shared/monaco-editor/constants/monaco/pr
13
14
 
14
15
 
15
16
  exports.MaterialExercise = MaterialExercise;
17
+ exports.MaterialExerciseMobile = MaterialExerciseMobile;
16
18
  exports.MonacoEditorLazy = MonacoEditorLazy;
17
19
  exports.MonacoEditorPerference = MonacoEditorPerferenceForm;
18
20
  exports.getLanguageFromFilename = monacoLanguage.getLanguageFromFilename;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { MaterialExerciseCommonProps } from './context';
3
+ declare type PickedMaterialExerciseCommonProps = Pick<MaterialExerciseCommonProps, 'materialExerciseId' | 'exerciseRoomId' | 'readOnlyEditor' | 'onExerciseRoomIdChange' | 'onDefaultExerciseRoomIdSet' | 'onError'>;
4
+ export interface MaterialExerciseMobileProps extends PickedMaterialExerciseCommonProps {
5
+ filename: string;
6
+ }
7
+ declare const _default: React.VFC<MaterialExerciseMobileProps & import("@elice/material-shared-utils").MaterialCommponentCommonProps>;
8
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { config } from '@elice/api-client';
3
+ import { withMaterial } from '@elice/material-shared-utils';
4
+ import { useSetRecoilState } from 'recoil';
5
+ import { exerciseActiveFilenameState } from './context/recoil.js';
6
+ import './context/context.js';
7
+ import './context/recoilTypes.js';
8
+ import './context/subjects.js';
9
+ import ExerciseProvider from './context/ExerciseProvider.js';
10
+ import ExerciseFile from './exercise-file/ExerciseFile.js';
11
+
12
+ //
13
+ //
14
+
15
+ /**
16
+ * Material exercise.
17
+ */
18
+
19
+ const MaterialExerciseMobile = ({
20
+ filename
21
+ }) => {
22
+ const setExerciseActiveFilename = useSetRecoilState(exerciseActiveFilenameState);
23
+ React.useEffect(() => setExerciseActiveFilename(filename), // eslint-disable-next-line react-hooks/exhaustive-deps
24
+ [filename]); //
25
+ //
26
+ //
27
+
28
+ return React.createElement(ExerciseFile, null);
29
+ }; //
30
+ //
31
+ //
32
+
33
+
34
+ var MaterialExerciseMobile$1 = withMaterial(props => React.createElement(ExerciseProvider, Object.assign({}, props), React.createElement(MaterialExerciseMobile, Object.assign({}, props))), config.init, {
35
+ overrideRecoilScope: true
36
+ });
37
+
38
+ export { MaterialExerciseMobile$1 as default };
@@ -1,3 +1,5 @@
1
1
  export { default as MaterialExercise } from './MaterialExercise';
2
2
  export type { MaterialExerciseProps, MaterialExerciseApis, } from './MaterialExercise';
3
+ export { default as MaterialExerciseMobile } from './MaterialExerciseMobile';
4
+ export type { MaterialExerciseMobileProps } from './MaterialExerciseMobile';
3
5
  export type { MaterialExerciseCommonApis, MaterialExerciseCommonApiSendTextToTerminal, MaterialExerciseCommonProps, MaterialExerciseCommonPropExerciseImageEmptyOptions, MaterialExerciseCommonPropOnCodeHelpRequest, MaterialExerciseCommonPropOnDefaultExerciseRoomIdSet, MaterialExerciseCommonPropOnExerciseRoomIdChange, MaterialExerciseCommonPropOnRunningDone, MaterialExerciseCommonPropOnSubmit, MaterialExerciseCommonPropOnError, } from './context/types';
@@ -15,9 +15,11 @@ declare type MonacoEditorApiGetValueInRange = (from: number, to: number) => stri
15
15
  /** Set (overwrite) value to editor. */
16
16
  declare type MonacoEditorApiSetValue = (value: string) => void;
17
17
  /** Insert value at specific position. */
18
- declare type MonacoEditorApiInsertValue = (index: number, value: string) => void;
18
+ declare type MonacoEditorApiInsertValue = (offset: number, value: string) => void;
19
19
  /** Remove value at specific range. */
20
20
  declare type MonacoEditorApiRemoveValue = (from: number, to: number) => void;
21
+ /** Get offset of current cursor position. */
22
+ declare type MonacoEditorApiGetPositionOffset = () => number;
21
23
  /** Set selection of editor with specific range. */
22
24
  declare type MonacoEditorApiSetSelection = (from: number, to: number) => void;
23
25
  /** Scroll editor to specific `scrollTop`. */
@@ -33,6 +35,7 @@ export interface MonacoEditorApis {
33
35
  setValue: MonacoEditorApiSetValue;
34
36
  insertValue: MonacoEditorApiInsertValue;
35
37
  removeValue: MonacoEditorApiRemoveValue;
38
+ getPositionOffset: MonacoEditorApiGetPositionOffset;
36
39
  setSelection: MonacoEditorApiSetSelection;
37
40
  scrollTo: MonacoEditorApiScrollTo;
38
41
  }
@@ -184,7 +184,7 @@ const MonacoEditor = forwardRef(({
184
184
  */
185
185
 
186
186
 
187
- const insertValue = (index, newValue) => {
187
+ const insertValue = (offset, newValue) => {
188
188
  if (!editor.current) {
189
189
  return;
190
190
  } // Replace value EOL as LF.
@@ -194,7 +194,7 @@ const MonacoEditor = forwardRef(({
194
194
  const model = getMonacoModel();
195
195
 
196
196
  if (model) {
197
- const position = model.getPositionAt(index);
197
+ const position = model.getPositionAt(offset);
198
198
  suppress.current = true;
199
199
  editor.current.pushUndoStop();
200
200
  model.pushEditOperations([], [{
@@ -233,6 +233,23 @@ const MonacoEditor = forwardRef(({
233
233
  suppress.current = false;
234
234
  }
235
235
  };
236
+ /**
237
+ * Get offset of current cursor position.
238
+ * @public
239
+ */
240
+
241
+
242
+ const getPositionOffset = () => {
243
+ var _a;
244
+
245
+ const model = getMonacoModel();
246
+
247
+ if (!editor.current || !model) {
248
+ return 0;
249
+ }
250
+
251
+ return model.getOffsetAt((_a = editor.current.getPosition()) !== null && _a !== void 0 ? _a : new monaco.Position(0, 0));
252
+ };
236
253
  /**
237
254
  * Set selection of editor with specific range.
238
255
  * @public
@@ -337,6 +354,7 @@ const MonacoEditor = forwardRef(({
337
354
  editorApis.current.setValue = setValue;
338
355
  editorApis.current.insertValue = insertValue;
339
356
  editorApis.current.removeValue = removeValue;
357
+ editorApis.current.getPositionOffset = getPositionOffset;
340
358
  editorApis.current.setSelection = setSelection;
341
359
  editorApis.current.scrollTo = scrollTo;
342
360
  React.useImperativeHandle(ref, () => editorApis.current, [editorApis]); //
@@ -1,11 +1,18 @@
1
1
  import React, { forwardRef } from 'react';
2
+ import { FlutterApp } from '@elice/utils';
2
3
  import ExerciseFileShimmer from '../exercise-shimmer/ExerciseFileShimmer.js';
3
4
  import '../exercise-shimmer/ExerciseFileTabsShimmer.js';
4
5
  import '../exercise-shimmer/ExerciseFileTabShimmer.js';
5
6
  import '../exercise-shimmer/ExerciseFileTreeListShimmer.js';
6
7
  import '../exercise-shimmer/ExerciseFileTreeListItemShimmer.js';
7
8
 
8
- const AsyncMonacoEditor = React.lazy(() => import('./MonacoEditor.js'));
9
+ //
10
+ //
11
+
12
+ const AsyncMonacoEditor = React.lazy(() => FlutterApp.checkWebview() ? import('./MonacoEditorMobile.js') : import('./MonacoEditor.js')); //
13
+ //
14
+ //
15
+
9
16
  const MonacoEditorLazy = forwardRef((props, ref) => {
10
17
  return React.createElement(React.Suspense, {
11
18
  fallback: React.createElement(ExerciseFileShimmer, null)
@@ -0,0 +1,3 @@
1
+ import MonacoEditor from './MonacoEditor';
2
+ declare const MonacoEditorMobile: typeof MonacoEditor;
3
+ export default MonacoEditorMobile;
@@ -0,0 +1,144 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { useEnsuredForwardedRef } from 'react-use';
3
+ import { FlutterApp } from '@elice/utils';
4
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
5
+ import MonacoEditor from './MonacoEditor.js';
6
+
7
+ //
8
+ //
9
+
10
+ const MOBILE_EDITOR_PREFERENCE = Object.freeze({
11
+ autoClosingBrackets: 'always',
12
+ cursorSmoothCaretAnimation: false,
13
+ detectIndentation: true,
14
+ fontSize: 16,
15
+ minimap: {
16
+ enabled: false
17
+ },
18
+ renderWhitespace: 'all',
19
+ tabSize: 4,
20
+ theme: 'elice',
21
+ wordWrap: 'on'
22
+ });
23
+ const IS_IOS = ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) || navigator.userAgent.includes('Mac') && 'ontouchend' in document; //
24
+ //
25
+ //
26
+
27
+ const MonacoEditorMobile = forwardRef((props, ref) => {
28
+ const editorApiRef = useEnsuredForwardedRef(ref);
29
+ const [preference, setPreference] = React.useState(MOBILE_EDITOR_PREFERENCE);
30
+ /**
31
+ * Add a button to show keyboard on non-Apple devices.
32
+ */
33
+
34
+ const addKeyboardButtonOverlayWidget = editor => {
35
+ if (IS_IOS) {
36
+ return;
37
+ }
38
+
39
+ editor.addOverlayWidget({
40
+ getId: () => {
41
+ return 'editor.contrib.ShowKeyboardWidget';
42
+ },
43
+ getDomNode: () => {
44
+ const domNode = document.createElement('textarea');
45
+ domNode.className = 'iPadShowKeyboard';
46
+ domNode.addEventListener('touchstart', () => editor.focus());
47
+ domNode.addEventListener('focus', () => editor.focus());
48
+ return domNode;
49
+ },
50
+ getPosition: () => {
51
+ return {
52
+ preference: monaco.editor.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER
53
+ };
54
+ }
55
+ });
56
+ };
57
+ /**
58
+ * Export window-level event functions for mobile app.
59
+ */
60
+
61
+
62
+ const exposeWindowGlobalEvents = editor => {
63
+ const editorApi = editorApiRef.current;
64
+
65
+ if (!editorApi) {
66
+ return;
67
+ }
68
+
69
+ window.cursorCharLeft = () => {
70
+ var _a;
71
+
72
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco.Position(0, 0);
73
+ editor.setPosition(new monaco.Position(pos.lineNumber, pos.column - 1));
74
+ };
75
+
76
+ window.cursorCharRight = () => {
77
+ var _a;
78
+
79
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco.Position(0, 0);
80
+ editor.setPosition(new monaco.Position(pos.lineNumber, pos.column + 1));
81
+ };
82
+
83
+ window.cursorLineUp = () => {
84
+ var _a;
85
+
86
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco.Position(0, 0);
87
+ editor.setPosition(new monaco.Position(pos.lineNumber - 1, pos.column));
88
+ };
89
+
90
+ window.cursorLineDown = () => {
91
+ var _a;
92
+
93
+ const pos = (_a = editor.getPosition()) !== null && _a !== void 0 ? _a : new monaco.Position(0, 0);
94
+ editor.setPosition(new monaco.Position(pos.lineNumber + 1, pos.column));
95
+ };
96
+
97
+ window.dispatchReconfigureFontSize = fontSize => {
98
+ setPreference(prev => Object.assign(Object.assign({}, prev), {
99
+ fontSize
100
+ }));
101
+ };
102
+
103
+ window.dispatchChangeInsert = insert => {
104
+ editorApi.insertValue(editorApi.getPositionOffset(), insert);
105
+ };
106
+
107
+ window.insertTab = () => {
108
+ const model = editorApi.getMonacoModel();
109
+
110
+ if (model) {
111
+ const modelOptions = model.getOptions();
112
+ editorApi.insertValue(editorApi.getPositionOffset(), modelOptions.insertSpaces ? ' '.repeat(modelOptions.tabSize) : '\t');
113
+ }
114
+ };
115
+ };
116
+ /**
117
+ *
118
+ */
119
+
120
+
121
+ const handleLoad = editor => {
122
+ if (typeof props.onLoad === 'function') {
123
+ props.onLoad(editor);
124
+ }
125
+
126
+ addKeyboardButtonOverlayWidget(editor);
127
+ exposeWindowGlobalEvents(editor);
128
+ editor.onDidChangeModelContent(() => {
129
+ FlutterApp.onDidChangeContent();
130
+ });
131
+ }; //
132
+ //
133
+ //
134
+
135
+
136
+ return React.createElement(MonacoEditor, Object.assign({}, props, {
137
+ noLanguageIntellisense: true,
138
+ preference: preference,
139
+ onLoad: handleLoad,
140
+ ref: editorApiRef
141
+ }));
142
+ });
143
+
144
+ export { MonacoEditorMobile as default };
package/es/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as MaterialExercise } from './components/material-exercise/MaterialExercise.js';
2
+ export { default as MaterialExerciseMobile } from './components/material-exercise/MaterialExerciseMobile.js';
2
3
  export { default as MonacoEditorLazy } from './components/shared/monaco-editor/MonacoEditorLazy.js';
3
4
  export { default as MonacoEditorPerference } from './components/shared/monaco-editor/MonacoEditorPerferenceForm.js';
4
5
  export { getLanguageFromFilename } from './components/shared/monaco-editor/utils/monacoLanguage.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elice/material-exercise",
3
- "version": "1.221228.0",
3
+ "version": "1.230111.0-mobexercise.1",
4
4
  "description": "User view and editing components of Elice material exercise",
5
5
  "repository": "https://git.elicer.io/elice/frontend/library/elice-material",
6
6
  "license": "UNLICENSED",
@@ -46,25 +46,6 @@
46
46
  "recoil": "^0.6.1",
47
47
  "styled-components": "^5.2.0"
48
48
  },
49
- "optionalDependencies": {
50
- "@codemirror/basic-setup": "^0.19.1",
51
- "@codemirror/commands": "^0.19.8",
52
- "@codemirror/highlight": "^0.19.7",
53
- "@codemirror/lang-cpp": "^0.19.1",
54
- "@codemirror/lang-css": "^0.19.3",
55
- "@codemirror/lang-html": "^0.19.4",
56
- "@codemirror/lang-java": "^0.19.1",
57
- "@codemirror/lang-javascript": "^0.19.7",
58
- "@codemirror/lang-json": "^0.19.2",
59
- "@codemirror/lang-markdown": "^0.19.6",
60
- "@codemirror/lang-python": "^0.19.4",
61
- "@codemirror/lang-rust": "^0.19.2",
62
- "@codemirror/lang-sql": "^0.19.4",
63
- "@codemirror/lang-xml": "^0.19.2",
64
- "@codemirror/state": "^0.19.9",
65
- "@codemirror/text": "^0.19.6",
66
- "@codemirror/view": "^0.19.47"
67
- },
68
49
  "dependencies": {
69
50
  "@novnc/novnc": "^1.3.0",
70
51
  "@nteract/notebook-preview": "^11.0.4-alpha.0",
@@ -93,30 +74,13 @@
93
74
  "xterm-addon-fit": "^0.5.0"
94
75
  },
95
76
  "devDependencies": {
96
- "@codemirror/basic-setup": "^0.19.1",
97
- "@codemirror/commands": "^0.19.8",
98
- "@codemirror/highlight": "^0.19.7",
99
- "@codemirror/lang-cpp": "^0.19.1",
100
- "@codemirror/lang-css": "^0.19.3",
101
- "@codemirror/lang-html": "^0.19.4",
102
- "@codemirror/lang-java": "^0.19.1",
103
- "@codemirror/lang-javascript": "^0.19.7",
104
- "@codemirror/lang-json": "^0.19.2",
105
- "@codemirror/lang-markdown": "^0.19.6",
106
- "@codemirror/lang-python": "^0.19.4",
107
- "@codemirror/lang-rust": "^0.19.2",
108
- "@codemirror/lang-sql": "^0.19.4",
109
- "@codemirror/lang-xml": "^0.19.2",
110
- "@codemirror/state": "^0.19.9",
111
- "@codemirror/text": "^0.19.6",
112
- "@codemirror/view": "^0.19.47",
113
77
  "@elice/api-client": "1.221217.0",
114
78
  "@elice/blocks": "^1.220803.0",
115
79
  "@elice/design-tokens": "^1.220803.0",
116
80
  "@elice/icons": "^1.220803.0",
117
81
  "@elice/markdown": "^1.220803.0",
118
- "@elice/material-shared-types": "1.221228.0",
119
- "@elice/material-shared-utils": "1.221228.0",
82
+ "@elice/material-shared-types": "1.230111.0-mobexercise.1",
83
+ "@elice/material-shared-utils": "1.230111.0-mobexercise.1",
120
84
  "@elice/types": "1.221217.0",
121
85
  "@elice/websocket": "^1.220803.0",
122
86
  "@types/classnames": "^2.3.1",
@@ -138,5 +102,5 @@
138
102
  "recoil": "^0.6.1",
139
103
  "styled-components": "^5.2.0"
140
104
  },
141
- "gitHead": "53eaff58a939c390104c7e96f0bc3eb8738a3ee7"
105
+ "gitHead": "8d7bcbe80aecd631228336b1ab73bfc4d2c751cb"
142
106
  }
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- export interface ExerciseMobileFileEditorProps {
3
- exerciseImageId: number;
4
- exerciseRoomId: number;
5
- filename: string;
6
- }
7
- declare const ExerciseMobileFileEditor: React.FC<ExerciseMobileFileEditorProps>;
8
- export default ExerciseMobileFileEditor;
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- export interface ExerciseMobileFileEditorProps {
3
- exerciseImageId: number;
4
- exerciseRoomId: number;
5
- filename: string;
6
- }
7
- declare const ExerciseMobileFileEditor: React.FC<ExerciseMobileFileEditorProps>;
8
- export default ExerciseMobileFileEditor;