@macrostrat/feedback-components 1.0.1 → 1.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 (104) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/esm/feedback-components.4359bc80.js +70 -0
  3. package/dist/esm/feedback-components.4359bc80.js.map +1 -0
  4. package/dist/esm/{extractions.65bb73cc.js → feedback-components.5df2a926.js} +46 -18
  5. package/dist/esm/feedback-components.5df2a926.js.map +1 -0
  6. package/dist/esm/feedback-components.6a6c8af5.js +552 -0
  7. package/dist/esm/feedback-components.6a6c8af5.js.map +1 -0
  8. package/dist/esm/{main.module.cd706d67.js → feedback-components.6d32ee91.js} +1 -1
  9. package/dist/esm/{main.module.cd706d67.js.map → feedback-components.6d32ee91.js.map} +1 -1
  10. package/dist/esm/{graph.f4f65d79.js → feedback-components.7cd9b6cc.js} +45 -14
  11. package/dist/esm/feedback-components.7cd9b6cc.js.map +1 -0
  12. package/dist/esm/{node.28634e40.js → feedback-components.87533431.js} +11 -6
  13. package/dist/esm/feedback-components.87533431.js.map +1 -0
  14. package/dist/esm/feedback-components.921dcd46.js +241 -0
  15. package/dist/esm/feedback-components.921dcd46.js.map +1 -0
  16. package/dist/esm/{type-selector.6e8952d6.js → feedback-components.ad9f284e.js} +6 -5
  17. package/dist/esm/feedback-components.ad9f284e.js.map +1 -0
  18. package/dist/esm/feedback-components.b7d9b015.css +156 -0
  19. package/dist/esm/feedback-components.b7d9b015.css.map +1 -0
  20. package/dist/esm/{edit-state.c39d8466.js → feedback-components.bf5f7cf7.js} +98 -7
  21. package/dist/esm/feedback-components.bf5f7cf7.js.map +1 -0
  22. package/dist/esm/{main.module.8d366b6e.css → feedback-components.bf93773c.css} +1 -1
  23. package/dist/esm/{main.module.8d366b6e.css.map → feedback-components.bf93773c.css.map} +1 -1
  24. package/dist/esm/{main.module.2f2972c8.css → feedback-components.e273ed5b.css} +1 -1
  25. package/dist/esm/{main.module.2f2972c8.css.map → feedback-components.e273ed5b.css.map} +1 -1
  26. package/dist/esm/{main.module.d2fbdf09.js → feedback-components.f9850d85.js} +1 -1
  27. package/dist/esm/{main.module.d2fbdf09.js.map → feedback-components.f9850d85.js.map} +1 -1
  28. package/dist/esm/index.d.ts +38 -13
  29. package/dist/esm/index.d.ts.map +1 -1
  30. package/dist/esm/index.js +2 -2
  31. package/dist/node/feedback-components.15e1316d.js +2 -0
  32. package/dist/node/feedback-components.15e1316d.js.map +1 -0
  33. package/dist/node/feedback-components.2f391fa4.js +2 -0
  34. package/dist/node/feedback-components.2f391fa4.js.map +1 -0
  35. package/dist/node/feedback-components.65d8488e.js +2 -0
  36. package/dist/node/feedback-components.65d8488e.js.map +1 -0
  37. package/dist/node/feedback-components.6681dbde.js +2 -0
  38. package/dist/node/feedback-components.6681dbde.js.map +1 -0
  39. package/dist/node/feedback-components.77b6fc89.css +2 -0
  40. package/dist/node/feedback-components.77b6fc89.css.map +1 -0
  41. package/dist/node/{main.module.ebdf985b.js → feedback-components.794f429b.js} +2 -2
  42. package/dist/node/feedback-components.794f429b.js.map +1 -0
  43. package/dist/node/feedback-components.7caa447a.js +2 -0
  44. package/dist/node/feedback-components.7caa447a.js.map +1 -0
  45. package/dist/node/{main.module.1fdfe813.css → feedback-components.83c21466.css} +1 -1
  46. package/dist/node/feedback-components.83c21466.css.map +1 -0
  47. package/dist/node/feedback-components.8b03e8be.js +2 -0
  48. package/dist/node/feedback-components.8b03e8be.js.map +1 -0
  49. package/dist/node/{main.module.6bc7d51b.css → feedback-components.9eb1d41a.css} +1 -1
  50. package/dist/node/feedback-components.9eb1d41a.css.map +1 -0
  51. package/dist/node/feedback-components.acac789b.js +2 -0
  52. package/dist/node/feedback-components.acac789b.js.map +1 -0
  53. package/dist/node/feedback-components.e2f3c4b7.js +2 -0
  54. package/dist/node/feedback-components.e2f3c4b7.js.map +1 -0
  55. package/dist/node/feedback-components.e8aa70b8.js +2 -0
  56. package/dist/node/feedback-components.e8aa70b8.js.map +1 -0
  57. package/dist/node/index.js +1 -1
  58. package/dist/node/index.js.map +1 -1
  59. package/package.json +7 -6
  60. package/src/extractions/index.ts +76 -21
  61. package/src/extractions/types.ts +6 -1
  62. package/src/feedback/edit-state.ts +146 -16
  63. package/src/feedback/feedback.module.sass +93 -1
  64. package/src/feedback/graph.ts +71 -30
  65. package/src/feedback/index.ts +444 -71
  66. package/src/feedback/node.ts +7 -1
  67. package/src/feedback/text-visualizer.ts +258 -47
  68. package/src/feedback/type-selector/index.ts +4 -2
  69. package/dist/esm/edit-state.c39d8466.js.map +0 -1
  70. package/dist/esm/extractions.65bb73cc.js.map +0 -1
  71. package/dist/esm/feedback.5c86878e.js +0 -252
  72. package/dist/esm/feedback.5c86878e.js.map +0 -1
  73. package/dist/esm/feedback.module.55921afe.css +0 -44
  74. package/dist/esm/feedback.module.55921afe.css.map +0 -1
  75. package/dist/esm/feedback.module.765b1e58.js +0 -28
  76. package/dist/esm/feedback.module.765b1e58.js.map +0 -1
  77. package/dist/esm/graph.f4f65d79.js.map +0 -1
  78. package/dist/esm/node.28634e40.js.map +0 -1
  79. package/dist/esm/text-visualizer.198e27ff.js +0 -101
  80. package/dist/esm/text-visualizer.198e27ff.js.map +0 -1
  81. package/dist/esm/type-selector.6e8952d6.js.map +0 -1
  82. package/dist/node/edit-state.f50ca728.js +0 -2
  83. package/dist/node/edit-state.f50ca728.js.map +0 -1
  84. package/dist/node/extractions.e6ea2eb9.js +0 -2
  85. package/dist/node/extractions.e6ea2eb9.js.map +0 -1
  86. package/dist/node/feedback.8d3d1219.js +0 -2
  87. package/dist/node/feedback.8d3d1219.js.map +0 -1
  88. package/dist/node/feedback.module.a8744203.js +0 -2
  89. package/dist/node/feedback.module.a8744203.js.map +0 -1
  90. package/dist/node/feedback.module.c4eab97d.css +0 -2
  91. package/dist/node/feedback.module.c4eab97d.css.map +0 -1
  92. package/dist/node/graph.ca5b649f.js +0 -2
  93. package/dist/node/graph.ca5b649f.js.map +0 -1
  94. package/dist/node/main.module.1857be22.js +0 -2
  95. package/dist/node/main.module.1857be22.js.map +0 -1
  96. package/dist/node/main.module.1fdfe813.css.map +0 -1
  97. package/dist/node/main.module.6bc7d51b.css.map +0 -1
  98. package/dist/node/main.module.ebdf985b.js.map +0 -1
  99. package/dist/node/node.33108ccc.js +0 -2
  100. package/dist/node/node.33108ccc.js.map +0 -1
  101. package/dist/node/text-visualizer.1e770afa.js +0 -2
  102. package/dist/node/text-visualizer.1e770afa.js.map +0 -1
  103. package/dist/node/type-selector.0035ef7d.js +0 -2
  104. package/dist/node/type-selector.0035ef7d.js.map +0 -1
@@ -1,11 +1,11 @@
1
- import { AnnotateBlendTag, TextAnnotateBlend } from "react-text-annotate-blend";
1
+ import { AnnotateBlendTag } from "react-text-annotate-blend";
2
2
  import { InternalEntity } from "./types";
3
3
  import { TreeDispatch } from "./edit-state";
4
4
  import styles from "./feedback.module.sass";
5
5
  import hyper from "@macrostrat/hyper";
6
6
  import { buildHighlights, getTagStyle } from "../extractions";
7
7
  import { Highlight } from "../extractions/types";
8
- import { useCallback } from "react";
8
+ import { useEffect, useRef } from "react";
9
9
 
10
10
  const h = hyper.styled(styles);
11
11
 
@@ -15,14 +15,15 @@ export interface FeedbackTextProps {
15
15
  nodes: InternalEntity[];
16
16
  updateNodes: (nodes: string[]) => void;
17
17
  dispatch: TreeDispatch;
18
+ lineHeight: string;
19
+ allowOverlap?: boolean;
18
20
  }
19
21
 
20
22
  function buildTags(
21
23
  highlights: Highlight[],
22
- selectedNodes: number[]
24
+ selectedNodes: number[],
23
25
  ): AnnotateBlendTag[] {
24
26
  let tags: AnnotateBlendTag[] = [];
25
-
26
27
  // If entity ID has already been seen, don't add it again
27
28
  const entities = new Set<number>();
28
29
 
@@ -32,23 +33,24 @@ function buildTags(
32
33
 
33
34
  const highlighted = isHighlighted(highlight, selectedNodes);
34
35
  const active = isActive(highlight, selectedNodes);
36
+ const tagStyle = getTagStyle(highlight.backgroundColor, {
37
+ highlighted,
38
+ active,
39
+ });
35
40
 
36
- tags.push({
37
- markStyle: {
38
- ...getTagStyle(highlight.backgroundColor, {
39
- highlighted,
40
- active,
41
- }),
42
- borderRadius: "0.2em",
43
- padding: "0.1em",
44
- borderWidth: "1.5px",
45
- cursor: "pointer",
46
- },
41
+ const tag = {
42
+ color: tagStyle.color,
47
43
  tagStyle: {
48
44
  display: "none",
49
45
  },
46
+ markStyle: {
47
+ backgroundColor: tagStyle.backgroundColor,
48
+ },
50
49
  ...highlight,
51
- });
50
+ backgroundColor: tagStyle.backgroundColor,
51
+ };
52
+
53
+ tags.push(tag);
52
54
 
53
55
  entities.add(highlight.id);
54
56
  }
@@ -71,46 +73,255 @@ function isHighlighted(tag: Highlight, selectedNodes: number[]) {
71
73
 
72
74
  export function FeedbackText(props: FeedbackTextProps) {
73
75
  // Convert input to tags
74
- const { text, selectedNodes, nodes, dispatch } = props;
75
- let allTags: AnnotateBlendTag[] = buildTags(
76
+ const { text, selectedNodes, nodes, dispatch, lineHeight, allowOverlap } =
77
+ props;
78
+ const allTags: AnnotateBlendTag[] = buildTags(
76
79
  buildHighlights(nodes, null),
77
- selectedNodes
80
+ selectedNodes,
78
81
  );
79
82
 
80
- const onChange = useCallback(
81
- (tags) => {
82
- // New tags
83
- console.log(tags);
84
- const newTags = tags.filter((d) => !("id" in d));
85
- if (newTags.length > 0) {
86
- const { start, end } = newTags[0];
87
- const payload = { start, end, text: text.slice(start, end) };
88
- dispatch({ type: "create-node", payload });
89
- return;
90
- }
83
+ return h(
84
+ "div.feedback-text-wrapper",
85
+ {
86
+ tabIndex: 0,
87
+ onKeyDown: (e) => {
88
+ if (e.key === "Backspace") {
89
+ dispatch({
90
+ type: "delete-node",
91
+ payload: { ids: selectedNodes },
92
+ });
93
+ }
94
+ },
95
+ },
96
+ h(HighlightedText, {
97
+ text,
98
+ allTags,
99
+ lineHeight,
100
+ allowOverlap,
101
+ dispatch,
102
+ selectedNodes,
103
+ }),
104
+ );
105
+ }
106
+
107
+ function createTagFromSelection({
108
+ container,
109
+ }: {
110
+ container: HTMLElement | null;
111
+ }) {
112
+ const selection = window.getSelection();
113
+ if (
114
+ !selection ||
115
+ selection.isCollapsed ||
116
+ selection.rangeCount === 0 ||
117
+ !container
118
+ )
119
+ return null;
120
+
121
+ const range = selection.getRangeAt(0);
122
+
123
+ if (
124
+ !container.contains(range.startContainer) ||
125
+ !container.contains(range.endContainer)
126
+ ) {
127
+ return null;
128
+ }
129
+
130
+ const preRange = document.createRange();
131
+ preRange.setStart(container, 0);
132
+ preRange.setEnd(range.startContainer, range.startOffset);
133
+ const start = preRange.toString().length;
134
+
135
+ const selectedText = range.toString();
136
+ const end = start + selectedText.length;
137
+
138
+ return {
139
+ start,
140
+ end,
141
+ text: selectedText,
142
+ };
143
+ }
144
+
145
+ function addTag({ tag, dispatch, text, allTags, allowOverlap }) {
146
+ const { start, end } = tag;
147
+ let payload = { start, end, text: text.slice(start, end) };
148
+
149
+ if (payload.text.trim() === "") {
150
+ console.log("Blank tag found, ignoring");
151
+ return;
152
+ }
153
+
154
+ const duplicate = allTags.find(
155
+ (t) =>
156
+ t.start === payload.start &&
157
+ (t.end === payload.end || t.end === payload.end - 1),
158
+ );
159
+
160
+ if (duplicate) {
161
+ console.log("Duplicate tag found, ignoring");
162
+ return;
163
+ }
164
+
165
+ if (payload.text.endsWith(" ")) {
166
+ payload.text = payload.text.slice(0, -1);
167
+ payload.end -= 1;
168
+ }
169
+
170
+ const inside = allTags.some(
171
+ (t) => t.start <= payload.start && t.end >= payload.end,
172
+ );
173
+
174
+ const overlap = allTags.some(
175
+ (t) => t.start < payload.end && t.end > payload.start,
176
+ );
177
+
178
+ if ((inside || overlap) && !allowOverlap) {
179
+ console.log("Tag is inside another tag, ignoring");
180
+ return;
181
+ }
91
182
 
92
- const tagIDs = new Set(tags.map((d) => d.id));
93
- const removedIds = allTags.map((d) => d.id).filter((d) => !tagIDs.has(d));
183
+ dispatch({ type: "create-node", payload });
184
+ }
185
+
186
+ function nestHighlights(text: string, tags: AnnotateBlendTag[]) {
187
+ const events: Array<{
188
+ pos: number;
189
+ type: "start" | "end";
190
+ tag: AnnotateBlendTag;
191
+ }> = [];
192
+
193
+ for (const tag of tags) {
194
+ events.push({ pos: tag.start, type: "start", tag });
195
+ events.push({ pos: tag.end, type: "end", tag });
196
+ }
197
+
198
+ events.sort((a, b) => {
199
+ if (a.pos !== b.pos) return a.pos - b.pos;
200
+ if (a.type === "end" && b.type === "start") return -1;
201
+ if (a.type === "start" && b.type === "end") return 1;
202
+ return 0;
203
+ });
204
+
205
+ const root = { children: [], textStart: 0 };
206
+ const stack = [root];
207
+ let lastPos = 0;
208
+
209
+ for (const { pos, type, tag } of events) {
210
+ const parent = stack[stack.length - 1];
211
+
212
+ if (pos > lastPos) {
213
+ const slice = text.slice(lastPos, pos);
214
+ parent.children.push(slice);
215
+ }
216
+
217
+ if (type === "start") {
218
+ const newNode = { tag, children: [], textStart: pos };
219
+ parent.children.push(newNode);
220
+ stack.push(newNode);
221
+ } else {
222
+ stack.pop();
223
+ }
224
+
225
+ lastPos = pos;
226
+ }
227
+
228
+ if (lastPos < text.length) {
229
+ stack[stack.length - 1].children.push(text.slice(lastPos));
230
+ }
231
+
232
+ return root;
233
+ }
234
+
235
+ function renderNode(
236
+ node: any,
237
+ dispatch: TreeDispatch,
238
+ selectedNodes: number[],
239
+ parentSelected: boolean,
240
+ ): any {
241
+ if (typeof node === "string") return node;
242
+
243
+ const { tag, children } = node;
244
+ const isSelected = selectedNodes?.includes(tag.id);
94
245
 
95
- /* Find the id that was removed: that is the one that will be selected
96
- (we are hijacking the 'click to delete' functionality to select instead) */
97
- if (removedIds.length > 0) {
246
+ const style = {
247
+ ...tag,
248
+ zIndex: parentSelected ? -1 : 1,
249
+ };
250
+
251
+ let moveText = [];
252
+ if (isSelected) {
253
+ for (const key in children) {
254
+ if (Object.prototype.hasOwnProperty.call(children, key)) {
255
+ const child = children[key];
256
+ if (child?.tag) {
257
+ moveText.push(child.children[0]);
258
+ } else {
259
+ moveText.push(child);
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ return h(
266
+ "span",
267
+ {
268
+ className: "highlight",
269
+ style,
270
+ onClick: (e: MouseEvent) => {
271
+ e.stopPropagation();
98
272
  dispatch({
99
273
  type: "toggle-node-selected",
100
- payload: { ids: removedIds },
274
+ payload: { ids: [tag.id] },
101
275
  });
102
- }
276
+ },
103
277
  },
104
- [allTags, text]
278
+ isSelected
279
+ ? moveText.flat()
280
+ : children.map((child: any, i: number) =>
281
+ renderNode(child, dispatch, selectedNodes, isSelected),
282
+ ),
105
283
  );
284
+ }
106
285
 
107
- return h(TextAnnotateBlend, {
108
- style: {
109
- fontSize: "1.2em",
110
- },
111
- className: "feedback-text",
112
- content: text,
113
- onChange,
114
- value: allTags,
115
- });
286
+ export function HighlightedText(props: {
287
+ text: string;
288
+ allTags: AnnotateBlendTag[];
289
+ lineHeight: string;
290
+ allowOverlap?: boolean;
291
+ dispatch: TreeDispatch;
292
+ selectedNodes: number[];
293
+ }) {
294
+ const {
295
+ text,
296
+ allTags = [],
297
+ lineHeight,
298
+ dispatch,
299
+ selectedNodes,
300
+ allowOverlap,
301
+ } = props;
302
+
303
+ const tree = nestHighlights(text, allTags);
304
+
305
+ const spanRef = useRef<HTMLSpanElement>(null);
306
+
307
+ useEffect(() => {
308
+ const handleMouseUp = () => {
309
+ const tag = createTagFromSelection({ container: spanRef.current });
310
+ if (!tag) return;
311
+ addTag({ tag, dispatch, text, allTags, allowOverlap });
312
+ };
313
+
314
+ document.addEventListener("mouseup", handleMouseUp);
315
+ return () => {
316
+ document.removeEventListener("mouseup", handleMouseUp);
317
+ };
318
+ }, [text, allTags, dispatch, allowOverlap]);
319
+
320
+ return h(
321
+ "span",
322
+ { style: { lineHeight }, ref: spanRef },
323
+ tree.children.map((child: any, i: number) =>
324
+ renderNode(child, dispatch, selectedNodes, false),
325
+ ),
326
+ );
116
327
  }
@@ -39,7 +39,7 @@ const TagListItem: React.ComponentType<TagItemProps<T>> = (props) => {
39
39
  [
40
40
  h("div.swatch", { style: { backgroundColor: item.color } }),
41
41
  h("div.item", {}, item.name),
42
- ]
42
+ ],
43
43
  );
44
44
  };
45
45
 
@@ -49,16 +49,18 @@ interface OmniboxProps<T> extends BoxLifecycleProps<T> {
49
49
  items: T[];
50
50
  selectedItem: T;
51
51
  onSelectItem: (t: T) => void;
52
+ onQueryChange: (query: string) => void;
52
53
  listItemComponent?: React.ComponentType<TagItemProps<T>>;
53
54
  }
54
55
 
55
56
  export function OmniboxSelector<T>(props: OmniboxProps<T>) {
56
57
  /** A general omnibox for annotation types */
57
- const { onSelectItem, items, isOpen, onClose } = props;
58
+ const { onSelectItem, items, isOpen, onClose, onQueryChange } = props;
58
59
 
59
60
  return h(Omnibar, {
60
61
  onItemSelect: onSelectItem,
61
62
  items,
63
+ onQueryChange,
62
64
  resetOnSelect: false,
63
65
  isOpen,
64
66
  onClose,
@@ -1 +0,0 @@
1
- {"mappings":"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","sources":["packages/feedback-components/src/feedback/edit-state.ts"],"sourcesContent":["import { TreeData } from \"./types\";\nimport { createContext, Dispatch, useContext, useReducer } from \"react\";\nimport update, { Spec } from \"immutability-helper\";\nimport { EntityType } from \"../extractions/types\";\n\nexport enum ViewMode {\n Tree = \"tree\",\n Graph = \"graph\",\n}\n\ninterface TreeState {\n initialTree: TreeData[];\n tree: TreeData[];\n selectedNodes: number[];\n entityTypesMap: Map<number, EntityType>;\n selectedEntityType: EntityType;\n lastInternalId: number;\n isSelectingEntityType: boolean;\n viewMode: ViewMode;\n}\n\ntype TextRange = {\n start: number;\n end: number;\n text: string;\n};\n\ntype TreeAction =\n | {\n type: \"move-node\";\n payload: { dragIds: number[]; parentId: number; index: number };\n }\n | { type: \"delete-node\"; payload: { ids: number[] } }\n | { type: \"select-node\"; payload: { ids: number[] } }\n | { type: \"toggle-node-selected\"; payload: { ids: number[] } }\n | { type: \"set-view-mode\"; payload: ViewMode }\n | { type: \"create-node\"; payload: TextRange }\n | { type: \"select-entity-type\"; payload: EntityType }\n | { type: \"toggle-entity-type-selector\"; payload?: boolean | null }\n | { type: \"deselect\" }\n | { type: \"reset\" };\n\nexport type TreeDispatch = Dispatch<TreeAction>;\n\nexport function useUpdatableTree(\n initialTree: TreeData[],\n entityTypes: Map<number, EntityType>\n): [TreeState, TreeDispatch] {\n // Get the first entity type\n const type = entityTypes.values().next().value;\n\n return useReducer(treeReducer, {\n initialTree,\n tree: initialTree,\n selectedNodes: [],\n entityTypesMap: entityTypes,\n selectedEntityType: type,\n lastInternalId: 0,\n isSelectingEntityType: false,\n viewMode: ViewMode.Tree,\n });\n}\n\nexport const TreeDispatchContext = createContext<TreeDispatch | null>(null);\n\nexport function useTreeDispatch() {\n const dispatch = useContext(TreeDispatchContext);\n if (dispatch == null) {\n throw new Error(\"No dispatch context available\");\n }\n return dispatch;\n}\n\nfunction treeReducer(state: TreeState, action: TreeAction) {\n console.log(action);\n switch (action.type) {\n case \"move-node\":\n // For each node in the tree, if the node is in the dragIds, remove it from the tree and collect it\n const [newTree, removedNodes] = removeNodes(\n state.tree,\n action.payload.dragIds\n );\n\n let keyPath: (number | \"children\")[] = [];\n if (action.payload.parentId) {\n keyPath = findNode(newTree, action.payload.parentId);\n keyPath.push(\"children\");\n }\n\n // Add removed nodes to the new tree at the correct location\n let updateSpec = buildNestedSpec(keyPath, {\n $splice: [[action.payload.index, 0, ...removedNodes]],\n });\n\n return { ...state, tree: update(newTree, updateSpec) };\n case \"delete-node\":\n // For each node in the tree, if the node is in the ids, remove it from the tree\n const [newTree2, _removedNodes] = removeNodes(\n state.tree,\n action.payload.ids\n );\n // Get children of the removed nodes\n // If children are not present elsewhere in the tree, insert them\n\n const children = _removedNodes\n .flatMap((node) => node.children ?? [])\n .filter((child) => !nodeIsInTree(newTree2, child.id));\n\n // Reset the selection\n\n return {\n ...state,\n tree: [...newTree2, ...children],\n selectedNodes: state.selectedNodes.filter(\n (id) => !action.payload.ids.includes(id)\n ),\n };\n case \"select-node\":\n const { ids } = action.payload;\n return { ...state, selectedNodes: ids };\n // otherwise fall through to toggle-node-selected for a single ID\n case \"toggle-node-selected\":\n const nodesToAdd = action.payload.ids.filter(\n (id) => !state.selectedNodes.includes(id)\n );\n const nodesToKeep = state.selectedNodes.filter(\n (id) => !action.payload.ids.includes(id)\n );\n return { ...state, selectedNodes: [...nodesToKeep, ...nodesToAdd] };\n\n case \"create-node\":\n const newId = state.lastInternalId - 1;\n const { text, start, end } = action.payload;\n const node: TreeData = {\n id: newId,\n name: text,\n children: [],\n indices: [start, end],\n type: state.selectedEntityType,\n };\n\n return {\n ...state,\n tree: [...state.tree, node],\n selectedNodes: [newId],\n lastInternalId: newId,\n };\n\n /** Entity type selection */\n case \"toggle-entity-type-selector\":\n return {\n ...state,\n isSelectingEntityType: action.payload ?? !state.isSelectingEntityType,\n };\n case \"select-entity-type\": {\n // For each selected node, update the type\n let newTree2 = state.tree;\n for (let id of state.selectedNodes) {\n const keyPath = findNode(state.tree, id);\n const nestedSpec = buildNestedSpec(keyPath, {\n type: { $set: action.payload },\n });\n newTree2 = update(newTree2, nestedSpec);\n }\n\n return {\n ...state,\n tree: newTree2,\n selectedEntityType: action.payload,\n };\n }\n case \"deselect\":\n return { ...state, selectedNodes: [] };\n case \"reset\":\n return {\n ...state,\n tree: state.initialTree,\n selectedNodes: [],\n };\n case \"set-view-mode\":\n return { ...state, viewMode: action.payload };\n }\n}\n\nfunction nodeIsInTree(tree: TreeData[], id: number): boolean {\n for (let node of tree) {\n if (node.id == id) {\n return true;\n } else if (node.children) {\n if (nodeIsInTree(node.children, id)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction buildNestedSpec(\n keyPath: (number | \"children\")[],\n innerSpec: Spec<any>\n): Spec<TreeData[]> {\n // Build a nested object from a key path\n\n let spec = innerSpec;\n for (let i = keyPath.length - 1; i >= 0; i--) {\n spec = { [keyPath[i]]: spec };\n }\n return spec as any;\n // Since we don't have a \"children\" key at the root, we make the top-level spec an array\n}\n\nfunction findNode(\n tree: TreeData[],\n id: number\n): (number | \"children\")[] | null {\n // Find the index of the node with the given id in the tree, returning the key path\n for (let i = 0; i < tree.length; i++) {\n if (tree[i].id == id) {\n return [i];\n } else if (tree[i].children) {\n let path = findNode(tree[i].children, id);\n if (path != null) {\n return [i, \"children\", ...path];\n }\n }\n }\n return null;\n}\n\nfunction removeNodes(\n tree: TreeData[],\n ids: number[]\n): [TreeData[], TreeData[]] {\n /** Remove nodes with the given ids from the tree and return the new tree and the removed nodes */\n let newTree: TreeData[] = [];\n let removedNodes: TreeData[] = [];\n\n for (let node of tree) {\n if (ids.includes(node.id)) {\n removedNodes.push(node);\n } else {\n // Recurse into children\n if (node.children) {\n let [newChildren, removedChildren] = removeNodes(node.children, ids);\n node = { ...node, children: newChildren };\n removedNodes.push(...removedChildren);\n }\n newTree.push(node);\n }\n }\n\n return [newTree, removedNodes];\n}\n\nexport interface EntityOutput {\n id: number;\n type: number | null;\n txt_range: number[][];\n name: string;\n match: any | null;\n reasoning: string | null;\n}\n\nexport interface GraphData {\n nodes: EntityOutput[];\n edges: { source: number; dest: number }[];\n}\n\nexport function treeToGraph(tree: TreeData[]): GraphData {\n // Convert the tree to a graph\n let nodes: EntityOutput[] = [];\n let edges: { source: number; dest: number }[] = [];\n const nodeMap = new Map<number, TreeData>();\n\n for (let node of tree) {\n // If we've already found an instance of this node, we don't need to record\n // it again\n if (nodeMap.has(node.id)) {\n continue;\n }\n\n const { indices, id, name } = node;\n\n const nodeData: EntityOutput = {\n id,\n type: node.type.id,\n name,\n txt_range: [indices],\n reasoning: null,\n match: node.match,\n };\n\n nodeMap.set(node.id, node);\n nodes.push(nodeData);\n\n if (node.children) {\n for (let child of node.children) {\n edges.push({ source: node.id, dest: child.id });\n }\n\n // Now process the children\n const { nodes: childNodes, edges: childEdges } = treeToGraph(\n node.children\n );\n nodes.push(...childNodes);\n edges.push(...childEdges);\n }\n }\n\n return { nodes, edges };\n}\n"],"names":[],"version":3,"file":"edit-state.c39d8466.js.map"}
@@ -1 +0,0 @@
1
- {"mappings":";;;;;;;;;;;;;;;;AAUA,MAAM,0BAAI,CAAA,GAAA,sBAAI,EAAE,MAAM,CAAC,CAAA,GAAA,sEAAK;AAErB,SAAS,0CACd,QAAqB,EACrB,MAAwB;IAExB,IAAI,aAAa,EAAE;IACnB,IAAI,UAAU,EAAE;IAChB,IAAI,UAAU,MACZ,UAAU;QAAC,OAAO,EAAE;WAAM,OAAO,OAAO,IAAI,EAAE;KAAE;IAGlD,KAAK,MAAM,UAAU,SAAU;QAC7B,WAAW,IAAI,CAAC;YACd,OAAO,OAAO,OAAO,CAAC,EAAE;YACxB,KAAK,OAAO,OAAO,CAAC,EAAE;YACtB,MAAM,OAAO,IAAI;YACjB,iBAAiB,OAAO,IAAI,CAAC,KAAK,IAAI;YACtC,KAAK,OAAO,IAAI,CAAC,IAAI;YACrB,IAAI,OAAO,EAAE;qBACb;QACF;QACA,WAAW,IAAI,IAAI,0CAAgB,OAAO,QAAQ,IAAI,EAAE,EAAE;IAC5D;IACA,OAAO;AACT;AAEO,SAAS,yCAAY,cAAc,EAAE,MAAM,EAAE,WAAW;IAC7D,OAAO;QACL,GAAG,cAAc;QACjB,OAAO,OAAO,GAAG,CAAC,eAAe,QAAQ;QACzC,UAAU,eAAe,QAAQ,EAAE,IAAI,CAAC,IACtC,oCAAc,GAAG;IAErB;AACF;AAEO,SAAS,0CACd,SAAiB,EACjB,OAA0E;IAE1E,MAAM,aAAa,CAAA,GAAA,oBAAY,EAAE,aAAa;IAC9C,MAAM,eAAE,cAAc,kBAAM,aAAa,eAAO,SAAS,OAAO,GAAG;IAEnE,IAAI,YAAY,cAAc,MAAM;IACpC,IAAI,kBAAkB,cAAc,MAAM;IAE1C,IAAI,QAAQ;QACV,YAAY;QACZ,kBAAkB;IACpB;IAEA,MAAM,YAAY,aAAa,UAAU;IAEzC,MAAM,QAAQ,WAAW,GAAG,CAAC,WAAW,WAAW,GAAG;IACtD,MAAM,cAAc,cAChB,WAAW,GAAG,CAAC,WAAW,YAAY,GAAG,GAAG,KAC5C;IAEJ,OAAO;eACL;QACA,iBAAiB,WAAW,KAAK,CAAC,iBAAiB,GAAG;QACtD,WAAW;QACX,aAAa;qBACb;QACA,aAAa;QACb,YAAY,SAAS,SAAS;IAChC;AACF;AAEA,SAAS,oCACP,MAAc,EACd,WAAoC;IAEpC,OAAO;QACL,GAAG,MAAM;QACT,MAAM,+BAAS,YAAY,GAAG,CAAC,OAAO,IAAI,GAAG,OAAO,KAAK,IAAI;QAC7D,UAAU,OAAO,QAAQ,EAAE,IAAI,CAAC,IAAM,oCAAc,GAAG;IACzD;AACF;AAEA,SAAS,+BAAS,UAAsB,EAAE,QAAQ,KAAK;IACrD,MAAM,QAAQ,CAAA,GAAA,oBAAY,EAAE,WAAW,KAAK,IAAI,QAAQ,QAAQ,CAC9D,QAAQ,IAAI;IAGd,OAAO;QAAE,GAAG,UAAU;QAAE,OAAO,MAAM,GAAG;IAAG;AAC7C;AAEO,SAAS,0CAAkB,QAChC,IAAI,eACJ,WAAW,kBACX,cAAc,EAKf;IACC,MAAM,aAAa,0CAAgB,KAAK,QAAQ,EAAE;IAElD,OAAO,wBAAE,OAAO;QACd,wBAAE,KAAK,wBAAE,uCAAiB;YAAE,MAAM,KAAK,cAAc;wBAAE;QAAW;QAClE,wBAAE,2CAAW;YAAE,MAAM,KAAK,KAAK;QAAC;QAChC,wBACE,eACA,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAM,wBAAE,sCAAgB;gBAAE,MAAM;gCAAG;YAAe;KAExE;AACH;AAEO,SAAS,0CAAU,QAAE,IAAI,EAAE;IAChC,OAAO,wBAAE,gBAAgB;QAAC;QAAW,wBAAE,iBAAiB,KAAK,IAAI;KAAE;AACrE;AAYO,SAAS,0CAAU,QACxB,IAAI,eACJ,cAAc,cACd,SAAS,oBACT,WAAW,kBACX,iBAAiB,MACF;IACf,MAAM,QAAE,IAAI,QAAE,IAAI,SAAE,KAAK,EAAE,GAAG;IAC9B,MAAM,YAAY,CAAA,GAAA,iBAAS,EACzB;QACE,SAAS,SAAS;QAClB,MAAM,KAAK,IAAI,CAAC,IAAI;IACtB,GACA;IAGF,MAAM,QAAQ,0CAAY,KAAK,KAAK,IAAI,WAAW;qBAAE;gBAAa;IAAO;IAEzE,IAAI,aAAa;IACjB,IAAI,SAAS,QAAQ,kBAAkB,MACrC,aAAa,wBAAE,gBAAgB;QAAE,MAAM;IAAM;IAG/C,OAAO,wBAAE,CAAA,GAAA,UAAE,GAAG;eAAE;mBAAO;IAAU,GAAG;QAClC,wBAAE,oBAAoB;QACtB;QACA,wBACE,6BACA;YACE,SAAQ,GAAG;gBACT,IAAI,UAAU,eAAe,MAAM;oBACjC,YAAY;oBACZ,IAAI,eAAe;gBACrB;YACF;QACF,GACA;YAAC,KAAK,IAAI;YAAE;SAAW;KAE1B;AACH;AAEA,SAAS,qCAAe,QACtB,IAAI,kBACJ,iBAAiB,MAIlB;IACC,MAAM,WAAW,KAAK,QAAQ,IAAI,EAAE;IAEpC,OAAO,wBAAE,iBAAiB;QACxB,wBAAE,2CAAW;kBAAE;4BAAM;QAAe;QACpC,wBAAE,EAAE,CAAC,SAAS,MAAM,GAAG,GAAG;YACxB,wBACE,eACA,SAAS,GAAG,CAAC,CAAC,IAAM,wBAAE,sCAAgB;oBAAE,MAAM;oCAAG;gBAAe;SAEnE;KACF;AACH;AAEA,SAAS,sCAAgB,KAAgD;IACvE,MAAM,QAAE,IAAI,cAAE,aAAa,EAAE,EAAE,GAAG;IAClC,MAAM,QAAQ,EAAE;IAChB,IAAI,QAAQ;IAEZ,MAAM,mBAAmB,WAAW,IAAI,CAAC,CAAC,GAAG,IAAM,EAAE,KAAK,GAAG,EAAE,KAAK;IACpE,MAAM,yBAAyB,iBAAiB,GAAG,CAAC,CAAC,WAAW;QAC9D,IAAI,MAAM,GAAG,OAAO;QACpB,MAAM,OAAO,gBAAgB,CAAC,IAAI,EAAE;QACpC,IAAI,UAAU,KAAK,GAAG,KAAK,GAAG,EAC5B,UAAU,KAAK,GAAG,KAAK,GAAG;QAE5B,OAAO;IACT;IAEA,KAAK,MAAM,aAAa,uBAAwB;QAC9C,MAAM,EAAE,OAAO,CAAC,OAAE,GAAG,EAAE,GAAG,MAAM,GAAG;QACnC,MAAM,IAAI,CAAC,KAAK,KAAK,CAAC,OAAO;QAC7B,MAAM,IAAI,CAAC,wBAAE,kBAAkB;YAAE,OAAO;QAAK,GAAG,KAAK,KAAK,CAAC,GAAG;QAC9D,QAAQ;IACV;IACA,MAAM,IAAI,CAAC,KAAK,KAAK,CAAC;IACtB,OAAO,wBAAE,QAAQ;AACnB","sources":["packages/feedback-components/src/extractions/index.ts"],"sourcesContent":["import styles from \"./main.module.sass\";\nimport classNames from \"classnames\";\nimport { Tag } from \"@blueprintjs/core\";\nimport type { Entity, EntityExt, Highlight, EntityType } from \"./types\";\nimport { CSSProperties } from \"react\";\nimport { asChromaColor } from \"@macrostrat/color-utils\";\nimport hyper from \"@macrostrat/hyper\";\n\nexport type { Entity, EntityExt };\n\nconst h = hyper.styled(styles);\n\nexport function buildHighlights(\n entities: EntityExt[],\n parent: EntityExt | null\n): Highlight[] {\n let highlights = [];\n let parents = [];\n if (parent != null) {\n parents = [parent.id, ...(parent.parents ?? [])];\n }\n\n for (const entity of entities) {\n highlights.push({\n start: entity.indices[0],\n end: entity.indices[1],\n text: entity.name,\n backgroundColor: entity.type.color ?? \"#ddd\",\n tag: entity.type.name,\n id: entity.id,\n parents,\n });\n highlights.push(...buildHighlights(entity.children ?? [], entity));\n }\n return highlights;\n}\n\nexport function enhanceData(extractionData, models, entityTypes) {\n return {\n ...extractionData,\n model: models.get(extractionData.model_id),\n entities: extractionData.entities?.map((d) =>\n enhanceEntity(d, entityTypes)\n ),\n };\n}\n\nexport function getTagStyle(\n baseColor: string,\n options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean }\n): CSSProperties {\n const _baseColor = asChromaColor(baseColor ?? \"#ddd\");\n const { highlighted = true, inDarkMode = false, active = false } = options;\n\n let mixAmount = highlighted ? 0.8 : 0.5;\n let backgroundAlpha = highlighted ? 0.8 : 0.2;\n\n if (active) {\n mixAmount = 1;\n backgroundAlpha = 1;\n }\n\n const mixTarget = inDarkMode ? \"white\" : \"black\";\n\n const color = _baseColor.mix(mixTarget, mixAmount).css();\n const borderColor = highlighted\n ? _baseColor.mix(mixTarget, mixAmount / 2).css()\n : \"transparent\";\n\n return {\n color,\n backgroundColor: _baseColor.alpha(backgroundAlpha).css(),\n boxSizing: \"border-box\",\n borderStyle: \"solid\",\n borderColor,\n borderWidth: \"1px\",\n fontWeight: active ? \"bold\" : \"normal\",\n };\n}\n\nfunction enhanceEntity(\n entity: Entity,\n entityTypes: Map<number, EntityType>\n): EntityExt {\n return {\n ...entity,\n type: addColor(entityTypes.get(entity.type), entity.match != null),\n children: entity.children?.map((d) => enhanceEntity(d, entityTypes)),\n };\n}\n\nfunction addColor(entityType: EntityType, match = false) {\n const color = asChromaColor(entityType.color ?? \"#ddd\").brighten(\n match ? 1 : 2\n );\n\n return { ...entityType, color: color.css() };\n}\n\nexport function ExtractionContext({\n data,\n entityTypes,\n matchComponent,\n}: {\n data: any;\n entityTypes: Map<number, EntityType>;\n matchComponent: MatchComponent;\n}) {\n const highlights = buildHighlights(data.entities, null);\n\n return h(\"div\", [\n h(\"p\", h(HighlightedText, { text: data.paragraph_text, highlights })),\n h(ModelInfo, { data: data.model }),\n h(\n \"ul.entities\",\n data.entities.map((d) => h(ExtractionInfo, { data: d, matchComponent }))\n ),\n ]);\n}\n\nexport function ModelInfo({ data }) {\n return h(\"p.model-name\", [\"Model: \", h(\"code.bp5-code\", data.name)]);\n}\n\nexport type MatchComponent = (props: { data: any }) => any;\n\ntype EntityTagProps = {\n data: EntityExt;\n highlighted?: boolean;\n active?: boolean;\n onClickType?: (type: EntityType) => void;\n matchComponent?: MatchComponent;\n};\n\nexport function EntityTag({\n data,\n highlighted = true,\n active = false,\n onClickType,\n matchComponent = null,\n}: EntityTagProps) {\n const { name, type, match } = data;\n const className = classNames(\n {\n matched: match != null,\n type: data.type.name,\n },\n \"entity\"\n );\n\n const style = getTagStyle(type.color ?? \"#aaaaaa\", { highlighted, active });\n\n let _matchLink = null;\n if (match != null && matchComponent != null) {\n _matchLink = h(matchComponent, { data: match });\n }\n\n return h(Tag, { style, className }, [\n h(\"span.entity-name\", name),\n \" \",\n h(\n \"code.entity-type.bp5-code\",\n {\n onClick(evt) {\n if (active && onClickType != null) {\n onClickType(type);\n evt.stopPropagation();\n }\n },\n },\n [type.name, _matchLink]\n ),\n ]);\n}\n\nfunction ExtractionInfo({\n data,\n matchComponent = null,\n}: {\n data: EntityExt;\n matchComponent: MatchComponent;\n}) {\n const children = data.children ?? [];\n\n return h(\"li.entity-row\", [\n h(EntityTag, { data, matchComponent }),\n h.if(children.length > 0)([\n h(\n \"ul.children\",\n children.map((d) => h(ExtractionInfo, { data: d, matchComponent }))\n ),\n ]),\n ]);\n}\n\nfunction HighlightedText(props: { text: string; highlights: Highlight[] }) {\n const { text, highlights = [] } = props;\n const parts = [];\n let start = 0;\n\n const sortedHighlights = highlights.sort((a, b) => a.start - b.start);\n const deconflictedHighlights = sortedHighlights.map((highlight, i) => {\n if (i === 0) return highlight;\n const prev = sortedHighlights[i - 1];\n if (highlight.start < prev.end) {\n highlight.start = prev.end;\n }\n return highlight;\n });\n\n for (const highlight of deconflictedHighlights) {\n const { start: s, end, ...rest } = highlight;\n parts.push(text.slice(start, s));\n parts.push(h(\"span.highlight\", { style: rest }, text.slice(s, end)));\n start = end;\n }\n parts.push(text.slice(start));\n return h(\"span\", parts);\n}\n"],"names":[],"version":3,"file":"extractions.65bb73cc.js.map"}
@@ -1,252 +0,0 @@
1
- import "./feedback.module.55921afe.css";
2
- import $bvJLP$feedbackmodule765b1e58js from "./feedback.module.765b1e58.js";
3
- import $b6b9741bf83336eb$export$2e2bcd8739ae039 from "./node.28634e40.js";
4
- import {FeedbackText as $156a3efbc315814c$export$6e107db9091b8219} from "./text-visualizer.198e27ff.js";
5
- import {ModelInfo as $03d8811e9c9b360d$export$4eb2a0ce903ce967} from "./extractions.65bb73cc.js";
6
- import {useUpdatableTree as $b79bf29960412ca7$export$911bb4b9c8065d3d, TreeDispatchContext as $b79bf29960412ca7$export$e5ce04c5b3f58533, treeToGraph as $b79bf29960412ca7$export$8d9dbb7a64bf2a5e} from "./edit-state.c39d8466.js";
7
- import {OmniboxSelector as $fda9ef5406c1cfb4$export$d8660660a589068c} from "./type-selector.6e8952d6.js";
8
- import {GraphView as $ff8c3e7f2bc22925$export$6a7fe3ef90e8d566} from "./graph.f4f65d79.js";
9
- import $bvJLP$macrostrathyper from "@macrostrat/hyper";
10
- import {Tree as $bvJLP$Tree} from "react-arborist";
11
- import {useRef as $bvJLP$useRef, useCallback as $bvJLP$useCallback, useEffect as $bvJLP$useEffect} from "react";
12
- import {SegmentedControl as $bvJLP$SegmentedControl, Card as $bvJLP$Card, ButtonGroup as $bvJLP$ButtonGroup} from "@blueprintjs/core";
13
- import {FlexRow as $bvJLP$FlexRow, CancelButton as $bvJLP$CancelButton, SaveButton as $bvJLP$SaveButton, DataField as $bvJLP$DataField} from "@macrostrat/ui-components";
14
- import $bvJLP$useelementdimensions from "use-element-dimensions";
15
-
16
-
17
- function $parcel$interopDefault(a) {
18
- return a && a.__esModule ? a.default : a;
19
- }
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
- const $71d20dff35996763$var$h = (0, $bvJLP$macrostrathyper).styled((0, ($parcel$interopDefault($bvJLP$feedbackmodule765b1e58js))));
34
- function $71d20dff35996763$var$setsAreTheSame(a, b) {
35
- if (a.size !== b.size) return false;
36
- for (const item of a){
37
- if (!b.has(item)) return false;
38
- }
39
- return true;
40
- }
41
- function $71d20dff35996763$export$a90600c9da52b40c({ entities: entities = [], text: text, model: model, entityTypes: entityTypes, matchComponent: matchComponent, onSave: onSave }) {
42
- // Get the input arguments
43
- const [state, dispatch] = (0, $b79bf29960412ca7$export$911bb4b9c8065d3d)(entities.map($71d20dff35996763$var$processEntity), entityTypes);
44
- const { selectedNodes: selectedNodes, tree: tree, selectedEntityType: selectedEntityType, isSelectingEntityType: isSelectingEntityType } = state;
45
- const [{ width: width, height: height }, ref] = (0, $bvJLP$useelementdimensions)();
46
- return $71d20dff35996763$var$h((0, $b79bf29960412ca7$export$e5ce04c5b3f58533).Provider, {
47
- value: dispatch
48
- }, [
49
- $71d20dff35996763$var$h((0, $156a3efbc315814c$export$6e107db9091b8219), {
50
- text: text,
51
- dispatch: dispatch,
52
- // @ts-ignore
53
- nodes: tree,
54
- selectedNodes: selectedNodes
55
- }),
56
- $71d20dff35996763$var$h((0, $bvJLP$FlexRow), {
57
- alignItems: "baseline",
58
- justifyContent: "space-between"
59
- }, [
60
- $71d20dff35996763$var$h((0, $03d8811e9c9b360d$export$4eb2a0ce903ce967), {
61
- data: model
62
- }),
63
- $71d20dff35996763$var$h((0, $bvJLP$SegmentedControl), {
64
- options: [
65
- {
66
- label: "Tree",
67
- value: "tree"
68
- },
69
- {
70
- label: "Graph",
71
- value: "graph"
72
- }
73
- ],
74
- value: state.viewMode,
75
- small: true,
76
- onValueChange (value) {
77
- console.log("Setting view mode", value);
78
- dispatch({
79
- type: "set-view-mode",
80
- payload: value
81
- });
82
- }
83
- })
84
- ]),
85
- $71d20dff35996763$var$h("div.entity-panel", {
86
- ref: ref
87
- }, [
88
- $71d20dff35996763$var$h((0, $bvJLP$Card), {
89
- className: "control-panel"
90
- }, [
91
- $71d20dff35996763$var$h((0, $bvJLP$ButtonGroup), {
92
- vertical: true,
93
- fill: true,
94
- minimal: true,
95
- alignText: "left"
96
- }, [
97
- $71d20dff35996763$var$h((0, $bvJLP$CancelButton), {
98
- icon: "trash",
99
- disabled: state.initialTree == state.tree,
100
- onClick () {
101
- dispatch({
102
- type: "reset"
103
- });
104
- }
105
- }, "Reset"),
106
- $71d20dff35996763$var$h((0, $bvJLP$SaveButton), {
107
- onClick () {
108
- onSave(state.tree);
109
- },
110
- disabled: state.initialTree == state.tree
111
- }, "Save")
112
- ]),
113
- $71d20dff35996763$var$h($71d20dff35996763$var$EntityTypeSelector, {
114
- entityTypes: entityTypes,
115
- selected: selectedEntityType,
116
- onChange (payload) {
117
- dispatch({
118
- type: "select-entity-type",
119
- payload: payload
120
- });
121
- },
122
- isOpen: isSelectingEntityType,
123
- setOpen: (isOpen)=>dispatch({
124
- type: "toggle-entity-type-selector",
125
- payload: isOpen
126
- })
127
- })
128
- ]),
129
- $71d20dff35996763$var$h.if(state.viewMode == "tree")($71d20dff35996763$var$ManagedSelectionTree, {
130
- selectedNodes: selectedNodes,
131
- dispatch: dispatch,
132
- tree: tree,
133
- width: width,
134
- height: height,
135
- matchComponent: matchComponent
136
- }),
137
- $71d20dff35996763$var$h.if(state.viewMode == "graph")((0, $ff8c3e7f2bc22925$export$6a7fe3ef90e8d566), {
138
- tree: tree,
139
- width: width,
140
- height: height
141
- })
142
- ])
143
- ]);
144
- }
145
- function $71d20dff35996763$var$processEntity(entity) {
146
- // @ts-ignore
147
- return {
148
- ...entity,
149
- // @ts-ignore
150
- term_type: entity.type.name,
151
- txt_range: [
152
- entity.indices
153
- ],
154
- children: entity.children?.map($71d20dff35996763$var$processEntity) ?? []
155
- };
156
- }
157
- function $71d20dff35996763$var$EntityTypeSelector({ entityTypes: entityTypes, selected: selected, isOpen: isOpen, setOpen: setOpen, onChange: onChange }) {
158
- // Show all entity types when selected is null
159
- const _selected = selected != null ? selected : undefined;
160
- return $71d20dff35996763$var$h((0, $bvJLP$DataField), {
161
- label: "Entity type",
162
- inline: true
163
- }, [
164
- $71d20dff35996763$var$h("code.bp5-code", {
165
- onClick () {
166
- setOpen((d)=>!d);
167
- }
168
- }, selected.name),
169
- $71d20dff35996763$var$h((0, $fda9ef5406c1cfb4$export$d8660660a589068c), {
170
- isOpen: isOpen,
171
- items: Array.from(entityTypes.values()),
172
- selectedItem: _selected,
173
- onSelectItem (item) {
174
- setOpen(false);
175
- onChange(item);
176
- },
177
- onClose () {
178
- setOpen(false);
179
- }
180
- })
181
- ]);
182
- }
183
- function $71d20dff35996763$var$ManagedSelectionTree(props) {
184
- const { selectedNodes: selectedNodes, dispatch: dispatch, tree: tree, height: height, width: width, matchComponent: matchComponent, ...rest } = props;
185
- const ref = (0, $bvJLP$useRef)();
186
- const _Node = (0, $bvJLP$useCallback)((props)=>$71d20dff35996763$var$h((0, $b6b9741bf83336eb$export$2e2bcd8739ae039), {
187
- ...props,
188
- matchComponent: matchComponent
189
- }), [
190
- matchComponent
191
- ]);
192
- (0, $bvJLP$useEffect)(()=>{
193
- if (ref.current == null) return;
194
- // Check if selection matches current
195
- const selection = new Set(selectedNodes.map((d)=>d.toString()));
196
- const currentSelection = ref.current.selectedIds;
197
- if ($71d20dff35996763$var$setsAreTheSame(selection, currentSelection)) return;
198
- // If the selection is the same, do nothing
199
- // Set selection
200
- ref.current.setSelection({
201
- ids: selectedNodes.map((d)=>d.toString()),
202
- anchor: null,
203
- mostRecent: null
204
- });
205
- }, [
206
- selectedNodes
207
- ]);
208
- return $71d20dff35996763$var$h((0, $bvJLP$Tree), {
209
- className: "selection-tree",
210
- height: height,
211
- width: width,
212
- ref: ref,
213
- data: tree,
214
- onMove ({ dragIds: dragIds, parentId: parentId, index: index }) {
215
- dispatch({
216
- type: "move-node",
217
- payload: {
218
- dragIds: dragIds.map((d)=>parseInt(d)),
219
- parentId: parentId ? parseInt(parentId) : null,
220
- index: index
221
- }
222
- });
223
- },
224
- onDelete ({ ids: ids }) {
225
- dispatch({
226
- type: "delete-node",
227
- payload: {
228
- ids: ids.map((d)=>parseInt(d))
229
- }
230
- });
231
- },
232
- onSelect (nodes) {
233
- let ids = nodes.map((d)=>parseInt(d.id));
234
- if (ids.length == 1 && ids[0] == selectedNodes[0]) // Deselect
235
- ids = [];
236
- dispatch({
237
- type: "select-node",
238
- payload: {
239
- ids: ids
240
- }
241
- });
242
- },
243
- children: _Node,
244
- idAccessor (d) {
245
- return d.id.toString();
246
- }
247
- });
248
- }
249
-
250
-
251
- export {$71d20dff35996763$export$a90600c9da52b40c as FeedbackComponent, $b79bf29960412ca7$export$8d9dbb7a64bf2a5e as treeToGraph};
252
- //# sourceMappingURL=feedback.5c86878e.js.map