@macrostrat/feedback-components 1.0.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 (48) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +3 -0
  3. package/dist/edit-state.e8edb13a.js +251 -0
  4. package/dist/edit-state.e8edb13a.js.map +1 -0
  5. package/dist/extractions.54be85f8.js +177 -0
  6. package/dist/extractions.54be85f8.js.map +1 -0
  7. package/dist/feedback.46c2b5c4.js +252 -0
  8. package/dist/feedback.46c2b5c4.js.map +1 -0
  9. package/dist/feedback.module.7e16830e.css +44 -0
  10. package/dist/feedback.module.7e16830e.css.map +1 -0
  11. package/dist/feedback.module.c28cbac7.js +28 -0
  12. package/dist/feedback.module.c28cbac7.js.map +1 -0
  13. package/dist/graph.cb42b871.js +83 -0
  14. package/dist/graph.cb42b871.js.map +1 -0
  15. package/dist/index.d.ts +145 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +9 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/main.module.21bbfaf4.js +19 -0
  20. package/dist/main.module.21bbfaf4.js.map +1 -0
  21. package/dist/main.module.ca3db294.js +16 -0
  22. package/dist/main.module.ca3db294.js.map +1 -0
  23. package/dist/main.module.d6508c0e.css +14 -0
  24. package/dist/main.module.d6508c0e.css.map +1 -0
  25. package/dist/main.module.f9f92ece.css +17 -0
  26. package/dist/main.module.f9f92ece.css.map +1 -0
  27. package/dist/node.30d0b8c3.js +59 -0
  28. package/dist/node.30d0b8c3.js.map +1 -0
  29. package/dist/text-visualizer.77af0d24.js +101 -0
  30. package/dist/text-visualizer.77af0d24.js.map +1 -0
  31. package/dist/type-selector.e75dd247.js +62 -0
  32. package/dist/type-selector.e75dd247.js.map +1 -0
  33. package/package.json +48 -0
  34. package/src/extractions/index.ts +219 -0
  35. package/src/extractions/main.module.sass +10 -0
  36. package/src/extractions/types.ts +30 -0
  37. package/src/feedback/edit-state.ts +311 -0
  38. package/src/feedback/feedback.module.sass +37 -0
  39. package/src/feedback/graph.ts +98 -0
  40. package/src/feedback/index.ts +271 -0
  41. package/src/feedback/node.ts +65 -0
  42. package/src/feedback/text-visualizer.ts +116 -0
  43. package/src/feedback/type-selector/index.ts +75 -0
  44. package/src/feedback/type-selector/main.module.sass +13 -0
  45. package/src/feedback/types.ts +76 -0
  46. package/src/index.ts +2 -0
  47. package/stories/feedback.stories.ts +40 -0
  48. package/stories/test-data.ts +330 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.0.0] - 2025-02-14
8
+
9
+ First public release of the `@macrostrat/feedback-components` library,
10
+ focused on text feedback for Macrostrat unit information.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Feedback components
2
+
3
+ Components for user feedback and assessment of (often AI-extracted) information
@@ -0,0 +1,251 @@
1
+ import {useReducer as $5j0pg$useReducer, createContext as $5j0pg$createContext, useContext as $5j0pg$useContext} from "react";
2
+ import $5j0pg$immutabilityhelper from "immutability-helper";
3
+
4
+
5
+
6
+ var $b79bf29960412ca7$export$53ec42062883b2d4 = /*#__PURE__*/ function(ViewMode) {
7
+ ViewMode["Tree"] = "tree";
8
+ ViewMode["Graph"] = "graph";
9
+ return ViewMode;
10
+ }({});
11
+ function $b79bf29960412ca7$export$911bb4b9c8065d3d(initialTree, entityTypes) {
12
+ // Get the first entity type
13
+ const type = entityTypes.values().next().value;
14
+ return (0, $5j0pg$useReducer)($b79bf29960412ca7$var$treeReducer, {
15
+ initialTree: initialTree,
16
+ tree: initialTree,
17
+ selectedNodes: [],
18
+ entityTypesMap: entityTypes,
19
+ selectedEntityType: type,
20
+ lastInternalId: 0,
21
+ isSelectingEntityType: false,
22
+ viewMode: "tree"
23
+ });
24
+ }
25
+ const $b79bf29960412ca7$export$e5ce04c5b3f58533 = (0, $5j0pg$createContext)(null);
26
+ function $b79bf29960412ca7$export$e1068f2d1c68f87e() {
27
+ const dispatch = (0, $5j0pg$useContext)($b79bf29960412ca7$export$e5ce04c5b3f58533);
28
+ if (dispatch == null) throw new Error("No dispatch context available");
29
+ return dispatch;
30
+ }
31
+ function $b79bf29960412ca7$var$treeReducer(state, action) {
32
+ console.log(action);
33
+ switch(action.type){
34
+ case "move-node":
35
+ // For each node in the tree, if the node is in the dragIds, remove it from the tree and collect it
36
+ const [newTree, removedNodes] = $b79bf29960412ca7$var$removeNodes(state.tree, action.payload.dragIds);
37
+ let keyPath = [];
38
+ if (action.payload.parentId) {
39
+ keyPath = $b79bf29960412ca7$var$findNode(newTree, action.payload.parentId);
40
+ keyPath.push("children");
41
+ }
42
+ // Add removed nodes to the new tree at the correct location
43
+ let updateSpec = $b79bf29960412ca7$var$buildNestedSpec(keyPath, {
44
+ $splice: [
45
+ [
46
+ action.payload.index,
47
+ 0,
48
+ ...removedNodes
49
+ ]
50
+ ]
51
+ });
52
+ return {
53
+ ...state,
54
+ tree: (0, $5j0pg$immutabilityhelper)(newTree, updateSpec)
55
+ };
56
+ case "delete-node":
57
+ // For each node in the tree, if the node is in the ids, remove it from the tree
58
+ const [newTree2, _removedNodes] = $b79bf29960412ca7$var$removeNodes(state.tree, action.payload.ids);
59
+ // Get children of the removed nodes
60
+ // If children are not present elsewhere in the tree, insert them
61
+ const children = _removedNodes.flatMap((node)=>node.children ?? []).filter((child)=>!$b79bf29960412ca7$var$nodeIsInTree(newTree2, child.id));
62
+ // Reset the selection
63
+ return {
64
+ ...state,
65
+ tree: [
66
+ ...newTree2,
67
+ ...children
68
+ ],
69
+ selectedNodes: state.selectedNodes.filter((id)=>!action.payload.ids.includes(id))
70
+ };
71
+ case "select-node":
72
+ const { ids: ids } = action.payload;
73
+ return {
74
+ ...state,
75
+ selectedNodes: ids
76
+ };
77
+ // otherwise fall through to toggle-node-selected for a single ID
78
+ case "toggle-node-selected":
79
+ const nodesToAdd = action.payload.ids.filter((id)=>!state.selectedNodes.includes(id));
80
+ const nodesToKeep = state.selectedNodes.filter((id)=>!action.payload.ids.includes(id));
81
+ return {
82
+ ...state,
83
+ selectedNodes: [
84
+ ...nodesToKeep,
85
+ ...nodesToAdd
86
+ ]
87
+ };
88
+ case "create-node":
89
+ const newId = state.lastInternalId - 1;
90
+ const { text: text, start: start, end: end } = action.payload;
91
+ const node = {
92
+ id: newId,
93
+ name: text,
94
+ children: [],
95
+ indices: [
96
+ start,
97
+ end
98
+ ],
99
+ type: state.selectedEntityType
100
+ };
101
+ return {
102
+ ...state,
103
+ tree: [
104
+ ...state.tree,
105
+ node
106
+ ],
107
+ selectedNodes: [
108
+ newId
109
+ ],
110
+ lastInternalId: newId
111
+ };
112
+ /** Entity type selection */ case "toggle-entity-type-selector":
113
+ return {
114
+ ...state,
115
+ isSelectingEntityType: action.payload ?? !state.isSelectingEntityType
116
+ };
117
+ case "select-entity-type":
118
+ {
119
+ // For each selected node, update the type
120
+ let newTree2 = state.tree;
121
+ for (let id of state.selectedNodes){
122
+ const keyPath = $b79bf29960412ca7$var$findNode(state.tree, id);
123
+ const nestedSpec = $b79bf29960412ca7$var$buildNestedSpec(keyPath, {
124
+ type: {
125
+ $set: action.payload
126
+ }
127
+ });
128
+ newTree2 = (0, $5j0pg$immutabilityhelper)(newTree2, nestedSpec);
129
+ }
130
+ return {
131
+ ...state,
132
+ tree: newTree2,
133
+ selectedEntityType: action.payload
134
+ };
135
+ }
136
+ case "deselect":
137
+ return {
138
+ ...state,
139
+ selectedNodes: []
140
+ };
141
+ case "reset":
142
+ return {
143
+ ...state,
144
+ tree: state.initialTree,
145
+ selectedNodes: []
146
+ };
147
+ case "set-view-mode":
148
+ return {
149
+ ...state,
150
+ viewMode: action.payload
151
+ };
152
+ }
153
+ }
154
+ function $b79bf29960412ca7$var$nodeIsInTree(tree, id) {
155
+ for (let node of tree){
156
+ if (node.id == id) return true;
157
+ else if (node.children) {
158
+ if ($b79bf29960412ca7$var$nodeIsInTree(node.children, id)) return true;
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+ function $b79bf29960412ca7$var$buildNestedSpec(keyPath, innerSpec) {
164
+ // Build a nested object from a key path
165
+ let spec = innerSpec;
166
+ for(let i = keyPath.length - 1; i >= 0; i--)spec = {
167
+ [keyPath[i]]: spec
168
+ };
169
+ return spec;
170
+ // Since we don't have a "children" key at the root, we make the top-level spec an array
171
+ }
172
+ function $b79bf29960412ca7$var$findNode(tree, id) {
173
+ // Find the index of the node with the given id in the tree, returning the key path
174
+ for(let i = 0; i < tree.length; i++){
175
+ if (tree[i].id == id) return [
176
+ i
177
+ ];
178
+ else if (tree[i].children) {
179
+ let path = $b79bf29960412ca7$var$findNode(tree[i].children, id);
180
+ if (path != null) return [
181
+ i,
182
+ "children",
183
+ ...path
184
+ ];
185
+ }
186
+ }
187
+ return null;
188
+ }
189
+ function $b79bf29960412ca7$var$removeNodes(tree, ids) {
190
+ /** Remove nodes with the given ids from the tree and return the new tree and the removed nodes */ let newTree = [];
191
+ let removedNodes = [];
192
+ for (let node of tree)if (ids.includes(node.id)) removedNodes.push(node);
193
+ else {
194
+ // Recurse into children
195
+ if (node.children) {
196
+ let [newChildren, removedChildren] = $b79bf29960412ca7$var$removeNodes(node.children, ids);
197
+ node = {
198
+ ...node,
199
+ children: newChildren
200
+ };
201
+ removedNodes.push(...removedChildren);
202
+ }
203
+ newTree.push(node);
204
+ }
205
+ return [
206
+ newTree,
207
+ removedNodes
208
+ ];
209
+ }
210
+ function $b79bf29960412ca7$export$8d9dbb7a64bf2a5e(tree) {
211
+ // Convert the tree to a graph
212
+ let nodes = [];
213
+ let edges = [];
214
+ const nodeMap = new Map();
215
+ for (let node of tree){
216
+ // If we've already found an instance of this node, we don't need to record
217
+ // it again
218
+ if (nodeMap.has(node.id)) continue;
219
+ const { indices: indices, id: id, name: name } = node;
220
+ const nodeData = {
221
+ id: id,
222
+ type: node.type.id,
223
+ name: name,
224
+ txt_range: [
225
+ indices
226
+ ],
227
+ reasoning: null,
228
+ match: node.match
229
+ };
230
+ nodeMap.set(node.id, node);
231
+ nodes.push(nodeData);
232
+ if (node.children) {
233
+ for (let child of node.children)edges.push({
234
+ source: node.id,
235
+ dest: child.id
236
+ });
237
+ // Now process the children
238
+ const { nodes: childNodes, edges: childEdges } = $b79bf29960412ca7$export$8d9dbb7a64bf2a5e(node.children);
239
+ nodes.push(...childNodes);
240
+ edges.push(...childEdges);
241
+ }
242
+ }
243
+ return {
244
+ nodes: nodes,
245
+ edges: edges
246
+ };
247
+ }
248
+
249
+
250
+ export {$b79bf29960412ca7$export$53ec42062883b2d4 as ViewMode, $b79bf29960412ca7$export$911bb4b9c8065d3d as useUpdatableTree, $b79bf29960412ca7$export$e5ce04c5b3f58533 as TreeDispatchContext, $b79bf29960412ca7$export$e1068f2d1c68f87e as useTreeDispatch, $b79bf29960412ca7$export$8d9dbb7a64bf2a5e as treeToGraph};
251
+ //# sourceMappingURL=edit-state.e8edb13a.js.map
@@ -0,0 +1 @@
1
+ {"mappings":";;;;;AAKO,IAAA,AAAK,mEAAA;;;WAAA;;AAuCL,SAAS,0CACd,WAAuB,EACvB,WAAoC;IAEpC,4BAA4B;IAC5B,MAAM,OAAO,YAAY,MAAM,GAAG,IAAI,GAAG,KAAK;IAE9C,OAAO,CAAA,GAAA,iBAAS,EAAE,mCAAa;qBAC7B;QACA,MAAM;QACN,eAAe,EAAE;QACjB,gBAAgB;QAChB,oBAAoB;QACpB,gBAAgB;QAChB,uBAAuB;QACvB,QAAQ;IACV;AACF;AAEO,MAAM,4CAAsB,CAAA,GAAA,oBAAY,EAAuB;AAE/D,SAAS;IACd,MAAM,WAAW,CAAA,GAAA,iBAAS,EAAE;IAC5B,IAAI,YAAY,MACd,MAAM,IAAI,MAAM;IAElB,OAAO;AACT;AAEA,SAAS,kCAAY,KAAgB,EAAE,MAAkB;IACvD,QAAQ,GAAG,CAAC;IACZ,OAAQ,OAAO,IAAI;QACjB,KAAK;YACH,mGAAmG;YACnG,MAAM,CAAC,SAAS,aAAa,GAAG,kCAC9B,MAAM,IAAI,EACV,OAAO,OAAO,CAAC,OAAO;YAGxB,IAAI,UAAmC,EAAE;YACzC,IAAI,OAAO,OAAO,CAAC,QAAQ,EAAE;gBAC3B,UAAU,+BAAS,SAAS,OAAO,OAAO,CAAC,QAAQ;gBACnD,QAAQ,IAAI,CAAC;YACf;YAEA,4DAA4D;YAC5D,IAAI,aAAa,sCAAgB,SAAS;gBACxC,SAAS;oBAAC;wBAAC,OAAO,OAAO,CAAC,KAAK;wBAAE;2BAAM;qBAAa;iBAAC;YACvD;YAEA,OAAO;gBAAE,GAAG,KAAK;gBAAE,MAAM,CAAA,GAAA,yBAAK,EAAE,SAAS;YAAY;QACvD,KAAK;YACH,gFAAgF;YAChF,MAAM,CAAC,UAAU,cAAc,GAAG,kCAChC,MAAM,IAAI,EACV,OAAO,OAAO,CAAC,GAAG;YAEpB,oCAAoC;YACpC,iEAAiE;YAEjE,MAAM,WAAW,cACd,OAAO,CAAC,CAAC,OAAS,KAAK,QAAQ,IAAI,EAAE,EACrC,MAAM,CAAC,CAAC,QAAU,CAAC,mCAAa,UAAU,MAAM,EAAE;YAErD,sBAAsB;YAEtB,OAAO;gBACL,GAAG,KAAK;gBACR,MAAM;uBAAI;uBAAa;iBAAS;gBAChC,eAAe,MAAM,aAAa,CAAC,MAAM,CACvC,CAAC,KAAO,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;YAEzC;QACF,KAAK;YACH,MAAM,OAAE,GAAG,EAAE,GAAG,OAAO,OAAO;YAC9B,OAAO;gBAAE,GAAG,KAAK;gBAAE,eAAe;YAAI;QACxC,iEAAiE;QACjE,KAAK;YACH,MAAM,aAAa,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAC1C,CAAC,KAAO,CAAC,MAAM,aAAa,CAAC,QAAQ,CAAC;YAExC,MAAM,cAAc,MAAM,aAAa,CAAC,MAAM,CAC5C,CAAC,KAAO,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;YAEvC,OAAO;gBAAE,GAAG,KAAK;gBAAE,eAAe;uBAAI;uBAAgB;iBAAW;YAAC;QAEpE,KAAK;YACH,MAAM,QAAQ,MAAM,cAAc,GAAG;YACrC,MAAM,QAAE,IAAI,SAAE,KAAK,OAAE,GAAG,EAAE,GAAG,OAAO,OAAO;YAC3C,MAAM,OAAiB;gBACrB,IAAI;gBACJ,MAAM;gBACN,UAAU,EAAE;gBACZ,SAAS;oBAAC;oBAAO;iBAAI;gBACrB,MAAM,MAAM,kBAAkB;YAChC;YAEA,OAAO;gBACL,GAAG,KAAK;gBACR,MAAM;uBAAI,MAAM,IAAI;oBAAE;iBAAK;gBAC3B,eAAe;oBAAC;iBAAM;gBACtB,gBAAgB;YAClB;QAEF,0BAA0B,GAC1B,KAAK;YACH,OAAO;gBACL,GAAG,KAAK;gBACR,uBAAuB,OAAO,OAAO,IAAI,CAAC,MAAM,qBAAqB;YACvE;QACF,KAAK;YAAsB;gBACzB,0CAA0C;gBAC1C,IAAI,WAAW,MAAM,IAAI;gBACzB,KAAK,IAAI,MAAM,MAAM,aAAa,CAAE;oBAClC,MAAM,UAAU,+BAAS,MAAM,IAAI,EAAE;oBACrC,MAAM,aAAa,sCAAgB,SAAS;wBAC1C,MAAM;4BAAE,MAAM,OAAO,OAAO;wBAAC;oBAC/B;oBACA,WAAW,CAAA,GAAA,yBAAK,EAAE,UAAU;gBAC9B;gBAEA,OAAO;oBACL,GAAG,KAAK;oBACR,MAAM;oBACN,oBAAoB,OAAO,OAAO;gBACpC;YACF;QACA,KAAK;YACH,OAAO;gBAAE,GAAG,KAAK;gBAAE,eAAe,EAAE;YAAC;QACvC,KAAK;YACH,OAAO;gBACL,GAAG,KAAK;gBACR,MAAM,MAAM,WAAW;gBACvB,eAAe,EAAE;YACnB;QACF,KAAK;YACH,OAAO;gBAAE,GAAG,KAAK;gBAAE,UAAU,OAAO,OAAO;YAAC;IAChD;AACF;AAEA,SAAS,mCAAa,IAAgB,EAAE,EAAU;IAChD,KAAK,IAAI,QAAQ,KAAM;QACrB,IAAI,KAAK,EAAE,IAAI,IACb,OAAO;aACF,IAAI,KAAK,QAAQ,EAAE;YACxB,IAAI,mCAAa,KAAK,QAAQ,EAAE,KAC9B,OAAO;QAEX;IACF;IACA,OAAO;AACT;AAEA,SAAS,sCACP,OAAgC,EAChC,SAAoB;IAEpB,wCAAwC;IAExC,IAAI,OAAO;IACX,IAAK,IAAI,IAAI,QAAQ,MAAM,GAAG,GAAG,KAAK,GAAG,IACvC,OAAO;QAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;IAAK;IAE9B,OAAO;AACP,wFAAwF;AAC1F;AAEA,SAAS,+BACP,IAAgB,EAChB,EAAU;IAEV,mFAAmF;IACnF,IAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,EAAE,IAAK;QACpC,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,IAChB,OAAO;YAAC;SAAE;aACL,IAAI,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE;YAC3B,IAAI,OAAO,+BAAS,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE;YACtC,IAAI,QAAQ,MACV,OAAO;gBAAC;gBAAG;mBAAe;aAAK;QAEnC;IACF;IACA,OAAO;AACT;AAEA,SAAS,kCACP,IAAgB,EAChB,GAAa;IAEb,gGAAgG,GAChG,IAAI,UAAsB,EAAE;IAC5B,IAAI,eAA2B,EAAE;IAEjC,KAAK,IAAI,QAAQ,KACf,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,GACtB,aAAa,IAAI,CAAC;SACb;QACL,wBAAwB;QACxB,IAAI,KAAK,QAAQ,EAAE;YACjB,IAAI,CAAC,aAAa,gBAAgB,GAAG,kCAAY,KAAK,QAAQ,EAAE;YAChE,OAAO;gBAAE,GAAG,IAAI;gBAAE,UAAU;YAAY;YACxC,aAAa,IAAI,IAAI;QACvB;QACA,QAAQ,IAAI,CAAC;IACf;IAGF,OAAO;QAAC;QAAS;KAAa;AAChC;AAgBO,SAAS,0CAAY,IAAgB;IAC1C,8BAA8B;IAC9B,IAAI,QAAwB,EAAE;IAC9B,IAAI,QAA4C,EAAE;IAClD,MAAM,UAAU,IAAI;IAEpB,KAAK,IAAI,QAAQ,KAAM;QACrB,2EAA2E;QAC3E,WAAW;QACX,IAAI,QAAQ,GAAG,CAAC,KAAK,EAAE,GACrB;QAGF,MAAM,WAAE,OAAO,MAAE,EAAE,QAAE,IAAI,EAAE,GAAG;QAE9B,MAAM,WAAyB;gBAC7B;YACA,MAAM,KAAK,IAAI,CAAC,EAAE;kBAClB;YACA,WAAW;gBAAC;aAAQ;YACpB,WAAW;YACX,OAAO,KAAK,KAAK;QACnB;QAEA,QAAQ,GAAG,CAAC,KAAK,EAAE,EAAE;QACrB,MAAM,IAAI,CAAC;QAEX,IAAI,KAAK,QAAQ,EAAE;YACjB,KAAK,IAAI,SAAS,KAAK,QAAQ,CAC7B,MAAM,IAAI,CAAC;gBAAE,QAAQ,KAAK,EAAE;gBAAE,MAAM,MAAM,EAAE;YAAC;YAG/C,2BAA2B;YAC3B,MAAM,EAAE,OAAO,UAAU,EAAE,OAAO,UAAU,EAAE,GAAG,0CAC/C,KAAK,QAAQ;YAEf,MAAM,IAAI,IAAI;YACd,MAAM,IAAI,IAAI;QAChB;IACF;IAEA,OAAO;eAAE;eAAO;IAAM;AACxB","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;\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.e8edb13a.js.map"}
@@ -0,0 +1,177 @@
1
+ import "./main.module.d6508c0e.css";
2
+ import $hx0US$mainmoduleca3db294js from "./main.module.ca3db294.js";
3
+ import $hx0US$classnames from "classnames";
4
+ import {Tag as $hx0US$Tag} from "@blueprintjs/core";
5
+ import {asChromaColor as $hx0US$asChromaColor} from "@macrostrat/color-utils";
6
+ import $hx0US$macrostrathyper from "@macrostrat/hyper";
7
+
8
+
9
+ function $parcel$interopDefault(a) {
10
+ return a && a.__esModule ? a.default : a;
11
+ }
12
+
13
+
14
+
15
+
16
+
17
+ const $03d8811e9c9b360d$var$h = (0, $hx0US$macrostrathyper).styled((0, ($parcel$interopDefault($hx0US$mainmoduleca3db294js))));
18
+ function $03d8811e9c9b360d$export$c4b91360064ad200(entities, parent) {
19
+ let highlights = [];
20
+ let parents = [];
21
+ if (parent != null) parents = [
22
+ parent.id,
23
+ ...parent.parents ?? []
24
+ ];
25
+ for (const entity of entities){
26
+ highlights.push({
27
+ start: entity.indices[0],
28
+ end: entity.indices[1],
29
+ text: entity.name,
30
+ backgroundColor: entity.type.color ?? "#ddd",
31
+ tag: entity.type.name,
32
+ id: entity.id,
33
+ parents: parents
34
+ });
35
+ highlights.push(...$03d8811e9c9b360d$export$c4b91360064ad200(entity.children ?? [], entity));
36
+ }
37
+ return highlights;
38
+ }
39
+ function $03d8811e9c9b360d$export$d60b563f571177d(extractionData, models, entityTypes) {
40
+ return {
41
+ ...extractionData,
42
+ model: models.get(extractionData.model_id),
43
+ entities: extractionData.entities?.map((d)=>$03d8811e9c9b360d$var$enhanceEntity(d, entityTypes))
44
+ };
45
+ }
46
+ function $03d8811e9c9b360d$export$35baa338324d8550(baseColor, options) {
47
+ const _baseColor = (0, $hx0US$asChromaColor)(baseColor ?? "#ddd");
48
+ const { highlighted: highlighted = true, inDarkMode: inDarkMode = false, active: active = false } = options;
49
+ let mixAmount = highlighted ? 0.8 : 0.5;
50
+ let backgroundAlpha = highlighted ? 0.8 : 0.2;
51
+ if (active) {
52
+ mixAmount = 1;
53
+ backgroundAlpha = 1;
54
+ }
55
+ const mixTarget = inDarkMode ? "white" : "black";
56
+ const color = _baseColor.mix(mixTarget, mixAmount).css();
57
+ const borderColor = highlighted ? _baseColor.mix(mixTarget, mixAmount / 2).css() : "transparent";
58
+ return {
59
+ color: color,
60
+ backgroundColor: _baseColor.alpha(backgroundAlpha).css(),
61
+ boxSizing: "border-box",
62
+ borderStyle: "solid",
63
+ borderColor: borderColor,
64
+ borderWidth: "1px",
65
+ fontWeight: active ? "bold" : "normal"
66
+ };
67
+ }
68
+ function $03d8811e9c9b360d$var$enhanceEntity(entity, entityTypes) {
69
+ return {
70
+ ...entity,
71
+ type: $03d8811e9c9b360d$var$addColor(entityTypes.get(entity.type), entity.match != null),
72
+ children: entity.children?.map((d)=>$03d8811e9c9b360d$var$enhanceEntity(d, entityTypes))
73
+ };
74
+ }
75
+ function $03d8811e9c9b360d$var$addColor(entityType, match = false) {
76
+ const color = (0, $hx0US$asChromaColor)(entityType.color ?? "#ddd").brighten(match ? 1 : 2);
77
+ return {
78
+ ...entityType,
79
+ color: color.css()
80
+ };
81
+ }
82
+ function $03d8811e9c9b360d$export$2b07158757c249e0({ data: data, entityTypes: entityTypes, matchComponent: matchComponent }) {
83
+ const highlights = $03d8811e9c9b360d$export$c4b91360064ad200(data.entities, null);
84
+ return $03d8811e9c9b360d$var$h("div", [
85
+ $03d8811e9c9b360d$var$h("p", $03d8811e9c9b360d$var$h($03d8811e9c9b360d$var$HighlightedText, {
86
+ text: data.paragraph_text,
87
+ highlights: highlights
88
+ })),
89
+ $03d8811e9c9b360d$var$h($03d8811e9c9b360d$export$4eb2a0ce903ce967, {
90
+ data: data.model
91
+ }),
92
+ $03d8811e9c9b360d$var$h("ul.entities", data.entities.map((d)=>$03d8811e9c9b360d$var$h($03d8811e9c9b360d$var$ExtractionInfo, {
93
+ data: d,
94
+ matchComponent: matchComponent
95
+ })))
96
+ ]);
97
+ }
98
+ function $03d8811e9c9b360d$export$4eb2a0ce903ce967({ data: data }) {
99
+ return $03d8811e9c9b360d$var$h("p.model-name", [
100
+ "Model: ",
101
+ $03d8811e9c9b360d$var$h("code.bp5-code", data.name)
102
+ ]);
103
+ }
104
+ function $03d8811e9c9b360d$export$117e56c71b172cde({ data: data, highlighted: highlighted = true, active: active = false, onClickType: onClickType, matchComponent: matchComponent = null }) {
105
+ const { name: name, type: type, match: match } = data;
106
+ const className = (0, $hx0US$classnames)({
107
+ matched: match != null,
108
+ type: data.type.name
109
+ }, "entity");
110
+ const style = $03d8811e9c9b360d$export$35baa338324d8550(type.color ?? "#aaaaaa", {
111
+ highlighted: highlighted,
112
+ active: active
113
+ });
114
+ let _matchLink = null;
115
+ if (match != null && matchComponent != null) _matchLink = $03d8811e9c9b360d$var$h(matchComponent, {
116
+ data: match
117
+ });
118
+ return $03d8811e9c9b360d$var$h((0, $hx0US$Tag), {
119
+ style: style,
120
+ className: className
121
+ }, [
122
+ $03d8811e9c9b360d$var$h("span.entity-name", name),
123
+ " ",
124
+ $03d8811e9c9b360d$var$h("code.entity-type.bp5-code", {
125
+ onClick (evt) {
126
+ if (active && onClickType != null) {
127
+ onClickType(type);
128
+ evt.stopPropagation();
129
+ }
130
+ }
131
+ }, [
132
+ type.name,
133
+ _matchLink
134
+ ])
135
+ ]);
136
+ }
137
+ function $03d8811e9c9b360d$var$ExtractionInfo({ data: data, matchComponent: matchComponent = null }) {
138
+ const children = data.children ?? [];
139
+ return $03d8811e9c9b360d$var$h("li.entity-row", [
140
+ $03d8811e9c9b360d$var$h($03d8811e9c9b360d$export$117e56c71b172cde, {
141
+ data: data,
142
+ matchComponent: matchComponent
143
+ }),
144
+ $03d8811e9c9b360d$var$h.if(children.length > 0)([
145
+ $03d8811e9c9b360d$var$h("ul.children", children.map((d)=>$03d8811e9c9b360d$var$h($03d8811e9c9b360d$var$ExtractionInfo, {
146
+ data: d,
147
+ matchComponent: matchComponent
148
+ })))
149
+ ])
150
+ ]);
151
+ }
152
+ function $03d8811e9c9b360d$var$HighlightedText(props) {
153
+ const { text: text, highlights: highlights = [] } = props;
154
+ const parts = [];
155
+ let start = 0;
156
+ const sortedHighlights = highlights.sort((a, b)=>a.start - b.start);
157
+ const deconflictedHighlights = sortedHighlights.map((highlight, i)=>{
158
+ if (i === 0) return highlight;
159
+ const prev = sortedHighlights[i - 1];
160
+ if (highlight.start < prev.end) highlight.start = prev.end;
161
+ return highlight;
162
+ });
163
+ for (const highlight of deconflictedHighlights){
164
+ const { start: s, end: end, ...rest } = highlight;
165
+ parts.push(text.slice(start, s));
166
+ parts.push($03d8811e9c9b360d$var$h("span.highlight", {
167
+ style: rest
168
+ }, text.slice(s, end)));
169
+ start = end;
170
+ }
171
+ parts.push(text.slice(start));
172
+ return $03d8811e9c9b360d$var$h("span", parts);
173
+ }
174
+
175
+
176
+ export {$03d8811e9c9b360d$export$c4b91360064ad200 as buildHighlights, $03d8811e9c9b360d$export$d60b563f571177d as enhanceData, $03d8811e9c9b360d$export$35baa338324d8550 as getTagStyle, $03d8811e9c9b360d$export$2b07158757c249e0 as ExtractionContext, $03d8811e9c9b360d$export$4eb2a0ce903ce967 as ModelInfo, $03d8811e9c9b360d$export$117e56c71b172cde as EntityTag};
177
+ //# sourceMappingURL=extractions.54be85f8.js.map
@@ -0,0 +1 @@
1
+ {"mappings":"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","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.54be85f8.js.map"}