@elice/material-quiz 1.240130.1 → 1.240131.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/cjs/components/material-quiz/context/MaterialQuizContext.js +13 -5
- package/cjs/components/material-quiz-edit/MaterialQuizEdit.d.ts +1 -1
- package/cjs/components/material-quiz-edit/MaterialQuizEditContent.js +64 -30
- package/cjs/components/material-quiz-edit/locales.d.ts +4 -0
- package/cjs/components/material-quiz-edit/locales.js +8 -0
- package/cjs/components/material-quiz-edit/options/OptionEditor.d.ts +1 -0
- package/cjs/components/material-quiz-edit/options/OptionEditor.js +25 -11
- package/cjs/components/material-quiz-edit/options/OptionSelectMultiple.js +42 -12
- package/cjs/components/material-quiz-edit/options/OptionSelectMultipleOrder.js +41 -13
- package/cjs/components/material-quiz-edit/options/OptionSelectOne.js +43 -13
- package/cjs/components/material-quiz-edit/options/OptionText.js +24 -5
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerInfo.js +19 -14
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.d.ts +1 -0
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.js +27 -15
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupInfo.js +19 -8
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.d.ts +1 -0
- package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.js +9 -5
- package/cjs/components/material-quiz-edit/utils/editValue.d.ts +2 -2
- package/cjs/components/material-quiz-edit/utils/editValue.js +3 -3
- package/es/components/material-quiz/context/MaterialQuizContext.js +14 -6
- package/es/components/material-quiz-edit/MaterialQuizEdit.d.ts +1 -1
- package/es/components/material-quiz-edit/MaterialQuizEditContent.js +64 -30
- package/es/components/material-quiz-edit/locales.d.ts +4 -0
- package/es/components/material-quiz-edit/locales.js +8 -0
- package/es/components/material-quiz-edit/options/OptionEditor.d.ts +1 -0
- package/es/components/material-quiz-edit/options/OptionEditor.js +25 -11
- package/es/components/material-quiz-edit/options/OptionSelectMultiple.js +44 -14
- package/es/components/material-quiz-edit/options/OptionSelectMultipleOrder.js +43 -15
- package/es/components/material-quiz-edit/options/OptionSelectOne.js +45 -15
- package/es/components/material-quiz-edit/options/OptionText.js +26 -7
- package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerInfo.js +19 -14
- package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.d.ts +1 -0
- package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.js +29 -17
- package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupInfo.js +20 -9
- package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.d.ts +1 -0
- package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.js +10 -6
- package/es/components/material-quiz-edit/utils/editValue.d.ts +2 -2
- package/es/components/material-quiz-edit/utils/editValue.js +3 -3
- package/package.json +25 -7
|
@@ -26,11 +26,19 @@ function MaterialQuizProvider({
|
|
|
26
26
|
materialQuiz,
|
|
27
27
|
materialLecturePage,
|
|
28
28
|
refetch: refreshOrgMaterialQuiz
|
|
29
|
-
} = materialSharedUtils.useMaterialFetchRaw(types.enums.LectureMaterialType.Quiz, React.useCallback(signal =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
} = materialSharedUtils.useMaterialFetchRaw(types.enums.LectureMaterialType.Quiz, React.useCallback(async signal => {
|
|
30
|
+
await apiClient.postOrgMaterialQuizOptionsSetSelect({
|
|
31
|
+
materialQuizId
|
|
32
|
+
}, {
|
|
33
|
+
signal
|
|
34
|
+
});
|
|
35
|
+
return await apiClient.getOrgMaterialQuizGet({
|
|
36
|
+
materialQuizId,
|
|
37
|
+
userId
|
|
38
|
+
}, {
|
|
39
|
+
signal
|
|
40
|
+
});
|
|
41
|
+
}, [materialQuizId, userId]), canInit);
|
|
34
42
|
const init = React.useCallback(async () => {
|
|
35
43
|
const controller = new AbortController();
|
|
36
44
|
const {
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { MarkdownEditorFileUploadReqFn } from '@elice/markdown';
|
|
3
3
|
import type { GetOrgMaterialQuizGetResponses } from '@elice/types';
|
|
4
4
|
import type { FormState } from 'react-hook-form';
|
|
5
|
-
export type MaterialQuizEditValue = Pick<GetOrgMaterialQuizGetResponses['materialQuiz'], 'id' | 'questionTitle' | 'questionDescription' | 'optionType' | '
|
|
5
|
+
export type MaterialQuizEditValue = Pick<GetOrgMaterialQuizGetResponses['materialQuiz'], 'id' | 'questionTitle' | 'questionDescription' | 'optionType' | 'optionsDefault' | 'answerInfoDefault' | 'answerHint' | 'isAutoGrade' | 'explanationInfo' | 'groups' | 'optionsSetEnabled'>;
|
|
6
6
|
export type MaterialQuizEditFormState = Pick<FormState<Record<string, any>>, 'isDirty' | 'isValid'>;
|
|
7
7
|
export interface MaterialQuizEditProps {
|
|
8
8
|
/** Value of material quiz edit form. */
|
|
@@ -9,8 +9,8 @@ var reactTransitionGroup = require('react-transition-group');
|
|
|
9
9
|
var blocks = require('@elice/blocks');
|
|
10
10
|
var markdown = require('@elice/markdown');
|
|
11
11
|
var types = require('@elice/types');
|
|
12
|
+
var material = require('@mui/material');
|
|
12
13
|
var flattenDeep = require('lodash-es/flattenDeep');
|
|
13
|
-
var styled = require('styled-components');
|
|
14
14
|
var OptionGroup = require('./options/options-group/OptionGroup.js');
|
|
15
15
|
var OptionSelectMultiple = require('./options/OptionSelectMultiple.js');
|
|
16
16
|
var OptionSelectMultipleOrder = require('./options/OptionSelectMultipleOrder.js');
|
|
@@ -22,9 +22,6 @@ var context = require('./context.js');
|
|
|
22
22
|
|
|
23
23
|
const MIN_TEXT_LENGTH = 1;
|
|
24
24
|
const MAX_TEXT_LENGTH = 128;
|
|
25
|
-
const StyledQuizOptionTypeSelectWrap = styled.div.withConfig({
|
|
26
|
-
componentId: "sc-1cf4b99-0"
|
|
27
|
-
})(["display:flex;max-width:12rem;"]);
|
|
28
25
|
const MaterialQuizEditContent = () => {
|
|
29
26
|
const intl = reactIntl.useIntl();
|
|
30
27
|
const {
|
|
@@ -36,13 +33,13 @@ const MaterialQuizEditContent = () => {
|
|
|
36
33
|
watch,
|
|
37
34
|
setValue
|
|
38
35
|
} = reactHookForm.useFormContext();
|
|
39
|
-
const [watchedOptionType, watchedOptionInfo, watchedAnswerInfo, watchedAnswerHint, watchedExplanationInfo, watchedIsAutoGrade, watchedGroups] = watch(['optionType', '
|
|
36
|
+
const [watchedOptionType, watchedOptionInfo, watchedAnswerInfo, watchedAnswerHint, watchedExplanationInfo, watchedIsAutoGrade, watchedGroups, optionsSetEnabled] = watch(['optionType', 'optionsDefault', 'answerInfoDefault', 'answerHint', 'explanationInfo', 'isAutoGrade', 'groups', 'optionsSetEnabled']);
|
|
40
37
|
//
|
|
41
38
|
// Change `options` according to `optionType`.
|
|
42
39
|
//
|
|
43
40
|
React.useEffect(() => {
|
|
44
41
|
const get = () => {
|
|
45
|
-
const filteredNotMarkdownOptions = watchedOptionInfo.filter(option => {
|
|
42
|
+
const filteredNotMarkdownOptions = watchedOptionInfo === null || watchedOptionInfo === void 0 ? void 0 : watchedOptionInfo.filter(option => {
|
|
46
43
|
var _a;
|
|
47
44
|
return !((_a = option.content) === null || _a === void 0 ? void 0 : _a.includes('![]'));
|
|
48
45
|
});
|
|
@@ -84,7 +81,7 @@ const MaterialQuizEditContent = () => {
|
|
|
84
81
|
}
|
|
85
82
|
return watchedOptionInfo;
|
|
86
83
|
case types.enums.QuizOptionType.Group:
|
|
87
|
-
if (!watchedOptionInfo.length) {
|
|
84
|
+
if (!(watchedOptionInfo === null || watchedOptionInfo === void 0 ? void 0 : watchedOptionInfo.length)) {
|
|
88
85
|
// add default option info
|
|
89
86
|
return [{
|
|
90
87
|
id: randomId.createRandomId(),
|
|
@@ -123,7 +120,7 @@ const MaterialQuizEditContent = () => {
|
|
|
123
120
|
return [];
|
|
124
121
|
}
|
|
125
122
|
};
|
|
126
|
-
setValue('
|
|
123
|
+
setValue('optionsDefault', get());
|
|
127
124
|
},
|
|
128
125
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
129
126
|
[watchedOptionType, setValue, intl]);
|
|
@@ -159,7 +156,7 @@ const MaterialQuizEditContent = () => {
|
|
|
159
156
|
return [];
|
|
160
157
|
}
|
|
161
158
|
};
|
|
162
|
-
setValue('
|
|
159
|
+
setValue('answerInfoDefault', get());
|
|
163
160
|
},
|
|
164
161
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
165
162
|
[watchedOptionType, setValue, intl]);
|
|
@@ -252,10 +249,10 @@ const MaterialQuizEditContent = () => {
|
|
|
252
249
|
return OptionSelectMultiple.default;
|
|
253
250
|
case types.enums.QuizOptionType.SelectMultipleOrder:
|
|
254
251
|
return OptionSelectMultipleOrder.default;
|
|
255
|
-
case types.enums.QuizOptionType.Text:
|
|
256
|
-
return OptionText.default;
|
|
257
252
|
case types.enums.QuizOptionType.Group:
|
|
258
253
|
return OptionGroup.default;
|
|
254
|
+
case types.enums.QuizOptionType.Text:
|
|
255
|
+
return OptionText.default;
|
|
259
256
|
default:
|
|
260
257
|
return React.Fragment;
|
|
261
258
|
}
|
|
@@ -361,56 +358,93 @@ const MaterialQuizEditContent = () => {
|
|
|
361
358
|
name: "optionType",
|
|
362
359
|
render: ({
|
|
363
360
|
field
|
|
364
|
-
}) => React.createElement(
|
|
365
|
-
title: disabled
|
|
366
|
-
id:
|
|
367
|
-
})
|
|
361
|
+
}) => React.createElement(material.Tooltip, {
|
|
362
|
+
title: disabled && React.createElement(reactIntl.FormattedMessage, {
|
|
363
|
+
id: "content.option.tooltip.disabled"
|
|
364
|
+
}),
|
|
368
365
|
placement: "top-end"
|
|
369
|
-
}, React.createElement(
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
366
|
+
}, React.createElement(material.Stack, {
|
|
367
|
+
direction: "row",
|
|
368
|
+
justifyContent: "space-between",
|
|
369
|
+
marginBottom: "0.5rem"
|
|
370
|
+
}, React.createElement(material.TextField, Object.assign({
|
|
371
|
+
select: true,
|
|
372
|
+
disabled: disabled
|
|
373
373
|
}, field, {
|
|
374
|
-
onChange:
|
|
375
|
-
|
|
374
|
+
onChange: event => {
|
|
375
|
+
const isTextQuizOption = Number(event.target.value) === types.enums.QuizOptionType.Text;
|
|
376
|
+
if (isTextQuizOption) {
|
|
377
|
+
setValue('optionsSetEnabled', false);
|
|
378
|
+
}
|
|
379
|
+
field.onChange(event);
|
|
380
|
+
}
|
|
381
|
+
}), React.createElement(material.MenuItem, {
|
|
376
382
|
value: types.enums.QuizOptionType.SelectOne,
|
|
377
383
|
children: intl.formatMessage({
|
|
378
384
|
id: 'content.option.select.items.selectOne'
|
|
379
385
|
})
|
|
380
|
-
}), React.createElement(
|
|
386
|
+
}), React.createElement(material.MenuItem, {
|
|
381
387
|
value: types.enums.QuizOptionType.SelectMultiple,
|
|
382
388
|
children: intl.formatMessage({
|
|
383
389
|
id: 'content.option.select.items.selectMultiple'
|
|
384
390
|
})
|
|
385
|
-
}), React.createElement(
|
|
391
|
+
}), React.createElement(material.MenuItem, {
|
|
386
392
|
value: types.enums.QuizOptionType.SelectMultipleOrder,
|
|
387
393
|
children: intl.formatMessage({
|
|
388
394
|
id: 'content.option.select.items.selectMultipleOrder'
|
|
389
395
|
})
|
|
390
|
-
}), React.createElement(
|
|
396
|
+
}), React.createElement(material.MenuItem, {
|
|
391
397
|
value: types.enums.QuizOptionType.Group,
|
|
392
398
|
children: intl.formatMessage({
|
|
393
399
|
id: 'content.option.select.items.group'
|
|
394
400
|
})
|
|
395
|
-
}), React.createElement(
|
|
401
|
+
}), React.createElement(material.MenuItem, {
|
|
396
402
|
value: types.enums.QuizOptionType.Text,
|
|
397
403
|
children: intl.formatMessage({
|
|
398
404
|
id: 'content.option.select.items.text'
|
|
399
405
|
})
|
|
400
|
-
}))
|
|
401
|
-
|
|
406
|
+
})), watchedOptionType !== types.enums.QuizOptionType.Text ? React.createElement(reactHookForm.Controller, {
|
|
407
|
+
name: "optionsSetEnabled",
|
|
408
|
+
control: control,
|
|
409
|
+
render: ({
|
|
410
|
+
field
|
|
411
|
+
}) => React.createElement(material.Tooltip, {
|
|
412
|
+
title: disabled ? '' : React.createElement(reactIntl.FormattedMessage, {
|
|
413
|
+
id: "content.option.optionsSetEnabled.tooltip"
|
|
414
|
+
}),
|
|
415
|
+
placement: "top"
|
|
416
|
+
}, React.createElement(material.FormControlLabel, {
|
|
417
|
+
disabled: disabled,
|
|
418
|
+
label: React.createElement(reactIntl.FormattedMessage, {
|
|
419
|
+
id: "content.option.optionsSetEnabled.label"
|
|
420
|
+
}),
|
|
421
|
+
control: React.createElement(material.Switch, Object.assign({}, field, {
|
|
422
|
+
checked: field.value
|
|
423
|
+
}))
|
|
424
|
+
}))
|
|
425
|
+
}) : null))
|
|
426
|
+
}), watchedOptionType !== types.enums.QuizOptionType.Text && optionsSetEnabled ? React.createElement(material.Alert, {
|
|
427
|
+
severity: "info",
|
|
428
|
+
sx: {
|
|
429
|
+
marginBottom: '1rem'
|
|
430
|
+
}
|
|
431
|
+
}, React.createElement(material.AlertTitle, null, React.createElement(reactIntl.FormattedMessage, {
|
|
432
|
+
id: "content.option.alert.randomized.title"
|
|
433
|
+
})), React.createElement(reactIntl.FormattedMessage, {
|
|
434
|
+
id: "content.option.alert.randomized.description"
|
|
435
|
+
})) : null, React.createElement(reactTransitionGroup.Transition, {
|
|
402
436
|
in: watchedOptionType === types.enums.QuizOptionType.SelectMultipleOrder || watchedOptionType === types.enums.QuizOptionType.Group,
|
|
403
437
|
timeout: 0,
|
|
404
438
|
mountOnEnter: true,
|
|
405
439
|
unmountOnExit: true
|
|
440
|
+
}, React.createElement(material.Box, {
|
|
441
|
+
marginBottom: "0.5rem"
|
|
406
442
|
}, React.createElement(blocks.StatusText, {
|
|
407
443
|
role: "description",
|
|
408
444
|
preWrap: true
|
|
409
445
|
}, React.createElement(reactIntl.FormattedMessage, {
|
|
410
446
|
id: watchedOptionType === types.enums.QuizOptionType.SelectMultipleOrder ? 'content.option.statusText.dragNDrop' : 'content.option.statusText.dragNDropGroup'
|
|
411
|
-
}))), React.createElement(
|
|
412
|
-
height: 0.5
|
|
413
|
-
}), React.createElement(Option, null))
|
|
447
|
+
})))), React.createElement(Option, null))
|
|
414
448
|
});
|
|
415
449
|
};
|
|
416
450
|
/**
|
|
@@ -13,6 +13,10 @@ export declare const en: {
|
|
|
13
13
|
'content.option.select.items.selectMultiple': string;
|
|
14
14
|
'content.option.select.items.selectMultipleOrder': string;
|
|
15
15
|
'content.option.select.items.text': string;
|
|
16
|
+
'content.option.optionsSetEnabled.label': string;
|
|
17
|
+
'content.option.optionsSetEnabled.tooltip': string;
|
|
18
|
+
'content.option.alert.randomized.title': string;
|
|
19
|
+
'content.option.alert.randomized.description': string;
|
|
16
20
|
'content.option.select.items.group': string;
|
|
17
21
|
'content.option.statusText.dragNDrop': string;
|
|
18
22
|
'content.option.statusText.dragNDropGroup': string;
|
|
@@ -15,6 +15,10 @@ const en = {
|
|
|
15
15
|
'content.option.select.items.selectMultiple': 'Multiple Choice (Multiple Answers)',
|
|
16
16
|
'content.option.select.items.selectMultipleOrder': 'Drag and Drop',
|
|
17
17
|
'content.option.select.items.text': 'Subjective',
|
|
18
|
+
'content.option.optionsSetEnabled.label': 'Shuffle answer order',
|
|
19
|
+
'content.option.optionsSetEnabled.tooltip': 'When the feature is enabled, the order of answers is shuffled for each student',
|
|
20
|
+
'content.option.alert.randomized.title': 'Shuffling the order of answers is enabled',
|
|
21
|
+
'content.option.alert.randomized.description': 'Students will see the order of their answers shuffled',
|
|
18
22
|
'content.option.select.items.group': 'Drag and Drop (Group Type)',
|
|
19
23
|
'content.option.statusText.dragNDrop': "After entering the options, click in the order of the correct answers.\nYou can check the configured problem in the Learner's Materials tab on the left.",
|
|
20
24
|
'content.option.statusText.dragNDropGroup': "You can check the configured problem in the Learner's Materials tab on the left.",
|
|
@@ -70,6 +74,10 @@ const ko = {
|
|
|
70
74
|
'content.option.select.items.selectMultiple': '객관식 (다중 선택)',
|
|
71
75
|
'content.option.select.items.selectMultipleOrder': '드래그 앤 드롭',
|
|
72
76
|
'content.option.select.items.text': '주관식',
|
|
77
|
+
'content.option.optionsSetEnabled.label': '답안 순서 섞기',
|
|
78
|
+
'content.option.optionsSetEnabled.tooltip': '기능 활성화 시 학생마다 답안의 순서가 섞여서 표시됩니다.',
|
|
79
|
+
'content.option.alert.randomized.title': '답안 순서 섞기가 활성화 되어있습니다.',
|
|
80
|
+
'content.option.alert.randomized.description': '학생에게 답안의 순서가 섞여서 표시됩니다.',
|
|
73
81
|
'content.option.select.items.group': '드래그 앤 드롭 (그룹형)',
|
|
74
82
|
'content.option.statusText.dragNDrop': '보기를 입력한 후 정답 순서대로 클릭하세요.\n구성된 문제는 좌측 학습자료 탭에서 확인하실 수 있습니다.',
|
|
75
83
|
'content.option.statusText.dragNDropGroup': '구성된 문제는 좌측 학습자료 탭에서 확인하실 수 있습니다.',
|
|
@@ -6,21 +6,26 @@ var tslib = require('tslib');
|
|
|
6
6
|
var React = require('react');
|
|
7
7
|
var blocks = require('@elice/blocks');
|
|
8
8
|
var designTokens = require('@elice/design-tokens');
|
|
9
|
+
var material = require('@mui/material');
|
|
9
10
|
var classNames = require('classnames');
|
|
10
11
|
var styled = require('styled-components');
|
|
11
12
|
|
|
12
13
|
//
|
|
13
14
|
//
|
|
14
15
|
//
|
|
16
|
+
const SHEET_Z_INDEX = 982; // prevent override blocks components.
|
|
15
17
|
const PREFIX = 'em-option-editor';
|
|
16
18
|
//
|
|
17
19
|
//
|
|
18
20
|
//
|
|
19
|
-
const
|
|
21
|
+
const StyledSortedListItem = styled(blocks.SortableListItem).withConfig({
|
|
20
22
|
componentId: "sc-50ghuz-0"
|
|
21
|
-
})(["padding:0
|
|
22
|
-
const
|
|
23
|
+
})(["display:flex;padding:0;flex:1;z-index:", ";padding:0;background:transparent;box-shadow:none;margin:0;"], SHEET_Z_INDEX + 1);
|
|
24
|
+
const StyledTextarea = styled(blocks.Textarea).withConfig({
|
|
23
25
|
componentId: "sc-50ghuz-1"
|
|
26
|
+
})(["padding:0.75rem 3rem;&.focus{border:1px solid ", ";}", ";", ";", ";"], designTokens.base.color.primary6, props => props.invalid ? styled.css(["border:1px solid ", " !important;"], designTokens.base.color.red8) : null, props => props.disabled ? styled.css(["background-color:", ";cursor:not-allowed;"], designTokens.base.color.gray2) : null, props => props.readOnly ? styled.css(["background-color:", ";"], designTokens.base.color.gray1) : null);
|
|
27
|
+
const StyledTextareaWrap = styled.div.withConfig({
|
|
28
|
+
componentId: "sc-50ghuz-2"
|
|
24
29
|
})(["display:flex;position:relative;.em-option-editor-adornment{position:absolute;top:50%;transform:translateY(-50%);z-index:1;&.prefix{left:1rem;}&.suffix{right:1rem;}}"]);
|
|
25
30
|
//
|
|
26
31
|
//
|
|
@@ -31,9 +36,10 @@ const OptionEditor = React.forwardRef((_a, ref) => {
|
|
|
31
36
|
prefix,
|
|
32
37
|
invalid,
|
|
33
38
|
invalidText,
|
|
34
|
-
readOnly
|
|
39
|
+
readOnly,
|
|
40
|
+
index
|
|
35
41
|
} = _a,
|
|
36
|
-
props = tslib.__rest(_a, ["suffix", "prefix", "invalid", "invalidText", "readOnly"]);
|
|
42
|
+
props = tslib.__rest(_a, ["suffix", "prefix", "invalid", "invalidText", "readOnly", "index"]);
|
|
37
43
|
/**
|
|
38
44
|
* Extract textarea element from legacy TextArea ref prop.
|
|
39
45
|
*/
|
|
@@ -45,8 +51,12 @@ const OptionEditor = React.forwardRef((_a, ref) => {
|
|
|
45
51
|
const textAreaInput = (_a = textAreaApi === null || textAreaApi === void 0 ? void 0 : textAreaApi.input) !== null && _a !== void 0 ? _a : null;
|
|
46
52
|
typeof ref === 'function' ? ref(textAreaInput) : ref.current = textAreaInput;
|
|
47
53
|
}, [ref]);
|
|
48
|
-
return React.createElement(
|
|
49
|
-
|
|
54
|
+
return React.createElement(StyledSortedListItem, {
|
|
55
|
+
index: index,
|
|
56
|
+
disabled: readOnly
|
|
57
|
+
}, React.createElement(material.Box, {
|
|
58
|
+
className: classNames(PREFIX, props.className),
|
|
59
|
+
flex: 1
|
|
50
60
|
}, React.createElement(StyledTextareaWrap, {
|
|
51
61
|
className: `${PREFIX}-textarea-wrapper`
|
|
52
62
|
}, prefix ? React.createElement("div", {
|
|
@@ -56,18 +66,22 @@ const OptionEditor = React.forwardRef((_a, ref) => {
|
|
|
56
66
|
invalid: invalid,
|
|
57
67
|
readOnly: readOnly,
|
|
58
68
|
resetFocus: props.onBlur,
|
|
69
|
+
disabled: readOnly,
|
|
59
70
|
"aria-disabled": props.disabled
|
|
60
71
|
})), suffix ? React.createElement("div", {
|
|
61
|
-
className: `${PREFIX}-adornment suffix
|
|
62
|
-
|
|
72
|
+
className: `${PREFIX}-adornment suffix`,
|
|
73
|
+
onDragStart: e => e.stopPropagation(),
|
|
74
|
+
onDragCapture: e => e.stopPropagation(),
|
|
75
|
+
onTouchStart: e => e.stopPropagation()
|
|
76
|
+
}, suffix) : null), invalid ? React.createElement(material.Box, {
|
|
63
77
|
padding: "0 0.75rem",
|
|
64
|
-
|
|
78
|
+
marginTop: "0.25rem",
|
|
65
79
|
className: `${PREFIX}-helperText-wrap`
|
|
66
80
|
}, React.createElement(blocks.Text, {
|
|
67
81
|
role: "red",
|
|
68
82
|
size: "tiny",
|
|
69
83
|
className: `${PREFIX}-helperText`
|
|
70
|
-
}, invalidText !== null && invalidText !== void 0 ? invalidText : '')) : null);
|
|
84
|
+
}, invalidText !== null && invalidText !== void 0 ? invalidText : '')) : null));
|
|
71
85
|
});
|
|
72
86
|
|
|
73
87
|
exports.default = OptionEditor;
|
|
@@ -5,9 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var reactHookForm = require('react-hook-form');
|
|
7
7
|
var reactIntl = require('react-intl');
|
|
8
|
+
var reactSortableHoc = require('react-sortable-hoc');
|
|
8
9
|
var reactTransitionGroup = require('react-transition-group');
|
|
9
10
|
var blocks = require('@elice/blocks');
|
|
10
11
|
var icons = require('@elice/icons');
|
|
12
|
+
var lodashEs = require('lodash-es');
|
|
11
13
|
var styled = require('styled-components');
|
|
12
14
|
var context = require('../context.js');
|
|
13
15
|
var randomId = require('../utils/randomId.js');
|
|
@@ -17,8 +19,8 @@ const MIN_OPTION_INFO_COUNT = 2;
|
|
|
17
19
|
const MAX_OPTION_INFO_COUNT = 20;
|
|
18
20
|
const StyledWrap = styled.div.withConfig({
|
|
19
21
|
componentId: "sc-1nbx9b8-0"
|
|
20
|
-
})([""]);
|
|
21
|
-
const StyledInputGroup = styled.
|
|
22
|
+
})(["& > ul{display:flex;flex-direction:column;gap:0.75rem;}"]);
|
|
23
|
+
const StyledInputGroup = styled(blocks.SortableListGroup).withConfig({
|
|
22
24
|
componentId: "sc-1nbx9b8-1"
|
|
23
25
|
})(["width:100%;.em-option-editor{margin-bottom:0.5rem;&:last-of-type{margin-bottom:0;}}"]);
|
|
24
26
|
const OptionSelectMultiple = () => {
|
|
@@ -29,29 +31,36 @@ const OptionSelectMultiple = () => {
|
|
|
29
31
|
const {
|
|
30
32
|
control,
|
|
31
33
|
getValues,
|
|
32
|
-
setValue
|
|
33
|
-
watch
|
|
34
|
+
setValue
|
|
34
35
|
} = reactHookForm.useFormContext();
|
|
35
36
|
const {
|
|
36
37
|
fields: optionInfoFields,
|
|
37
38
|
append: appendOptionInfoFieldItem,
|
|
38
|
-
remove: removeOptionInfoFieldItem
|
|
39
|
+
remove: removeOptionInfoFieldItem,
|
|
40
|
+
move: moveOptionInfoFieldItem
|
|
39
41
|
} = reactHookForm.useFieldArray({
|
|
40
42
|
control,
|
|
41
|
-
name: '
|
|
43
|
+
name: 'optionsDefault',
|
|
42
44
|
keyName: 'id',
|
|
43
45
|
shouldUnregister: true
|
|
44
46
|
});
|
|
45
|
-
const watchedAnswerInfo =
|
|
47
|
+
const watchedAnswerInfo = reactHookForm.useWatch({
|
|
48
|
+
control,
|
|
49
|
+
name: 'answerInfoDefault'
|
|
50
|
+
});
|
|
51
|
+
const watchedOptions = reactHookForm.useWatch({
|
|
52
|
+
control,
|
|
53
|
+
name: 'optionsDefault'
|
|
54
|
+
});
|
|
46
55
|
/**
|
|
47
56
|
* Update answer info.
|
|
48
57
|
*/
|
|
49
58
|
const updateAnswerInfo = option => {
|
|
50
|
-
const prevAnswerInfo = getValues('
|
|
59
|
+
const prevAnswerInfo = getValues('answerInfoDefault');
|
|
51
60
|
if (!Array.isArray(prevAnswerInfo)) {
|
|
52
61
|
return;
|
|
53
62
|
}
|
|
54
|
-
setValue('
|
|
63
|
+
setValue('answerInfoDefault', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
|
|
55
64
|
// if answer removed, re-calculate answer index
|
|
56
65
|
answerIndex < option.index ? answerIndex : answerIndex - 1 :
|
|
57
66
|
// or maintain current answer index
|
|
@@ -81,6 +90,22 @@ const OptionSelectMultiple = () => {
|
|
|
81
90
|
});
|
|
82
91
|
removeOptionInfoFieldItem(index);
|
|
83
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Sort options based on the old and new index.
|
|
95
|
+
*/
|
|
96
|
+
const handleSortEnd = ({
|
|
97
|
+
oldIndex,
|
|
98
|
+
newIndex
|
|
99
|
+
}) => {
|
|
100
|
+
const prevAnswerInfo = lodashEs.cloneDeep(watchedAnswerInfo);
|
|
101
|
+
const prevOptions = lodashEs.cloneDeep(watchedOptions).map((option, index) => Object.assign(Object.assign({}, option), {
|
|
102
|
+
isAnswer: prevAnswerInfo.includes(index)
|
|
103
|
+
}));
|
|
104
|
+
const updatedOptions = reactSortableHoc.arrayMove(prevOptions, oldIndex, newIndex);
|
|
105
|
+
const updatedAnswerInfo = updatedOptions.map((option, index) => option.isAnswer ? index : null).filter(option => option !== null);
|
|
106
|
+
setValue('answerInfoDefault', updatedAnswerInfo);
|
|
107
|
+
moveOptionInfoFieldItem(oldIndex, newIndex);
|
|
108
|
+
};
|
|
84
109
|
//
|
|
85
110
|
//
|
|
86
111
|
//
|
|
@@ -88,7 +113,7 @@ const OptionSelectMultiple = () => {
|
|
|
88
113
|
return null;
|
|
89
114
|
}
|
|
90
115
|
return React.createElement(StyledWrap, null, React.createElement(reactHookForm.Controller, {
|
|
91
|
-
name: "
|
|
116
|
+
name: "answerInfoDefault",
|
|
92
117
|
control: control,
|
|
93
118
|
rules: {
|
|
94
119
|
validate: v => {
|
|
@@ -116,12 +141,16 @@ const OptionSelectMultiple = () => {
|
|
|
116
141
|
height: 0.5
|
|
117
142
|
})));
|
|
118
143
|
}
|
|
119
|
-
}), React.createElement(StyledInputGroup,
|
|
144
|
+
}), React.createElement(StyledInputGroup, {
|
|
145
|
+
pressDelay: 100,
|
|
146
|
+
useDragHandle: true,
|
|
147
|
+
onSortEnd: handleSortEnd
|
|
148
|
+
}, optionInfoFields.map(({
|
|
120
149
|
id
|
|
121
150
|
}, index) => React.createElement(reactHookForm.Controller, {
|
|
122
151
|
key: id,
|
|
123
152
|
control: control,
|
|
124
|
-
name: `
|
|
153
|
+
name: `optionsDefault.${index}.content`,
|
|
125
154
|
rules: {
|
|
126
155
|
required: {
|
|
127
156
|
value: true,
|
|
@@ -136,6 +165,7 @@ const OptionSelectMultiple = () => {
|
|
|
136
165
|
}) => {
|
|
137
166
|
var _a;
|
|
138
167
|
return React.createElement(OptionEditor.default, Object.assign({
|
|
168
|
+
index: index,
|
|
139
169
|
invalid: fieldState.invalid,
|
|
140
170
|
invalidText: (_a = fieldState === null || fieldState === void 0 ? void 0 : fieldState.error) === null || _a === void 0 ? void 0 : _a.message,
|
|
141
171
|
readOnly: disabled,
|
|
@@ -5,9 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var reactHookForm = require('react-hook-form');
|
|
7
7
|
var reactIntl = require('react-intl');
|
|
8
|
+
var reactSortableHoc = require('react-sortable-hoc');
|
|
8
9
|
var reactTransitionGroup = require('react-transition-group');
|
|
9
10
|
var blocks = require('@elice/blocks');
|
|
10
11
|
var icons = require('@elice/icons');
|
|
12
|
+
var lodashEs = require('lodash-es');
|
|
11
13
|
var styled = require('styled-components');
|
|
12
14
|
var context = require('../context.js');
|
|
13
15
|
var randomId = require('../utils/randomId.js');
|
|
@@ -17,8 +19,8 @@ const MIN_OPTION_INFO_COUNT = 2;
|
|
|
17
19
|
const MAX_OPTION_INFO_COUNT = 20;
|
|
18
20
|
const StyledWrap = styled.div.withConfig({
|
|
19
21
|
componentId: "sc-1xufc1p-0"
|
|
20
|
-
})([""]);
|
|
21
|
-
const StyledInputGroup = styled.
|
|
22
|
+
})(["& > ul{display:flex;flex-direction:column;gap:0.75rem;}"]);
|
|
23
|
+
const StyledInputGroup = styled(blocks.SortableListGroup).withConfig({
|
|
22
24
|
componentId: "sc-1xufc1p-1"
|
|
23
25
|
})(["width:100%;.em-option-editor{margin-bottom:0.5rem;&:last-of-type{margin-bottom:0;}}"]);
|
|
24
26
|
const OptionSelectMultipleOrder = () => {
|
|
@@ -29,28 +31,35 @@ const OptionSelectMultipleOrder = () => {
|
|
|
29
31
|
const {
|
|
30
32
|
control,
|
|
31
33
|
getValues,
|
|
32
|
-
setValue
|
|
33
|
-
watch
|
|
34
|
+
setValue
|
|
34
35
|
} = reactHookForm.useFormContext();
|
|
35
36
|
const {
|
|
36
37
|
fields: optionInfoFields,
|
|
37
38
|
append: appendOptionInfoFieldItem,
|
|
38
|
-
remove: removeOptionInfoFieldItem
|
|
39
|
+
remove: removeOptionInfoFieldItem,
|
|
40
|
+
move: moveOptionInfoFieldItem
|
|
39
41
|
} = reactHookForm.useFieldArray({
|
|
40
|
-
name: '
|
|
42
|
+
name: 'optionsDefault',
|
|
41
43
|
keyName: 'id',
|
|
42
44
|
shouldUnregister: true
|
|
43
45
|
});
|
|
44
|
-
const watchedAnswerInfo =
|
|
46
|
+
const watchedAnswerInfo = reactHookForm.useWatch({
|
|
47
|
+
control,
|
|
48
|
+
name: 'answerInfoDefault'
|
|
49
|
+
});
|
|
50
|
+
const watchedOptions = reactHookForm.useWatch({
|
|
51
|
+
control,
|
|
52
|
+
name: 'optionsDefault'
|
|
53
|
+
});
|
|
45
54
|
/**
|
|
46
55
|
* Update answer info.
|
|
47
56
|
*/
|
|
48
57
|
const updateAnswerInfo = option => {
|
|
49
|
-
const prevAnswerInfo = getValues('
|
|
58
|
+
const prevAnswerInfo = getValues('answerInfoDefault');
|
|
50
59
|
if (!Array.isArray(prevAnswerInfo)) {
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
|
-
setValue('
|
|
62
|
+
setValue('answerInfoDefault', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
|
|
54
63
|
// if answer removed, re-calculate answer index
|
|
55
64
|
answerIndex < option.index ? answerIndex : answerIndex - 1 :
|
|
56
65
|
// or maintain current answer index
|
|
@@ -80,6 +89,21 @@ const OptionSelectMultipleOrder = () => {
|
|
|
80
89
|
});
|
|
81
90
|
removeOptionInfoFieldItem(index);
|
|
82
91
|
};
|
|
92
|
+
/**
|
|
93
|
+
* Sort options based on the old and new index.
|
|
94
|
+
*/
|
|
95
|
+
const handleSortEnd = ({
|
|
96
|
+
oldIndex,
|
|
97
|
+
newIndex
|
|
98
|
+
}) => {
|
|
99
|
+
const prevOptions = lodashEs.cloneDeep(watchedOptions).map((option, index) => Object.assign(Object.assign({}, option), {
|
|
100
|
+
originIndex: index
|
|
101
|
+
}));
|
|
102
|
+
const updatedOptions = reactSortableHoc.arrayMove(prevOptions, oldIndex, newIndex);
|
|
103
|
+
const updatedAnswerInfo = watchedAnswerInfo.map(answerIndex => updatedOptions.findIndex(option => option.originIndex === answerIndex));
|
|
104
|
+
setValue('answerInfoDefault', updatedAnswerInfo);
|
|
105
|
+
moveOptionInfoFieldItem(oldIndex, newIndex);
|
|
106
|
+
};
|
|
83
107
|
//
|
|
84
108
|
//
|
|
85
109
|
//
|
|
@@ -87,7 +111,7 @@ const OptionSelectMultipleOrder = () => {
|
|
|
87
111
|
return null;
|
|
88
112
|
}
|
|
89
113
|
return React.createElement(StyledWrap, null, React.createElement(reactHookForm.Controller, {
|
|
90
|
-
name: "
|
|
114
|
+
name: "answerInfoDefault",
|
|
91
115
|
control: control,
|
|
92
116
|
rules: {
|
|
93
117
|
validate: v => {
|
|
@@ -115,12 +139,15 @@ const OptionSelectMultipleOrder = () => {
|
|
|
115
139
|
height: 0.5
|
|
116
140
|
})));
|
|
117
141
|
}
|
|
118
|
-
}), React.createElement(StyledInputGroup,
|
|
142
|
+
}), React.createElement(StyledInputGroup, {
|
|
143
|
+
useDragHandle: true,
|
|
144
|
+
onSortEnd: handleSortEnd
|
|
145
|
+
}, optionInfoFields.map(({
|
|
119
146
|
id
|
|
120
147
|
}, index) => React.createElement(reactHookForm.Controller, {
|
|
121
148
|
key: id,
|
|
122
149
|
control: control,
|
|
123
|
-
name: `
|
|
150
|
+
name: `optionsDefault.${index}.content`,
|
|
124
151
|
rules: {
|
|
125
152
|
required: {
|
|
126
153
|
value: true,
|
|
@@ -135,12 +162,13 @@ const OptionSelectMultipleOrder = () => {
|
|
|
135
162
|
}) => {
|
|
136
163
|
var _a;
|
|
137
164
|
return React.createElement(OptionEditor.default, Object.assign({
|
|
165
|
+
index: index,
|
|
138
166
|
placeholder: intl.formatMessage({
|
|
139
167
|
id: 'option.common.select.placeholder'
|
|
140
168
|
}),
|
|
141
169
|
prefix: React.createElement(blocks.Checkbox, {
|
|
142
|
-
checked: watchedAnswerInfo.includes(index),
|
|
143
170
|
disabled: disabled,
|
|
171
|
+
checked: watchedAnswerInfo.includes(index),
|
|
144
172
|
altChar: watchedAnswerInfo.indexOf(index) + 1,
|
|
145
173
|
onChange: checked => updateAnswerInfo({
|
|
146
174
|
index,
|