@elice/material-quiz 1.240709.0 → 1.240711.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 (35) hide show
  1. package/cjs/components/material-quiz/MaterialQuiz.js +32 -12
  2. package/cjs/components/material-quiz/MaterialQuizInfo.js +57 -12
  3. package/cjs/components/material-quiz/MaterialQuizSelectMultiple.js +12 -5
  4. package/cjs/components/material-quiz/MaterialQuizSelectMultipleOrder.js +11 -5
  5. package/cjs/components/material-quiz/MaterialQuizSelectOne.js +12 -5
  6. package/cjs/components/material-quiz/MaterialQuizText.js +11 -5
  7. package/cjs/components/material-quiz/context/MaterialQuizContext.d.ts +2 -0
  8. package/cjs/components/material-quiz/context/MaterialQuizContext.js +14 -2
  9. package/cjs/components/material-quiz/locales/en.json.js +1 -1
  10. package/cjs/components/material-quiz/locales/ja.json.js +1 -1
  11. package/cjs/components/material-quiz/locales/ko.json.js +1 -1
  12. package/cjs/components/material-quiz/locales/th.json.js +1 -1
  13. package/cjs/components/material-quiz/material-quiz-group/MaterialQuizGroup.js +23 -30
  14. package/cjs/components/shared/QuestionBox.js +57 -37
  15. package/cjs/components/shared/utils/mergeRefs.d.ts +2 -0
  16. package/cjs/components/shared/utils/mergeRefs.js +11 -0
  17. package/cjs/hooks/useCaculatePassage.js +11 -3
  18. package/es/components/material-quiz/MaterialQuiz.js +32 -12
  19. package/es/components/material-quiz/MaterialQuizInfo.js +58 -13
  20. package/es/components/material-quiz/MaterialQuizSelectMultiple.js +14 -7
  21. package/es/components/material-quiz/MaterialQuizSelectMultipleOrder.js +12 -6
  22. package/es/components/material-quiz/MaterialQuizSelectOne.js +13 -6
  23. package/es/components/material-quiz/MaterialQuizText.js +12 -6
  24. package/es/components/material-quiz/context/MaterialQuizContext.d.ts +2 -0
  25. package/es/components/material-quiz/context/MaterialQuizContext.js +15 -3
  26. package/es/components/material-quiz/locales/en.json.js +1 -1
  27. package/es/components/material-quiz/locales/ja.json.js +1 -1
  28. package/es/components/material-quiz/locales/ko.json.js +1 -1
  29. package/es/components/material-quiz/locales/th.json.js +1 -1
  30. package/es/components/material-quiz/material-quiz-group/MaterialQuizGroup.js +24 -31
  31. package/es/components/shared/QuestionBox.js +57 -37
  32. package/es/components/shared/utils/mergeRefs.d.ts +2 -0
  33. package/es/components/shared/utils/mergeRefs.js +9 -0
  34. package/es/hooks/useCaculatePassage.js +12 -4
  35. package/package.json +5 -4
@@ -7,7 +7,7 @@ var apiClient = require('@elice/api-client');
7
7
  var blocks = require('@elice/blocks');
8
8
  var designTokens = require('@elice/design-tokens');
9
9
  var intl = require('@elice/intl');
10
- var markdown = require('@elice/markdown');
10
+ var material = require('@mui/material');
11
11
  var cloneDeep = require('lodash-es/cloneDeep');
12
12
  var flattenDeep = require('lodash-es/flattenDeep');
13
13
  var element = require('../../../constant/element.js');
@@ -16,6 +16,7 @@ var useCaculatePassage = require('../../../hooks/useCaculatePassage.js');
16
16
  var QuestionBox = require('../../shared/QuestionBox.js');
17
17
  var MaterialQuizContext = require('../context/MaterialQuizContext.js');
18
18
  var MaterialQuizAnswerExplanation = require('../MaterialQuizAnswerExplanation.js');
19
+ var MaterialQuizInfo = require('../MaterialQuizInfo.js');
19
20
  var QuizResultBadge = require('../QuizResultBadge.js');
20
21
  var QuizSubmitStatusText = require('../QuizSubmitStatusText.js');
21
22
  var context = require('./context/context.js');
@@ -31,7 +32,8 @@ const MaterialQuizGroup = () => {
31
32
  const {
32
33
  materialQuiz,
33
34
  userId,
34
- vertical
35
+ vertical,
36
+ isLongPassage
35
37
  } = MaterialQuizContext.useMaterialQuizState();
36
38
  const {
37
39
  onSubmit,
@@ -39,6 +41,7 @@ const MaterialQuizGroup = () => {
39
41
  refreshOrgMaterialQuiz,
40
42
  onDirty
41
43
  } = MaterialQuizContext.useMaterialQuizDispatch();
44
+ const theme = material.useTheme();
42
45
  const [groupList, setGroupList] = React.useState([]);
43
46
  const [optionList, setOptionList] = React.useState([]);
44
47
  const [currentAnswerList, setCurrentAnswerList] = React.useState([]);
@@ -47,9 +50,12 @@ const MaterialQuizGroup = () => {
47
50
  const [submitStatus, setSubmitStatus] = React.useState('idle');
48
51
  const [hasSubmitted, setHasSubmitted] = React.useState(false);
49
52
  const isNextActive = hasSubmitted && typeof onNext === 'function';
53
+ const isDisabled = !flattenDeep(currentAnswerList).length || !!userId;
50
54
  const {
51
- questionRef
55
+ questionRef,
56
+ containerRef
52
57
  } = useCaculatePassage.useCaculatePassage();
58
+ const isVisibleSideBySide = !vertical && isLongPassage;
53
59
  /**
54
60
  *
55
61
  */
@@ -231,7 +237,7 @@ const MaterialQuizGroup = () => {
231
237
  *
232
238
  */
233
239
  const renderQuizInfo = () => {
234
- if (!materialQuiz) {
240
+ if (!materialQuiz || isVisibleSideBySide) {
235
241
  return null;
236
242
  }
237
243
  return React.createElement(blocks.Flex, {
@@ -239,26 +245,9 @@ const MaterialQuizGroup = () => {
239
245
  id: element.MATERIAL_QUIZ_PASSIVE_ID,
240
246
  column: true,
241
247
  ref: questionRef
242
- }, React.createElement(blocks.Flex, null, React.createElement(blocks.Text, {
243
- bold: true,
244
- size: "large",
245
- customStyles: {
246
- color: designTokens.base.color.primary3,
247
- marginRight: '0.5rem'
248
- }
249
- }, 'Q.'), React.createElement(blocks.Text, {
250
- bold: true,
251
- role: "white",
252
- size: "large",
253
- wordBreak: "break-word"
254
- }, materialQuiz.questionTitle)), materialQuiz.questionDescription ? React.createElement(React.Fragment, null, React.createElement(blocks.Vspace, {
255
- height: 1
256
- }), React.createElement(markdown.MarkdownSSR, {
257
- children: materialQuiz.questionDescription,
258
- dark: true,
259
- paddingx: 0,
260
- paddingy: 0
261
- })) : null, React.createElement(MaterialQuizAnswerExplanation.default, null));
248
+ }, React.createElement(MaterialQuizInfo.default, {
249
+ renderWithBox: false
250
+ }));
262
251
  };
263
252
  //
264
253
  //
@@ -287,21 +276,25 @@ const MaterialQuizGroup = () => {
287
276
  submitResult: React.createElement(QuizResultBadge.default, {
288
277
  materialQuizResponse: materialQuizResponse
289
278
  }),
279
+ bodyContainerRef: containerRef,
290
280
  footerActions: [{
291
- border: true,
292
- disabled: !flattenDeep(currentAnswerList).length || !!userId,
281
+ border: false,
282
+ disabled: isDisabled,
293
283
  loading: submitStatus === 'pending',
294
284
  tabIndex: 0,
295
285
  transparent: false,
296
- role: isNextActive ? 'secondary' : 'lightpurple',
297
286
  onClick: handleSubmit,
298
287
  children: intl$1.formatMessage({
299
288
  id: isNextActive ? 'materialQuiz.resubmit' : 'materialQuiz.submit'
300
- })
289
+ }),
290
+ customStyles: {
291
+ backgroundColor: isNextActive ? theme.palette.secondary.main : isDisabled ? designTokens.base.color.gray6 : theme.palette.primary.main,
292
+ color: isNextActive ? theme.palette.secondary.contrastText : isDisabled ? designTokens.base.color.gray3 : theme.palette.primary.contrastText
293
+ }
301
294
  }]
302
- }, renderQuizInfo(), vertical ? React.createElement("div", {
295
+ }, renderQuizInfo(), vertical || isVisibleSideBySide ? React.createElement("div", {
303
296
  id: element.MATERIAL_QUIZ_ANSWER_ID
304
- }, React.createElement(MaterialQuizGroupMobile.default, null)) : React.createElement(MaterialQuizGroupDesktop.default, null)));
297
+ }, React.createElement(MaterialQuizGroupMobile.default, null)) : React.createElement(React.Fragment, null, React.createElement(MaterialQuizGroupDesktop.default, null)), React.createElement(MaterialQuizAnswerExplanation.default, null)));
305
298
  };
306
299
  var MaterialQuizGroup$1 = MaterialQuizGroup;
307
300
 
@@ -8,10 +8,16 @@ var reactUse = require('react-use');
8
8
  var blocks = require('@elice/blocks');
9
9
  var designTokens = require('@elice/design-tokens');
10
10
  var intl = require('@elice/intl');
11
+ var material = require('@mui/material');
12
+ var animateScrollTo = require('animated-scroll-to');
11
13
  var styled = require('styled-components');
12
14
  var element = require('../../constant/element.js');
13
15
  var MaterialQuizContext = require('../material-quiz/context/MaterialQuizContext.js');
16
+ var mergeRefs = require('./utils/mergeRefs.js');
14
17
 
18
+ const easeInOutCubic = t => {
19
+ return t < 0.5 ? 4 * Math.pow(t, 3) : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
20
+ };
15
21
  const StyledQuestionBox = styled.div.withConfig({
16
22
  componentId: "sc-6qfyxj-0"
17
23
  })(["position:relative;display:flex;flex-direction:column;overflow:", ";border-radius:", ";width:100%;background-color:", ";", ";"], ({
@@ -26,7 +32,9 @@ const StyledQuestionBox = styled.div.withConfig({
26
32
  `);
27
33
  const StyledQuestionBoxHeader = styled.div.withConfig({
28
34
  componentId: "sc-6qfyxj-1"
29
- })(["display:flex;justify-content:space-between;background-color:", ";padding:1.5rem;flex:none;", ""], designTokens.base.color.navy8, ({
35
+ })(["display:flex;justify-content:space-between;background-color:", ";padding:", ";flex:none;", ""], designTokens.base.color.navy8, ({
36
+ vertical
37
+ }) => !vertical ? '1.5rem' : '1.5rem 1rem 1rem', ({
30
38
  vertical
31
39
  }) => vertical ? `
32
40
  position: sticky;
@@ -36,18 +44,16 @@ const StyledQuestionBoxHeader = styled.div.withConfig({
36
44
  ` : '');
37
45
  const StyledQuestionBoxBody = styled.div.withConfig({
38
46
  componentId: "sc-6qfyxj-2"
39
- })(["background-color:", ";flex:", ";", ";"], designTokens.base.color.navy8, ({
40
- vertical
41
- }) => vertical ? 'none' : 'auto', ({
47
+ })(["background-color:", ";flex:auto;", ";"], designTokens.base.color.navy8, ({
42
48
  hasFooter,
43
49
  vertical
44
- }) => hasFooter && !vertical ? 'height: 100%; padding: 0 1.5rem 1.5rem; overflow-y: auto;' : 'padding: 1.5rem');
50
+ }) => hasFooter && !vertical ? 'height: 100%; padding: 0 1.5rem 1.5rem; overflow-y: auto;' : 'padding: 0.25rem 1.5rem 1.5rem');
45
51
  const StyledAnchorBox = styled.div.withConfig({
46
52
  componentId: "sc-6qfyxj-3"
47
53
  })(["position:sticky;bottom:0;left:0;display:flex;justify-content:center;background-color:", ";border-top:1px solid ", ";"], designTokens.base.color.navy8, designTokens.base.color.gray7);
48
54
  const StyledQuestionBoxFooter = styled.div.withConfig({
49
55
  componentId: "sc-6qfyxj-4"
50
- })(["flex:none;display:flex;align-items:center;padding:1rem 1.5rem 1.5rem;background-color:", ";", ""], designTokens.base.color.navy8, ({
56
+ })(["flex:none;display:flex;align-items:center;padding:1rem;background-color:", ";", ""], designTokens.base.color.navy8, ({
51
57
  vertical
52
58
  }) => {
53
59
  return vertical ? `
@@ -66,16 +72,6 @@ const StyledQuestionBoxFooterActions = styled.div.withConfig({
66
72
  }) => {
67
73
  return vertical ? 'width: 100%' : '';
68
74
  });
69
- const StyledQuestionBoxFooterStatus = styled.div.withConfig({
70
- componentId: "sc-6qfyxj-6"
71
- })(["margin-left:0.75rem;", ""], ({
72
- vertical
73
- }) => {
74
- return vertical ? `
75
- margin-top: 0.75rem;
76
- order: 1;
77
- ` : '';
78
- });
79
75
  const QuestionBox = _a => {
80
76
  var {
81
77
  children,
@@ -89,18 +85,22 @@ const QuestionBox = _a => {
89
85
  bodyContainerRef
90
86
  } = _a,
91
87
  props = tslib.__rest(_a, ["children", "footerActions", "title", "titlePrefix", "submitResult", "submitStatus", "onNext", "isNextActive", "bodyContainerRef"]);
88
+ const theme = material.useTheme();
92
89
  const intl$1 = intl.useRawEliceIntl();
93
90
  const {
94
91
  vertical,
95
92
  isLongPassage
96
93
  } = MaterialQuizContext.useMaterialQuizState();
97
94
  const intersectionRef = React.useRef(null);
95
+ const headerRef = React.useRef(null);
96
+ const bodyRef = React.useRef(null);
97
+ const currentBodyRef = mergeRefs.mergeRefs(bodyContainerRef, bodyRef);
98
98
  const hasFooter = footerActions.length > 0;
99
99
  const visibleAnchorSection = vertical && isLongPassage;
100
100
  const intersection = reactUse.useIntersection(intersectionRef, {
101
101
  root: null,
102
102
  rootMargin: '0px',
103
- threshold: 1
103
+ threshold: 0.1
104
104
  });
105
105
  const isViewingAnswerContainer = Boolean(intersection === null || intersection === void 0 ? void 0 : intersection.isIntersecting);
106
106
  React.useEffect(() => {
@@ -108,15 +108,22 @@ const QuestionBox = _a => {
108
108
  // only enable for vertical mode
109
109
  if (answerContainer && vertical) intersectionRef.current = answerContainer;
110
110
  }, [intersectionRef, vertical]);
111
- const scrollToElement = elementId => {
111
+ const scrollToElement = async elementId => {
112
+ var _a, _b;
112
113
  const target = document.getElementById(elementId);
113
- target && target.scrollIntoView({
114
- behavior: 'smooth',
115
- block: 'start'
116
- });
114
+ if (target && bodyRef.current) {
115
+ await animateScrollTo(target.offsetTop, {
116
+ elementToScroll: bodyRef.current,
117
+ verticalOffset: -((_b = (_a = headerRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0),
118
+ easing: easeInOutCubic,
119
+ minDuration: 50,
120
+ speed: 200
121
+ });
122
+ }
117
123
  };
118
124
  const header = title ? React.createElement(StyledQuestionBoxHeader, {
119
- vertical: vertical
125
+ vertical: vertical,
126
+ ref: headerRef
120
127
  }, React.createElement(blocks.Flex, null, titlePrefix ? React.createElement(blocks.Text, {
121
128
  bold: true,
122
129
  size: "large",
@@ -131,36 +138,38 @@ const QuestionBox = _a => {
131
138
  wordBreak: "break-word"
132
139
  }, title)), submitResult ? React.createElement(blocks.Box, null, submitResult) : null) : null;
133
140
  const body = React.createElement(StyledQuestionBoxBody, {
141
+ ref: !vertical ? currentBodyRef : undefined,
134
142
  hasFooter: hasFooter,
135
- ref: bodyContainerRef,
136
143
  vertical: vertical
137
144
  }, children);
138
145
  const footer = React.createElement(StyledQuestionBoxFooter, {
139
146
  vertical: vertical
140
- }, React.createElement(StyledQuestionBoxFooterStatus, {
141
- vertical: vertical
142
- }, submitStatus), React.createElement(StyledQuestionBoxFooterActions, {
147
+ }, React.createElement(StyledQuestionBoxFooterActions, {
143
148
  vertical: vertical
144
149
  }, footerActions.map((action, index) => React.createElement(blocks.Button, Object.assign({
145
- isFluid: true,
150
+ isFluid: vertical,
146
151
  key: index,
147
152
  size: "small"
148
153
  }, action), action.children)), isNextActive ? React.createElement(blocks.Button, {
149
- isFluid: true,
154
+ isFluid: vertical,
150
155
  size: "small",
151
- border: true,
156
+ border: false,
152
157
  tabIndex: 0,
153
158
  transparent: false,
154
- role: "lightpurple",
155
- onClick: onNext
159
+ onClick: onNext,
160
+ customStyles: {
161
+ backgroundColor: theme.palette.primary.main,
162
+ color: theme.palette.primary.contrastText
163
+ }
156
164
  }, intl$1.formatMessage({
157
165
  id: 'materialQuiz.next'
158
166
  })) : null));
159
167
  const _renderAnchorSection = () => {
160
168
  const getCustomStyles = active => ({
161
- borderBottom: active ? '3px solid currentColor' : 'none',
169
+ borderBottom: '3px solid currentColor',
162
170
  background: 'none',
163
- paddingBlock: '1.5rem'
171
+ borderColor: active ? 'currentColor' : 'transparent',
172
+ color: active ? theme.palette.primary.main : theme.palette.secondary.light
164
173
  });
165
174
  return visibleAnchorSection && React.createElement(StyledAnchorBox, null, React.createElement(blocks.Button, {
166
175
  size: "small",
@@ -168,7 +177,6 @@ const QuestionBox = _a => {
168
177
  hasBorderRadius: false,
169
178
  tabIndex: 0,
170
179
  transparent: true,
171
- role: isViewingAnswerContainer ? 'white' : 'primary',
172
180
  onClick: scrollToElement.bind(null, element.MATERIAL_QUIZ_PASSIVE_ID),
173
181
  customStyles: getCustomStyles(!isViewingAnswerContainer)
174
182
  }, intl$1.formatMessage({
@@ -179,16 +187,28 @@ const QuestionBox = _a => {
179
187
  hasBorderRadius: false,
180
188
  tabIndex: 0,
181
189
  transparent: true,
182
- role: isViewingAnswerContainer ? 'primary' : 'white',
183
190
  onClick: scrollToElement.bind(null, element.MATERIAL_QUIZ_ANSWER_ID),
184
191
  customStyles: getCustomStyles(isViewingAnswerContainer)
185
192
  }, intl$1.formatMessage({
186
193
  id: 'materialQuiz.anchorLabel.answer'
187
194
  })));
188
195
  };
196
+ const renderContent = () => {
197
+ const content = React.createElement(React.Fragment, null, body, footerActions.length > 0 ? footer : null);
198
+ if (vertical) {
199
+ return React.createElement("div", {
200
+ ref: currentBodyRef,
201
+ style: {
202
+ height: '100%',
203
+ overflow: 'auto'
204
+ }
205
+ }, content);
206
+ }
207
+ return content;
208
+ };
189
209
  return React.createElement(StyledQuestionBox, Object.assign({}, props, {
190
210
  vertical: vertical
191
- }), header, body, footerActions.length > 0 ? footer : null, _renderAnchorSection());
211
+ }), header, renderContent(), _renderAnchorSection());
192
212
  };
193
213
 
194
214
  exports.StyledQuestionBox = StyledQuestionBox;
@@ -0,0 +1,2 @@
1
+ import type { Ref, RefCallback } from 'react';
2
+ export declare const mergeRefs: <T>(...refs: (Ref<T> | undefined)[]) => RefCallback<T>;
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ const mergeRefs = (...refs) => element => refs.forEach(ref => {
4
+ if (typeof ref === 'function') {
5
+ ref(element);
6
+ } else if (ref && typeof ref === 'object') {
7
+ ref.current = element;
8
+ }
9
+ });
10
+
11
+ exports.mergeRefs = mergeRefs;
@@ -11,7 +11,8 @@ const useCaculatePassage = () => {
11
11
  vertical
12
12
  } = MaterialQuizContext.useMaterialQuizState();
13
13
  const {
14
- setIsLongPassage
14
+ setIsLongPassage,
15
+ setIsInitialLoading
15
16
  } = MaterialQuizContext.useMaterialQuizDispatch();
16
17
  const [questionRef, {
17
18
  height: questionDetailHeight
@@ -19,13 +20,20 @@ const useCaculatePassage = () => {
19
20
  const [containerRef, {
20
21
  height: containerHeight
21
22
  }] = reactUse.useMeasure();
22
- React.useLayoutEffect(() => {
23
+ React.useEffect(() => {
23
24
  var _a, _b;
24
25
  const currentContainerHeight = vertical ? (_b = (_a = document.getElementById(element.MATERIAL_QUIZ_CONTAINER_ID)) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0 : containerHeight;
25
26
  if (currentContainerHeight && questionDetailHeight && materialQuiz) {
26
27
  setIsLongPassage(questionDetailHeight > currentContainerHeight);
28
+ // add timeout for forcing caculate layout and render in the parent
29
+ // finish before turning off loading
30
+ setTimeout(() => {
31
+ setIsInitialLoading(false);
32
+ }, 300);
33
+ } else if (materialQuiz && !materialQuiz.questionDescription) {
34
+ setIsInitialLoading(false);
27
35
  }
28
- }, [containerHeight, questionDetailHeight, materialQuiz, setIsLongPassage, vertical]);
36
+ }, [containerHeight, questionDetailHeight, materialQuiz, setIsLongPassage, vertical, setIsInitialLoading]);
29
37
  return {
30
38
  questionRef,
31
39
  containerRef
@@ -2,7 +2,9 @@ import React from 'react';
2
2
  import { useMeasure } from 'react-use';
3
3
  import { base } from '@elice/design-tokens';
4
4
  import { IntlComponentBuilder, RawEliceIntlProvider } from '@elice/intl';
5
+ import { createEliceTheme } from '@elice/mui-system';
5
6
  import { enums } from '@elice/types';
7
+ import { ThemeProvider } from '@mui/material';
6
8
  import styled from 'styled-components';
7
9
  import { MATERIAL_QUIZ_CONTAINER_ID } from '../../constant/element.js';
8
10
  import { MaterialQuizProvider, useMaterialQuizState, useMaterialQuizDispatch } from './context/MaterialQuizContext.js';
@@ -11,27 +13,39 @@ import messageKo from './locales/ko.json.js';
11
13
  import MaterialQuizShimmer from './MaterialQuizShimmer.js';
12
14
  import MaterialQuizInfo from './MaterialQuizInfo.js';
13
15
 
16
+ const eliceTheme = createEliceTheme({
17
+ paletteMode: 'dark',
18
+ paletteName: 'purple'
19
+ });
14
20
  const AsyncMaterialQuizSelectMultiple = React.lazy(() => import('./MaterialQuizSelectMultiple.js'));
15
21
  const AsyncMaterialQuizSelectMultipleOrder = React.lazy(() => import('./MaterialQuizSelectMultipleOrder.js'));
16
22
  const AsyncMaterialQuizText = React.lazy(() => import('./MaterialQuizText.js'));
17
23
  const AsyncMaterialQuizSelectOne = React.lazy(() => import('./MaterialQuizSelectOne.js'));
18
24
  const AsyncMaterialQuizGroup = React.lazy(() => import('./material-quiz-group/index.js'));
25
+ // 746px
26
+ const MAX_CONTENT_WIDTH = '46.625rem';
19
27
  const StyledMaterialQuizInfo = styled.div.withConfig({
20
28
  componentId: "sc-1eyn8fb-0"
21
29
  })([""]);
22
30
  const StyledMaterialQuizContent = styled.div.withConfig({
23
31
  componentId: "sc-1eyn8fb-1"
24
- })(["min-width:0;margin:", ";height:100%;"], ({
32
+ })(["position:relative;z-index:0;min-width:0;margin:", ";height:100%;"], ({
25
33
  vertical
26
34
  }) => vertical ? 'unset' : 'auto');
27
- const StyledMaterialQuizWrapper = styled.div.withConfig({
35
+ const LoadingContainer = styled.div.withConfig({
28
36
  componentId: "sc-1eyn8fb-2"
29
- })(["-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;width:100%;height:100%;flex-direction:", ";& > *{flex:", ";}gap:1rem;", "{height:", ";overflow-y:", ";& > div{max-height:unset;}}"], ({
37
+ })(["position:absolute;width:100%;height:100%;top:0;left:0;z-index:1;max-width:none !important;background-color:", ";"], base.color.navy8);
38
+ const StyledMaterialQuizWrapper = styled.div.withConfig({
39
+ componentId: "sc-1eyn8fb-3"
40
+ })(["-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:flex;width:100%;height:100%;flex-direction:", ";position:relative;& > *{flex:", ";max-width:", ";}gap:1rem;", "{height:", ";overflow-y:", ";& > div{max-height:unset;}}"], ({
30
41
  vertical
31
42
  }) => vertical ? 'column' : 'row', ({
43
+ vertical
44
+ }) => vertical ? 'auto' : '1', ({
32
45
  vertical,
33
- isQuizGroupType
34
- }) => vertical || isQuizGroupType ? 'auto' : '0.5', StyledMaterialQuizInfo, ({
46
+ isQuizGroupType,
47
+ isLongPassage
48
+ }) => !isLongPassage && !vertical && !isQuizGroupType ? `${MAX_CONTENT_WIDTH}` : 'unset', StyledMaterialQuizInfo, ({
35
49
  vertical
36
50
  }) => vertical ? 'auto' : '100%', ({
37
51
  vertical
@@ -41,7 +55,8 @@ const MaterialQuiz = () => {
41
55
  materialQuiz,
42
56
  vertical,
43
57
  course,
44
- isLongPassage
58
+ isLongPassage,
59
+ isInitialLoading
45
60
  } = useMaterialQuizState();
46
61
  const {
47
62
  setVertical
@@ -50,7 +65,9 @@ const MaterialQuiz = () => {
50
65
  width
51
66
  }] = useMeasure();
52
67
  const isQuizGroupType = Boolean((materialQuiz === null || materialQuiz === void 0 ? void 0 : materialQuiz.optionType) === enums.QuizOptionType.Group);
53
- const isVisibleSideBySide = !vertical && isLongPassage && !isQuizGroupType;
68
+ const isFetchingData = !materialQuiz || !course;
69
+ const isLoadingLayout = isFetchingData || isInitialLoading;
70
+ const isVisibleSideBySide = !vertical && isLongPassage;
54
71
  const isRenderQuestionWithPassage = (vertical || !isLongPassage || isQuizGroupType) && !!materialQuiz;
55
72
  React.useEffect(() => {
56
73
  if (width > 0) {
@@ -58,8 +75,8 @@ const MaterialQuiz = () => {
58
75
  }
59
76
  }, [width, setVertical]);
60
77
  const renderQuestionOption = () => {
61
- if (!materialQuiz || !course) {
62
- return React.createElement(MaterialQuizShimmer, null);
78
+ if (isFetchingData) {
79
+ return null;
63
80
  }
64
81
  switch (materialQuiz.optionType) {
65
82
  case enums.QuizOptionType.SelectOne:
@@ -87,8 +104,9 @@ const MaterialQuiz = () => {
87
104
  }, React.createElement(StyledMaterialQuizWrapper, {
88
105
  ref: ref,
89
106
  vertical: vertical,
90
- isQuizGroupType: isQuizGroupType
91
- }, isVisibleSideBySide && React.createElement(StyledMaterialQuizInfo, null, React.createElement(MaterialQuizInfo, null)), React.createElement(StyledMaterialQuizContent, {
107
+ isQuizGroupType: isQuizGroupType,
108
+ isLongPassage: isLongPassage
109
+ }, isLoadingLayout && React.createElement(LoadingContainer, null, React.createElement(MaterialQuizShimmer, null)), isVisibleSideBySide && React.createElement(StyledMaterialQuizInfo, null, React.createElement(MaterialQuizInfo, null)), React.createElement(StyledMaterialQuizContent, {
92
110
  id: MATERIAL_QUIZ_CONTAINER_ID,
93
111
  vertical: vertical
94
112
  }, renderQuestionOption())));
@@ -103,13 +121,15 @@ const MaterialQuizContainer = ({
103
121
  }) => {
104
122
  return React.createElement(RawEliceIntlProvider, {
105
123
  value: __intl
124
+ }, React.createElement(ThemeProvider, {
125
+ theme: eliceTheme
106
126
  }, React.createElement(MaterialQuizProvider, {
107
127
  materialQuizId: materialQuizId,
108
128
  userId: userId,
109
129
  onDirty: onDirty,
110
130
  onSubmit: onSubmit,
111
131
  onNext: onNext
112
- }, React.createElement(MaterialQuiz, null)));
132
+ }, React.createElement(MaterialQuiz, null))));
113
133
  };
114
134
  var MaterialQuiz$1 = new IntlComponentBuilder(MaterialQuizContainer).add('en', messageEn).add('ko', messageKo).addAsync('th', import('./locales/th.json.js')).addAsync('ja', import('./locales/ja.json.js')).build();
115
135
 
@@ -1,13 +1,13 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
+ import { useMeasure } from 'react-use';
2
3
  import { Vspace, Shimmer, IconButton } from '@elice/blocks';
3
- import { base } from '@elice/design-tokens';
4
4
  import { eilMathsignMultiplyBasic } from '@elice/icons';
5
5
  import { MarkdownSSR } from '@elice/markdown';
6
- import { Modal, Box } from '@mui/material';
6
+ import { styled as styled$1, Modal, Box } from '@mui/material';
7
7
  import styled from 'styled-components';
8
8
  import QuestionBox from '../shared/QuestionBox.js';
9
+ import { mergeRefs } from '../shared/utils/mergeRefs.js';
9
10
  import { useMaterialQuizState } from './context/MaterialQuizContext.js';
10
- import MaterialQuizAnswerExplanation from './MaterialQuizAnswerExplanation.js';
11
11
 
12
12
  //
13
13
  //
@@ -20,23 +20,51 @@ const StyledMarkdownSSR = styled(MarkdownSSR).withConfig({
20
20
  //
21
21
  const IMAGE_CONTAINER_CLASSNAME = 'markdown-zoomable-image-container';
22
22
  const ZOOM_ICON_CLASSNAME = 'markdown-zoom-icon';
23
- const MarkdownContainer = styled.div.withConfig({
24
- componentId: "sc-1s7jbf9-1"
25
- })([".", "{position:relative;span.", "{cursor:pointer;position:absolute;right:0;top:0;width:2rem;aspect-ratio:1;background-color:", ";margin:0.5rem;border-radius:50%;display:flex;align-items:center;justify-content:center;}}"], IMAGE_CONTAINER_CLASSNAME, ZOOM_ICON_CLASSNAME, base.color.tertiary9);
23
+ const MarkdownContainer = styled$1('div')`
24
+ .${IMAGE_CONTAINER_CLASSNAME} {
25
+ position: relative;
26
+
27
+ span.${ZOOM_ICON_CLASSNAME} {
28
+ cursor: pointer;
29
+
30
+ position: absolute;
31
+ top: 0;
32
+ right: ${({
33
+ vertical
34
+ }) => vertical ? '0!important' : '0'};
35
+
36
+ width: 2rem;
37
+ aspect-ratio: 1;
38
+ background-color: ${({
39
+ theme
40
+ }) => theme.palette.inverse.main};
41
+ margin: 0.5rem;
42
+ border-radius: 50%;
43
+
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ }
48
+ }
49
+ `;
26
50
  const MaterialQuizInfo = ({
27
51
  renderWithBox = true
28
52
  }) => {
29
53
  const {
30
- materialQuiz
54
+ materialQuiz,
55
+ vertical
31
56
  } = useMaterialQuizState();
32
57
  const [isRenderFinish, setIsRenderFinish] = useState(false);
33
58
  const containerRef = useRef(null);
59
+ const [markdownMeasueRef, {
60
+ width
61
+ }] = useMeasure();
62
+ const ref = mergeRefs(containerRef, markdownMeasueRef);
34
63
  const [zoomImageUrl, setZoomImageUrl] = useState('');
35
64
  useEffect(() => {
36
65
  if (!(materialQuiz === null || materialQuiz === void 0 ? void 0 : materialQuiz.questionDescription) || !isRenderFinish || !containerRef.current) return;
37
- const images = containerRef.current.querySelectorAll('img');
38
66
  // append zoom icon for image html render by MarkdownSSR
39
- images.forEach(img => {
67
+ containerRef.current.querySelectorAll('img').forEach(img => {
40
68
  const parent = img.parentElement;
41
69
  const zoomIconStr = `
42
70
  <svg width="25" height="25" viewBox="0 0 25 25" fill="white" xmlns="http://www.w3.org/2000/svg">
@@ -44,27 +72,44 @@ const MaterialQuizInfo = ({
44
72
  </svg>
45
73
  `;
46
74
  if (parent) {
75
+ const imageRect = img.getBoundingClientRect();
76
+ const parentRect = parent.getBoundingClientRect();
77
+ const zoomIcons = parent.querySelectorAll(`.${ZOOM_ICON_CLASSNAME}`);
78
+ const totalImages = Array.from(parent.querySelectorAll(`img`));
79
+ const idx = totalImages.findIndex(item => item === img);
80
+ // restyle the zoom position when chaging the width instead of recreate it
81
+ if (zoomIcons.length === totalImages.length && idx !== -1) {
82
+ zoomIcons[idx].style.top = `${imageRect.top - parentRect.top}px`;
83
+ zoomIcons[idx].style.right = `${parentRect.right - imageRect.right}px`;
84
+ return;
85
+ }
47
86
  parent.classList.add(IMAGE_CONTAINER_CLASSNAME);
48
87
  parent.style.position = 'relative';
49
88
  const span = document.createElement('span');
50
89
  span.innerHTML = zoomIconStr;
51
90
  span.classList.add(ZOOM_ICON_CLASSNAME);
91
+ span.style.top = `${imageRect.top - parentRect.top}px`;
92
+ span.style.right = `${parentRect.right - imageRect.right}px`;
52
93
  span.onclick = () => {
53
94
  setZoomImageUrl(img.src);
54
95
  };
55
96
  parent.appendChild(span);
56
97
  }
57
98
  });
58
- }, [materialQuiz === null || materialQuiz === void 0 ? void 0 : materialQuiz.questionDescription, isRenderFinish]);
99
+ }, [materialQuiz === null || materialQuiz === void 0 ? void 0 : materialQuiz.questionDescription, isRenderFinish, width]);
59
100
  const onCloseImageModal = () => {
60
101
  setZoomImageUrl('');
61
102
  };
62
103
  const _renderQuiz = () => {
63
104
  return React.createElement(React.Fragment, null, materialQuiz ? React.createElement(MarkdownContainer, {
64
- ref: containerRef
105
+ ref: ref,
106
+ vertical: vertical
65
107
  }, React.createElement(StyledMarkdownSSR, {
66
108
  onRender: () => {
67
- setIsRenderFinish(true);
109
+ // set timeout for waiting time to the image can render
110
+ setTimeout(() => {
111
+ setIsRenderFinish(true);
112
+ }, 300);
68
113
  },
69
114
  children: materialQuiz === null || materialQuiz === void 0 ? void 0 : materialQuiz.questionDescription,
70
115
  dark: true,
@@ -137,7 +182,7 @@ const MaterialQuizInfo = ({
137
182
  top: '-10%'
138
183
  },
139
184
  onClick: onCloseImageModal
140
- }))), React.createElement(MaterialQuizAnswerExplanation, null));
185
+ }))));
141
186
  };
142
187
  if (renderWithBox) return React.createElement(QuestionBox, null, _renderQuiz());
143
188
  return React.createElement(React.Fragment, null, _renderQuiz());