@macrostrat/feedback-components 1.1.3 → 1.1.4

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 (62) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/esm/{feedback-components.95dbe7d7.js → feedback-components.00434ff7.js} +10 -1
  3. package/dist/esm/feedback-components.00434ff7.js.map +1 -0
  4. package/dist/esm/{feedback-components.f577ebea.js → feedback-components.1c15f37f.js} +32 -24
  5. package/dist/esm/feedback-components.1c15f37f.js.map +1 -0
  6. package/dist/esm/{feedback-components.1e7da538.js → feedback-components.204f7d2b.js} +23 -281
  7. package/dist/esm/feedback-components.204f7d2b.js.map +1 -0
  8. package/dist/esm/{feedback-components.832b2eae.js → feedback-components.28ba71be.js} +5 -5
  9. package/dist/esm/{feedback-components.832b2eae.js.map → feedback-components.28ba71be.js.map} +1 -1
  10. package/dist/esm/feedback-components.7e879290.js +286 -0
  11. package/dist/esm/feedback-components.7e879290.js.map +1 -0
  12. package/dist/esm/{feedback-components.45d25912.js → feedback-components.d55a1d18.js} +5 -5
  13. package/dist/esm/{feedback-components.45d25912.js.map → feedback-components.d55a1d18.js.map} +1 -1
  14. package/dist/esm/{feedback-components.fb60c70d.css → feedback-components.d591ffec.css} +20 -1
  15. package/dist/esm/feedback-components.d591ffec.css.map +1 -0
  16. package/dist/esm/{feedback-components.fa1d3641.js → feedback-components.f6605b83.js} +49 -7
  17. package/dist/esm/feedback-components.f6605b83.js.map +1 -0
  18. package/dist/esm/feedback-components.fd8ac9ca.js +230 -0
  19. package/dist/esm/feedback-components.fd8ac9ca.js.map +1 -0
  20. package/dist/esm/index.d.ts.map +1 -1
  21. package/dist/esm/index.js +1 -1
  22. package/dist/node/feedback-components.0eef8d0c.js +2 -0
  23. package/dist/node/feedback-components.0eef8d0c.js.map +1 -0
  24. package/dist/node/{feedback-components.f9abf0d6.js → feedback-components.2f740fc7.js} +2 -2
  25. package/dist/node/{feedback-components.f9abf0d6.js.map → feedback-components.2f740fc7.js.map} +1 -1
  26. package/dist/node/{feedback-components.4cd6b208.js → feedback-components.41db283a.js} +2 -2
  27. package/dist/node/{feedback-components.4cd6b208.js.map → feedback-components.41db283a.js.map} +1 -1
  28. package/dist/node/feedback-components.69d0ccd0.js +2 -0
  29. package/dist/node/feedback-components.69d0ccd0.js.map +1 -0
  30. package/dist/node/feedback-components.a7b43cfa.js +2 -0
  31. package/dist/node/feedback-components.a7b43cfa.js.map +1 -0
  32. package/dist/node/feedback-components.b9317f9c.js +2 -0
  33. package/dist/node/feedback-components.b9317f9c.js.map +1 -0
  34. package/dist/node/{feedback-components.c88cb37f.css → feedback-components.e096504e.css} +2 -2
  35. package/dist/node/feedback-components.e096504e.css.map +1 -0
  36. package/dist/node/feedback-components.e140ac86.js +2 -0
  37. package/dist/node/feedback-components.e140ac86.js.map +1 -0
  38. package/dist/node/feedback-components.f8373b58.js +2 -0
  39. package/dist/node/feedback-components.f8373b58.js.map +1 -0
  40. package/dist/node/index.js +1 -1
  41. package/dist/node/index.js.map +1 -1
  42. package/package.json +1 -1
  43. package/src/feedback/edit-state.ts +52 -3
  44. package/src/feedback/feedback.module.sass +17 -1
  45. package/src/feedback/index.ts +11 -317
  46. package/src/feedback/matches.ts +241 -0
  47. package/src/feedback/text-visualizer.ts +21 -21
  48. package/src/feedback/typelist.ts +312 -0
  49. package/dist/esm/feedback-components.1e7da538.js.map +0 -1
  50. package/dist/esm/feedback-components.95dbe7d7.js.map +0 -1
  51. package/dist/esm/feedback-components.f577ebea.js.map +0 -1
  52. package/dist/esm/feedback-components.fa1d3641.js.map +0 -1
  53. package/dist/esm/feedback-components.fb60c70d.css.map +0 -1
  54. package/dist/node/feedback-components.25f1909a.js +0 -2
  55. package/dist/node/feedback-components.25f1909a.js.map +0 -1
  56. package/dist/node/feedback-components.9328e8ba.js +0 -2
  57. package/dist/node/feedback-components.9328e8ba.js.map +0 -1
  58. package/dist/node/feedback-components.b7946db4.js +0 -2
  59. package/dist/node/feedback-components.b7946db4.js.map +0 -1
  60. package/dist/node/feedback-components.c459cc27.js +0 -2
  61. package/dist/node/feedback-components.c459cc27.js.map +0 -1
  62. package/dist/node/feedback-components.c88cb37f.css.map +0 -1
@@ -0,0 +1,241 @@
1
+ import { Switch } from "@blueprintjs/core";
2
+ import { Match } from "./text-visualizer";
3
+ import { Select } from "@blueprintjs/select";
4
+ import styles from "./feedback.module.sass";
5
+ import hyper from "@macrostrat/hyper";
6
+ import { useState } from "react";
7
+ import { Icon, Divider, Overlay2 } from "@blueprintjs/core";
8
+ import { JSONView, SaveButton } from "@macrostrat/ui-components";
9
+ import { useAPIResult, DataField } from "@macrostrat/ui-components";
10
+ import { LithologyTag } from "@macrostrat/data-components";
11
+
12
+ const h = hyper.styled(styles);
13
+
14
+ export function Matches({
15
+ match,
16
+ setMatchLinks,
17
+ matchLinks,
18
+ selectedNodes,
19
+ tree,
20
+ dispatch,
21
+ }) {
22
+ const [overlayOpen, setOverlayOpen] = useState(false);
23
+
24
+ let nodeMatch = null;
25
+ if (selectedNodes.length === 1) {
26
+ nodeMatch = findMatchingNode(tree, selectedNodes[0]);
27
+ }
28
+
29
+ return h.if(matchLinks)("div", [
30
+ h(Divider),
31
+ h(Switch, {
32
+ label: "Show matches",
33
+ checked: match !== null,
34
+ onChange: (e) => {
35
+ setMatchLinks(match === null ? matchLinks || {} : null);
36
+ },
37
+ }),
38
+ h.if(nodeMatch && match)(Match, {
39
+ data: nodeMatch?.match,
40
+ matchLinks: matchLinks,
41
+ dispatch,
42
+ nodeId: nodeMatch?.id,
43
+ }),
44
+ h.if(selectedNodes.length == 1 && !nodeMatch?.match && match)(
45
+ "div.add-match-container",
46
+ [
47
+ h(
48
+ "div.add-type",
49
+ {
50
+ onClick: () => {
51
+ setOverlayOpen(true);
52
+ },
53
+ },
54
+ [h("p.add-match-text", "Add match"), h(Icon, { icon: "plus" })],
55
+ ),
56
+ h(MatchOverlay, {
57
+ isOpen: overlayOpen,
58
+ setOverlayOpen,
59
+ nodeMatch,
60
+ dispatch,
61
+ }),
62
+ ],
63
+ ),
64
+ ]);
65
+ }
66
+
67
+ function findMatchingNode(tree, nodeId) {
68
+ let match = null;
69
+
70
+ function traverse(node) {
71
+ if (node.id === nodeId) {
72
+ match = node;
73
+ return true;
74
+ }
75
+ if (Array.isArray(node.children)) {
76
+ for (const child of node.children) {
77
+ if (traverse(child)) return true;
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+
83
+ tree.forEach(traverse);
84
+ return match;
85
+ }
86
+
87
+ function MatchOverlay({ isOpen, setOverlayOpen, nodeMatch, dispatch }) {
88
+ const [inputValue, setInputValue] = useState(nodeMatch?.name || "");
89
+ const [selectedItem, setSelectedItem] = useState(h("div", "Select a match"));
90
+ const [disabled, setDisabled] = useState(true);
91
+ const [payload, setPayload] = useState({});
92
+
93
+ const data = useAPIResult(
94
+ "https://dev.macrostrat.org/api/pg/type_lookup?name=ilike.*" +
95
+ inputValue +
96
+ "*",
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
+ });
181
+
182
+ return h(
183
+ Overlay2,
184
+ {
185
+ isOpen,
186
+ },
187
+ h(
188
+ "div.overlay-container",
189
+ h("div.add-type-overlay", [
190
+ h("h2.title", [
191
+ "Add match with " + nodeMatch.name,
192
+ h(Icon, {
193
+ icon: "cross",
194
+ className: "close-icon",
195
+ onClick: () => {
196
+ setOverlayOpen(false);
197
+ },
198
+ style: { cursor: "pointer", color: "red" },
199
+ }),
200
+ ]),
201
+ h("div.form-group", [
202
+ h(
203
+ Select,
204
+ {
205
+ items: items || [],
206
+ itemRenderer: (item, { handleClick }) => {
207
+ return h("div.match-item", { onClick: handleClick }, item);
208
+ },
209
+ onItemSelect: (item) => {
210
+ setDisabled(false);
211
+ setSelectedItem(item);
212
+ },
213
+ onQueryChange: (query) => setInputValue(query),
214
+ popoverProps: { minimal: true },
215
+ query: inputValue,
216
+ placeholder: "Enter match name",
217
+ },
218
+ selectedItem,
219
+ ),
220
+ ]),
221
+ h(
222
+ SaveButton,
223
+ {
224
+ className: "save-btn",
225
+ small: true,
226
+ onClick: () => {
227
+ // Handle save changes
228
+ dispatch({
229
+ type: "add-match",
230
+ payload: { id: nodeMatch.id, payload },
231
+ });
232
+ setOverlayOpen(false);
233
+ },
234
+ disabled,
235
+ },
236
+ "Save changes",
237
+ ),
238
+ ]),
239
+ ),
240
+ );
241
+ }
@@ -6,7 +6,7 @@ import hyper from "@macrostrat/hyper";
6
6
  import { buildHighlights, getTagStyle } from "../extractions";
7
7
  import { Highlight } from "../extractions/types";
8
8
  import { useEffect, useRef } from "react";
9
- import { Popover } from "@blueprintjs/core";
9
+ import { Icon } from "@blueprintjs/core";
10
10
  import { DataField, JSONView } from "@macrostrat/ui-components";
11
11
  import { LithologyList, LithologyTag } from "@macrostrat/data-components";
12
12
 
@@ -289,9 +289,7 @@ function renderNode(
289
289
  }
290
290
  }
291
291
 
292
- const match = tag.match;
293
-
294
- const TagComponent = h(
292
+ return h(
295
293
  "span",
296
294
  {
297
295
  onMouseEnter: (e: MouseEvent) => {
@@ -334,18 +332,6 @@ function renderNode(
334
332
  renderNode(child, dispatch, selectedNodes, isSelected, matchLinks),
335
333
  ),
336
334
  );
337
-
338
- return matchLinks && match
339
- ? h(
340
- Popover,
341
- {
342
- autoFocus: false,
343
- content: h("div.description", h(Match, { data: match, matchLinks })),
344
- interactionKind: "hover",
345
- },
346
- TagComponent,
347
- )
348
- : TagComponent;
349
335
  }
350
336
 
351
337
  export function HighlightedText(props: {
@@ -396,9 +382,13 @@ export function HighlightedText(props: {
396
382
  );
397
383
  }
398
384
 
399
- function Match({ data, matchLinks }) {
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
+
400
390
  if (data.lith_id) {
401
- return h(DataField, {
391
+ tag = h(DataField, {
402
392
  label: "Lithology",
403
393
  value: h(LithologyTag, {
404
394
  data: { name: data.name, id: data.lith_id, color: data.color },
@@ -413,7 +403,7 @@ function Match({ data, matchLinks }) {
413
403
  }
414
404
 
415
405
  if (data.strat_name_id) {
416
- return h("div", [
406
+ tag = h("div", [
417
407
  h(DataField, {
418
408
  label: "Stratigraphic name",
419
409
  value: h(LithologyTag, {
@@ -445,7 +435,7 @@ function Match({ data, matchLinks }) {
445
435
  }
446
436
 
447
437
  if (data.lith_att_id) {
448
- return h(DataField, {
438
+ tag = h(DataField, {
449
439
  label: "Lithology attribute",
450
440
  value: h(LithologyTag, {
451
441
  data: { name: data.name, id: data.lith_att_id },
@@ -459,5 +449,15 @@ function Match({ data, matchLinks }) {
459
449
  });
460
450
  }
461
451
 
462
- return h(JSONView, { data });
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
463
  }
@@ -0,0 +1,312 @@
1
+ import styles from "./feedback.module.sass";
2
+ import hyper from "@macrostrat/hyper";
3
+
4
+ import { getTagStyle } from "../extractions";
5
+ import { useState } from "react";
6
+ import { Icon, Popover, Overlay2 } from "@blueprintjs/core";
7
+ import { SaveButton } from "@macrostrat/ui-components";
8
+ import { useInDarkMode } from "@macrostrat/ui-components";
9
+ import { ColorPicker } from "@macrostrat/data-sheet";
10
+
11
+ const h = hyper.styled(styles);
12
+
13
+ export function TypeList({ types, selected, dispatch, selectedNodes, tree }) {
14
+ const [selectedType, setSelectedType] = useState(null);
15
+ const isSelectedNodes = selectedNodes.length > 0;
16
+ const darkMode = useInDarkMode();
17
+ const luminance = darkMode ? 0.9 : 0.4;
18
+
19
+ return h("div.type-list-container", [
20
+ h(
21
+ "div.type-list-header",
22
+ isSelectedNodes && !selectedType
23
+ ? "Change selected nodes to:"
24
+ : "Entity Types",
25
+ ),
26
+ h(
27
+ "div.type-list",
28
+ Array.from(types.values()).map((type) =>
29
+ h(TypeTag, {
30
+ type,
31
+ luminance,
32
+ selectedType,
33
+ setSelectedType,
34
+ dispatch,
35
+ tree,
36
+ selectedNodes,
37
+ selected,
38
+ isSelectedNodes,
39
+ }),
40
+ ),
41
+ ),
42
+ h(AddType, { dispatch }),
43
+ ]);
44
+ }
45
+
46
+ function collectMatchingIds(tree, id) {
47
+ const ids = [];
48
+
49
+ function traverse(node) {
50
+ if (node.type.id === id) {
51
+ ids.push(node.id);
52
+ }
53
+ if (Array.isArray(node.children)) {
54
+ node.children.forEach(traverse);
55
+ }
56
+ }
57
+
58
+ tree.forEach(traverse);
59
+ return ids;
60
+ }
61
+
62
+ function AddType({ dispatch }) {
63
+ const [overlayOpen, setOverlayOpen] = useState(false);
64
+
65
+ const saveHandler = (payload) => {
66
+ dispatch({
67
+ type: "add-entity-type",
68
+ payload,
69
+ });
70
+ setOverlayOpen(false);
71
+ };
72
+
73
+ return h("div.add-type-container", [
74
+ h("div.add-type", { onClick: () => setOverlayOpen(true) }, [
75
+ h("p.add-type-text", "Add new type"),
76
+ h(Icon, { icon: "plus" }),
77
+ ]),
78
+ h(TypeOverlay, {
79
+ setOverlayOpen,
80
+ overlayOpen,
81
+ title: "Add New Type",
82
+ saveHandler,
83
+ }),
84
+ ]);
85
+ }
86
+
87
+ function EditType({ dispatch, type }) {
88
+ const [editorOpen, setEditorOpen] = useState(false);
89
+
90
+ const saveHandler = (payload) => {
91
+ dispatch({
92
+ type: "update-entity-type",
93
+ payload,
94
+ });
95
+ setEditorOpen(false);
96
+ };
97
+
98
+ return h("div.edit-type", [
99
+ h(Icon, {
100
+ icon: "edit",
101
+ className: "edit-icon",
102
+ onClick: (e) => {
103
+ e.stopPropagation();
104
+ setEditorOpen(true);
105
+ },
106
+ }),
107
+ h(TypeOverlay, {
108
+ setOverlayOpen: setEditorOpen,
109
+ overlayOpen: editorOpen,
110
+ originalType: type,
111
+ title: "Edit Type",
112
+ saveHandler,
113
+ }),
114
+ ]);
115
+ }
116
+
117
+ function TypeOverlay({
118
+ setOverlayOpen,
119
+ overlayOpen,
120
+ originalType,
121
+ title,
122
+ saveHandler,
123
+ }) {
124
+ const { name, description, color, id } = originalType || {};
125
+
126
+ const [nameInput, setNameInput] = useState(name || "");
127
+ const [descriptionInput, setDescriptionInput] = useState(description || "");
128
+ const [colorInput, setColorInput] = useState(color || "#fff");
129
+
130
+ return h(
131
+ Overlay2,
132
+ {
133
+ isOpen: overlayOpen,
134
+ },
135
+ h(
136
+ "div.overlay-container",
137
+ h("div.add-type-overlay", [
138
+ h("h2.title", [
139
+ title,
140
+ h(Icon, {
141
+ icon: "cross",
142
+ className: "close-icon",
143
+ onClick: () => {
144
+ setOverlayOpen(false);
145
+ },
146
+ style: { cursor: "pointer", color: "red" },
147
+ }),
148
+ ]),
149
+ h("div.form-group", [
150
+ h("div.text-inputs", [
151
+ h("div.form-field.name", [
152
+ h("p.label", "Name"),
153
+ h("input", {
154
+ type: "text",
155
+ placeholder: "Enter type name",
156
+ onChange: (e) => setNameInput(e.target.value),
157
+ value: nameInput,
158
+ }),
159
+ ]),
160
+ h("div.form-field.form-description", [
161
+ h("p.label", "Description"),
162
+ h("input", {
163
+ type: "text",
164
+ placeholder: "Enter type description",
165
+ onChange: (e) => setDescriptionInput(e.target.value),
166
+ value: descriptionInput,
167
+ }),
168
+ ]),
169
+ ]),
170
+ h("div.form-field.color", [
171
+ h("p.label", "Color"),
172
+ h(ColorPicker, {
173
+ value: colorInput,
174
+ onChange: (color) => setColorInput(color),
175
+ style: { width: "100%" },
176
+ }),
177
+ ]),
178
+ ]),
179
+ h(
180
+ SaveButton,
181
+ {
182
+ className: "save-btn",
183
+ small: true,
184
+ onClick: () =>
185
+ saveHandler({
186
+ name: nameInput,
187
+ description: descriptionInput,
188
+ color: colorInput,
189
+ id,
190
+ }),
191
+ },
192
+ "Save changes",
193
+ ),
194
+ ]),
195
+ ),
196
+ );
197
+ }
198
+
199
+ function TypeTag({
200
+ type,
201
+ luminance,
202
+ selectedType,
203
+ setSelectedType,
204
+ dispatch,
205
+ tree,
206
+ selectedNodes,
207
+ selected,
208
+ isSelectedNodes,
209
+ }) {
210
+ const { color, name, id, description } = type;
211
+ const darkMode = useInDarkMode();
212
+ const isSelected = id === selected?.id && selectedNodes.length > 0;
213
+
214
+ const style = getTagStyle(color, {
215
+ active: isSelected,
216
+ highlighted: selectedNodes.length === 0,
217
+ });
218
+
219
+ const payload = {
220
+ id,
221
+ name,
222
+ color,
223
+ description,
224
+ };
225
+
226
+ const ids = collectMatchingIds(tree, id);
227
+
228
+ const handleTagClick = () => {
229
+ if (!isSelectedNodes && selectedType === null) {
230
+ if (ids.length > 0) {
231
+ setSelectedType(type);
232
+ dispatch({ type: "toggle-node-selected", payload: { ids } });
233
+ }
234
+ } else if (isSelectedNodes && selectedType === null) {
235
+ if (id === selected?.id && selectedNodes.length > 0) {
236
+ dispatch({
237
+ type: "toggle-node-selected",
238
+ payload: { ids: selectedNodes },
239
+ });
240
+ } else {
241
+ dispatch({ type: "select-entity-type", payload });
242
+ }
243
+ } else if (isSelectedNodes && selectedType.id === id) {
244
+ setSelectedType(null);
245
+ dispatch({ type: "toggle-node-selected", payload: { ids } });
246
+ } else if (isSelectedNodes && selectedType.id !== id) {
247
+ if (ids.length > 0) {
248
+ setSelectedType(type);
249
+ const oldIds = collectMatchingIds(tree, selectedType.id);
250
+
251
+ dispatch({ type: "toggle-node-selected", payload: { ids: oldIds } });
252
+ dispatch({ type: "toggle-node-selected", payload: { ids } });
253
+ }
254
+ } else {
255
+ console.warn("Unexpected state in TypeTag click handler", {
256
+ isSelectedNodes,
257
+ selectedType,
258
+ selectedNodes,
259
+ ids,
260
+ id,
261
+ selected,
262
+ });
263
+ }
264
+ };
265
+
266
+ return h(
267
+ Popover,
268
+ {
269
+ autoFocus: false,
270
+ content: h("div.description", description || "No description available"),
271
+ interactionKind: "hover",
272
+ },
273
+ h(
274
+ "div.type-tag",
275
+ {
276
+ onClick: handleTagClick,
277
+ style: {
278
+ cursor:
279
+ ids.length > 0 || (isSelectedNodes && !selectedType)
280
+ ? "pointer"
281
+ : "",
282
+ color: "black",
283
+ backgroundColor: style.backgroundColor,
284
+ border: isSelected
285
+ ? `1px solid var(--text-emphasized-color)`
286
+ : `1px solid var(--background-color)`,
287
+ },
288
+ },
289
+ h("div.type-container", [
290
+ h("div.type-name", name),
291
+ h("div.icons", [
292
+ h(EditType, {
293
+ dispatch,
294
+ type,
295
+ }),
296
+ h(Icon, {
297
+ icon: "cross",
298
+ className: "delete-type-icon",
299
+ style: { color: "red", cursor: "pointer" },
300
+ onClick: (e) => {
301
+ e.stopPropagation();
302
+ dispatch({
303
+ type: "delete-entity-type",
304
+ payload: { id },
305
+ });
306
+ },
307
+ }),
308
+ ]),
309
+ ]),
310
+ ),
311
+ );
312
+ }