@pie-lib/editable-html-tip-tap 0.1.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 (158) hide show
  1. package/dist/components/CharacterPicker.d.ts +31 -0
  2. package/dist/components/CharacterPicker.d.ts.map +1 -0
  3. package/dist/components/CharacterPicker.js +129 -0
  4. package/dist/components/EditableHtml.d.ts +11 -0
  5. package/dist/components/EditableHtml.d.ts.map +1 -0
  6. package/dist/components/EditableHtml.js +270 -0
  7. package/dist/components/MenuBar.d.ts +11 -0
  8. package/dist/components/MenuBar.d.ts.map +1 -0
  9. package/dist/components/MenuBar.js +460 -0
  10. package/dist/components/TiptapContainer.d.ts +11 -0
  11. package/dist/components/TiptapContainer.d.ts.map +1 -0
  12. package/dist/components/TiptapContainer.js +157 -0
  13. package/dist/components/characters/characterUtils.d.ts +36 -0
  14. package/dist/components/characters/characterUtils.d.ts.map +1 -0
  15. package/dist/components/characters/characterUtils.js +465 -0
  16. package/dist/components/characters/custom-popper.d.ts +14 -0
  17. package/dist/components/characters/custom-popper.d.ts.map +1 -0
  18. package/dist/components/characters/custom-popper.js +32 -0
  19. package/dist/components/common/done-button.d.ts +30 -0
  20. package/dist/components/common/done-button.d.ts.map +1 -0
  21. package/dist/components/common/done-button.js +26 -0
  22. package/dist/components/common/toolbar-buttons.d.ts +39 -0
  23. package/dist/components/common/toolbar-buttons.d.ts.map +1 -0
  24. package/dist/components/common/toolbar-buttons.js +91 -0
  25. package/dist/components/icons/CssIcon.d.ts +11 -0
  26. package/dist/components/icons/CssIcon.d.ts.map +1 -0
  27. package/dist/components/icons/CssIcon.js +14 -0
  28. package/dist/components/icons/RespArea.d.ts +26 -0
  29. package/dist/components/icons/RespArea.d.ts.map +1 -0
  30. package/dist/components/icons/RespArea.js +42 -0
  31. package/dist/components/icons/TableIcons.d.ts +14 -0
  32. package/dist/components/icons/TableIcons.d.ts.map +1 -0
  33. package/dist/components/icons/TableIcons.js +32 -0
  34. package/dist/components/icons/TextAlign.d.ts +18 -0
  35. package/dist/components/icons/TextAlign.d.ts.map +1 -0
  36. package/dist/components/icons/TextAlign.js +134 -0
  37. package/dist/components/image/AltDialog.d.ts +23 -0
  38. package/dist/components/image/AltDialog.d.ts.map +1 -0
  39. package/dist/components/image/AltDialog.js +61 -0
  40. package/dist/components/image/ImageToolbar.d.ts +25 -0
  41. package/dist/components/image/ImageToolbar.d.ts.map +1 -0
  42. package/dist/components/image/ImageToolbar.js +80 -0
  43. package/dist/components/image/InsertImageHandler.d.ts +33 -0
  44. package/dist/components/image/InsertImageHandler.d.ts.map +1 -0
  45. package/dist/components/image/InsertImageHandler.js +55 -0
  46. package/dist/components/media/MediaDialog.d.ts +44 -0
  47. package/dist/components/media/MediaDialog.d.ts.map +1 -0
  48. package/dist/components/media/MediaDialog.js +389 -0
  49. package/dist/components/media/MediaToolbar.d.ts +20 -0
  50. package/dist/components/media/MediaToolbar.d.ts.map +1 -0
  51. package/dist/components/media/MediaToolbar.js +41 -0
  52. package/dist/components/media/MediaWrapper.d.ts +20 -0
  53. package/dist/components/media/MediaWrapper.d.ts.map +1 -0
  54. package/dist/components/respArea/DragInTheBlank/DragInTheBlank.d.ts +23 -0
  55. package/dist/components/respArea/DragInTheBlank/DragInTheBlank.d.ts.map +1 -0
  56. package/dist/components/respArea/DragInTheBlank/DragInTheBlank.js +58 -0
  57. package/dist/components/respArea/DragInTheBlank/choice.d.ts +56 -0
  58. package/dist/components/respArea/DragInTheBlank/choice.d.ts.map +1 -0
  59. package/dist/components/respArea/DragInTheBlank/choice.js +156 -0
  60. package/dist/components/respArea/ExplicitConstructedResponse.d.ts +20 -0
  61. package/dist/components/respArea/ExplicitConstructedResponse.d.ts.map +1 -0
  62. package/dist/components/respArea/ExplicitConstructedResponse.js +67 -0
  63. package/dist/components/respArea/InlineDropdown.d.ts +18 -0
  64. package/dist/components/respArea/InlineDropdown.d.ts.map +1 -0
  65. package/dist/components/respArea/InlineDropdown.js +91 -0
  66. package/dist/components/respArea/MathTemplated.d.ts +19 -0
  67. package/dist/components/respArea/MathTemplated.d.ts.map +1 -0
  68. package/dist/components/respArea/MathTemplated.js +97 -0
  69. package/dist/components/respArea/ToolbarIcon.d.ts +14 -0
  70. package/dist/components/respArea/ToolbarIcon.d.ts.map +1 -0
  71. package/dist/components/respArea/ToolbarIcon.js +17 -0
  72. package/dist/constants.d.ts +14 -0
  73. package/dist/constants.d.ts.map +1 -0
  74. package/dist/constants.js +4 -0
  75. package/dist/extensions/css.d.ts +12 -0
  76. package/dist/extensions/css.d.ts.map +1 -0
  77. package/dist/extensions/css.js +115 -0
  78. package/dist/extensions/custom-toolbar-wrapper.d.ts +11 -0
  79. package/dist/extensions/custom-toolbar-wrapper.d.ts.map +1 -0
  80. package/dist/extensions/custom-toolbar-wrapper.js +58 -0
  81. package/dist/extensions/div-node.d.ts +11 -0
  82. package/dist/extensions/div-node.d.ts.map +1 -0
  83. package/dist/extensions/div-node.js +25 -0
  84. package/dist/extensions/extended-table.d.ts +11 -0
  85. package/dist/extensions/extended-table.d.ts.map +1 -0
  86. package/dist/extensions/extended-table.js +15 -0
  87. package/dist/extensions/image-component.d.ts +22 -0
  88. package/dist/extensions/image-component.d.ts.map +1 -0
  89. package/dist/extensions/image-component.js +200 -0
  90. package/dist/extensions/image.d.ts +11 -0
  91. package/dist/extensions/image.d.ts.map +1 -0
  92. package/dist/extensions/image.js +42 -0
  93. package/dist/extensions/index.d.ts +17 -0
  94. package/dist/extensions/index.d.ts.map +1 -0
  95. package/dist/extensions/index.js +65 -0
  96. package/dist/extensions/math.d.ts +15 -0
  97. package/dist/extensions/math.d.ts.map +1 -0
  98. package/dist/extensions/math.js +150 -0
  99. package/dist/extensions/media.d.ts +19 -0
  100. package/dist/extensions/media.d.ts.map +1 -0
  101. package/dist/extensions/media.js +147 -0
  102. package/dist/extensions/responseArea.d.ts +28 -0
  103. package/dist/extensions/responseArea.d.ts.map +1 -0
  104. package/dist/extensions/responseArea.js +259 -0
  105. package/dist/index.d.ts +13 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +6 -0
  108. package/dist/styles/editorContainerStyles.d.ts +135 -0
  109. package/dist/styles/editorContainerStyles.d.ts.map +1 -0
  110. package/dist/theme.d.ts +10 -0
  111. package/dist/theme.d.ts.map +1 -0
  112. package/dist/utils/helper.d.ts +10 -0
  113. package/dist/utils/helper.d.ts.map +1 -0
  114. package/dist/utils/helper.js +7 -0
  115. package/dist/utils/size.d.ts +10 -0
  116. package/dist/utils/size.d.ts.map +1 -0
  117. package/dist/utils/size.js +14 -0
  118. package/package.json +71 -0
  119. package/src/components/CharacterPicker.tsx +210 -0
  120. package/src/components/EditableHtml.tsx +416 -0
  121. package/src/components/MenuBar.tsx +558 -0
  122. package/src/components/TiptapContainer.tsx +228 -0
  123. package/src/components/characters/characterUtils.ts +457 -0
  124. package/src/components/characters/custom-popper.tsx +48 -0
  125. package/src/components/common/done-button.tsx +37 -0
  126. package/src/components/common/toolbar-buttons.tsx +132 -0
  127. package/src/components/icons/CssIcon.tsx +25 -0
  128. package/src/components/icons/RespArea.tsx +81 -0
  129. package/src/components/icons/TableIcons.tsx +62 -0
  130. package/src/components/icons/TextAlign.tsx +124 -0
  131. package/src/components/image/AltDialog.tsx +92 -0
  132. package/src/components/image/ImageToolbar.tsx +109 -0
  133. package/src/components/image/InsertImageHandler.ts +121 -0
  134. package/src/components/media/MediaDialog.tsx +606 -0
  135. package/src/components/media/MediaToolbar.tsx +59 -0
  136. package/src/components/media/MediaWrapper.tsx +49 -0
  137. package/src/components/respArea/DragInTheBlank/DragInTheBlank.tsx +86 -0
  138. package/src/components/respArea/DragInTheBlank/choice.tsx +266 -0
  139. package/src/components/respArea/ExplicitConstructedResponse.tsx +122 -0
  140. package/src/components/respArea/InlineDropdown.tsx +152 -0
  141. package/src/components/respArea/MathTemplated.tsx +134 -0
  142. package/src/components/respArea/ToolbarIcon.tsx +76 -0
  143. package/src/constants.ts +15 -0
  144. package/src/extensions/css.tsx +230 -0
  145. package/src/extensions/custom-toolbar-wrapper.tsx +88 -0
  146. package/src/extensions/div-node.tsx +46 -0
  147. package/src/extensions/extended-table.ts +34 -0
  148. package/src/extensions/image-component.tsx +303 -0
  149. package/src/extensions/image.tsx +64 -0
  150. package/src/extensions/index.tsx +91 -0
  151. package/src/extensions/math.tsx +285 -0
  152. package/src/extensions/media.tsx +198 -0
  153. package/src/extensions/responseArea.tsx +404 -0
  154. package/src/index.tsx +15 -0
  155. package/src/styles/editorContainerStyles.ts +155 -0
  156. package/src/theme.ts +11 -0
  157. package/src/utils/helper.tsx +27 -0
  158. package/src/utils/size.ts +42 -0
@@ -0,0 +1,86 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @synced-from pie-lib/packages/editable-html-tip-tap/src/components/respArea/DragInTheBlank/DragInTheBlank.jsx
4
+ * @auto-generated
5
+ *
6
+ * This file is automatically synced from pie-elements and converted to TypeScript.
7
+ * Manual edits will be overwritten on next sync.
8
+ * To make changes, edit the upstream JavaScript file and run sync again.
9
+ */
10
+
11
+ import React from 'react';
12
+ import PropTypes from 'prop-types';
13
+ import { NodeViewWrapper } from '@tiptap/react';
14
+ import DragDropTile from './choice.js';
15
+ import omit from 'lodash-es/omit.js';
16
+
17
+ export const onValueChange = (editor, node, pos, choice) => {
18
+ const { tr } = editor.state;
19
+
20
+ // Merge old and new attributes
21
+ tr.setNodeMarkup(pos, undefined, {
22
+ ...node.attrs,
23
+ ...choice.value,
24
+ });
25
+ tr.isDone = true;
26
+ editor.view.dispatch(tr);
27
+ };
28
+
29
+ export const onRemoveResponse = (editor, node, choice) => {
30
+ const { tr } = editor.state;
31
+
32
+ // Merge old and new attributes
33
+ tr.setNodeMarkup(choice.pos, undefined, omit(node.attrs, ['value', 'id']));
34
+ tr.isDone = true;
35
+ editor.view.dispatch(tr);
36
+ };
37
+
38
+ const DragDrop = (props) => {
39
+ const { editor, node, getPos, options, selected } = props;
40
+ const { attrs: attributes } = node;
41
+ const { inTable } = attributes;
42
+ const pos = getPos();
43
+
44
+ // console.log({nodeProps.children})
45
+ return (
46
+ <NodeViewWrapper
47
+ className="drag-in-the-blank"
48
+ data-selected={selected}
49
+ style={{ display: 'inline', whiteSpace: 'normal' }}
50
+ >
51
+ <span
52
+ {...attributes}
53
+ style={{
54
+ display: 'inline-flex',
55
+ minHeight: '50px',
56
+ minWidth: '178px',
57
+ position: 'relative',
58
+ margin: inTable ? '10px' : '0 10px',
59
+ cursor: 'pointer',
60
+ }}
61
+ >
62
+ <DragDropTile
63
+ n={attributes}
64
+ dragKey={attributes.id}
65
+ targetId="0"
66
+ pos={pos}
67
+ value={attributes}
68
+ duplicates={options.duplicates}
69
+ selected={selected}
70
+ onChange={(choice) => onValueChange(editor, node, pos, choice)}
71
+ removeResponse={(choice) => onRemoveResponse(editor, node, choice)}
72
+ ></DragDropTile>
73
+ </span>
74
+ </NodeViewWrapper>
75
+ );
76
+ };
77
+
78
+ DragDrop.propTypes = {
79
+ attributes: PropTypes.object,
80
+ data: PropTypes.object,
81
+ n: PropTypes.object,
82
+ nodeProps: PropTypes.object,
83
+ opts: PropTypes.object,
84
+ };
85
+
86
+ export default DragDrop;
@@ -0,0 +1,266 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @synced-from pie-lib/packages/editable-html-tip-tap/src/components/respArea/DragInTheBlank/choice.jsx
4
+ * @auto-generated
5
+ *
6
+ * This file is automatically synced from pie-elements and converted to TypeScript.
7
+ * Manual edits will be overwritten on next sync.
8
+ * To make changes, edit the upstream JavaScript file and run sync again.
9
+ */
10
+
11
+ import React, { useEffect, useRef, useState } from 'react';
12
+ import PropTypes from 'prop-types';
13
+ import { useDraggable, useDroppable } from '@dnd-kit/core';
14
+ import { color } from '@pie-lib/render-ui';
15
+ import { renderMath } from '@pie-element/shared-math-rendering-mathjax';
16
+ import { styled } from '@mui/material/styles';
17
+ import classnames from 'classnames';
18
+
19
+ import { GripIcon } from '../../icons/RespArea.js';
20
+
21
+ const StyledContent: any = styled('span')(({ theme }) => ({
22
+ border: `solid 0px ${theme.palette.primary.main}`,
23
+ '& mjx-frac': {
24
+ fontSize: '120% !important',
25
+ },
26
+ }));
27
+
28
+ export function BlankContent({ n, children, isDragging, isOver, dragItem, value, selected }) {
29
+ const [hoveredElementSize, setHoveredElementSize] = useState(null);
30
+ const elementRef = useRef(null);
31
+
32
+ const handleClick = (event) => {
33
+ if (!elementRef.current) return;
34
+
35
+ if (elementRef.current.contains(event.target)) {
36
+ elementRef.current.classList.add('selected');
37
+ } else {
38
+ elementRef.current.classList.remove('selected');
39
+ }
40
+ };
41
+
42
+ useEffect(() => {
43
+ document.addEventListener('click', handleClick);
44
+ return () => {
45
+ document.removeEventListener('click', handleClick);
46
+ };
47
+ }, []);
48
+
49
+ useEffect(() => {
50
+ if (elementRef.current && typeof renderMath === 'function') {
51
+ renderMath(elementRef.current);
52
+ }
53
+ }, [value?.value, isOver, dragItem?.value?.value]);
54
+
55
+ useEffect(() => {
56
+ if (isOver && elementRef.current && !hoveredElementSize) {
57
+ const node = elementRef.current;
58
+ setHoveredElementSize({ width: node.offsetWidth, height: node.offsetHeight });
59
+ } else if (!isOver && hoveredElementSize) {
60
+ setHoveredElementSize(null);
61
+ }
62
+ }, [isOver, hoveredElementSize]);
63
+
64
+ const label = dragItem && isOver ? dragItem.value.value : value.value || '\u00A0';
65
+ const finalLabel = isDragging ? '\u00A0' : label;
66
+ const hasGrip = finalLabel !== '\u00A0';
67
+ const isPreview = dragItem && isOver;
68
+
69
+ const borderStyle = selected
70
+ ? `2px solid ${color.primaryDark()}`
71
+ : isPreview
72
+ ? `1px solid ${color.defaults.BORDER_DARK}`
73
+ : `1px solid ${color.defaults.BORDER_LIGHT}`;
74
+
75
+ return (
76
+ <div
77
+ ref={elementRef}
78
+ className={selected ? 'selected' : undefined}
79
+ style={{
80
+ display: 'inline-flex',
81
+ minWidth: '178px',
82
+ minHeight: '36px',
83
+ background: isPreview ? `${color.defaults.BORDER_LIGHT}` : `${color.defaults.WHITE}`,
84
+ border: borderStyle,
85
+ boxSizing: 'border-box',
86
+ borderRadius: '3px',
87
+ overflow: 'hidden',
88
+ position: 'relative',
89
+ padding: '8px 8px 8px 35px',
90
+ width: hoveredElementSize ? hoveredElementSize.width : undefined,
91
+ height: hoveredElementSize ? hoveredElementSize.height : undefined,
92
+ touchAction: 'none',
93
+ }}
94
+ data-key={n.index}
95
+ contentEditable={false}
96
+ >
97
+ {hasGrip && (
98
+ <GripIcon
99
+ style={{
100
+ position: 'absolute',
101
+ top: '6px',
102
+ left: '15px',
103
+ color: '#9B9B9B',
104
+ }}
105
+ contentEditable={false}
106
+ />
107
+ )}
108
+ <span
109
+ dangerouslySetInnerHTML={{
110
+ __html: finalLabel,
111
+ }}
112
+ />
113
+ {children}
114
+ </div>
115
+ );
116
+ }
117
+
118
+ BlankContent.propTypes = {
119
+ n: PropTypes.object,
120
+ children: PropTypes.node,
121
+ isDragging: PropTypes.bool,
122
+ isOver: PropTypes.bool,
123
+ dragItem: PropTypes.object,
124
+ value: PropTypes.object,
125
+ selected: PropTypes.bool,
126
+ };
127
+
128
+ function DragDropChoice({
129
+ value,
130
+ disabled,
131
+ instanceId,
132
+ children,
133
+ n,
134
+ onChange,
135
+ removeResponse,
136
+ duplicates,
137
+ pos,
138
+ selected,
139
+ }) {
140
+ const {
141
+ attributes: dragAttributes,
142
+ listeners: dragListeners,
143
+ setNodeRef: setDragNodeRef,
144
+ isDragging,
145
+ } = useDraggable({
146
+ id: `drag-${n.index}`,
147
+ disabled: disabled || !value?.value,
148
+ data: {
149
+ id: `drag-${n.index}`,
150
+ value,
151
+ instanceId,
152
+ n,
153
+ pos,
154
+ opts: { duplicates },
155
+ type: 'drag-in-the-blank-placed-choice',
156
+ fromChoice: !value,
157
+ onRemove: (draggedData) => removeResponse(draggedData),
158
+ onDrop: (draggedData, dropData) => {
159
+ // check if we're dropping into a blank
160
+ const isValidBlank = dropData?.type === 'drag-in-the-blank-drop-choice';
161
+
162
+ if (!isValidBlank) return;
163
+
164
+ // place into blank
165
+ onChange(draggedData);
166
+
167
+ if (!duplicates && draggedData.fromChoice) {
168
+ removeResponse(draggedData);
169
+ }
170
+ },
171
+ },
172
+ });
173
+
174
+ const {
175
+ setNodeRef: setDropNodeRef,
176
+ isOver,
177
+ active: dragItem,
178
+ } = useDroppable({
179
+ id: `drop-${n.index}`,
180
+ data: {
181
+ type: 'drag-in-the-blank-drop-choice',
182
+ accepts: ['drag-in-the-blank-choice', 'drag-in-the-blank-placed-choice'],
183
+ instanceId: instanceId,
184
+ value: value,
185
+ id: `drop-${n.index}`,
186
+ pos,
187
+ n,
188
+ opts: { duplicates },
189
+ onDrop: (draggedData, dropData) => {
190
+ // check if we're dropping into a blank
191
+ const isValidBlank = dropData?.type === 'drag-in-the-blank-drop-choice';
192
+
193
+ if (!isValidBlank) return;
194
+
195
+ // if the dragged and dropped data are the same, do nothing
196
+ if (draggedData.value.id === dropData.value.id) return;
197
+
198
+ if (draggedData.type === 'drag-in-the-blank-choice') {
199
+ // place into blank
200
+ onChange(draggedData);
201
+
202
+ if (!duplicates && draggedData.fromChoice) {
203
+ removeResponse(draggedData);
204
+ }
205
+ return;
206
+ }
207
+
208
+ // moving placed choice between blanks
209
+ if (draggedData.type === 'drag-in-the-blank-placed-choice') {
210
+ // clear target blank
211
+ removeResponse(dropData);
212
+
213
+ // set new blank value
214
+ onChange(draggedData);
215
+
216
+ // clear original blank - slight delay to ensure state updates correctly
217
+ setTimeout(() => removeResponse(draggedData), 10);
218
+ }
219
+ },
220
+ },
221
+ });
222
+
223
+ const setNodeRef = (node) => {
224
+ setDragNodeRef(node);
225
+ setDropNodeRef(node);
226
+ };
227
+
228
+ const dragContent = (
229
+ <BlankContent
230
+ n={n}
231
+ isDragging={isDragging}
232
+ isOver={isOver}
233
+ dragItem={dragItem?.data?.current}
234
+ value={value}
235
+ selected={selected}
236
+ >
237
+ {children}
238
+ </BlankContent>
239
+ );
240
+
241
+ const dragEl = !value ? (
242
+ <span ref={setDropNodeRef}>{dragContent}</span>
243
+ ) : (
244
+ <span ref={setNodeRef} {...dragAttributes} {...dragListeners}>
245
+ {dragContent}
246
+ </span>
247
+ );
248
+
249
+ const content = <StyledContent className={classnames(isOver && 'over')}>{dragEl}</StyledContent>;
250
+
251
+ return content;
252
+ }
253
+
254
+ DragDropChoice.propTypes = {
255
+ value: PropTypes.object,
256
+ disabled: PropTypes.bool,
257
+ instanceId: PropTypes.string,
258
+ children: PropTypes.node,
259
+ n: PropTypes.object.isRequired,
260
+ onChange: PropTypes.func.isRequired,
261
+ removeResponse: PropTypes.func.isRequired,
262
+ duplicates: PropTypes.bool,
263
+ selected: PropTypes.bool,
264
+ };
265
+
266
+ export default DragDropChoice;
@@ -0,0 +1,122 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @synced-from pie-lib/packages/editable-html-tip-tap/src/components/respArea/ExplicitConstructedResponse.jsx
4
+ * @auto-generated
5
+ *
6
+ * This file is automatically synced from pie-elements and converted to TypeScript.
7
+ * Manual edits will be overwritten on next sync.
8
+ * To make changes, edit the upstream JavaScript file and run sync again.
9
+ */
10
+
11
+ import React, { useEffect, useRef, useState } from 'react';
12
+ import { NodeViewWrapper } from '@tiptap/react';
13
+ import PropTypes from 'prop-types';
14
+
15
+ const ExplicitConstructedResponse = (props) => {
16
+ const { editor, node, getPos, options, selected } = props;
17
+ const { attrs: attributes } = node;
18
+ const { value } = attributes;
19
+ const { respAreaToolbar, error: errorFn } = options;
20
+ const pos = getPos();
21
+ const [showToolbar, setShowToolbar] = useState(false);
22
+ const EcrToolbar = respAreaToolbar([node, pos], editor, () => {});
23
+ const toolbarRef = useRef(null);
24
+
25
+ let error;
26
+
27
+ if (errorFn) {
28
+ const errorValue = errorFn();
29
+ const respIndex = parseInt(attributes.index, 10);
30
+
31
+ error = !!errorValue?.[respIndex]?.[0];
32
+ }
33
+
34
+ const handleDone = (newLatex) => {
35
+ updateAttributes({ latex: newLatex });
36
+ setShowToolbar(false);
37
+ editor.commands.focus();
38
+ };
39
+
40
+ useEffect(() => {
41
+ const { selection } = editor.state;
42
+ const onlyThisNodeSelected = selection.from + node.nodeSize === selection.to;
43
+
44
+ if (selected) {
45
+ if (onlyThisNodeSelected) {
46
+ setShowToolbar(selected);
47
+ }
48
+ } else {
49
+ setShowToolbar(selected);
50
+ }
51
+ }, [editor, node, selected]);
52
+
53
+ useEffect(() => {
54
+ const handleClickOutside = (event) => {
55
+ if (
56
+ toolbarRef.current &&
57
+ !toolbarRef.current.contains(event.target) &&
58
+ !event.target.closest('[data-inline-node]')
59
+ ) {
60
+ setShowToolbar(false);
61
+ }
62
+ };
63
+
64
+ if (showToolbar) {
65
+ document.addEventListener('mousedown', handleClickOutside);
66
+ } else {
67
+ document.removeEventListener('mousedown', handleClickOutside);
68
+ }
69
+
70
+ return () => document.removeEventListener('mousedown', handleClickOutside);
71
+ }, [showToolbar]);
72
+
73
+ return (
74
+ <NodeViewWrapper
75
+ className="drag-in-the-blank"
76
+ data-selected={selected}
77
+ style={{
78
+ display: 'inline-flex',
79
+ minHeight: '55px',
80
+ position: 'relative',
81
+ cursor: 'pointer',
82
+ }}
83
+ >
84
+ <div
85
+ {...attributes}
86
+ style={{
87
+ display: 'inline-flex',
88
+ width: '100%',
89
+ minHeight: '46px',
90
+ height: '46px',
91
+ backgroundColor: '#FFF',
92
+ border: `1px solid ${error ? 'red' : '#C0C3CF'}`,
93
+ boxSizing: 'border-box',
94
+ borderRadius: '4px',
95
+ overflow: 'hidden',
96
+ padding: '12px 21px',
97
+ margin: '0 4px',
98
+ minWidth: '178px',
99
+ visibility: showToolbar ? 'hidden' : 'visible',
100
+ }}
101
+ onClick={() => setShowToolbar(true)}
102
+ dangerouslySetInnerHTML={{
103
+ __html: value || '<div>&nbsp;</div>',
104
+ }}
105
+ />
106
+ {showToolbar && (
107
+ <div ref={toolbarRef} className="absolute z-50 bg-white shadow-lg rounded p-2" style={{ zIndex: 1 }}>
108
+ <EcrToolbar />
109
+ </div>
110
+ )}
111
+ </NodeViewWrapper>
112
+ );
113
+ };
114
+
115
+ ExplicitConstructedResponse.propTypes = {
116
+ attributes: PropTypes.object,
117
+ error: PropTypes.any,
118
+ value: PropTypes.string,
119
+ isFocused: PropTypes.bool,
120
+ };
121
+
122
+ export default ExplicitConstructedResponse;
@@ -0,0 +1,152 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @synced-from pie-lib/packages/editable-html-tip-tap/src/components/respArea/InlineDropdown.jsx
4
+ * @auto-generated
5
+ *
6
+ * This file is automatically synced from pie-elements and converted to TypeScript.
7
+ * Manual edits will be overwritten on next sync.
8
+ * To make changes, edit the upstream JavaScript file and run sync again.
9
+ */
10
+
11
+ import React, { useEffect, useRef, useState } from 'react';
12
+ import PropTypes from 'prop-types';
13
+ import { NodeViewWrapper } from '@tiptap/react';
14
+ import { Chevron } from '../icons/RespArea.js';
15
+ import ReactDOM from 'react-dom';
16
+
17
+ const InlineDropdown = (props) => {
18
+ const { editor, node, getPos, options, selected } = props;
19
+ const { attrs: attributes } = node;
20
+ const { value, error } = attributes;
21
+ // TODO: Investigate
22
+ // Needed because items with values inside have different positioning for some reason
23
+ const html = value || '<div>&nbsp</div>';
24
+ const pos = getPos();
25
+ const toolbarRef = useRef(null);
26
+ const toolbarEditor = useRef(null);
27
+ const [showToolbar, setShowToolbar] = useState(false);
28
+ const [position, setPosition] = useState({ top: 0, left: 0 });
29
+ const InlineDropdownToolbar = options.respAreaToolbar([node, pos], editor, () => {});
30
+
31
+ useEffect(() => {
32
+ const { selection } = editor.state;
33
+ const onlyThisNodeSelected = selection.from + node.nodeSize === selection.to;
34
+
35
+ if (selected) {
36
+ if (onlyThisNodeSelected) {
37
+ setShowToolbar(selected);
38
+ }
39
+ } else {
40
+ setShowToolbar(selected);
41
+ }
42
+ }, [editor, node, selected]);
43
+
44
+ useEffect(() => {
45
+ // Calculate position relative to selection
46
+ const bodyRect = document.body.getBoundingClientRect();
47
+ const { from } = editor.state.selection;
48
+ const start = editor.view.coordsAtPos(from);
49
+
50
+ setPosition({
51
+ top: start.top + Math.abs(bodyRect.top) + 40, // shift above
52
+ left: start.left,
53
+ });
54
+
55
+ const handleClickOutside = (event) => {
56
+ const insideSomeEditor = event.target.closest('[data-toolbar-for]');
57
+
58
+ if (
59
+ (!insideSomeEditor || insideSomeEditor.dataset.toolbarFor !== toolbarEditor.current.instanceId) &&
60
+ !editor._toolbarOpened &&
61
+ toolbarRef.current &&
62
+ !toolbarRef.current.contains(event.target) &&
63
+ !event.target.closest('[data-inline-node]')
64
+ ) {
65
+ setShowToolbar(false);
66
+ }
67
+ };
68
+
69
+ if (showToolbar) {
70
+ document.addEventListener('mousedown', handleClickOutside);
71
+ } else {
72
+ document.removeEventListener('mousedown', handleClickOutside);
73
+ }
74
+
75
+ return () => document.removeEventListener('mousedown', handleClickOutside);
76
+ }, [showToolbar]);
77
+
78
+ return (
79
+ <NodeViewWrapper
80
+ className="inline-dropdown"
81
+ data-selected={selected}
82
+ style={{
83
+ display: 'inline-flex',
84
+ height: '50px',
85
+ margin: '0 5px',
86
+ cursor: 'pointer',
87
+ }}
88
+ >
89
+ <div
90
+ style={{
91
+ display: 'inline-flex',
92
+ minWidth: '178px',
93
+ height: '36px',
94
+ background: '#FFF',
95
+ border: '1px solid #C0C3CF',
96
+ boxSizing: 'border-box',
97
+ borderRadius: '3px',
98
+ margin: '0 4px',
99
+ position: 'relative',
100
+ alignItems: 'center',
101
+ }}
102
+ onClick={() => setShowToolbar(true)}
103
+ >
104
+ <div
105
+ style={{
106
+ flex: 1,
107
+ overflow: 'hidden',
108
+ padding: '0 25px 0 8px',
109
+ whiteSpace: 'nowrap',
110
+ textOverflow: 'ellipsis',
111
+ }}
112
+ >
113
+ <span
114
+ style={{
115
+ display: 'inline-block',
116
+ verticalAlign: 'middle',
117
+ }}
118
+ dangerouslySetInnerHTML={{
119
+ __html: html,
120
+ }}
121
+ />
122
+ </div>
123
+ <Chevron
124
+ direction="down"
125
+ style={{
126
+ position: 'absolute',
127
+ top: '5px',
128
+ right: '5px',
129
+ }}
130
+ />
131
+ </div>
132
+ {showToolbar &&
133
+ ReactDOM.createPortal(
134
+ <div ref={toolbarRef} style={{ zIndex: 1 }}>
135
+ <InlineDropdownToolbar
136
+ editorCallback={(instance) => {
137
+ toolbarEditor.current = instance;
138
+ }}
139
+ />
140
+ </div>,
141
+ document.body,
142
+ )}
143
+ </NodeViewWrapper>
144
+ );
145
+ };
146
+
147
+ InlineDropdown.propTypes = {
148
+ attributes: PropTypes.object,
149
+ selectedItem: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
150
+ };
151
+
152
+ export default InlineDropdown;