@macrostrat/feedback-components 1.1.4 → 1.1.6

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 (74) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/esm/{feedback-components.7e879290.js → feedback-components.03f08dc7.js} +10 -9
  3. package/dist/esm/feedback-components.03f08dc7.js.map +1 -0
  4. package/dist/esm/{feedback-components.f6605b83.js → feedback-components.3d7fd2df.js} +83 -46
  5. package/dist/esm/feedback-components.3d7fd2df.js.map +1 -0
  6. package/dist/esm/{feedback-components.204f7d2b.js → feedback-components.47b7bf19.js} +49 -21
  7. package/dist/esm/feedback-components.47b7bf19.js.map +1 -0
  8. package/dist/esm/{feedback-components.d591ffec.css → feedback-components.5a8f0185.css} +11 -5
  9. package/dist/esm/feedback-components.5a8f0185.css.map +1 -0
  10. package/dist/esm/{feedback-components.1c15f37f.js → feedback-components.63a12d32.js} +14 -97
  11. package/dist/esm/feedback-components.63a12d32.js.map +1 -0
  12. package/dist/esm/{feedback-components.00434ff7.js → feedback-components.7c2fe400.js} +7 -1
  13. package/dist/esm/feedback-components.7c2fe400.js.map +1 -0
  14. package/dist/esm/{feedback-components.fd8ac9ca.js → feedback-components.a451f964.js} +116 -98
  15. package/dist/esm/feedback-components.a451f964.js.map +1 -0
  16. package/dist/esm/{feedback-components.d55a1d18.js → feedback-components.e068f453.js} +5 -5
  17. package/dist/esm/{feedback-components.d55a1d18.js.map → feedback-components.e068f453.js.map} +1 -1
  18. package/dist/esm/{feedback-components.28ba71be.js → feedback-components.e4935bf3.js} +7 -7
  19. package/dist/esm/feedback-components.e4935bf3.js.map +1 -0
  20. package/dist/esm/index.d.ts +2 -1
  21. package/dist/esm/index.d.ts.map +1 -1
  22. package/dist/esm/index.js +1 -1
  23. package/dist/node/feedback-components.2ad7d057.js +2 -0
  24. package/dist/node/feedback-components.2ad7d057.js.map +1 -0
  25. package/dist/node/feedback-components.441e2203.js +2 -0
  26. package/dist/node/feedback-components.441e2203.js.map +1 -0
  27. package/dist/node/{feedback-components.2f740fc7.js → feedback-components.67e60839.js} +2 -2
  28. package/dist/node/{feedback-components.2f740fc7.js.map → feedback-components.67e60839.js.map} +1 -1
  29. package/dist/node/feedback-components.76ed75d8.js +2 -0
  30. package/dist/node/feedback-components.76ed75d8.js.map +1 -0
  31. package/dist/node/feedback-components.827f8d80.js +2 -0
  32. package/dist/node/feedback-components.827f8d80.js.map +1 -0
  33. package/dist/node/feedback-components.8caef76e.js +2 -0
  34. package/dist/node/feedback-components.8caef76e.js.map +1 -0
  35. package/dist/node/feedback-components.c31cf831.js +2 -0
  36. package/dist/node/feedback-components.c31cf831.js.map +1 -0
  37. package/dist/node/feedback-components.ce5efb18.js +2 -0
  38. package/dist/node/feedback-components.ce5efb18.js.map +1 -0
  39. package/dist/node/feedback-components.db4d0a14.css +2 -0
  40. package/dist/node/feedback-components.db4d0a14.css.map +1 -0
  41. package/dist/node/index.js +1 -1
  42. package/dist/node/index.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/feedback/edit-state.ts +101 -49
  45. package/src/feedback/feedback.module.sass +9 -5
  46. package/src/feedback/graph.ts +5 -2
  47. package/src/feedback/index.ts +30 -4
  48. package/src/feedback/matches.ts +125 -87
  49. package/src/feedback/text-visualizer.ts +32 -86
  50. package/src/feedback/typelist.ts +13 -4
  51. package/dist/esm/feedback-components.00434ff7.js.map +0 -1
  52. package/dist/esm/feedback-components.1c15f37f.js.map +0 -1
  53. package/dist/esm/feedback-components.204f7d2b.js.map +0 -1
  54. package/dist/esm/feedback-components.28ba71be.js.map +0 -1
  55. package/dist/esm/feedback-components.7e879290.js.map +0 -1
  56. package/dist/esm/feedback-components.d591ffec.css.map +0 -1
  57. package/dist/esm/feedback-components.f6605b83.js.map +0 -1
  58. package/dist/esm/feedback-components.fd8ac9ca.js.map +0 -1
  59. package/dist/node/feedback-components.0eef8d0c.js +0 -2
  60. package/dist/node/feedback-components.0eef8d0c.js.map +0 -1
  61. package/dist/node/feedback-components.41db283a.js +0 -2
  62. package/dist/node/feedback-components.41db283a.js.map +0 -1
  63. package/dist/node/feedback-components.69d0ccd0.js +0 -2
  64. package/dist/node/feedback-components.69d0ccd0.js.map +0 -1
  65. package/dist/node/feedback-components.a7b43cfa.js +0 -2
  66. package/dist/node/feedback-components.a7b43cfa.js.map +0 -1
  67. package/dist/node/feedback-components.b9317f9c.js +0 -2
  68. package/dist/node/feedback-components.b9317f9c.js.map +0 -1
  69. package/dist/node/feedback-components.e096504e.css +0 -2
  70. package/dist/node/feedback-components.e096504e.css.map +0 -1
  71. package/dist/node/feedback-components.e140ac86.js +0 -2
  72. package/dist/node/feedback-components.e140ac86.js.map +0 -1
  73. package/dist/node/feedback-components.f8373b58.js +0 -2
  74. package/dist/node/feedback-components.f8373b58.js.map +0 -1
@@ -56,13 +56,19 @@ export function FeedbackComponent({
56
56
  onSave,
57
57
  allowOverlap,
58
58
  matchLinks,
59
+ view = false,
59
60
  }) {
61
+ const [viewOnly, setViewOnly] = useState(view);
62
+ const [match, setMatchLinks] = useState(matchLinks);
63
+ const matchMode = match !== undefined;
64
+
60
65
  // Get the input arguments
61
66
  const [state, dispatch] = useUpdatableTree(
62
67
  entities.map(processEntity) as any,
63
68
  entityTypes,
69
+ viewOnly,
70
+ matchMode,
64
71
  );
65
- const [match, setMatchLinks] = useState(matchLinks || {});
66
72
 
67
73
  const {
68
74
  selectedNodes,
@@ -78,6 +84,19 @@ export function FeedbackComponent({
78
84
  h(
79
85
  "div.feedback-container",
80
86
  h(TreeDispatchContext.Provider, { value: dispatch }, [
87
+ h.if(!view)(SegmentedControl, {
88
+ options: [
89
+ { label: "View", value: "view" },
90
+ { label: "Edit", value: "edit" },
91
+ ],
92
+ value: viewOnly ? "view" : "edit",
93
+ small: true,
94
+ onValueChange() {
95
+ setViewOnly(!viewOnly);
96
+ dispatch({ type: "toggle-view-only" });
97
+ },
98
+ role: "toolbar",
99
+ }),
81
100
  h(
82
101
  ErrorBoundary,
83
102
  {
@@ -92,6 +111,7 @@ export function FeedbackComponent({
92
111
  selectedNodes,
93
112
  allowOverlap,
94
113
  matchLinks: match,
114
+ viewOnly,
95
115
  }),
96
116
  ),
97
117
  h(
@@ -133,6 +153,7 @@ export function FeedbackComponent({
133
153
  height,
134
154
  dispatch,
135
155
  selectedNodes,
156
+ viewOnly,
136
157
  }),
137
158
  ],
138
159
  ),
@@ -140,7 +161,7 @@ export function FeedbackComponent({
140
161
  ),
141
162
  h(Card, { className: "control-panel" }, [
142
163
  h("div.control-content", [
143
- h(
164
+ h.if(!viewOnly)(
144
165
  ButtonGroup,
145
166
  {
146
167
  vertical: true,
@@ -172,7 +193,7 @@ export function FeedbackComponent({
172
193
  ),
173
194
  ],
174
195
  ),
175
- h(Matches, {
196
+ h.if(!viewOnly)(Matches, {
176
197
  match,
177
198
  setMatchLinks,
178
199
  matchLinks,
@@ -180,7 +201,7 @@ export function FeedbackComponent({
180
201
  tree,
181
202
  dispatch,
182
203
  }),
183
- h(Divider),
204
+ h.if(!viewOnly)(Divider),
184
205
  h(EntityTypeSelector, {
185
206
  entityTypes: entityTypesMap,
186
207
  selected: selectedEntityType,
@@ -196,6 +217,8 @@ export function FeedbackComponent({
196
217
  type: "toggle-entity-type-selector",
197
218
  payload: isOpen,
198
219
  }),
220
+ viewOnly,
221
+ matchMode,
199
222
  }),
200
223
  ]),
201
224
  ]),
@@ -222,6 +245,8 @@ function EntityTypeSelector({
222
245
  tree,
223
246
  dispatch,
224
247
  selectedNodes = [],
248
+ viewOnly,
249
+ matchMode,
225
250
  }) {
226
251
  // Show all entity types when selected is null
227
252
  const _selected = selected != null ? selected : undefined;
@@ -242,6 +267,7 @@ function EntityTypeSelector({
242
267
  dispatch,
243
268
  selectedNodes,
244
269
  tree,
270
+ viewOnly: viewOnly || matchMode,
245
271
  }),
246
272
  h(OmniboxSelector, {
247
273
  isOpen,
@@ -1,5 +1,4 @@
1
1
  import { Switch } from "@blueprintjs/core";
2
- import { Match } from "./text-visualizer";
3
2
  import { Select } from "@blueprintjs/select";
4
3
  import styles from "./feedback.module.sass";
5
4
  import hyper from "@macrostrat/hyper";
@@ -29,10 +28,11 @@ export function Matches({
29
28
  return h.if(matchLinks)("div", [
30
29
  h(Divider),
31
30
  h(Switch, {
32
- label: "Show matches",
33
- checked: match !== null,
31
+ label: "Match mode",
32
+ checked: match !== undefined,
34
33
  onChange: (e) => {
35
- setMatchLinks(match === null ? matchLinks || {} : null);
34
+ setMatchLinks(match === undefined ? matchLinks || {} : undefined);
35
+ dispatch({ type: "toggle-match-mode" });
36
36
  },
37
37
  }),
38
38
  h.if(nodeMatch && match)(Match, {
@@ -95,89 +95,7 @@ function MatchOverlay({ isOpen, setOverlayOpen, nodeMatch, dispatch }) {
95
95
  inputValue +
96
96
  "*",
97
97
  );
98
- const items = data?.map((data) => {
99
- const type = data.type || "";
100
-
101
- if (type === "lith") {
102
- return h(
103
- "div",
104
- {
105
- onClick: () => {
106
- setPayload({ lith_id: data.id, name: data.name });
107
- },
108
- },
109
- h(DataField, {
110
- className: "match-item",
111
- label: "Lithology",
112
- value: h(LithologyTag, {
113
- data: { name: data.name, id: data.lith_id, color: data.color },
114
- }),
115
- }),
116
- );
117
- }
118
-
119
- if (type === "strat_name") {
120
- return h(
121
- "div",
122
- {
123
- onClick: () => {
124
- setPayload({ strat_name_id: data.id, name: data.name });
125
- },
126
- },
127
- h(DataField, {
128
- className: "match-item",
129
- label: "Stratigraphic name",
130
- value: h(LithologyTag, {
131
- data: { name: data.name, id: data.id, color: data.color },
132
- }),
133
- }),
134
- );
135
- }
136
-
137
- if (type === "lith_att") {
138
- return h(
139
- "div",
140
- {
141
- onClick: () => {
142
- setPayload({ lith_att_id: data.lith_att_id, name: data.name });
143
- },
144
- },
145
- h(DataField, {
146
- className: "match-item",
147
- label: "Lithology attribute",
148
- value: h(LithologyTag, {
149
- data: { name: data.name, id: data.lith_att_id },
150
- }),
151
- onClick: () => {
152
- setPayload({ lith_att_id: data.lith_att_id, name: data.name });
153
- },
154
- }),
155
- );
156
- }
157
-
158
- if (type === "interval") {
159
- h(
160
- "div",
161
- {
162
- onClick: () => {
163
- setPayload({ int_id: data.id, name: data.name });
164
- },
165
- },
166
- h(DataField, {
167
- label: "Interval",
168
- className: "match-item",
169
- value: h(LithologyTag, {
170
- data: { name: data.name, id: data.id },
171
- }),
172
- onClick: () => {
173
- setPayload({ int_id: data.id, name: data.name });
174
- },
175
- }),
176
- );
177
- }
178
-
179
- return h(JSONView, { data });
180
- });
98
+ const items = data?.map((data) => h(MatchTag, { data, setPayload }));
181
99
 
182
100
  return h(
183
101
  Overlay2,
@@ -239,3 +157,123 @@ function MatchOverlay({ isOpen, setOverlayOpen, nodeMatch, dispatch }) {
239
157
  ),
240
158
  );
241
159
  }
160
+
161
+ function Match({ data, matchLinks, dispatch, nodeId }) {
162
+ return h.if(data)("div.match-container", [
163
+ MatchTag({ data, matchLinks }),
164
+ h(Icon, {
165
+ icon: "cross",
166
+ color: "red",
167
+ className: "close-btn",
168
+ onClick: () => {
169
+ dispatch({ type: "remove-match", payload: { id: nodeId } });
170
+ },
171
+ }),
172
+ ]);
173
+ }
174
+
175
+ interface MatchTagProps {
176
+ data: any;
177
+ matchLinks?: Record<string, string>;
178
+ setPayload?: (payload: Record<string, any>) => void;
179
+ }
180
+
181
+ function MatchTag({ data, matchLinks, setPayload }: MatchTagProps) {
182
+ if (!data || Object.keys(data).length === 0) return;
183
+
184
+ if (data.lith_id || data?.type === "lith") {
185
+ return h(
186
+ "div",
187
+ {
188
+ onClick: () => {
189
+ data.type === "lith"
190
+ ? setPayload({ lith_id: data.id, name: data.name })
191
+ : null;
192
+ },
193
+ },
194
+ h(DataField, {
195
+ className: "match-item",
196
+ label: "Stratigraphic name",
197
+ value: h(LithologyTag, {
198
+ data: { name: data.name, id: data.id, color: data.color },
199
+ onClick: () =>
200
+ window.open(
201
+ matchLinks.strat_name + "/" + data.strat_name_id,
202
+ "_blank",
203
+ ),
204
+ }),
205
+ }),
206
+ );
207
+ }
208
+
209
+ if (data.strat_name_id || data?.type === "strat_name") {
210
+ return h(
211
+ "div",
212
+ {
213
+ onClick: () => {
214
+ data.type === "strat_name"
215
+ ? setPayload({ strat_name_id: data.id, name: data.name })
216
+ : null;
217
+ },
218
+ },
219
+ h(DataField, {
220
+ className: "match-item",
221
+ label: "Stratigraphic name",
222
+ value: h(LithologyTag, {
223
+ data: { name: data.name, id: data.id, color: data.color },
224
+ onClick: () =>
225
+ window.open(
226
+ matchLinks.strat_name + "/" + data.strat_name_id,
227
+ "_blank",
228
+ ),
229
+ }),
230
+ }),
231
+ );
232
+ }
233
+
234
+ if (data.lith_att_id || data?.type === "lith_att") {
235
+ return h(
236
+ "div",
237
+ {
238
+ onClick: () => {
239
+ data.type === "lith_att"
240
+ ? setPayload({ lith_att_id: data.id, name: data.name })
241
+ : null;
242
+ },
243
+ },
244
+ h(DataField, {
245
+ className: "match-item",
246
+ label: "Lithology attribute",
247
+ value: h(LithologyTag, {
248
+ data: { name: data.name, id: data.lith_att_id },
249
+ onClick: () =>
250
+ window.open(matchLinks.lith_att + "/" + data.lith_att_id, "_blank"),
251
+ }),
252
+ }),
253
+ );
254
+ }
255
+
256
+ if (data.int_id || data?.type === "interval") {
257
+ return h(
258
+ "div",
259
+ {
260
+ onClick: () => {
261
+ data.type === "interval"
262
+ ? setPayload({ int_id: data.id, name: data.name })
263
+ : null;
264
+ },
265
+ },
266
+ h(DataField, {
267
+ label: "Interval",
268
+ className: "match-item",
269
+ value: h(LithologyTag, {
270
+ data: { name: data.name, id: data.id },
271
+ onClick: () =>
272
+ window.open(matchLinks.interval + "/" + data.int_id, "_blank"),
273
+ }),
274
+ }),
275
+ );
276
+ }
277
+
278
+ return h(JSONView, { data });
279
+ }
@@ -25,6 +25,7 @@ export interface FeedbackTextProps {
25
25
  strat_name: string;
26
26
  lith_att: string;
27
27
  };
28
+ viewOnly?: boolean;
28
29
  }
29
30
 
30
31
  function buildTags(
@@ -81,8 +82,15 @@ function isHighlighted(tag: Highlight, selectedNodes: number[]) {
81
82
 
82
83
  export function FeedbackText(props: FeedbackTextProps) {
83
84
  // Convert input to tags
84
- const { text, selectedNodes, nodes, dispatch, allowOverlap, matchLinks } =
85
- props;
85
+ const {
86
+ text,
87
+ selectedNodes,
88
+ nodes,
89
+ dispatch,
90
+ allowOverlap,
91
+ matchLinks,
92
+ viewOnly,
93
+ } = props;
86
94
  const allTags: AnnotateBlendTag[] = buildTags(
87
95
  buildHighlights(nodes, null),
88
96
  selectedNodes,
@@ -107,6 +115,7 @@ export function FeedbackText(props: FeedbackTextProps) {
107
115
  allowOverlap,
108
116
  dispatch,
109
117
  selectedNodes,
118
+ viewOnly,
110
119
  matchLinks,
111
120
  }),
112
121
  );
@@ -261,17 +270,25 @@ function renderNode(
261
270
  strat_name: string;
262
271
  lith_att: string;
263
272
  },
273
+ viewOnly?: boolean,
264
274
  ): any {
265
275
  if (typeof node === "string") return node;
266
276
 
267
277
  const { tag, children } = node;
268
278
  const isSelected = selectedNodes?.includes(tag.id);
269
279
  const showBorder = selectedNodes.length === 0 || isSelected;
280
+ const match = tag.match;
270
281
 
271
282
  const style = {
272
283
  ...tag,
273
284
  zIndex: parentSelected ? -1 : 1,
274
- border: "1px solid " + (showBorder ? tag.color : "transparent"),
285
+ border:
286
+ "1px solid " +
287
+ (match != undefined && matchLinks && !viewOnly
288
+ ? "orange"
289
+ : showBorder
290
+ ? tag.color
291
+ : "transparent"),
275
292
  margin: "-1px",
276
293
  };
277
294
 
@@ -295,7 +312,7 @@ function renderNode(
295
312
  onMouseEnter: (e: MouseEvent) => {
296
313
  e.stopPropagation();
297
314
  },
298
- className: "highlight",
315
+ className: "highlight" + (!viewOnly ? " clickable" : ""),
299
316
  style,
300
317
  onClick: (e: MouseEvent) => {
301
318
  e.stopPropagation();
@@ -329,7 +346,14 @@ function renderNode(
329
346
  isSelected
330
347
  ? moveText.flat()
331
348
  : children.map((child: any, i: number) =>
332
- renderNode(child, dispatch, selectedNodes, isSelected, matchLinks),
349
+ renderNode(
350
+ child,
351
+ dispatch,
352
+ selectedNodes,
353
+ isSelected,
354
+ matchLinks,
355
+ viewOnly,
356
+ ),
333
357
  ),
334
358
  );
335
359
  }
@@ -346,6 +370,7 @@ export function HighlightedText(props: {
346
370
  strat_name: string;
347
371
  lith_att: string;
348
372
  };
373
+ viewOnly?: boolean;
349
374
  }) {
350
375
  const {
351
376
  text,
@@ -354,6 +379,7 @@ export function HighlightedText(props: {
354
379
  selectedNodes,
355
380
  allowOverlap,
356
381
  matchLinks,
382
+ viewOnly,
357
383
  } = props;
358
384
 
359
385
  const tree = nestHighlights(text, allTags);
@@ -377,87 +403,7 @@ export function HighlightedText(props: {
377
403
  "span",
378
404
  { ref: spanRef },
379
405
  tree.children.map((child: any, i: number) =>
380
- renderNode(child, dispatch, selectedNodes, false, matchLinks),
406
+ renderNode(child, dispatch, selectedNodes, false, matchLinks, viewOnly),
381
407
  ),
382
408
  );
383
409
  }
384
-
385
- export function Match({ data, matchLinks, dispatch, nodeId }) {
386
- if (!data || Object.keys(data).length === 0) return;
387
-
388
- let tag = h(JSONView, { data });
389
-
390
- if (data.lith_id) {
391
- tag = h(DataField, {
392
- label: "Lithology",
393
- value: h(LithologyTag, {
394
- data: { name: data.name, id: data.lith_id, color: data.color },
395
- onClick: (e) => {
396
- e.stopPropagation();
397
- if (matchLinks.lithology) {
398
- window.open(matchLinks.lithology + "/" + data.lith_id, "_blank");
399
- }
400
- },
401
- }),
402
- });
403
- }
404
-
405
- if (data.strat_name_id) {
406
- tag = h("div", [
407
- h(DataField, {
408
- label: "Stratigraphic name",
409
- value: h(LithologyTag, {
410
- data: { name: data.name, id: data.strat_name_id, color: data.color },
411
- onClick: (e) => {
412
- e.stopPropagation();
413
- if (matchLinks.strat_name) {
414
- window.open(
415
- matchLinks.strat_name + "/" + data.strat_name_id,
416
- "_blank",
417
- );
418
- }
419
- },
420
- }),
421
- }),
422
- h.if(data.concept_id)(DataField, {
423
- label: "Stratigraphic concept",
424
- value: h(LithologyTag, {
425
- data: { name: data.name, id: data.concept_id, color: data.color },
426
- onClick: (e) => {
427
- e.stopPropagation();
428
- if (matchLinks.concept) {
429
- window.open(matchLinks.concept + "/" + data.concept_id, "_blank");
430
- }
431
- },
432
- }),
433
- }),
434
- ]);
435
- }
436
-
437
- if (data.lith_att_id) {
438
- tag = h(DataField, {
439
- label: "Lithology attribute",
440
- value: h(LithologyTag, {
441
- data: { name: data.name, id: data.lith_att_id },
442
- onClick: (e) => {
443
- e.stopPropagation();
444
- if (matchLinks.lith_att) {
445
- window.open(matchLinks.lith_att + "/" + data.lith_att_id, "_blank");
446
- }
447
- },
448
- }),
449
- });
450
- }
451
-
452
- return h("div.match-container", [
453
- tag,
454
- h(Icon, {
455
- icon: "cross",
456
- color: "red",
457
- className: "close-btn",
458
- onClick: () => {
459
- dispatch({ type: "remove-match", payload: { id: nodeId } });
460
- },
461
- }),
462
- ]);
463
- }
@@ -10,7 +10,14 @@ import { ColorPicker } from "@macrostrat/data-sheet";
10
10
 
11
11
  const h = hyper.styled(styles);
12
12
 
13
- export function TypeList({ types, selected, dispatch, selectedNodes, tree }) {
13
+ export function TypeList({
14
+ types,
15
+ selected,
16
+ dispatch,
17
+ selectedNodes,
18
+ tree,
19
+ viewOnly,
20
+ }) {
14
21
  const [selectedType, setSelectedType] = useState(null);
15
22
  const isSelectedNodes = selectedNodes.length > 0;
16
23
  const darkMode = useInDarkMode();
@@ -32,6 +39,7 @@ export function TypeList({ types, selected, dispatch, selectedNodes, tree }) {
32
39
  selectedType,
33
40
  setSelectedType,
34
41
  dispatch,
42
+ viewOnly,
35
43
  tree,
36
44
  selectedNodes,
37
45
  selected,
@@ -39,7 +47,7 @@ export function TypeList({ types, selected, dispatch, selectedNodes, tree }) {
39
47
  }),
40
48
  ),
41
49
  ),
42
- h(AddType, { dispatch }),
50
+ h.if(!viewOnly)(AddType, { dispatch }),
43
51
  ]);
44
52
  }
45
53
 
@@ -206,6 +214,7 @@ function TypeTag({
206
214
  selectedNodes,
207
215
  selected,
208
216
  isSelectedNodes,
217
+ viewOnly,
209
218
  }) {
210
219
  const { color, name, id, description } = type;
211
220
  const darkMode = useInDarkMode();
@@ -276,7 +285,7 @@ function TypeTag({
276
285
  onClick: handleTagClick,
277
286
  style: {
278
287
  cursor:
279
- ids.length > 0 || (isSelectedNodes && !selectedType)
288
+ (ids.length > 0 || (isSelectedNodes && !selectedType)) && !viewOnly
280
289
  ? "pointer"
281
290
  : "",
282
291
  color: "black",
@@ -288,7 +297,7 @@ function TypeTag({
288
297
  },
289
298
  h("div.type-container", [
290
299
  h("div.type-name", name),
291
- h("div.icons", [
300
+ h.if(!viewOnly)("div.icons", [
292
301
  h(EditType, {
293
302
  dispatch,
294
303
  type,
@@ -1 +0,0 @@
1
- {"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AA1BA,4CAA6B,CAAC,eAAe,CAAC;AAC9C,4CAAqC,CAAC,uBAAuB,CAAC;AAC9D,4CAA8B,CAAC,gBAAgB,CAAC;AAChD,4CAAoC,CAAC,sBAAsB,CAAC;AAC5D,4CAAkC,CAAC,oBAAoB,CAAC;AACxD,4CAAgC,CAAC,kBAAkB,CAAC;AACpD,2CAAiC,CAAC,mBAAmB,CAAC;AACtD,4CAAuC,CAAC,yBAAyB,CAAC;AAClE,4CAAuC,CAAC,yBAAyB,CAAC;AAClE,4CAAkC,CAAC,oBAAoB,CAAC;AACxD,2CAA0C,CAAC,4BAA4B,CAAC;AACxE,4CAA+B,CAAC,iBAAiB,CAAC;AAClD,4CAA8B,CAAC,gBAAgB,CAAC;AAChD,4CAA0B,CAAC,YAAY,CAAC;AACxC,4CAAoC,CAAC,sBAAsB,CAAC;AAC5D,4CAA+B,CAAC,iBAAiB,CAAC;AAClD,4CAAyB,CAAC,WAAW,CAAC;AACtC,4CAA+B,CAAC,iBAAiB,CAAC;AAClD,4CAAsC,CAAC,wBAAwB,CAAC;AAChE,4CAAiC,CAAC,mBAAmB,CAAC;AACtD,4CAA6B,CAAC,eAAe,CAAC;AAC9C,4CAAmC,CAAC,qBAAqB,CAAC;AAC1D,2CAAgC,CAAC,kBAAkB,CAAC;AACpD,4CAA0B,CAAC,YAAY,CAAC;AACxC,4CAAmC,CAAC,qBAAqB,CAAC;AAC1D,4CAA8B,CAAC,gBAAgB,CAAC;AAChD,2CAA6B,CAAC,eAAe,CAAC","sources":["packages/feedback-components/src/feedback/feedback.module.sass"],"sourcesContent":[":root\n --text-line-height: 3em\n --main-extra-width: 200px\n\n.page-wrapper\n display: flex\n flex-direction: row\n position: relative\n gap: 2em\n align-items: flex-start // makes control-content lose stick\n\n.feedback-container\n flex: 4\n\n.control-panel\n flex: 1\n height: auto\n\n.control-content\n position: sticky\n top: 0\n\n.feedback-component\n position: relative\n width: 800px\n\n & > svg\n width: 800px\n\n.node\n cursor: pointer\n\ncircle\n cursor: pointer\n border: 1px solid black\n\n.selected\n border: 1px solid white\n \n.feedback-text\n margin-bottom: 2em\n\n.entity-panel\n position: relative\n max-height: 600px\n width: calc(100% - 2em)\n flex: 1\n min-height: 100px\n padding: 1em\n background: var(--panel-secondary-background-color)\n border-radius: 4px\n // Inset box shadow\n box-shadow: 0 0 0 1px var(--panel-border-color) inset\n\n.selection-tree\n margin: -1em 0\n padding: 1em 0\n \n.type-list\n display: grid\n grid-auto-flow: column\n grid-template-rows: repeat(10, auto)\n gap: 0.2em\n\n .type-tag\n padding: .2em .5em\n border-radius: .2em\n\n.description\n max-width: 300px\n padding: .5em\n\nmark\n border-radius: .2em\n cursor: pointer\n color: black !important\n\n[role=\"treeitem\"]\n width: auto !important\n\n.highlight\n cursor: pointer\n padding: .2em 0\n border-radius: .2em\n position: relative\n zIndex: 10\n\n.feedback-text-wrapper \n position: relative\n z-index: 0\n overflow: visible\n line-height: var(--text-line-height)\n\n.type-container\n display: flex\n justify-content: space-between\n align-items: center\n column-gap: 1em\n\n.add-type\n cursor: pointer\n display: flex\n justify-content: space-between\n padding: 0 .5em\n align-items: center\n\n p\n margin: 0\n\n.overlay-container\n height: 80vh\n width: 100vw\n display: flex\n justify-content: center\n align-items: center\n\n .add-type-overlay\n background-color: var(--secondary-color)\n padding: .5em 1em\n display: flex\n flex-direction: column\n gap: 1em\n border-radius: .2em\n\n .title\n display: flex\n justify-content: space-between\n align-items: center\n\n h2\n margin: 0\n\n .form-group\n display: flex\n gap: 3em\n\n .text-inputs\n display: flex\n flex-direction: column\n gap: 1em\n\n.icons\n display: flex\n gap: .25em\n\n.node-label\n fill: var(--text-emphasized-color)\n fontSize: 10px\n pointerEvents: none\n\n.match-item\n background-color: var(--background-color)\n color: var(--text-emphasized-color)\n padding: .1em .2em\n border-radius: .2em\n margin-bottom: 4px\n cursor: pointer\n\n.match-container\n display: flex\n justify-content: space-between\n align-items: center\n\n .close-btn\n cursor: pointer"],"names":[],"version":3,"file":"feedback-components.00434ff7.js.map"}
@@ -1 +0,0 @@
1
- {"mappings":"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","sources":["packages/feedback-components/src/feedback/text-visualizer.ts"],"sourcesContent":["import { AnnotateBlendTag } from \"react-text-annotate-blend\";\nimport { InternalEntity } from \"./types\";\nimport { TreeDispatch } from \"./edit-state\";\nimport styles from \"./feedback.module.sass\";\nimport hyper from \"@macrostrat/hyper\";\nimport { buildHighlights, getTagStyle } from \"../extractions\";\nimport { Highlight } from \"../extractions/types\";\nimport { useEffect, useRef } from \"react\";\nimport { Icon } from \"@blueprintjs/core\";\nimport { DataField, JSONView } from \"@macrostrat/ui-components\";\nimport { LithologyList, LithologyTag } from \"@macrostrat/data-components\";\n\nconst h = hyper.styled(styles);\n\nexport interface FeedbackTextProps {\n text: string;\n selectedNodes: number[];\n nodes: InternalEntity[];\n updateNodes: (nodes: string[]) => void;\n dispatch: TreeDispatch;\n lineHeight: string;\n allowOverlap?: boolean;\n matchLinks?: {\n lithology: string;\n strat_name: string;\n lith_att: string;\n };\n}\n\nfunction buildTags(\n highlights: Highlight[],\n selectedNodes: number[],\n): AnnotateBlendTag[] {\n let tags: AnnotateBlendTag[] = [];\n // If entity ID has already been seen, don't add it again\n const entities = new Set<number>();\n\n for (const highlight of highlights) {\n // Don't add multiply-linked entities multiple times\n if (entities.has(highlight.id)) continue;\n\n const highlighted = isHighlighted(highlight, selectedNodes);\n const active = isActive(highlight, selectedNodes);\n const tagStyle = getTagStyle(highlight.backgroundColor, {\n highlighted,\n active,\n });\n\n const tag = {\n color: tagStyle.color,\n tagStyle: {\n display: \"none\",\n },\n markStyle: {\n backgroundColor: tagStyle.backgroundColor,\n },\n ...highlight,\n backgroundColor: tagStyle.backgroundColor,\n };\n\n tags.push(tag);\n\n entities.add(highlight.id);\n }\n\n return tags;\n}\n\nfunction isActive(tag: Highlight, selectedNodes: number[]) {\n return selectedNodes.includes(tag.id);\n}\n\nfunction isHighlighted(tag: Highlight, selectedNodes: number[]) {\n if (selectedNodes.length === 0) return true;\n return (\n (selectedNodes.includes(tag.id) ||\n tag.parents?.some((d) => selectedNodes.includes(d))) ??\n false\n );\n}\n\nexport function FeedbackText(props: FeedbackTextProps) {\n // Convert input to tags\n const { text, selectedNodes, nodes, dispatch, allowOverlap, matchLinks } =\n props;\n const allTags: AnnotateBlendTag[] = buildTags(\n buildHighlights(nodes, null),\n selectedNodes,\n );\n\n return h(\n \"div.feedback-text-wrapper\",\n {\n tabIndex: 0,\n onKeyDown: (e) => {\n if (e.key === \"Backspace\") {\n dispatch({\n type: \"delete-node\",\n payload: { ids: selectedNodes },\n });\n }\n },\n },\n h(HighlightedText, {\n text,\n allTags,\n allowOverlap,\n dispatch,\n selectedNodes,\n matchLinks,\n }),\n );\n}\n\nfunction createTagFromSelection({\n container,\n}: {\n container: HTMLElement | null;\n}) {\n const selection = window.getSelection();\n if (\n !selection ||\n selection.isCollapsed ||\n selection.rangeCount === 0 ||\n !container\n )\n return null;\n\n const range = selection.getRangeAt(0);\n\n if (\n !container.contains(range.startContainer) ||\n !container.contains(range.endContainer)\n ) {\n return null;\n }\n\n const preRange = document.createRange();\n preRange.setStart(container, 0);\n preRange.setEnd(range.startContainer, range.startOffset);\n const start = preRange.toString().length;\n\n const selectedText = range.toString();\n const end = start + selectedText.length;\n\n return {\n start,\n end,\n text: selectedText,\n };\n}\n\nfunction addTag({ tag, dispatch, text, allTags, allowOverlap }) {\n let { start, end } = tag;\n // snap to text\n if (text[end - 1] != \" \") {\n // double clicking word overselects by one, shouldn't increase to next word\n while (start > 0 && /\\w/.test(text[start - 1])) {\n start--;\n }\n while (end < text.length && /\\w/.test(text[end])) {\n end++;\n }\n }\n\n let payload = { start, end, text: text.slice(start, end) };\n\n if (payload.text.trim() === \"\") {\n console.log(\"Blank tag found, ignoring\");\n return;\n }\n\n const duplicate = allTags.find(\n (t) =>\n t.start === payload.start &&\n (t.end === payload.end || t.end === payload.end - 1),\n );\n\n if (duplicate) {\n console.log(\"Duplicate tag found, ignoring\");\n return;\n }\n\n if (payload.text.endsWith(\" \")) {\n payload.text = payload.text.slice(0, -1);\n payload.end -= 1;\n }\n\n const inside = allTags.some(\n (t) => t.start <= payload.start && t.end >= payload.end,\n );\n\n const overlap = allTags.some(\n (t) => t.start < payload.end && t.end > payload.start,\n );\n\n if ((inside || overlap) && !allowOverlap) {\n console.log(\"Tag is inside another tag, ignoring\");\n return;\n }\n\n dispatch({ type: \"create-node\", payload });\n}\n\nfunction nestHighlights(text: string, tags: AnnotateBlendTag[]) {\n const events: Array<{\n pos: number;\n type: \"start\" | \"end\";\n tag: AnnotateBlendTag;\n }> = [];\n\n for (const tag of tags) {\n events.push({ pos: tag.start, type: \"start\", tag });\n events.push({ pos: tag.end, type: \"end\", tag });\n }\n\n events.sort((a, b) => {\n if (a.pos !== b.pos) return a.pos - b.pos;\n if (a.type === \"end\" && b.type === \"start\") return -1;\n if (a.type === \"start\" && b.type === \"end\") return 1;\n return 0;\n });\n\n const root = { children: [], textStart: 0 };\n const stack = [root];\n let lastPos = 0;\n\n for (const { pos, type, tag } of events) {\n const parent = stack[stack.length - 1];\n\n if (pos > lastPos) {\n const slice = text.slice(lastPos, pos);\n parent.children.push(slice);\n }\n\n if (type === \"start\") {\n const newNode = { tag, children: [], textStart: pos };\n parent.children.push(newNode);\n stack.push(newNode);\n } else {\n stack.pop();\n }\n\n lastPos = pos;\n }\n\n if (lastPos < text.length) {\n stack[stack.length - 1].children.push(text.slice(lastPos));\n }\n\n return root;\n}\n\nfunction renderNode(\n node: any,\n dispatch: TreeDispatch,\n selectedNodes: number[],\n parentSelected: boolean,\n matchLinks?: {\n lithology: string;\n strat_name: string;\n lith_att: string;\n },\n): any {\n if (typeof node === \"string\") return node;\n\n const { tag, children } = node;\n const isSelected = selectedNodes?.includes(tag.id);\n const showBorder = selectedNodes.length === 0 || isSelected;\n\n const style = {\n ...tag,\n zIndex: parentSelected ? -1 : 1,\n border: \"1px solid \" + (showBorder ? tag.color : \"transparent\"),\n margin: \"-1px\",\n };\n\n let moveText = [];\n if (isSelected) {\n for (const key in children) {\n if (Object.prototype.hasOwnProperty.call(children, key)) {\n const child = children[key];\n if (child?.tag) {\n moveText.push(child.children[0]);\n } else {\n moveText.push(child);\n }\n }\n }\n }\n\n return h(\n \"span\",\n {\n onMouseEnter: (e: MouseEvent) => {\n e.stopPropagation();\n },\n className: \"highlight\",\n style,\n onClick: (e: MouseEvent) => {\n e.stopPropagation();\n if (\n e.ctrlKey ||\n e.metaKey ||\n (selectedNodes[0] === tag.id && selectedNodes.length === 1)\n ) {\n // Toggle selection on ctrl/cmd click or when node is only selected node\n e.stopPropagation();\n dispatch({\n type: \"toggle-node-selected\",\n payload: { ids: [tag.id] },\n });\n } else if (e.shiftKey && selectedNodes.length > 0) {\n // Select range from last selected node to this one\n const lastSelected = selectedNodes[selectedNodes.length - 1];\n\n dispatch({\n type: \"select-range\",\n payload: { ids: [lastSelected, tag.id] },\n });\n } else {\n dispatch({\n type: \"select-node\",\n payload: { ids: [tag.id] },\n });\n }\n },\n },\n isSelected\n ? moveText.flat()\n : children.map((child: any, i: number) =>\n renderNode(child, dispatch, selectedNodes, isSelected, matchLinks),\n ),\n );\n}\n\nexport function HighlightedText(props: {\n text: string;\n allTags: AnnotateBlendTag[];\n lineHeight: string;\n allowOverlap?: boolean;\n dispatch: TreeDispatch;\n selectedNodes: number[];\n matchLinks?: {\n lithology: string;\n strat_name: string;\n lith_att: string;\n };\n}) {\n const {\n text,\n allTags = [],\n dispatch,\n selectedNodes,\n allowOverlap,\n matchLinks,\n } = props;\n\n const tree = nestHighlights(text, allTags);\n\n const spanRef = useRef<HTMLSpanElement>(null);\n\n useEffect(() => {\n const handleMouseUp = () => {\n const tag = createTagFromSelection({ container: spanRef.current });\n if (!tag) return;\n addTag({ tag, dispatch, text, allTags, allowOverlap });\n };\n\n document.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [text, allTags, dispatch, allowOverlap]);\n\n return h(\n \"span\",\n { ref: spanRef },\n tree.children.map((child: any, i: number) =>\n renderNode(child, dispatch, selectedNodes, false, matchLinks),\n ),\n );\n}\n\nexport function Match({ data, matchLinks, dispatch, nodeId }) {\n if (!data || Object.keys(data).length === 0) return;\n\n let tag = h(JSONView, { data });\n\n if (data.lith_id) {\n tag = h(DataField, {\n label: \"Lithology\",\n value: h(LithologyTag, {\n data: { name: data.name, id: data.lith_id, color: data.color },\n onClick: (e) => {\n e.stopPropagation();\n if (matchLinks.lithology) {\n window.open(matchLinks.lithology + \"/\" + data.lith_id, \"_blank\");\n }\n },\n }),\n });\n }\n\n if (data.strat_name_id) {\n tag = h(\"div\", [\n h(DataField, {\n label: \"Stratigraphic name\",\n value: h(LithologyTag, {\n data: { name: data.name, id: data.strat_name_id, color: data.color },\n onClick: (e) => {\n e.stopPropagation();\n if (matchLinks.strat_name) {\n window.open(\n matchLinks.strat_name + \"/\" + data.strat_name_id,\n \"_blank\",\n );\n }\n },\n }),\n }),\n h.if(data.concept_id)(DataField, {\n label: \"Stratigraphic concept\",\n value: h(LithologyTag, {\n data: { name: data.name, id: data.concept_id, color: data.color },\n onClick: (e) => {\n e.stopPropagation();\n if (matchLinks.concept) {\n window.open(matchLinks.concept + \"/\" + data.concept_id, \"_blank\");\n }\n },\n }),\n }),\n ]);\n }\n\n if (data.lith_att_id) {\n tag = h(DataField, {\n label: \"Lithology attribute\",\n value: h(LithologyTag, {\n data: { name: data.name, id: data.lith_att_id },\n onClick: (e) => {\n e.stopPropagation();\n if (matchLinks.lith_att) {\n window.open(matchLinks.lith_att + \"/\" + data.lith_att_id, \"_blank\");\n }\n },\n }),\n });\n }\n\n return h(\"div.match-container\", [\n tag,\n h(Icon, {\n icon: \"cross\",\n color: \"red\",\n className: \"close-btn\",\n onClick: () => {\n dispatch({ type: \"remove-match\", payload: { id: nodeId } });\n },\n }),\n ]);\n}\n"],"names":[],"version":3,"file":"feedback-components.1c15f37f.js.map"}
@@ -1 +0,0 @@
1
- {"mappings":"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","sources":["packages/feedback-components/src/feedback/index.ts"],"sourcesContent":["import styles from \"./feedback.module.sass\";\nimport hyper from \"@macrostrat/hyper\";\n\nimport { Tree, TreeApi } from \"react-arborist\";\nimport Node from \"./node\";\nimport { FeedbackText } from \"./text-visualizer\";\nimport type { InternalEntity, TreeData } from \"./types\";\nimport type { Entity } from \"../extractions\";\nimport { getTagStyle, ModelInfo } from \"../extractions\";\nimport {\n TreeDispatchContext,\n treeToGraph,\n useUpdatableTree,\n ViewMode,\n} from \"./edit-state\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n ButtonGroup,\n Card,\n SegmentedControl,\n Divider,\n} from \"@blueprintjs/core\";\nimport { OmniboxSelector } from \"./type-selector\";\nimport {\n CancelButton,\n ErrorBoundary,\n FlexRow,\n SaveButton,\n} from \"@macrostrat/ui-components\";\nimport useElementDimensions from \"use-element-dimensions\";\nimport { GraphView } from \"./graph\";\n\nimport { Matches } from \"./matches\";\nimport { TypeList } from \"./typelist\";\n\nexport type { GraphData } from \"./edit-state\";\nexport { treeToGraph } from \"./edit-state\";\nexport type { TreeData } from \"./types\";\n\nconst h = hyper.styled(styles);\n\nfunction setsAreTheSame<T>(a: Set<T>, b: Set<T>) {\n if (a.size !== b.size) return false;\n for (const item of a) {\n if (!b.has(item)) return false;\n }\n return true;\n}\n\nexport function FeedbackComponent({\n entities = [],\n text,\n model,\n entityTypes,\n matchComponent,\n onSave,\n allowOverlap,\n matchLinks,\n}) {\n // Get the input arguments\n const [state, dispatch] = useUpdatableTree(\n entities.map(processEntity) as any,\n entityTypes,\n );\n const [match, setMatchLinks] = useState(matchLinks || {});\n\n const {\n selectedNodes,\n tree,\n selectedEntityType,\n isSelectingEntityType,\n entityTypesMap,\n } = state;\n\n const [{ width, height }, ref] = useElementDimensions();\n\n return h(\"div.page-wrapper\", [\n h(\n \"div.feedback-container\",\n h(TreeDispatchContext.Provider, { value: dispatch }, [\n h(\n ErrorBoundary,\n {\n description:\n \"An error occurred while rendering the feedback text component.\",\n },\n h(FeedbackText, {\n text,\n dispatch,\n // @ts-ignore\n nodes: tree,\n selectedNodes,\n allowOverlap,\n matchLinks: match,\n }),\n ),\n h(\n FlexRow,\n { alignItems: \"baseline\", justifyContent: \"space-between\" },\n [\n h(ModelInfo, { data: model }),\n h(SegmentedControl, {\n options: [\n { label: \"Tree\", value: \"tree\" },\n { label: \"Graph\", value: \"graph\" },\n ],\n value: state.viewMode,\n small: true,\n onValueChange(value: ViewMode) {\n console.log(\"Setting view mode\", value);\n dispatch({ type: \"set-view-mode\", payload: value });\n },\n }),\n ],\n ),\n h(\n \"div.entity-panel\",\n {\n ref,\n },\n [\n h.if(state.viewMode == \"tree\")(ManagedSelectionTree, {\n selectedNodes,\n dispatch,\n tree,\n width,\n height,\n matchComponent,\n }),\n h.if(state.viewMode == \"graph\")(GraphView, {\n tree,\n width,\n height,\n dispatch,\n selectedNodes,\n }),\n ],\n ),\n ]),\n ),\n h(Card, { className: \"control-panel\" }, [\n h(\"div.control-content\", [\n h(\n ButtonGroup,\n {\n vertical: true,\n fill: true,\n minimal: true,\n alignText: \"left\",\n },\n [\n h(\n CancelButton,\n {\n icon: \"trash\",\n disabled: state.initialTree == state.tree,\n onClick() {\n dispatch({ type: \"reset\" });\n },\n },\n \"Reset\",\n ),\n h(\n SaveButton,\n {\n onClick() {\n onSave(state.tree);\n },\n disabled: state.initialTree == state.tree,\n },\n \"Save\",\n ),\n ],\n ),\n h(Matches, {\n match,\n setMatchLinks,\n matchLinks,\n selectedNodes,\n tree,\n dispatch,\n }),\n h(Divider),\n h(EntityTypeSelector, {\n entityTypes: entityTypesMap,\n selected: selectedEntityType,\n onChange(payload) {\n dispatch({ type: \"select-entity-type\", payload });\n },\n dispatch,\n tree,\n selectedNodes,\n isOpen: isSelectingEntityType,\n setOpen: (isOpen: boolean) =>\n dispatch({\n type: \"toggle-entity-type-selector\",\n payload: isOpen,\n }),\n }),\n ]),\n ]),\n ]);\n}\n\nfunction processEntity(entity: Entity): InternalEntity {\n // @ts-ignore\n return {\n ...entity,\n // @ts-ignore\n term_type: entity.type.name,\n txt_range: [entity.indices],\n children: entity.children?.map(processEntity) ?? [],\n };\n}\n\nfunction EntityTypeSelector({\n entityTypes,\n selected,\n isOpen,\n setOpen,\n onChange,\n tree,\n dispatch,\n selectedNodes = [],\n}) {\n // Show all entity types when selected is null\n const _selected = selected != null ? selected : undefined;\n const [inputValue, setInputValue] = useState(\"\");\n const types = Array.from(entityTypes.values());\n\n const items =\n inputValue !== \"\"\n ? types.filter((d) =>\n d.name.toLowerCase().includes(inputValue.toLowerCase()),\n )\n : types;\n\n return h(\"div.entity-type-selector\", [\n h(TypeList, {\n types: entityTypes,\n selected: _selected,\n dispatch,\n selectedNodes,\n tree,\n }),\n h(OmniboxSelector, {\n isOpen,\n items,\n selectedItem: _selected,\n onSelectItem(item) {\n setOpen(false);\n onChange(item);\n },\n onQueryChange(query) {\n setInputValue(query);\n },\n onClose() {\n setOpen(false);\n },\n }),\n ]);\n}\n\nfunction countNodes(tree) {\n if (!tree) return 0;\n let count = 0;\n\n function recurse(nodes) {\n for (const node of nodes) {\n count++;\n if (node.children && Array.isArray(node.children)) {\n recurse(node.children);\n }\n }\n }\n\n recurse(tree);\n return count;\n}\n\nfunction ManagedSelectionTree(props) {\n const { selectedNodes, dispatch, tree, height, width, matchComponent } =\n props;\n\n const ref = useRef<TreeApi<TreeData>>();\n // Use a ref to track clicks (won't cause rerender)\n const clickedRef = useRef(false);\n\n const _Node = useCallback(\n (props) => h(Node, { ...props, matchComponent }),\n [matchComponent],\n );\n\n // Update Tree selection when selectedNodes change\n useEffect(() => {\n if (ref.current == null) return;\n\n const selection = new Set(selectedNodes.map((d) => d.toString()));\n const currentSelection = ref.current.selectedIds;\n if (setsAreTheSame(selection, currentSelection)) return;\n\n ref.current.setSelection({\n ids: selectedNodes.map((d) => d.toString()),\n anchor: null,\n mostRecent: null,\n });\n }, [selectedNodes]);\n\n // Mark clicked when user clicks inside the tree container\n function handleClick() {\n clickedRef.current = true;\n }\n\n const ctrlPressedRef = useRef(false);\n\n useEffect(() => {\n const down = (e) => {\n if (e.ctrlKey || e.metaKey) ctrlPressedRef.current = true;\n };\n const up = () => (ctrlPressedRef.current = false);\n\n window.addEventListener(\"keydown\", down);\n window.addEventListener(\"keyup\", up);\n return () => {\n window.removeEventListener(\"keydown\", down);\n window.removeEventListener(\"keyup\", up);\n };\n }, []);\n\n const handleSelect = useCallback(\n (nodes) => {\n if (!clickedRef.current) return;\n clickedRef.current = false;\n const isMultiSelect = ctrlPressedRef.current;\n\n let ids = nodes.map((d) => parseInt(d.id));\n\n if (isMultiSelect) {\n dispatch({ type: \"toggle-node-selected\", payload: { ids } });\n } else {\n if (ids.length === 1 && ids[0] === selectedNodes[0]) {\n ids = [];\n }\n\n dispatch({ type: \"select-node\", payload: { ids } });\n }\n },\n [selectedNodes, dispatch],\n );\n\n return h(\n \"div.selection-tree-wrapper\",\n { onPointerDown: handleClick },\n h(Tree, {\n className: \"selection-tree\",\n height,\n width,\n ref,\n data: tree,\n onMove({ dragIds, parentId, index }) {\n dispatch({\n type: \"move-node\",\n payload: {\n dragIds: dragIds.map((d) => parseInt(d)),\n parentId: parentId ? parseInt(parentId) : null,\n index,\n },\n });\n },\n onDelete({ ids }) {\n dispatch({\n type: \"delete-node\",\n payload: { ids: ids.map((d) => parseInt(d)) },\n });\n },\n onSelect: handleSelect,\n children: _Node,\n idAccessor(d) {\n return d.id.toString();\n },\n }),\n );\n}\n"],"names":[],"version":3,"file":"feedback-components.204f7d2b.js.map"}