@macrostrat/feedback-components 1.0.0 → 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 (86) hide show
  1. package/CHANGELOG.md +13 -5
  2. package/dist/esm/feedback-components.4359bc80.js +70 -0
  3. package/dist/esm/feedback-components.4359bc80.js.map +1 -0
  4. package/dist/{extractions.54be85f8.js → esm/feedback-components.5df2a926.js} +52 -24
  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/{main.module.ca3db294.js → esm/feedback-components.6d32ee91.js} +1 -1
  9. package/dist/{main.module.ca3db294.js.map → esm/feedback-components.6d32ee91.js.map} +1 -1
  10. package/dist/esm/feedback-components.7cd9b6cc.js +114 -0
  11. package/dist/esm/feedback-components.7cd9b6cc.js.map +1 -0
  12. package/dist/{node.30d0b8c3.js → esm/feedback-components.87533431.js} +12 -7
  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/{type-selector.e75dd247.js → esm/feedback-components.ad9f284e.js} +11 -10
  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/{edit-state.e8edb13a.js → esm/feedback-components.bf5f7cf7.js} +105 -14
  21. package/dist/esm/feedback-components.bf5f7cf7.js.map +1 -0
  22. package/dist/{main.module.f9f92ece.css → esm/feedback-components.bf93773c.css} +1 -1
  23. package/dist/{main.module.f9f92ece.css.map → esm/feedback-components.bf93773c.css.map} +1 -1
  24. package/dist/{main.module.d6508c0e.css → esm/feedback-components.e273ed5b.css} +1 -1
  25. package/dist/{main.module.d6508c0e.css.map → esm/feedback-components.e273ed5b.css.map} +1 -1
  26. package/dist/{main.module.21bbfaf4.js → esm/feedback-components.f9850d85.js} +1 -1
  27. package/dist/{main.module.21bbfaf4.js.map → esm/feedback-components.f9850d85.js.map} +1 -1
  28. package/dist/{index.d.ts → esm/index.d.ts} +38 -13
  29. package/dist/esm/index.d.ts.map +1 -0
  30. package/dist/{index.js → 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/feedback-components.794f429b.js +2 -0
  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/feedback-components.83c21466.css +2 -0
  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/feedback-components.9eb1d41a.css +2 -0
  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 +2 -0
  58. package/dist/node/index.js.map +1 -0
  59. package/package.json +29 -15
  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/edit-state.e8edb13a.js.map +0 -1
  70. package/dist/extractions.54be85f8.js.map +0 -1
  71. package/dist/feedback.46c2b5c4.js +0 -252
  72. package/dist/feedback.46c2b5c4.js.map +0 -1
  73. package/dist/feedback.module.7e16830e.css +0 -44
  74. package/dist/feedback.module.7e16830e.css.map +0 -1
  75. package/dist/feedback.module.c28cbac7.js +0 -28
  76. package/dist/feedback.module.c28cbac7.js.map +0 -1
  77. package/dist/graph.cb42b871.js +0 -83
  78. package/dist/graph.cb42b871.js.map +0 -1
  79. package/dist/index.d.ts.map +0 -1
  80. package/dist/node.30d0b8c3.js.map +0 -1
  81. package/dist/text-visualizer.77af0d24.js +0 -101
  82. package/dist/text-visualizer.77af0d24.js.map +0 -1
  83. package/dist/type-selector.e75dd247.js.map +0 -1
  84. package/stories/feedback.stories.ts +0 -40
  85. package/stories/test-data.ts +0 -330
  86. /package/dist/{index.js.map → esm/index.js.map} +0 -0
@@ -5,6 +5,7 @@ import type { Entity, EntityExt, Highlight, EntityType } from "./types";
5
5
  import { CSSProperties } from "react";
6
6
  import { asChromaColor } from "@macrostrat/color-utils";
7
7
  import hyper from "@macrostrat/hyper";
8
+ import { useDarkMode } from "@macrostrat/ui-components";
8
9
 
9
10
  export type { Entity, EntityExt };
10
11
 
@@ -12,7 +13,7 @@ const h = hyper.styled(styles);
12
13
 
13
14
  export function buildHighlights(
14
15
  entities: EntityExt[],
15
- parent: EntityExt | null
16
+ parent: EntityExt | null,
16
17
  ): Highlight[] {
17
18
  let highlights = [];
18
19
  let parents = [];
@@ -25,8 +26,8 @@ export function buildHighlights(
25
26
  start: entity.indices[0],
26
27
  end: entity.indices[1],
27
28
  text: entity.name,
28
- backgroundColor: entity.type.color ?? "#ddd",
29
- tag: entity.type.name,
29
+ backgroundColor: entity.type?.color,
30
+ tag: entity.type?.name ?? "lith",
30
31
  id: entity.id,
31
32
  parents,
32
33
  });
@@ -40,17 +41,21 @@ export function enhanceData(extractionData, models, entityTypes) {
40
41
  ...extractionData,
41
42
  model: models.get(extractionData.model_id),
42
43
  entities: extractionData.entities?.map((d) =>
43
- enhanceEntity(d, entityTypes)
44
+ enhanceEntity(d, entityTypes),
44
45
  ),
45
46
  };
46
47
  }
47
48
 
48
49
  export function getTagStyle(
49
50
  baseColor: string,
50
- options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean }
51
+ options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean },
51
52
  ): CSSProperties {
52
- const _baseColor = asChromaColor(baseColor ?? "#ddd");
53
- const { highlighted = true, inDarkMode = false, active = false } = options;
53
+ const _baseColor = asChromaColor(baseColor ?? "#fff");
54
+ const {
55
+ highlighted = true,
56
+ inDarkMode = useDarkMode().isEnabled,
57
+ active = false,
58
+ } = options;
54
59
 
55
60
  let mixAmount = highlighted ? 0.8 : 0.5;
56
61
  let backgroundAlpha = highlighted ? 0.8 : 0.2;
@@ -60,27 +65,38 @@ export function getTagStyle(
60
65
  backgroundAlpha = 1;
61
66
  }
62
67
 
63
- const mixTarget = inDarkMode ? "white" : "black";
68
+ const mixTarget = "black";
64
69
 
65
- const color = _baseColor.mix(mixTarget, mixAmount).css();
70
+ const color = active ? "#000" : _baseColor.mix(mixTarget, mixAmount).hex();
66
71
  const borderColor = highlighted
67
- ? _baseColor.mix(mixTarget, mixAmount / 2).css()
72
+ ? _baseColor.mix(mixTarget, mixAmount / 1.1).hex()
68
73
  : "transparent";
69
74
 
75
+ let backgroundColor = active
76
+ ? _baseColor.alpha(backgroundAlpha).hex()
77
+ : normalizeColor(_baseColor.alpha(backgroundAlpha).hex());
78
+
79
+ // handle white backgrounds in light mode
80
+ if (!inDarkMode && backgroundColor === "#ffffff") {
81
+ console.log("Adjusting background color for light mode:", backgroundColor);
82
+ backgroundColor = "#f0f0f0";
83
+ }
84
+
70
85
  return {
71
86
  color,
72
- backgroundColor: _baseColor.alpha(backgroundAlpha).css(),
87
+ backgroundColor,
73
88
  boxSizing: "border-box",
74
89
  borderStyle: "solid",
75
90
  borderColor,
76
- borderWidth: "1px",
91
+ borderWidth: "1.5px",
77
92
  fontWeight: active ? "bold" : "normal",
93
+ fontSize: "0.9em",
78
94
  };
79
95
  }
80
96
 
81
97
  function enhanceEntity(
82
98
  entity: Entity,
83
- entityTypes: Map<number, EntityType>
99
+ entityTypes: Map<number, EntityType>,
84
100
  ): EntityExt {
85
101
  return {
86
102
  ...entity,
@@ -90,8 +106,8 @@ function enhanceEntity(
90
106
  }
91
107
 
92
108
  function addColor(entityType: EntityType, match = false) {
93
- const color = asChromaColor(entityType.color ?? "#ddd").brighten(
94
- match ? 1 : 2
109
+ const color = asChromaColor(entityType.color ?? "#fff").brighten(
110
+ match ? 1 : 2,
95
111
  );
96
112
 
97
113
  return { ...entityType, color: color.css() };
@@ -113,7 +129,7 @@ export function ExtractionContext({
113
129
  h(ModelInfo, { data: data.model }),
114
130
  h(
115
131
  "ul.entities",
116
- data.entities.map((d) => h(ExtractionInfo, { data: d, matchComponent }))
132
+ data.entities.map((d) => h(ExtractionInfo, { data: d, matchComponent })),
117
133
  ),
118
134
  ]);
119
135
  }
@@ -140,15 +156,16 @@ export function EntityTag({
140
156
  matchComponent = null,
141
157
  }: EntityTagProps) {
142
158
  const { name, type, match } = data;
159
+
143
160
  const className = classNames(
144
161
  {
145
162
  matched: match != null,
146
- type: data.type.name,
163
+ type: data.type?.name ?? "lith",
147
164
  },
148
- "entity"
165
+ "entity",
149
166
  );
150
167
 
151
- const style = getTagStyle(type.color ?? "#aaaaaa", { highlighted, active });
168
+ const style = getTagStyle(type?.color, { highlighted, active });
152
169
 
153
170
  let _matchLink = null;
154
171
  if (match != null && matchComponent != null) {
@@ -168,7 +185,7 @@ export function EntityTag({
168
185
  }
169
186
  },
170
187
  },
171
- [type.name, _matchLink]
188
+ [type?.name, _matchLink],
172
189
  ),
173
190
  ]);
174
191
  }
@@ -187,7 +204,7 @@ function ExtractionInfo({
187
204
  h.if(children.length > 0)([
188
205
  h(
189
206
  "ul.children",
190
- children.map((d) => h(ExtractionInfo, { data: d, matchComponent }))
207
+ children.map((d) => h(ExtractionInfo, { data: d, matchComponent })),
191
208
  ),
192
209
  ]),
193
210
  ]);
@@ -217,3 +234,41 @@ function HighlightedText(props: { text: string; highlights: Highlight[] }) {
217
234
  parts.push(text.slice(start));
218
235
  return h("span", parts);
219
236
  }
237
+
238
+ function normalizeColor(hex8) {
239
+ const background = useDarkMode().isEnabled ? "#000000" : "#ffffff";
240
+
241
+ const r = parseInt(hex8.slice(1, 3), 16);
242
+ const g = parseInt(hex8.slice(3, 5), 16);
243
+ const b = parseInt(hex8.slice(5, 7), 16);
244
+ const a = parseInt(hex8.slice(7, 9), 16) / 255;
245
+
246
+ const bgR = parseInt(background.slice(1, 3), 16);
247
+ const bgG = parseInt(background.slice(3, 5), 16);
248
+ const bgB = parseInt(background.slice(5, 7), 16);
249
+
250
+ const blend = (fg, bg) => Math.round((1 - a) * bg + a * fg);
251
+
252
+ const blendedR = blend(r, bgR);
253
+ const blendedG = blend(g, bgG);
254
+ const blendedB = blend(b, bgB);
255
+
256
+ return (
257
+ "#" +
258
+ blendedR.toString(16).padStart(2, "0") +
259
+ blendedG.toString(16).padStart(2, "0") +
260
+ blendedB.toString(16).padStart(2, "0")
261
+ );
262
+ }
263
+
264
+ function isHighlighted(id: number, selectedNodes: number[], nodes: any[]) {
265
+ if (selectedNodes?.length === 0) return true;
266
+ return (
267
+ selectedNodes?.includes(id) ||
268
+ nodes?.some(
269
+ (node) =>
270
+ selectedNodes?.includes(node.id) &&
271
+ node.children.some((child) => child.id === id),
272
+ )
273
+ );
274
+ }
@@ -1,4 +1,9 @@
1
- type EntityType = { name: string; color: string; id: number };
1
+ type EntityType = {
2
+ name: string;
3
+ color: string;
4
+ id: number;
5
+ description?: string;
6
+ };
2
7
  type Match = any;
3
8
 
4
9
  export interface Entity {
@@ -38,15 +38,25 @@ type TreeAction =
38
38
  | { type: "select-entity-type"; payload: EntityType }
39
39
  | { type: "toggle-entity-type-selector"; payload?: boolean | null }
40
40
  | { type: "deselect" }
41
- | { type: "reset" };
41
+ | { type: "reset" }
42
+ | { type: "delete-entity-type"; payload: { id: number } }
43
+ | {
44
+ type: "add-entity-type";
45
+ payload: { name: string; description: string; color: string };
46
+ }
47
+ | {
48
+ type: "update-entity-type";
49
+ payload: { id: number; name: string; description: string; color: string };
50
+ };
42
51
 
43
52
  export type TreeDispatch = Dispatch<TreeAction>;
44
53
 
45
54
  export function useUpdatableTree(
46
55
  initialTree: TreeData[],
47
- entityTypes: Map<number, EntityType>
56
+ entityTypes: Map<number, EntityType>,
48
57
  ): [TreeState, TreeDispatch] {
49
58
  // Get the first entity type
59
+ // issue: grabs second entity instead of selected one
50
60
  const type = entityTypes.values().next().value;
51
61
 
52
62
  return useReducer(treeReducer, {
@@ -72,13 +82,63 @@ export function useTreeDispatch() {
72
82
  }
73
83
 
74
84
  function treeReducer(state: TreeState, action: TreeAction) {
75
- console.log(action);
76
85
  switch (action.type) {
86
+ case "add-entity-type": {
87
+ // Add a new entity type to the map
88
+ const { name, description, color } = action.payload;
89
+ const newId = state.lastInternalId - 1;
90
+ const newType: EntityType = {
91
+ id: newId,
92
+ name,
93
+ description: description === "" ? null : description,
94
+ color,
95
+ };
96
+
97
+ const newEntityTypesMap = new Map(state.entityTypesMap);
98
+ newEntityTypesMap.set(newId, newType);
99
+
100
+ return {
101
+ ...state,
102
+ entityTypesMap: newEntityTypesMap,
103
+ selectedEntityType: newType,
104
+ lastInternalId: newId,
105
+ };
106
+ }
107
+ case "update-entity-type": {
108
+ // Update an existing entity type in the map
109
+ const { id, name, description, color } = action.payload;
110
+ const newEntityTypesMap = new Map(state.entityTypesMap);
111
+ const oldType = newEntityTypesMap.get(id);
112
+
113
+ if (!oldType) {
114
+ console.warn(`Entity type with id ${id} not found`);
115
+ return state;
116
+ }
117
+
118
+ const updatedType: EntityType = {
119
+ ...oldType,
120
+ name,
121
+ description: description === "" ? null : description,
122
+ color,
123
+ };
124
+
125
+ newEntityTypesMap.set(id, updatedType);
126
+
127
+ // Update the tree to reflect the new type
128
+ const newTree = updateTreeTypes(state.tree, oldType, updatedType);
129
+
130
+ return {
131
+ ...state,
132
+ tree: newTree,
133
+ entityTypesMap: newEntityTypesMap,
134
+ selectedEntityType: updatedType,
135
+ };
136
+ }
77
137
  case "move-node":
78
138
  // For each node in the tree, if the node is in the dragIds, remove it from the tree and collect it
79
139
  const [newTree, removedNodes] = removeNodes(
80
140
  state.tree,
81
- action.payload.dragIds
141
+ action.payload.dragIds,
82
142
  );
83
143
 
84
144
  let keyPath: (number | "children")[] = [];
@@ -97,7 +157,7 @@ function treeReducer(state: TreeState, action: TreeAction) {
97
157
  // For each node in the tree, if the node is in the ids, remove it from the tree
98
158
  const [newTree2, _removedNodes] = removeNodes(
99
159
  state.tree,
100
- action.payload.ids
160
+ action.payload.ids,
101
161
  );
102
162
  // Get children of the removed nodes
103
163
  // If children are not present elsewhere in the tree, insert them
@@ -112,21 +172,39 @@ function treeReducer(state: TreeState, action: TreeAction) {
112
172
  ...state,
113
173
  tree: [...newTree2, ...children],
114
174
  selectedNodes: state.selectedNodes.filter(
115
- (id) => !action.payload.ids.includes(id)
175
+ (id) => !action.payload.ids.includes(id),
116
176
  ),
117
177
  };
118
178
  case "select-node":
119
179
  const { ids } = action.payload;
120
- return { ...state, selectedNodes: ids };
180
+
181
+ const type =
182
+ action.payload.ids.length > 0
183
+ ? findNodeById(state.tree, ids[0])?.type
184
+ : null;
185
+
186
+ console.log("Selecting nodes:", ids, "Type:", type);
187
+
188
+ return { ...state, selectedNodes: ids, selectedEntityType: type };
121
189
  // otherwise fall through to toggle-node-selected for a single ID
122
190
  case "toggle-node-selected":
123
191
  const nodesToAdd = action.payload.ids.filter(
124
- (id) => !state.selectedNodes.includes(id)
192
+ (id) => !state.selectedNodes.includes(id),
125
193
  );
126
194
  const nodesToKeep = state.selectedNodes.filter(
127
- (id) => !action.payload.ids.includes(id)
195
+ (id) => !action.payload.ids.includes(id),
128
196
  );
129
- return { ...state, selectedNodes: [...nodesToKeep, ...nodesToAdd] };
197
+
198
+ const newType =
199
+ action.payload.ids.length > 0
200
+ ? findNodeById(state.tree, action.payload.ids[0])?.type
201
+ : null;
202
+
203
+ return {
204
+ ...state,
205
+ selectedNodes: [...nodesToKeep, ...nodesToAdd],
206
+ selectedEntityType: newType,
207
+ };
130
208
 
131
209
  case "create-node":
132
210
  const newId = state.lastInternalId - 1;
@@ -146,6 +224,25 @@ function treeReducer(state: TreeState, action: TreeAction) {
146
224
  lastInternalId: newId,
147
225
  };
148
226
 
227
+ case "delete-entity-type": {
228
+ // Remove the entity type from the map
229
+ console.log("Deleting entity type:", action.payload.id);
230
+ const { id } = action.payload;
231
+ const newEntityTypesMap = new Map(state.entityTypesMap);
232
+ const oldType = newEntityTypesMap.get(id);
233
+ newEntityTypesMap.delete(id);
234
+
235
+ const defaultType = newEntityTypesMap.values().next().value;
236
+ const newTree = updateTreeTypes(state.tree, oldType, defaultType);
237
+
238
+ return {
239
+ ...state,
240
+ tree: newTree,
241
+ entityTypesMap: newEntityTypesMap,
242
+ selectedNodes: [],
243
+ };
244
+ }
245
+
149
246
  /** Entity type selection */
150
247
  case "toggle-entity-type-selector":
151
248
  return {
@@ -197,7 +294,7 @@ function nodeIsInTree(tree: TreeData[], id: number): boolean {
197
294
 
198
295
  function buildNestedSpec(
199
296
  keyPath: (number | "children")[],
200
- innerSpec: Spec<any>
297
+ innerSpec: Spec<any>,
201
298
  ): Spec<TreeData[]> {
202
299
  // Build a nested object from a key path
203
300
 
@@ -211,7 +308,7 @@ function buildNestedSpec(
211
308
 
212
309
  function findNode(
213
310
  tree: TreeData[],
214
- id: number
311
+ id: number,
215
312
  ): (number | "children")[] | null {
216
313
  // Find the index of the node with the given id in the tree, returning the key path
217
314
  for (let i = 0; i < tree.length; i++) {
@@ -229,7 +326,7 @@ function findNode(
229
326
 
230
327
  function removeNodes(
231
328
  tree: TreeData[],
232
- ids: number[]
329
+ ids: number[],
233
330
  ): [TreeData[], TreeData[]] {
234
331
  /** Remove nodes with the given ids from the tree and return the new tree and the removed nodes */
235
332
  let newTree: TreeData[] = [];
@@ -259,6 +356,8 @@ export interface EntityOutput {
259
356
  name: string;
260
357
  match: any | null;
261
358
  reasoning: string | null;
359
+ color: string | null;
360
+ children: any[] | null;
262
361
  }
263
362
 
264
363
  export interface GraphData {
@@ -279,15 +378,17 @@ export function treeToGraph(tree: TreeData[]): GraphData {
279
378
  continue;
280
379
  }
281
380
 
282
- const { indices, id, name } = node;
381
+ const { indices, id, name, type, children } = node;
283
382
 
284
383
  const nodeData: EntityOutput = {
285
384
  id,
286
- type: node.type.id,
385
+ type: type.id,
386
+ color: type.color,
287
387
  name,
288
388
  txt_range: [indices],
289
389
  reasoning: null,
290
390
  match: node.match,
391
+ children,
291
392
  };
292
393
 
293
394
  nodeMap.set(node.id, node);
@@ -300,7 +401,7 @@ export function treeToGraph(tree: TreeData[]): GraphData {
300
401
 
301
402
  // Now process the children
302
403
  const { nodes: childNodes, edges: childEdges } = treeToGraph(
303
- node.children
404
+ node.children,
304
405
  );
305
406
  nodes.push(...childNodes);
306
407
  edges.push(...childEdges);
@@ -309,3 +410,32 @@ export function treeToGraph(tree: TreeData[]): GraphData {
309
410
 
310
411
  return { nodes, edges };
311
412
  }
413
+
414
+ function findNodeById(tree, id) {
415
+ for (const node of tree) {
416
+ if (node.id === id) {
417
+ return node;
418
+ }
419
+ if (node.children) {
420
+ const found = findNodeById(node.children, id);
421
+ if (found) return found;
422
+ }
423
+ }
424
+ return null;
425
+ }
426
+
427
+ function updateTreeTypes(tree, oldType, defaultType) {
428
+ return tree.map((node) => updateNodeType(node, oldType, defaultType));
429
+ }
430
+
431
+ function updateNodeType(node, oldType, defaultType) {
432
+ const type = node.type.id === oldType.id ? defaultType : node.type;
433
+
434
+ return {
435
+ ...node,
436
+ type,
437
+ children: node.children
438
+ ? updateTreeTypes(node.children, oldType, defaultType)
439
+ : [],
440
+ };
441
+ }
@@ -8,7 +8,13 @@
8
8
  .node
9
9
  cursor: pointer
10
10
 
11
+ circle
12
+ cursor: pointer
13
+ border: 1px solid black
11
14
 
15
+ .selected
16
+ border: 1px solid white
17
+
12
18
  .feedback-text
13
19
  margin-bottom: 2em
14
20
 
@@ -17,7 +23,6 @@
17
23
  max-height: 600px
18
24
 
19
25
  .control-panel
20
- max-width: 15em
21
26
  position: absolute
22
27
  top: 1em
23
28
  right: 1em
@@ -35,3 +40,90 @@
35
40
  .selection-tree
36
41
  margin: -1em 0
37
42
  padding: 1em 0
43
+ width: 70% !important
44
+
45
+ .type-list
46
+ display: grid
47
+ grid-auto-flow: column
48
+ grid-template-rows: repeat(10, auto)
49
+ gap: 0.2em
50
+
51
+ .type-tag
52
+ padding: .2em .5em
53
+ border-radius: .2em
54
+
55
+ .description
56
+ max-width: 300px
57
+ padding: .5em
58
+
59
+ mark
60
+ border-radius: .2em
61
+ cursor: pointer
62
+ color: black !important
63
+
64
+ [role="treeitem"]
65
+ width: auto !important
66
+
67
+ .highlight
68
+ cursor: pointer
69
+ padding: .2em 0
70
+ border-radius: .2em
71
+ position: relative
72
+ zIndex: 10
73
+
74
+ .feedback-text-wrapper
75
+ position: relative
76
+ z-index: 0
77
+ overflow: visible
78
+
79
+ .type-container
80
+ display: flex
81
+ justify-content: space-between
82
+ align-items: center
83
+ column-gap: 1em
84
+
85
+ .add-type
86
+ cursor: pointer
87
+ display: flex
88
+ justify-content: space-between
89
+ padding: 0 .5em
90
+ align-items: center
91
+
92
+ p
93
+ margin: 0
94
+
95
+ .overlay-container
96
+ height: 80vh
97
+ width: 100vw
98
+ display: flex
99
+ justify-content: center
100
+ align-items: center
101
+
102
+ .add-type-overlay
103
+ background-color: var(--secondary-color)
104
+ padding: .5em 1em
105
+ display: flex
106
+ flex-direction: column
107
+ gap: 1em
108
+ border-radius: .2em
109
+
110
+ .title
111
+ display: flex
112
+ justify-content: space-between
113
+ align-items: center
114
+
115
+ h2
116
+ margin: 0
117
+
118
+ .form-group
119
+ display: flex
120
+ gap: 3em
121
+
122
+ .text-inputs
123
+ display: flex
124
+ flex-direction: column
125
+ gap: 1em
126
+
127
+ .icons
128
+ display: flex
129
+ gap: .25em