@pie-lib/editable-html-tip-tap 2.1.10 → 2.2.0-beta
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 +0 -75
- package/lib/__tests__/EditableHtml.test.js +831 -0
- package/lib/__tests__/EditableHtml.test.js.map +1 -0
- package/lib/__tests__/constants.test.js +21 -0
- package/lib/__tests__/constants.test.js.map +1 -0
- package/lib/__tests__/div-to-paragraph-conversion.test.js +213 -0
- package/lib/__tests__/div-to-paragraph-conversion.test.js.map +1 -0
- package/lib/__tests__/extensions.test.js +209 -0
- package/lib/__tests__/extensions.test.js.map +1 -0
- package/lib/__tests__/index.test.js +250 -0
- package/lib/__tests__/index.test.js.map +1 -0
- package/lib/__tests__/size-utils.test.js +57 -0
- package/lib/__tests__/size-utils.test.js.map +1 -0
- package/lib/__tests__/theme.test.js +17 -0
- package/lib/__tests__/theme.test.js.map +1 -0
- package/lib/components/EditableHtml.js +4 -2
- package/lib/components/EditableHtml.js.map +1 -1
- package/lib/components/__tests__/AltDialog.test.js +201 -0
- package/lib/components/__tests__/AltDialog.test.js.map +1 -0
- package/lib/components/__tests__/CharacterPicker.test.js +455 -0
- package/lib/components/__tests__/CharacterPicker.test.js.map +1 -0
- package/lib/components/__tests__/CssIcon.test.js +58 -0
- package/lib/components/__tests__/CssIcon.test.js.map +1 -0
- package/lib/components/__tests__/DragInTheBlank.test.js +295 -0
- package/lib/components/__tests__/DragInTheBlank.test.js.map +1 -0
- package/lib/components/__tests__/ExplicitConstructedResponse.test.js +345 -0
- package/lib/components/__tests__/ExplicitConstructedResponse.test.js.map +1 -0
- package/lib/components/__tests__/ImageToolbar.test.js +185 -0
- package/lib/components/__tests__/ImageToolbar.test.js.map +1 -0
- package/lib/components/__tests__/InlineDropdown.test.js +839 -0
- package/lib/components/__tests__/InlineDropdown.test.js.map +1 -0
- package/lib/components/__tests__/InsertImageHandler.test.js +171 -0
- package/lib/components/__tests__/InsertImageHandler.test.js.map +1 -0
- package/lib/components/__tests__/MediaDialog.test.js +433 -0
- package/lib/components/__tests__/MediaDialog.test.js.map +1 -0
- package/lib/components/__tests__/MediaToolbar.test.js +126 -0
- package/lib/components/__tests__/MediaToolbar.test.js.map +1 -0
- package/lib/components/__tests__/MediaWrapper.test.js +96 -0
- package/lib/components/__tests__/MediaWrapper.test.js.map +1 -0
- package/lib/components/__tests__/MenuBar.test.js +502 -0
- package/lib/components/__tests__/MenuBar.test.js.map +1 -0
- package/lib/components/__tests__/RespArea.test.js +171 -0
- package/lib/components/__tests__/RespArea.test.js.map +1 -0
- package/lib/components/__tests__/TableIcons.test.js +153 -0
- package/lib/components/__tests__/TableIcons.test.js.map +1 -0
- package/lib/components/__tests__/TextAlign.test.js +209 -0
- package/lib/components/__tests__/TextAlign.test.js.map +1 -0
- package/lib/components/__tests__/TiptapContainer.test.js +196 -0
- package/lib/components/__tests__/TiptapContainer.test.js.map +1 -0
- package/lib/components/__tests__/characterUtils.test.js +178 -0
- package/lib/components/__tests__/characterUtils.test.js.map +1 -0
- package/lib/components/__tests__/choice.test.js +213 -0
- package/lib/components/__tests__/choice.test.js.map +1 -0
- package/lib/components/__tests__/custom-popper.test.js +108 -0
- package/lib/components/__tests__/custom-popper.test.js.map +1 -0
- package/lib/components/__tests__/done-button.test.js +72 -0
- package/lib/components/__tests__/done-button.test.js.map +1 -0
- package/lib/components/__tests__/toolbar-buttons.test.js +277 -0
- package/lib/components/__tests__/toolbar-buttons.test.js.map +1 -0
- package/lib/components/respArea/DragInTheBlank/__tests__/choice.test.js +90 -0
- package/lib/components/respArea/DragInTheBlank/__tests__/choice.test.js.map +1 -0
- package/lib/components/respArea/DragInTheBlank/choice.js +3 -0
- package/lib/components/respArea/DragInTheBlank/choice.js.map +1 -1
- package/lib/components/respArea/MathTemplated.js +2 -2
- package/lib/components/respArea/MathTemplated.js.map +1 -1
- package/lib/components/respArea/__tests__/MathTemplated.test.js +217 -0
- package/lib/components/respArea/__tests__/MathTemplated.test.js.map +1 -0
- package/lib/extensions/__tests__/css.test.js +214 -0
- package/lib/extensions/__tests__/css.test.js.map +1 -0
- package/lib/extensions/__tests__/custom-toolbar-wrapper.test.js +175 -0
- package/lib/extensions/__tests__/custom-toolbar-wrapper.test.js.map +1 -0
- package/lib/extensions/__tests__/divNode.test.js +108 -0
- package/lib/extensions/__tests__/divNode.test.js.map +1 -0
- package/lib/extensions/__tests__/ensure-empty-root-div.test.js +50 -0
- package/lib/extensions/__tests__/ensure-empty-root-div.test.js.map +1 -0
- package/lib/extensions/__tests__/ensure-list-item-content-is-div.test.js +60 -0
- package/lib/extensions/__tests__/ensure-list-item-content-is-div.test.js.map +1 -0
- package/lib/extensions/__tests__/extended-list-item.test.js +13 -0
- package/lib/extensions/__tests__/extended-list-item.test.js.map +1 -0
- package/lib/extensions/__tests__/extended-table-cell.test.js +15 -0
- package/lib/extensions/__tests__/extended-table-cell.test.js.map +1 -0
- package/lib/extensions/__tests__/extended-table.test.js +200 -0
- package/lib/extensions/__tests__/extended-table.test.js.map +1 -0
- package/lib/extensions/__tests__/image-component.test.js +432 -0
- package/lib/extensions/__tests__/image-component.test.js.map +1 -0
- package/lib/extensions/__tests__/image.test.js +313 -0
- package/lib/extensions/__tests__/image.test.js.map +1 -0
- package/lib/extensions/__tests__/math.test.js +1399 -0
- package/lib/extensions/__tests__/math.test.js.map +1 -0
- package/lib/extensions/__tests__/media-node-view.test.js +307 -0
- package/lib/extensions/__tests__/media-node-view.test.js.map +1 -0
- package/lib/extensions/__tests__/media.test.js +292 -0
- package/lib/extensions/__tests__/media.test.js.map +1 -0
- package/lib/extensions/__tests__/responseArea.test.js +736 -0
- package/lib/extensions/__tests__/responseArea.test.js.map +1 -0
- package/lib/extensions/image-component.js +9 -6
- package/lib/extensions/image-component.js.map +1 -1
- package/lib/extensions/responseArea.js +7 -1
- package/lib/extensions/responseArea.js.map +1 -1
- package/lib/utils/__tests__/helper.test.js +107 -0
- package/lib/utils/__tests__/helper.test.js.map +1 -0
- package/lib/utils/__tests__/toolbar.test.js +38 -0
- package/lib/utils/__tests__/toolbar.test.js.map +1 -0
- package/package.json +7 -7
- package/src/components/EditableHtml.jsx +5 -3
- package/src/components/respArea/DragInTheBlank/__tests__/choice.test.jsx +72 -0
- package/src/components/respArea/DragInTheBlank/choice.jsx +3 -0
- package/src/components/respArea/MathTemplated.jsx +1 -1
- package/src/components/respArea/__tests__/MathTemplated.test.jsx +1 -1
- package/src/extensions/__tests__/image-component.test.jsx +1 -0
- package/src/extensions/__tests__/responseArea.test.js +57 -3
- package/src/extensions/image-component.jsx +8 -6
- package/src/extensions/responseArea.js +7 -1
- package/LICENSE.md +0 -5
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _toolbar = require("../toolbar");
|
|
4
|
+
describe('setToolbarOpened', function () {
|
|
5
|
+
var createEditor = function createEditor() {
|
|
6
|
+
var toolbarOpened = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
7
|
+
var tr = {
|
|
8
|
+
setMeta: jest.fn().mockReturnThis()
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
_toolbarOpened: toolbarOpened,
|
|
12
|
+
state: {
|
|
13
|
+
tr: tr
|
|
14
|
+
},
|
|
15
|
+
view: {
|
|
16
|
+
dispatch: jest.fn()
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
it('sets editor._toolbarOpened and dispatches a meta transaction', function () {
|
|
21
|
+
var editor = createEditor(false);
|
|
22
|
+
(0, _toolbar.setToolbarOpened)(editor, true);
|
|
23
|
+
expect(editor._toolbarOpened).toBe(true);
|
|
24
|
+
expect(editor.state.tr.setMeta).toHaveBeenCalledWith(_toolbar.TOOLBAR_OPENED_META_KEY, true);
|
|
25
|
+
expect(editor.view.dispatch).toHaveBeenCalledWith(editor.state.tr);
|
|
26
|
+
});
|
|
27
|
+
it('does nothing when the value is unchanged', function () {
|
|
28
|
+
var editor = createEditor(true);
|
|
29
|
+
(0, _toolbar.setToolbarOpened)(editor, true);
|
|
30
|
+
expect(editor.view.dispatch).not.toHaveBeenCalled();
|
|
31
|
+
});
|
|
32
|
+
it('coerces the opened value to a boolean', function () {
|
|
33
|
+
var editor = createEditor(false);
|
|
34
|
+
(0, _toolbar.setToolbarOpened)(editor, 1);
|
|
35
|
+
expect(editor._toolbarOpened).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=toolbar.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar.test.js","names":["_toolbar","require","describe","createEditor","toolbarOpened","arguments","length","undefined","tr","setMeta","jest","fn","mockReturnThis","_toolbarOpened","state","view","dispatch","it","editor","setToolbarOpened","expect","toBe","toHaveBeenCalledWith","TOOLBAR_OPENED_META_KEY","not","toHaveBeenCalled"],"sources":["../../../src/utils/__tests__/toolbar.test.js"],"sourcesContent":["import { setToolbarOpened, TOOLBAR_OPENED_META_KEY } from '../toolbar';\n\ndescribe('setToolbarOpened', () => {\n const createEditor = (toolbarOpened = false) => {\n const tr = {\n setMeta: jest.fn().mockReturnThis(),\n };\n\n return {\n _toolbarOpened: toolbarOpened,\n state: { tr },\n view: {\n dispatch: jest.fn(),\n },\n };\n };\n\n it('sets editor._toolbarOpened and dispatches a meta transaction', () => {\n const editor = createEditor(false);\n\n setToolbarOpened(editor, true);\n\n expect(editor._toolbarOpened).toBe(true);\n expect(editor.state.tr.setMeta).toHaveBeenCalledWith(TOOLBAR_OPENED_META_KEY, true);\n expect(editor.view.dispatch).toHaveBeenCalledWith(editor.state.tr);\n });\n\n it('does nothing when the value is unchanged', () => {\n const editor = createEditor(true);\n\n setToolbarOpened(editor, true);\n\n expect(editor.view.dispatch).not.toHaveBeenCalled();\n });\n\n it('coerces the opened value to a boolean', () => {\n const editor = createEditor(false);\n\n setToolbarOpened(editor, 1);\n\n expect(editor._toolbarOpened).toBe(true);\n });\n});\n"],"mappings":";;AAAA,IAAAA,QAAA,GAAAC,OAAA;AAEAC,QAAQ,CAAC,kBAAkB,EAAE,YAAM;EACjC,IAAMC,YAAY,GAAG,SAAfA,YAAYA,CAAA,EAA8B;IAAA,IAA1BC,aAAa,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;IACzC,IAAMG,EAAE,GAAG;MACTC,OAAO,EAAEC,IAAI,CAACC,EAAE,CAAC,CAAC,CAACC,cAAc,CAAC;IACpC,CAAC;IAED,OAAO;MACLC,cAAc,EAAET,aAAa;MAC7BU,KAAK,EAAE;QAAEN,EAAE,EAAFA;MAAG,CAAC;MACbO,IAAI,EAAE;QACJC,QAAQ,EAAEN,IAAI,CAACC,EAAE,CAAC;MACpB;IACF,CAAC;EACH,CAAC;EAEDM,EAAE,CAAC,8DAA8D,EAAE,YAAM;IACvE,IAAMC,MAAM,GAAGf,YAAY,CAAC,KAAK,CAAC;IAElC,IAAAgB,yBAAgB,EAACD,MAAM,EAAE,IAAI,CAAC;IAE9BE,MAAM,CAACF,MAAM,CAACL,cAAc,CAAC,CAACQ,IAAI,CAAC,IAAI,CAAC;IACxCD,MAAM,CAACF,MAAM,CAACJ,KAAK,CAACN,EAAE,CAACC,OAAO,CAAC,CAACa,oBAAoB,CAACC,gCAAuB,EAAE,IAAI,CAAC;IACnFH,MAAM,CAACF,MAAM,CAACH,IAAI,CAACC,QAAQ,CAAC,CAACM,oBAAoB,CAACJ,MAAM,CAACJ,KAAK,CAACN,EAAE,CAAC;EACpE,CAAC,CAAC;EAEFS,EAAE,CAAC,0CAA0C,EAAE,YAAM;IACnD,IAAMC,MAAM,GAAGf,YAAY,CAAC,IAAI,CAAC;IAEjC,IAAAgB,yBAAgB,EAACD,MAAM,EAAE,IAAI,CAAC;IAE9BE,MAAM,CAACF,MAAM,CAACH,IAAI,CAACC,QAAQ,CAAC,CAACQ,GAAG,CAACC,gBAAgB,CAAC,CAAC;EACrD,CAAC,CAAC;EAEFR,EAAE,CAAC,uCAAuC,EAAE,YAAM;IAChD,IAAMC,MAAM,GAAGf,YAAY,CAAC,KAAK,CAAC;IAElC,IAAAgB,yBAAgB,EAACD,MAAM,EAAE,CAAC,CAAC;IAE3BE,MAAM,CAACF,MAAM,CAACL,cAAc,CAAC,CAACQ,IAAI,CAAC,IAAI,CAAC;EAC1C,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.2.0-beta",
|
|
7
7
|
"description": "",
|
|
8
8
|
"license": "ISC",
|
|
9
9
|
"main": "lib/index.js",
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"@dnd-kit/utilities": "3.2.2",
|
|
17
17
|
"@mui/icons-material": "^7.3.4",
|
|
18
18
|
"@mui/material": "^7.3.4",
|
|
19
|
-
"@pie-lib/drag": "^4.0.
|
|
20
|
-
"@pie-lib/math-input": "^
|
|
21
|
-
"@pie-lib/math-rendering": "^5.
|
|
22
|
-
"@pie-lib/math-toolbar": "^3.0
|
|
23
|
-
"@pie-lib/render-ui": "^6.1.
|
|
19
|
+
"@pie-lib/drag": "^4.0.2",
|
|
20
|
+
"@pie-lib/math-input-mathlive": "^1.0.1",
|
|
21
|
+
"@pie-lib/math-rendering": "^5.0.2",
|
|
22
|
+
"@pie-lib/math-toolbar": "^3.1.0-beta",
|
|
23
|
+
"@pie-lib/render-ui": "^6.1.0",
|
|
24
24
|
"@tiptap/core": "3.20.0",
|
|
25
25
|
"@tiptap/extension-character-count": "3.20.0",
|
|
26
26
|
"@tiptap/extension-color": "3.20.0",
|
|
@@ -59,6 +59,6 @@
|
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"react": "^18.2.0"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "433bcb776c2975739e7417f133d31cd996164116",
|
|
63
63
|
"scripts": {}
|
|
64
64
|
}
|
|
@@ -243,7 +243,7 @@ export const EditableHtml = (props) => {
|
|
|
243
243
|
let cb;
|
|
244
244
|
|
|
245
245
|
if (scheduled && result) {
|
|
246
|
-
|
|
246
|
+
// finish editing only on success
|
|
247
247
|
cb = props.onChange;
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -424,10 +424,12 @@ const StyledEditorContent = styled(EditorContent, {
|
|
|
424
424
|
},
|
|
425
425
|
|
|
426
426
|
// Out of flow so the caret stays at the start of the block; in-flow ::before pushes the caret after the hint text.
|
|
427
|
-
|
|
427
|
+
// :only-child ensures the placeholder is hidden whenever the editor has other content (images, upload nodes, etc.)
|
|
428
|
+
// and covers the type+backspace edge case where Tiptap only adds is-empty (not is-editor-empty).
|
|
429
|
+
'& p[data-placeholder].is-empty:only-child, & div[data-placeholder].is-empty:only-child': {
|
|
428
430
|
position: 'relative',
|
|
429
431
|
},
|
|
430
|
-
'& p.is-
|
|
432
|
+
'& p[data-placeholder].is-empty:only-child::before, & div[data-placeholder].is-empty:only-child::before': {
|
|
431
433
|
content: 'attr(data-placeholder)',
|
|
432
434
|
position: 'absolute',
|
|
433
435
|
left: 0,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import DragDropChoice from '../choice';
|
|
4
|
+
|
|
5
|
+
// Mock @dnd-kit hooks to avoid DndContext requirement
|
|
6
|
+
jest.mock('@dnd-kit/core', () => ({
|
|
7
|
+
useDraggable: jest.fn(() => ({
|
|
8
|
+
attributes: {},
|
|
9
|
+
listeners: {},
|
|
10
|
+
setNodeRef: jest.fn(),
|
|
11
|
+
isDragging: false,
|
|
12
|
+
})),
|
|
13
|
+
useDroppable: jest.fn(() => ({
|
|
14
|
+
setNodeRef: jest.fn(),
|
|
15
|
+
isOver: false,
|
|
16
|
+
active: null,
|
|
17
|
+
})),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock('@pie-lib/math-rendering', () => ({
|
|
21
|
+
renderMath: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
// Collect the CSS rules emotion/MUI injected into the document (jsdom uses insertRule).
|
|
25
|
+
const collectEmotionRules = () => {
|
|
26
|
+
const rules = [];
|
|
27
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
28
|
+
try {
|
|
29
|
+
for (const rule of Array.from(sheet.cssRules)) {
|
|
30
|
+
rules.push(rule.cssText);
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
/* inaccessible stylesheet */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return rules;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
describe('DragInTheBlank choice', () => {
|
|
40
|
+
const defaultProps = {
|
|
41
|
+
value: { id: '1', value: '<math>1/2</math>' },
|
|
42
|
+
disabled: false,
|
|
43
|
+
instanceId: 'test-instance',
|
|
44
|
+
n: { index: 0 },
|
|
45
|
+
onChange: jest.fn(),
|
|
46
|
+
removeResponse: jest.fn(),
|
|
47
|
+
duplicates: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
it('renders without crashing', () => {
|
|
51
|
+
const { container } = render(<DragDropChoice {...defaultProps} />);
|
|
52
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('fraction math styling', () => {
|
|
56
|
+
it('enlarges numerator/denominator digits adjacent to a fraction to 120%', () => {
|
|
57
|
+
render(<DragDropChoice {...defaultProps} />);
|
|
58
|
+
const rule = collectEmotionRules().find((r) => r.includes('mjx-mn') && r.includes('mjx-mfrac'));
|
|
59
|
+
expect(rule).toBeDefined();
|
|
60
|
+
expect(rule).toMatch(/mjx-mn:has\(~\s*mjx-mfrac\)/);
|
|
61
|
+
expect(rule).toMatch(/mjx-mfrac\s*~\s*mjx-mn/);
|
|
62
|
+
expect(rule).toMatch(/font-size:\s*120%\s*!important/i);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('keeps the existing mjx-frac 120% rule', () => {
|
|
66
|
+
render(<DragDropChoice {...defaultProps} />);
|
|
67
|
+
const rule = collectEmotionRules().find((r) => /(^|[^-])mjx-frac/.test(r) && !r.includes('mjx-mfrac'));
|
|
68
|
+
expect(rule).toBeDefined();
|
|
69
|
+
expect(rule).toMatch(/font-size:\s*120%\s*!important/i);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -10,6 +10,9 @@ import { GripIcon } from '../../icons/RespArea';
|
|
|
10
10
|
|
|
11
11
|
const StyledContent = styled('span')(({ theme }) => ({
|
|
12
12
|
border: `solid 0px ${theme.palette.primary.main}`,
|
|
13
|
+
'& mjx-mn:has(~ mjx-mfrac), mjx-mfrac ~ mjx-mn': {
|
|
14
|
+
fontSize: '120% !important',
|
|
15
|
+
},
|
|
13
16
|
'& mjx-frac': {
|
|
14
17
|
fontSize: '120% !important',
|
|
15
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { NodeViewWrapper } from '@tiptap/react';
|
|
4
|
-
import { mq } from '@pie-lib/math-input';
|
|
4
|
+
import { mq } from '@pie-lib/math-input-mathlive';
|
|
5
5
|
import { styled } from '@mui/material/styles';
|
|
6
6
|
|
|
7
7
|
const StyledSpanContainer = styled('span')(() => ({
|
|
@@ -264,16 +264,16 @@ describe('ResponseAreaExtension', () => {
|
|
|
264
264
|
jest.resetModules();
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
-
const buildInsertCommand = () => {
|
|
267
|
+
const buildInsertCommand = (type = 'inline-dropdown') => {
|
|
268
268
|
const { ResponseAreaExtension } = require('../responseArea');
|
|
269
269
|
const context = {
|
|
270
270
|
options: {
|
|
271
|
-
type
|
|
271
|
+
type,
|
|
272
272
|
maxResponseAreas: 5,
|
|
273
273
|
},
|
|
274
274
|
};
|
|
275
275
|
const commands = ResponseAreaExtension.addCommands.call(context);
|
|
276
|
-
return commands.insertResponseArea(
|
|
276
|
+
return commands.insertResponseArea(type);
|
|
277
277
|
};
|
|
278
278
|
|
|
279
279
|
const createDoc = (existingCount, typeName = 'inline_dropdown') => ({
|
|
@@ -391,6 +391,60 @@ describe('ResponseAreaExtension', () => {
|
|
|
391
391
|
expect(create).not.toHaveBeenCalled();
|
|
392
392
|
expect(mockTr.insert).not.toHaveBeenCalled();
|
|
393
393
|
});
|
|
394
|
+
|
|
395
|
+
describe('selection after insert', () => {
|
|
396
|
+
const buildStateAndTr = (typeName, { withResolve = false } = {}) => {
|
|
397
|
+
const mockInlineNode = { nodeSize: 1 };
|
|
398
|
+
const create = jest.fn(() => mockInlineNode);
|
|
399
|
+
const mockDoc = {
|
|
400
|
+
descendants: jest.fn(),
|
|
401
|
+
content: { size: 50 },
|
|
402
|
+
...(withResolve ? { resolve: jest.fn((pos) => ({ resolved: pos })) } : {}),
|
|
403
|
+
};
|
|
404
|
+
const mockTr = {
|
|
405
|
+
insert: jest.fn(),
|
|
406
|
+
doc: mockDoc,
|
|
407
|
+
setSelection: jest.fn(),
|
|
408
|
+
};
|
|
409
|
+
const state = {
|
|
410
|
+
schema: { nodes: { [typeName]: { create } } },
|
|
411
|
+
doc: mockDoc,
|
|
412
|
+
selection: { from: 5 },
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
return { mockTr, state };
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
it.each(['inline-dropdown', 'explicit-constructed-response'])(
|
|
419
|
+
'sets a NodeSelection on the inserted node for %s',
|
|
420
|
+
(type) => {
|
|
421
|
+
const insert = buildInsertCommand(type);
|
|
422
|
+
const typeName = type.replace(/-/g, '_');
|
|
423
|
+
const { mockTr, state } = buildStateAndTr(typeName);
|
|
424
|
+
const { NodeSelection, TextSelection } = require('prosemirror-state');
|
|
425
|
+
|
|
426
|
+
insert({ tr: mockTr, state, dispatch: jest.fn(), commands: { focus: jest.fn() } });
|
|
427
|
+
|
|
428
|
+
expect(NodeSelection.create).toHaveBeenCalledWith(mockTr.doc, 5);
|
|
429
|
+
expect(TextSelection.near).not.toHaveBeenCalled();
|
|
430
|
+
expect(mockTr.setSelection).toHaveBeenCalledWith({ type: 'node', pos: 5 });
|
|
431
|
+
},
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
it('sets a TextSelection just after the inserted node for math-templated (no NodeSelection)', () => {
|
|
435
|
+
const insert = buildInsertCommand('math-templated');
|
|
436
|
+
const { mockTr, state } = buildStateAndTr('math_templated', { withResolve: true });
|
|
437
|
+
const { NodeSelection, TextSelection } = require('prosemirror-state');
|
|
438
|
+
|
|
439
|
+
insert({ tr: mockTr, state, dispatch: jest.fn(), commands: { focus: jest.fn() } });
|
|
440
|
+
|
|
441
|
+
expect(NodeSelection.create).not.toHaveBeenCalled();
|
|
442
|
+
// usedPos (5) + nodeSize (1) === 6
|
|
443
|
+
expect(mockTr.doc.resolve).toHaveBeenCalledWith(6);
|
|
444
|
+
expect(TextSelection.near).toHaveBeenCalledWith({ resolved: 6 }, 1);
|
|
445
|
+
expect(mockTr.setSelection).toHaveBeenCalledWith({ type: 'text', pos: { resolved: 6 }, dir: 1 });
|
|
446
|
+
});
|
|
447
|
+
});
|
|
394
448
|
});
|
|
395
449
|
});
|
|
396
450
|
});
|
|
@@ -125,7 +125,7 @@ function ImageComponent(props) {
|
|
|
125
125
|
);
|
|
126
126
|
|
|
127
127
|
const applySizeData = useCallback(() => {
|
|
128
|
-
if (!node.attrs.width || !imgRef.current) return;
|
|
128
|
+
if (!node.attrs.width || !imgRef.current || !imgRef.current.naturalWidth) return;
|
|
129
129
|
const resizePercent = getPercentFromWidth(node.attrs.width);
|
|
130
130
|
if (node.attrs.resizePercent === resizePercent) return;
|
|
131
131
|
updateThisNode({ resizePercent });
|
|
@@ -138,7 +138,7 @@ function ImageComponent(props) {
|
|
|
138
138
|
|
|
139
139
|
useEffect(() => {
|
|
140
140
|
if (selected) {
|
|
141
|
-
if (onlyThisNodeSelected) {
|
|
141
|
+
if (onlyThisNodeSelected && editor.isEditable) {
|
|
142
142
|
// Only open the upload UI for a fresh placeholder. Remounting after tab switch
|
|
143
143
|
// would otherwise call insertImageRequested again and reopen the file modal.
|
|
144
144
|
const hasImageSrc = String(node.attrs?.src ?? '').trim();
|
|
@@ -156,15 +156,17 @@ function ImageComponent(props) {
|
|
|
156
156
|
} else {
|
|
157
157
|
setShowToolbar(selected);
|
|
158
158
|
}
|
|
159
|
-
}, [onlyThisNodeSelected, selected]);
|
|
159
|
+
}, [onlyThisNodeSelected, selected, editor.isEditable]);
|
|
160
160
|
|
|
161
161
|
useEffect(() => {
|
|
162
162
|
applySizeData();
|
|
163
163
|
|
|
164
|
-
const resizeHandle = resizeRef
|
|
165
|
-
|
|
164
|
+
const resizeHandle = resizeRef?.current;
|
|
165
|
+
|
|
166
|
+
if (resizeHandle && editor.isEditable) {
|
|
166
167
|
resizeHandle.addEventListener('mousedown', initResize, false);
|
|
167
168
|
}
|
|
169
|
+
|
|
168
170
|
return () => {
|
|
169
171
|
if (resizeHandle) {
|
|
170
172
|
resizeHandle.removeEventListener('mousedown', initResize, false);
|
|
@@ -272,7 +274,7 @@ function ImageComponent(props) {
|
|
|
272
274
|
onLoad={loadImage}
|
|
273
275
|
alt={node.attrs.alt}
|
|
274
276
|
/>
|
|
275
|
-
<StyledResize ref={resizeRef} className="resize" />
|
|
277
|
+
<StyledResize ref={resizeRef} className="resize" style={{ display: editor.isEditable ? undefined : 'none' }} />
|
|
276
278
|
</StyledImageContainer>
|
|
277
279
|
</StyledRoot>
|
|
278
280
|
|
|
@@ -195,7 +195,13 @@ export const ResponseAreaExtension = Extension.create({
|
|
|
195
195
|
// tr.setSelection(NodeSelection.create(tr.doc, usedPos))
|
|
196
196
|
|
|
197
197
|
// --- Cursor move behavior for certain types (Slate: moveFocusTo next text) ---
|
|
198
|
-
|
|
198
|
+
// Only types whose node view opens its own toolbar on selection
|
|
199
|
+
// (inline_dropdown, explicit_constructed_response) benefit from a
|
|
200
|
+
// NodeSelection here — the toolbar is the visual feedback that it's
|
|
201
|
+
// selected. math_templated has no such UI, so a NodeSelection there
|
|
202
|
+
// just looks unfocused (a highlighted node, no blinking caret);
|
|
203
|
+
// moving the cursor to just after it gives a real, visible caret.
|
|
204
|
+
if (['inline_dropdown', 'explicit_constructed_response'].includes(typeName)) {
|
|
199
205
|
tr.setSelection(NodeSelection.create(tr.doc, usedPos));
|
|
200
206
|
} else {
|
|
201
207
|
const after = usedPos + newInline.nodeSize;
|
package/LICENSE.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
Copyright 2019 CoreSpring Inc
|
|
2
|
-
|
|
3
|
-
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
4
|
-
|
|
5
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|