@pie-lib/text-select 1.32.2-next.0 → 1.34.0-mui-update.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/CHANGELOG.md +19 -10
- package/lib/index.js +1 -12
- package/lib/index.js.map +1 -1
- package/lib/legend.js +87 -91
- package/lib/legend.js.map +1 -1
- package/lib/text-select.js +18 -51
- package/lib/text-select.js.map +1 -1
- package/lib/token-select/index.js +77 -129
- package/lib/token-select/index.js.map +1 -1
- package/lib/token-select/token.js +160 -189
- package/lib/token-select/token.js.map +1 -1
- package/lib/tokenizer/builder.js +23 -68
- package/lib/tokenizer/builder.js.map +1 -1
- package/lib/tokenizer/controls.js +50 -81
- package/lib/tokenizer/controls.js.map +1 -1
- package/lib/tokenizer/index.js +37 -84
- package/lib/tokenizer/index.js.map +1 -1
- package/lib/tokenizer/selection-utils.js +2 -12
- package/lib/tokenizer/selection-utils.js.map +1 -1
- package/lib/tokenizer/token-text.js +45 -78
- package/lib/tokenizer/token-text.js.map +1 -1
- package/lib/utils.js +8 -24
- package/lib/utils.js.map +1 -1
- package/package.json +13 -12
- package/src/legend.js +76 -67
- package/src/token-select/index.jsx +63 -66
- package/src/token-select/token.jsx +131 -122
- package/src/tokenizer/controls.jsx +40 -42
- package/src/tokenizer/index.jsx +17 -15
- package/src/tokenizer/token-text.jsx +12 -10
package/lib/utils.js
CHANGED
|
@@ -4,64 +4,48 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.prepareText = exports.parseParagraphs = exports.parseParagraph = exports.parseBrs = void 0;
|
|
7
|
-
|
|
8
7
|
var createElementFromHTML = function createElementFromHTML() {
|
|
9
8
|
var htmlString = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
10
9
|
var div = document.createElement('div');
|
|
11
10
|
div.innerHTML = htmlString.trim();
|
|
12
11
|
return div;
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
var parseBrs = function parseBrs(dom) {
|
|
13
|
+
var parseBrs = exports.parseBrs = function parseBrs(dom) {
|
|
16
14
|
var brs = dom.querySelectorAll('br');
|
|
17
15
|
brs.forEach(function (br) {
|
|
18
16
|
return br.replaceWith('\n');
|
|
19
17
|
});
|
|
20
18
|
dom.innerHTML = dom.innerHTML.replace(/\n\n/g, '\n');
|
|
21
19
|
};
|
|
22
|
-
|
|
23
|
-
exports.parseBrs = parseBrs;
|
|
24
|
-
|
|
25
|
-
var parseParagraph = function parseParagraph(paragraph, end) {
|
|
20
|
+
var parseParagraph = exports.parseParagraph = function parseParagraph(paragraph, end) {
|
|
26
21
|
if (end) {
|
|
27
22
|
return paragraph.innerHTML;
|
|
28
23
|
}
|
|
29
|
-
|
|
30
24
|
return "".concat(paragraph.innerHTML, "\n\n");
|
|
31
25
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
var parseParagraphs = function parseParagraphs(dom) {
|
|
36
|
-
var paragraphs = dom.querySelectorAll('p'); // separate variable for easily debugging, if needed
|
|
37
|
-
|
|
26
|
+
var parseParagraphs = exports.parseParagraphs = function parseParagraphs(dom) {
|
|
27
|
+
var paragraphs = dom.querySelectorAll('p');
|
|
28
|
+
// separate variable for easily debugging, if needed
|
|
38
29
|
var str = '';
|
|
39
30
|
paragraphs.forEach(function (par, index) {
|
|
40
31
|
str += parseParagraph(par, index === paragraphs.length - 1);
|
|
41
32
|
});
|
|
42
33
|
return str || null;
|
|
43
34
|
};
|
|
44
|
-
|
|
45
|
-
exports.parseParagraphs = parseParagraphs;
|
|
46
|
-
|
|
47
|
-
var prepareText = function prepareText(text) {
|
|
35
|
+
var prepareText = exports.prepareText = function prepareText(text) {
|
|
48
36
|
var txtDom = createElementFromHTML(text);
|
|
49
37
|
var allDomElements = Array.from(txtDom.querySelectorAll('*'));
|
|
50
|
-
|
|
51
38
|
if (txtDom.querySelectorAll('p').length === 0) {
|
|
52
39
|
var div = document.createElement('div');
|
|
53
40
|
div.innerHTML = "<p>".concat(txtDom.innerHTML, "</p>");
|
|
54
41
|
txtDom = div;
|
|
55
|
-
}
|
|
56
|
-
|
|
42
|
+
}
|
|
57
43
|
|
|
44
|
+
// if no dom elements, we just return the text
|
|
58
45
|
if (allDomElements.length === 0) {
|
|
59
46
|
return text;
|
|
60
47
|
}
|
|
61
|
-
|
|
62
48
|
parseBrs(txtDom);
|
|
63
49
|
return parseParagraphs(txtDom);
|
|
64
50
|
};
|
|
65
|
-
|
|
66
|
-
exports.prepareText = prepareText;
|
|
67
51
|
//# sourceMappingURL=utils.js.map
|
package/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"utils.js","names":["createElementFromHTML","htmlString","arguments","length","undefined","div","document","createElement","innerHTML","trim","parseBrs","exports","dom","brs","querySelectorAll","forEach","br","replaceWith","replace","parseParagraph","paragraph","end","concat","parseParagraphs","paragraphs","str","par","index","prepareText","text","txtDom","allDomElements","Array","from"],"sources":["../src/utils.js"],"sourcesContent":["const createElementFromHTML = (htmlString = '') => {\n const div = document.createElement('div');\n\n div.innerHTML = htmlString.trim();\n\n return div;\n};\n\nexport const parseBrs = (dom) => {\n const brs = dom.querySelectorAll('br');\n\n brs.forEach((br) => br.replaceWith('\\n'));\n\n dom.innerHTML = dom.innerHTML.replace(/\\n\\n/g, '\\n');\n};\n\nexport const parseParagraph = (paragraph, end) => {\n if (end) {\n return paragraph.innerHTML;\n }\n\n return `${paragraph.innerHTML}\\n\\n`;\n};\n\nexport const parseParagraphs = (dom) => {\n const paragraphs = dom.querySelectorAll('p');\n // separate variable for easily debugging, if needed\n let str = '';\n\n paragraphs.forEach((par, index) => {\n str += parseParagraph(par, index === paragraphs.length - 1);\n });\n\n return str || null;\n};\n\nexport const prepareText = (text) => {\n let txtDom = createElementFromHTML(text);\n const allDomElements = Array.from(txtDom.querySelectorAll('*'));\n\n if (txtDom.querySelectorAll('p').length === 0) {\n const div = document.createElement('div');\n\n div.innerHTML = `<p>${txtDom.innerHTML}</p>`;\n txtDom = div;\n }\n\n // if no dom elements, we just return the text\n if (allDomElements.length === 0) {\n return text;\n }\n\n parseBrs(txtDom);\n\n return parseParagraphs(txtDom);\n};\n"],"mappings":";;;;;;AAAA,IAAMA,qBAAqB,GAAG,SAAxBA,qBAAqBA,CAAA,EAAwB;EAAA,IAApBC,UAAU,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,EAAE;EAC5C,IAAMG,GAAG,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EAEzCF,GAAG,CAACG,SAAS,GAAGP,UAAU,CAACQ,IAAI,CAAC,CAAC;EAEjC,OAAOJ,GAAG;AACZ,CAAC;AAEM,IAAMK,QAAQ,GAAAC,OAAA,CAAAD,QAAA,GAAG,SAAXA,QAAQA,CAAIE,GAAG,EAAK;EAC/B,IAAMC,GAAG,GAAGD,GAAG,CAACE,gBAAgB,CAAC,IAAI,CAAC;EAEtCD,GAAG,CAACE,OAAO,CAAC,UAACC,EAAE;IAAA,OAAKA,EAAE,CAACC,WAAW,CAAC,IAAI,CAAC;EAAA,EAAC;EAEzCL,GAAG,CAACJ,SAAS,GAAGI,GAAG,CAACJ,SAAS,CAACU,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;AACtD,CAAC;AAEM,IAAMC,cAAc,GAAAR,OAAA,CAAAQ,cAAA,GAAG,SAAjBA,cAAcA,CAAIC,SAAS,EAAEC,GAAG,EAAK;EAChD,IAAIA,GAAG,EAAE;IACP,OAAOD,SAAS,CAACZ,SAAS;EAC5B;EAEA,UAAAc,MAAA,CAAUF,SAAS,CAACZ,SAAS;AAC/B,CAAC;AAEM,IAAMe,eAAe,GAAAZ,OAAA,CAAAY,eAAA,GAAG,SAAlBA,eAAeA,CAAIX,GAAG,EAAK;EACtC,IAAMY,UAAU,GAAGZ,GAAG,CAACE,gBAAgB,CAAC,GAAG,CAAC;EAC5C;EACA,IAAIW,GAAG,GAAG,EAAE;EAEZD,UAAU,CAACT,OAAO,CAAC,UAACW,GAAG,EAAEC,KAAK,EAAK;IACjCF,GAAG,IAAIN,cAAc,CAACO,GAAG,EAAEC,KAAK,KAAKH,UAAU,CAACrB,MAAM,GAAG,CAAC,CAAC;EAC7D,CAAC,CAAC;EAEF,OAAOsB,GAAG,IAAI,IAAI;AACpB,CAAC;AAEM,IAAMG,WAAW,GAAAjB,OAAA,CAAAiB,WAAA,GAAG,SAAdA,WAAWA,CAAIC,IAAI,EAAK;EACnC,IAAIC,MAAM,GAAG9B,qBAAqB,CAAC6B,IAAI,CAAC;EACxC,IAAME,cAAc,GAAGC,KAAK,CAACC,IAAI,CAACH,MAAM,CAAChB,gBAAgB,CAAC,GAAG,CAAC,CAAC;EAE/D,IAAIgB,MAAM,CAAChB,gBAAgB,CAAC,GAAG,CAAC,CAACX,MAAM,KAAK,CAAC,EAAE;IAC7C,IAAME,GAAG,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAEzCF,GAAG,CAACG,SAAS,SAAAc,MAAA,CAASQ,MAAM,CAACtB,SAAS,SAAM;IAC5CsB,MAAM,GAAGzB,GAAG;EACd;;EAEA;EACA,IAAI0B,cAAc,CAAC5B,MAAM,KAAK,CAAC,EAAE;IAC/B,OAAO0B,IAAI;EACb;EAEAnB,QAAQ,CAACoB,MAAM,CAAC;EAEhB,OAAOP,eAAe,CAACO,MAAM,CAAC;AAChC,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.34.0-mui-update.0",
|
|
7
7
|
"description": "Some react components for text selection",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"react",
|
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
"author": "",
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@
|
|
20
|
+
"@emotion/react": "^11.14.0",
|
|
21
|
+
"@emotion/style": "^0.8.0",
|
|
22
|
+
"@mui/icons-material": "^7.3.4",
|
|
23
|
+
"@mui/material": "^7.3.4",
|
|
21
24
|
"@pie-framework/parse-english": "^1.0.0",
|
|
22
|
-
"@pie-lib/render-ui": "^4.
|
|
23
|
-
"@pie-lib/style-utils": "^0.
|
|
24
|
-
"@pie-lib/translator": "^2.
|
|
25
|
+
"@pie-lib/render-ui": "^4.37.0-mui-update.0",
|
|
26
|
+
"@pie-lib/style-utils": "^0.23.0-mui-update.0",
|
|
27
|
+
"@pie-lib/translator": "^2.26.0-mui-update.0",
|
|
25
28
|
"classnames": "^2.2.6",
|
|
26
29
|
"debug": "^4.1.1",
|
|
27
30
|
"invariant": "^2.2.4",
|
|
@@ -30,17 +33,15 @@
|
|
|
30
33
|
"unist-util-inspect": "^4.1.3"
|
|
31
34
|
},
|
|
32
35
|
"devDependencies": {
|
|
33
|
-
"@material-ui/core": "^3.8.3",
|
|
34
36
|
"@pie-framework/parse-english": "^1.0.0",
|
|
35
|
-
"@pie-lib/test-utils": "^0.
|
|
37
|
+
"@pie-lib/test-utils": "^0.24.0-mui-update.0",
|
|
36
38
|
"natural": "^0.6.3",
|
|
37
|
-
"react": "^
|
|
38
|
-
"react-dom": "^
|
|
39
|
+
"react": "^18.2.0",
|
|
40
|
+
"react-dom": "^18.2.0"
|
|
39
41
|
},
|
|
40
42
|
"peerDependencies": {
|
|
41
|
-
"
|
|
42
|
-
"react": "^16.8.1"
|
|
43
|
+
"react": "^18.2.0"
|
|
43
44
|
},
|
|
44
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "4d8ccede3634986a13ea7df987defd26d089f0d6",
|
|
45
46
|
"scripts": {}
|
|
46
47
|
}
|
package/src/legend.js
CHANGED
|
@@ -1,80 +1,87 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import Check from '@
|
|
4
|
-
import Close from '@
|
|
2
|
+
import { styled } from '@mui/material/styles';
|
|
3
|
+
import Check from '@mui/icons-material/Check';
|
|
4
|
+
import Close from '@mui/icons-material/Close';
|
|
5
5
|
import { color } from '@pie-lib/render-ui';
|
|
6
6
|
import Translator from '@pie-lib/translator';
|
|
7
|
-
import classNames from 'classnames';
|
|
8
7
|
|
|
9
8
|
const { translator } = Translator;
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
10
|
+
const StyledFlexContainer = styled('div')(({ theme }) => ({
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'row',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
gap: theme.spacing(2),
|
|
15
|
+
borderBottom: '1px solid lightgrey',
|
|
16
|
+
borderTop: '1px solid lightgrey',
|
|
17
|
+
paddingBottom: theme.spacing(1),
|
|
18
|
+
paddingTop: theme.spacing(1),
|
|
19
|
+
marginBottom: theme.spacing(1),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const StyledKey = styled('span')(({ theme }) => ({
|
|
23
|
+
fontSize: '14px',
|
|
24
|
+
fontWeight: 'bold',
|
|
25
|
+
color: color.black(),
|
|
26
|
+
marginLeft: theme.spacing(1),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
const StyledContainer = styled('div')(() => ({
|
|
30
|
+
position: 'relative',
|
|
31
|
+
padding: '4px',
|
|
32
|
+
fontSize: '14px',
|
|
33
|
+
borderRadius: '4px',
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const StyledCorrectContainer = styled(StyledContainer)(() => ({
|
|
37
|
+
border: `${color.correctTertiary()} solid 2px`,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const StyledIncorrectContainer = styled(StyledContainer)(() => ({
|
|
41
|
+
border: `${color.incorrectWithIcon()} solid 2px`,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const StyledMissingContainer = styled(StyledContainer)(() => ({
|
|
45
|
+
border: `${color.incorrectWithIcon()} dashed 2px`,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
const StyledIcon = styled('div')(() => ({
|
|
49
|
+
color: color.white(),
|
|
50
|
+
position: 'absolute',
|
|
51
|
+
top: '-8px',
|
|
52
|
+
left: '-8px',
|
|
53
|
+
borderRadius: '50%',
|
|
54
|
+
fontSize: '12px',
|
|
55
|
+
padding: '2px',
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
const StyledCorrectIcon = styled(StyledIcon)(() => ({
|
|
59
|
+
backgroundColor: color.correctTertiary(),
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
const StyledIncorrectIcon = styled(StyledIcon)(() => ({
|
|
63
|
+
backgroundColor: color.incorrectWithIcon(),
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
export const Legend = ({ language, showOnlyCorrect }) => {
|
|
60
67
|
const legendItems = [
|
|
61
68
|
{
|
|
62
69
|
Icon: Check,
|
|
63
70
|
label: translator.t('selectText.correctAnswerSelected', { lng: language }),
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
Container: StyledCorrectContainer,
|
|
72
|
+
IconComponent: StyledCorrectIcon,
|
|
66
73
|
},
|
|
67
74
|
{
|
|
68
75
|
Icon: Close,
|
|
69
76
|
label: translator.t('selectText.incorrectSelection', { lng: language }),
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
Container: StyledIncorrectContainer,
|
|
78
|
+
IconComponent: StyledIncorrectIcon,
|
|
72
79
|
},
|
|
73
80
|
{
|
|
74
81
|
Icon: Close,
|
|
75
82
|
label: translator.t('selectText.correctAnswerNotSelected', { lng: language }),
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
Container: StyledMissingContainer,
|
|
84
|
+
IconComponent: StyledIncorrectIcon,
|
|
78
85
|
},
|
|
79
86
|
];
|
|
80
87
|
|
|
@@ -83,14 +90,16 @@ export const Legend = withStyles((theme) => ({
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
return (
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
{legendItems.map(({ Icon, label,
|
|
89
|
-
<
|
|
90
|
-
<
|
|
93
|
+
<StyledFlexContainer>
|
|
94
|
+
<StyledKey>{translator.t('selectText.key', { lng: language })}</StyledKey>
|
|
95
|
+
{legendItems.map(({ Icon, label, Container, IconComponent }, idx) => (
|
|
96
|
+
<Container key={idx}>
|
|
97
|
+
<IconComponent>
|
|
98
|
+
<Icon />
|
|
99
|
+
</IconComponent>
|
|
91
100
|
<span>{label}</span>
|
|
92
|
-
</
|
|
101
|
+
</Container>
|
|
93
102
|
))}
|
|
94
|
-
</
|
|
103
|
+
</StyledFlexContainer>
|
|
95
104
|
);
|
|
96
|
-
}
|
|
105
|
+
};
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import Token, { TokenTypes } from './token';
|
|
4
|
-
import {
|
|
5
|
-
import classNames from 'classnames';
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
6
5
|
import clone from 'lodash/clone';
|
|
7
6
|
import debug from 'debug';
|
|
8
7
|
import { noSelect } from '@pie-lib/style-utils';
|
|
9
|
-
import { renderToString } from 'react-dom/server';
|
|
10
8
|
import isEqual from 'lodash/isEqual';
|
|
11
9
|
|
|
12
10
|
const log = debug('@pie-lib:text-select:token-select');
|
|
13
11
|
|
|
12
|
+
const StyledTokenSelect = styled('div')(() => ({
|
|
13
|
+
backgroundColor: 'none',
|
|
14
|
+
whiteSpace: 'pre',
|
|
15
|
+
...noSelect(),
|
|
16
|
+
'& p': {
|
|
17
|
+
whiteSpace: 'break-spaces',
|
|
18
|
+
margin: 0,
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
14
22
|
export class TokenSelect extends React.Component {
|
|
15
23
|
static propTypes = {
|
|
16
24
|
tokens: PropTypes.arrayOf(PropTypes.shape(TokenTypes)).isRequired,
|
|
17
25
|
className: PropTypes.string,
|
|
18
|
-
classes: PropTypes.object.isRequired,
|
|
19
26
|
onChange: PropTypes.func.isRequired,
|
|
20
27
|
disabled: PropTypes.bool,
|
|
21
28
|
highlightChoices: PropTypes.bool,
|
|
@@ -34,49 +41,36 @@ export class TokenSelect extends React.Component {
|
|
|
34
41
|
canSelectMore = (selectedCount) => {
|
|
35
42
|
const { maxNoOfSelections } = this.props;
|
|
36
43
|
|
|
37
|
-
if (maxNoOfSelections === 1)
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
44
|
+
if (maxNoOfSelections === 1) return true;
|
|
40
45
|
|
|
41
46
|
log('[canSelectMore] maxNoOfSelections: ', maxNoOfSelections, 'selectedCount: ', selectedCount);
|
|
42
47
|
return maxNoOfSelections <= 0 || (isFinite(maxNoOfSelections) && selectedCount < maxNoOfSelections);
|
|
43
48
|
};
|
|
44
49
|
|
|
45
|
-
/**
|
|
46
|
-
@function
|
|
47
|
-
@param { object } event
|
|
48
|
-
|
|
49
|
-
@description
|
|
50
|
-
each token is wrapped into a span that has Token.rootClassName class and indexkey attribute (represents the index of the token)
|
|
51
|
-
tokens are updated with the targeted token having the correct value set for 'selected' property
|
|
52
|
-
*/
|
|
53
50
|
toggleToken = (event) => {
|
|
54
51
|
const { target } = event;
|
|
55
52
|
const { tokens, animationsDisabled } = this.props;
|
|
56
53
|
const tokensCloned = clone(tokens);
|
|
57
|
-
const targetSpanWrapper = target.closest(`.${Token.rootClassName}`);
|
|
58
|
-
const targetedTokenIndex = targetSpanWrapper && targetSpanWrapper.dataset && targetSpanWrapper.dataset.indexkey;
|
|
59
|
-
const t = targetedTokenIndex && tokensCloned[targetedTokenIndex];
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
const targetSpanWrapper = target.closest?.(`.${Token.rootClassName}`);
|
|
56
|
+
const targetedTokenIndex = targetSpanWrapper?.dataset?.indexkey;
|
|
57
|
+
const t = targetedTokenIndex !== undefined ? tokensCloned[targetedTokenIndex] : undefined;
|
|
58
|
+
|
|
59
|
+
// don't toggle if in print mode, correctness is defined, or is missing
|
|
63
60
|
if (t && t.correct === undefined && !animationsDisabled && !t.isMissing) {
|
|
64
61
|
const { onChange, maxNoOfSelections } = this.props;
|
|
65
62
|
const selected = !t.selected;
|
|
66
63
|
|
|
67
64
|
if (maxNoOfSelections === 1 && this.selectedCount() === 1) {
|
|
68
|
-
const selectedToken = (tokens || []).filter((
|
|
69
|
-
|
|
65
|
+
const selectedToken = (tokens || []).filter((tk) => tk.selected);
|
|
70
66
|
const updatedTokens = tokensCloned.map((token) => {
|
|
71
67
|
if (isEqual(token, selectedToken[0])) {
|
|
72
68
|
return { ...token, selected: false };
|
|
73
69
|
}
|
|
74
|
-
|
|
75
70
|
return { ...token, selectable: true };
|
|
76
71
|
});
|
|
77
72
|
|
|
78
|
-
const update = { ...t, selected
|
|
79
|
-
|
|
73
|
+
const update = { ...t, selected };
|
|
80
74
|
updatedTokens.splice(targetedTokenIndex, 1, update);
|
|
81
75
|
onChange(updatedTokens);
|
|
82
76
|
} else {
|
|
@@ -84,32 +78,42 @@ export class TokenSelect extends React.Component {
|
|
|
84
78
|
log('skip toggle max reached');
|
|
85
79
|
return;
|
|
86
80
|
}
|
|
87
|
-
|
|
88
|
-
const update = { ...t, selected: !t.selected };
|
|
89
|
-
|
|
81
|
+
const update = { ...t, selected };
|
|
90
82
|
tokensCloned.splice(targetedTokenIndex, 1, update);
|
|
91
83
|
onChange(tokensCloned);
|
|
92
84
|
}
|
|
93
85
|
}
|
|
94
86
|
};
|
|
95
87
|
|
|
96
|
-
|
|
88
|
+
/** Build a React tree instead of an HTML string so Emotion can inject CSS */
|
|
89
|
+
generateTokensNodes = () => {
|
|
97
90
|
const { tokens, disabled, highlightChoices, animationsDisabled } = this.props;
|
|
98
91
|
const selectedCount = this.selectedCount();
|
|
92
|
+
|
|
99
93
|
const isLineBreak = (text) => text === '\n';
|
|
100
94
|
const isNewParagraph = (text) => text === '\n\n';
|
|
101
95
|
|
|
102
|
-
const
|
|
96
|
+
const paragraphs = [];
|
|
97
|
+
let currentChildren = [];
|
|
98
|
+
|
|
99
|
+
const flushParagraph = () => {
|
|
100
|
+
// Always push a <p>, even if empty, to mirror previous behavior
|
|
101
|
+
paragraphs.push(<p key={`p-${paragraphs.length}`}>{currentChildren}</p>);
|
|
102
|
+
currentChildren = [];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
(tokens || []).forEach((t, index) => {
|
|
103
106
|
const selectable = t.selected || (t.selectable && this.canSelectMore(selectedCount));
|
|
104
107
|
const showCorrectAnswer = t.correct !== undefined && (t.selectable || t.selected);
|
|
105
|
-
let finalAcc = accumulator;
|
|
106
108
|
|
|
107
109
|
if (isNewParagraph(t.text)) {
|
|
108
|
-
|
|
110
|
+
flushParagraph();
|
|
111
|
+
return;
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
if (isLineBreak(t.text)) {
|
|
112
|
-
|
|
115
|
+
currentChildren.push(<br key={`br-${index}`} />);
|
|
116
|
+
return;
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
if (
|
|
@@ -117,48 +121,41 @@ export class TokenSelect extends React.Component {
|
|
|
117
121
|
showCorrectAnswer ||
|
|
118
122
|
t.selected ||
|
|
119
123
|
t.isMissing ||
|
|
120
|
-
(animationsDisabled && t.predefined) //
|
|
124
|
+
(animationsDisabled && t.predefined) // print mode
|
|
121
125
|
) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
animationsDisabled={animationsDisabled}
|
|
133
|
-
/>,
|
|
134
|
-
)
|
|
126
|
+
currentChildren.push(
|
|
127
|
+
<Token
|
|
128
|
+
key={index}
|
|
129
|
+
disabled={disabled}
|
|
130
|
+
index={index}
|
|
131
|
+
{...t}
|
|
132
|
+
selectable={selectable}
|
|
133
|
+
highlight={highlightChoices}
|
|
134
|
+
animationsDisabled={animationsDisabled}
|
|
135
|
+
/>
|
|
135
136
|
);
|
|
136
137
|
} else {
|
|
137
|
-
|
|
138
|
+
// raw text node – React will escape as needed
|
|
139
|
+
currentChildren.push(<React.Fragment key={index}>{t.text}</React.Fragment>);
|
|
138
140
|
}
|
|
139
|
-
};
|
|
141
|
+
});
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
// flush last paragraph
|
|
144
|
+
flushParagraph();
|
|
142
145
|
|
|
143
|
-
return
|
|
146
|
+
return paragraphs;
|
|
144
147
|
};
|
|
145
148
|
|
|
146
149
|
render() {
|
|
147
|
-
const {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
const { className: classNameProp } = this.props;
|
|
151
|
+
const nodes = this.generateTokensNodes();
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<StyledTokenSelect className={classNameProp} onClick={this.toggleToken}>
|
|
155
|
+
{nodes}
|
|
156
|
+
</StyledTokenSelect>
|
|
157
|
+
);
|
|
152
158
|
}
|
|
153
159
|
}
|
|
154
160
|
|
|
155
|
-
export default
|
|
156
|
-
tokenSelect: {
|
|
157
|
-
backgroundColor: 'none',
|
|
158
|
-
whiteSpace: 'pre',
|
|
159
|
-
...noSelect(),
|
|
160
|
-
'& p': {
|
|
161
|
-
whiteSpace: 'break-spaces',
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
}))(TokenSelect);
|
|
161
|
+
export default TokenSelect;
|