UNPKG

graph-explorer

Version:

Graph Explorer can be used to explore and RDF graphs in SPARQL endpoints or on the web.

13,463 lines 577 kB
(function() {	try {		if (typeof document != "undefined") {			var elementStyle = document.createElement("style");			elementStyle.appendChild(document.createTextNode(".graph-explorer {\n  --ge-font-sans: \"Inter\", system-ui, -apple-system, BlinkMacSystemFont,\n    \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n  --ge-font-mono: \"SFMono-Regular\", \"JetBrains Mono\", \"Fira Code\", ui-monospace,\n    Menlo, Consolas, monospace;\n  --ge-bg: #f1f5f9;\n  --ge-surface: #ffffff;\n  --ge-surface-2: #f8fafc;\n  --ge-surface-3: #f1f5f9;\n  --ge-border: #e5e9f0;\n  --ge-border-strong: #cbd5e1;\n  --ge-text: #0f172a;\n  --ge-text-muted: #475569;\n  --ge-text-subtle: #94a3b8;\n  --ge-accent: #4f46e5;\n  --ge-accent-hover: #4338ca;\n  --ge-accent-fg: #ffffff;\n  --ge-accent-soft: #eef2ff;\n  --ge-accent-soft-border: #c7d2fe;\n  --ge-success: #16a34a;\n  --ge-success-hover: #15803d;\n  --ge-danger: #dc2626;\n  --ge-danger-hover: #b91c1c;\n  --ge-warning: #f59e0b;\n  --ge-canvas: #fbfcfe;\n  --ge-canvas-dot: #dbe2ee;\n  --ge-radius-sm: 6px;\n  --ge-radius: 8px;\n  --ge-radius-lg: 12px;\n  --ge-radius-pill: 999px;\n  --ge-shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.06);\n  --ge-shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.08),\n    0 1px 2px rgba(15, 23, 42, 0.06);\n  --ge-shadow-md: 0 6px 16px rgba(15, 23, 42, 0.1),\n    0 2px 6px rgba(15, 23, 42, 0.06);\n  --ge-shadow-lg: 0 16px 40px rgba(15, 23, 42, 0.16),\n    0 6px 12px rgba(15, 23, 42, 0.08);\n  --ge-ring: 0 0 0 3px rgba(79, 70, 229, 0.28);\n  --ge-transition: 0.18s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.graph-explorer-spinner__arrow {\n  animation-name: graph-explorer-spinner-rotation;\n  animation-duration: 1.5s;\n  animation-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1);\n  animation-iteration-count: infinite;\n}\n.graph-explorer-spinner[data-error=true] .graph-explorer-spinner__arrow {\n  animation-iteration-count: 1;\n}\n\n@keyframes graph-explorer-spinner-rotation {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n.clearfix:before, .clearfix:after {\n  display: table;\n  content: \"\";\n}\n.clearfix:after {\n  clear: both;\n}\n\n.graph-explorer-label {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: 700;\n}\n\n.graph-explorer-btn {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: 6px;\n  padding: 7px 13px;\n  margin-bottom: 0;\n  font-size: 13px;\n  font-weight: 500;\n  line-height: 1.4;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: var(--ge-radius-sm);\n  text-transform: none;\n  transition: background-color var(--ge-transition), border-color var(--ge-transition), box-shadow var(--ge-transition), color var(--ge-transition);\n}\n.graph-explorer-btn:focus-visible {\n  outline: none;\n  box-shadow: var(--ge-ring);\n}\n.graph-explorer-btn[disabled] {\n  cursor: not-allowed;\n  opacity: 0.55;\n  box-shadow: none;\n}\n\n.graph-explorer-btn-default {\n  background-color: var(--ge-surface);\n  border-color: var(--ge-border-strong);\n  color: var(--ge-text-muted);\n  box-shadow: var(--ge-shadow-xs);\n}\n.graph-explorer-btn-default:hover {\n  background-color: var(--ge-surface-3);\n  border-color: var(--ge-border-strong);\n  color: var(--ge-text);\n}\n.graph-explorer-btn-default.active {\n  background-color: var(--ge-accent-soft);\n  border-color: var(--ge-accent-soft-border);\n  color: var(--ge-accent-hover);\n}\n.graph-explorer-btn-default.active:hover {\n  background-color: var(--ge-accent-soft);\n  border-color: var(--ge-accent);\n}\n.graph-explorer-btn-default[disabled], .graph-explorer-btn-default[disabled]:hover, .graph-explorer-btn-default[disabled].active, .graph-explorer-btn-default[disabled].active:hover {\n  background-color: var(--ge-surface-3);\n  color: var(--ge-text-subtle);\n}\n\n.graph-explorer-btn-primary {\n  color: var(--ge-accent-fg);\n  background-color: var(--ge-accent);\n  border-color: var(--ge-accent);\n  box-shadow: var(--ge-shadow-xs);\n}\n.graph-explorer-btn-primary:hover, .graph-explorer-btn-primary:focus, .graph-explorer-btn-primary:active {\n  background-color: var(--ge-accent-hover);\n  border-color: var(--ge-accent-hover);\n}\n.graph-explorer-btn-primary.active {\n  border-color: var(--ge-accent-hover);\n}\n.graph-explorer-btn-primary[disabled], .graph-explorer-btn-primary[disabled]:hover, .graph-explorer-btn-primary[disabled]:focus, .graph-explorer-btn-primary[disabled]:active, .graph-explorer-btn-primary[disabled].active {\n  background-color: var(--ge-accent);\n}\n\n.graph-explorer-btn-success {\n  background-color: var(--ge-success);\n  border-color: var(--ge-success);\n  color: #fff;\n  box-shadow: var(--ge-shadow-xs);\n}\n.graph-explorer-btn-success:hover {\n  background-color: var(--ge-success-hover);\n  border-color: var(--ge-success-hover);\n}\n\n.graph-explorer-btn-danger {\n  background-color: var(--ge-danger);\n  border-color: var(--ge-danger);\n  color: #fff;\n  box-shadow: var(--ge-shadow-xs);\n}\n.graph-explorer-btn-danger:hover {\n  background-color: var(--ge-danger-hover);\n  border-color: var(--ge-danger-hover);\n}\n\n.graph-explorer-btn-group {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.graph-explorer-btn-group > .graph-explorer-btn, .graph-explorer-btn-group > .graph-explorer-btn-group {\n  position: relative;\n  float: left;\n}\n.graph-explorer-btn-group > .graph-explorer-btn:hover,\n.graph-explorer-btn-group > .graph-explorer-btn:focus,\n.graph-explorer-btn-group > .graph-explorer-btn.active,\n.graph-explorer-btn-group > .graph-explorer-btn.active:hover {\n  z-index: 2;\n}\n.graph-explorer-btn-group .graph-explorer-btn + .graph-explorer-btn,\n.graph-explorer-btn-group .graph-explorer-btn + .graph-explorer-btn-group,\n.graph-explorer-btn-group .graph-explorer-btn-group + .graph-explorer-btn,\n.graph-explorer-btn-group .graph-explorer-btn-group + .graph-explorer-btn-group {\n  margin-left: -1px;\n}\n.graph-explorer-btn-group > .graph-explorer-btn:first-child {\n  margin-left: 0;\n}\n.graph-explorer-btn-group-sm > .graph-explorer-btn {\n  font-size: 12px;\n  line-height: 1.5;\n  padding: 5px 10px;\n}\n.graph-explorer-btn-group-xs > .graph-explorer-btn {\n  font-size: 12px;\n  line-height: 1.5;\n  padding: 1px 5px;\n}\n\n.graph-explorer-form-control {\n  display: block;\n  width: 100%;\n  height: 36px;\n  margin: 0;\n  padding: 7px 12px;\n  font-size: 14px;\n  line-height: 1.5;\n  color: var(--ge-text);\n  background: var(--ge-surface);\n  border: 1px solid var(--ge-border-strong);\n  border-radius: var(--ge-radius-sm);\n  transition: border-color var(--ge-transition), box-shadow var(--ge-transition);\n}\n.graph-explorer-form-control::placeholder {\n  color: var(--ge-text-subtle);\n}\n.graph-explorer-form-control:focus {\n  border-color: var(--ge-accent);\n  outline: 0;\n  box-shadow: var(--ge-ring);\n}\n.graph-explorer-form-control:disabled {\n  background-color: var(--ge-surface-3);\n  cursor: not-allowed;\n  opacity: 0.6;\n}\n\n.graph-explorer-input-group {\n  position: relative;\n  display: flex;\n  align-items: stretch;\n}\n.graph-explorer-input-group .graph-explorer-form-control {\n  position: relative;\n  z-index: 2;\n  flex: 1 1 auto;\n  width: 1%;\n  margin-bottom: 0;\n}\n.graph-explorer-input-group .graph-explorer-form-control:not(:last-child) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n.graph-explorer-input-group-btn {\n  display: flex;\n  align-items: stretch;\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.graph-explorer-input-group-btn > .graph-explorer-btn {\n  height: 100%;\n  margin-left: -1px;\n  z-index: 2;\n}\n.graph-explorer-input-group-btn:last-child > .graph-explorer-btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.graph-explorer-list-group {\n  margin: 0;\n  padding: 0;\n}\n\n.graph-explorer-list-group-item:last-child {\n  margin-bottom: 0;\n}\n\n.graph-explorer-list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 14px;\n  margin-bottom: -1px;\n  background-color: var(--ge-surface);\n  border: 1px solid var(--ge-border);\n}\n.graph-explorer-list-group-item:first-child {\n  border-top-left-radius: var(--ge-radius-sm);\n  border-top-right-radius: var(--ge-radius-sm);\n}\n.graph-explorer-list-group-item:last-child {\n  border-bottom-left-radius: var(--ge-radius-sm);\n  border-bottom-right-radius: var(--ge-radius-sm);\n}\n\n.graph-explorer-badge {\n  display: inline-block;\n  min-width: 10px;\n  font-size: 11px;\n  font-weight: 600;\n  line-height: 1;\n  color: var(--ge-text-muted);\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  background-color: var(--ge-surface-3);\n  border: 1px solid var(--ge-border);\n  padding: 3px 8px;\n  border-radius: var(--ge-radius-pill);\n}\n\n.graph-explorer-overlayed-element {\n  cursor: move;\n  outline: none;\n}\n\n.graph-explorer-overlayed-element,\n.graph-explorer-exported-element {\n  box-sizing: border-box;\n  color: var(--ge-text, #0f172a);\n  font-family: var(--ge-font-sans, \"Inter\", system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif);\n  font-size: 14px;\n  line-height: 1.5;\n}\n.graph-explorer-overlayed-element img,\n.graph-explorer-exported-element img {\n  vertical-align: middle;\n}\n\n.graph-explorer-exported-element *, .graph-explorer-exported-element *:before, .graph-explorer-exported-element *:after {\n  box-sizing: inherit;\n}\n\n.graph-explorer-overlayed-element--blurred {\n  filter: grayscale(100%);\n  opacity: 0.5;\n}\n\n.graph-explorer-link__wrap {\n  stroke-width: 12px;\n  stroke-linejoin: round;\n  stroke-linecap: round;\n  stroke: transparent;\n  fill: none;\n}\n.graph-explorer-link:hover .graph-explorer-link__wrap {\n  stroke: rgba(140, 140, 140, 0.44);\n}\n.graph-explorer-link__vertex {\n  cursor: all-scroll;\n}\n.graph-explorer-link:not(:hover) .graph-explorer-link__vertex {\n  fill: transparent;\n}\n.graph-explorer-link__vertex-tools {\n  opacity: 0;\n  cursor: pointer;\n}\n.graph-explorer-link__vertex-tools > circle {\n  fill: gray;\n}\n.graph-explorer-link__vertex-tools > path {\n  stroke: white;\n}\n.graph-explorer-link__vertex-tools:hover > circle {\n  fill: black;\n}\n.graph-explorer-link:hover .graph-explorer-link__vertex-tools {\n  opacity: 0.8;\n}\n.graph-explorer-link--blurred {\n  opacity: 0.5;\n}\n\n.graph-explorer-paper-area {\n  flex: auto;\n  width: 0;\n  display: flex;\n  position: relative;\n  cursor: default;\n  background-color: var(--ge-canvas);\n}\n.graph-explorer-paper-area__area {\n  flex: auto;\n  overflow: hidden;\n  background-image: radial-gradient(var(--ge-canvas-dot) 1px, transparent 1px);\n  background-attachment: local;\n}\n.graph-explorer-paper-area__widgets {\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.graph-explorer-paper-area__watermark {\n  background-size: cover;\n  width: 8%;\n  max-width: 130px;\n  min-width: 50px;\n  position: absolute;\n  top: 15px;\n  right: 25px;\n  cursor: pointer;\n  opacity: 0.3;\n  transition: opacity 0.3s;\n}\n.graph-explorer-paper-area__watermark:hover {\n  opacity: 0.5;\n}\n.graph-explorer-paper-area--hide-scrollbars {\n  overflow: hidden;\n}\n\n.graph-explorer-paper {\n  position: relative;\n}\n\n.graph-explorer-exported-watermark {\n  opacity: 0.3;\n  transition: opacity 0.3s;\n}\n\n.graph-explorer-paper-area--animated .graph-explorer-overlayed-element {\n  transition: transform 0.5s ease-in-out;\n}\n.graph-explorer-paper-area--animated .graph-explorer-link-layer, .graph-explorer-paper-area--animated .graph-explorer-paper-area__widgets {\n  transition: none;\n  opacity: 0;\n}\n\n.graph-explorer-link-layer, .graph-explorer-paper-area__widgets {\n  transition: opacity 0.5s ease-in-out;\n}\n\n.graph-explorer-loading-widget {\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  margin: auto;\n  position: absolute;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: rgba(255, 255, 255, 0.9);\n  z-index: 10;\n}\n\n.graph-explorer-authoring-state__item-error {\n  align-self: flex-end;\n  margin: 0px 5px;\n  display: flex;\n  align-items: center;\n  cursor: help;\n}\n.graph-explorer-authoring-state__item-error-icon {\n  background: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20style='fill:%20white'%20viewBox='0%200%20576%20512'%3e%3crect%20style='fill:%20white'%20width='160'%20height='340'%20x='207.9998'%20y='136'%20ry='0'%20/%3e%3cpath%20style='fill:%20red'%20d='M569.517%20440.013C587.975%20472.007%20564.806%20512%20527.94%20512H48.054c-36.937%200-59.999-40.055-41.577-71.987L246.423%2023.985c18.467-32.009%2064.72-31.951%2083.154%200l239.94%20416.028zM288%20354c-25.405%200-46%2020.595-46%2046s20.595%2046%2046%2046%2046-20.595%2046-46-20.595-46-46-46zm-43.673-165.346l7.418%20136c.347%206.364%205.609%2011.346%2011.982%2011.346h48.546c6.373%200%2011.635-4.982%2011.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884%200-12.356%205.78-11.981%2012.654z'/%3e%3c/svg%3e\");\n  height: 15px;\n  width: 17px;\n}\n.graph-explorer-authoring-state__state-label {\n  font-weight: bold;\n  margin-right: 5px;\n}\n.graph-explorer-authoring-state__state-cancel {\n  color: #3f87a6;\n  cursor: pointer;\n}\n.graph-explorer-authoring-state__state-cancel:hover {\n  text-decoration: underline;\n}\n.graph-explorer-authoring-state__state-indicator {\n  position: absolute;\n}\n.graph-explorer-authoring-state__state-indicator-container {\n  position: relative;\n}\n.graph-explorer-authoring-state__state-indicator-body {\n  position: absolute;\n  white-space: nowrap;\n  display: flex;\n  align-items: center;\n  bottom: 0;\n  background: rgba(255, 255, 255, 0.7);\n  border-radius: 5px;\n}\n\n.graph-explorer-authoring-tools {\n  margin: 10px;\n}\n.graph-explorer-authoring-tools__create-entity {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  justify-content: center;\n  width: 100%;\n  white-space: normal;\n}\n.graph-explorer-authoring-tools__type-label {\n  color: black;\n  border: black 1px dashed;\n  background: rgb(255, 210, 33);\n  padding: 0 0.5em 0 0.5em;\n  word-wrap: break-word;\n}\n\n.graph-explorer-class-tree {\n  flex: auto;\n  display: flex;\n  flex-direction: column;\n}\n.graph-explorer-class-tree__filter {\n  flex-shrink: 0;\n  margin: 10px 0 10px 0;\n}\n.graph-explorer-class-tree__filter-group {\n  margin-left: 10px;\n  margin-right: 10px;\n}\n.graph-explorer-class-tree__only-creatable {\n  display: block;\n  margin-top: 5px;\n}\n.graph-explorer-class-tree__tree {\n  border-top: 1px solid var(--ge-border);\n  padding: 6px 8px;\n  overflow: auto;\n}\n.graph-explorer-class-tree__spinner {\n  align-self: center;\n  /* center vertically in flexbox */\n  margin: auto;\n}\n\n.graph-explorer-class-leaf {\n  margin: 1px 0;\n}\n.graph-explorer-class-leaf__row {\n  display: flex;\n  align-items: center;\n  white-space: nowrap;\n  user-select: none;\n}\n.graph-explorer-class-leaf__row > * {\n  flex-shrink: 0;\n}\n.graph-explorer-class-leaf__body {\n  display: flex;\n  align-items: center;\n  text-decoration: none;\n  font-size: 14px;\n  padding: 4px 6px;\n  border: 1px solid transparent;\n  border-radius: var(--ge-radius-sm);\n  transition: background var(--ge-transition), border-color var(--ge-transition);\n}\n.graph-explorer-class-leaf__body:hover {\n  background: var(--ge-surface-3);\n  border-color: transparent;\n  cursor: pointer;\n}\n.graph-explorer-class-leaf__body--selected {\n  background-color: var(--ge-accent-soft);\n  border-color: var(--ge-accent-soft-border);\n}\n.graph-explorer-class-leaf__body--selected:hover {\n  background-color: var(--ge-accent-soft);\n}\n.graph-explorer-class-leaf__icon-container {\n  height: 18px;\n}\n.graph-explorer-class-leaf__icon {\n  display: block;\n  height: 100%;\n}\n.graph-explorer-class-leaf__label {\n  margin-left: 7px;\n  color: var(--ge-text);\n}\n.graph-explorer-class-leaf__highlighted-term {\n  font-weight: bold;\n}\n.graph-explorer-class-leaf__count {\n  margin-left: 5px;\n}\n.graph-explorer-class-leaf__children {\n  margin-left: 20px;\n}\n.graph-explorer-class-leaf__no-toggle {\n  display: inline-block;\n  width: 22px;\n  height: 22px;\n}\n.graph-explorer-class-leaf__toggle {\n  display: inline-block;\n  width: 12px;\n  height: 12px;\n  margin: 5px;\n  border-radius: var(--ge-radius-sm);\n}\n.graph-explorer-class-leaf__toggle:hover:not(:empty) {\n  background: var(--ge-surface-3);\n  cursor: pointer;\n}\n.graph-explorer-class-leaf__toggle-icon {\n  display: block;\n  height: 100%;\n}\n.graph-explorer-class-leaf__create {\n  margin-left: 5px;\n}\n.graph-explorer-class-leaf__create > button {\n  cursor: move;\n}\n\n.graph-explorer-connections-menu {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n.graph-explorer-connections-menu__sort-switch {\n  display: none;\n}\n.graph-explorer-connections-menu__sort-switch:checked + .graph-explorer-connections-menu__sort-switch-label {\n  color: var(--ge-accent);\n  opacity: 1;\n}\n.graph-explorer-connections-menu__sort-switch-label {\n  cursor: pointer;\n  display: block;\n  margin: 0;\n  opacity: 0.4;\n  text-align: center;\n}\n.graph-explorer-connections-menu__sort-switch-label:hover {\n  opacity: 1;\n}\n.graph-explorer-connections-menu__search-line-input {\n  flex: 1 1 100%;\n}\n\n.graph-explorer-connections-menu_bread-crumbs {\n  padding: 10px;\n  padding-bottom: 0px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  height: 27px;\n  min-height: 27px;\n  flex-grow: 0;\n}\n\n.graph-explorer-connections-menu__title-label {\n  position: absolute;\n  top: -11px;\n  left: 10px;\n  background: var(--ge-surface);\n  color: var(--ge-text);\n  font-weight: 600;\n  padding-left: 6px;\n  padding-right: 6px;\n  border-radius: var(--ge-radius-sm);\n}\n\n.graph-explorer-connections-menu_search-line {\n  padding: 10px;\n  display: flex;\n  align-items: center;\n  flex: 0 0 auto;\n}\n\n.graph-explorer-connections-menu_search-line-sort-switches {\n  flex: 0 0 20px;\n  margin-left: 10px;\n}\n\n.graph-explorer-connections-menu_links-list {\n  padding: 5px;\n  overflow-x: hidden;\n  overflow-y: auto;\n  border-top: 1px solid var(--ge-border);\n  flex-grow: 1;\n  margin: 0;\n}\n\n.ocm_links-list-empty {\n  display: flex;\n  align-items: center;\n}\n\n.graph-explorer-connections-menu_links-list__empty {\n  width: 100%;\n  position: relative;\n  font-size: x-large;\n  color: #cbcbcb;\n  text-align: center;\n}\n\n.graph-explorer-connections-menu__loading,\n.graph-explorer-connections-menu__error {\n  width: 100%;\n  height: 100%;\n  position: relative;\n  font-size: x-large;\n  display: flex;\n  color: #cbcbcb;\n  align-items: center;\n  justify-content: center;\n}\n\n.graph-explorer-connections-menu__loading-objects {\n  border: 1px solid gray;\n  flex-grow: 1;\n  box-shadow: inset 0px 0px 23px -8px gray;\n  background-color: whitesmoke;\n  position: relative;\n  font-size: x-large;\n  display: flex;\n  color: #cbcbcb;\n  align-items: center;\n  justify-content: center;\n  margin-bottom: 5px;\n}\n\n.graph-explorer-connections-menu__move-to-filter {\n  display: flex;\n  padding: 5px 10px;\n  user-select: none;\n  cursor: pointer;\n}\n.graph-explorer-connections-menu__move-to-filter:hover {\n  background-color: #e6e6e6;\n}\n\n.link-in-popup-menu {\n  display: flex;\n  overflow: hidden;\n  padding: 0 5px 0 0;\n  align-items: center;\n  margin-bottom: 4px;\n  background: #f7f7f7;\n}\n.link-in-popup-menu__link-title {\n  flex-grow: 1;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  margin: 5px 0px 5px 5px;\n}\n.link-in-popup-menu__count {\n  flex-shrink: 0;\n  margin-left: 10px;\n}\n.link-in-popup-menu__navigate-button {\n  float: right;\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGrSURBVHic7dYxSgNRGEXhGwOuRQyCi1AR3IHoUiwFW21cj5sRC3tFgrExzUBIMmPmP76cD145MxcODyYRyrTgm+dJDpO8F3xbHRdJPpK8JZkVb9l7yxiL32OUQt0YRim0KoZRCqyLYZQRbRrDKCOYZbsYy/Oa5Khgb/MmSZ6yfRBvyg4ZBcgoQEYBMgqQUYCMAmQUIKMAGQXIKEBGATIKkFGAjAJkFKChUY7Hn9w+owAZBcgoQEYBMgqQUYCMAjRJ8hijoBgFyChARgEyCpBRgIwCZBQgowANjXI6/uT2DYkyT3I5/uT2GQXIKEBGATIKkFGAsFEOdvViuEWSlyTfPZ6dJjn72zm6SvKZfjfkuWBv04wBYgwQY4AYA8QYIH1jzJPcFext2pAYtwV7m2YMEGOAGAPEGCDGADEGiDFAjAFiDBBjgBgDxBggxgAxBogxQIwBMiTGTcHephkDxBggxgAxBogxQIwBYgwQY4AYA8QYIMYAMQaIMUCMAWIMkJMkX+kX47pg7164jzcDZ9MoxhjRuijGKLAqijEKdaMYA2AZxRggD/HXVv/FDxh8HInEGLhOAAAAAElFTkSuQmCC\");\n  width: 16px;\n  height: 16px;\n  opacity: 0.5;\n  margin-left: 10px;\n  min-width: 16px;\n  background-size: cover;\n}\n.link-in-popup-menu__navigate-button:hover {\n  opacity: 1;\n}\n.link-in-popup-menu__filter-button {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAuxJREFUeF7t3V1u4jAYhWFu+FkDIHHBGlgZILbBjtN8M/labEywYzs+js8rHYFUqGo/6twNXTHGWIVdLpduv993x+ORm3Fy53L3A8Nf8sX+gSuw4e7NCFJuBAEbQcBGELARBGxOkNPp9PZCbp4Nd2/2eDy67Xb79mIu7+TO5e775+/d7/dut9u9vYnLM7lrufP++eeIMs+8MDSi5F0QhkaUPJuEoREl7aIwNKKkWRIMjShxS4qhEWXasmBoRAlbVgyNKH6bBUMjyvhmxdCI4l4RDI0o5opiaET5PwgMrXUUKAytVRRIDK01FGgMrRWUKjC0paNUhaEtFaVKDG1pKFVjaEtBWQSGVjvKojC0WlEWiaHVhrJoDK0WlCYwNHSUpjA0VJQmMTQ0lKYxNBQUSIyu697mkXEwa16VRoHCcCHoPDMOZ827UihwvxkuCFlAxgGtBTU3ChyGFIkhGYe0FtxcKJAYUiSGZBzU2qRyo8BiSIggUi4UaAwJFURKjQKPISGDSKlQqsCQEEHsn+N2u3Xr9dr+3t6T98r36J/jVwOIJJ8r1T9M2vDeOqoFJOajP5wfXYGaHp4gIDlAfg9SYP8iyPBIEIAIAhZBwCIIWAQBiyBgKcQLSGjG4a1NiiAEwYkgYCGCuCKIf8bhrSWLIP4Zh7eWLIL4ZxzeWrKaBZmAYhzeWrKaBpEFZBzeWrKaB5F5ZhzeWrIIMswj4/DWkkWQl33JOLy1ZBHEsZIRZGQlIkjCpYgggfvU2NdCIojnvuXzGp8I8mW+hbx2LIIkXIqaAaklgoDVDIjrn5gciy0GxPl3AlFzXV6OxTYVZPTvBCLmurwci20KSDX/je011+XlWGyhIFViSK7Ly7HYQkCqxZBcl5djsfmCVI0huS4vx2LzAakeQ3JdXo7F9g1kERiS6/JyLLYxkMVg1NQnEGIUygVCjILZIMQo3CsIMQBSEGKAdDgcus1mQwyUzudzd71eiYHS8/kkBpu71eoHWjSksuGbaS0AAAAASUVORK5CYII=\");\n  background-size: 20px 20px;\n  width: 20px;\n  height: 20px;\n  opacity: 0.4;\n  margin-left: 10px;\n}\n.link-in-popup-menu__filter-button:hover {\n  opacity: 1;\n}\n.link-in-popup-menu:hover {\n  background-color: #e2e2e2;\n}\n\n.link-in-popup-menu_direction {\n  background: rgba(219, 219, 219, 0.35);\n  min-height: 30px;\n  padding: 5px 0px 5px 10px;\n  display: flex;\n  align-items: center;\n}\n\n.link-in-popup-menu_direction__in-direction {\n  background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAbCAYAAAAOEM1uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAZEQAAGREBkIelaAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAG2SURBVFiFzde9axRRFMbhJ3Hjx0YRgkWElGIRGyVgaaG9XQpBrNIETJHKjxBSJCA2NiIWdhYKgoqCIELq/AU2tiJpAiliDMHEWEyKZfdO5szHrr4wzcx77vnNnXPnnktcK9jBwYCuLcwNBeHGsIGovyltDweNbYOHg9Eo4D9Tq0bsGj40BXKoO5isEjiht4ifHuE/qVpJvO/O049PvIxN/MBMH8ZP6pzeGVxK+C4kfAsl8vTMYBnI1x1Bv3E54bmWSHCAx2KfvBbgKGbxJAfOIcS7HMjnKCqpWoBRtfE5B/IVRsoAtnAGd3GlQchd/NE7Y7dwCtPYiw72xuD216KFk/zN3Ii+SYOajhqHZUU9aK1GjS3M4xumFK+yMuPexLHEsy9YbChPJR3HW+na+yjbBvNU+zdzHbcxfoTnUw7cS8XNSS3AFx1B6zif8FzKgXsmVj6VAduyFrwzcCUHcL/L9yiaJAUYXRRjON1172zC9xX3ZS+ziTk8KAFYWWX7wRGcqJAnudVV1RTu1YhP6WL3jWjXO4HvzbLE9N8fmqKAv/SpNyvQdmorSmlHVvhX1TsJltFPPPwL/+nTC6wUIf8AAAAASUVORK5CYII=\") 0 0 no-repeat;\n  flex-shrink: 0;\n  width: 22px;\n  height: 15px;\n  margin: 0 14px 0 0;\n  background-size: contain;\n  opacity: 0.5;\n}\n\n.link-in-popup-menu_direction__out-direction {\n  background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAbCAYAAAAOEM1uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAZEQAAGREBkIelaAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGCSURBVFiFzdi9ShxRFAfwn+uiaAoRVBQbbfMEFqIoFja+QCoLLQQr8R0sbdIJgTQiSgT1AcTKzkdIQhpTaOlX0GyK2WJ2c8d1Pt0/XBjOnTnnP+eerxnYxj0aJa9nfEOvlLirgFx8zaQhV8Ng2jfKiVT2amWxKAr1gOwElwXpH8NWXiXtMbKZV2EMHwP6F2P7dR1O8T2PeBW/8EMHp5TpwWGtJewF06JEuWmzu4ueqgnC55juw6ZsHE8B218F8qJsgkS1b0Grh74EbDdwioGqCYbQj6MEkhcYIlxm3opZrGEyh47eJqH22JvDOZbJ5sEJ4Rgqeh1nLTMr6Mv4bBpMZSV4hj9FMknA96wxeC3qCOvyxWAd88L17wobdHkWV0VwxP+e3ksgd6LiOrgtyvhn7DRlo3gM2K68kwziNqb7QTSC9eN3m9136cWvjVuf8FOHaSZPJ8mLfRw0r/8m3RQiuIQPBZEY67CfSCyOsttV0hG/CV3/0VQTTbxVIrW9rv6z8A+8NRQ5z9bcwQAAAABJRU5ErkJggg==\") 0 0 no-repeat;\n  flex-shrink: 0;\n  width: 22px;\n  height: 15px;\n  margin: 0 8px 0 6px;\n  background-size: contain;\n  opacity: 0.5;\n}\n\n.graph-explorer-connections-menu_links-list__loading {\n  text-align: center;\n  width: 100%;\n  position: relative;\n  font-size: x-large;\n  color: #cbcbcb;\n}\n\n.graph-explorer-connections-menu_links-list__hr {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n\n.graph-explorer-connections-menu_objects-panel {\n  flex-grow: 1;\n  padding: 10px;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  padding-top: 0px;\n}\n\n.graph-explorer-connections-menu_objects-panel__select-all {\n  white-space: nowrap;\n  margin-bottom: 5px;\n  display: flex;\n}\n.graph-explorer-connections-menu_objects-panel__select-all input {\n  margin-right: 5px;\n}\n.graph-explorer-connections-menu_objects-panel__select-all input:disabled {\n  opacity: 0.3;\n}\n\n.graph-explorer-connections-menu_objects-panel_bottom-panel {\n  height: 25px;\n  white-space: nowrap;\n  display: flex;\n  justify-content: space-between;\n}\n\n.graph-explorer-connections-menu_objects-panel_bottom-panel__count-label {\n  height: 25px;\n  float: left;\n  padding: 0px 5px;\n  font-size: larger;\n  display: flex;\n  align-items: center;\n  max-width: 60%;\n}\n\n.graph-explorer-connections-menu_objects-panel_bottom-panel__extra-elements {\n  color: gray;\n  cursor: help;\n}\n\n.graph-explorer-btn.graph-explorer-connections-menu_objects-panel_bottom-panel__add-button {\n  height: 25px;\n  padding-top: 1px;\n  padding-bottom: 2px;\n}\n\n.graph-explorer-connections-menu_objects-panel_objects-list {\n  border: 1px solid gray;\n  height: 0;\n  flex-grow: 1;\n  overflow-x: hidden;\n  overflow-y: scroll;\n  padding: 5px;\n  margin-bottom: 5px;\n}\n\n.graph-explorer-connections-menu__link {\n  color: var(--ge-accent);\n  cursor: pointer;\n  text-decoration: none;\n}\n.graph-explorer-connections-menu__link:hover {\n  text-decoration: underline;\n}\n\n.graph-explorer-dialog {\n  background: var(--ge-surface);\n  border: 1px solid var(--ge-border);\n  border-radius: var(--ge-radius-lg);\n  box-shadow: var(--ge-shadow-lg);\n  position: absolute;\n}\n.graph-explorer-dialog__caption {\n  font-weight: 600;\n  position: absolute;\n  top: -11px;\n  left: 10px;\n  background: var(--ge-surface);\n  color: var(--ge-text);\n  padding-left: 6px;\n  padding-right: 6px;\n  border-radius: var(--ge-radius-sm);\n}\n.graph-explorer-dialog__close-button {\n  background: transparent url(\"data:image/svg+xml,%3csvg%20aria-hidden='true'%20focusable='false'%20data-prefix='far'%20data-icon='times-circle'%20class='svg-inline--fa%20fa-times-circle%20fa-w-16'%20role='img'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20512%20512'%3e%3cpath%20fill='currentColor'%20d='M256%208C119%208%208%20119%208%20256s111%20248%20248%20248%20248-111%20248-248S393%208%20256%208zm0%20448c-110.5%200-200-89.5-200-200S145.5%2056%20256%2056s200%2089.5%20200%20200-89.5%20200-200%20200zm101.8-262.2L295.6%20256l62.2%2062.2c4.7%204.7%204.7%2012.3%200%2017l-22.6%2022.6c-4.7%204.7-12.3%204.7-17%200L256%20295.6l-62.2%2062.2c-4.7%204.7-12.3%204.7-17%200l-22.6-22.6c-4.7-4.7-4.7-12.3%200-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3%200-17l22.6-22.6c4.7-4.7%2012.3-4.7%2017%200l62.2%2062.2%2062.2-62.2c4.7-4.7%2012.3-4.7%2017%200l22.6%2022.6c4.7%204.7%204.7%2012.3%200%2017z'%3e%3c/path%3e%3c/svg%3e\");\n  background-size: contain;\n  border: 0 none;\n  cursor: pointer;\n  display: block;\n  outline: none;\n  padding: 0;\n  position: absolute;\n  top: -22px;\n  right: -22px;\n  height: 20px;\n  width: 20px;\n  opacity: 0.5;\n  transition: 0.3s;\n}\n.graph-explorer-dialog__close-button:hover {\n  opacity: 1;\n}\n\n.graph-explorer-dialog__bottom-right-handle {\n  position: absolute;\n  bottom: 0;\n  right: 0;\n  width: 0;\n  height: 0;\n  border-style: solid;\n  border-width: 0 0 10px 10px;\n  border-color: transparent transparent rgba(0, 0, 0, 0.38) transparent;\n  cursor: nwse-resize;\n}\n.graph-explorer-dialog__bottom-right-handle::before {\n  content: \"\";\n  position: absolute;\n  bottom: -10px;\n  right: 0;\n  width: 0;\n  height: 0;\n  border-style: solid;\n  border-width: 0 0 5px 5px;\n  border-color: transparent transparent rgba(0, 0, 0, 0.38) transparent;\n}\n.graph-explorer-dialog__bottom-right-handle:hover {\n  border-color: transparent transparent rgba(0, 0, 0, 0.5) transparent;\n}\n\n.graph-explorer-dialog__bottom-handle, .graph-explorer-dialog__right-handle {\n  position: absolute;\n  opacity: 0;\n  background-color: black;\n}\n.graph-explorer-dialog__bottom-handle:hover, .graph-explorer-dialog__right-handle:hover {\n  opacity: 0.1;\n}\n\n.graph-explorer-dialog__bottom-handle {\n  bottom: 0;\n  width: 100%;\n  height: 5px;\n  cursor: ns-resize;\n}\n\n.graph-explorer-dialog__right-handle {\n  top: 0;\n  right: 0;\n  width: 5px;\n  height: 100%;\n  cursor: ew-resize;\n}\n\n.graph-explorer-edit-form {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n.graph-explorer-edit-form__body {\n  overflow: auto;\n  padding: 10px;\n  flex: 1 1 100%;\n  display: flex;\n  flex-direction: column;\n  position: relative;\n}\n.graph-explorer-edit-form__controls {\n  border-top: 1px solid #ccc;\n  padding: 10px;\n  text-align: right;\n  flex: 0 0 auto;\n}\n.graph-explorer-edit-form__apply-button {\n  margin-right: 5px;\n}\n.graph-explorer-edit-form__form-row {\n  display: block;\n  margin-bottom: 10px;\n}\n.graph-explorer-edit-form__element-selector {\n  flex-grow: 1;\n  display: flex;\n  flex-direction: column;\n}\n.graph-explorer-edit-form__search {\n  flex-shrink: 0;\n  position: relative;\n}\n.graph-explorer-edit-form__search-icon {\n  opacity: 0.6;\n  position: absolute;\n  top: 50%;\n  left: 10px;\n  margin-top: -7px;\n}\n.graph-explorer-edit-form__search-input {\n  padding-left: 33px;\n}\n.graph-explorer-edit-form__existing-elements-list {\n  flex: 1 1 0;\n  margin-top: 7px;\n  padding-right: 10px;\n  overflow-y: scroll;\n}\n.graph-explorer-edit-form__separator {\n  margin: 7px 0;\n  overflow: hidden;\n  text-align: center;\n}\n.graph-explorer-edit-form__separator-text {\n  color: #555;\n  display: inline-block;\n  font-size: 13px;\n  position: relative;\n}\n.graph-explorer-edit-form__separator-text:before, .graph-explorer-edit-form__separator-text:after {\n  content: \"\";\n  border-top: 1px solid;\n  position: absolute;\n  top: 50%;\n  margin: 0 10px;\n  width: 500px;\n}\n.graph-explorer-edit-form__separator-text:before {\n  left: 100%;\n}\n.graph-explorer-edit-form__separator-text:after {\n  right: 100%;\n}\n.graph-explorer-edit-form__progress {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  right: 0;\n}\n.graph-explorer-edit-form__control-row {\n  position: relative;\n  padding-bottom: 18px;\n}\n.graph-explorer-edit-form__control-error {\n  color: red;\n  position: absolute;\n  bottom: 0;\n  left: 0;\n}\n\n.graph-explorer-halo {\n  position: absolute;\n  pointer-events: none;\n  border: 1.5px dashed var(--ge-accent);\n  border-radius: var(--ge-radius);\n  box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.12);\n}\n.graph-explorer-halo__navigate {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__navigate:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__navigate[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__navigate {\n  top: 50%;\n  margin-top: -10px;\n  right: -22px;\n}\n.graph-explorer-halo__navigate--open {\n  background-image: url(\"data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'%20standalone='no'?%3e%3csvg%20xmlns:svg='http://www.w3.org/2000/svg'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20110%20110'%20version='1.1'%20width='500'%20height='500'%3e%3cpath%20d='M%2055.105965,54.648825%20M%2082.182422,8.0521107%20A%2053.892377,53.892377%200%201%200%2028.029508,101.24554%2053.892377,53.892377%200%201%200%2082.182422,8.0521107%20Z%20M%2055.105965,54.648825%20M%2076.692536,17.499824%20A%2042.965432,42.965432%200%200%201%2033.519393,91.797827%2042.965432,42.965432%200%200%201%2076.692536,17.499824%20Z'%20style='stroke-width:1.06812763;fill:%23000000'%20/%3e%3cpath%20style='fill:%23000000;stroke:none;stroke-width:0.25893259px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1'%20d='M%2025.29481,56.552597%20C%2078.882863,29.834905%2079.035536,29.834905%2079.035536,29.834905%20L%2052.165174,84.18632%2049.56974,59.3007%20Z'%20/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__navigate--closed {\n  background-image: url(\"data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'%20standalone='no'?%3e%3csvg%20xmlns:svg='http://www.w3.org/2000/svg'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20110%20110'%20version='1.1'%20width='500'%20height='500'%3e%3cpath%20d='M%2055.105965,54.648825%20M%2082.182422,8.0521107%20A%2053.892377,53.892377%200%201%200%2028.029508,101.24554%2053.892377,53.892377%200%201%200%2082.182422,8.0521107%20Z%20M%2055.105965,54.648825%20M%2076.692536,17.499824%20A%2042.965432,42.965432%200%200%201%2033.519393,91.797827%2042.965432,42.965432%200%200%201%2076.692536,17.499824%20Z'%20style='stroke-width:1.06812763'%20/%3e%3cpath%20d='M%2070.749364,31.224635%2078.426933,38.910146%2063.054265,54.266973%2078.41107,69.639662%2070.725571,77.317242%2055.368766,61.944553%2039.996098,77.301379%2032.318529,69.615869%2047.691197,54.259042%2032.334392,38.886353%20l%207.685499,-7.67758%2015.356805,15.372689%20z'%20style='stroke-width:1.17913187'%20/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__folow {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__folow:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__folow[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__folow {\n  top: 50%;\n  margin-top: -10px;\n  left: -22px;\n  background-image: url(\"data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='utf-8'?%3e%3csvg%20version='1.1'%20id='Layer_1'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20x='0px'%20y='0px'%20width='512px'%20height='512px'%20viewBox='0%200%20512%20512'%20enable-background='new%200%200%20512%20512'%20xml:space='preserve'%3e%3cpath%20fill='%23010101'%20d='M459.654,233.373l-90.531,90.5c-49.969,50-131.031,50-181,0c-7.875-7.844-14.031-16.688-19.438-25.813%20l42.063-42.063c2-2.016,4.469-3.172,6.828-4.531c2.906,9.938,7.984,19.344,15.797,27.156c24.953,24.969,65.563,24.938,90.5,0%20l90.5-90.5c24.969-24.969,24.969-65.563,0-90.516c-24.938-24.953-65.531-24.953-90.5,0l-32.188,32.219%20c-26.109-10.172-54.25-12.906-81.641-8.891l68.578-68.578c50-49.984,131.031-49.984,181.031,0%20C509.623,102.342,509.623,183.389,459.654,233.373z%20M220.326,382.186l-32.203,32.219c-24.953,24.938-65.563,24.938-90.516,0%20c-24.953-24.969-24.953-65.563,0-90.531l90.516-90.5c24.969-24.969,65.547-24.969,90.5,0c7.797,7.797,12.875,17.203,15.813,27.125%20c2.375-1.375,4.813-2.5,6.813-4.5l42.063-42.047c-5.375-9.156-11.563-17.969-19.438-25.828c-49.969-49.984-131.031-49.984-181.016,0%20l-90.5,90.5c-49.984,50-49.984,131.031,0,181.031c49.984,49.969,131.031,49.969,181.016,0l68.594-68.594%20C274.561,395.092,246.42,392.342,220.326,382.186z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__remove {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__remove:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__remove[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__remove {\n  top: -22px;\n  right: -22px;\n  background-image: url(\"data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'%20standalone='no'?%3e%3csvg%20xmlns:svg='http://www.w3.org/2000/svg'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20110%20110'%20version='1.1'%20width='500'%20height='500'%3e%3cpath%20d='M%2082.182422,8.0521107%20C%2056.44775,-6.9018137%2023.463185,1.8377258%208.5092706,27.57238%20-6.4446434,53.307034%202.2948357,86.291616%2028.029508,101.24554%2053.76418,116.19946%2086.748746,107.45993%20101.70266,81.725271%20116.65657,55.990616%20107.91709,23.006035%2082.182422,8.0521107%20Z%20M%2071.75602,28.578553%2082.28685,38.846984%2065.453479,56.373296%2083.064738,73.314301%2072.796937,83.844485%2055.169736,66.657039%2039.010998,83.228711%2028.480167,72.96028%2044.639378,56.389069%2028.415211,40.568631%2038.683013,30.038446%2054.938893,45.85871%20Z'%20style='fill:%23000000;stroke-width:1.06812763'%20/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__expand {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__expand:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__expand[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__expand {\n  bottom: -22px;\n  left: 50%;\n  margin-left: -10px;\n}\n.graph-explorer-halo__expand--open {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIMDxQ3d8lonQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAEOSURBVEjH7dXNK0RhFAbwXxRyZyIlKwtlMbvZkUIW9rOThezEniIf/4E/UYgkGwskaTI2V51uF/NxZ6LuU+/ivec5z/Pe9+McSpQoUeK/YTgz38AEbgv2WcUkHvKCS2ilY7tA0/VU8w2NPMICHoP5TgGmy0HvBfXviNN4D+TdHkzn8BG05n9LmMJdSNjvwrSOZtjiWruJFdwE86MOTGshr4m1TlddxWsQOW5zwTFnsdtzquAyCJ39wJ3Fc+Cu9HozR3ERBE9zODOZF7FV1FtM8BSET0JsKC0MX7FG0VVuHFeZbR/Bffi22a8SO5Y58/inh/2u70lahVph7A2quVRxnZoeDLqzJTgvG3yJP4dPo59Rw97b1k8AAAAASUVORK5CYII=\");\n}\n.graph-explorer-halo__expand--closed {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIMDx0nu7zDsAAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAD+SURBVEjH7ZQxa8JQFIU/HFSqXQri1KHQwc2txaLi4N5NHMRNdFeoqPkH/YlFRRBxcVAREakuEQ7RiDWJWHgHAuHl3Pu9e/PuAyOjO1QM+L419BEYAjugdctKlzb08DSChkaBvgCn8v4VFPQBGAjIAsLARNbKQbR3LoCufAs5Kv/0CxoBfiRx74QnCczEU/EKjTv+qXXG+wwsxJvzMjIrSdS5cKMa835NpSNJ0P5DbEritkDh0sAnYCzBzSu6lbahO2Btb+asEsBGoHUP5+MF+JVcr27GN8fJrPkwEVnJt7Q7caSMmKo+3gFFabnrjJeAjwBuvbxbtUZGRkb/R3tcflA+OTpkkAAAAABJRU5ErkJggg==\");\n}\n.graph-explorer-halo__add-to-filter {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__add-to-filter:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__add-to-filter[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__add-to-filter {\n  bottom: -22px;\n  right: -22px;\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAuxJREFUeF7t3V1u4jAYhWFu+FkDIHHBGlgZILbBjtN8M/labEywYzs+js8rHYFUqGo/6twNXTHGWIVdLpduv993x+ORm3Fy53L3A8Nf8sX+gSuw4e7NCFJuBAEbQcBGELARBGxOkNPp9PZCbp4Nd2/2eDy67Xb79mIu7+TO5e775+/d7/dut9u9vYnLM7lrufP++eeIMs+8MDSi5F0QhkaUPJuEoREl7aIwNKKkWRIMjShxS4qhEWXasmBoRAlbVgyNKH6bBUMjyvhmxdCI4l4RDI0o5opiaET5PwgMrXUUKAytVRRIDK01FGgMrRWUKjC0paNUhaEtFaVKDG1pKFVjaEtBWQSGVjvKojC0WlEWiaHVhrJoDK0WlCYwNHSUpjA0VJQmMTQ0lKYxNBQUSIyu697mkXEwa16VRoHCcCHoPDMOZ827UihwvxkuCFlAxgGtBTU3ChyGFIkhGYe0FtxcKJAYUiSGZBzU2qRyo8BiSIggUi4UaAwJFURKjQKPISGDSKlQqsCQEEHsn+N2u3Xr9dr+3t6T98r36J/jVwOIJJ8r1T9M2vDeOqoFJOajP5wfXYGaHp4gIDlAfg9SYP8iyPBIEIAIAhZBwCIIWAQBiyBgKcQLSGjG4a1NiiAEwYkgYCGCuCKIf8bhrSWLIP4Zh7eWLIL4ZxzeWrKaBZmAYhzeWrKaBpEFZBzeWrKaB5F5ZhzeWrIIMswj4/DWkkWQl33JOLy1ZBHEsZIRZGQlIkjCpYgggfvU2NdCIojnvuXzGp8I8mW+hbx2LIIkXIqaAaklgoDVDIjrn5gciy0GxPl3AlFzXV6OxTYVZPTvBCLmurwci20KSDX/je011+XlWGyhIFViSK7Ly7HYQkCqxZBcl5djsfmCVI0huS4vx2LzAakeQ3JdXo7F9g1kERiS6/JyLLYxkMVg1NQnEGIUygVCjILZIMQo3CsIMQBSEGKAdDgcus1mQwyUzudzd71eiYHS8/kkBpu71eoHWjSksuGbaS0AAAAASUVORK5CYII=\");\n}\n.graph-explorer-halo__revert {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__revert:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__revert[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__revert {\n  top: -22px;\n  left: 50%;\n  margin-left: -10px;\n  background-image: url(\"data:image/svg+xml,%3csvg%20aria-hidden='true'%20data-prefix='fas'%20data-icon='undo'%20class='svg-inline--fa%20fa-undo%20fa-w-16'%20role='img'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20512%20512'%3e%3cpath%20fill='currentColor'%20d='M212.333%20224.333H12c-6.627%200-12-5.373-12-12V12C0%205.373%205.373%200%2012%200h48c6.627%200%2012%205.373%2012%2012v78.112C117.773%2039.279%20184.26%207.47%20258.175%208.007c136.906.994%20246.448%20111.623%20246.157%20248.532C504.041%20393.258%20393.12%20504%20256.333%20504c-64.089%200-122.496-24.313-166.51-64.215-5.099-4.622-5.334-12.554-.467-17.42l33.967-33.967c4.474-4.474%2011.662-4.717%2016.401-.525C170.76%20415.336%20211.58%20432%20256.333%20432c97.268%200%20176-78.716%20176-176%200-97.267-78.716-176-176-176-58.496%200-110.28%2028.476-142.274%2072.333h98.274c6.627%200%2012%205.373%2012%2012v48c0%206.627-5.373%2012-12%2012z'%3e%3c/path%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__establish-connection {\n  position: absolute;\n  background-color: transparent;\n  background-size: contain;\n  background-repeat: no-repeat;\n  background-position: center;\n  border: 0 none;\n  cursor: pointer;\n  outline: none;\n  padding: 0;\n  pointer-events: auto;\n  width: 20px;\n  height: 20px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo__establish-connection:hover {\n  opacity: 1;\n}\n.graph-explorer-halo__establish-connection[disabled] {\n  cursor: not-allowed;\n  opacity: 0.2;\n}\n.graph-explorer-halo__establish-connection {\n  bottom: -22px;\n  left: -22px;\n  background-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20384%20512'%3e%3cpath%20d='M256%20144V32c0-17.673%2014.327-32%2032-32s32%2014.327%2032%2032v112h-64zm112%2016H16c-8.837%200-16%207.163-16%2016v32c0%208.837%207.163%2016%2016%2016h16v32c0%2077.406%2054.969%20141.971%20128%20156.796V512h64v-99.204c73.031-14.825%20128-79.39%20128-156.796v-32h16c8.837%200%2016-7.163%2016-16v-32c0-8.837-7.163-16-16-16zm-240-16V32c0-17.673-14.327-32-32-32S64%2014.327%2064%2032v112h64z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo__establish-connection-spinner {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  bottom: -22px;\n  left: -22px;\n}\n\n.graph-explorer-halo-link__button {\n  background: transparent;\n  border: 0 none;\n  cursor: pointer;\n  padding: 0;\n  position: absolute;\n  opacity: 0.8;\n  outline: none;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo-link__button:hover {\n  opacity: 1;\n}\n.graph-explorer-halo-link__button[disabled] {\n  cursor: not-allowed;\n  opacity: 0.5;\n}\n.graph-explorer-halo-link__edit {\n  background-color: #ccc;\n  background-position: 50%;\n  background-repeat: no-repeat;\n  background-size: 60%;\n  border-radius: 10px;\n  height: 20px;\n  width: 20px;\n  background-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20576%20512'%3e%3cpath%20d='M402.6%2083.2l90.2%2090.2c3.8%203.8%203.8%2010%200%2013.8L274.4%20405.6l-92.8%2010.3c-12.4%201.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8%2083.2c3.8-3.8%2010-3.8%2013.8%200zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2%200l-35.4%2035.4c-3.8%203.8-3.8%2010%200%2013.8l90.2%2090.2c3.8%203.8%2010%203.8%2013.8%200l35.4-35.4c15.2-15.3%2015.2-40%200-55.2zM384%20346.2V448H64V128h229.8c3.2%200%206.2-1.3%208.5-3.5l40-40c7.6-7.6%202.2-20.5-8.5-20.5H48C21.5%2064%200%2085.5%200%20112v352c0%2026.5%2021.5%2048%2048%2048h352c26.5%200%2048-21.5%2048-48V306.2c0-10.7-12.9-16-20.5-8.5l-40%2040c-2.2%202.3-3.5%205.3-3.5%208.5z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo-link__delete {\n  background-color: #ccc;\n  background-position: 50%;\n  background-repeat: no-repeat;\n  background-size: 60%;\n  border-radius: 10px;\n  height: 20px;\n  width: 20px;\n  background-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20448%20512'%3e%3cpath%20d='M0%2084V56c0-13.3%2010.7-24%2024-24h112l9.4-18.7c4-8.2%2012.3-13.3%2021.4-13.3h114.3c9.1%200%2017.4%205.1%2021.5%2013.3L312%2032h112c13.3%200%2024%2010.7%2024%2024v28c0%206.6-5.4%2012-12%2012H12C5.4%2096%200%2090.6%200%2084zm416%2056v324c0%2026.5-21.5%2048-48%2048H80c-26.5%200-48-21.5-48-48V140c0-6.6%205.4-12%2012-12h360c6.6%200%2012%205.4%2012%2012zm-272%2068c0-8.8-7.2-16-16-16s-16%207.2-16%2016v224c0%208.8%207.2%2016%2016%2016s16-7.2%2016-16V208zm96%200c0-8.8-7.2-16-16-16s-16%207.2-16%2016v224c0%208.8%207.2%2016%2016%2016s16-7.2%2016-16V208zm96%200c0-8.8-7.2-16-16-16s-16%207.2-16%2016v224c0%208.8%207.2%2016%2016%2016s16-7.2%2016-16V208z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-halo-link__spinner {\n  position: absolute;\n}\n.graph-explorer-halo-link__edit-label-button {\n  background: transparent url(\"data:image/svg+xml,%3csvg%20aria-hidden='true'%20data-prefix='fas'%20data-icon='pen-square'%20class='svg-inline--fa%20fa-pen-square%20fa-w-14'%20role='img'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20448%20512'%3e%3cpath%20fill='currentColor'%20d='M400%20480H48c-26.5%200-48-21.5-48-48V80c0-26.5%2021.5-48%2048-48h352c26.5%200%2048%2021.5%2048%2048v352c0%2026.5-21.5%2048-48%2048zM238.1%20177.9L102.4%20313.6l-6.3%2057.1c-.8%207.6%205.6%2014.1%2013.3%2013.3l57.1-6.3L302.2%20242c2.3-2.3%202.3-6.1%200-8.5L246.7%20178c-2.5-2.4-6.3-2.4-8.6-.1zM345%20165.1L314.9%20135c-9.4-9.4-24.6-9.4-33.9%200l-23.1%2023.1c-2.3%202.3-2.3%206.1%200%208.5l55.5%2055.5c2.3%202.3%206.1%202.3%208.5%200L345%20199c9.3-9.3%209.3-24.5%200-33.9z'%3e%3c/path%3e%3c/svg%3e\") no-repeat;\n  background-size: cover;\n  border: 0 none;\n  cursor: pointer;\n  padding: 0;\n  position: absolute;\n  margin-left: 5px;\n  outline: none;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-halo-link__edit-label-button:hover {\n  opacity: 1;\n}\n\n.graph-explorer-instances-search {\n  flex: auto;\n  display: flex;\n  flex-direction: column;\n}\n.graph-explorer-instances-search__criteria {\n  flex-shrink: 0;\n  margin: 10px 0 10px 0;\n}\n.graph-explorer-instances-search__criterions {\n  padding-left: 15px;\n  margin-bottom: 10px;\n}\n.graph-explorer-instances-search__criterions:empty {\n  margin-bottom: 0;\n}\n.graph-explorer-instances-search__criterion {\n  display: block;\n  position: relative;\n  width: 100%;\n}\n.graph-explorer-instances-search__criterion-class, .graph-explorer-instances-search__criterion-element, .graph-explorer-instances-search__criterion-link-type {\n  display: inline-block;\n  padding: 2px 10px;\n  border-radius: var(--ge-radius-pill);\n  border: 1px solid transparent;\n  font-size: 12px;\n  font-weight: 500;\n  word-wrap: break-word;\n}\n.graph-explorer-instances-search__criterion-class {\n  background: #fef3c7;\n  border-color: #fcd34d;\n  color: #92400e;\n}\n.graph-explorer-instances-search__criterion-element {\n  background: #ffedd5;\n  border-color: #fdba74;\n  color: #9a3412;\n}\n.graph-explorer-instances-search__criterion-link-type {\n  background: #dcfce7;\n  border-color: #86efac;\n  color: #166534;\n}\n.graph-explorer-instances-search__link-direction {\n  height: 1em;\n  opacity: 0.5;\n}\n.graph-explorer-instances-search__criterion-remove {\n  float: right;\n  margin: 0 10px 4px 4px;\n}\n.graph-explorer-instances-search__text-criteria {\n  margin: 0 10px;\n}\n.graph-explorer-instances-search__rest {\n  padding: 10px 10px 0 10px;\n  border-top: 1px solid var(--ge-border);\n}\n.graph-explorer-instances-search__results {\n  padding-left: 0;\n  padding-top: 10px;\n  margin: 0 10px 0 10px;\n  outline: none;\n}\n.graph-explorer-instances-search[data-state=finished] .graph-explorer-instances-search__results:empty:before {\n  content: \"No items correspond to the specified criteria.\";\n  font-style: italic;\n}\n.graph-explorer-instances-search__rest-end {\n  margin: 5px 0 10px 0;\n}\n.graph-explorer-instances-search__load-more {\n  width: 100%;\n}\n\n.link-types-toolbox {\n  flex: auto;\n  display: flex;\n  flex-direction: column;\n  margin-bottom: 0;\n}\n.link-types-toolbox__heading {\n  padding: 10px;\n}\n.link-types-toolbox__searching-box {\n  display: flex;\n  align-items: center;\n}\n.link-types-toolbox__clearSearch {\n  margin-left: -25px;\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: 0 0;\n  border: 0;\n}\n.link-types-toolbox__switch-all {\n  margin-top: 5px;\n}\n.link-types-toolbox__rest {\n  border-top: 1px solid #dddddd;\n  flex: auto;\n  display: flex;\n  flex-direction: column;\n}\n\n.link-types-toolbox .panel-heading {\n  flex-shrink: 0;\n  -webkit-flex-shrink: 0; /* safari 8 */\n}\n\n.link-types-toolbox ul {\n  margin-bottom: 0;\n}\n\n.link-types-toolbox .links-heading {\n  margin-left: 0.4em;\n}\n\n.link-types-toolbox .links-heading span {\n  border: black 1px dashed;\n  background: rgb(255, 131, 92);\n  padding: 0 0.5em 0 0.5em;\n  word-wrap: break-word;\n  line-height: 1.3;\n}\n\n.link-types-toolbox__heading .link-types-toolbox-controls {\n  padding: 5px 15px;\n  font-size: 14px;\n  font-style: italic;\n}\n\n.link-types-toolbox__heading .link-types-toolbox-controls > span {\n  padding-left: 0.3em;\n}\n\n.graph-explorer-list-group .linkInToolBox {\n  padding: 0 0 0 5px;\n  word-break: break-word;\n}\n\n.linkInToolBox > div {\n  display: inline;\n}\n.linkInToolBox__new-tag {\n  margin-left: 0.5em;\n  white-space: normal;\n  word-wrap: normal;\n  border-radius: 2px;\n  padding: 0 5px;\n  background: orange;\n}\n.linkInToolBox .graph-explorer-badge {\n  display: none;\n  margin-left: 0.5em;\n  white-space: normal;\n  word-wrap: normal;\n}\n.linkInToolBox .link-title {\n  font-size: 16px;\n  color: black;\n  display: inline;\n}\n.linkInToolBox .graph-explorer-btn-group {\n  float: left;\n  margin-top: 2px;\n  margin-right: 6px;\n  margin-bottom: 2px;\n}\n.linkInToolBox .graph-explorer-btn.graph-explorer-btn-default {\n  border-color: rgb(195, 195, 195);\n}\n.linkInToolBox__filter-button {\n  display: none;\n  float: right;\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAuxJREFUeF7t3V1u4jAYhWFu+FkDIHHBGlgZILbBjtN8M/labEywYzs+js8rHYFUqGo/6twNXTHGWIVdLpduv993x+ORm3Fy53L3A8Nf8sX+gSuw4e7NCFJuBAEbQcBGELARBGxOkNPp9PZCbp4Nd2/2eDy67Xb79mIu7+TO5e775+/d7/dut9u9vYnLM7lrufP++eeIMs+8MDSi5F0QhkaUPJuEoREl7aIwNKKkWRIMjShxS4qhEWXasmBoRAlbVgyNKH6bBUMjyvhmxdCI4l4RDI0o5opiaET5PwgMrXUUKAytVRRIDK01FGgMrRWUKjC0paNUhaEtFaVKDG1pKFVjaEtBWQSGVjvKojC0WlEWiaHVhrJoDK0WlCYwNHSUpjA0VJQmMTQ0lKYxNBQUSIyu697mkXEwa16VRoHCcCHoPDMOZ827UihwvxkuCFlAxgGtBTU3ChyGFIkhGYe0FtxcKJAYUiSGZBzU2qRyo8BiSIggUi4UaAwJFURKjQKPISGDSKlQqsCQEEHsn+N2u3Xr9dr+3t6T98r36J/jVwOIJJ8r1T9M2vDeOqoFJOajP5wfXYGaHp4gIDlAfg9SYP8iyPBIEIAIAhZBwCIIWAQBiyBgKcQLSGjG4a1NiiAEwYkgYCGCuCKIf8bhrSWLIP4Zh7eWLIL4ZxzeWrKaBZmAYhzeWrKaBpEFZBzeWrKaB5F5ZhzeWrIIMswj4/DWkkWQl33JOLy1ZBHEsZIRZGQlIkjCpYgggfvU2NdCIojnvuXzGp8I8mW+hbx2LIIkXIqaAaklgoDVDIjrn5gciy0GxPl3AlFzXV6OxTYVZPTvBCLmurwci20KSDX/je011+XlWGyhIFViSK7Ly7HYQkCqxZBcl5djsfmCVI0huS4vx2LzAakeQ3JdXo7F9g1kERiS6/JyLLYxkMVg1NQnEGIUygVCjILZIMQo3CsIMQBSEGKAdDgcus1mQwyUzudzd71eiYHS8/kkBpu71eoHWjSksuGbaS0AAAAASUVORK5CYII=\");\n  background-size: 20px 20px;\n  width: 20px;\n  height: 20px;\n  margin: 3px;\n  cursor: pointer;\n  opacity: 0.4;\n  transition: opacity 200ms 0ms;\n}\n.linkInToolBox:hover .linkInToolBox__filter-button {\n  opacity: 1;\n  transition: opacity 200ms 0ms;\n}\n\n.connected-links .linkInToolBox .graph-explorer-badge {\n  /* show connection count badge only in \"Connected to Element\" list */\n  display: inline;\n}\n\n.connected-links .linkInToolBox__filter-button {\n  /* show filter button only in \"Connected to Element\" list */\n  display: inline;\n}\n\n.graph-explorer-list-element-view {\n  position: relative;\n  display: block;\n  background: var(--ge-text-subtle);\n  padding: 2px 2px 2px 6px;\n  border-radius: var(--ge-radius-sm);\n  margin: 0 0 4px 0;\n  opacity: 1;\n  cursor: move;\n  user-select: none;\n  box-shadow: var(--ge-shadow-xs);\n  transition: box-shadow var(--ge-transition), transform var(--ge-transition);\n}\n.graph-explorer-list-element-view:hover {\n  box-shadow: var(--ge-shadow-sm);\n}\n.graph-explorer-list-element-view--disabled {\n  opacity: 0.4;\n  cursor: default;\n  box-shadow: none;\n}\n.graph-explorer-list-element-view__label {\n  background: var(--ge-surface);\n  border-radius: 0 var(--ge-radius-sm) var(--ge-radius-sm) 0;\n  font-family: var(--ge-font-mono);\n  font-size: 13px;\n  color: var(--ge-text);\n  min-height: 1.4em;\n  padding: 3px 8px;\n  overflow-wrap: break-word;\n}\n\n.graph-explorer-text-highlight {\n  font-weight: 700;\n  color: var(--ge-accent-hover);\n}\n\n.graph-explorer-navigator {\n  display: block;\n  position: absolute;\n  bottom: 25px;\n  right: 25px;\n  overflow: hidden;\n}\n.graph-explorer .graph-explorer-navigator {\n  box-sizing: content-box;\n}\n.graph-explorer-navigator {\n  background: var(--ge-surface);\n  border: 1px solid var(--ge-border);\n  border-radius: var(--ge-radius);\n  box-shadow: var(--ge-shadow-md);\n  transition: width 0.3s, height 0.3s;\n}\n.graph-explorer-navigator--collapsed {\n  width: 26px;\n  height: 26px;\n}\n.graph-explorer-navigator > canvas {\n  transition: opacity 0.3s;\n}\n.graph-explorer-navigator--expanded > canvas {\n  opacity: 1;\n}\n.graph-explorer-navigator--collapsed > canvas {\n  opacity: 0;\n}\n.graph-explorer-navigator__toggle {\n  position: absolute;\n  background: transparent;\n  border: none;\n  outline: none;\n  padding: 4px;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.graph-explorer-navigator__toggle:hover {\n  opacity: 1;\n}\n.graph-explorer-navigator--expanded .graph-explorer-navigator__toggle {\n  top: 5px;\n  left: 5px;\n}\n.graph-explorer-navigator--collapsed .graph-explorer-navigator__toggle {\n  top: 0px;\n  left: 0px;\n}\n.graph-explorer-navigator__toggle-icon {\n  width: 18px;\n  height: 18px;\n  background-size: 18px 18px;\n  background-repeat: no-repeat;\n}\n.graph-explorer-navigator--expanded .graph-explorer-navigator__toggle-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg%20aria-hidden='true'%20focusable='false'%20data-prefix='far'%20data-icon='minus-square'%20class='svg-inline--fa%20fa-minus-square%20fa-w-14'%20role='img'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20448%20512'%3e%3cpath%20fill='currentColor'%20d='M108%20284c-6.6%200-12-5.4-12-12v-32c0-6.6%205.4-12%2012-12h232c6.6%200%2012%205.4%2012%2012v32c0%206.6-5.4%2012-12%2012H108zM448%2080v352c0%2026.5-21.5%2048-48%2048H48c-26.5%200-48-21.5-48-48V80c0-26.5%2021.5-48%2048-48h352c26.5%200%2048%2021.5%2048%2048zm-48%20346V86c0-3.3-2.7-6-6-6H54c-3.3%200-6%202.7-6%206v340c0%203.3%202.7%206%206%206h340c3.3%200%206-2.7%206-6z'%3e%3c/path%3e%3c/svg%3e\");\n}\n.graph-explorer-navigator--collapsed .graph-explorer-navigator__toggle-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg%20aria-hidden='true'%20focusable='false'%20data-prefix='far'%20data-icon='plus-square'%20class='svg-inline--fa%20fa-plus-square%20fa-w-14'%20role='img'%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20448%20512'%3e%3cpath%20fill='currentColor'%20d='M352%20240v32c0%206.6-5.4%2012-12%2012h-88v88c0%206.6-5.4%2012-12%2012h-32c-6.6%200-12-5.4-12-12v-88h-88c-6.6%200-12-5.4-12-12v-32c0-6.6%205.4-12%2012-12h88v-88c0-6.6%205.4-12%2012-12h32c6.6%200%2012%205.4%2012%2012v88h88c6.6%200%2012%205.4%2012%2012zm96-160v352c0%2026.5-21.5%2048-48%2048H48c-26.5%200-48-21.5-48-48V80c0-26.5%2021.5-48%2048-48h352c26.5%200%2048%2021.5%2048%2048zm-48%20346V86c0-3.3-2.7-6-6-6H54c-3.3%200-6%202.7-6%206v340c0%203.3%202.7%206%206%206h340c3.3%200%206-2.7%206-6z'%3e%3c/path%3e%3c/svg%3e\");\n}\n\n@keyframes graph-explorer-progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.graph-explorer-progress-bar {\n  flex-shrink: 0;\n  -webkit-flex-shrink: 0; /* safari 8 */\n  width: 100%;\n  background-color: var(--ge-surface-3);\n  background-repeat: repeat-x;\n  overflow: hidden;\n}\n.graph-explorer-progress-bar__bar {\n  float: left;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  transition: width 0.6s ease;\n  background-color: var(--ge-accent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-repeat: repeat-x;\n  background-size: 40px 40px;\n  animation: graph-explorer-progress-bar-stripes 2s linear infinite;\n}\n.graph-explorer-progress-bar--error .graph-explorer-progress-bar__bar {\n  background-color: var(--ge-danger);\n}\n.graph-explorer-progress-bar--loading, .graph-explorer-progress-bar--error {\n  /* property name | duration | delay */\n  transition: height 300ms 300ms;\n}\n.graph-explorer-progress-bar--completed {\n  /* property name | duration | delay */\n  transition: height 200ms 0ms;\n}\n\n.graph-explorer-search-results {\n  margin: 0;\n  padding: 0;\n  outline: none;\n}\n\n.graph-explorer-accordion {\n  flex: auto;\n  display: flex;\n  height: 100%;\n  width: 100%;\n}\n.graph-explorer-accordion--scrollable {\n  overflow: auto;\n}\n.graph-explorer-accordion--vertical {\n  flex-direction: column;\n}\n.graph-explorer-accordion--vertical:not(.graph-explorer-accordion--resizing) > .graph-explorer-accordion-item {\n  transition: height 0.3s ease-in-out;\n}\n\n.graph-explorer-accordion-item {\n  display: flex;\n  position: relative;\n  flex: auto;\n}\n.graph-explorer-accordion-item--resizing > .graph-explorer-accordion-item__handle, .graph-explorer-accordion-item__handle:hover {\n  background: rgba(0, 0, 0, 0.1);\n}\n.graph-explorer-accordion-item--vertical {\n  border-top: 1px solid var(--ge-border);\n}\n.graph-explorer-accordion-item--vertical:first-child {\n  border-top-width: 0;\n}\n.graph-explorer-accordion-item--horizontal {\n  border-right: 1px solid var(--ge-border);\n}\n.graph-explorer-accordion-item--horizontal:last-child {\n  border-right-width: 0;\n}\n.graph-explorer-accordion-item__handle {\n  position: absolute;\n  z-index: 2;\n}\n.graph-explorer-accordion-item__handle-vertical {\n  height: 5px;\n  bottom: -2.5px;\n  left: 0;\n  width: 100%;\n  cursor: ns-resize;\n}\n.graph-explorer-accordion-item__handle-horizontal {\n  height: 100%;\n  top: 0;\n  right: -2.5px;\n  width: 5px;\n  cursor: ew-resize;\n}\n.graph-explorer-accordion-item__handle-btn {\n  background: var(--ge-surface);\n  border: 2px solid var(--ge-accent);\n  box-shadow: var(--ge-shadow-sm);\n  border-radius: 10px;\n  cursor: pointer;\n  height: 20px;\n  position: absolute;\n  top: 50%;\n  margin-top: -10px;\n  width: 20px;\n  z-index: 20;\n  transition: 0.3s;\n}\n.graph-explorer-accordion-item__handle-btn::before {\n  background-position: 0 0;\n  background-repeat: no-repeat;\n  background-size: cover;\n  content: \"\";\n  height: 8px;\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  margin-top: -4px;\n  margin-left: -4px;\n  width: 8px;\n  transition: background 0.3s;\n}\n.graph-explorer-accordion-item__handle-btn:hover {\n  background: var(--ge-accent);\n}\n.graph-explorer-accordion-item__handle-btn-left {\n  left: 100%;\n  margin-left: -10px;\n}\n.graph-explorer-accordion-item__handle-btn-left:before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACXSURBVHjaYvz//z8DIbBlyxYmIDUTiI/6+PgsQJZjJGQAVPMcIE4E4n9AnAA0ZDFRBqBphoELQGwKNOQPiMNEoubLQOwG04zTADyanYGaXyOrZaJEM4YBpGpGMYAczXgDkVgANwBoCyiOU4B4PpK8LhDvBbpOlCgXkGMIhhdINQRrGJBiCO2SMg6XgPh9yEmZkdLsDBBgAMUxZ3KEE1BeAAAAAElFTkSuQmCC\");\n}\n.graph-explorer-accordion-item__handle-btn-left:hover:before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACXSURBVHjaYvz//z8DIfD+/XsmIDUTiI8KCgouQJZjJGQAVPMcIE4E4n9AnAA0ZDFRBqBphoELQGwKNOQPiMNEoubLQOwG04zTADyanYGaXyOrZaJEM4YBpGpGMYAczXgDkVgANwBoCyiOU4B4PpK8LhDvBbpOlCgXkGMIhhdINQRrGJBiCO2SMg6XgPh9yEmZkdLsDBBgAKQBZhCkUF/8AAAAAElFTkSuQmCC\");\n}\n.graph-explorer-accordion-item__handle-btn-right {\n  right: 100%;\n  margin-right: -10px;\n}\n.graph-explorer-accordion-item__handle-btn-right:before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACdSURBVHjaYvz//z8DMtiyZUsCkLIG4nQfH59/DAQAI7IBQM2xQGoBEDMB8XwgTiFkCNwAoGYWIHUaiA2Q5AkawgRjABX9AVJuQHwZST4RiOcADWciaADUkNdAypkUQzAESTUEq6mkGILTb8QawsRAIcBpANAWUSC1F4h18UUrEyWasRpAimYMA0jVTJOk3AfE/4jVjJEbycnOAAEGABIyZ3LVo9KqAAAAAElFTkSuQmCC\");\n}\n.graph-explorer-accordion-item__handle-btn-right:hover:before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACeSURBVHjaYvz//z8DMnj//n0CkLIG4nRBQcF/DAQAC5rmWCA1F4iZgJgZyE8hZAgjzAVAxSDDTgOxAZL8fCDGawgTjAFU9AdIuQHxZST5RCCeAzSciaABUENeAylnUgzBECTVEKymkmIITr8RawgTA4UApwFAW0SB1F4g1sUXrUyUaMZqACmaMQwgVTNNknIfEP8jVjOKC8jNzgABBgBosmVE6sxD1QAAAABJRU5ErkJggg==\");\n}\n.graph-explorer-accordion-item--collapsed .graph-explorer-accordion-item__handle-btn:before {\n  transform: rotate(180deg);\n}\n.graph-explorer-accordion-item__inner {\n  flex: auto;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n}\n.graph-explorer-accordion-item__body {\n  flex: 1 1 0px;\n  display: flex;\n  flex-direction: column;\n  background: var(--ge-surface);\n}\n.graph-explorer-accordion-item__header {\n  padding: 11px 12px 11px 24px;\n  position: relative;\n  flex-shrink: 0;\n  font-size: 11px;\n  font-weight: 600;\n  letter-spacing: 0.06em;\n  text-transform: uppercase;\n  color: var(--ge-text-muted);\n  background: var(--ge-surface-2);\n  border-bottom: 1px solid var(--ge-border);\n  cursor: pointer;\n  transition: background var(--ge-transition), color var(--ge-transition);\n  /* unselectable */\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.graph-explorer-accordion-item__header:hover {\n  background: var(--ge-surface-3);\n  color: var(--ge-text);\n}\n.graph-explorer-accordion-item__header:before {\n  border-top: 5px solid var(--ge-text-subtle);\n  border-left: 4px solid transparent;\n  border-right: 4px solid transparent;\n  content: \"\";\n  position: absolute;\n  top: 50%;\n  left: 9px;\n  margin-top: -2px;\n  transition: transform 0.15s ease;\n}\n.graph-explorer-accordion-item--collapsed .graph-explorer-accordion-item__header:before {\n  -webkit-transform: rotate(-90deg);\n  -moz-transform: rotate(-90deg);\n  -ms-transform: rotate(-90deg);\n  transform: rotate(-90deg);\n}\n.graph-explorer-accordion-item--collapsed .graph-explorer-accordion-item__body {\n  display: none;\n}\n\n.graph-explorer-drag-resizable-column.graph-explorer-drag-resizable-column--docked-bottom .graph-explorer-drag-resizable-column__handle,\n.graph-explorer-drag-resizable-column.graph-explorer-drag-resizable-column--docked-top .graph-explorer-drag-resizable-column__handle {\n  height: 8px;\n  width: 100%;\n  top: initial;\n  left: 0;\n  cursor: ns-resize;\n}\n.graph-explorer-drag-resizable-column.graph-explorer-drag-resizable-column--docked-bottom .graph-explorer-drag-resizable-column__handle-btn,\n.graph-explorer-drag-resizable-column.graph-explorer-drag-resizable-column--docked-top .graph-explorer-drag-resizable-column__handle-btn {\n  height: 100%;\n  width: 40px;\n  top: 0;\n  left: 50%;\n  margin-left: -20px;\n  margin-top: 0px;\n}\n\n.graph-explorer-drag-resizable-column {\n  display: flex;\n  flex-direction: column;\n  position: relative;\n}\n.graph-explorer-drag-resizable-column__handle {\n  background: #fff url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAHElEQVQIW2PcvHnzf19fX0YGKIAzMARgKjFUAABdvQgFy9518AAAAABJRU5ErkJggg==\") repeat;\n  width: 8px;\n  height: 100%;\n  position: absolute;\n  top: 0;\n  left: initial;\n  z-index: 2;\n  -webkit-transition: 0.3s;\n  -moz-transition: 0.3s;\n  transition: 0.3s;\n  cursor: ew-resize;\n}\n.graph-explorer-drag-resizable-column__handle-btn {\n  background: #eee;\n  cursor: pointer;\n  height: 40px;\n  position: absolute;\n  top: 50%;\n  left: 0;\n  margin-top: -20px;\n  width: 100%;\n  z-index: 1;\n  -webkit-transition: 0.3s;\n  -moz-transition: 0.3s;\n  transition: 0.3s;\n}\n.graph-explorer-drag-resizable-column__handle-btn::before {\n  background-position: 0 0;\n  background-repeat: no-repeat;\n  background-size: cover;\n  content: \"\";\n  height: 6px;\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  margin-top: -3px;\n  margin-left: -3px;\n  width: 6px;\n  -webkit-transition: 0.3s;\n  -moz-transition: 0.3s;\n  transition: 0.3s;\n}\n.graph-explorer-drag-resizable-column__handle-btn:hover {\n  background: #b3b3b3;\n  transform: scale(1.2);\n}\n.graph-explorer-drag-resizable-column--closed .graph-explorer-drag-resizable-column__handle-btn::before {\n  transform: rotate(180deg);\n}\n.graph-explorer-drag-resizable-column--docked-left {\n  margin-right: 8px;\n}\n.graph-explorer-drag-resizable-column--docked-left .graph-explorer-drag-resizable-column__handle {\n  right: -8px;\n}\n.graph-explorer-drag-resizable-column--docked-left .graph-explorer-drag-resizable-column__handle-btn::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACXSURBVHjaYvz//z8DIbBlyxYmIDUTiI/6+PgsQJZjJGQAVPMcIE4E4n9AnAA0ZDFRBqBphoELQGwKNOQPiMNEoubLQOwG04zTADyanYGaXyOrZaJEM4YBpGpGMYAczXgDkVgANwBoCyiOU4B4PpK8LhDvBbpOlCgXkGMIhhdINQRrGJBiCO2SMg6XgPh9yEmZkdLsDBBgAMUxZ3KEE1BeAAAAAElFTkSuQmCC\");\n}\n.graph-explorer-drag-resizable-column--docked-left .graph-explorer-drag-resizable-column__handle-btn:hover::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACXSURBVHjaYvz//z8DIfD+/XsmIDUTiI8KCgouQJZjJGQAVPMcIE4E4n9AnAA0ZDFRBqBphoELQGwKNOQPiMNEoubLQOwG04zTADyanYGaXyOrZaJEM4YBpGpGMYAczXgDkVgANwBoCyiOU4B4PpK8LhDvBbpOlCgXkGMIhhdINQRrGJBiCO2SMg6XgPh9yEmZkdLsDBBgAKQBZhCkUF/8AAAAAElFTkSuQmCC\");\n}\n.graph-explorer-drag-resizable-column--docked-right {\n  margin-left: 8px;\n}\n.graph-explorer-drag-resizable-column--docked-right .graph-explorer-drag-resizable-column__handle {\n  left: -8px;\n}\n.graph-explorer-drag-resizable-column--docked-right .graph-explorer-drag-resizable-column__handle-btn::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACdSURBVHjaYvz//z8DMtiyZUsCkLIG4nQfH59/DAQAI7IBQM2xQGoBEDMB8XwgTiFkCNwAoGYWIHUaiA2Q5AkawgRjABX9AVJuQHwZST4RiOcADWciaADUkNdAypkUQzAESTUEq6mkGILTb8QawsRAIcBpANAWUSC1F4h18UUrEyWasRpAimYMA0jVTJOk3AfE/4jVjJEbycnOAAEGABIyZ3LVo9KqAAAAAElFTkSuQmCC\");\n}\n.graph-explorer-drag-resizable-column--docked-right .graph-explorer-drag-resizable-column__handle-btn:hover::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACeSURBVHjaYvz//z8DMnj//n0CkLIG4nRBQcF/DAQAC5rmWCA1F4iZgJgZyE8hZAgjzAVAxSDDTgOxAZL8fCDGawgTjAFU9AdIuQHxZST5RCCeAzSciaABUENeAylnUgzBECTVEKymkmIITr8RawgTA4UApwFAW0SB1F4g1sUXrUyUaMZqACmaMQwgVTNNknIfEP8jVjOKC8jNzgABBgBosmVE6sxD1QAAAABJRU5ErkJggg==\");\n}\n.graph-explorer-drag-resizable-column--docked-top {\n  margin-bottom: 8px;\n}\n.graph-explorer-drag-resizable-column--docked-top .graph-explorer-drag-resizable-column__handle {\n  bottom: -8px;\n}\n.graph-explorer-drag-resizable-column--docked-top .graph-explorer-drag-resizable-column__handle-btn::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4T7WTzw2CMBSH37Ou4BiemICYeODABiYSmcAJOoELiPHgBiXhYGKYgBNjuIJQ80ghBfsaEmKPbb/v90v/ICwcuJAHr0BKuaIAKWXLBbECgoMgyAisqirlJE6BBScm+c5JfgQOuG/vlIwEHpiVDAIGrg25tQ5x1KQTcLAQYkfrTdO8AMApQR8cRdGbBEVRbDgJ5nl+BYDUqlhTcg/384wkQ6XUERFvAECPxgkzklZrferOQCl1QMSzEGI/TZ6+QNPkqbW+xHH8GG6hLMt1GIafOX/D3vvfzzSnzRcwRIO9lTALYQAAAABJRU5ErkJggg==\");\n}\n.graph-explorer-drag-resizable-column--docked-top .graph-explorer-drag-resizable-column__handle-btn:hover::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA1ElEQVQ4T7WTQQrCMBBF88Usu2jBY3gKwVsIij2BB/ECVlx4C8FT9BhCZ9FlpV9SmlJrphSKWSZ57w+ZCczMhZm8GRWQXLgAALUWpAocXBRF5sAkSVJNEhR4GMDBCUjeNMmPYAj70jXJl0CDxySdQIHzFl5rkkagwdbajTuvquppjAlKMAZHUfRygrIsV6pERC4k016fc5fsYb8fkgDIICJ7kldjjBuaIKxIagDH5g1EZEfyZK3dDpOHE9hW8gBwjuP43u/CEsB7yt8g2d3972eaUs0Hvw2bpYUKd8YAAAAASUVORK5CYII=\");\n}\n.graph-explorer-drag-resizable-column--docked-bottom {\n  margin-top: 8px;\n}\n.graph-explorer-drag-resizable-column--docked-bottom .graph-explorer-drag-resizable-column__handle {\n  top: -8px;\n}\n.graph-explorer-drag-resizable-column--docked-bottom .graph-explorer-drag-resizable-column__handle-btn::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA60lEQVQ4T62TzQ2CQBBGv3FtwTI8UQEx8cCBDkw0UoEVbAU2IMaDHSwJBxNDBZwswxZc1ixhCbI/IUGOy7w3s7MzhJkfzeTRC6qqWsZx/JkiHMa2AiHEjohOjLFtkiTvkKQsy5WU8qGUOqdpeichxJ6IrgAWAF6MsY1P0sFPAGsAjVLqSEVRXABkg6xOyQg24TlxzhdRFOUADj6JB77VdZ21PQhJ9H8ppSnb5GhhznnTv4JP0hH6zhasD37mwCMZPkqf2RxagxSQWLBVgbE6JE7YKxg1FqZhrgEL7oKupJM1vun83zJNWSJXzBeWo4O9On9s3QAAAABJRU5ErkJggg==\");\n}\n.graph-explorer-drag-resizable-column--docked-bottom .graph-explorer-drag-resizable-column__handle-btn:hover::before {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA5klEQVQ4T62TQQrCMBBF5xez7KIFj+EpBG8hKPYEHsQLWHHhLQRP4TGEZtFlpF8S2hJtUgo1q5DMf/NnJoHMXJiplx5AcgHgPQXoxzqA1npL8qiU2qRp+hqD1HW9NMbcAZyyLLtBa70jeRGRRESeSql1DNKKHyKyEpEGwMECziQLL2sQ8iN24QBKkEyqqioB7GOQkJjkNc/zwvVgDGLvjTGdbZejFwONP4Wgk9aVrXkgdmX4HY846UP8zN3h4CHFICHxwIFn86ucmDgK8Btr967bQBN6YKN/wZbTzjsoHnUw5U/8BfABHFmbpQyQ0q0AAAAASUVORK5CYII=\");\n}\n\n.introjs-tooltiptext {\n  color: #333;\n  font-family: \"Helvetica Neue\", \"Helvetica\", \"Arial\", sans-serif;\n  font-size: 14px;\n  line-height: 1.42857;\n}\n\n.graph-explorer-toolbar {\n  display: inline-flex;\n  align-items: center;\n  padding: 6px;\n  background: var(--ge-surface);\n  border: 1px solid var(--ge-border);\n  border-radius: var(--ge-radius-lg);\n  box-shadow: var(--ge-shadow-md);\n}\n.graph-explorer-toolbar .graph-explorer-btn-group {\n  display: inline-flex;\n  align-items: center;\n  flex-wrap: wrap;\n  gap: 2px;\n}\n.graph-explorer-toolbar .graph-explorer-btn-group > .graph-explorer-btn,\n.graph-explorer-toolbar .graph-explorer-btn-group > .graph-explorer-btn-group {\n  float: none;\n  margin-left: 0;\n}\n.graph-explorer-toolbar .graph-explorer-btn-default {\n  background: transparent;\n  border-color: transparent;\n  box-shadow: none;\n  color: var(--ge-text-muted);\n}\n.graph-explorer-toolbar .graph-explorer-btn-default:hover {\n  background: var(--ge-surface-3);\n  border-color: transparent;\n  color: var(--ge-text);\n}\n.graph-explorer-toolbar .graph-explorer-btn-default.active {\n  background: var(--ge-accent-soft);\n  border-color: transparent;\n  color: var(--ge-accent-hover);\n}\n.graph-explorer-toolbar__language-selector {\n  display: inline-flex;\n  align-items: center;\n  margin-left: 8px;\n  padding-left: 10px;\n  border-left: 1px solid var(--ge-border);\n  color: var(--ge-text-muted);\n  font-size: 13px;\n}\n.graph-explorer-toolbar__language-selector > label {\n  margin-right: 8px;\n  margin-bottom: 0;\n  font-weight: 500;\n}\n.graph-explorer-toolbar__language-selector > label > span {\n  vertical-align: middle;\n}\n.graph-explorer-toolbar__language-selector > select {\n  height: 32px;\n  padding: 0 10px;\n  background: var(--ge-surface);\n  border: 1px solid var(--ge-border-strong);\n  border-radius: var(--ge-radius-sm);\n  color: var(--ge-text);\n  cursor: pointer;\n  transition: border-color var(--ge-transition), box-shadow var(--ge-transition);\n}\n.graph-explorer-toolbar__language-selector > select:focus {\n  outline: none;\n  border-color: var(--ge-accent);\n  box-shadow: var(--ge-ring);\n}\n.graph-explorer-toolbar__toggle {\n  line-height: 1;\n}\n.graph-explorer-toolbar__toggle:after {\n  background-position: center;\n  background-repeat: no-repeat;\n  content: \"\";\n  display: block;\n  height: 14px;\n  margin: 2px 0;\n  width: 14px;\n}\n.graph-explorer-toolbar__toggle-left:after {\n  background-image: url(\"data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%20469.333%20469.333'%3e%3cpath%20fill='%23333'%20d='M448,0H21.333C9.552,0,0,9.552,0,21.333V448c0,11.781,9.552,21.333,21.333,21.333H448c11.781,0,21.333-9.552,21.333-21.333V21.333C469.333,9.552,459.781,0,448,0z%20M138.667,426.667h-96v-384h96V426.667zM426.667,426.667H181.333v-384h245.333V426.667z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-toolbar__toggle-right:after {\n  background-image: url(\"data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%20469.333%20469.333'%3e%3cpath%20fill='%23333'%20d='M448,0H21.333C9.552,0,0,9.552,0,21.333V448c0,11.781,9.552,21.333,21.333,21.333H448c11.781,0,21.333-9.552,21.333-21.333V21.333C469.333,9.552,459.781,0,448,0z%20M288,426.667H42.667v-384H288V426.667zM426.667,426.667h-96v-384h96V426.667z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-toolbar__toggle-left.active:after {\n  background-image: url(\"data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%20469.333%20469.333'%3e%3cpath%20fill='%23333'%20d='m%2030.5,235.66084%200,-205.208259%2059.6835,0%2059.68352,0%200,205.208259%200,205.20828%20-59.68352,0%20-59.6835,0%200,-205.20828%20z'/%3e%3cpath%20fill='%23333'%20d='M448,0H21.333C9.552,0,0,9.552,0,21.333V448c0,11.781,9.552,21.333,21.333,21.333H448c11.781,0,21.333-9.552,21.333-21.333V21.333C469.333,9.552,459.781,0,448,0z%20M138.667,426.667h-96v-384h96V426.667zM426.667,426.667H181.333v-384h245.333V426.667z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-toolbar__toggle-right.active:after {\n  background-image: url(\"data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%20469.333%20469.333'%3e%3cpath%20fill='%23333'%20d='m%20318.9149,233.50816%200,-205.208262%2059.6835,0%2059.68351,0%200,205.208262%200,205.20828%20-59.68351,0%20-59.6835,0%200,-205.20828%20z'/%3e%3cpath%20fill='%23333'%20d='M448,0H21.333C9.552,0,0,9.552,0,21.333V448c0,11.781,9.552,21.333,21.333,21.333H448c11.781,0,21.333-9.552,21.333-21.333V21.333C469.333,9.552,459.781,0,448,0z%20M288,426.667H42.667v-384H288V426.667zM426.667,426.667h-96v-384h96V426.667z'/%3e%3c/svg%3e\");\n}\n.graph-explorer-toolbar__layout-group {\n  display: inline-flex;\n  align-items: center;\n  margin-left: 5px;\n  height: 32px;\n}\n.graph-explorer-toolbar__layout-group > label {\n  margin-right: 5px;\n  margin-bottom: 0;\n}\n.graph-explorer-toolbar__layout-group .btn-group, .graph-explorer-toolbar__layout-group button {\n  height: 100%;\n}\n\n.graph-explorer-toolbar .graph-explorer-toolbar__undo,\n.graph-explorer-toolbar .graph-explorer-toolbar__redo {\n  display: none;\n}\n\n.graph-explorer {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  box-sizing: border-box;\n  white-space: initial;\n  color: var(--ge-text);\n  background: var(--ge-bg);\n  font-family: var(--ge-font-sans);\n  font-size: 14px;\n  line-height: 1.5;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-rendering: optimizeLegibility;\n}\n.graph-explorer *, .graph-explorer *:before, .graph-explorer *:after {\n  box-sizing: inherit;\n}\n.graph-explorer__toolbar-widget {\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n.graph-explorer__workspace {\n  display: flex;\n  flex: auto;\n  overflow: hidden;\n  flex-direction: column;\n}\n.graph-explorer__main-panel {\n  display: flex;\n  flex: auto;\n  overflow: hidden;\n  width: 0;\n}\n.graph-explorer--unselectable {\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.graph-explorer--horizontal-resizing * {\n  cursor: ew-resize !important;\n}\n.graph-explorer--vertical-resizing * {\n  cursor: ns-resize !important;\n}\n.graph-explorer h4 {\n  font-size: 18px;\n  font-weight: 600;\n  line-height: 1.2;\n  letter-spacing: -0.01em;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.graph-explorer select {\n  color: inherit;\n  margin: 0;\n  font: inherit;\n  line-height: inherit;\n  text-transform: none;\n}\n.graph-explorer hr {\n  border: 0;\n  border-top: 1px solid var(--ge-border);\n  height: 0;\n}\n.graph-explorer ::-webkit-scrollbar {\n  width: 10px;\n  height: 10px;\n}\n.graph-explorer ::-webkit-scrollbar-thumb {\n  background: var(--ge-border-strong);\n  border: 3px solid transparent;\n  background-clip: content-box;\n  border-radius: var(--ge-radius-pill);\n}\n.graph-explorer ::-webkit-scrollbar-thumb:hover {\n  background: var(--ge-text-subtle);\n  border: 3px solid transparent;\n  background-clip: content-box;\n}\n.graph-explorer ::-webkit-scrollbar-track {\n  background: transparent;\n}\n\n.graph-explorer-scrollable {\n  flex: 1 1 0px;\n  overflow-y: scroll;\n}\n\n.graph-explorer-scrollable > * {\n  position: relative;\n}\n\n.jstree-icon.jstree-themeicon.jstree-themeicon-custom {\n  background-size: contain !important;\n}\n\n.graph-explorer-default-template, .graph-explorer-group-template__wrap {\n  max-width: 450px;\n  float: left;\n  border-radius: var(--ge-radius-lg);\n  border-style: solid;\n  border-width: 1px;\n  overflow: hidden;\n  box-shadow: var(--ge-shadow-md);\n}\n.graph-explorer-default-template__thumbnail {\n  text-align: center;\n}\n.graph-explorer-default-template__thumbnail > img {\n  max-width: 200px;\n}\n.graph-explorer-default-template[data-expanded=true] .graph-explorer-default-template__thumbnail > img, [data-expanded=true].graph-explorer-group-template__wrap .graph-explorer-default-template__thumbnail > img {\n  max-width: 350px;\n}\n\n.graph-explorer-default-template_type-line, .graph-explorer-group-template__type-line {\n  padding: 0px 7px;\n  color: white;\n  height: 18px;\n  margin-bottom: 2px;\n  overflow: hidden;\n  display: flex;\n  align-items: baseline;\n  margin-top: -3px;\n}\n\ndiv.graph-explorer-default-template_type-line__icon, div.graph-explorer-group-template__type-line-icon {\n  position: inherit !important;\n  margin-right: 4px;\n}\n\n.graph-explorer-default-template_type-line_text-container, .graph-explorer-group-template__type-line-text-container {\n  flex-grow: 1;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  width: 0;\n}\n\n.graph-explorer-default-template_type-line_text-container__text, .graph-explorer-group-template__type-line-text {\n  display: inline;\n  white-space: nowrap;\n  font-size: 12px;\n}\n\n.graph-explorer-default-template_body, .graph-explorer-group-template__body {\n  border-bottom-left-radius: 12px;\n  border-bottom-right-radius: 12px;\n  border-top-style: solid;\n  border-top-width: 1px;\n  background: white;\n  padding: 7px 10px 8px 10px;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n}\n\n.graph-explorer-default-template_body__label, .graph-explorer-group-template__label {\n  font-size: 18px;\n  font-weight: 600;\n  letter-spacing: -0.01em;\n  color: var(--ge-text);\n  overflow: hidden;\n  text-overflow: ellipsis;\n  margin-bottom: 0;\n  white-space: nowrap;\n  word-wrap: break-word;\n}\n\n.graph-explorer-default-template_body_expander {\n  width: 100%;\n  overflow: hidden;\n  display: flex;\n}\n\n.graph-explorer-default-template_body_expander__iri_label {\n  font-size: 12px;\n  font-weight: 100;\n  margin-right: 15px;\n  color: #b6b6b6;\n}\n\n.graph-explorer-default-template_body_expander_iri {\n  font-size: 12px;\n  width: 100%;\n  overflow: hidden;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n\n.graph-explorer-default-template_body_expander_iri__link {\n  color: #b6b6b6;\n}\n\n.graph-explorer-default-template_body_expander__hr {\n  margin: 5px 0px 5px 0px;\n}\n\n.graph-explorer-default-template_body_expander_property-table {\n  font-size: 15px;\n  font-weight: 100;\n  margin-bottom: 5px;\n  max-height: 200px;\n  overflow-y: scroll;\n  overflow-x: hidden;\n}\n\n.graph-explorer-default-template_body_expander_property-table_row {\n  white-space: nowrap;\n}\n\n.graph-explorer-default-template_body_expander_property-table_row__key {\n  display: inline-block;\n  width: 50%;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  vertical-align: top;\n}\n\n.graph-explorer-default-template_body_expander_property-table_row_key {\n  display: inline-block;\n  width: 50%;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  vertical-align: top;\n}\n\n.graph-explorer-default-template_body_expander_property-table_row_key_values {\n  display: inline-block;\n  width: 50%;\n  text-overflow: ellipsis;\n  overflow: hidden;\n}\n\n.graph-explorer-default-template_body_expander_property-table_row_key_values__value {\n  width: 100%;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: initial;\n  padding-right: 10px;\n}\n\n.graph-explorer-group-template {\n  overflow: hidden;\n}\n.graph-explorer-group-template__wrap {\n  max-width: none;\n}\n.graph-explorer-group-template__body {\n  overflow: visible;\n}\n.graph-explorer-group-template__embedded-layer {\n  margin-top: 7px;\n}\n.graph-explorer-group-template .graph-explorer-paper__canvas {\n  border-color: #fff;\n}\n\n.graph-explorer-standard-template {\n  min-width: 180px;\n  max-width: 400px;\n  float: left;\n}\n.graph-explorer-standard-template__main {\n  border-radius: var(--ge-radius);\n  border: 1px solid;\n  overflow: hidden;\n  box-shadow: var(--ge-shadow-md);\n}\n.graph-explorer-standard-template__body {\n  margin-left: 8px;\n  border-radius: 0 var(--ge-radius) var(--ge-radius) 0;\n  border-left: 1px solid;\n  padding: 4px 0;\n  background: var(--ge-surface);\n}\n.graph-explorer-standard-template__body-horizontal {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  overflow: hidden;\n}\n.graph-explorer-standard-template__body-content {\n  flex-grow: 1;\n  min-width: 0;\n  margin-right: 12px;\n}\n.graph-explorer-standard-template__label {\n  font-size: 18px;\n  font-weight: 600;\n  letter-spacing: -0.01em;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n.graph-explorer-standard-template__thumbnail {\n  font-size: 26px;\n  margin: 5px 10px;\n  flex-shrink: 0;\n  width: 50px;\n  height: 50px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n.graph-explorer-standard-template__thumbnail-image {\n  max-height: 100%;\n  max-width: 100%;\n}\n.graph-explorer-standard-template__thumbnail-icon {\n  max-height: 26px;\n  max-width: 26px;\n}\n.graph-explorer-standard-template__photo {\n  border-bottom: 1px solid;\n}\n.graph-explorer-standard-template__photo-image {\n  width: 100%;\n  border-radius: 2px 2px 0 0;\n}\n.graph-explorer-standard-template__type {\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  font-size: 11px;\n  font-style: italic;\n  color: #999;\n  display: flex;\n}\n.graph-explorer-standard-template__type-value {\n  width: 0;\n  flex-grow: 1;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n.graph-explorer-standard-template__iri {\n  width: 100%;\n  overflow: hidden;\n  display: flex;\n}\n.graph-explorer-standard-template__iri-key {\n  font-size: 12px;\n  margin-right: 4px;\n  color: #b6b6b6;\n}\n.graph-explorer-standard-template__iri-value {\n  font-size: 12px;\n  width: 100%;\n  overflow: hidden;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n.graph-explorer-standard-template__iri-value a {\n  color: #b6b6b6;\n}\n.graph-explorer-standard-template__hr {\n  margin: 5px 0;\n}\n.graph-explorer-standard-template__properties {\n  font-size: 15px;\n  max-height: 200px;\n  overflow-y: scroll;\n  overflow-x: hidden;\n}\n.graph-explorer-standard-template__propertites-row {\n  white-space: nowrap;\n}\n.graph-explorer-standard-template__properties-key {\n  display: inline-block;\n  width: 50%;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  vertical-align: top;\n}\n.graph-explorer-standard-template__properties-values {\n  display: inline-block;\n  width: 50%;\n  text-overflow: ellipsis;\n  overflow: hidden;\n}\n.graph-explorer-standard-template__properties-value {\n  width: 100%;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: initial;\n  padding-right: 10px;\n}\n.graph-explorer-standard-template__pinned-props {\n  border-top: 1px solid;\n  margin: 0 5px;\n}\n.graph-explorer-standard-template__dropdown {\n  border-radius: var(--ge-radius);\n  background-color: var(--ge-surface);\n  margin-top: 6px;\n  border: 1px solid;\n  box-shadow: var(--ge-shadow-md);\n}\n.graph-explorer-standard-template__dropdown-content {\n  width: 100%;\n  padding: 9px;\n}\n.graph-explorer-standard-template__actions {\n  display: flex;\n  justify-content: space-between;\n}\n.graph-explorer-standard-template__actions button {\n  padding: 5px;\n  min-width: 60px;\n}/*$vite$:1*/"));			document.head.appendChild(elementStyle);		}	} catch (e) {		console.error("vite-plugin-css-injected-by-js", e);	}})();
import * as React from "react";
import { Component, cloneElement, createContext, createElement } from "react";
import { hcl } from "d3-color";
import { cloneDeep, defaultsDeep, each, keyBy, map, pick, uniqueId } from "lodash";
import * as N3 from "n3";
import * as cola from "webcola";
import { createRoot } from "react-dom/client";
import saveAs from "file-saverjs";
//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __exportAll = (all, no_symbols) => {
	let target = {};
	for (var name in all) __defProp(target, name, {
		get: all[name],
		enumerable: true
	});
	if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
	return target;
};
//#endregion
//#region src/graph-explorer/data/utils.ts
/** Generates random 32-digit hexadecimal string. */
function generate128BitID() {
	function random32BitDigits() {
		return Math.floor((1 + Math.random()) * 4294967296).toString(16).substring(1);
	}
	return random32BitDigits() + random32BitDigits() + random32BitDigits() + random32BitDigits();
}
/**
* Calculate a 32 bit FNV-1a hash
* Found here: https://gist.github.com/vaiorabbit/5657561
* Ref.: http://isthe.com/chongo/tech/comp/fnv/
*
* @param {string} str the input value
* @param {integer} [seed] optionally pass the hash of the previous chunk
* @returns {integer}
*/
function hashFnv32a(str, seed = 2166136261) {
	let i, l, hval = seed & 2147483647;
	for (i = 0, l = str.length; i < l; i++) {
		hval ^= str.charCodeAt(i);
		hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
	}
	return hval >>> 0;
}
/**
* Extracts local name for URI the same way as it's done in RDF4J.
*/
function getUriLocalName(uri) {
	let index = uri.indexOf("#");
	if (index < 0) index = uri.lastIndexOf("/");
	if (index < 0) index = uri.lastIndexOf(":");
	if (index < 0) return;
	return uri.substring(index + 1);
}
//#endregion
//#region src/graph-explorer/data/model.ts
function isIriProperty(e) {
	return e && e.type === "uri";
}
function isLiteralProperty(e) {
	return e && e.type === "string";
}
function sameLink(left, right) {
	return left.linkTypeId === right.linkTypeId && left.sourceId === right.sourceId && left.targetId === right.targetId;
}
function hashLink(link) {
	const { linkTypeId, sourceId, targetId } = link;
	let hash = hashFnv32a(linkTypeId);
	hash = hash * 31 + hashFnv32a(sourceId);
	hash = hash * 31 + hashFnv32a(targetId);
	return hash;
}
function sameElement(left, right) {
	return left.id === right.id && isArraysEqual(left.types, right.types) && isLiteralsEqual(left.label.values, right.label.values) && left.image === right.image && isPropertiesEqual(left.properties, right.properties) && (!left.sources && !right.sources || left.sources && right.sources && isArraysEqual(left.sources, right.sources));
}
function isArraysEqual(left, right) {
	if (left.length !== right.length) return false;
	for (let i = 0; i < left.length; i++) if (left[i] !== right[i]) return false;
	return true;
}
function isLiteralsEqual(left, right) {
	if (left.length !== right.length) return false;
	for (let i = 0; i < left.length; i++) {
		const leftValue = left[i];
		const rightValue = right[i];
		if (leftValue.value !== rightValue.value || leftValue.language !== rightValue.language) return false;
	}
	return true;
}
function isIriPropertiesEqual(left, right) {
	if (!isIriProperty(left) || !isIriProperty(right)) return false;
	if (left.values.length !== right.values.length) return false;
	for (let i = 0; i < left.values.length; i++) {
		const leftValue = left.values[i];
		const rightValue = right.values[i];
		if (leftValue.value !== rightValue.value) return false;
	}
	return true;
}
function isLiteralPropertiesEqual(left, right) {
	if (!isLiteralProperty(left) || !isLiteralProperty(right)) return false;
	return isLiteralsEqual(left.values, right.values);
}
function isPropertiesEqual(left, right) {
	if (Object.keys(left).length !== Object.keys(right).length) return false;
	for (const key in left.properties) if (key in left.properties) {
		const leftProperty = left[key];
		const rightProperty = right[key];
		if (!rightProperty) return false;
		if (!isIriPropertiesEqual(leftProperty, rightProperty) && !isLiteralPropertiesEqual(leftProperty, rightProperty)) return false;
	}
	return true;
}
//#endregion
//#region src/graph-explorer/customization/templates/utils.ts
function getProperty(props, id) {
	if (props && props[id]) return getPropertyValues(props[id]).join(", ");
	else return;
}
function getPropertyValues(property) {
	if (isIriProperty(property)) return property.values.map(({ value }) => value);
	else if (isLiteralProperty(property)) return property.values.map(({ value }) => value);
	return [];
}
//#endregion
//#region src/graph-explorer/customization/templates/default.tsx
var CLASS_NAME$25 = "graph-explorer-default-template";
var DefaultElementTemplate = class extends React.Component {
	render() {
		const props = this.props;
		const image = props.imgUrl ? /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$25}__thumbnail` }, /* @__PURE__ */ React.createElement("img", { src: props.imgUrl })) : void 0;
		const expander = props.isExpanded ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_body_expander" }, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_body_expander__iri_label" }, "IRI:"), /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_body_expander_iri" }, /* @__PURE__ */ React.createElement("a", {
			className: "graph-explorer-default-template_body_expander_iri__link",
			href: props.iri,
			title: props.iri
		}, props.iri))), /* @__PURE__ */ React.createElement("hr", { className: "graph-explorer-default-template_body_expander__hr" }), this.renderPropertyTable()) : null;
		return /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-default-template",
			style: {
				backgroundColor: props.color,
				borderColor: props.color
			},
			"data-expanded": this.props.isExpanded
		}, /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-default-template_type-line",
			title: props.label
		}, /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-default-template_type-line__icon",
			"aria-hidden": "true"
		}, /* @__PURE__ */ React.createElement("img", { src: props.iconUrl })), /* @__PURE__ */ React.createElement("div", {
			title: props.types,
			className: "graph-explorer-default-template_type-line_text-container"
		}, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_type-line_text-container__text" }, props.types))), image, /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-default-template_body",
			style: { borderColor: props.color }
		}, /* @__PURE__ */ React.createElement("span", {
			className: "graph-explorer-default-template_body__label",
			title: props.label
		}, props.label), expander));
	}
	renderPropertyTable() {
		const { propsAsList } = this.props;
		if (propsAsList && propsAsList.length > 0) return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_body_expander_property-table" }, propsAsList.map((prop) => {
			const values = getPropertyValues(prop.property).map((text, index) => /* @__PURE__ */ React.createElement("div", {
				className: "graph-explorer-default-template_body_expander_property-table_row_key_values__value",
				key: index,
				title: text
			}, text));
			return /* @__PURE__ */ React.createElement("div", {
				key: prop.id,
				className: "graph-explorer-default-template_body_expander_property-table_row"
			}, /* @__PURE__ */ React.createElement("div", {
				title: prop.name + " (" + prop.id + ")",
				className: "graph-explorer-default-template_body_expander_property-table_row__key"
			}, prop.name), /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-default-template_body_expander_property-table_row_key_values" }, values));
		}));
		else return /* @__PURE__ */ React.createElement("div", null, "no properties");
	}
};
//#endregion
//#region src/graph-explorer/data/schema.ts
var DIAGRAM_CONTEXT_URL_V1 = "https://graph-explorer.org/context/v1.json";
var PLACEHOLDER_ELEMENT_TYPE = "http://graph-explorer.org/NewEntity";
var PLACEHOLDER_LINK_TYPE = "http://graph-explorer.org/NewLink";
var GRAPH_EXPLORER_ID_URL_PREFIX = "http://graph-explorer.org/data/";
var GenerateID = {
	forElement() {
		return `${GRAPH_EXPLORER_ID_URL_PREFIX}e_${generate128BitID()}`;
	},
	forLink() {
		return `${GRAPH_EXPLORER_ID_URL_PREFIX}l_${generate128BitID()}`;
	}
};
var TemplateProperties = {
	PinnedProperties: "graph-explorer:pinnedProperties",
	CustomLabel: "graph-explorer:customLabel"
};
//#endregion
//#region src/graph-explorer/viewUtils/events.ts
var EventSource = class {
	constructor() {
		this.listeners = /* @__PURE__ */ new Map();
	}
	on(eventKey, listener) {
		let listeners = this.listeners.get(eventKey);
		if (!listeners) {
			listeners = [];
			this.listeners.set(eventKey, listeners);
		}
		listeners.push(listener);
	}
	onAny(listener) {
		let listeners = this.anyListeners;
		if (!listeners) {
			listeners = [];
			this.anyListeners = listeners;
		}
		listeners.push(listener);
	}
	off(eventKey, listener) {
		const listeners = this.listeners.get(eventKey);
		if (!listeners) return;
		const index = listeners.indexOf(listener);
		if (index >= 0) listeners.splice(index, 1);
	}
	offAny(listener) {
		const listeners = this.anyListeners;
		if (!listeners) return;
		const index = listeners.indexOf(listener);
		if (index >= 0) listeners.splice(index, 1);
	}
	trigger(eventKey, data) {
		const listeners = this.listeners.get(eventKey);
		if (listeners) for (const listener of listeners) listener(data, eventKey);
		if (this.anyListeners) for (const anyListener of this.anyListeners) anyListener({ [eventKey]: data }, eventKey);
	}
};
var EventObserver = class {
	constructor() {
		this.unsubscribeByKey = /* @__PURE__ */ new Map();
		this.onDispose = [];
	}
	listen(events, eventKey, listener) {
		events.on(eventKey, listener);
		this.onDispose.push(() => events.off(eventKey, listener));
	}
	listenAny(events, listener) {
		events.onAny(listener);
		this.onDispose.push(() => events.offAny(listener));
	}
	listenOnce(events, eventKey, listener) {
		let handled = false;
		const onceListener = (data, key) => {
			handled = true;
			events.off(eventKey, onceListener);
			listener(data, key);
		};
		events.on(eventKey, onceListener);
		this.onDispose.push(() => {
			if (handled) return;
			events.off(eventKey, onceListener);
		});
	}
	stopListening() {
		for (const unsubscribe of this.onDispose) unsubscribe();
		this.onDispose.length = 0;
		this.unsubscribeByKey.forEach((unsubscribers) => {
			for (const unsubscribe of unsubscribers) unsubscribe();
		});
		this.unsubscribeByKey.clear();
	}
};
//#endregion
//#region src/graph-explorer/diagram/geometry.ts
var Vector = {
	equals(a, b) {
		return a.x === b.x && a.y === b.y;
	},
	length({ x, y }) {
		return Math.sqrt(x * x + y * y);
	},
	normalize({ x, y }) {
		if (x === 0 && y === 0) return {
			x,
			y
		};
		const inverseLength = 1 / Math.sqrt(x * x + y * y);
		return {
			x: x * inverseLength,
			y: y * inverseLength
		};
	},
	dot({ x: x1, y: y1 }, { x: x2, y: y2 }) {
		return x1 * x2 + y1 * y2;
	},
	cross2D({ x: x1, y: y1 }, { x: x2, y: y2 }) {
		return x1 * y2 - y1 * x2;
	}
};
var Rect = { center({ x, y, width, height }) {
	return {
		x: x + width / 2,
		y: y + height / 2
	};
} };
function boundsOf(element) {
	const { x, y } = element.position;
	const { width, height } = element.size;
	return {
		x,
		y,
		width,
		height
	};
}
function intersectRayFromRectangleCenter(sourceRect, rayTarget) {
	const isTargetInsideRect = sourceRect.width === 0 || sourceRect.height === 0 || rayTarget.x > sourceRect.x && rayTarget.x < sourceRect.x + sourceRect.width && rayTarget.y > sourceRect.y && rayTarget.y < sourceRect.y + sourceRect.height;
	const halfWidth = sourceRect.width / 2;
	const halfHeight = sourceRect.height / 2;
	const center = {
		x: sourceRect.x + halfWidth,
		y: sourceRect.y + halfHeight
	};
	if (isTargetInsideRect) return center;
	const direction = Vector.normalize({
		x: rayTarget.x - center.x,
		y: rayTarget.y - center.y
	});
	const rightDirection = {
		x: Math.abs(direction.x),
		y: direction.y
	};
	if (Vector.cross2D({
		x: halfWidth,
		y: -halfHeight
	}, rightDirection) > 0 && Vector.cross2D({
		x: halfWidth,
		y: halfHeight
	}, rightDirection) < 0) return {
		x: center.x + halfWidth * Math.sign(direction.x),
		y: center.y + halfWidth * direction.y / Math.abs(direction.x)
	};
	else return {
		x: center.x + halfHeight * direction.x / Math.abs(direction.y),
		y: center.y + halfHeight * Math.sign(direction.y)
	};
}
function isPolylineEqual(left, right) {
	if (left === right) return true;
	if (left.length !== right.length) return false;
	for (let i = 0; i < left.length; i++) {
		const a = left[i];
		const b = right[i];
		if (!(a.x === b.x && a.y === b.y)) return false;
	}
	return true;
}
function computePolyline(source, target, vertices) {
	const sourceRect = boundsOf(source);
	const targetRect = boundsOf(target);
	const startPoint = intersectRayFromRectangleCenter(sourceRect, vertices.length > 0 ? vertices[0] : Rect.center(targetRect));
	const endPoint = intersectRayFromRectangleCenter(targetRect, vertices.length > 0 ? vertices[vertices.length - 1] : Rect.center(sourceRect));
	return [
		startPoint,
		...vertices,
		endPoint
	];
}
function computePolylineLength(polyline) {
	let previous;
	return polyline.reduce((acc, point) => {
		const segmentLength = previous ? Vector.length({
			x: point.x - previous.x,
			y: point.y - previous.y
		}) : 0;
		previous = point;
		return acc + segmentLength;
	}, 0);
}
function getPointAlongPolyline(polyline, offset) {
	if (polyline.length === 0) throw new Error("Cannot compute a point for empty polyline");
	if (offset < 0) return polyline[0];
	let currentOffset = 0;
	for (let i = 1; i < polyline.length; i++) {
		const previous = polyline[i - 1];
		const point = polyline[i];
		const segment = {
			x: point.x - previous.x,
			y: point.y - previous.y
		};
		const segmentLength = Vector.length(segment);
		const newOffset = currentOffset + segmentLength;
		if (offset < newOffset) {
			const leftover = (offset - currentOffset) / segmentLength;
			return {
				x: previous.x + leftover * segment.x,
				y: previous.y + leftover * segment.y
			};
		} else currentOffset = newOffset;
	}
	return polyline[polyline.length - 1];
}
function findNearestSegmentIndex(polyline, location) {
	let minDistance = Infinity;
	let foundIndex = 0;
	for (let i = 0; i < polyline.length - 1; i++) {
		const pivot = polyline[i];
		const next = polyline[i + 1];
		const target = {
			x: location.x - pivot.x,
			y: location.y - pivot.y
		};
		const segment = {
			x: next.x - pivot.x,
			y: next.y - pivot.y
		};
		const segmentLength = Vector.length(segment);
		const projectionToSegment = Vector.dot(target, segment) / segmentLength;
		if (projectionToSegment < 0 || projectionToSegment > segmentLength) continue;
		const distanceToSegment = Math.abs(Vector.cross2D(target, segment)) / segmentLength;
		if (distanceToSegment < minDistance) {
			minDistance = distanceToSegment;
			foundIndex = i;
		}
	}
	return foundIndex;
}
function findElementAtPoint(elements, point) {
	for (let i = elements.length - 1; i >= 0; i--) {
		const element = elements[i];
		const { x, y, width, height } = boundsOf(element);
		if (element.temporary) continue;
		if (point.x >= x && point.x <= x + width && point.y >= y && point.y <= y + height) return element;
	}
}
function computeGrouping(elements) {
	const grouping = /* @__PURE__ */ new Map();
	for (const element of elements) {
		const group = element.group;
		if (typeof group === "string") {
			let children = grouping.get(group);
			if (!children) {
				children = [];
				grouping.set(group, children);
			}
			children.push(element);
		}
	}
	return grouping;
}
//#endregion
//#region src/graph-explorer/diagram/elements.ts
var LinkDirection = /* @__PURE__ */ function(LinkDirection) {
	LinkDirection["in"] = "in";
	LinkDirection["out"] = "out";
	return LinkDirection;
}({});
var Element$1 = class {
	constructor(props) {
		this.source = new EventSource();
		this.events = this.source;
		this.links = [];
		const { id, data, position = {
			x: 0,
			y: 0
		}, size = {
			width: 0,
			height: 0
		}, expanded = false, group, elementState, temporary = false } = props;
		this.id = id;
		this._data = data;
		this._position = position;
		this._size = size;
		this._expanded = expanded;
		this._group = group;
		this._elementState = elementState;
		this._temporary = temporary;
	}
	get iri() {
		return this._data.id;
	}
	get data() {
		return this._data;
	}
	setData(value) {
		const previous = this._data;
		if (previous === value) return;
		this._data = value;
		this.source.trigger("changeData", {
			source: this,
			previous
		});
		updateLinksToReferByNewIri(this, previous.id, value.id);
	}
	get position() {
		return this._position;
	}
	setPosition(value) {
		const previous = this._position;
		if (previous.x === value.x && previous.y === value.y) return;
		this._position = value;
		this.source.trigger("changePosition", {
			source: this,
			previous
		});
	}
	get size() {
		return this._size;
	}
	setSize(value) {
		const previous = this._size;
		if (previous.width === value.width && previous.height === value.height) return;
		this._size = value;
		this.source.trigger("changeSize", {
			source: this,
			previous
		});
	}
	get isExpanded() {
		return this._expanded;
	}
	setExpanded(value) {
		const previous = this._expanded;
		if (previous === value) return;
		this._expanded = value;
		this.source.trigger("changeExpanded", {
			source: this,
			previous
		});
	}
	get group() {
		return this._group;
	}
	setGroup(value) {
		const previous = this._group;
		if (previous === value) return;
		this._group = value;
		this.source.trigger("changeGroup", {
			source: this,
			previous
		});
	}
	get elementState() {
		return this._elementState;
	}
	setElementState(value) {
		const previous = this._elementState;
		if (previous === value) return;
		this._elementState = value;
		this.source.trigger("changeElementState", {
			source: this,
			previous
		});
	}
	get temporary() {
		return this._temporary;
	}
	focus() {
		this.source.trigger("requestedFocus", { source: this });
	}
	requestGroupContent() {
		this.source.trigger("requestedGroupContent", { source: this });
	}
	addToFilter(linkType, direction) {
		this.source.trigger("requestedAddToFilter", {
			source: this,
			linkType,
			direction
		});
	}
	redraw() {
		this.source.trigger("requestedRedraw", { source: this });
	}
};
function updateLinksToReferByNewIri(element, oldIri, newIri) {
	if (oldIri === newIri) return;
	for (const link of element.links) {
		let data = link.data;
		if (data.sourceId === oldIri) data = {
			...data,
			sourceId: newIri
		};
		if (data.targetId === oldIri) data = {
			...data,
			targetId: newIri
		};
		link.setData(data);
	}
}
var FatClassModel = class {
	constructor(props) {
		this.source = new EventSource();
		this.events = this.source;
		const { id, label = [], count } = props;
		this.id = id;
		this._label = label;
		this._count = count;
	}
	get label() {
		return this._label;
	}
	setLabel(value) {
		const previous = this._label;
		if (previous === value) return;
		this._label = value;
		this.source.trigger("changeLabel", {
			source: this,
			previous
		});
	}
	get count() {
		return this._count;
	}
	setCount(value) {
		const previous = this._count;
		if (previous === value) return;
		this._count = value;
		this.source.trigger("changeCount", {
			source: this,
			previous
		});
	}
};
var RichProperty = class {
	constructor(props) {
		this.source = new EventSource();
		this.events = this.source;
		const { id, label = [] } = props;
		this.id = id;
		this._label = label;
	}
	get label() {
		return this._label;
	}
	setLabel(value) {
		const previous = this._label;
		if (previous === value) return;
		this._label = value;
		this.source.trigger("changeLabel", {
			source: this,
			previous
		});
	}
};
var Link = class {
	constructor(props) {
		this.source = new EventSource();
		this.events = this.source;
		const { id = GenerateID.forLink(), typeId, sourceId, targetId, data, vertices = [], linkState } = props;
		this.id = id;
		this._typeId = typeId;
		this._sourceId = sourceId;
		this._targetId = targetId;
		this._data = data;
		this._vertices = vertices;
		this._linkState = linkState;
	}
	get typeId() {
		return this._typeId;
	}
	get sourceId() {
		return this._sourceId;
	}
	get targetId() {
		return this._targetId;
	}
	get data() {
		return this._data;
	}
	setData(value) {
		const previous = this._data;
		if (previous === value) return;
		this._data = value;
		this._typeId = value.linkTypeId;
		this.source.trigger("changeData", {
			source: this,
			previous
		});
	}
	get labelBounds() {
		return this._labelBounds;
	}
	setLabelBounds(value) {
		const previous = this._labelBounds;
		if (previous === value) return;
		this._labelBounds = value;
		this.source.trigger("changeLabelBounds", {
			source: this,
			previous
		});
	}
	get layoutOnly() {
		return this._layoutOnly;
	}
	setLayoutOnly(value) {
		const previous = this._layoutOnly;
		if (previous === value) return;
		this._layoutOnly = value;
		this.source.trigger("changeLayoutOnly", {
			source: this,
			previous
		});
	}
	get vertices() {
		return this._vertices;
	}
	setVertices(value) {
		const previous = this._vertices;
		if (isPolylineEqual(this._vertices, value)) return;
		this._vertices = value;
		this.source.trigger("changeVertices", {
			source: this,
			previous
		});
	}
	get linkState() {
		return this._linkState;
	}
	setLinkState(value) {
		const previous = this._linkState;
		if (previous === value) return;
		this._linkState = value;
		this.source.trigger("changeLinkState", {
			source: this,
			previous
		});
	}
};
function linkMarkerKey(linkTypeIndex, startMarker) {
	return `graph-explorer-${startMarker ? "mstart" : "mend"}-${linkTypeIndex}`;
}
/**
* Properties:
*     visible: boolean
*     showLabel: boolean
*     isNew?: boolean
*     label?: { values: LocalizedString[] }
*/
var FatLinkType = class {
	constructor(props) {
		this.source = new EventSource();
		this.events = this.source;
		this._isNew = false;
		this._visible = true;
		this._showLabel = true;
		const { id, index, label = [] } = props;
		this.id = id;
		this._index = index;
		this._label = label;
	}
	get index() {
		return this._index;
	}
	setIndex(value) {
		if (typeof this._index === "number") throw new Error("Cannot set index for link type more than once.");
		this._index = value;
	}
	get label() {
		return this._label;
	}
	setLabel(value) {
		const previous = this._label;
		if (previous === value) return;
		this._label = value;
		this.source.trigger("changeLabel", {
			source: this,
			previous
		});
	}
	get visible() {
		return this._visible;
	}
	get showLabel() {
		return this._showLabel;
	}
	setVisibility(params) {
		if (this._visible === params.visible && this._showLabel === params.showLabel) return;
		const preventLoading = Boolean(params.preventLoading) || this._visible === params.visible;
		this._visible = params.visible;
		this._showLabel = params.showLabel;
		this.source.trigger("changeVisibility", {
			source: this,
			preventLoading
		});
	}
	get isNew() {
		return this._isNew;
	}
	setIsNew(value) {
		const previous = this._isNew;
		if (previous === value) return;
		this._isNew = value;
		this.source.trigger("changeIsNew", {
			source: this,
			previous
		});
	}
};
var LinkVertex = class {
	constructor(link, vertexIndex) {
		this.link = link;
		this.vertexIndex = vertexIndex;
	}
	createAt(location) {
		const vertices = [...this.link.vertices];
		vertices.splice(this.vertexIndex, 0, location);
		this.link.setVertices(vertices);
	}
	moveTo(location) {
		const vertices = [...this.link.vertices];
		vertices.splice(this.vertexIndex, 1, location);
		this.link.setVertices(vertices);
	}
	remove() {
		const vertices = [...this.link.vertices];
		vertices.splice(this.vertexIndex, 1);
		this.link.setVertices(vertices);
	}
};
//#endregion
//#region src/graph-explorer/viewUtils/async.ts
var BatchingScheduler = class {
	constructor(waitingTime = 0) {
		this.waitingTime = waitingTime;
		this.useAnimationFrame = waitingTime === 0;
		this.runSynchronously = this.runSynchronously.bind(this);
	}
	schedule() {
		if (typeof this.scheduled === "undefined") if (this.useAnimationFrame) this.scheduled = requestAnimationFrame(this.runSynchronously);
		else this.scheduled = Number(setTimeout(this.runSynchronously, this.waitingTime));
	}
	runSynchronously() {
		if (this.cancelScheduledTimeout()) this.run();
	}
	dispose() {
		this.cancelScheduledTimeout();
	}
	cancelScheduledTimeout() {
		if (typeof this.scheduled !== "undefined") {
			if (this.useAnimationFrame) cancelAnimationFrame(this.scheduled);
			else clearTimeout(this.scheduled);
			this.scheduled = void 0;
			return true;
		}
		return false;
	}
};
var BufferingQueue = class extends BatchingScheduler {
	constructor(onFetch, waitingTime = 200) {
		super(waitingTime);
		this.onFetch = onFetch;
		this.fetchingQueue = Object.create(null);
	}
	push(key) {
		this.fetchingQueue[key] = true;
		this.schedule();
	}
	clear() {
		this.fetchingQueue = Object.create(null);
	}
	run() {
		const { fetchingQueue, onFetch } = this;
		this.fetchingQueue = Object.create(null);
		onFetch(Object.keys(fetchingQueue));
	}
};
var Debouncer = class extends BatchingScheduler {
	call(callback) {
		this.callback = callback;
		this.schedule();
	}
	run() {
		const callback = this.callback;
		callback();
	}
};
var Cancellation = class {
	static {
		this.NEVER_SIGNAL = {
			aborted: false,
			addEventListener: () => {},
			removeEventListener: () => {}
		};
	}
	constructor() {
		this.source = new EventSource();
		this.aborted = false;
		this.signal = new class {
			constructor(parent) {
				this.parent = parent;
			}
			get aborted() {
				return this.parent.aborted;
			}
			addEventListener(event, handler) {
				if (event !== "abort") return;
				if (this.parent.source) this.parent.source.on("abort", handler);
				else handler();
			}
			removeEventListener(event, handler) {
				if (event !== "abort") return;
				if (this.parent.source) this.parent.source.off("abort", handler);
			}
		}(this);
	}
	abort() {
		if (this.aborted) return;
		this.aborted = true;
		this.source.trigger("abort", void 0);
		this.source = void 0;
	}
};
var CancellationToken = {
	throwIfAborted(ct) {
		if (ct.aborted) throw new CancelledError();
	},
	mapCancelledToNull(ct, promise) {
		const onResolve = (value) => {
			if (ct.aborted) return null;
			return value;
		};
		const onReject = (err) => {
			if (ct.aborted) return null;
			return Promise.reject(err);
		};
		return promise.then(onResolve, onReject);
	}
};
var CancelledError = class CancelledError extends Error {
	constructor(message = "Operation was cancelled") {
		super(message);
		this.name = CancelledError.name;
		Object.setPrototypeOf(this, CancelledError.prototype);
	}
};
function delay(timeout) {
	return new Promise((resolve) => setTimeout(resolve, timeout));
}
function animateInterval(duration, onProgress, cancellation) {
	return new Promise((resolve) => {
		let animationFrameId;
		let start;
		const animate = (time) => {
			if (cancellation && cancellation.signal.aborted) return;
			start = start || time;
			let timePassed = time - start;
			if (timePassed > duration) timePassed = duration;
			onProgress(timePassed / duration);
			if (timePassed < duration) animationFrameId = requestAnimationFrame(animate);
			else resolve();
		};
		cancellation.signal.addEventListener("abort", () => {
			cancelAnimationFrame(animationFrameId);
			resolve();
		});
		animationFrameId = requestAnimationFrame(animate);
	});
}
function easeInOutBezier(t) {
	if (t < 0) return 0;
	if (t > 1) return 1;
	return t * t * (3 - 2 * t);
}
//#endregion
//#region src/graph-explorer/viewUtils/keyedObserver.ts
var KeyedObserver = class {
	constructor(subscribe) {
		this.subscribe = subscribe;
		this.observedKeys = /* @__PURE__ */ new Map();
	}
	observe(keys) {
		if (keys.length === 0 && this.observedKeys.size === 0) return;
		const newObservedKeys = /* @__PURE__ */ new Map();
		for (const key of keys) {
			if (newObservedKeys.has(key)) continue;
			let unsubscribe = this.observedKeys.get(key);
			if (!unsubscribe) unsubscribe = this.subscribe(key);
			newObservedKeys.set(key, unsubscribe);
		}
		this.observedKeys.forEach((unsubscribe, key) => {
			if (!newObservedKeys.has(key)) unsubscribe();
		});
		this.observedKeys = newObservedKeys;
	}
	stopListening() {
		this.observe([]);
	}
};
function observeElementTypes(model, event, listener) {
	return new KeyedObserver((key) => {
		const type = model.getClass(key);
		if (type) {
			type.events.on(event, listener);
			return () => type.events.off(event, listener);
		}
	});
}
function observeProperties(model, event, listener) {
	return new KeyedObserver((key) => {
		const property = model.getProperty(key);
		if (property) {
			property.events.on(event, listener);
			return () => property.events.off(event, listener);
		}
	});
}
function observeLinkTypes(model, event, listener) {
	return new KeyedObserver((key) => {
		const type = model.createLinkType(key);
		if (type) {
			type.events.on(event, listener);
			return () => type.events.off(event, listener);
		}
	});
}
//#endregion
//#region src/graph-explorer/diagram/history.ts
function createAction(title, action) {
	return {
		title,
		invoke: action
	};
}
function effectAction(title, body) {
	const perform = {
		title,
		invoke: () => {
			body();
			return skip;
		}
	};
	const skip = {
		title: "Skipped effect: " + title,
		invoke: () => perform
	};
	return perform;
}
var Command = {
	create: createAction,
	effect: effectAction
};
var NonRememberingHistory = class {
	constructor() {
		this.source = new EventSource();
		this.events = this.source;
		this.undoStack = [];
		this.redoStack = [];
		this.storeBatch = () => {};
		this.discardBatch = () => {};
	}
	reset() {
		this.source.trigger("historyChanged", { hasChanges: false });
	}
	undo() {
		throw new Error("Undo is unsupported");
	}
	redo() {
		throw new Error("Redo is unsupported");
	}
	execute(command) {
		command.invoke();
		this.source.trigger("historyChanged", { hasChanges: true });
	}
	registerToUndo(_command) {
		this.source.trigger("historyChanged", { hasChanges: true });
	}
	startBatch(_title) {
		return {
			history: this,
			store: this.storeBatch,
			discard: this.discardBatch
		};
	}
};
//#endregion
//#region src/graph-explorer/diagram/commands.ts
var RestoreGeometry = class RestoreGeometry {
	constructor(elementState, linkState) {
		this.elementState = elementState;
		this.linkState = linkState;
		this.title = "Move elements and links";
	}
	static capture(model) {
		return RestoreGeometry.captureElementsAndLinks(model.elements, model.links);
	}
	static captureElementsAndLinks(elements, links) {
		return new RestoreGeometry(elements.map((element) => ({
			element,
			position: element.position
		})), links.map((link) => ({
			link,
			vertices: link.vertices
		})));
	}
	hasChanges() {
		return this.elementState.length > 0 || this.linkState.length > 0;
	}
	filterOutUnchanged() {
		return new RestoreGeometry(this.elementState.filter(({ element, position }) => !Vector.equals(element.position, position)), this.linkState.filter(({ link, vertices }) => !isPolylineEqual(link.vertices, vertices)));
	}
	invoke() {
		const previous = RestoreGeometry.captureElementsAndLinks(this.elementState.map((state) => state.element), this.linkState.map((state) => state.link));
		for (const { element, position } of [...this.elementState].reverse()) element.setPosition(position);
		for (const { link, vertices } of this.linkState) link.setVertices(vertices);
		return previous;
	}
};
function restoreCapturedLinkGeometry(link) {
	const vertices = link.vertices;
	return Command.create("Change link vertices", () => {
		const capturedInverse = restoreCapturedLinkGeometry(link);
		link.setVertices(vertices);
		return capturedInverse;
	});
}
function setElementExpanded(element, expanded) {
	const title = expanded ? "Expand element" : "Collapse element";
	return Command.create(title, () => {
		element.setExpanded(expanded);
		return setElementExpanded(element, !expanded);
	});
}
function changeLinkTypeVisibility(params) {
	const { linkType, visible, showLabel, preventLoading } = params;
	return Command.create("Change link type visibility", () => {
		const previousVisible = linkType.visible;
		const previousShowLabel = linkType.showLabel;
		linkType.setVisibility({
			visible,
			showLabel,
			preventLoading
		});
		return changeLinkTypeVisibility({
			linkType,
			visible: previousVisible,
			showLabel: previousShowLabel,
			preventLoading
		});
	});
}
function setElementData(model, target, data) {
	const elements = model.elements.filter((el) => el.iri === target);
	const previous = elements.length > 0 ? elements[0].data : void 0;
	return Command.create("Set element data", () => {
		for (const element of model.elements.filter((el) => el.iri === target)) element.setData(data);
		return setElementData(model, data.id, previous);
	});
}
function setLinkData(model, oldData, newData) {
	if (!sameLink(oldData, newData)) throw new Error("Cannot change typeId, sourceId or targetId when changing link data");
	return Command.create("Set link data", () => {
		for (const link of model.links) if (sameLink(link.data, oldData)) link.setData(newData);
		return setLinkData(model, newData, oldData);
	});
}
//#endregion
//#region images/icons/class.svg
var class_default = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAyNiAyNiI+CiAgICA8dGV4dCB4PSIzIiB5PSIyMiIgY2xhc3M9InRleHQiIGZpbGw9IiNlYWFjNzciCiAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLCAnSGVsdmV0aWNhJywgJ0FyaWFsJywgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAyNnB4OyBmb250LXdlaWdodDogYm9sZDsiPgogICAgICAgIEMKICAgIDwvdGV4dD4KPC9zdmc+Cg==";
//#endregion
//#region images/icons/objectProperty.svg
var objectProperty_default = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAyNiAyNiI+CiAgICA8dGV4dCB4PSIwIiB5PSIyMCIgY2xhc3M9InRleHQiIGZpbGw9IiMzNGM3ZjMiCiAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLCAnSGVsdmV0aWNhJywgJ0FyaWFsJywgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsiPgogICAgICAgIE9QCiAgICA8L3RleHQ+Cjwvc3ZnPgo=";
//#endregion
//#region images/icons/datatypeProperty.svg
var datatypeProperty_default = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAyNiAyNiI+CiAgICA8dGV4dCB4PSIwIiB5PSIyMCIgY2xhc3M9InRleHQiIGZpbGw9IiMzNGM3ZjMiCiAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLCAnSGVsdmV0aWNhJywgJ0FyaWFsJywgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsiPgogICAgICAgIERQCiAgICA8L3RleHQ+Cjwvc3ZnPgo=";
//#endregion
//#region images/icons/person.svg
var person_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20viewBox='0%200%20350%20350'%3e%3cpath%20fill='%23eb7777'%20d='M175,171.173c38.914,0,70.463-38.318,70.463-85.586C245.463,38.318,235.105,0,175,0s-70.465,38.318-70.465,85.587%20C104.535,132.855,136.084,171.173,175,171.173z'/%3e%3cpath%20fill='%23eb7777'%20d='M41.909,301.853C41.897,298.971,41.885,301.041,41.909,301.853L41.909,301.853z'/%3e%3cpath%20fill='%23eb7777'%20d='M308.085,304.104C308.123,303.315,308.098,298.63,308.085,304.104L308.085,304.104z'/%3e%3cpath%20fill='%23eb7777'%20d='M307.935,298.397c-1.305-82.342-12.059-105.805-94.352-120.657c0,0-11.584,14.761-38.584,14.761%20s-38.586-14.761-38.586-14.761c-81.395,14.69-92.803,37.805-94.303,117.982c-0.123,6.547-0.18,6.891-0.202,6.131%20c0.005,1.424,0.011,4.058,0.011,8.651c0,0,19.592,39.496,133.08,39.496c113.486,0,133.08-39.496,133.08-39.496%20c0-2.951,0.002-5.003,0.005-6.399C308.062,304.575,308.018,303.664,307.935,298.397z'/%3e%3c/svg%3e";
//#endregion
//#region images/icons/country.svg
var country_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20viewBox='0%200%20512%20512'%3e%3cpath%20fill='%2377ca98'%20d='M472.928,34.752c-4.416-3.008-10.016-3.552-14.944-1.6c-1.024,0.416-106.88,42.048-195.168,0.384%20C186.72-2.432,102.912,14.4,64,25.76V16c0-8.832-7.168-16-16-16c-8.832,0-16,7.168-16,16v32v256v192c0,8.832,7.168,16,16,16%20c8.832,0,16-7.168,16-16V315.328c28.384-9.184,112.608-31.136,185.184,3.136c34.592,16.352,70.784,21.792,103.648,21.792%20c63.2,0,114.016-20.128,117.184-21.408c6.016-2.464,9.984-8.32,9.984-14.848V48C480,42.688,477.344,37.728,472.928,34.752z'/%3e%3c/svg%3e";
//#endregion
//#region images/icons/organization.svg
var organization_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20viewBox='0%200%20512%20512'%3e%3cpath%20fill='%2377ca98'%20d='M155,0H15C6.716,0,0,6.716,0,15v35h170V15C170,6.716,163.284,0,155,0z'/%3e%3cpath%20fill='%2377ca98'%20d='M504.464,142.989c-4.662-2.674-10.397-2.651-15.036,0.063L341,229.852V156c0-5.374-2.875-10.337-7.536-13.011%20c-4.662-2.674-10.397-2.651-15.036,0.063L170,229.852V80H0v417c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V156%20C512,150.626,509.125,145.663,504.464,142.989z%20M230,406.5c0,8.284-6.716,15-15,15h-60c-8.284,0-15-6.716-15-15v-60%20c0-8.284,6.716-15,15-15h60c8.284,0,15,6.716,15,15V406.5z%20M401,406.5c0,8.284-6.716,15-15,15h-60c-8.284,0-15-6.716-15-15v-60%20c0-8.284,6.716-15,15-15h60c8.284,0,15,6.716,15,15V406.5z'/%3e%3c/svg%3e";
//#endregion
//#region images/icons/location.svg
var location_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20width='47.825px'%20height='47.825px'%20viewBox='0%200%2047.825%2047.825'%3e%3cpath%20fill='%23bebc71'%20d='M36.439,12.646c0-6.919-5.608-12.527-12.528-12.527S11.384,5.727,11.384,12.646c0,9.913,12.527,24.582,12.527,24.582%20S36.439,22.508,36.439,12.646z%20M17.733,11.898c0-3.413,2.767-6.179,6.179-6.179s6.179,2.766,6.179,6.179%20c0,3.413-2.767,6.179-6.179,6.179S17.733,15.311,17.733,11.898z'/%3e%3ccircle%20fill='%23bebc71'%20cx='23.911'%20cy='11.898'%20r='3.038'/%3e%3cpath%20fill='%23bebc71'%20d='M30.994,32.87c-1.021,1.476-1.979,2.761-2.777,3.793c7.916,0.476,13.104,2.185,15.034,3.456%20c-2.261,1.491-8.979,3.587-19.338,3.587c-10.358,0-17.077-2.097-19.338-3.587c1.93-1.271,7.114-2.979,15.022-3.455%20c-0.8-1.032-1.759-2.316-2.781-3.792C7.075,33.831,0,36.713,0,40.118c0,4.19,10.707,7.588,23.913,7.588%20c13.207,0,23.912-3.396,23.912-7.588C47.827,36.711,40.744,33.828,30.994,32.87z'/%3e%3c/svg%3e";
//#endregion
//#region images/icons/event.svg
var event_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20width='97.473px'%20height='97.473px'%20viewBox='0%200%2097.473%2097.473'%3e%3crect%20fill='%23b4b1fb'%20x='41.569'%20y='47.753'%20width='14.333'%20height='14.333'/%3e%3crect%20fill='%23b4b1fb'%20x='41.569'%20y='67.754'%20width='14.333'%20height='14.332'/%3e%3crect%20fill='%23b4b1fb'%20x='18.569'%20y='67.754'%20width='14.333'%20height='14.332'/%3e%3crect%20fill='%23b4b1fb'%20x='18.569'%20y='47.753'%20width='14.333'%20height='14.333'/%3e%3cpath%20fill='%23b4b1fb'%20d='M95.472,14.466H84.427V2.701c0-1.104-0.896-2-2-2H65.811c-1.104,0-2,0.896-2,2v11.765H33.662V2.701c0-1.104-0.896-2-2-2%20H15.045c-1.104,0-2,0.896-2,2v11.765H2c-1.104,0-2,0.896-2,2v78.305c0,1.104,0.896,2,2,2h93.473c1.104,0,2-0.896,2-2V16.466%20C97.472,15.362,96.576,14.466,95.472,14.466z%20M69.645,8.037c0-0.828,0.672-1.5,1.5-1.5h5.947c0.829,0,1.5,0.672,1.5,1.5v20.34%20c0,0.828-0.671,1.5-1.5,1.5h-5.947c-0.828,0-1.5-0.672-1.5-1.5V8.037z%20M18.88,8.037c0-0.828,0.671-1.5,1.5-1.5h5.947%20c0.829,0,1.5,0.672,1.5,1.5v20.34c0,0.828-0.671,1.5-1.5,1.5H20.38c-0.829,0-1.5-0.672-1.5-1.5V8.037z%20M87.068,84.902%20c0,0.828-0.67,1.5-1.5,1.5H11.903c-0.829,0-1.5-0.672-1.5-1.5v-40c0-0.828,0.671-1.5,1.5-1.5h73.666c0.83,0,1.5,0.672,1.5,1.5%20V84.902z'/%3e%3crect%20fill='%23b4b1fb'%20x='64.568'%20y='47.753'%20width='14.334'%20height='14.333'/%3e%3crect%20fill='%23b4b1fb'%20x='64.568'%20y='67.754'%20width='14.334'%20height='14.332'/%3e%3c/svg%3e";
//#endregion
//#region images/icons/object.svg
var object_default = "data:image/svg+xml,%3csvg%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20x='0px'%20y='0px'%20width='50px'%20height='50px'%20viewBox='0%200%2050%2050'%3e%3cpath%20fill='%2353ccb2'%20d='M26.12,14.488c0.879-1.468,2.27-3.569,4.027-5.585h0.002c1.488-1.711,4.402-3.907,4.402-3.907%20c0.438-0.331,0.391-0.792-0.107-1.024l-3.522-1.646c-0.498-0.233-1.175-0.063-1.505,0.376c0,0-2.605,3.737-5.671,11.692%20c-9.48-4.288-18.491,1.718-18.491,12.162c0,10.909,8.393,27.48,19.743,22.478c11.954,5.173,19.749-11.568,19.749-22.478%20C44.747,16.022,36.647,9.846,26.12,14.488z'/%3e%3cpath%20fill='%2353ccb2'%20d='M23.997,10.955c0.548-0.046,1.032-0.531,1.076-1.078c0,0,0.352-4.266-2.621-7.242c-2.982-2.977-7.24-2.622-7.24-2.622%20c-0.548,0.046-1.032,0.531-1.077,1.078c0,0-0.358,4.268,2.619,7.245C19.729,11.31,23.997,10.955,23.997,10.955z'/%3e%3c/svg%3e";
//#endregion
//#region src/graph-explorer/customization/defaultTypeStyles.ts
var DefaultTypeStyleBundle = (types) => {
	if (types.indexOf("http://www.w3.org/2002/07/owl#Class") !== -1 || types.indexOf("http://www.w3.org/2000/01/rdf-schema#Class") !== -1) return {
		color: "#eaac77",
		icon: class_default
	};
	else if (types.indexOf("http://www.w3.org/2002/07/owl#ObjectProperty") !== -1) return {
		color: "#34c7f3",
		icon: objectProperty_default
	};
	else if (types.indexOf("http://www.w3.org/2002/07/owl#DatatypeProperty") !== -1) return {
		color: "#34c7f3",
		icon: datatypeProperty_default
	};
	else if (types.indexOf("http://xmlns.com/foaf/0.1/Person") !== -1 || types.indexOf("http://www.wikidata.org/entity/Q5") !== -1) return {
		color: "#eb7777",
		icon: person_default
	};
	else if (types.indexOf("http://www.wikidata.org/entity/Q6256") !== -1) return {
		color: "#77ca98",
		icon: country_default
	};
	else if (types.indexOf("http://schema.org/Organization") !== -1 || types.indexOf("http://dbpedia.org/ontology/Organisation") !== -1 || types.indexOf("http://xmlns.com/foaf/0.1/Organization") !== -1 || types.indexOf("http://www.wikidata.org/entity/Q43229") !== -1) return {
		color: "#77ca98",
		icon: organization_default
	};
	else if (types.indexOf("http://www.wikidata.org/entity/Q618123") !== -1) return {
		color: "#bebc71",
		icon: location_default
	};
	else if (types.indexOf("http://www.wikidata.org/entity/Q1190554") !== -1) return {
		color: "#b4b1fb",
		icon: event_default
	};
	else if (types.indexOf("http://www.wikidata.org/entity/Q488383") !== -1) return {
		color: "#53ccb2",
		icon: object_default
	};
	else return;
};
//#endregion
//#region src/graph-explorer/customization/defaultLinkStyles.ts
var LINK_SHOW_IRI = { renderLink: (link) => ({ properties: [{
	position: .5,
	attrs: { text: {
		text: [{
			value: link.typeId,
			language: ""
		}],
		fill: "gray",
		"font-size": 12,
		"font-weight": "lighter"
	} }
}] }) };
var LINK_SUB_CLASS_OF = {
	markerTarget: {
		fill: "#f8a485",
		stroke: "#cf8e76"
	},
	renderLink: () => ({ connection: {
		stroke: "#f8a485",
		"stroke-width": 2
	} })
};
var LINK_DOMAIN = {
	markerTarget: {
		fill: "#34c7f3",
		stroke: "#38b5db"
	},
	renderLink: () => ({ connection: {
		stroke: "#34c7f3",
		"stroke-width": 2
	} })
};
var LINK_RANGE = {
	markerTarget: {
		fill: "#34c7f3",
		stroke: "#38b5db"
	},
	renderLink: () => ({ connection: {
		stroke: "#34c7f3",
		"stroke-width": 2
	} })
};
var LINK_TYPE_OF = {
	markerTarget: {
		fill: "#8cd965",
		stroke: "#5b9a3b"
	},
	renderLink: () => ({ connection: {
		stroke: "#8cd965",
		"stroke-width": 2
	} })
};
var DefaultLinkTemplateBundle = (type) => {
	if (type === "http://www.w3.org/2000/01/rdf-schema#subClassOf") return LINK_SUB_CLASS_OF;
	else if (type === "http://www.w3.org/2000/01/rdf-schema#domain") return LINK_DOMAIN;
	else if (type === "http://www.w3.org/2000/01/rdf-schema#range") return LINK_RANGE;
	else if (type === "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") return LINK_TYPE_OF;
	else if (type === "http://graph-explorer.org/NewLink") return { markerTarget: { fill: "none" } };
	else return;
};
//#endregion
//#region src/graph-explorer/data/sparql/sparqlModels.ts
function isRdfBlank(e) {
	return e && e.type === "bnode";
}
function isRdfIri(e) {
	return e && e.type === "uri";
}
function isRdfLiteral(e) {
	return e && e.type === "literal";
}
function isBlankBinding(binding) {
	const blank = binding;
	return blank.blankTrgProp !== void 0 || blank.blankTrg !== void 0 || blank.blankSrcProp !== void 0 || blank.blankSrc !== void 0;
}
var ENCODED_PREFIX = "sparql-blank:";
var BLANK_NODE_QUERY_PARAMETERS = "?blankTrgProp ?blankTrg ?blankSrc ?blankSrcProp ?listHead";
var BLANK_NODE_QUERY = `
    OPTIONAL {
        FILTER (ISBLANK(?inst)).
        {
            ?inst ?blankTrgProp ?blankTrg.
            ?blankSrc ?blankSrcProp ?inst.
            FILTER NOT EXISTS { ?inst rdf:first _:smth1 }.
            BIND("blankNode" as ?blankType)
        } UNION {
            ?inst rdf:rest*/rdf:first ?blankTrg.
            ?blankSrc ?blankSrcProp ?inst.
            _:smth2 rdf:first ?blankTrg.
            BIND(?blankSrcProp as ?blankTrgProp)
            BIND("listHead" as ?blankType)
            FILTER NOT EXISTS { _:smth3 rdf:rest ?inst }.
        } UNION {
            ?listHead rdf:rest* ?inst.
            FILTER NOT EXISTS { _:smth4 rdf:rest ?listHead }.

            ?listHead rdf:rest*/rdf:first ?blankTrg.
            ?blankSrc ?blankSrcProp ?listHead.
            _:smth5 rdf:first ?blankTrg.
            BIND(?blankSrcProp as ?blankTrgProp)
            BIND("listHead" as ?blankType)
        }
    }
`;
function isEncodedBlank(id) {
	return id.startsWith(ENCODED_PREFIX);
}
var QueryExecutor = class {
	constructor(queryFunction) {
		this.queryFunction = queryFunction;
		this.queryDictionary = {};
	}
	executeQuery(query) {
		const execution = this.queryDictionary[query];
		if (execution) return execution;
		else {
			this.queryDictionary[query] = this.queryFunction(query).then((response) => {
				delete this.queryDictionary[query];
				return response;
			});
			return this.queryDictionary[query];
		}
	}
};
function updateFilterResults(result, queryFunction, settings) {
	const completeBindings = [];
	const blankBindings = [];
	for (const binding of result.results.bindings) if (isBlankBinding(binding)) blankBindings.push(binding);
	else completeBindings.push(binding);
	return processBlankBindings(blankBindings, (callBackQuery) => {
		return queryFunction(callBackQuery);
	}, settings).then((processedBindings) => {
		result.results.bindings = completeBindings.concat(processedBindings);
		return result;
	});
}
function processBlankBindings(blankBindings, queryFunction, settings) {
	const bindingGroupsById = {};
	for (const binding of blankBindings) {
		if (binding.newInst) binding.inst = binding.newInst;
		if (!bindingGroupsById[binding.inst.value]) bindingGroupsById[binding.inst.value] = [];
		bindingGroupsById[binding.inst.value].push(binding);
	}
	const relatedBlankBindnings = [];
	for (const b of blankBindings) if (isRdfBlank(b.blankTrg)) relatedBlankBindnings.push([b]);
	return loadRelatedBlankNodes(relatedBlankBindnings, new QueryExecutor(queryFunction), settings).then((loadedGroupsById) => {
		const idsMap = getEncodedIdDictionary(loadedGroupsById);
		const groups = Object.keys(bindingGroupsById).map((key) => bindingGroupsById[key]);
		for (const group of groups) {
			for (const blankBinding of group) {
				if (!blankBinding.label) blankBinding.label = createLabelForBlankBinding(blankBinding);
				const encodedId4LoadedElement = idsMap[blankBinding.blankTrg.value];
				if (encodedId4LoadedElement) blankBinding.blankTrg.value = encodedId4LoadedElement;
			}
			updateGroupIds(group, encodeId(group));
		}
		return blankBindings;
	});
}
function getEncodedIdDictionary(blankBindingGroups) {
	const idDictionary = {};
	const keys = Object.keys(blankBindingGroups);
	for (const key of keys) {
		idDictionary[key] = encodeId(blankBindingGroups[key]);
		updateGroupIds(blankBindingGroups[key], idDictionary[key]);
	}
	return idDictionary;
}
function updateGroupIds(group, newId) {
	for (const loadedBlankBinding of group) loadedBlankBinding.inst.value = newId;
}
function encodeId(blankBindings) {
	const bindingSet = {};
	for (const binding of blankBindings) {
		const { inst: _inst, ...exceptInst } = binding;
		const encodedBinding = JSON.stringify(exceptInst);
		bindingSet[encodedBinding] = exceptInst;
	}
	const normalizedBindings = Object.keys(bindingSet).sort().map((key) => bindingSet[key]);
	return ENCODED_PREFIX + encodeURI(JSON.stringify(normalizedBindings));
}
function decodeId(id) {
	if (!isEncodedBlank(id)) return;
	try {
		const clearId = id.substring(13, id.length);
		return JSON.parse(decodeURI(clearId)).map((binding) => {
			binding.inst = {
				type: "uri",
				value: id
			};
			return binding;
		});
	} catch (_error) {
		return;
	}
}
function createLabelForBlankBinding(bn) {
	if (bn.blankType.value === "listHead") return {
		type: "literal",
		value: "RDFList",
		"xml:lang": ""
	};
	else return {
		type: "literal",
		value: bn.class ? getUriLocalName(bn.class.value) || bn.class.value : "anonymous",
		"xml:lang": ""
	};
}
function loadRelatedBlankNodes(blankChains, queryExecutor, settings, recursionDeep) {
	recursionDeep = recursionDeep || 1;
	if (recursionDeep > 3) return Promise.resolve({});
	const promises = blankChains.map((chain) => ({
		query: getQueryForChain(chain, settings),
		chain
	})).map((pair) => queryExecutor.executeQuery(pair.query).then((response) => ({
		response,
		chain: pair.chain
	})));
	return Promise.all(promises).then((results) => {
		const recursionPromises = [];
		const loadedBlankBindings = {};
		for (const result of results) {
			const bindings = result.response.results.bindings;
			if (bindings.length > 0) {
				const relatedBlankBindings = [];
				for (const binding of bindings) if (isRdfBlank(binding.blankTrg)) relatedBlankBindings.push(result.chain.concat([binding]));
				recursionPromises.push(loadRelatedBlankNodes(relatedBlankBindings, queryExecutor, settings, recursionDeep + 1).then((loadedGroupsById) => {
					const idsMap = getEncodedIdDictionary(loadedGroupsById);
					const mergedResults = {};
					for (const binding of bindings) {
						binding.label = createLabelForBlankBinding(binding);
						const encodedId = idsMap[binding.blankTrg.value];
						if (encodedId) binding.blankTrg.value = encodedId;
						if (!mergedResults[binding.inst.value]) mergedResults[binding.inst.value] = [];
						mergedResults[binding.inst.value].push(binding);
					}
					Object.keys(mergedResults).forEach((key) => {
						const group = mergedResults[key];
						const originalId = group[0].inst.value;
						loadedBlankBindings[originalId] = group;
					});
					return true;
				}));
			}
		}
		return Promise.all(recursionPromises).then(() => {
			return loadedBlankBindings;
		});
	});
}
function getQueryForChain(blankNodes, sparqlDataProviderSettings) {
	function getQueryBlock(blankNode, index, maxIndex) {
		const trustableTrgProp = index === 0 || blankNode.blankType.value !== "listHead";
		const sourceId = index > 0 ? "?inst" + (index - 1) : "<" + blankNode.blankSrc.value + ">";
		const sourcePropId = trustableTrgProp ? index > 0 ? "?blankTrgProp" + (index - 1) : "<" + blankNode.blankSrcProp.value + ">" : "?anyType" + index;
		const instPostfix = index === maxIndex ? "" : index.toString();
		const targetPropId = trustableTrgProp ? "<" + blankNode.blankTrgProp.value + ">" : "?anyType0" + index;
		return `
        # ======================
        ${sourceId} ${sourcePropId} ?blankSrc${index}.
        ${index === 0 && blankNode.blankType.value === "listHead" ? `
            ?blankSrc${index} rdf:rest*/rdf:first ?inst${instPostfix}.
            ` : `?blankSrc${index} ${targetPropId} ?inst${instPostfix}.`}
        BIND (<${blankNode.blankTrgProp.value}> as ?blankSrcProp${index}).
        FILTER (ISBLANK(?inst${instPostfix})).
        {
            ?inst${instPostfix} ?blankTrgProp${instPostfix} ?blankTrg${instPostfix}.
            BIND("blankNode" as ?blankType${instPostfix}).
            FILTER NOT EXISTS { ?inst${instPostfix} rdf:first _:smth1${index} }.
        } UNION {
            ?inst${instPostfix} rdf:rest*/rdf:first ?blankTrg${instPostfix}.
            ?blankSrc${index} ?blankSrcProp${index} ?inst${instPostfix}.
            _:smth2${index} rdf:first ?blankTrg${instPostfix}.
            BIND(?blankSrcProp${index} as ?blankTrgProp${instPostfix})
            BIND("listHead" as ?blankType${instPostfix})
            FILTER NOT EXISTS { _:smth3${index} rdf:rest ?inst${instPostfix} }.
        }
        OPTIONAL {
            ?inst${instPostfix} rdf:type ?class${instPostfix}.
        }
    `;
	}
	const body = blankNodes.map((bn, index) => getQueryBlock(bn, index, blankNodes.length - 1)).join("\n");
	return `${sparqlDataProviderSettings.defaultPrefix}
    SELECT ?inst ?class ?label ?blankTrgProp ?blankTrg ?blankType
        WHERE {
           ${body}
        }
    `;
}
function elementInfo(elementIds) {
	return {
		head: void 0,
		results: { bindings: getElementBindings(elementIds.filter((id) => isEncodedBlank(id))) }
	};
}
function linksInfo(elementIds) {
	return {
		head: void 0,
		results: { bindings: getLinkBinding(elementIds) }
	};
}
function linkTypesOf(params) {
	return {
		head: void 0,
		results: { bindings: getLinkCountBinding(params.elementId) }
	};
}
function filter(params) {
	const filterResponse = {
		head: void 0,
		results: { bindings: [] }
	};
	if (params.limit === 0) params.limit = 100;
	if (params.elementTypeId) filterResponse.results.bindings = [];
	else if (params.refElementId && params.refElementLinkId) filterResponse.results.bindings = getAllRelatedByLinkTypeElements(params.refElementId, params.refElementLinkId, params.linkDirection);
	else if (params.refElementId) filterResponse.results.bindings = getAllRelatedElements(params.refElementId);
	if (params.text && filterResponse.results.bindings.length !== 0) filterResponse.results.bindings = filterResponse.results.bindings.filter((be) => be.inst.value.toLowerCase().indexOf(params.text) !== -1);
	return filterResponse;
}
function getElementTypes$1(elementIds) {
	const bindings = [];
	for (const id of elementIds) {
		const blankBindings = decodeId(id);
		if (blankBindings) {
			for (const be of blankBindings) if (isRdfIri(be.inst) && be.class) bindings.push({
				inst: be.inst,
				class: be.class
			});
		}
	}
	return {
		head: void 0,
		results: { bindings }
	};
}
function getAllRelatedByLinkTypeElements(refElementId, refElementLinkId, linkDirection) {
	const blankElements = (decodeId(refElementId) || []).concat(decodeId(refElementLinkId) || []);
	let bindings = [];
	if (blankElements.length > 0) {
		for (const be of blankElements) if (linkDirection === "in") {
			if (be.inst.value === refElementId && (isRdfIri(be.blankSrc) || isRdfBlank(be.blankSrc)) && refElementLinkId === be.blankSrcProp.value) if (isRdfIri(be.blankSrc)) bindings.push({ inst: be.blankSrc });
			else bindings = bindings.concat(decodeId(be.blankSrc.value) || [{ inst: be.blankSrc }]);
			else if (be.blankTrg.value === refElementId && refElementLinkId === be.blankTrgProp.value) bindings.push(be);
		} else if (be.inst.value === refElementId && (isRdfIri(be.blankTrg) || isRdfBlank(be.blankTrg)) && refElementLinkId === be.blankTrgProp.value) if (isRdfIri(be.blankTrg)) bindings.push({ inst: be.blankTrg });
		else bindings = bindings.concat(decodeId(be.blankTrg.value) || [{ inst: be.blankTrg }]);
		else if (be.blankSrc.value === refElementId && refElementLinkId === be.blankSrcProp.value) bindings.push(be);
	}
	return bindings;
}
function getAllRelatedElements(id) {
	const blankElements = decodeId(id);
	let bindings = [];
	if (blankElements) {
		for (const be of blankElements) if (be.inst.value === id || id === be.blankSrc.value || id === be.blankTrg.value) {
			bindings.push(be);
			if (isRdfIri(be.blankSrc)) bindings.push({ inst: be.blankSrc });
			else if (isRdfBlank(be.blankSrc)) bindings = bindings.concat(decodeId(be.blankSrc.value) || [{ inst: be.blankSrc }]);
			if (isRdfIri(be.blankTrg)) bindings.push({ inst: be.blankTrg });
			else if (isRdfBlank(be.blankTrg)) bindings = bindings.concat(decodeId(be.blankTrg.value) || [{ inst: be.blankTrg }]);
		}
	}
	return bindings;
}
function getElementBindings(ids) {
	let blankElements = [];
	for (const id of ids) if (decodeId(id)) blankElements = blankElements.concat(decodeId(id));
	return blankElements.filter((be) => {
		return ids.indexOf(be.inst.value) !== -1;
	});
}
function getLinkBinding(ids) {
	let blankElements = [];
	for (const id of ids) if (decodeId(id)) blankElements = blankElements.concat(decodeId(id));
	const bindings = [];
	for (const be of blankElements) if (ids.indexOf(be.inst.value) !== -1) {
		if ((isRdfIri(be.blankSrc) || isRdfBlank(be.blankSrc)) && isRdfIri(be.blankSrcProp) && ids.indexOf(be.blankSrc.value) !== -1) bindings.push({
			source: be.blankSrc,
			type: be.blankSrcProp,
			target: be.inst
		});
		if ((isRdfIri(be.blankTrg) || isRdfBlank(be.blankTrg)) && isRdfIri(be.blankTrgProp) && ids.indexOf(be.blankTrg.value) !== -1) bindings.push({
			source: be.inst,
			type: be.blankTrgProp,
			target: be.blankTrg
		});
	}
	return bindings;
}
function getLinkCountBinding(id) {
	const blankElements = decodeId(id);
	const dictionary = {};
	for (const be of blankElements) if (id === be.inst.value) {
		if ((isRdfIri(be.blankTrg) || isRdfBlank(be.blankTrg)) && isRdfIri(be.blankTrgProp)) {
			if ((isRdfIri(be.blankSrc) || isRdfBlank(be.blankSrc)) && isRdfIri(be.blankSrcProp)) {
				if (!dictionary[be.blankSrcProp.value]) dictionary[be.blankSrcProp.value] = {
					link: be.blankSrcProp,
					inCount: {
						type: "literal",
						value: "1",
						"xml:lang": ""
					},
					outCount: {
						type: "literal",
						value: "0",
						"xml:lang": ""
					}
				};
			}
			if (!dictionary[be.blankTrgProp.value]) dictionary[be.blankTrgProp.value] = {
				link: be.blankTrgProp,
				inCount: {
					type: "literal",
					value: "0",
					"xml:lang": ""
				},
				outCount: {
					type: "literal",
					value: "1",
					"xml:lang": ""
				}
			};
			else dictionary[be.blankTrgProp.value].outCount.value = (+dictionary[be.blankTrgProp.value].outCount.value + 1).toString();
		}
	}
	return Object.keys(dictionary).map((k) => dictionary[k]);
}
//#endregion
//#region src/graph-explorer/diagram/linkRouter.ts
var DefaultLinkRouter = class {
	constructor(gap = 20) {
		this.gap = gap;
	}
	route(model) {
		const routings = /* @__PURE__ */ new Map();
		for (const link of model.links) {
			if (routings.has(link.id)) continue;
			const { sourceId, targetId } = link;
			if (!sourceId || !targetId) continue;
			else if (sourceId === targetId) this.routeFeedbackSiblingLinks(model, sourceId, routings);
			else this.routeNormalSiblingLinks(model, sourceId, targetId, routings);
		}
		return routings;
	}
	routeFeedbackSiblingLinks(model, elementId, routings) {
		const element = model.getElement(elementId);
		const { x, y } = element.position;
		const { width, height } = element.size;
		let index = 0;
		for (const sibling of element.links) {
			if (routings.has(sibling.id) || hasUserPlacedVertices(sibling)) continue;
			const { sourceId, targetId } = sibling;
			if (sourceId === targetId) {
				const offset = this.gap * (index + 1);
				const vertices = [
					{
						x: x - offset,
						y: y + height / 2
					},
					{
						x: x - offset,
						y: y - offset
					},
					{
						x: x + width / 2,
						y: y - offset
					}
				];
				routings.set(sibling.id, {
					linkId: sibling.id,
					vertices
				});
				index++;
			}
		}
	}
	routeNormalSiblingLinks(model, sourceId, targetId, routings) {
		const source = model.getElement(sourceId);
		const target = model.getElement(targetId);
		const sourceCenter = centerOfElement(source);
		const targetCenter = centerOfElement(target);
		const midPoint = {
			x: (sourceCenter.x + targetCenter.x) / 2,
			y: (sourceCenter.y + targetCenter.y) / 2
		};
		const direction = Vector.normalize({
			x: targetCenter.x - sourceCenter.x,
			y: targetCenter.y - sourceCenter.y
		});
		const siblings = source.links.filter((link) => (link.sourceId === targetId || link.targetId === targetId) && !routings.has(link.id) && !hasUserPlacedVertices(link));
		if (siblings.length <= 1) return;
		const indexModifier = siblings.length % 2 ? 0 : 1;
		siblings.forEach((sibling, siblingIndex) => {
			const index = siblingIndex + indexModifier;
			const offset = this.gap * Math.ceil(index / 2) - (indexModifier ? this.gap / 2 : 0);
			const offsetDirection = index % 2 ? {
				x: -direction.y,
				y: direction.x
			} : {
				x: direction.y,
				y: -direction.x
			};
			const vertex = {
				x: midPoint.x + offsetDirection.x * offset,
				y: midPoint.y + offsetDirection.y * offset
			};
			routings.set(sibling.id, {
				linkId: sibling.id,
				vertices: [vertex],
				labelTextAnchor: this.getLabelAlignment(direction, siblingIndex, siblings.length)
			});
		});
	}
	getLabelAlignment(connectionDirection, siblingIndex, siblingCount) {
		const angle = Math.atan2(connectionDirection.y, connectionDirection.x);
		const absoluteAngle = Math.abs(angle);
		const isHorizontal = absoluteAngle < Math.PI * 1 / 8 || absoluteAngle > Math.PI * 7 / 8;
		const isTop = angle < 0;
		const isBottom = angle > 0;
		const firstOuter = siblingCount - 2;
		const secondOuter = siblingCount - 1;
		if (!isHorizontal) {
			if (isTop && siblingIndex === secondOuter || isBottom && siblingIndex === firstOuter) return "end";
			else if (isTop && siblingIndex === firstOuter || isBottom && siblingIndex === secondOuter) return "start";
		}
		return "middle";
	}
};
function hasUserPlacedVertices(link) {
	const vertices = link.vertices;
	return vertices && vertices.length > 0;
}
function centerOfElement(element) {
	const { x, y } = element.position;
	const { width, height } = element.size;
	return {
		x: x + width / 2,
		y: y + height / 2
	};
}
//#endregion
//#region src/graph-explorer/diagram/view.ts
var IriClickIntent = /* @__PURE__ */ function(IriClickIntent) {
	IriClickIntent["JumpToEntity"] = "jumpToEntity";
	IriClickIntent["OpenEntityIri"] = "openEntityIri";
	IriClickIntent["OpenOtherIri"] = "openOtherIri";
	return IriClickIntent;
}({});
var RenderingLayer = /* @__PURE__ */ function(RenderingLayer) {
	RenderingLayer[RenderingLayer["Element"] = 1] = "Element";
	RenderingLayer[RenderingLayer["ElementSize"] = 2] = "ElementSize";
	RenderingLayer[RenderingLayer["PaperArea"] = 3] = "PaperArea";
	RenderingLayer[RenderingLayer["Link"] = 4] = "Link";
	RenderingLayer[RenderingLayer["Editor"] = 5] = "Editor";
	RenderingLayer[RenderingLayer["FirstToUpdate"] = 1] = "FirstToUpdate";
	RenderingLayer[RenderingLayer["LastToUpdate"] = 5] = "LastToUpdate";
	return RenderingLayer;
}({});
var WidgetAttachment = /* @__PURE__ */ function(WidgetAttachment) {
	WidgetAttachment[WidgetAttachment["Viewport"] = 1] = "Viewport";
	WidgetAttachment[WidgetAttachment["OverElements"] = 2] = "OverElements";
	WidgetAttachment[WidgetAttachment["OverLinks"] = 3] = "OverLinks";
	return WidgetAttachment;
}({});
var DiagramView = class {
	constructor(model, options = {}) {
		this.model = model;
		this.options = options;
		this.listener = new EventObserver();
		this.source = new EventSource();
		this.events = this.source;
		this.disposed = false;
		this.colorSeed = 195935983;
		this._language = "en";
		this.linkTemplates = /* @__PURE__ */ new Map();
		this.routings = /* @__PURE__ */ new Map();
		this.resolveTypeStyle = options.typeStyleResolver || DefaultTypeStyleBundle;
		this.resolveLinkTemplate = options.linkTemplateResolver || DefaultLinkTemplateBundle;
		this.resolveElementTemplate = options.elementTemplateResolver || DefaultElementTemplateBundle;
		this.initRouting();
	}
	initRouting() {
		this.router = this.options.linkRouter || new DefaultLinkRouter();
		this.updateRoutings();
		this.listener.listen(this.model.events, "changeCells", () => this.updateRoutings());
		this.listener.listen(this.model.events, "linkEvent", ({ key: _key, data }) => {
			if (data.changeVertices) this.updateRoutings();
		});
		this.listener.listen(this.model.events, "elementEvent", ({ key: _key, data }) => {
			if (data.changePosition || data.changeSize) this.updateRoutings();
		});
	}
	updateRoutings() {
		const previousRoutes = this.routings;
		const computedRoutes = this.router.route(this.model);
		previousRoutes.forEach((previous, linkId) => {
			const computed = computedRoutes.get(linkId);
			if (computed && sameRoutedLink(previous, computed)) computedRoutes.set(linkId, previous);
		});
		this.routings = computedRoutes;
		this.source.trigger("updateRoutings", {
			source: this,
			previous: previousRoutes
		});
	}
	getRoutings() {
		return this.routings;
	}
	getRouting(linkId) {
		return this.routings.get(linkId);
	}
	getLanguage() {
		return this._language;
	}
	setLanguage(value) {
		if (!value) throw new Error("Cannot set empty language.");
		const previous = this._language;
		if (previous === value) return;
		this._language = value;
		this.source.trigger("changeLanguage", {
			source: this,
			previous
		});
	}
	getLinkTemplates() {
		return this.linkTemplates;
	}
	performSyncUpdate() {
		for (let layer = 1; layer <= 5; layer++) this.source.trigger("syncUpdate", { layer });
	}
	onIriClick(iri, element, clickIntent, event) {
		event.persist();
		event.preventDefault();
		const { onIriClick } = this.options;
		if (onIriClick) onIriClick({
			iri,
			element,
			clickIntent,
			originalEvent: event
		});
	}
	setPaperWidget(widget) {
		const { key, widget: element, attachment } = widget;
		const widgets = { [key]: element ? {
			element,
			attachment
		} : void 0 };
		this.source.trigger("updateWidgets", { widgets });
	}
	setHandlerForNextDropOnPaper(handler) {
		this.dropOnPaperHandler = handler;
	}
	_tryHandleDropOnPaper(e) {
		const { dropOnPaperHandler } = this;
		if (dropOnPaperHandler) {
			this.dropOnPaperHandler = void 0;
			dropOnPaperHandler(e);
			return true;
		}
		return false;
	}
	selectLabel(labels, language) {
		const targetLanguage = typeof language === "undefined" ? this.getLanguage() : language;
		const { selectLabelLanguage = defaultSelectLabel } = this.options;
		return selectLabelLanguage(labels, targetLanguage);
	}
	formatLabel(labels, fallbackIri, language) {
		return resolveLabel(this.selectLabel(labels, language), fallbackIri);
	}
	getElementTypeString(elementModel) {
		return elementModel.types.map((typeId) => {
			const type = this.model.createClass(typeId);
			return this.formatLabel(type.label, type.id);
		}).sort().join(", ");
	}
	getTypeStyle(types) {
		types.sort();
		const customStyle = this.resolveTypeStyle(types);
		const icon = customStyle ? customStyle.icon : void 0;
		let color;
		if (customStyle && customStyle.color) color = hcl(customStyle.color);
		else color = {
			h: getHueFromClasses(types, this.colorSeed),
			c: 40,
			l: 75
		};
		return {
			icon,
			color
		};
	}
	formatIri(iri) {
		if (isEncodedBlank(iri)) return "(blank node)";
		return `<${iri}>`;
	}
	getElementTemplate(types) {
		return this.resolveElementTemplate(types) || StandardTemplate;
	}
	createLinkTemplate(linkType) {
		const existingTemplate = this.linkTemplates.get(linkType.id);
		if (existingTemplate) return existingTemplate;
		let template = {};
		const result = this.resolveLinkTemplate(linkType.id);
		if (result) template = cloneDeep(result);
		fillLinkTemplateDefaults(template);
		this.linkTemplates.set(linkType.id, template);
		this.source.trigger("changeLinkTemplates", {});
		return template;
	}
	dispose() {
		if (this.disposed) return;
		this.source.trigger("dispose", {});
		this.listener.stopListening();
		this.disposed = true;
	}
	get highlighter() {
		return this._highlighter;
	}
	setHighlighter(value) {
		const previous = this._highlighter;
		if (previous === value) return;
		this._highlighter = value;
		this.source.trigger("changeHighlight", {
			source: this,
			previous
		});
	}
	_setElementDecorator(decorator) {
		this._elementDecorator = decorator;
	}
	_decorateElement(element) {
		return this._elementDecorator(element);
	}
};
function sameRoutedLink(a, b) {
	return a.linkId === b.linkId && a.labelTextAnchor === b.labelTextAnchor && isPolylineEqual(a.vertices, b.vertices);
}
function getHueFromClasses(classes, seed) {
	let hash = seed;
	for (const name of classes) hash = hashFnv32a(name, hash);
	return 360 * ((hash === void 0 ? 0 : hash) / 2147483647);
}
function fillLinkTemplateDefaults(template) {
	defaultsDeep(template, { markerTarget: {
		d: "M0,0 L0,8 L9,4 z",
		width: 9,
		height: 8,
		fill: "black"
	} });
	if (!template.renderLink) template.renderLink = () => ({});
}
function defaultSelectLabel(texts, language) {
	if (texts.length === 0) return;
	let defaultValue;
	let englishValue;
	for (const text of texts) if (text.language === language) return text;
	else if (text.language === "") defaultValue = text;
	else if (text.language === "en") englishValue = text;
	return defaultValue !== void 0 ? defaultValue : englishValue !== void 0 ? englishValue : texts[0];
}
function resolveLabel(label, fallbackIri) {
	if (label) return label.value;
	return getUriLocalName(fallbackIri) || fallbackIri;
}
//#endregion
//#region src/graph-explorer/diagram/elementLayer.tsx
var ElementLayer = class extends React.Component {
	constructor(props, context) {
		super(props, context);
		this.listener = new EventObserver();
		this.redrawBatch = {
			requests: /* @__PURE__ */ new Map(),
			forAll: 0
		};
		this.delatedRedraw = new Debouncer();
		this.sizeRequests = /* @__PURE__ */ new Map();
		this.delayedUpdateSizes = new Debouncer();
		this.onMount = (layer) => {
			this.layer = layer;
		};
		this.requestRedraw = (element, request) => {
			if ((this.redrawBatch.forAll | request) === this.redrawBatch.forAll) return;
			const existing = this.redrawBatch.requests.get(element.id);
			this.redrawBatch.requests.set(element.id, existing | request);
			this.delatedRedraw.call(this.redrawElements);
		};
		this.redrawElements = () => {
			const props = this.props;
			this.setState((state) => ({ elementStates: applyRedrawRequests(props.view, props.group, this.redrawBatch, state.elementStates) }));
		};
		this.requestSizeUpdate = (element, node) => {
			this.sizeRequests.set(element.id, {
				element,
				node
			});
			this.delayedUpdateSizes.call(this.recomputeQueuedSizes);
		};
		this.recomputeQueuedSizes = () => {
			const batch = this.sizeRequests;
			this.sizeRequests = /* @__PURE__ */ new Map();
			batch.forEach(({ element, node }) => {
				const { clientWidth, clientHeight } = node;
				element.setSize({
					width: clientWidth,
					height: clientHeight
				});
			});
		};
		const { view, group } = this.props;
		this.state = { elementStates: applyRedrawRequests(view, group, this.redrawBatch, /* @__PURE__ */ new Map()) };
	}
	render() {
		const { view, style } = this.props;
		const { elementStates } = this.state;
		const elementsToRender = [];
		for (const { id } of view.model.elements) {
			const state = elementStates.get(id);
			if (state) elementsToRender.push(state);
		}
		return /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-element-layer",
			ref: this.onMount,
			style
		}, elementsToRender.map((state) => {
			const overlayElement = /* @__PURE__ */ React.createElement(OverlayedElement, {
				key: state.element.id,
				state,
				view,
				onInvalidate: this.requestRedraw,
				onResize: this.requestSizeUpdate
			});
			const elementDecorator = view._decorateElement(state.element);
			if (elementDecorator) return /* @__PURE__ */ React.createElement("div", { key: state.element.id }, overlayElement, elementDecorator);
			return overlayElement;
		}));
	}
	componentDidMount() {
		const { view } = this.props;
		this.listener.listen(view.model.events, "changeCells", (e) => {
			if (e.updateAll) this.requestRedrawAll(0);
			else if (e.changedElement) this.requestRedraw(e.changedElement, 0);
		});
		this.listener.listen(view.events, "changeLanguage", () => {
			this.requestRedrawAll(3);
		});
		this.listener.listen(view.events, "changeHighlight", () => {
			this.requestRedrawAll(5);
		});
		this.listener.listen(view.model.events, "elementEvent", ({ data }) => {
			const invalidatesTemplate = data.changeData || data.changeExpanded || data.changeElementState;
			if (invalidatesTemplate) this.requestRedraw(invalidatesTemplate.source, 3);
			const invalidatesRender = data.changePosition || data.requestedRedraw;
			if (invalidatesRender) this.requestRedraw(invalidatesRender.source, 1);
		});
		this.listener.listen(view.events, "syncUpdate", ({ layer }) => {
			if (layer === RenderingLayer.Element) this.delatedRedraw.runSynchronously();
			else if (layer === RenderingLayer.ElementSize) this.delayedUpdateSizes.runSynchronously();
		});
	}
	componentDidUpdate(nextProps) {
		if (this.props.group !== nextProps.group) this.setState((state) => ({ elementStates: applyRedrawRequests(nextProps.view, nextProps.group, this.redrawBatch, state.elementStates) }));
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.delatedRedraw.dispose();
		this.delayedUpdateSizes.dispose();
	}
	requestRedrawAll(request) {
		this.redrawBatch.forAll |= request;
		this.delatedRedraw.call(this.redrawElements);
	}
};
function applyRedrawRequests(view, targetGroup, batch, previous) {
	const computed = /* @__PURE__ */ new Map();
	for (const element of view.model.elements) {
		if (element.group !== targetGroup) continue;
		const elementId = element.id;
		if (previous.has(elementId)) {
			let state = previous.get(elementId);
			const request = (batch.requests.get(elementId) || 0) | batch.forAll;
			if (request & 1) state = {
				element,
				templateProps: (request & 3) === 3 ? computeTemplateProps(state.element, view) : state.templateProps,
				blurred: (request & 5) === 5 ? computeIsBlurred(state.element, view) : state.blurred
			};
			computed.set(elementId, state);
			batch.requests.delete(elementId);
		} else computed.set(element.id, {
			element,
			templateProps: computeTemplateProps(element, view),
			blurred: computeIsBlurred(element, view)
		});
	}
	batch.forAll = 0;
	return computed;
}
var ElementContext = React.createContext(null);
var OverlayedElement = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.element = null;
		this.listener = new EventObserver();
		this.disposed = false;
		this.rerenderTemplate = () => {
			if (this.disposed) return;
			this.props.onInvalidate(this.props.state.element, 3);
		};
		this.onMount = (node) => {
			this.element = node;
			if (!node) return;
			const { state, onResize } = this.props;
			onResize(state.element, node);
		};
		this.onLoadOrErrorEvent = () => {
			const { state, onResize } = this.props;
			if (this.element) onResize(state.element, this.element);
		};
		this.onClick = (e) => {
			if (e.target instanceof HTMLElement && e.target.localName === "a") {
				const anchor = e.target;
				const { view, state } = this.props;
				const clickIntent = e.target.getAttribute("data-iri-click-intent") === IriClickIntent.OpenEntityIri ? IriClickIntent.OpenEntityIri : IriClickIntent.OpenOtherIri;
				view.onIriClick(decodeURI(anchor.href), state.element, clickIntent, e);
			}
		};
		this.onDoubleClick = (e) => {
			e.preventDefault();
			e.stopPropagation();
			const { view, state: { element } } = this.props;
			view.model.history.execute(setElementExpanded(element, !element.isExpanded));
		};
	}
	render() {
		const { state: { element, blurred } } = this.props;
		if (element.temporary) return /* @__PURE__ */ React.createElement("div", null);
		const { x = 0, y = 0 } = element.position;
		const transform = `translate(${x}px,${y}px)`;
		const className = `graph-explorer-overlayed-element ${blurred ? "graph-explorer-overlayed-element--blurred" : ""}`;
		return /* @__PURE__ */ React.createElement(ElementContext.Provider, { value: { graphExplorerElement: { element } } }, /* @__PURE__ */ React.createElement("div", {
			className,
			"data-element-id": element.id,
			style: {
				position: "absolute",
				transform
			},
			tabIndex: 0,
			ref: this.onMount,
			onLoad: this.onLoadOrErrorEvent,
			onError: this.onLoadOrErrorEvent,
			onClick: this.onClick,
			onDoubleClick: this.onDoubleClick
		}, /* @__PURE__ */ React.createElement(TemplatedElement, this.props)));
	}
	componentDidMount() {
		const { state, view } = this.props;
		this.listener.listen(state.element.events, "requestedFocus", () => {
			if (this.element) this.element.focus();
		});
		this.typesObserver = observeElementTypes(view.model, "changeLabel", this.rerenderTemplate);
		this.propertiesObserver = observeProperties(view.model, "changeLabel", this.rerenderTemplate);
		this.observeTypes();
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.typesObserver.stopListening();
		this.propertiesObserver.stopListening();
		this.disposed = true;
	}
	shouldComponentUpdate(nextProps) {
		return this.props.state !== nextProps.state;
	}
	componentDidUpdate() {
		this.observeTypes();
		if (this.element) this.props.onResize(this.props.state.element, this.element);
	}
	observeTypes() {
		const { state: { element } } = this.props;
		this.typesObserver.observe(element.data.types);
		this.propertiesObserver.observe(Object.keys(element.data.properties));
	}
};
var TemplatedElement = class extends React.Component {
	render() {
		const { state, view } = this.props;
		const { element, templateProps } = state;
		const templateClass = view.getElementTemplate(element.data.types);
		this.cachedTemplateClass = templateClass;
		this.cachedTemplateProps = templateProps;
		return React.createElement(templateClass, templateProps);
	}
	shouldComponentUpdate(nextProps) {
		const templateClass = nextProps.view.getElementTemplate(nextProps.state.element.data.types);
		return !(this.cachedTemplateClass === templateClass && this.cachedTemplateProps === nextProps.state.templateProps);
	}
};
function computeTemplateProps(model, view) {
	const types = model.data.types.length > 0 ? view.getElementTypeString(model.data) : "Thing";
	const label = view.formatLabel(model.data.label.values, model.iri);
	const { color, icon } = computeStyleFor(model, view);
	const propsAsList = computePropertyTable(model, view);
	return {
		elementId: model.id,
		data: model.data,
		iri: model.iri,
		types,
		label,
		color,
		iconUrl: icon,
		imgUrl: model.data.image,
		isExpanded: model.isExpanded,
		props: model.data.properties,
		propsAsList
	};
}
function computePropertyTable(model, view) {
	if (!model.data.properties) return [];
	const propTable = Object.keys(model.data.properties).map((key) => {
		const property = view.model.createProperty(key);
		return {
			id: key,
			name: view.formatLabel(property.label, key),
			property: model.data.properties[key]
		};
	});
	propTable.sort((a, b) => {
		const aLabel = (a.name || a.id).toLowerCase();
		const bLabel = (b.name || b.id).toLowerCase();
		return aLabel.localeCompare(bLabel);
	});
	return propTable;
}
function computeStyleFor(model, view) {
	const { color: { h, c, l }, icon } = view.getTypeStyle(model.data.types);
	return {
		icon,
		color: hcl(h, c, l).toString()
	};
}
function computeIsBlurred(element, view) {
	return view.highlighter && !view.highlighter(element);
}
//#endregion
//#region src/graph-explorer/diagram/linkLayer.tsx
var CLASS_NAME$24 = "graph-explorer-link-layer";
var LinkLayer = class extends Component {
	constructor(..._args) {
		super(..._args);
		this.listener = new EventObserver();
		this.delayedUpdate = new Debouncer();
		this.updateState = 1;
		this.scheduledToUpdate = /* @__PURE__ */ new Set();
		this.scheduleUpdateAll = () => {
			if (this.updateState !== 2) {
				this.updateState = 2;
				this.scheduledToUpdate = /* @__PURE__ */ new Set();
			}
			this.delayedUpdate.call(this.performUpdate);
		};
		this.performUpdate = () => {
			this.forceUpdate();
		};
		this.getLinks = () => {
			const { view, links, group } = this.props;
			if (!group) return links;
			const nestedElements = computeDeepNestedElements(computeGrouping(view.model.elements), group);
			return links.filter((link) => {
				const { sourceId, targetId } = link;
				const source = view.model.getElement(sourceId);
				const target = view.model.getElement(targetId);
				if (!source || !target) return false;
				const sourceGroup = source.group;
				const targetGroup = target.group;
				return nestedElements[sourceGroup] || nestedElements[targetGroup];
			});
		};
	}
	componentDidMount() {
		const { view } = this.props;
		const scheduleUpdateElementLinks = (element) => {
			for (const link of element.links) this.scheduleUpdateLink(link.id);
		};
		this.listener.listen(view.events, "changeLanguage", this.scheduleUpdateAll);
		this.listener.listen(view.events, "changeHighlight", this.scheduleUpdateAll);
		const updateChangedRoutes = (changed, previous) => {
			changed.forEach((routing, linkId) => {
				if (previous.get(linkId) !== routing) this.scheduleUpdateLink(linkId);
			});
		};
		this.listener.listen(view.events, "updateRoutings", ({ previous }) => {
			const newRoutes = view.getRoutings();
			updateChangedRoutes(newRoutes, previous);
			updateChangedRoutes(previous, newRoutes);
		});
		this.listener.listen(view.model.events, "changeCells", (e) => {
			if (e.updateAll) this.scheduleUpdateAll();
			else {
				if (e.changedElement) scheduleUpdateElementLinks(e.changedElement);
				if (e.changedLinks) for (const link of e.changedLinks) this.scheduleUpdateLink(link.id);
			}
		});
		this.listener.listen(view.model.events, "elementEvent", ({ data }) => {
			const elementEvent = data.changePosition || data.changeSize;
			if (!elementEvent) return;
			scheduleUpdateElementLinks(elementEvent.source);
		});
		this.listener.listen(view.model.events, "linkEvent", ({ data }) => {
			const linkEvent = data.changeData || data.changeLayoutOnly || data.changeVertices || data.changeLinkState;
			if (linkEvent) this.scheduleUpdateLink(linkEvent.source.id);
		});
		this.listener.listen(view.model.events, "linkTypeEvent", ({ data }) => {
			const linkTypeEvent = data.changeLabel || data.changeVisibility;
			if (!linkTypeEvent) return;
			const linkTypeId = linkTypeEvent.source.id;
			for (const link of view.model.linksOfType(linkTypeId)) this.scheduleUpdateLink(link.id);
		});
		this.listener.listen(view.events, "syncUpdate", ({ layer }) => {
			if (layer !== RenderingLayer.Link) return;
			this.delayedUpdate.runSynchronously();
		});
	}
	shouldComponentUpdate() {
		return false;
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.delayedUpdate.dispose();
	}
	scheduleUpdateLink(linkId) {
		if (this.updateState === 1) this.scheduledToUpdate.add(linkId);
		this.delayedUpdate.call(this.performUpdate);
	}
	popShouldUpdatePredicate() {
		const { updateState, scheduledToUpdate } = this;
		this.scheduledToUpdate = /* @__PURE__ */ new Set();
		this.updateState = 1;
		return updateState === 2 ? () => true : (link) => scheduledToUpdate.has(link.id);
	}
	render() {
		const { view } = this.props;
		const shouldUpdate = this.popShouldUpdatePredicate();
		return /* @__PURE__ */ React.createElement("g", { className: CLASS_NAME$24 }, this.getLinks().map((model) => /* @__PURE__ */ React.createElement(LinkView, {
			key: model.id,
			view,
			model,
			shouldUpdate: shouldUpdate(model),
			route: view.getRouting(model.id)
		})));
	}
};
function computeDeepNestedElements(grouping, groupId) {
	const deepChildren = {};
	function collectNestedItems(parentId) {
		deepChildren[parentId] = true;
		const children = grouping.get(parentId);
		if (!children) return;
		for (const element of children) {
			if (element.group !== parentId) continue;
			collectNestedItems(element.id);
		}
	}
	collectNestedItems(groupId);
	return deepChildren;
}
var LINK_CLASS = "graph-explorer-link";
var LABEL_GROUPING_PRECISION = 100;
var TEMPORARY_LABEL_LINES = /* @__PURE__ */ new Map();
var LinkView = class extends Component {
	constructor(props, context) {
		super(props, context);
		this.onRemoveLinkVertex = (vertex) => {
			this.props.view.model.history.registerToUndo(restoreCapturedLinkGeometry(vertex.link));
			vertex.remove();
		};
		this.onBoundsUpdate = (newBounds) => {
			const { model } = this.props;
			model.setLabelBounds(newBounds);
		};
		this.grabLinkTemplate(this.props);
	}
	componentDidUpdate(nextProps) {
		if (this.linkType.id !== nextProps.model.typeId) this.grabLinkTemplate(nextProps);
	}
	shouldComponentUpdate(nextProps, _nextState) {
		return nextProps.shouldUpdate;
	}
	grabLinkTemplate(props) {
		this.linkType = props.view.model.getLinkType(props.model.typeId);
		this.template = props.view.createLinkTemplate(this.linkType);
	}
	render() {
		const { view, model, route } = this.props;
		const source = view.model.getElement(model.sourceId);
		const target = view.model.getElement(model.targetId);
		if (!(source && target)) return null;
		const verticesDefinedByUser = model.vertices || [];
		const polyline = computePolyline(source, target, route ? route.vertices : verticesDefinedByUser);
		const path = "M" + polyline.map(({ x, y }) => `${x},${y}`).join(" L");
		const { index: typeIndex, showLabel } = this.linkType;
		const style = this.template.renderLink(model);
		const pathAttributes = getPathAttributes(model, style);
		const className = `${LINK_CLASS} ${view.highlighter && !view.highlighter(model) ? `${LINK_CLASS}--blurred` : ""}`;
		return /* @__PURE__ */ React.createElement("g", {
			className,
			"data-link-id": model.id,
			"data-source-id": source.id,
			"data-target-id": target.id
		}, /* @__PURE__ */ React.createElement("path", {
			className: `${LINK_CLASS}__connection`,
			d: path,
			...pathAttributes,
			markerStart: `url(#${linkMarkerKey(typeIndex, true)})`,
			markerEnd: `url(#${linkMarkerKey(typeIndex, false)})`
		}), /* @__PURE__ */ React.createElement("path", {
			className: `${LINK_CLASS}__wrap`,
			d: path
		}), showLabel ? this.renderLabels(polyline, style) : void 0, this.renderVertices(verticesDefinedByUser, pathAttributes.stroke));
	}
	renderVertices(vertices, fill) {
		const elements = [];
		const vertexClass = `${LINK_CLASS}__vertex`;
		const vertexRadius = 10;
		let index = 0;
		for (const { x, y } of vertices) {
			elements.push(/* @__PURE__ */ React.createElement("circle", {
				key: index * 2,
				"data-vertex": index,
				className: vertexClass,
				cx: x,
				cy: y,
				r: vertexRadius,
				fill
			}));
			elements.push(/* @__PURE__ */ React.createElement(VertexTools, {
				key: index * 2 + 1,
				className: `${LINK_CLASS}__vertex-tools`,
				model: this.props.model,
				vertexIndex: index,
				vertexRadius,
				x,
				y,
				onRemove: this.onRemoveLinkVertex
			}));
			index++;
		}
		return /* @__PURE__ */ React.createElement("g", { className: `${LINK_CLASS}__vertices` }, elements);
	}
	renderLabels(polyline, style) {
		const { view, model, route } = this.props;
		const labels = computeLinkLabels(model, style, view);
		let textAnchor = "middle";
		if (route && route.labelTextAnchor) textAnchor = route.labelTextAnchor;
		const polylineLength = computePolylineLength(polyline);
		TEMPORARY_LABEL_LINES.clear();
		return /* @__PURE__ */ React.createElement("g", { className: `${LINK_CLASS}__labels` }, labels.map((label, index) => {
			const { x, y } = getPointAlongPolyline(polyline, polylineLength * label.offset);
			const groupKey = Math.round(label.offset * LABEL_GROUPING_PRECISION) / LABEL_GROUPING_PRECISION;
			const line = TEMPORARY_LABEL_LINES.get(groupKey) || 0;
			TEMPORARY_LABEL_LINES.set(groupKey, line + 1);
			return /* @__PURE__ */ React.createElement(LinkLabel, {
				key: index,
				x,
				y,
				line,
				label,
				textAnchor,
				onBoundsUpdate: index === 0 ? this.onBoundsUpdate : void 0
			});
		}));
	}
};
function computeLinkLabels(model, style, view) {
	const labels = [];
	const labelStyle = style.label || {};
	const labelTexts = labelStyle.attrs && labelStyle.attrs.text ? labelStyle.attrs.text.text : void 0;
	let text;
	let title = labelStyle.title;
	if (labelTexts && labelTexts.length > 0) text = view.selectLabel(labelTexts);
	else {
		const type = view.model.getLinkType(model.typeId);
		text = view.selectLabel(type.label) || {
			value: view.formatLabel(type.label, type.id),
			language: ""
		};
		if (title === void 0) title = `${text.value} ${view.formatIri(model.typeId)}`;
	}
	labels.push({
		offset: labelStyle.position || .5,
		text,
		title,
		attributes: {
			text: getLabelTextAttributes(labelStyle),
			rect: getLabelRectAttributes(labelStyle)
		}
	});
	if (style.properties) for (const property of style.properties) {
		if (!(property.attrs && property.attrs.text && property.attrs.text.text)) continue;
		labels.push({
			offset: property.position || .5,
			text: view.selectLabel(property.attrs.text.text),
			title: property.title,
			attributes: {
				text: getLabelTextAttributes(property),
				rect: getLabelRectAttributes(property)
			}
		});
	}
	return labels;
}
function getPathAttributes(model, style) {
	const connectionAttributes = style.connection || {};
	const defaultStrokeDasharray = model.layoutOnly ? "5,5" : void 0;
	const { fill = "none", stroke = "black", "stroke-width": strokeWidth, "stroke-dasharray": strokeDasharray = defaultStrokeDasharray } = connectionAttributes;
	return {
		fill,
		stroke,
		strokeWidth,
		strokeDasharray
	};
}
function getLabelTextAttributes(label) {
	const { fill = "black", stroke = "none", "stroke-width": strokeWidth = 0, "font-family": fontFamily = "\"Helvetica Neue\", \"Helvetica\", \"Arial\", sans-serif", "font-size": fontSize = "inherit", "font-weight": fontWeight = "bold" } = label.attrs ? label.attrs.text : {};
	return {
		fill,
		stroke,
		strokeWidth,
		fontFamily,
		fontSize,
		fontWeight
	};
}
function getLabelRectAttributes(label) {
	const { fill = "white", stroke = "none", "stroke-width": strokeWidth = 0 } = label.attrs && label.attrs.rect ? label.attrs.rect : {};
	return {
		fill,
		stroke,
		strokeWidth
	};
}
var GROUPED_LABEL_MARGIN = 2;
var LinkLabel = class extends Component {
	constructor(props) {
		super(props);
		this.shouldUpdateBounds = true;
		this.onTextMount = (text) => {
			this.text = text;
		};
		this.state = {
			width: 0,
			height: 0
		};
	}
	render() {
		const { x, y, label, line, textAnchor } = this.props;
		const { width, height } = this.state;
		const { x: rectX, y: rectY } = this.getLabelRectangle(width, height);
		const transform = line === 0 ? void 0 : `translate(0, ${line * (height + GROUPED_LABEL_MARGIN)}px)`;
		return /* @__PURE__ */ React.createElement("g", { style: transform ? { transform } : void 0 }, label.title ? /* @__PURE__ */ React.createElement("title", null, label.title) : void 0, /* @__PURE__ */ React.createElement("rect", {
			x: rectX,
			y: rectY,
			width,
			height,
			style: label.attributes.rect
		}), /* @__PURE__ */ React.createElement("text", {
			ref: this.onTextMount,
			x,
			y,
			dy: "0.6ex",
			textAnchor,
			style: label.attributes.text
		}, label.text.value));
	}
	getLabelRectangle(width, height) {
		const { x, y, textAnchor } = this.props;
		let xOffset = 0;
		if (textAnchor === "middle") xOffset = -width / 2;
		else if (textAnchor === "end") xOffset = -width;
		return {
			x: x + xOffset,
			y: y - height / 2,
			width,
			height
		};
	}
	componentDidMount() {
		this.recomputeBounds(this.props);
	}
	componentWillUnmount() {
		const { onBoundsUpdate } = this.props;
		onBoundsUpdate(void 0);
	}
	componentDidUpdate(_nextProps) {
		this.shouldUpdateBounds = true;
	}
	UNSAFE_componentWillReceiveProps() {
		this.recomputeBounds(this.props);
	}
	recomputeBounds(_props) {
		if (this.shouldUpdateBounds) {
			const { onBoundsUpdate } = this.props;
			this.shouldUpdateBounds = false;
			const bounds = this.text.getBBox();
			if (onBoundsUpdate) onBoundsUpdate(this.getLabelRectangle(bounds.width, bounds.height));
			this.setState({
				width: bounds.width,
				height: bounds.height
			});
		}
	}
};
var VertexTools = class extends Component {
	constructor(..._args2) {
		super(..._args2);
		this.onRemoveVertex = (e) => {
			if (e.button !== 0) return;
			e.preventDefault();
			e.stopPropagation();
			const { onRemove, model, vertexIndex } = this.props;
			onRemove(new LinkVertex(model, vertexIndex));
		};
	}
	render() {
		const { className, vertexRadius, x, y } = this.props;
		const transform = `translate(${x + 2 * vertexRadius},${y - 2 * vertexRadius})scale(${vertexRadius})`;
		return /* @__PURE__ */ React.createElement("g", {
			className,
			transform,
			onMouseDown: this.onRemoveVertex
		}, /* @__PURE__ */ React.createElement("title", null, "Remove vertex"), /* @__PURE__ */ React.createElement("circle", { r: 1 }), /* @__PURE__ */ React.createElement("path", {
			d: "M-0.5,-0.5 L0.5,0.5 M0.5,-0.5 L-0.5,0.5",
			strokeWidth: 2 / vertexRadius
		}));
	}
};
var LinkMarkers = class extends Component {
	constructor(..._args3) {
		super(..._args3);
		this.listener = new EventObserver();
		this.delayedUpdate = new Debouncer();
	}
	render() {
		const { view } = this.props;
		const markers = [];
		view.getLinkTemplates().forEach((template, linkTypeId) => {
			const type = view.model.getLinkType(linkTypeId);
			if (!type) return;
			const typeIndex = type.index;
			if (template.markerSource) markers.push(/* @__PURE__ */ React.createElement(LinkMarker, {
				key: typeIndex * 2,
				linkTypeIndex: typeIndex,
				style: template.markerSource,
				isStartMarker: true
			}));
			if (template.markerTarget) markers.push(/* @__PURE__ */ React.createElement(LinkMarker, {
				key: typeIndex * 2 + 1,
				linkTypeIndex: typeIndex,
				style: template.markerTarget,
				isStartMarker: false
			}));
		});
		return /* @__PURE__ */ React.createElement("defs", null, markers);
	}
	componentDidMount() {
		const { view } = this.props;
		this.listener.listen(view.events, "syncUpdate", ({ layer }) => {
			if (layer !== RenderingLayer.Link) return;
			this.delayedUpdate.runSynchronously();
		});
		this.listener.listen(view.events, "changeLinkTemplates", () => {
			this.delayedUpdate.call(() => this.forceUpdate());
		});
	}
	shouldComponentUpdate() {
		return false;
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.delayedUpdate.dispose();
	}
};
var SVG_NAMESPACE$1 = "http://www.w3.org/2000/svg";
var LinkMarker = class extends Component {
	constructor(..._args4) {
		super(..._args4);
		this.onMarkerMount = (marker) => {
			if (!marker) return;
			const { linkTypeIndex, isStartMarker, style } = this.props;
			marker.setAttribute("id", linkMarkerKey(linkTypeIndex, isStartMarker));
			marker.setAttribute("markerWidth", style.width.toString());
			marker.setAttribute("markerHeight", style.height.toString());
			marker.setAttribute("orient", "auto");
			const xOffset = isStartMarker ? 0 : style.width - 1;
			marker.setAttribute("refX", xOffset.toString());
			marker.setAttribute("refY", (style.height / 2).toString());
			marker.setAttribute("markerUnits", "userSpaceOnUse");
			const path = document.createElementNS(SVG_NAMESPACE$1, "path");
			path.setAttribute("d", style.d);
			if (style.fill !== void 0) path.setAttribute("fill", style.fill);
			if (style.stroke !== void 0) path.setAttribute("stroke", style.stroke);
			if (style.strokeWidth !== void 0) path.setAttribute("stroke-width", style.strokeWidth);
			marker.appendChild(path);
		};
	}
	render() {
		return /* @__PURE__ */ React.createElement("marker", { ref: this.onMarkerMount });
	}
	shouldComponentUpdate() {
		return false;
	}
};
//#endregion
//#region src/graph-explorer/diagram/paper.tsx
var CLASS_NAME$23 = "graph-explorer-paper";
var Paper = class extends Component {
	constructor(..._args) {
		super(..._args);
		this.onMouseDown = (e) => {
			const { view, onPointerDown } = this.props;
			const cell = e.target instanceof Element ? findCell(e.target, e.currentTarget, view.model) : void 0;
			if (onPointerDown) onPointerDown(e, cell);
		};
	}
	render() {
		const { view, group, paperTransform, linkLayerWidgets, elementLayerWidgets } = this.props;
		const { width, height, originX, originY, scale, paddingX, paddingY } = paperTransform;
		const scaledWidth = width * scale;
		const scaledHeight = height * scale;
		const style = {
			width: scaledWidth + paddingX,
			height: scaledHeight + paddingY,
			marginLeft: paddingX,
			marginTop: paddingY,
			paddingRight: paddingX,
			paddingBottom: paddingY
		};
		const htmlTransformStyle = {
			position: "absolute",
			left: 0,
			top: 0,
			transform: `scale(${scale},${scale})translate(${originX}px,${originY}px)`
		};
		return /* @__PURE__ */ React.createElement("div", {
			className: CLASS_NAME$23,
			style,
			onMouseDown: this.onMouseDown
		}, /* @__PURE__ */ React.createElement(TransformedSvgCanvas, {
			className: `${CLASS_NAME$23}__canvas`,
			style: { overflow: "visible" },
			paperTransform
		}, /* @__PURE__ */ React.createElement(LinkMarkers, { view }), /* @__PURE__ */ React.createElement(LinkLayer, {
			view,
			links: view.model.links,
			group
		})), linkLayerWidgets, /* @__PURE__ */ React.createElement(ElementLayer, {
			view,
			group,
			style: htmlTransformStyle
		}), elementLayerWidgets);
	}
};
function findCell(bottom, top, model) {
	let target = bottom;
	let vertexIndex;
	while (true) {
		if (target instanceof Element) {
			if (target.hasAttribute("data-element-id")) return model.getElement(target.getAttribute("data-element-id"));
			else if (target.hasAttribute("data-link-id")) {
				const link = model.getLinkById(target.getAttribute("data-link-id"));
				return typeof vertexIndex === "number" ? new LinkVertex(link, vertexIndex) : link;
			} else if (target.hasAttribute("data-vertex")) vertexIndex = Number(target.getAttribute("data-vertex"));
		}
		if (!target || target === top) break;
		target = target.parentNode;
	}
}
var TransformedSvgCanvas = class TransformedSvgCanvas extends Component {
	static {
		this.SVG_STYLE = {
			position: "absolute",
			top: 0,
			left: 0
		};
	}
	render() {
		const { paperTransform, style, children, ...otherProps } = this.props;
		const { width, height, originX, originY, scale } = paperTransform;
		const scaledWidth = width * scale;
		const scaledHeight = height * scale;
		let svgStyle = TransformedSvgCanvas.SVG_STYLE;
		if (style) svgStyle = {
			...svgStyle,
			...style
		};
		return /* @__PURE__ */ React.createElement("svg", {
			width: scaledWidth,
			height: scaledHeight,
			style: svgStyle,
			...otherProps
		}, /* @__PURE__ */ React.createElement("g", { transform: `scale(${scale},${scale})translate(${originX},${originY})` }, children));
	}
};
/**
* @returns scrollable pane size in non-scaled pane coords.
*/
function totalPaneSize(pt) {
	return {
		x: pt.width * pt.scale + pt.paddingX * 2,
		y: pt.height * pt.scale + pt.paddingY * 2
	};
}
/**
* @returns scrollable pane top-left corner position in non-scaled pane coords.
*/
function paneTopLeft(pt) {
	return {
		x: -pt.paddingX,
		y: -pt.paddingY
	};
}
function paneFromPaperCoords(paper, pt) {
	return {
		x: (paper.x + pt.originX) * pt.scale,
		y: (paper.y + pt.originY) * pt.scale
	};
}
function paperFromPaneCoords(pane, pt) {
	return {
		x: pane.x / pt.scale - pt.originX,
		y: pane.y / pt.scale - pt.originY
	};
}
//#endregion
//#region src/graph-explorer/viewUtils/toSvg.ts
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
/**
* Padding (in px) for <foreignObject> elements of exported SVG to
* mitigate issues with elements body overflow caused by missing styles
* in exported image.
*/
var FOREIGN_OBJECT_SIZE_PADDING = 2;
var BORDER_PADDING = 100;
function toSVG(options) {
	return exportSVG(options).then((svg) => new XMLSerializer().serializeToString(svg));
}
function exportSVG(options) {
	const { contentBox: bbox, watermarkSvg } = options;
	const { svgClone, imageBounds } = clonePaperSvg(options, FOREIGN_OBJECT_SIZE_PADDING);
	const paddedWidth = bbox.width + 2 * BORDER_PADDING;
	const paddedHeight = bbox.height + 2 * BORDER_PADDING;
	if (options.preserveDimensions) {
		svgClone.setAttribute("width", paddedWidth.toString());
		svgClone.setAttribute("height", paddedHeight.toString());
	} else {
		svgClone.setAttribute("width", "100%");
		svgClone.setAttribute("height", "100%");
	}
	const viewBox = {
		x: bbox.x - BORDER_PADDING,
		y: bbox.y - BORDER_PADDING,
		width: paddedWidth,
		height: paddedHeight
	};
	svgClone.setAttribute("viewBox", `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`);
	addWatermark(svgClone, viewBox, watermarkSvg);
	const images = [];
	foreachNode(svgClone.querySelectorAll("img"), (node) => images.push(node));
	return Promise.all(images.map((img) => {
		const exportKey = img.getAttribute("export-key");
		img.removeAttribute("export-key");
		if (exportKey) {
			const { width, height } = imageBounds[exportKey];
			img.setAttribute("width", width.toString());
			img.setAttribute("height", height.toString());
			if (!options.convertImagesToDataUris) return Promise.resolve();
			return exportAsDataUri(img).then((dataUri) => {
				if (dataUri && dataUri !== "data:image/svg+xml,") img.src = dataUri;
			}).catch((err) => {
				console.warn("Failed to export image: " + img.src, err);
			});
		} else return Promise.resolve();
	})).then(() => {
		const exportedCssText = extractCSSFromDocument(svgClone);
		const exportedVariables = extractCSSVariables(options.paper.closest(".graph-explorer"));
		const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
		defs.innerHTML = `<style>${exportedVariables}\n${exportedCssText}</style>`;
		svgClone.insertBefore(defs, svgClone.firstChild);
		if (options.elementsToRemoveSelector) foreachNode(svgClone.querySelectorAll(options.elementsToRemoveSelector), (node) => node.remove());
		return svgClone;
	});
}
function addWatermark(svg, viewBox, watermarkSvg) {
	const WATERMARK_CLASS = "graph-explorer-exported-watermark";
	const WATERMARK_MAX_WIDTH = 120;
	const WATERMARK_PADDING = 20;
	const image = document.createElementNS(SVG_NAMESPACE, "image");
	image.setAttributeNS("http://www.w3.org/1999/xlink", "href", watermarkSvg);
	image.setAttribute("class", WATERMARK_CLASS);
	const width = Math.min(viewBox.width * .2, WATERMARK_MAX_WIDTH);
	const x = viewBox.x + viewBox.width - width - WATERMARK_PADDING;
	const y = viewBox.y + WATERMARK_PADDING;
	image.setAttribute("x", x.toString());
	image.setAttribute("y", y.toString());
	image.setAttribute("width", width.toString());
	image.setAttribute("opacity", "0.3");
	svg.insertBefore(image, svg.firstChild);
}
function forEachStyleRule(callback) {
	for (let i = 0; i < document.styleSheets.length; i++) {
		let rules;
		try {
			const cssSheet = document.styleSheets[i];
			rules = cssSheet.cssRules || cssSheet.rules;
			if (!rules) continue;
		} catch (_e) {
			continue;
		}
		for (let j = 0; j < rules.length; j++) {
			const rule = rules[j];
			if (rule instanceof CSSStyleRule) callback(rule);
		}
	}
}
/**
* The exported SVG is detached from the workspace, so CSS custom properties
* (the design tokens) declared on the workspace root are not in scope and every
* `var(--…)` reference in the exported rules would resolve to nothing, dropping
* colours, radii and shadows. Re-declare the resolved values on the exported
* root so the export matches what is on the canvas.
*/
function extractCSSVariables(source) {
	if (!source) return "";
	const computed = getComputedStyle(source);
	const declarations = /* @__PURE__ */ new Map();
	forEachStyleRule((rule) => {
		for (let i = 0; i < rule.style.length; i++) {
			const property = rule.style.item(i);
			if (!property.startsWith("--") || declarations.has(property)) continue;
			const value = computed.getPropertyValue(property).trim();
			if (value) declarations.set(property, value);
		}
	});
	if (declarations.size === 0) return "";
	return `svg { ${Array.from(declarations, ([name, value]) => `${name}: ${value};`).join(" ")} }`;
}
function extractCSSFromDocument(targetSubtree) {
	const exportedRules = /* @__PURE__ */ new Set();
	forEachStyleRule((rule) => {
		try {
			if (targetSubtree.querySelector(rule.selectorText)) exportedRules.add(rule);
		} catch (_e) {}
	});
	const exportedCssTexts = [];
	exportedRules.forEach((rule) => exportedCssTexts.push(rule.cssText));
	return exportedCssTexts.join("\n");
}
function clonePaperSvg(options, elementSizePadding) {
	const { model, paper, getOverlayedElement } = options;
	const svgClone = paper.cloneNode(true);
	svgClone.removeAttribute("class");
	svgClone.removeAttribute("style");
	function findViewport() {
		let child = svgClone.firstChild;
		while (child) {
			if (child instanceof SVGGElement) return child;
			child = child.nextSibling;
		}
	}
	const viewport = findViewport();
	viewport.removeAttribute("transform");
	const imageBounds = {};
	for (const element of model.elements) {
		const modelId = element.id;
		const overlayedView = getOverlayedElement(modelId);
		if (!overlayedView) continue;
		const elementRoot = document.createElementNS(SVG_NAMESPACE, "g");
		const overlayedViewContent = overlayedView.firstChild.cloneNode(true);
		elementRoot.setAttribute("class", "graph-explorer-exported-element");
		const newRoot = document.createElementNS(SVG_NAMESPACE, "foreignObject");
		newRoot.appendChild(overlayedViewContent);
		const { x, y, width, height } = boundsOf(element);
		newRoot.setAttribute("transform", `translate(${x},${y})`);
		newRoot.setAttribute("width", (width + elementSizePadding).toString());
		newRoot.setAttribute("height", (height + elementSizePadding).toString());
		elementRoot.appendChild(newRoot);
		viewport.appendChild(elementRoot);
		const clonedNodes = overlayedViewContent.querySelectorAll("img");
		foreachNode(overlayedView.querySelectorAll("img"), (img, index) => {
			const exportKey = uniqueId("export-key-");
			clonedNodes[index].setAttribute("export-key", exportKey);
			imageBounds[exportKey] = {
				width: img.clientWidth,
				height: img.clientHeight
			};
		});
	}
	return {
		svgClone,
		imageBounds
	};
}
function exportAsDataUri(original) {
	const url = original.src;
	if (!url || url.startsWith("data:")) return Promise.resolve(url);
	return loadCrossOriginImage(original.src).then((image) => {
		const canvas = document.createElement("canvas");
		canvas.width = image.width;
		canvas.height = image.height;
		canvas.getContext("2d").drawImage(image, 0, 0);
		const extensionMatch = url.match(/\.([a-zA-Z0-9]+)[^.a-zA-Z0-9]?[^.]*$/);
		const extension = extensionMatch ? extensionMatch[1].toLowerCase() : "png";
		try {
			const mimeType = "image/" + (extension === "jpg" ? "jpeg" : extension);
			const dataUri = canvas.toDataURL(mimeType);
			return Promise.resolve(dataUri);
		} catch (_e) {
			if (extension !== "svg") return Promise.reject("Failed to convert image to data URI");
			return fetch(url).then((response) => response.text()).then((svg) => svg.length > 0 ? "data:image/svg+xml," + encodeURIComponent(svg) : "");
		}
	});
}
function loadCrossOriginImage(src) {
	const image = new Image();
	image.crossOrigin = "anonymous";
	const promise = new Promise((resolve, reject) => {
		image.onload = () => resolve(image);
		image.onerror = (ev) => reject(ev);
	});
	image.src = src;
	return promise;
}
function foreachNode(nodeList, callback) {
	for (let i = 0; i < nodeList.length; i++) callback(nodeList[i], i);
}
var MAX_CANVAS_LENGTH = 4096;
async function toDataURL(options) {
	const { paper: _paper, mimeType = "image/png" } = options;
	const svg = await exportSVG({
		...options,
		convertImagesToDataUris: true,
		mockImages: false,
		preserveDimensions: true
	});
	const svgBox = {
		width: Number(svg.getAttribute("width")),
		height: Number(svg.getAttribute("height"))
	};
	const { innerSize, outerSize, offset } = computeAutofit(svgBox, typeof options.width === "number" || typeof options.height === "number" ? {
		width: options.width,
		height: options.height
	} : fallbackContainerSize(svgBox));
	svg.setAttribute("width", innerSize.width.toString());
	svg.setAttribute("height", innerSize.height.toString());
	const svgString = new XMLSerializer().serializeToString(svg);
	const { canvas, context } = createCanvas(outerSize.width, outerSize.height, options.backgroundColor);
	const image = await loadImage("data:image/svg+xml," + encodeURIComponent(svgString));
	context.drawImage(image, offset.x, offset.y, innerSize.width, innerSize.height);
	return canvas.toDataURL(mimeType, options.quality);
	function createCanvas(canvasWidth, canvasHeight, backgroundColor) {
		const cnv = document.createElement("canvas");
		cnv.width = canvasWidth;
		cnv.height = canvasHeight;
		const cnt = cnv.getContext("2d");
		if (backgroundColor) {
			cnt.fillStyle = backgroundColor;
			cnt.fillRect(0, 0, canvasWidth, canvasHeight);
		}
		return {
			canvas: cnv,
			context: cnt
		};
	}
}
function loadImage(source) {
	return new Promise((resolve, reject) => {
		const image = new Image();
		image.onload = function() {
			resolve(image);
		};
		image.onerror = function(ev) {
			reject(ev);
		};
		image.src = source;
	});
}
function computeAutofit(itemSize, containerSize) {
	const fit = fitRectKeepingAspectRatio(itemSize.width, itemSize.height, containerSize.width, containerSize.height);
	const innerSize = {
		width: Math.floor(fit.width),
		height: Math.floor(fit.height)
	};
	const outerSize = {
		width: typeof containerSize.width === "number" ? containerSize.width : innerSize.width,
		height: typeof containerSize.height === "number" ? containerSize.height : innerSize.height
	};
	return {
		innerSize,
		outerSize,
		offset: {
			x: Math.round((outerSize.width - innerSize.width) / 2),
			y: Math.round((outerSize.height - innerSize.height) / 2)
		}
	};
}
function fallbackContainerSize(itemSize) {
	const maxResolutionScale = Math.min(MAX_CANVAS_LENGTH / itemSize.width, MAX_CANVAS_LENGTH / itemSize.height);
	const resolutionScale = Math.min(2, maxResolutionScale);
	return {
		width: Math.floor(itemSize.width * resolutionScale),
		height: Math.floor(itemSize.height * resolutionScale)
	};
}
function fitRectKeepingAspectRatio(sourceWidth, sourceHeight, targetWidth, targetHeight) {
	if (!(typeof targetWidth === "number" || typeof targetHeight === "number")) return {
		width: sourceWidth,
		height: sourceHeight
	};
	const sourceAspectRatio = sourceWidth / sourceHeight;
	targetWidth = typeof targetWidth === "number" ? targetWidth : targetHeight * sourceAspectRatio;
	targetHeight = typeof targetHeight === "number" ? targetHeight : targetWidth / sourceAspectRatio;
	if (targetHeight * sourceAspectRatio <= targetWidth) return {
		width: targetHeight * sourceAspectRatio,
		height: targetHeight
	};
	else return {
		width: targetWidth,
		height: targetWidth / sourceAspectRatio
	};
}
/**
* Creates and returns a blob from a data URL (either base64 encoded or not).
*
* @param {string} dataURL The data URL to convert.
* @return {Blob} A blob representing the array buffer data.
*/
function dataURLToBlob(dataURL) {
	const BASE64_MARKER = ";base64,";
	if (dataURL.indexOf(BASE64_MARKER) === -1) {
		const parts = dataURL.split(",");
		const contentType = parts[0].split(":")[1];
		const raw = decodeURIComponent(parts[1]);
		return new Blob([raw], { type: contentType });
	} else {
		const parts = dataURL.split(BASE64_MARKER);
		const contentType = parts[0].split(":")[1];
		const raw = window.atob(parts[1]);
		const rawLength = raw.length;
		const uInt8Array = new Uint8Array(rawLength);
		for (let i = 0; i < rawLength; ++i) uInt8Array[i] = raw.charCodeAt(i);
		return new Blob([uInt8Array], { type: contentType });
	}
}
//#endregion
//#region src/graph-explorer/diagram/paperArea.tsx
var PaperAreaContext = React.createContext(null);
var CLASS_NAME$22 = "graph-explorer-paper-area";
var DEFAULT_ANIMATION_DURATION = 500;
var LEFT_MOUSE_BUTTON = 0;
var MIDDLE_MOUSE_BUTTON = 1;
/** Spacing of the background dot grid, in paper (unscaled) coordinates. */
var GRID_STEP = 24;
var PaperArea = class extends React.Component {
	get zoomOptions() {
		const { min = .2, max = 2, step = .1, maxFit = 1, fitPadding = 20, requireCtrl = true } = this.props.zoomOptions || {};
		return {
			min,
			max,
			step,
			maxFit,
			fitPadding,
			requireCtrl
		};
	}
	constructor(props, context) {
		super(props, context);
		this.listener = new EventObserver();
		this.source = new EventSource();
		this.events = this.source;
		this.widgets = {};
		this.pageSize = {
			x: 1500,
			y: 800
		};
		this.cssAnimations = 0;
		this.delayedPaperAdjust = new Debouncer();
		this.onOuterMount = (outer) => {
			this.outer = outer;
		};
		this.onAreaMount = (area) => {
			this.area = area;
		};
		this.onWidgetsMouseDown = (e) => {
			e.stopPropagation();
		};
		this.adjustPaper = (callback) => {
			const { clientWidth, clientHeight } = this.area;
			const adjusted = {
				...this.computeAdjustedBox(),
				paddingX: Math.ceil(clientWidth),
				paddingY: Math.ceil(clientHeight)
			};
			const previous = this.state;
			if (!(adjusted.paperWidth === previous.paperWidth && adjusted.paperHeight === previous.paperHeight && adjusted.originX === previous.originX && adjusted.originY === previous.originY && adjusted.paddingX === previous.paddingX && adjusted.paddingY === previous.paddingY)) {
				this.scrollBeforeUpdate = {
					left: this.area.scrollLeft,
					top: this.area.scrollTop
				};
				this.setState(adjusted, callback);
			} else if (callback) callback();
		};
		this.onPaperPointerDown = (e, cell) => {
			if (this.movingState) return;
			const restore = RestoreGeometry.capture(this.props.view.model);
			const batch = this.props.view.model.history.startBatch(restore.title);
			if (cell && e.button === LEFT_MOUSE_BUTTON) if (cell instanceof Element$1) {
				e.preventDefault();
				this.startMoving(e, cell);
				this.listenToPointerMove(e, cell, batch, restore);
			} else {
				e.preventDefault();
				this.listenToPointerMove(e, cell, batch, restore);
			}
			else {
				e.preventDefault();
				this.listenToPointerMove(e, void 0, batch, restore);
			}
		};
		this.onAreaPointerDown = (e) => {
			if (e.target === this.area) this.onPaperPointerDown(e, void 0);
		};
		this.onPointerMove = (e) => {
			if (!this.movingState || this.scrollBeforeUpdate) return;
			const { origin, target, panning } = this.movingState;
			const pageOffsetX = e.pageX - origin.pageX;
			const pageOffsetY = e.pageY - origin.pageY;
			if (Math.abs(pageOffsetX) >= 1 && Math.abs(pageOffsetY) >= 1) this.movingState.pointerMoved = true;
			if (typeof target === "undefined") {
				if (panning) {
					this.area.scrollLeft = this.panningScrollOrigin.scrollLeft - pageOffsetX;
					this.area.scrollTop = this.panningScrollOrigin.scrollTop - pageOffsetY;
				}
				this.source.trigger("pointerMove", {
					source: this,
					sourceEvent: e,
					target,
					panning
				});
			} else if (target instanceof Element$1) {
				const { x, y } = this.pageToPaperCoords(e.pageX, e.pageY);
				const { pointerX, pointerY, elementX, elementY } = this.movingElementOrigin;
				target.setPosition({
					x: elementX + x - pointerX,
					y: elementY + y - pointerY
				});
				this.source.trigger("pointerMove", {
					source: this,
					sourceEvent: e,
					target,
					panning
				});
				this.props.view.performSyncUpdate();
			} else if (target instanceof Link) {
				const location = this.pageToPaperCoords(e.pageX, e.pageY);
				const linkVertex = this.generateLinkVertex(target, location);
				linkVertex.createAt(location);
				this.movingState.target = linkVertex;
			} else if (target instanceof LinkVertex) {
				const location = this.pageToPaperCoords(e.pageX, e.pageY);
				target.moveTo(location);
				this.source.trigger("pointerMove", {
					source: this,
					sourceEvent: e,
					target,
					panning
				});
				this.props.view.performSyncUpdate();
			}
		};
		this.stopListeningToPointerMove = (e) => {
			const movingState = this.movingState;
			this.movingState = void 0;
			if (movingState) {
				document.removeEventListener("mousemove", this.onPointerMove);
				document.removeEventListener("mouseup", this.stopListeningToPointerMove);
			}
			if (e && movingState) {
				const { pointerMoved, target, batch, restoreGeometry } = movingState;
				this.source.trigger("pointerUp", {
					source: this,
					sourceEvent: e,
					target,
					panning: movingState.panning,
					triggerAsClick: !pointerMoved
				});
				const restore = restoreGeometry.filterOutUnchanged();
				if (restore.hasChanges()) batch.history.registerToUndo(restore);
				batch.store();
			}
		};
		this.onWheel = (e) => {
			if (this.shouldStartZooming(e)) {
				e.preventDefault();
				const delta = Math.max(-1, Math.min(1, e.deltaY || e.deltaX));
				const pivot = this.pageToPaperCoords(e.pageX, e.pageY);
				this.zoomBy(-delta * .1, { pivot });
			}
		};
		this.onDragOver = (e) => {
			if (e.preventDefault) e.preventDefault();
			e.dataTransfer.dropEffect = "move";
			const { x: _x, y: _y } = clientCoordsFor(this.area, e);
			return false;
		};
		this.onDragDrop = (e) => {
			if (this.props.onDragDrop) {
				const { x, y } = clientCoordsFor(this.area, e);
				const paperPosition = this.clientToPaperCoords(x, y);
				this.props.onDragDrop(e, paperPosition);
			}
		};
		this.onScroll = () => {
			this.source.trigger("scroll", { source: this });
		};
		this.applyViewportState = (targetState) => {
			const scale = targetState.scale.x;
			const paperCenter = targetState.center;
			this.setState({ scale }, () => {
				const { originX, originY, paddingX, paddingY } = this.state;
				const scrollCenterX = (paperCenter.x + originX) * scale;
				const scrollCenterY = (paperCenter.y + originY) * scale;
				const { clientWidth, clientHeight } = this.area;
				this.area.scrollLeft = scrollCenterX - clientWidth / 2 + paddingX;
				this.area.scrollTop = scrollCenterY - clientHeight / 2 + paddingY;
				if (this.props.onZoom) this.props.onZoom(scale, scale);
			});
		};
		this.state = {
			paperWidth: this.pageSize.x,
			paperHeight: this.pageSize.y,
			originX: 0,
			originY: 0,
			scale: 1,
			paddingX: 0,
			paddingY: 0,
			renderedWidgets: []
		};
	}
	render() {
		const { view, watermarkSvg, watermarkUrl } = this.props;
		const { paperWidth, paperHeight, originX, originY, scale, paddingX, paddingY, renderedWidgets } = this.state;
		const paperTransform = {
			width: paperWidth,
			height: paperHeight,
			originX,
			originY,
			scale,
			paddingX,
			paddingY
		};
		const widgetProps = {
			paperArea: this,
			paperTransform
		};
		let areaClass = `${CLASS_NAME$22}__area`;
		if (this.props.hideScrollBars) areaClass += ` ${CLASS_NAME$22}--hide-scrollbars`;
		let componentClass = CLASS_NAME$22;
		if (this.isAnimatingGraph()) componentClass += ` ${CLASS_NAME$22}--animated`;
		const gridStep = GRID_STEP * scale;
		const gridStyle = {
			backgroundSize: `${gridStep}px ${gridStep}px`,
			backgroundPosition: `${paddingX + originX * scale}px ${paddingY + originY * scale}px`
		};
		return /* @__PURE__ */ React.createElement(PaperAreaContext.Provider, { value: { paperArea: {
			paperArea: this,
			view
		} } }, /* @__PURE__ */ React.createElement("div", {
			className: componentClass,
			ref: this.onOuterMount
		}, /* @__PURE__ */ React.createElement("div", {
			className: areaClass,
			ref: this.onAreaMount,
			style: gridStyle,
			onMouseDown: this.onAreaPointerDown
		}, /* @__PURE__ */ React.createElement(Paper, {
			view,
			paperTransform,
			onPointerDown: this.onPaperPointerDown,
			linkLayerWidgets: /* @__PURE__ */ React.createElement("div", {
				className: `${CLASS_NAME$22}__widgets`,
				onMouseDown: this.onWidgetsMouseDown
			}, renderedWidgets.filter((w) => w.attachment === WidgetAttachment.OverLinks).map((widget) => React.cloneElement(widget.element, widgetProps))),
			elementLayerWidgets: /* @__PURE__ */ React.createElement("div", {
				className: `${CLASS_NAME$22}__widgets`,
				onMouseDown: this.onWidgetsMouseDown
			}, renderedWidgets.filter((w) => w.attachment === WidgetAttachment.OverElements).map((widget) => React.cloneElement(widget.element, widgetProps)))
		}), watermarkSvg ? /* @__PURE__ */ React.createElement("a", {
			href: watermarkUrl,
			target: "_blank",
			rel: "noopener noreferrer"
		}, /* @__PURE__ */ React.createElement("img", {
			className: `${CLASS_NAME$22}__watermark`,
			src: watermarkSvg,
			draggable: false
		})) : null), renderedWidgets.filter((w) => w.attachment === WidgetAttachment.Viewport).map((widget) => {
			return React.cloneElement(widget.element, widgetProps);
		})));
	}
	componentDidMount() {
		this.adjustPaper(() => this.centerTo());
		const { view } = this.props;
		const delayedAdjust = () => this.delayedPaperAdjust.call(this.adjustPaper);
		this.listener.listen(view.model.events, "changeCells", delayedAdjust);
		this.listener.listen(view.model.events, "elementEvent", ({ data }) => {
			if (data.changePosition || data.changeSize) delayedAdjust();
		});
		this.listener.listen(view.model.events, "linkEvent", ({ data }) => {
			if (data.changeVertices) delayedAdjust();
		});
		this.listener.listen(view.events, "syncUpdate", ({ layer }) => {
			if (layer !== RenderingLayer.PaperArea) return;
			this.delayedPaperAdjust.runSynchronously();
		});
		this.listener.listen(view.events, "updateWidgets", ({ widgets }) => {
			this.updateWidgets(widgets);
		});
		this.area.addEventListener("dragover", this.onDragOver);
		this.area.addEventListener("drop", this.onDragDrop);
		this.area.addEventListener("scroll", this.onScroll);
		this.area.addEventListener("wheel", this.onWheel, { passive: false });
	}
	componentDidUpdate(prevProps, prevState) {
		if (this.scrollBeforeUpdate) {
			const { scale, originX, originY, paddingX, paddingY } = this.state;
			const scrollX = (originX - prevState.originX) * scale + (paddingX - prevState.paddingX);
			const scrollY = (originY - prevState.originY) * scale + (paddingY - prevState.paddingY);
			const scrollLeft = this.scrollBeforeUpdate.left + scrollX;
			const scrollTop = this.scrollBeforeUpdate.top + scrollY;
			this.area.scrollLeft = scrollLeft;
			this.area.scrollTop = scrollTop;
			this.scrollBeforeUpdate = void 0;
		}
	}
	componentWillUnmount() {
		this.stopListeningToPointerMove();
		this.listener.stopListening();
		this.area.removeEventListener("dragover", this.onDragOver);
		this.area.removeEventListener("drop", this.onDragDrop);
		this.area.removeEventListener("scroll", this.onScroll);
		this.area.removeEventListener("wheel", this.onWheel);
	}
	updateWidgets(update) {
		this.widgets = {
			...this.widgets,
			...update
		};
		const renderedWidgets = Object.keys(this.widgets).filter((key) => this.widgets[key]).map((key) => {
			const widget = this.widgets[key];
			const element = React.cloneElement(widget.element, { key });
			return {
				...widget,
				element
			};
		});
		this.setState({ renderedWidgets });
	}
	pageToPaperCoords(pageX, pageY) {
		const { left, top } = this.area.getBoundingClientRect();
		return this.clientToPaperCoords(pageX - (left + window.pageXOffset), pageY - (top + window.pageYOffset));
	}
	clientToPaperCoords(areaClientX, areaClientY) {
		const { x: paneX, y: paneY } = this.clientToScrollablePaneCoords(areaClientX, areaClientY);
		return this.scrollablePaneToPaperCoords(paneX, paneY);
	}
	clientToScrollablePaneCoords(areaClientX, areaClientY) {
		const { paddingX, paddingY } = this.state;
		return {
			x: areaClientX + this.area.scrollLeft - paddingX,
			y: areaClientY + this.area.scrollTop - paddingY
		};
	}
	scrollablePaneToPaperCoords(paneX, paneY) {
		const { scale, originX, originY } = this.state;
		return {
			x: paneX / scale - originX,
			y: paneY / scale - originY
		};
	}
	paperToScrollablePaneCoords(paperX, paperY) {
		const { scale, originX, originY } = this.state;
		return {
			x: (paperX + originX) * scale,
			y: (paperY + originY) * scale
		};
	}
	/** Returns bounding box of paper content in paper coordinates. */
	getContentFittingBox() {
		const { elements, links } = this.props.view.model;
		return getContentFittingBox(elements, links);
	}
	/** Returns paper size in paper coordinates. */
	getPaperSize() {
		const { paperWidth: width, paperHeight: height, scale } = this.state;
		return {
			width: width / scale,
			height: height / scale
		};
	}
	getAreaMetrics() {
		const { clientWidth, clientHeight, offsetWidth, offsetHeight } = this.area;
		return {
			clientWidth,
			clientHeight,
			offsetWidth,
			offsetHeight
		};
	}
	computeAdjustedBox() {
		const bbox = this.getContentFittingBox();
		const bboxLeft = bbox.x;
		const bboxTop = bbox.y;
		const bboxRight = bbox.x + bbox.width;
		const bboxBottom = bbox.y + bbox.height;
		const { x: gridWidth, y: gridHeight } = this.pageSize;
		const bboxGrid = {
			left: Math.floor(bboxLeft / gridWidth),
			top: Math.floor(bboxTop / gridHeight),
			right: Math.ceil(bboxRight / gridWidth),
			bottom: Math.ceil(bboxBottom / gridHeight)
		};
		const originX = -bboxGrid.left * gridWidth;
		const originY = -bboxGrid.top * gridHeight;
		return {
			paperWidth: Math.max(bboxGrid.right - bboxGrid.left, 1) * gridWidth,
			paperHeight: Math.max(bboxGrid.bottom - bboxGrid.top, 1) * gridHeight,
			originX,
			originY
		};
	}
	shouldStartZooming(e) {
		return Boolean(e.ctrlKey) && Boolean(this.zoomOptions.requireCtrl) || !this.zoomOptions.requireCtrl;
	}
	shouldStartPanning(e) {
		if (e.button === MIDDLE_MOUSE_BUTTON) return true;
		const modifierPressed = e.ctrlKey || e.shiftKey || e.altKey;
		return e.button === LEFT_MOUSE_BUTTON && !modifierPressed;
	}
	startMoving(e, element) {
		const { x: pointerX, y: pointerY } = this.pageToPaperCoords(e.pageX, e.pageY);
		const { x: elementX, y: elementY } = element.position;
		this.movingElementOrigin = {
			pointerX,
			pointerY,
			elementX,
			elementY
		};
	}
	startPanning(_event) {
		const { scrollLeft, scrollTop } = this.area;
		this.panningScrollOrigin = {
			scrollLeft,
			scrollTop
		};
		this.clearTextSelectionInArea();
	}
	/** Clears accidental text selection in the diagram area. */
	clearTextSelectionInArea() {
		if (document.getSelection) {
			const selection = document.getSelection();
			if (selection.removeAllRanges) selection.removeAllRanges();
		}
	}
	generateLinkVertex(link, location) {
		const previous = link.vertices;
		const vertices = previous ? [...previous] : [];
		const model = this.props.view.model;
		return new LinkVertex(link, findNearestSegmentIndex(computePolyline(model.getElement(link.sourceId), model.getElement(link.targetId), vertices), location));
	}
	listenToPointerMove(event, cell, batch, restoreGeometry) {
		if (this.movingState) return;
		const panning = cell === void 0 && this.shouldStartPanning(event);
		if (panning) this.startPanning(event);
		const { pageX, pageY } = event;
		this.movingState = {
			origin: {
				pageX,
				pageY
			},
			target: cell,
			panning,
			pointerMoved: false,
			batch,
			restoreGeometry
		};
		document.addEventListener("mousemove", this.onPointerMove);
		document.addEventListener("mouseup", this.stopListeningToPointerMove);
		this.source.trigger("pointerDown", {
			source: this,
			sourceEvent: event,
			target: cell,
			panning
		});
	}
	centerTo(paperPosition, options = {}) {
		const { paperWidth, paperHeight } = this.state;
		const viewportState = { center: paperPosition || {
			x: paperWidth / 2,
			y: paperHeight / 2
		} };
		return this.setViewportState(viewportState, options);
	}
	centerContent(options = {}) {
		const bbox = this.getContentFittingBox();
		return this.centerTo({
			x: bbox.x + bbox.width / 2,
			y: bbox.y + bbox.height / 2
		}, options);
	}
	getScale() {
		return this.state.scale;
	}
	setScale(value, options) {
		let scale = value;
		const { min, max } = this.zoomOptions;
		scale = Math.max(scale, min);
		scale = Math.min(scale, max);
		let viewportState;
		if (options && options.pivot) {
			const { x, y } = options.pivot;
			const paperCenter = this.clientToPaperCoords(this.area.clientWidth / 2, this.area.clientHeight / 2);
			const previousScale = this.state.scale;
			const scaledBy = scale / previousScale;
			viewportState = {
				center: {
					x: x - (x - paperCenter.x) / scaledBy,
					y: y - (y - paperCenter.y) / scaledBy
				},
				scale: {
					x: scale,
					y: scale
				}
			};
		} else viewportState = { scale: {
			x: scale,
			y: scale
		} };
		return this.setViewportState(viewportState, options);
	}
	zoomBy(value, options) {
		return this.setScale(this.getScale() + value, options);
	}
	zoomIn(scaleOptions) {
		return this.zoomBy(this.zoomOptions.step, scaleOptions);
	}
	zoomOut(scaleOptions) {
		return this.zoomBy(-this.zoomOptions.step, scaleOptions);
	}
	zoomToFit(options = {}) {
		if (options.elements && options.elements.size === 0) return;
		if (this.props.view.model.elements.length === 0) return this.centerTo();
		let elements;
		if (options.elements) {
			const selectionElements = [];
			options.elements.forEach((el) => selectionElements.push(el));
			elements = selectionElements;
		} else elements = this.props.view.model.elements;
		const bbox = getContentFittingBox(elements, []);
		return this.zoomToFitRect(bbox, options);
	}
	zoomToFitRect(bbox, options = {}) {
		const { clientWidth, clientHeight } = this.area;
		if (bbox.width === 0) return;
		const { width } = fitRectKeepingAspectRatio(bbox.width, bbox.height, clientWidth, clientHeight);
		let scale = width / bbox.width;
		const { min, maxFit } = this.zoomOptions;
		scale = Math.max(scale, min);
		scale = Math.min(scale, maxFit);
		const viewPortState = {
			center: {
				x: bbox.x + bbox.width / 2,
				y: bbox.y + bbox.height / 2
			},
			scale: {
				x: scale,
				y: scale
			}
		};
		return this.setViewportState(viewPortState, options);
	}
	makeToSVGOptions() {
		const svg = this.area.querySelector(".graph-explorer-paper__canvas");
		if (!svg) throw new Error("Cannot find SVG canvas to export");
		return {
			model: this.props.view.model,
			paper: svg,
			contentBox: this.getContentFittingBox(),
			getOverlayedElement: (id) => this.area.querySelector(`[data-element-id='${id}']`),
			preserveDimensions: true,
			convertImagesToDataUris: true,
			elementsToRemoveSelector: ".graph-explorer-link__vertex-tools",
			watermarkSvg: this.props.watermarkSvg
		};
	}
	exportSVG() {
		return toSVG(this.makeToSVGOptions());
	}
	exportPNG(options) {
		return toDataURL({
			...options,
			...this.makeToSVGOptions()
		});
	}
	isAnimatingGraph() {
		return this.cssAnimations > 0;
	}
	/**
	* Starts animation for graph elements and links.
	*
	* @param setupChanges immediately called function to perform animatable changes on graph
	* @param duration animation duration in milliseconds (requires custom CSS to override)
	* @returns promise which resolves when this animation ends
	*/
	animateGraph(setupChanges, duration) {
		this.changeGraphAnimationCount(1);
		setupChanges();
		return delay(typeof duration === "number" ? duration : DEFAULT_ANIMATION_DURATION).then(() => this.onGraphAnimationEnd());
	}
	onGraphAnimationEnd() {
		this.changeGraphAnimationCount(-1);
	}
	changeGraphAnimationCount(change) {
		const newValue = this.cssAnimations + change;
		if (newValue < 0) return;
		const previous = this.isAnimatingGraph();
		this.cssAnimations = newValue;
		if (previous !== this.isAnimatingGraph()) {
			this.forceUpdate();
			this.source.trigger("changeAnimatingGraph", {
				source: this,
				previous
			});
		}
	}
	get viewportState() {
		const { clientWidth, clientHeight } = this.area;
		const { originX, originY, paddingX, paddingY, scale } = this.state;
		const scrollCenterX = this.area.scrollLeft + clientWidth / 2 - paddingX;
		const scrollCenterY = this.area.scrollTop + clientHeight / 2 - paddingY;
		return {
			center: {
				x: scrollCenterX / scale - originX,
				y: scrollCenterY / scale - originY
			},
			scale: {
				x: scale,
				y: scale
			}
		};
	}
	setViewportState(state, options) {
		if (this.viewportAnimation) this.viewportAnimation.cancellation.abort();
		const from = this.viewportState;
		const to = {
			...from,
			...state
		};
		if (options && (options.animate || options.duration > 0)) {
			const viewportAnimation = {
				from,
				to,
				cancellation: new Cancellation()
			};
			const awaitPromise = animateInterval(typeof options.duration === "number" ? options.duration : DEFAULT_ANIMATION_DURATION, (progress) => {
				const t = easeInOutBezier(progress);
				const computed = {
					center: {
						x: from.center.x + (to.center.x - from.center.x) * t,
						y: from.center.y + (to.center.y - from.center.y) * t
					},
					scale: {
						x: from.scale.x + (to.scale.x - from.scale.x) * t,
						y: from.scale.y + (to.scale.y - from.scale.y) * t
					}
				};
				this.applyViewportState(computed);
			}, viewportAnimation.cancellation);
			this.viewportAnimation = viewportAnimation;
			return awaitPromise.then(() => {
				this.viewportAnimation = void 0;
			});
		} else {
			this.applyViewportState(to);
			return Promise.resolve();
		}
	}
};
function clientCoordsFor(container, e) {
	const targetBox = (e.target instanceof SVGElement && e.target.ownerSVGElement !== null ? e.target.ownerSVGElement : e.target).getBoundingClientRect();
	const containerBox = container.getBoundingClientRect();
	return {
		x: e.offsetX + (targetBox.left - containerBox.left),
		y: e.offsetY + (targetBox.top - containerBox.top)
	};
}
function getContentFittingBox(elements, links) {
	let minX = Infinity, minY = Infinity;
	let maxX = -Infinity, maxY = -Infinity;
	for (const element of elements) {
		const { x, y } = element.position;
		const size = element.size;
		minX = Math.min(minX, x);
		minY = Math.min(minY, y);
		maxX = Math.max(maxX, x + size.width);
		maxY = Math.max(maxY, y + size.height);
	}
	for (const link of links) {
		const vertices = link.vertices || [];
		for (const { x, y } of vertices) {
			minX = Math.min(minX, x);
			minY = Math.min(minY, y);
			maxX = Math.max(maxX, x);
			maxY = Math.max(maxY, y);
		}
	}
	return {
		x: Number.isFinite(minX) ? minX : 0,
		y: Number.isFinite(minY) ? minY : 0,
		width: Number.isFinite(minX) && Number.isFinite(maxX) ? maxX - minX : 0,
		height: Number.isFinite(minY) && Number.isFinite(maxY) ? maxY - minY : 0
	};
}
//#endregion
//#region src/graph-explorer/diagram/embeddedLayer.tsx
var EmbeddedLayerInner = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.nestedElementListener = new EventObserver();
		this.layerOffsetLeft = 0;
		this.layerOffsetTop = 0;
		this.isApplyingParentMove = false;
		this.isNestedElementMoving = false;
		this.previousPositions = [];
		this.moveNestedElements = (offsetX, offsetY) => {
			this.isApplyingParentMove = true;
			try {
				for (const element of this.getNestedElements()) {
					const { x, y } = element.position;
					const newPosition = {
						x: x + offsetX,
						y: y + offsetY
					};
					element.setPosition(newPosition);
				}
			} finally {
				this.isApplyingParentMove = false;
				this.recomputeSelfBounds();
			}
		};
		this.recomputeSelfBounds = () => {
			if (this.isApplyingParentMove) return;
			const { element } = this.props.context.graphExplorerElement;
			const { x: offsetX, y: offsetY, width: paperWidth, height: paperHeight } = this.getContentFittingBox();
			if (this.isNestedElementMoving) {
				const position = {
					x: offsetX - this.layerOffsetLeft,
					y: offsetY - this.layerOffsetTop
				};
				element.setPosition(position);
			}
			this.setState({
				offsetX,
				offsetY,
				paperWidth,
				paperHeight
			}, () => element.redraw());
		};
		this.onPaperPointerDown = (e, cell) => {
			if (e.button !== 0) return;
			if (cell && cell instanceof Element$1) {
				e.preventDefault();
				this.isNestedElementMoving = true;
			}
		};
		this.onLayerInit = (layer) => {
			if (!layer) return;
			const { left, top } = this.calculateOffset(layer);
			this.layerOffsetLeft = left;
			this.layerOffsetTop = top;
		};
		this.state = {
			paperWidth: 0,
			paperHeight: 0,
			offsetX: 0,
			offsetY: 0
		};
	}
	componentDidMount() {
		const { element } = this.props.context.graphExplorerElement;
		const { paperArea, view } = this.props.context.paperArea;
		this.listener.listen(view.model.events, "changeGroupContent", ({ group }) => {
			if (group === element.id) {
				this.listenNestedElements(this.getNestedElements());
				const { offsetX, offsetY } = this.getOffset();
				this.moveNestedElements(offsetX, offsetY);
			}
		});
		this.listener.listen(element.events, "changePosition", () => {
			if (this.isNestedElementMoving) return;
			const { offsetX, offsetY } = this.getOffset();
			const { x, y } = this.getContentFittingBox();
			const diffX = offsetX - x;
			const diffY = offsetY - y;
			this.moveNestedElements(diffX, diffY);
			this.setState({
				offsetX,
				offsetY
			});
		});
		this.listener.listen(paperArea.events, "pointerUp", (_e) => {
			this.isNestedElementMoving = false;
		});
		const nestedElements = this.getNestedElements();
		this.listenNestedElements(nestedElements);
		if (nestedElements.length > 0) {
			const { x: offsetX, y: offsetY, width: paperWidth, height: paperHeight } = this.getContentFittingBox();
			this.setState({
				offsetX,
				offsetY,
				paperWidth,
				paperHeight
			}, () => element.redraw());
		} else element.requestGroupContent();
	}
	listenNestedElements(nestedElements) {
		const listener = new EventObserver();
		for (const nestedElement of nestedElements) {
			listener.listen(nestedElement.events, "changePosition", this.recomputeSelfBounds);
			listener.listen(nestedElement.events, "changeSize", this.recomputeSelfBounds);
		}
		this.nestedElementListener.stopListening();
		this.nestedElementListener = listener;
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.nestedElementListener.stopListening();
		this.removeElements();
		this.setState({
			paperWidth: 0,
			paperHeight: 0,
			offsetX: 0,
			offsetY: 0
		});
	}
	getNestedElements() {
		const { element } = this.props.context.graphExplorerElement;
		const { view } = this.props.context.paperArea;
		return view.model.elements.filter((el) => el.group === element.id);
	}
	getContentFittingBox() {
		return getContentFittingBox(this.getNestedElements(), []);
	}
	removeElements() {
		const { view } = this.props.context.paperArea;
		const batch = view.model.history.startBatch();
		for (const element of this.getNestedElements()) view.model.removeElement(element.id);
		batch.discard();
	}
	getOffset() {
		const { element } = this.props.context.graphExplorerElement;
		const { x: elementX, y: elementY } = element.position;
		return {
			offsetX: elementX + this.layerOffsetLeft,
			offsetY: elementY + this.layerOffsetTop
		};
	}
	calculateOffset(layer) {
		const { paperArea } = this.props.context.paperArea;
		const scale = paperArea.getScale();
		const parent = findParentElement(layer);
		const { left, top } = layer.getBoundingClientRect();
		const { left: parentLeft, top: parentTop } = parent.getBoundingClientRect();
		return {
			left: (left - parentLeft) / scale,
			top: (top - parentTop) / scale
		};
	}
	render() {
		const { element } = this.props.context.graphExplorerElement;
		const { view } = this.props.context.paperArea;
		const { paperWidth, paperHeight, offsetX, offsetY } = this.state;
		const paperTransform = {
			width: paperWidth,
			height: paperHeight,
			originX: -offsetX,
			originY: -offsetY,
			scale: 1,
			paddingX: 0,
			paddingY: 0
		};
		return /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-embedded-layer",
			ref: this.onLayerInit
		}, /* @__PURE__ */ React.createElement(Paper, {
			view,
			paperTransform,
			onPointerDown: this.onPaperPointerDown,
			group: element.id
		}));
	}
};
function EmbeddedLayer() {
	const elementContext = React.useContext(ElementContext);
	const paperAreaContext = React.useContext(PaperAreaContext);
	return /* @__PURE__ */ React.createElement(EmbeddedLayerInner, { context: {
		...elementContext,
		...paperAreaContext
	} });
}
function findParentElement(layer) {
	const parent = layer.parentElement;
	if (!parent) throw new Error("Cannot find parent diagram element for EmbeddedLayer");
	else if (parent.hasAttribute("data-element-id")) return parent;
	else return findParentElement(parent);
}
//#endregion
//#region src/graph-explorer/customization/templates/group.tsx
var CLASS = "graph-explorer-group-template";
var GroupTemplate = class extends React.Component {
	render() {
		const { label, iconUrl, types, color, isExpanded } = this.props;
		return /* @__PURE__ */ React.createElement("div", { className: CLASS }, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS}__wrap`,
			style: {
				backgroundColor: color,
				borderColor: color
			}
		}, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS}__type-line`,
			title: label
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS}__type-line-icon` }, /* @__PURE__ */ React.createElement("img", { src: iconUrl })), /* @__PURE__ */ React.createElement("div", {
			title: types,
			className: `${CLASS}__type-line-text-container`
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS}__type-line-text` }, types))), /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS}__body`,
			style: { borderColor: color }
		}, /* @__PURE__ */ React.createElement("span", {
			className: `${CLASS}__label`,
			title: label
		}, label), isExpanded ? /* @__PURE__ */ React.createElement("div", { className: `${CLASS}__embedded-layer` }, /* @__PURE__ */ React.createElement(EmbeddedLayer, null)) : null)));
	}
};
//#endregion
//#region src/graph-explorer/workspace/workspaceContext.ts
var WorkspaceEventKey = /* @__PURE__ */ function(WorkspaceEventKey) {
	WorkspaceEventKey["searchUpdateCriteria"] = "search:updateCriteria";
	WorkspaceEventKey["searchQueryItem"] = "search:queryItems";
	WorkspaceEventKey["connectionsLoadLinks"] = "connections:loadLinks";
	WorkspaceEventKey["connectionsExpandLink"] = "connections:expandLink";
	WorkspaceEventKey["connectionsLoadElements"] = "connections:loadElements";
	WorkspaceEventKey["editorChangeSelection"] = "editor:changeSelection";
	WorkspaceEventKey["editorToggleDialog"] = "editor:toggleDialog";
	WorkspaceEventKey["editorAddElements"] = "editor:addElements";
	return WorkspaceEventKey;
}({});
var WorkspaceContext = createContext(null);
//#endregion
//#region src/graph-explorer/viewUtils/collections.ts
function objectValues(obj) {
	const items = [];
	for (const key in obj) {
		if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
		items.push(obj[key]);
	}
	return items;
}
function isEmptyMap(map) {
	for (const key in map) if (Object.prototype.hasOwnProperty.call(map, key)) return false;
	return true;
}
/**
* Clones Map collection. Required due to IE11 not supporing `new Map(map)`.
*/
function cloneMap(map) {
	const clone = /* @__PURE__ */ new Map();
	map.forEach((value, key) => clone.set(key, value));
	return clone;
}
/**
* Clones Set collection. Required due to IE11 not supporing `new Set(set)`.
*/
function cloneSet(set) {
	const clone = /* @__PURE__ */ new Set();
	set.forEach((item) => clone.add(item));
	return clone;
}
function getOrCreateArrayInMap(map, key) {
	let values = map.get(key);
	if (!values) {
		values = [];
		map.set(key, values);
	}
	return values;
}
function getOrCreateSetInMap(map, key) {
	let values = map.get(key);
	if (!values) {
		values = /* @__PURE__ */ new Set();
		map.set(key, values);
	}
	return values;
}
var OrderedMap = class {
	constructor() {
		this.mapping = /* @__PURE__ */ new Map();
		this.ordered = [];
	}
	reorder(compare) {
		this.ordered.sort(compare);
	}
	get items() {
		return this.ordered;
	}
	get(key) {
		return this.mapping.get(key);
	}
	push(key, value) {
		if (this.mapping.has(key)) {
			const previous = this.mapping.get(key);
			if (previous === value) return;
			const index = this.ordered.indexOf(previous);
			this.ordered.splice(index, 1);
		}
		this.mapping.set(key, value);
		this.ordered.push(value);
	}
	delete(key) {
		if (!this.mapping.has(key)) return;
		const previous = this.mapping.get(key);
		const index = this.ordered.indexOf(previous);
		this.ordered.splice(index, 1);
		this.mapping.delete(key);
		return previous;
	}
};
var HashMap = class HashMap {
	constructor(hashCode, equals) {
		this.hashCode = hashCode;
		this.equals = equals;
		this.map = /* @__PURE__ */ new Map();
		this._size = 0;
	}
	get size() {
		return this._size;
	}
	has(key) {
		const items = this.map.get(this.hashCode(key));
		if (!items) return false;
		return Boolean(items.find((p) => this.equals(p.key, key)));
	}
	get(key) {
		const items = this.map.get(this.hashCode(key));
		if (!items) return;
		const pair = items.find((p) => this.equals(p.key, key));
		return pair ? pair.value : void 0;
	}
	set(key, value) {
		const hash = this.hashCode(key);
		let items = this.map.get(hash);
		if (items) {
			const index = items.findIndex((p) => this.equals(p.key, key));
			if (index >= 0) items.splice(index, 1);
			else this._size++;
			items.push({
				key,
				value
			});
		} else {
			items = [{
				key,
				value
			}];
			this.map.set(hash, items);
			this._size++;
		}
		return this;
	}
	delete(key) {
		const items = this.map.get(this.hashCode(key));
		if (!items) return false;
		const index = items.findIndex((p) => this.equals(p.key, key));
		if (index >= 0) {
			items.splice(index, 1);
			this._size--;
			return true;
		} else return false;
	}
	clear() {
		this.map.clear();
		this._size = 0;
	}
	forEach(callback) {
		this.map.forEach((items) => {
			for (const { key, value } of items) callback(value, key, this);
		});
	}
	clone() {
		const clone = new HashMap(this.hashCode, this.equals);
		clone._size = this.size;
		this.map.forEach((value, key) => clone.map.set(key, [...value]));
		return clone;
	}
};
var MoveDirection = /* @__PURE__ */ function(MoveDirection) {
	MoveDirection[MoveDirection["ToStart"] = -1] = "ToStart";
	MoveDirection[MoveDirection["ToEnd"] = 1] = "ToEnd";
	return MoveDirection;
}({});
function makeMoveComparator(items, selected, moveDirection) {
	const orderMap = /* @__PURE__ */ new Map();
	const selectionIndexOffset = moveDirection * items.length;
	items.forEach((item, index) => {
		orderMap.set(item, index);
	});
	for (const selectedItem of selected) orderMap.set(selectedItem, selectionIndexOffset + orderMap.get(selectedItem));
	return (a, b) => {
		const orderA = orderMap.get(a);
		const orderB = orderMap.get(b);
		return orderA > orderB ? 1 : orderA < orderB ? -1 : 0;
	};
}
//#endregion
//#region src/graph-explorer/editor/authoringState.ts
var AuthoringKind = /* @__PURE__ */ function(AuthoringKind) {
	AuthoringKind["ChangeElement"] = "changeElement";
	AuthoringKind["ChangeLink"] = "changeLink";
	return AuthoringKind;
}({});
var AuthoringState = {
	empty: {
		elements: /* @__PURE__ */ new Map(),
		links: new HashMap(hashLink, sameLink)
	},
	isEmpty(state) {
		return state.elements.size === 0 && state.links.size === 0;
	},
	clone(index) {
		return {
			elements: cloneMap(index.elements),
			links: index.links.clone()
		};
	},
	has(state, event) {
		return event.type === "changeElement" ? state.elements.get(event.after.id) === event : state.links.get(event.after) === event;
	},
	discard(state, discarded) {
		if (!this.has(state, discarded)) return state;
		const newState = this.clone(state);
		if (discarded.type === "changeElement") {
			newState.elements.delete(discarded.after.id);
			if (!discarded.before) state.links.forEach((e) => {
				if (isLinkConnectedToElement(e.after, discarded.after.id)) newState.links.delete(e.after);
			});
		} else newState.links.delete(discarded.after);
		return newState;
	},
	addElement(state, item) {
		const event = {
			type: "changeElement",
			after: item,
			deleted: false
		};
		const newState = this.clone(state);
		newState.elements.set(event.after.id, event);
		return newState;
	},
	addLink(state, item) {
		const event = {
			type: "changeLink",
			after: item,
			deleted: false
		};
		const newState = this.clone(state);
		newState.links.set(event.after, event);
		return newState;
	},
	changeElement(state, before, after) {
		const newState = this.clone(state);
		newState.elements.delete(before.id);
		const previous = state.elements.get(before.id);
		if (previous && !previous.before) {
			newState.elements.set(after.id, {
				type: "changeElement",
				after,
				deleted: false
			});
			if (before.id !== after.id) state.links.forEach((e) => {
				if (!e.before && isLinkConnectedToElement(e.after, before.id)) {
					const updatedLink = updateLinkToReferByNewIri(e.after, before.id, after.id);
					newState.links.delete(e.after);
					newState.links.set(updatedLink, {
						type: "changeLink",
						after: updatedLink,
						deleted: false
					});
				}
			});
		} else {
			const iriChanged = after.id !== before.id;
			const previousBefore = previous ? previous.before : void 0;
			newState.elements.set(before.id, {
				type: "changeElement",
				before: previousBefore || before,
				after: iriChanged ? {
					...after,
					id: before.id
				} : after,
				newIri: iriChanged ? after.id : void 0,
				deleted: false
			});
		}
		return newState;
	},
	changeLink(state, before, after) {
		if (!sameLink(before, after)) throw new Error("Cannot move link to another element or change its type");
		const newState = this.clone(state);
		const previous = state.links.get(before);
		newState.links.set(before, {
			type: "changeLink",
			before: previous ? previous.before : void 0,
			after,
			deleted: false
		});
		return newState;
	},
	deleteElement(state, model) {
		const newState = this.clone(state);
		newState.elements.delete(model.id);
		state.links.forEach((e) => {
			if (isLinkConnectedToElement(e.after, model.id)) newState.links.delete(e.after);
		});
		if (!this.isNewElement(state, model.id)) newState.elements.set(model.id, {
			type: "changeElement",
			before: model,
			after: model,
			deleted: true
		});
		return newState;
	},
	deleteLink(state, target) {
		const newState = this.clone(state);
		newState.links.delete(target);
		if (!this.isNewLink(state, target)) newState.links.set(target, {
			type: "changeLink",
			before: target,
			after: target,
			deleted: true
		});
		return newState;
	},
	deleteNewLinksConnectedToElements(state, elementIris) {
		const newState = this.clone(state);
		state.links.forEach((e) => {
			if (!e.before) {
				const target = e.after;
				if (elementIris.has(target.sourceId) || elementIris.has(target.targetId)) newState.links.delete(target);
			}
		});
		return newState;
	},
	isNewElement(state, target) {
		const event = state.elements.get(target);
		return event && event.type === "changeElement" && !event.before;
	},
	isDeletedElement(state, target) {
		const event = state.elements.get(target);
		return event && event.deleted;
	},
	isElementWithModifiedIri(state, target) {
		const event = state.elements.get(target);
		return event && event.type === "changeElement" && event.before && Boolean(event.newIri);
	},
	isNewLink(state, linkModel) {
		const event = state.links.get(linkModel);
		return event && !event.before;
	},
	isDeletedLink(state, linkModel) {
		const event = state.links.get(linkModel);
		return event && event.deleted || this.isDeletedElement(state, linkModel.sourceId) || this.isDeletedElement(state, linkModel.targetId);
	},
	isUncertainLink(state, linkModel) {
		return !this.isDeletedLink(state, linkModel) && (this.isElementWithModifiedIri(state, linkModel.sourceId) || this.isElementWithModifiedIri(state, linkModel.targetId));
	}
};
function isLinkConnectedToElement(link, elementIri) {
	return link.sourceId === elementIri || link.targetId === elementIri;
}
function updateLinkToReferByNewIri(link, oldIri, newIri) {
	return {
		...link,
		sourceId: link.sourceId === oldIri ? newIri : link.sourceId,
		targetId: link.targetId === oldIri ? newIri : link.targetId
	};
}
//#endregion
//#region src/graph-explorer/editor/authoredEntity.tsx
/**
* Component to simplify tracking changes in validation messages (property and link type labels).
*/
var AuthoredEntityInner = class extends React.Component {
	constructor(props) {
		super(props);
		this.queryCancellation = new Cancellation();
		this.onChangeAuthoringState = (e) => {
			const { source: editor, previous } = e;
			const iri = this.props.templateProps.data.id;
			if (editor.authoringState.elements.get(iri) !== previous.elements.get(iri)) this.queryAllowedActions();
		};
		this.onEdit = () => {
			const { editor } = this.props.context.workspace;
			const { elementId } = this.props.templateProps;
			const element = editor.model.getElement(elementId);
			editor.showEditEntityForm(element);
		};
		this.onDelete = () => {
			const { editor } = this.props.context.workspace;
			const { data } = this.props.templateProps;
			editor.deleteEntity(data.id);
		};
		this.state = {};
	}
	componentDidMount() {
		const { editor } = this.props.context.workspace;
		editor.events.on("changeAuthoringState", this.onChangeAuthoringState);
		this.queryAllowedActions();
	}
	componentDidUpdate(prevProps) {
		if (!(this.props.templateProps.data === prevProps.templateProps.data && this.props.templateProps.isExpanded === prevProps.templateProps.isExpanded)) this.queryAllowedActions();
	}
	componentWillUnmount() {
		const { editor } = this.props.context.workspace;
		editor.events.off("changeAuthoringState", this.onChangeAuthoringState);
		this.queryCancellation.abort();
	}
	queryAllowedActions() {
		const { isExpanded, data } = this.props.templateProps;
		if (!isExpanded) return;
		this.queryCancellation.abort();
		this.queryCancellation = new Cancellation();
		const { editor } = this.props.context.workspace;
		if (!editor.metadataApi || AuthoringState.isDeletedElement(editor.authoringState, data.id)) this.setState({
			canEdit: false,
			canDelete: false
		});
		else {
			this.queryCanEdit(data);
			this.queryCanDelete(data);
		}
	}
	queryCanEdit(data) {
		const { editor } = this.props.context.workspace;
		const signal = this.queryCancellation.signal;
		this.setState({ canEdit: void 0 });
		CancellationToken.mapCancelledToNull(signal, editor.metadataApi.canEditElement(data, signal)).then((canEdit) => {
			if (canEdit === null) return;
			this.setState({ canEdit });
		});
	}
	queryCanDelete(data) {
		const { editor } = this.props.context.workspace;
		const signal = this.queryCancellation.signal;
		this.setState({ canDelete: void 0 });
		CancellationToken.mapCancelledToNull(signal, editor.metadataApi.canDeleteElement(data, signal)).then((canDelete) => {
			if (canDelete === null) return;
			this.setState({ canDelete });
		});
	}
	render() {
		const { children: renderTemplate } = this.props;
		const { view } = this.props.context.paperArea;
		const { editor } = this.props.context.workspace;
		const { canEdit, canDelete } = this.state;
		const iri = this.props.templateProps.iri;
		const elementEvent = editor.authoringState.elements.get(iri);
		return renderTemplate({
			editor,
			view,
			canEdit,
			canDelete,
			editedIri: elementEvent && elementEvent.type === AuthoringKind.ChangeElement ? elementEvent.newIri : void 0,
			onEdit: this.onEdit,
			onDelete: this.onDelete
		});
	}
};
function AuthoredEntity(props) {
	const paperAreaContext = React.useContext(PaperAreaContext);
	const workspaceContext = React.useContext(WorkspaceContext);
	return /* @__PURE__ */ React.createElement(AuthoredEntityInner, {
		...props,
		context: {
			...paperAreaContext,
			...workspaceContext
		}
	});
}
//#endregion
//#region src/graph-explorer/viewUtils/spinner.tsx
var CLASS_NAME$21 = "graph-explorer-spinner";
var Spinner = class extends React.Component {
	render() {
		const { position = {
			x: 0,
			y: 0
		}, size = 50, statusText, errorOccured } = this.props;
		const textLeftMargin = 5;
		const pathGeometry = "m3.47,-19.7 a20,20 0 1,1 -6.95,0 m0,0 l-6,5 m6,-5 l-8,-0" + (errorOccured ? "M-8,-8L8,8M-8,8L8,-8" : "");
		return /* @__PURE__ */ React.createElement("g", {
			className: CLASS_NAME$21,
			"data-error": errorOccured,
			transform: `translate(${position.x},${position.y})`
		}, /* @__PURE__ */ React.createElement("g", { className: `${CLASS_NAME$21}__arrow` }, /* @__PURE__ */ React.createElement("path", {
			d: pathGeometry,
			transform: `scale(0.02)scale(${size})`,
			fill: "none",
			stroke: errorOccured ? "red" : "black",
			strokeWidth: "3",
			strokeLinecap: "round"
		})), /* @__PURE__ */ React.createElement("text", {
			style: { dominantBaseline: "middle" },
			x: size / 2 + textLeftMargin
		}, statusText));
	}
};
var HtmlSpinner = class extends React.Component {
	render() {
		const { width, height } = this.props;
		const size = Math.min(width, height);
		return /* @__PURE__ */ React.createElement("svg", {
			width,
			height
		}, /* @__PURE__ */ React.createElement(Spinner, {
			size,
			position: {
				x: width / 2,
				y: height / 2
			}
		}));
	}
};
//#endregion
//#region src/graph-explorer/customization/templates/standard.tsx
var FOAF_NAME = "http://xmlns.com/foaf/0.1/name";
var CLASS_NAME$20 = "graph-explorer-standard-template";
var StandardTemplate = class extends Component {
	render() {
		return /* @__PURE__ */ React.createElement(AuthoredEntity, { templateProps: this.props }, (context) => this.renderTemplate(context));
	}
	renderTemplate(context) {
		const { color, types, isExpanded, iri, propsAsList } = this.props;
		const label = this.getLabel();
		const { editor } = context;
		const leftStripeColor = AuthoringState.isNewElement(editor.authoringState, iri) ? "white" : color;
		const pinnedProperties = this.findPinnedProperties(context);
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$20 }, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__main`,
			style: {
				backgroundColor: leftStripeColor,
				borderColor: color
			}
		}, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__body`,
			style: { borderLeftColor: color }
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__body-horizontal` }, this.renderThumbnail(), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__body-content` }, /* @__PURE__ */ React.createElement("div", {
			title: types,
			className: `${CLASS_NAME$20}__type`
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__type-value` }, this.getTypesLabel())), /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__label`,
			title: label
		}, label))), pinnedProperties ? /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__pinned-props`,
			style: { borderColor: color }
		}, this.renderProperties(pinnedProperties)) : null)), isExpanded ? /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__dropdown`,
			style: { borderColor: color }
		}, this.renderPhoto(), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__dropdown-content` }, this.renderIri(context), this.renderProperties(propsAsList), editor.inAuthoringMode ? /* @__PURE__ */ React.createElement("hr", { className: `${CLASS_NAME$20}__hr` }) : null, editor.inAuthoringMode ? this.renderActions(context) : null)) : null);
	}
	findPinnedProperties(context) {
		const { isExpanded, propsAsList, elementId } = this.props;
		if (isExpanded) return;
		const templateState = context.view.model.getElement(elementId).elementState;
		if (!templateState) return;
		const pinned = templateState[TemplateProperties.PinnedProperties];
		if (!pinned) return;
		const filtered = propsAsList.filter((prop) => Boolean(pinned[prop.id]));
		return filtered.length === 0 ? void 0 : filtered;
	}
	renderProperties(propsAsList) {
		if (!propsAsList.length) return /* @__PURE__ */ React.createElement("div", null, "no properties");
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__properties` }, propsAsList.map(({ name, id, property }) => {
			const propertyValues = getPropertyValues(property);
			return /* @__PURE__ */ React.createElement("div", {
				key: id,
				className: `${CLASS_NAME$20}__properties-row`
			}, /* @__PURE__ */ React.createElement("div", {
				className: `${CLASS_NAME$20}__properties-key`,
				title: `${name} (${id})`
			}, name), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__properties-values` }, propertyValues.map((text, index) => /* @__PURE__ */ React.createElement("div", {
				className: `${CLASS_NAME$20}__properties-value`,
				key: index,
				title: text
			}, text))));
		}));
	}
	renderPhoto() {
		const { color, imgUrl } = this.props;
		if (!imgUrl) return null;
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__photo`,
			style: { borderColor: color }
		}, /* @__PURE__ */ React.createElement("img", {
			src: imgUrl,
			className: `${CLASS_NAME$20}__photo-image`
		}));
	}
	renderIri(context) {
		const { iri } = this.props;
		const finalIri = context.editedIri === void 0 ? iri : context.editedIri;
		return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__iri` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__iri-key` }, "IRI", context.editedIri ? "\xA0(edited)" : "", ":"), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__iri-value` }, isEncodedBlank(finalIri) ? /* @__PURE__ */ React.createElement("span", null, "(blank node)") : /* @__PURE__ */ React.createElement("a", {
			href: finalIri,
			title: finalIri,
			"data-iri-click-intent": "openEntityIri"
		}, finalIri))), /* @__PURE__ */ React.createElement("hr", { className: `${CLASS_NAME$20}__hr` }));
	}
	renderThumbnail() {
		const { color, imgUrl, iconUrl } = this.props;
		if (imgUrl) return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__thumbnail`,
			"aria-hidden": "true"
		}, /* @__PURE__ */ React.createElement("img", {
			src: imgUrl,
			className: `${CLASS_NAME$20}__thumbnail-image`
		}));
		else if (iconUrl) return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__thumbnail`,
			"aria-hidden": "true"
		}, /* @__PURE__ */ React.createElement("img", {
			src: iconUrl,
			className: `${CLASS_NAME$20}__thumbnail-icon`
		}));
		const typeLabel = this.getTypesLabel();
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$20}__thumbnail`,
			"aria-hidden": "true",
			style: { color }
		}, typeLabel.length > 0 ? typeLabel.charAt(0).toUpperCase() : "✳");
	}
	getTypesLabel() {
		return this.props.types;
	}
	getLabel() {
		const { label, props } = this.props;
		return getProperty(props, FOAF_NAME) || label;
	}
	renderActions(context) {
		const { canEdit, canDelete, onEdit, onDelete } = context;
		const SPINNER_WIDTH = 15;
		const SPINNER_HEIGHT = 12;
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$20}__actions` }, /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: canDelete ? "Delete entity" : "Deletion is unavailable for the selected element",
			disabled: !canDelete,
			onClick: onDelete
		}, /* @__PURE__ */ React.createElement("span", { className: "fa fa-trash" }), "\xA0", canEdit === void 0 ? /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: SPINNER_WIDTH,
			height: SPINNER_HEIGHT
		}) : "Delete"), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: canEdit ? "Edit entity" : "Editing is unavailable for the selected element",
			disabled: !canEdit,
			onClick: onEdit
		}, /* @__PURE__ */ React.createElement("span", { className: "fa fa-edit" }), "\xA0", canEdit === void 0 ? /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: SPINNER_WIDTH,
			height: SPINNER_HEIGHT
		}) : "Edit"));
	}
};
//#endregion
//#region src/graph-explorer/customization/templates/index.ts
var DefaultElementTemplateBundle = (_types) => void 0;
//#endregion
//#region src/graph-explorer/data/demo/provider.ts
var DemoDataProvider = class {
	constructor(allClasses, allLinkTypes, allElements, allLinks) {
		this.allClasses = allClasses;
		this.allLinkTypes = allLinkTypes;
		this.allElements = allElements;
		this.allLinks = allLinks;
	}
	simulateNetwork(result) {
		const MEAN_DELAY = 200;
		const cloned = cloneDeep(result);
		const delay = -Math.log(Math.random()) * MEAN_DELAY;
		return new Promise((resolve) => {
			setTimeout(() => resolve(cloned), delay);
		});
	}
	classTree() {
		return this.simulateNetwork(this.allClasses);
	}
	classInfo(params) {
		const classIds = params.classIds || [];
		return this.simulateNetwork(this.allClasses.filter((cl) => classIds.indexOf(cl.id)));
	}
	linkTypes() {
		return this.simulateNetwork(this.allLinkTypes);
	}
	linkTypesInfo(params) {
		const types = keyBy(params.linkTypeIds);
		const linkTypes = this.allLinkTypes.filter((type) => types[type.id]);
		return this.simulateNetwork(linkTypes);
	}
	elementInfo(params) {
		const elements = params.elementIds.map((elementId) => this.allElements[elementId]).filter((element) => element !== void 0);
		return this.simulateNetwork(keyBy(elements, (element) => element.id));
	}
	linksInfo(params) {
		const nodes = keyBy(params.elementIds);
		const types = keyBy(params.linkTypeIds);
		const links = this.allLinks.filter((link) => types[link.linkTypeId] && nodes[link.sourceId] && nodes[link.targetId]);
		return this.simulateNetwork(links);
	}
	linkTypesOf(params) {
		const counts = {};
		for (const link of this.allLinks) if (link.sourceId === params.elementId || link.targetId === params.elementId) {
			const linkCount = counts[link.linkTypeId];
			const isSource = link.sourceId === params.elementId;
			if (linkCount) if (isSource) linkCount.outCount++;
			else linkCount.inCount++;
			else counts[link.linkTypeId] = isSource ? {
				id: link.linkTypeId,
				inCount: 0,
				outCount: 1
			} : {
				id: link.linkTypeId,
				inCount: 1,
				outCount: 0
			};
		}
		return this.simulateNetwork(map(counts));
	}
	linkElements(params) {
		return this.filter({
			refElementId: params.elementId,
			refElementLinkId: params.linkId,
			linkDirection: params.direction,
			limit: params.limit,
			offset: params.offset,
			languageCode: ""
		});
	}
	filter(params) {
		if (params.limit === void 0) params.limit = 100;
		if (params.offset > 0) return Promise.resolve({});
		let filtered = {};
		if (params.elementTypeId) each(this.allElements, (element) => {
			if (element.types.indexOf(params.elementTypeId) >= 0) filtered[element.id] = element;
		});
		else if (params.refElementId) {
			const filteredLinks = params.refElementLinkId ? this.allLinks.filter((link) => link.linkTypeId === params.refElementLinkId) : this.allLinks;
			const nodeId = params.refElementId;
			for (const link of filteredLinks) {
				let linkedElementId;
				if (link.sourceId === nodeId && params.linkDirection !== "in") linkedElementId = link.targetId;
				else if (link.targetId === nodeId && params.linkDirection !== "out") linkedElementId = link.sourceId;
				if (linkedElementId !== void 0) {
					const linkedElement = this.allElements[linkedElementId];
					if (linkedElement) filtered[linkedElement.id] = linkedElement;
				}
			}
		} else if (params.text) filtered = this.allElements;
		else return Promise.reject(/* @__PURE__ */ new Error("This type of filter is not implemented"));
		if (params.text) {
			const filteredByText = {};
			const text = params.text.toLowerCase();
			each(filtered, (element) => {
				if (element.id.toLowerCase().indexOf(text) >= 0 || element.label.values.some((label) => label.value.toLowerCase().indexOf(text) >= 0)) filteredByText[element.id] = element;
			});
			return this.simulateNetwork(filteredByText);
		} else return this.simulateNetwork(filtered);
	}
};
//#endregion
//#region src/graph-explorer/data/sparql/responseHandler.ts
var LABEL_URI = "http://www.w3.org/2000/01/rdf-schema#label";
var RDF_TYPE_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
var EMPTY_MAP = /* @__PURE__ */ new Map();
function getClassTree(response) {
	const treeNodes = createClassMap(response.results.bindings);
	const allNodes = [];
	treeNodes.forEach((node) => {
		allNodes.push(node);
		node.parents.forEach((parent) => {
			treeNodes.get(parent).children.push(node);
		});
		node.parents = void 0;
	});
	const withoutCycles = breakCyclesAndCalculateCounts(allNodes);
	const leafs = /* @__PURE__ */ new Set();
	for (const node of withoutCycles) for (const child of node.children) leafs.add(child.id);
	return withoutCycles.filter((node) => !leafs.has(node.id));
}
function flattenClassTree(classTree) {
	const all = [];
	const visitClasses = (classes) => {
		for (const model of classes) {
			all.push(model);
			visitClasses(model.children);
		}
	};
	visitClasses(classTree);
	return all;
}
function createClassMap(bindings) {
	const treeNodes = /* @__PURE__ */ new Map();
	for (const binding of bindings) {
		if (!isRdfIri(binding.class)) continue;
		const classIri = binding.class.value;
		let node = treeNodes.get(classIri);
		if (!node) {
			node = createEmptyModel(classIri);
			treeNodes.set(classIri, node);
		}
		if (binding.label) appendLabel(node.label, getLocalizedString(binding.label));
		if (binding.parent) {
			const parentIri = binding.parent.value;
			node.parents.add(parentIri);
		}
		if (binding.instcount) node.count = getInstCount(binding.instcount);
	}
	for (const binding of bindings) if (binding.parent) {
		const parentIri = binding.parent.value;
		if (!treeNodes.has(parentIri)) treeNodes.set(parentIri, createEmptyModel(parentIri));
	}
	function createEmptyModel(iri) {
		return {
			id: iri,
			children: [],
			label: { values: [] },
			count: void 0,
			parents: /* @__PURE__ */ new Set()
		};
	}
	return treeNodes;
}
function breakCyclesAndCalculateCounts(tree) {
	const visiting = /* @__PURE__ */ new Set();
	function reduceChildren(acc, node) {
		if (visiting.has(node.id)) return acc;
		if (!node.children) return;
		visiting.add(node.id);
		node.children = node.children.reduce(reduceChildren, []);
		visiting.delete(node.id);
		let childCount;
		node.children.forEach(({ count }) => {
			if (count === void 0) return;
			childCount = childCount === void 0 ? count : childCount + count;
		});
		if (childCount !== void 0) node.count = node.count === void 0 ? childCount : node.count + childCount;
		acc.push(node);
		return acc;
	}
	return tree.reduce(reduceChildren, []);
}
function getClassInfo(response) {
	const classes = {};
	for (const binding of response.results.bindings) {
		if (!binding.class) continue;
		const id = binding.class.value;
		const model = classes[id];
		if (model) {
			appendLabel(model.label, getLocalizedString(binding.label));
			const instanceCount = getInstCount(binding.instcount);
			if (instanceCount !== void 0) model.count = Math.max(model.count, instanceCount);
		} else {
			const label = getLocalizedString(binding.label);
			classes[id] = {
				id,
				children: [],
				label: { values: label ? [label] : [] },
				count: getInstCount(binding.instcount)
			};
		}
	}
	const classesList = [];
	for (const id in classes) {
		if (!Object.prototype.hasOwnProperty.call(classes, id)) continue;
		const model = classes[id];
		classesList.push(model);
	}
	return classesList;
}
function getPropertyInfo(response) {
	const models = {};
	for (const sProperty of response.results.bindings) {
		const sPropertyTypeId = sProperty.property.value;
		if (models[sPropertyTypeId]) {
			if (sProperty.label) {
				const label = models[sPropertyTypeId].label;
				if (label.values.length === 1 && !label.values[0].language) label.values = [];
				label.values.push(getLocalizedString(sProperty.label));
			}
		} else models[sPropertyTypeId] = getPropertyModel(sProperty);
	}
	return models;
}
function getLinkTypes(response) {
	const sInst = response.results.bindings;
	const linkTypes = [];
	const linkTypesMap = {};
	for (const sLink of sInst) {
		const sInstTypeId = sLink.link.value;
		if (linkTypesMap[sInstTypeId]) {
			if (sLink.label) {
				const label = linkTypesMap[sInstTypeId].label;
				if (label.values.length === 1 && !label.values[0].language) label.values = [];
				label.values.push(getLocalizedString(sLink.label));
			}
		} else {
			linkTypesMap[sInstTypeId] = getLinkTypeInfo(sLink);
			linkTypes.push(linkTypesMap[sInstTypeId]);
		}
	}
	return linkTypes;
}
function triplesToElementBinding(triples) {
	const map = {};
	const convertedResponse = {
		head: { vars: [
			"inst",
			"class",
			"label",
			"blankType",
			"propType",
			"propValue"
		] },
		results: { bindings: [] }
	};
	for (const triple of triples) {
		const trippleId = triple.subject.value;
		if (!map[trippleId]) map[trippleId] = createAndPushBinding(triple);
		if (triple.predicate.value === LABEL_URI && isRdfLiteral(triple.object)) {
			if (map[trippleId].label) map[trippleId] = createAndPushBinding(triple);
			map[trippleId].label = triple.object;
		} else if (triple.predicate.value === RDF_TYPE_URI && isRdfIri(triple.object) && isRdfIri(triple.predicate)) {
			if (map[trippleId].class) map[trippleId] = createAndPushBinding(triple);
			map[trippleId].class = triple.object;
		} else if (!isRdfBlank(triple.object) && isRdfIri(triple.predicate)) {
			if (map[trippleId].propType) map[trippleId] = createAndPushBinding(triple);
			map[trippleId].propType = triple.predicate;
			map[trippleId].propValue = triple.object;
		}
	}
	function createAndPushBinding(tripple) {
		const binding = { inst: tripple.subject };
		convertedResponse.results.bindings.push(binding);
		return binding;
	}
	return convertedResponse;
}
function getElementsInfo(response, types = EMPTY_MAP, propertyByPredicate = EMPTY_MAP, openWorldProperties = true) {
	const instancesMap = {};
	for (const binding of response.results.bindings) {
		if (!isRdfIri(binding.inst)) continue;
		const iri = binding.inst.value;
		let model = instancesMap[iri];
		if (!model) {
			model = emptyElementInfo(iri);
			instancesMap[iri] = model;
		}
		enrichElement(model, binding);
	}
	if (!openWorldProperties || propertyByPredicate.size > 0) for (const iri in instancesMap) {
		if (!Object.hasOwnProperty.call(instancesMap, iri)) continue;
		const model = instancesMap[iri];
		model.properties = mapPropertiesByConfig(model, types.get(model.id), propertyByPredicate, openWorldProperties);
	}
	return instancesMap;
}
function mapPropertiesByConfig(model, modelTypes, propertyByPredicate, openWorldProperties) {
	const mapped = {};
	for (const propertyIri in model.properties) {
		if (!Object.hasOwnProperty.call(model.properties, propertyIri)) continue;
		const properties = propertyByPredicate.get(propertyIri);
		if (properties && properties.length > 0) {
			for (const property of properties) if (typeMatchesDomain(property, modelTypes)) mapped[property.id] = model.properties[propertyIri];
		} else if (openWorldProperties) mapped[propertyIri] = model.properties[propertyIri];
	}
	return mapped;
}
function enrichElementsWithImages(response, elementsInfo) {
	const respElements = response.results.bindings;
	for (const respEl of respElements) {
		const elementInfo = elementsInfo[respEl.inst.value];
		if (elementInfo) elementInfo.image = respEl.image.value;
	}
}
function getElementTypes(response) {
	const types = /* @__PURE__ */ new Map();
	for (const binding of response.results.bindings) if (isRdfIri(binding.inst) && isRdfIri(binding.class)) {
		const element = binding.inst.value;
		const type = binding.class.value;
		getOrCreateSetInMap(types, element).add(type);
	}
	return types;
}
function getLinksInfo(response, types = EMPTY_MAP, linkByPredicateType = EMPTY_MAP, openWorldLinks = true) {
	const sparqlLinks = response.results.bindings;
	const links = new HashMap(hashLink, sameLink);
	for (const binding of sparqlLinks) {
		const model = {
			sourceId: binding.source.value,
			linkTypeId: binding.type.value,
			targetId: binding.target.value,
			properties: {}
		};
		if (links.has(model)) {
			if (binding.propType) mergeProperties$1(links.get(model).properties, binding.propType, binding.propValue);
		} else {
			if (binding.propType) mergeProperties$1(model.properties, binding.propType, binding.propValue);
			const linkConfigs = linkByPredicateType.get(model.linkTypeId);
			if (linkConfigs && linkConfigs.length > 0) {
				for (const linkConfig of linkConfigs) if (typeMatchesDomain(linkConfig, types.get(model.sourceId))) {
					const mappedModel = isDirectLink(linkConfig) ? {
						...model,
						linkTypeId: linkConfig.id
					} : model;
					links.set(mappedModel, mappedModel);
				}
			} else if (openWorldLinks) links.set(model, model);
		}
	}
	const linkArray = [];
	links.forEach((value) => linkArray.push(value));
	return linkArray;
}
function getLinksTypesOf(response) {
	return response.results.bindings.filter((b) => !isRdfBlank(b.link)).map((sLink) => getLinkCount(sLink));
}
function getLinksTypeIds(response, linkByPredicateType = EMPTY_MAP, openWorldLinks = true) {
	const linkTypes = [];
	for (const binding of response.results.bindings) {
		if (!isRdfIri(binding.link)) continue;
		const linkConfigs = linkByPredicateType.get(binding.link.value);
		if (linkConfigs && linkConfigs.length > 0) for (const linkConfig of linkConfigs) {
			const mappedLinkType = isDirectLink(linkConfig) ? linkConfig.id : binding.link.value;
			linkTypes.push(mappedLinkType);
		}
		else if (openWorldLinks) linkTypes.push(binding.link.value);
	}
	return linkTypes;
}
function getLinkStatistics(response) {
	for (const binding of response.results.bindings) if (isRdfIri(binding.link)) return getLinkCount(binding);
}
function getFilteredData(response, sourceTypes, linkByPredicateType = EMPTY_MAP, openWorldLinks = true) {
	const instancesMap = {};
	const resultTypes = /* @__PURE__ */ new Map();
	const outPredicates = /* @__PURE__ */ new Map();
	const inPredicates = /* @__PURE__ */ new Map();
	for (const binding of response.results.bindings) {
		if (!isRdfIri(binding.inst) && !isRdfBlank(binding.inst)) continue;
		const iri = binding.inst.value;
		let model = instancesMap[iri];
		if (!model) {
			model = emptyElementInfo(iri);
			instancesMap[iri] = model;
		}
		enrichElement(model, binding);
		if (isRdfIri(binding.classAll)) getOrCreateSetInMap(resultTypes, iri).add(binding.classAll.value);
		if (!openWorldLinks && binding.link && binding.direction) getOrCreateSetInMap(binding.direction.value === "out" ? outPredicates : inPredicates, model.id).add(binding.link.value);
	}
	if (!openWorldLinks) for (const id of Object.keys(instancesMap)) {
		const model = instancesMap[id];
		const targetTypes = resultTypes.get(model.id);
		if (!(matchesDomainForLink(sourceTypes, outPredicates.get(model.id), linkByPredicateType) && matchesDomainForLink(targetTypes, inPredicates.get(model.id), linkByPredicateType))) delete instancesMap[id];
	}
	return instancesMap;
}
function matchesDomainForLink(types, predicates, linkByPredicateType) {
	if (!predicates) return true;
	let hasMatch = false;
	predicates.forEach((predicate) => {
		const matched = linkByPredicateType.get(predicate);
		if (matched) {
			for (const link of matched) if (typeMatchesDomain(link, types)) hasMatch = true;
		}
	});
	return hasMatch;
}
function isDirectLink(link) {
	return !/[?$][a-zA-Z]+\b/.test(link.path);
}
function isDirectProperty(property) {
	return !/[?$][a-zA-Z]+\b/.test(property.path);
}
function typeMatchesDomain(config, types) {
	if (!config.domain || config.domain.length === 0) return true;
	else if (!types) return false;
	else {
		for (const type of config.domain) if (types.has(type)) return true;
		return false;
	}
}
/**
* Modifies properties with merging with new values, couls be new peroperty or new value for existing properties.
* @param properties
* @param propType
* @param propValue
*/
function mergeProperties$1(properties, propType, propValue) {
	let property = properties[propType.value];
	if (isRdfIri(propValue)) {
		if (!property) property = {
			type: "uri",
			values: []
		};
		if (isIriProperty(property) && property.values.every(({ value }) => value !== propValue.value)) property.values = [...property.values, propValue];
	} else if (isRdfLiteral(propValue)) {
		if (!property) property = {
			type: "string",
			values: []
		};
		const propertyValue = getLocalizedString(propValue);
		if (isLiteralProperty(property) && property.values.every((value) => !isLocalizedEqual(value, propertyValue))) property.values = [...property.values, propertyValue];
	}
	properties[propType.value] = property;
}
function enrichElement(element, sInst) {
	if (!element) return;
	if (sInst.label) {
		const label = getLocalizedString(sInst.label);
		if (element.label.values.every((value) => !isLocalizedEqual(value, label))) element.label.values.push(label);
	}
	if (sInst.class && element.types.indexOf(sInst.class.value) < 0) element.types.push(sInst.class.value);
	if (sInst.propType && sInst.propType.value !== LABEL_URI) mergeProperties$1(element.properties, sInst.propType, sInst.propValue);
}
function appendLabel(container, newLabel) {
	if (!newLabel) return;
	for (const existing of container.values) if (isLocalizedEqual(existing, newLabel)) return;
	container.values.push(newLabel);
}
function isLocalizedEqual(left, right) {
	return left.language === right.language && left.value === right.value;
}
function getLocalizedString(label) {
	if (label) return {
		value: label.value,
		language: label["xml:lang"],
		datatype: label.datatype ? { value: label.datatype } : void 0
	};
	else return;
}
function getInstCount(instcount) {
	return instcount ? +instcount.value : void 0;
}
function getPropertyModel(node) {
	const label = getLocalizedString(node.label);
	return {
		id: node.property.value,
		label: { values: label ? [label] : [] }
	};
}
function getLinkCount(sLinkType) {
	return {
		id: sLinkType.link.value,
		inCount: getInstCount(sLinkType.inCount),
		outCount: getInstCount(sLinkType.outCount)
	};
}
function emptyElementInfo(id) {
	return {
		id,
		label: { values: [] },
		types: [],
		properties: {}
	};
}
function getLinkTypeInfo(sLinkInfo) {
	if (!sLinkInfo) return;
	const label = getLocalizedString(sLinkInfo.label);
	return {
		id: sLinkInfo.link.value,
		label: { values: label ? [label] : [] },
		count: getInstCount(sLinkInfo.instcount)
	};
}
function prependAdditionalBindings(base, additional) {
	if (!additional) return base;
	return {
		head: { vars: base.head.vars },
		results: { bindings: [...additional.results.bindings, ...base.results.bindings] }
	};
}
//#endregion
//#region src/graph-explorer/data/sparql/sparqlDataProviderSettings.ts
var RDFSettings = {
	linkConfigurations: [],
	openWorldLinks: false,
	propertyConfigurations: [],
	openWorldProperties: false,
	linksInfoQuery: `SELECT ?source ?type ?target
            WHERE {
                \${linkConfigurations}
                VALUES (?source) {\${ids}}
                VALUES (?target) {\${ids}}
            }`,
	defaultPrefix: "",
	schemaLabelProperty: "rdfs:label",
	dataLabelProperty: "rdfs:label",
	fullTextSearch: {
		prefix: "",
		queryPattern: ``,
		elementFirst: false
	},
	classTreeQuery: ``,
	classInfoQuery: `SELECT ?class ?label ?instcount WHERE {
    VALUES(?class) {\${ids}}
    OPTIONAL { ?class \${schemaLabelProperty} ?label }
    BIND("" as ?instcount)
}`,
	linkTypesQuery: `SELECT DISTINCT ?link ?instcount ?label WHERE {
    \${linkTypesPattern}
    OPTIONAL { ?link \${schemaLabelProperty} ?label }
}`,
	linkTypesPattern: ``,
	linkTypesInfoQuery: `SELECT ?link ?label WHERE {
    VALUES(?link) {\${ids}}
    OPTIONAL { ?link \${schemaLabelProperty} ?label }
}`,
	propertyInfoQuery: `SELECT ?property ?label WHERE {
    VALUES(?property) {\${ids}}
    OPTIONAL { ?property \${schemaLabelProperty} ?label }
}`,
	elementInfoQuery: ``,
	imageQueryPattern: ``,
	linkTypesOfQuery: ``,
	linkTypesStatisticsQuery: ``,
	filterRefElementLinkPattern: "",
	filterTypePattern: ``,
	filterAdditionalRestriction: ``,
	filterElementInfoPattern: ``
};
var WikidataSettingsOverride = {
	defaultPrefix: `PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
 PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
 PREFIX wdt: <http://www.wikidata.org/prop/direct/>
 PREFIX wd: <http://www.wikidata.org/entity/>
 PREFIX owl:  <http://www.w3.org/2002/07/owl#>

`,
	schemaLabelProperty: "rdfs:label",
	dataLabelProperty: "rdfs:label",
	fullTextSearch: {
		prefix: "PREFIX bds: <http://www.bigdata.com/rdf/search#>\n",
		queryPattern: `
              ?inst rdfs:label ?searchLabel.
              SERVICE bds:search {
                     ?searchLabel bds:search "\${text}*" ;
                                  bds:minRelevance '0.5' ;
                                  bds:matchAllTerms 'true' .
              }
              BIND(IF(STRLEN(?strInst) > 33,
                            0-<http://www.w3.org/2001/XMLSchema#integer>(SUBSTR(?strInst, 33)),
                            -10000) as ?score)
            `
	},
	classTreeQuery: `
            SELECT distinct ?class ?label ?parent WHERE {
              ?class rdfs:label ?label.
              { ?class wdt:P279 wd:Q35120. }
                UNION
              { ?parent wdt:P279 wd:Q35120.
                ?class wdt:P279 ?parent. }
                UNION
              { ?parent wdt:P279/wdt:P279 wd:Q35120.
                ?class wdt:P279 ?parent. }
            }
        `,
	linkTypesPattern: `?link wdt:P279* wd:Q18616576.
    BIND(0 as ?instcount)
`,
	elementInfoQuery: `
        CONSTRUCT {
            ?inst rdf:type ?class .
            ?inst rdfs:label ?label .
            ?inst ?propType ?propValue.
        } WHERE {
            VALUES (?inst) {\${ids}}
            OPTIONAL {
                ?inst wdt:P31 ?class
            }
            OPTIONAL {?inst rdfs:label ?label}
            OPTIONAL {
                \${propertyConfigurations}
                FILTER (isLiteral(?propValue))
            }
        }
    `,
	imageQueryPattern: ` { ?inst ?linkType ?fullImage } union { ?inst wdt:P163/wdt:P18 ?fullImage }
                BIND(CONCAT("https://commons.wikimedia.org/w/thumb.php?f=",
                    STRAFTER(STR(?fullImage), "Special:FilePath/"), "&w=200") AS ?image)`,
	linkTypesOfQuery: `
        SELECT DISTINCT ?link
        WHERE {
            \${linkConfigurations}
            ?claim <http://wikiba.se/ontology#directClaim> ?link .
        }
    `,
	linkTypesStatisticsQuery: `
        SELECT (\${linkId} as ?link) (COUNT(?outObject) AS ?outCount) (COUNT(?inObject) AS ?inCount)
        WHERE {
            {
                {
                    SELECT DISTINCT ?outObject WHERE {
                        \${linkConfigurationOut}
                        FILTER(ISIRI(?outObject))
                        ?outObject ?someprop ?someobj.
                    }
                    LIMIT 101
                }
            } UNION {
                {
                    SELECT DISTINCT ?inObject WHERE {
                        \${linkConfigurationIn}
                        FILTER(ISIRI(?inObject))
                        ?inObject ?someprop ?someobj.
                    }
                    LIMIT 101
                }
            }
        }
    `,
	filterRefElementLinkPattern: "?claim <http://wikiba.se/ontology#directClaim> ?link .",
	filterTypePattern: `?inst wdt:P31 ?instType. ?instType wdt:P279* ?class`,
	filterAdditionalRestriction: `FILTER ISIRI(?inst)
                        BIND(STR(?inst) as ?strInst)
                        FILTER exists {?inst ?someprop ?someobj}
`,
	filterElementInfoPattern: `OPTIONAL {?inst wdt:P31 ?foundClass}
                BIND (coalesce(?foundClass, owl:Thing) as ?class)
                OPTIONAL {?inst rdfs:label ?label}
`
};
var WikidataSettings = {
	...RDFSettings,
	...WikidataSettingsOverride
};
var OWLRDFSSettingsOverride = {
	defaultPrefix: `PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
 PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
 PREFIX owl:  <http://www.w3.org/2002/07/owl#>
`,
	schemaLabelProperty: "rdfs:label",
	dataLabelProperty: "rdfs:label",
	fullTextSearch: {
		prefix: "",
		queryPattern: ` OPTIONAL {?inst \${dataLabelProperty} ?search1}
        FILTER regex(COALESCE(str(?search1), str(?extractedLabel)), "\${text}", "i")
        BIND(0 as ?score)
`,
		extractLabel: true
	},
	classTreeQuery: `
            SELECT ?class ?label ?parent
            WHERE {
                {
                    ?class a rdfs:Class
                } UNION {
                    ?class a owl:Class
                }
                FILTER ISIRI(?class)
                OPTIONAL {?class rdfs:label ?label}
                OPTIONAL {?class rdfs:subClassOf ?parent. FILTER ISIRI(?parent)}
            }
        `,
	linkTypesPattern: `{  ?link a rdf:Property
                    } UNION {
                    ?link a owl:ObjectProperty
                }
                BIND('' as ?instcount)
    `,
	elementInfoQuery: `
        CONSTRUCT {
            ?inst rdf:type ?class .
            ?inst rdfs:label ?label .
            ?inst ?propType ?propValue.
        } WHERE {
            VALUES (?inst) {\${ids}}
            OPTIONAL { ?inst a ?class }
            OPTIONAL {?inst \${dataLabelProperty} ?label}
            OPTIONAL {
                \${propertyConfigurations}
                FILTER (isLiteral(?propValue))
            }
        }
    `,
	imageQueryPattern: `{ ?inst ?linkType ?image } UNION { [] ?linkType ?inst. BIND(?inst as ?image) }`,
	linkTypesOfQuery: `
        SELECT DISTINCT ?link
        WHERE {
            \${linkConfigurations}
        }
    `,
	linkTypesStatisticsQuery: `
        SELECT ?link ?outCount ?inCount
        WHERE {
            {
                SELECT (\${linkId} as ?link) (count(?outObject) as ?outCount) WHERE {
                    \${linkConfigurationOut}
                    \${navigateElementFilterOut}
                } LIMIT 101
            } {
                SELECT (\${linkId} as ?link) (count(?inObject) as ?inCount) WHERE {
                    \${linkConfigurationIn}
                    \${navigateElementFilterIn}
                } LIMIT 101
            }
        }
    `,
	filterRefElementLinkPattern: "",
	filterTypePattern: `?inst a ?instType. ?instType rdfs:subClassOf* ?class`,
	filterElementInfoPattern: `OPTIONAL {?inst rdf:type ?foundClass}
                BIND (coalesce(?foundClass, owl:Thing) as ?class)
                OPTIONAL {?inst \${dataLabelProperty} ?label}`,
	filterAdditionalRestriction: ""
};
var OWLRDFSSettings = {
	...RDFSettings,
	...OWLRDFSSettingsOverride
};
var OWLStatsOverride = { classTreeQuery: `
        SELECT ?class ?instcount ?label ?parent
        WHERE {
            {SELECT ?class (count(?inst) as ?instcount)
                WHERE {
                    ?inst rdf:type ?class.
                    FILTER ISIRI(?class)
                } GROUP BY ?class } UNION
            {
                ?class rdf:type rdfs:Class
            } UNION {
                ?class rdf:type owl:Class
            }
            OPTIONAL {?class rdfs:label ?label}
            OPTIONAL {?class rdfs:subClassOf ?parent. FILTER ISIRI(?parent)}
        }
    ` };
var OWLStatsSettings = {
	...OWLRDFSSettings,
	...OWLStatsOverride
};
var DBPediaOverride = {
	fullTextSearch: {
		prefix: "PREFIX dbo: <http://dbpedia.org/ontology/>\n",
		queryPattern: `
              ?inst rdfs:label ?searchLabel.
              ?searchLabel bif:contains "\${text}".
              ?inst dbo:wikiPageID ?origScore .
              BIND(0-?origScore as ?score)
        `
	},
	classTreeQuery: `
        SELECT distinct ?class ?label ?parent WHERE {
            ?class rdfs:label ?label.
            OPTIONAL {?class rdfs:subClassOf ?parent}
            ?root rdfs:subClassOf owl:Thing.
            ?class rdfs:subClassOf? | rdfs:subClassOf/rdfs:subClassOf ?root
        }
    `,
	elementInfoQuery: `
        CONSTRUCT {
            ?inst rdf:type ?class .
            ?inst rdfs:label ?label .
            ?inst ?propType ?propValue.
        } WHERE {
            VALUES (?inst) {\${ids}}
            ?inst a ?class .
            ?inst rdfs:label ?label .
            FILTER (!contains(str(?class), 'http://dbpedia.org/class/yago'))
            OPTIONAL {
                \${propertyConfigurations}
                FILTER (isLiteral(?propValue))
            }
        }
    `,
	filterTypePattern: `?inst a ?instType. ?instType rdfs:subClassOf* ?class`,
	filterElementInfoPattern: `
        OPTIONAL {?inst rdf:type ?foundClass. FILTER (!contains(str(?foundClass), 'http://dbpedia.org/class/yago'))}
        BIND (coalesce(?foundClass, owl:Thing) as ?class)
        OPTIONAL {?inst \${dataLabelProperty} ?label}`,
	imageQueryPattern: ` { ?inst ?linkType ?fullImage } UNION { [] ?linkType ?inst. BIND(?inst as ?fullImage) }
            BIND(CONCAT("https://commons.wikimedia.org/w/thumb.php?f=",
            STRAFTER(STR(?fullImage), "Special:FilePath/"), "&w=200") AS ?image)
    `
};
var DBPediaSettings = {
	...OWLRDFSSettings,
	...DBPediaOverride
};
var QLeverOverride = { fullTextSearch: {
	prefix: "PREFIX ql: <http://qlever.cs.uni-freiburg.de/builtin-functions/>\n",
	queryPatternPerWord: `
              ?inst \${dataLabelProperty} ?searchLabel .
              ?searchLabel ql:has-word "\${word}" .
        `
} };
var QLeverSettings = {
	...OWLRDFSSettings,
	...QLeverOverride
};
//#endregion
//#region src/graph-explorer/data/sparql/turtle.ts
function parseTurtleText(turtleText) {
	return new Promise((resolve, reject) => {
		const triples = [];
		new N3.Parser().parse(turtleText, (error, triple, _hash) => {
			if (error) reject(error);
			else if (triple) triples.push({
				subject: n3toRdfNode(triple.subject),
				predicate: n3toRdfNode(triple.predicate),
				object: n3toRdfNode(triple.object)
			});
			else resolve(triples);
		});
	});
}
function n3toRdfNode(entity) {
	if (N3.Util.isLiteral(entity)) {
		const literal = entity;
		return {
			type: "literal",
			value: literal.value,
			datatype: literal.datatype.value,
			"xml:lang": literal.language
		};
	} else return {
		type: "uri",
		value: entity.value
	};
}
//#endregion
//#region src/graph-explorer/data/sparql/sparqlDataProvider.ts
var SparqlQueryMethod = /* @__PURE__ */ function(SparqlQueryMethod) {
	SparqlQueryMethod[SparqlQueryMethod["GET"] = 1] = "GET";
	SparqlQueryMethod[SparqlQueryMethod["POST"] = 2] = "POST";
	return SparqlQueryMethod;
}({});
var SparqlDataProvider = class {
	constructor(options, settings = OWLStatsSettings) {
		this.linkByPredicate = /* @__PURE__ */ new Map();
		this.linkById = /* @__PURE__ */ new Map();
		this.propertyByPredicate = /* @__PURE__ */ new Map();
		const { queryFunction = queryInternal } = options;
		this.options = {
			...options,
			queryFunction
		};
		this.settings = settings;
		for (const link of settings.linkConfigurations) {
			this.linkById.set(link.id, link);
			const predicate = isDirectLink(link) ? link.path : link.id;
			getOrCreateArrayInMap(this.linkByPredicate, predicate).push(link);
		}
		this.openWorldLinks = settings.linkConfigurations.length === 0 || Boolean(settings.openWorldLinks);
		for (const property of settings.propertyConfigurations) {
			const predicate = isDirectProperty(property) ? property.path : property.id;
			getOrCreateArrayInMap(this.propertyByPredicate, predicate).push(property);
		}
		this.openWorldProperties = settings.propertyConfigurations.length === 0 || Boolean(settings.openWorldProperties);
	}
	async classTree() {
		const { defaultPrefix, schemaLabelProperty, classTreeQuery } = this.settings;
		if (!classTreeQuery) return [];
		const query = defaultPrefix + resolveTemplate(classTreeQuery, { schemaLabelProperty });
		const classTree = getClassTree(await this.executeSparqlQuery(query));
		if (this.options.prepareLabels) await attachLabels(flattenClassTree(classTree), this.options.prepareLabels);
		return classTree;
	}
	async propertyInfo(params) {
		const { defaultPrefix, schemaLabelProperty, propertyInfoQuery } = this.settings;
		let properties;
		if (propertyInfoQuery) {
			const query = defaultPrefix + resolveTemplate(propertyInfoQuery, {
				ids: params.propertyIds.map(escapeIri).map((id) => ` ( ${id} )`).join(" "),
				schemaLabelProperty
			});
			properties = getPropertyInfo(await this.executeSparqlQuery(query));
		} else {
			properties = {};
			for (const id of params.propertyIds) properties[id] = {
				id,
				label: { values: [] }
			};
		}
		if (this.options.prepareLabels) await attachLabels(objectValues(properties), this.options.prepareLabels);
		return properties;
	}
	async classInfo(params) {
		const { defaultPrefix, schemaLabelProperty, classInfoQuery } = this.settings;
		let classes;
		if (classInfoQuery) {
			const query = defaultPrefix + resolveTemplate(classInfoQuery, {
				ids: params.classIds.map(escapeIri).map((id) => ` ( ${id} )`).join(" "),
				schemaLabelProperty
			});
			classes = getClassInfo(await this.executeSparqlQuery(query));
		} else classes = params.classIds.map((id) => ({
			id,
			label: { values: [] },
			children: []
		}));
		if (this.options.prepareLabels) await attachLabels(classes, this.options.prepareLabels);
		return classes;
	}
	async linkTypesInfo(params) {
		const { defaultPrefix, schemaLabelProperty, linkTypesInfoQuery } = this.settings;
		let linkTypes;
		if (linkTypesInfoQuery) {
			const query = defaultPrefix + resolveTemplate(linkTypesInfoQuery, {
				ids: params.linkTypeIds.map(escapeIri).map((id) => ` ( ${id} )`).join(" "),
				schemaLabelProperty
			});
			linkTypes = getLinkTypes(await this.executeSparqlQuery(query));
		} else linkTypes = params.linkTypeIds.map((id) => ({
			id,
			label: { values: [] }
		}));
		if (this.options.prepareLabels) await attachLabels(linkTypes, this.options.prepareLabels);
		return linkTypes;
	}
	async linkTypes() {
		const { defaultPrefix, schemaLabelProperty, linkTypesQuery, linkTypesPattern } = this.settings;
		if (!linkTypesQuery) return [];
		const query = defaultPrefix + resolveTemplate(linkTypesQuery, {
			linkTypesPattern,
			schemaLabelProperty
		});
		const linkTypes = getLinkTypes(await this.executeSparqlQuery(query));
		if (this.options.prepareLabels) await attachLabels(linkTypes, this.options.prepareLabels);
		return linkTypes;
	}
	async elementInfo(params) {
		const nonBlankResources = params.elementIds.filter((id) => !isEncodedBlank(id));
		const blankNodeResponse = this.options.acceptBlankNodes ? elementInfo(params.elementIds) : void 0;
		let triples;
		if (nonBlankResources.length > 0) {
			const ids = nonBlankResources.map(escapeIri).map((id) => ` (${id})`).join(" ");
			const { defaultPrefix, dataLabelProperty, elementInfoQuery } = this.settings;
			const query = defaultPrefix + resolveTemplate(elementInfoQuery, {
				ids,
				dataLabelProperty,
				propertyConfigurations: this.formatPropertyInfo()
			});
			triples = await this.executeSparqlConstruct(query);
		} else triples = [];
		const types = this.queryManyElementTypes(this.settings.propertyConfigurations.length > 0 ? params.elementIds : []);
		const elementModels = getElementsInfo(prependAdditionalBindings(triplesToElementBinding(triples), blankNodeResponse), await types, this.propertyByPredicate, this.openWorldProperties);
		if (this.options.prepareLabels) await attachLabels(objectValues(elementModels), this.options.prepareLabels);
		if (this.options.prepareImages) await prepareElementImages(this.options.prepareImages, elementModels);
		else if (this.options.imagePropertyUris && this.options.imagePropertyUris.length) await this.attachImages(elementModels, this.options.imagePropertyUris);
		return elementModels;
	}
	async attachImages(elementsInfo, types) {
		const ids = Object.keys(elementsInfo).filter((id) => !isEncodedBlank(id)).map(escapeIri).map((id) => ` ( ${id} )`).join(" ");
		const typesString = types.map(escapeIri).map((id) => ` ( ${id} )`).join(" ");
		const query = this.settings.defaultPrefix + `
            SELECT ?inst ?linkType ?image
            WHERE {{
                VALUES (?inst) {${ids}}
                VALUES (?linkType) {${typesString}}
                ${this.settings.imageQueryPattern}
            }}
        `;
		try {
			enrichElementsWithImages(await this.executeSparqlQuery(query), elementsInfo);
		} catch (err) {
			console.error(err);
		}
	}
	async linksInfo(params) {
		const nonBlankResources = params.elementIds.filter((id) => !isEncodedBlank(id));
		const blankNodeResponse = this.options.acceptBlankNodes ? linksInfo(params.elementIds) : void 0;
		const linkConfigurations = this.formatLinkLinks();
		let bindings;
		let types;
		if (nonBlankResources.length > 0) {
			const ids = nonBlankResources.map(escapeIri).map((id) => ` ( ${id} )`).join(" ");
			const linksInfoQuery = this.settings.defaultPrefix + resolveTemplate(this.settings.linksInfoQuery, {
				ids,
				linkConfigurations
			});
			bindings = this.executeSparqlQuery(linksInfoQuery);
			types = this.queryManyElementTypes(params.elementIds);
		} else {
			bindings = Promise.resolve({
				head: { vars: [] },
				results: { bindings: [] }
			});
			types = this.queryManyElementTypes([]);
		}
		return getLinksInfo(prependAdditionalBindings(await bindings, blankNodeResponse), await types, this.linkByPredicate, this.openWorldLinks);
	}
	async linkTypesOf(params) {
		if (this.options.acceptBlankNodes && isEncodedBlank(params.elementId)) return Promise.resolve(getLinksTypesOf(linkTypesOf(params)));
		const { defaultPrefix, linkTypesOfQuery, linkTypesStatisticsQuery, filterTypePattern } = this.settings;
		const elementIri = escapeIri(params.elementId);
		const forAll = this.formatLinkUnion(params.elementId, void 0, void 0, "?outObject", "?inObject", false);
		if (forAll.usePredicatePart) {
			forAll.unionParts.push(`{ ${elementIri} ?link ?outObject }`);
			forAll.unionParts.push(`{ ?inObject ?link ${elementIri} }`);
		}
		const query = defaultPrefix + resolveTemplate(linkTypesOfQuery, {
			elementIri,
			linkConfigurations: forAll.unionParts.join("\nUNION\n")
		});
		const linkTypeIds = getLinksTypeIds(await this.executeSparqlQuery(query), this.linkByPredicate, this.openWorldLinks);
		const navigateElementFilterOut = this.options.acceptBlankNodes ? `FILTER (IsIri(?outObject) || IsBlank(?outObject))` : `FILTER IsIri(?outObject)`;
		const navigateElementFilterIn = this.options.acceptBlankNodes ? `FILTER (IsIri(?inObject) || IsBlank(?inObject))` : `FILTER IsIri(?inObject)`;
		const foundLinkStats = [];
		await Promise.all(linkTypeIds.map(async (linkId) => {
			const linkConfig = this.linkById.get(linkId);
			let linkConfigurationOut;
			let linkConfigurationIn;
			if (!linkConfig || isDirectLink(linkConfig)) {
				const predicate = escapeIri(linkConfig && isDirectLink(linkConfig) ? linkConfig.path : linkId);
				linkConfigurationOut = `${elementIri} ${predicate} ?outObject`;
				linkConfigurationIn = `?inObject ${predicate} ${elementIri}`;
			} else {
				linkConfigurationOut = this.formatLinkPath(linkConfig.path, elementIri, "?outObject");
				linkConfigurationIn = this.formatLinkPath(linkConfig.path, "?inObject", elementIri);
			}
			if (linkConfig && linkConfig.domain?.length > 0) {
				const commaSeparatedDomains = linkConfig.domain.map(escapeIri).join(", ");
				const restrictionOut = filterTypePattern.replace(/[?$]inst\b/g, elementIri);
				const restrictionIn = filterTypePattern.replace(/[?$]inst\b/g, "?inObject");
				linkConfigurationOut += ` { ${restrictionOut} FILTER(?class IN (${commaSeparatedDomains})) }`;
				linkConfigurationIn += ` { ${restrictionIn} FILTER(?class IN (${commaSeparatedDomains})) }`;
			}
			const statsQuery = defaultPrefix + resolveTemplate(linkTypesStatisticsQuery, {
				linkId: escapeIri(linkId),
				elementIri,
				linkConfigurationOut,
				linkConfigurationIn,
				navigateElementFilterOut,
				navigateElementFilterIn
			});
			const linkStats = getLinkStatistics(await this.executeSparqlQuery(statsQuery));
			if (linkStats) foundLinkStats.push(linkStats);
		}));
		return foundLinkStats;
	}
	linkElements(params) {
		return this.filter({
			refElementId: params.elementId,
			refElementLinkId: params.linkId,
			linkDirection: params.direction,
			limit: params.limit,
			offset: params.offset,
			languageCode: ""
		});
	}
	async filter(baseParams) {
		const params = { ...baseParams };
		if (params.limit === void 0) params.limit = 100;
		const types = this.querySingleElementTypes(params.refElementId && this.settings.linkConfigurations.length > 0 ? params.refElementId : void 0);
		const blankFiltration = this.options.acceptBlankNodes ? filter(params) : void 0;
		if (blankFiltration && blankFiltration.results.bindings.length > 0) return getFilteredData(blankFiltration, await types, this.linkByPredicate, this.openWorldLinks);
		const filterQuery = this.createFilterQuery(params);
		const bindings = await this.executeSparqlQuery(filterQuery);
		let bindingsWithBlanks;
		if (this.options.acceptBlankNodes) bindingsWithBlanks = await updateFilterResults(bindings, (blankQuery) => this.executeSparqlQuery(blankQuery), this.settings);
		else bindingsWithBlanks = bindings;
		const elementModels = getFilteredData(bindingsWithBlanks, await types, this.linkByPredicate, this.openWorldLinks);
		if (this.options.prepareLabels) await attachLabels(objectValues(elementModels), this.options.prepareLabels);
		return elementModels;
	}
	createFilterQuery(params) {
		if (!params.refElementId && params.refElementLinkId) throw new Error("Cannot execute refElementLink filter without refElement");
		let outerProjection = "?inst ?class ?label ?blankType";
		let innerProjection = "?inst";
		let refQueryPart = "";
		let refQueryTypes = "";
		if (params.refElementId) {
			outerProjection += " ?link ?direction";
			innerProjection += " ?link ?direction";
			refQueryPart = this.createRefQueryPart({
				elementId: params.refElementId,
				linkId: params.refElementLinkId,
				direction: params.linkDirection
			});
			if (this.settings.linkConfigurations.length > 0) {
				outerProjection += " ?classAll";
				refQueryTypes = this.settings.filterTypePattern.replace(/[?$]class\b/g, "?classAll");
			}
		}
		let elementTypePart = "";
		if (params.elementTypeId) {
			const elementTypeIri = escapeIri(params.elementTypeId);
			elementTypePart = this.settings.filterTypePattern.replace(/[?$]class\b/g, elementTypeIri);
			elementTypePart += " .";
		}
		const { defaultPrefix, fullTextSearch, dataLabelProperty } = this.settings;
		let textSearchPart = "";
		if (params.text) {
			innerProjection += " ?score";
			if (this.settings.fullTextSearch.extractLabel) textSearchPart += sparqlExtractLabel("?inst", "?extractedLabel");
			if (fullTextSearch.queryPatternPerWord) textSearchPart = params.text.trim().split(/\s+/).filter(Boolean).map((word) => resolveTemplate(fullTextSearch.queryPatternPerWord, {
				word: escapeSparqlStringLiteral(word),
				dataLabelProperty
			})).join("\n") + "\nBIND(0 as ?score)";
			else textSearchPart = resolveTemplate(fullTextSearch.queryPattern, {
				text: params.text,
				dataLabelProperty
			});
		}
		const blankNodes = this.options.acceptBlankNodes;
		if (blankNodes) outerProjection += ` ${BLANK_NODE_QUERY_PARAMETERS}`;
		return `${defaultPrefix}
            ${fullTextSearch.prefix}

        SELECT ${outerProjection}
        WHERE {
            {
                SELECT DISTINCT ${innerProjection} WHERE {
                    ${fullTextSearch.elementFirst ? "" : textSearchPart}
                    ${elementTypePart}
                    ${refQueryPart}
                    ${fullTextSearch.elementFirst ? textSearchPart : ""}
                    ${this.settings.filterAdditionalRestriction}
                }
                ${textSearchPart ? "ORDER BY DESC(?score)" : ""}
                LIMIT ${params.limit} OFFSET ${params.offset}
            }
            ${refQueryTypes}
            ${resolveTemplate(this.settings.filterElementInfoPattern, { dataLabelProperty })}
            ${blankNodes ? BLANK_NODE_QUERY : ""}
        } ${textSearchPart ? "ORDER BY DESC(?score)" : ""}
        `;
	}
	executeSparqlQuery(query) {
		const method = this.options.queryMethod ? this.options.queryMethod : 1;
		return executeSparqlQuery(this.options.endpointUrl, query, method, this.options.queryFunction);
	}
	executeSparqlConstruct(query) {
		const method = this.options.queryMethod ? this.options.queryMethod : 1;
		return executeSparqlConstruct(this.options.endpointUrl, query, method, this.options.queryFunction);
	}
	createRefQueryPart(params) {
		const { elementId, linkId, direction } = params;
		const { unionParts, usePredicatePart } = this.formatLinkUnion(elementId, linkId, direction, "?inst", "?inst", true);
		if (usePredicatePart) {
			const refElementIRI = escapeIri(params.elementId);
			let refLinkType;
			if (linkId) {
				const link = this.linkById.get(linkId);
				refLinkType = link && isDirectLink(link) ? escapeIri(link.path) : escapeIri(linkId);
			}
			const linkPattern = refLinkType || "?link";
			const bindType = refLinkType ? `BIND(${refLinkType} as ?link)` : "";
			const blankFilter = this.options.acceptBlankNodes ? "FILTER(isIri(?inst) || isBlank(?inst))" : "FILTER(isIri(?inst))";
			if (!direction || direction === "out") unionParts.push(`{ ${refElementIRI} ${linkPattern} ?inst BIND("out" as ?direction) ${bindType} ${blankFilter} }`);
			if (!direction || direction === "in") unionParts.push(`{ ?inst ${linkPattern} ${refElementIRI} BIND("in" as ?direction) ${bindType} ${blankFilter} }`);
		}
		let resultPattern = unionParts.length === 0 ? "FILTER(false)" : unionParts.join(`\nUNION\n`);
		if (!linkId && this.settings.filterRefElementLinkPattern.length > 0) resultPattern += `\n${this.settings.filterRefElementLinkPattern}`;
		return resultPattern;
	}
	formatLinkUnion(refElementIri, linkIri, direction, outElementVar, inElementVar, bindDirection) {
		const { linkConfigurations } = this.settings;
		const fixedIri = escapeIri(refElementIri);
		const unionParts = [];
		let hasDirectLink = false;
		for (const link of linkConfigurations) {
			if (linkIri && link.id !== linkIri) continue;
			if (isDirectLink(link)) hasDirectLink = true;
			else {
				const linkType = escapeIri(link.id);
				if (!direction || direction === "out") {
					const path = this.formatLinkPath(link.path, fixedIri, outElementVar);
					const boundedDirection = bindDirection ? `BIND("out" as ?direction) ` : "";
					unionParts.push(`{ ${path} BIND(${linkType} as ?link) ${boundedDirection}}`);
				}
				if (!direction || direction === "in") {
					const path = this.formatLinkPath(link.path, inElementVar, fixedIri);
					const boundedDirection = bindDirection ? `BIND("in" as ?direction) ` : "";
					unionParts.push(`{ ${path} BIND(${linkType} as ?link) ${boundedDirection}}`);
				}
			}
		}
		return {
			unionParts,
			usePredicatePart: this.openWorldLinks || hasDirectLink
		};
	}
	formatLinkLinks() {
		const unionParts = [];
		let hasDirectLink = false;
		for (const link of this.settings.linkConfigurations) if (isDirectLink(link)) hasDirectLink = true;
		else {
			const linkType = escapeIri(link.id);
			unionParts.push(`{ ${this.formatLinkPath(link.path, "?source", "?target")} BIND(${linkType} as ?type) }`);
		}
		if (this.openWorldLinks || hasDirectLink) unionParts.push(`{ ?source ?type ?target }`);
		return unionParts.join("\nUNION\n");
	}
	formatLinkPath(path, source, target) {
		return path.replace(/[?$]source\b/g, source).replace(/[?$]target\b/g, target);
	}
	formatPropertyInfo() {
		const unionParts = [];
		let hasDirectProperty = false;
		for (const property of this.settings.propertyConfigurations) if (isDirectProperty(property)) hasDirectProperty = true;
		else {
			const propType = escapeIri(property.id);
			const formatted = this.formatPropertyPath(property.path, "?inst", "?propValue");
			unionParts.push(`{ ${formatted} BIND(${propType} as ?propType) }`);
		}
		if (this.openWorldProperties || hasDirectProperty) unionParts.push(`{ ?inst ?propType ?propValue }`);
		return unionParts.join("\nUNION\n");
	}
	formatPropertyPath(path, subject, value) {
		return path.replace(/[?$]inst\b/g, subject).replace(/[?$]value\b/g, value);
	}
	async querySingleElementTypes(element) {
		return (await this.queryManyElementTypes(element ? [element] : [])).get(element);
	}
	async queryManyElementTypes(elements) {
		if (elements.length === 0) return /* @__PURE__ */ new Map();
		const { filterTypePattern } = this.settings;
		const ids = elements.filter((iri) => !isEncodedBlank(iri)).map((iri) => `(${escapeIri(iri)})`).join(" ");
		const query = resolveTemplate(this.settings.defaultPrefix + `SELECT ?inst ?class { VALUES(?inst) { \${ids} } \${filterTypePattern} }`, {
			ids,
			filterTypePattern
		});
		let response = await this.executeSparqlQuery(query);
		if (this.options.acceptBlankNodes && elements.find(isEncodedBlank)) {
			const blankResponse = getElementTypes$1(elements);
			response = prependAdditionalBindings(response, blankResponse);
		}
		return getElementTypes(response);
	}
};
async function attachLabels(items, fetchLabels) {
	const resources = /* @__PURE__ */ new Set();
	for (const item of items) {
		if (isEncodedBlank(item.id)) continue;
		resources.add(item.id);
	}
	const labels = await fetchLabels(resources);
	for (const item of items) if (labels.has(item.id)) item.label = { values: labels.get(item.id) };
}
function prepareElementImages(fetchImages, elementsInfo) {
	return fetchImages(elementsInfo).then((images) => {
		for (const iri in images) if (Object.prototype.hasOwnProperty.call(images, iri) && elementsInfo[iri]) elementsInfo[iri].image = images[iri];
	});
}
function resolveTemplate(template, values) {
	let result = template;
	for (const replaceKey in values) {
		if (!Object.prototype.hasOwnProperty.call(values, replaceKey)) continue;
		const replaceValue = values[replaceKey];
		if (replaceValue) result = result.replace(new RegExp("\\${" + replaceKey + "}", "g"), replaceValue);
	}
	return result;
}
function executeSparqlQuery(endpoint, query, method, queryFunction) {
	let internalQuery;
	if (method === 1) internalQuery = queryFunction({
		url: appendQueryParams(endpoint, { query }),
		headers: { Accept: "application/sparql-results+json" },
		method: "GET"
	});
	else internalQuery = queryFunction({
		url: endpoint,
		body: query,
		headers: {
			Accept: "application/sparql-results+json",
			"Content-Type": "application/sparql-query; charset=UTF-8"
		},
		method: "POST"
	});
	return internalQuery.then((response) => {
		if (response.ok) return response.json();
		else {
			const error = new Error(response.statusText);
			error.response = response;
			throw error;
		}
	});
}
function executeSparqlConstruct(endpoint, query, method, queryFunction) {
	let internalQuery;
	if (method === 1) internalQuery = queryFunction({
		url: appendQueryParams(endpoint, { query }),
		headers: { Accept: "text/turtle" },
		method: "GET"
	});
	else internalQuery = queryFunction({
		url: endpoint,
		body: query,
		headers: {
			Accept: "text/turtle",
			"Content-Type": "application/sparql-query; charset=UTF-8"
		},
		method: "POST"
	});
	return internalQuery.then((response) => {
		if (response.ok) return response.text();
		else {
			const error = new Error(response.statusText);
			error.response = response;
			throw error;
		}
	}).then(parseTurtleText);
}
function appendQueryParams(endpoint, queryParams = {}) {
	return endpoint + ((endpoint.indexOf("?") < 0 ? "?" : "&") + Object.keys(queryParams).map((key) => `${key}=${encodeURIComponent(queryParams[key])}`).join("&"));
}
function queryInternal(params) {
	return fetch(params.url, {
		method: params.method,
		body: params.body,
		credentials: "same-origin",
		mode: "cors",
		cache: "default",
		headers: params.headers
	});
}
function sparqlExtractLabel(subject, label) {
	return `
        BIND ( str( ${subject} ) as ?uriStr)
        BIND ( strafter(?uriStr, "#") as ?label3)
        BIND ( strafter(strafter(?uriStr, "//"), "/") as ?label6)
        BIND ( strafter(?label6, "/") as ?label5)
        BIND ( strafter(?label5, "/") as ?label4)
        BIND (if (?label3 != "", ?label3,
            if (?label4 != "", ?label4,
            if (?label5 != "", ?label5, ?label6))) as ${label})
    `;
}
function escapeIri(iri) {
	if (typeof iri !== "string") throw new Error(`Cannot escape IRI of type "${typeof iri}"`);
	return `<${iri}>`;
}
/** Escapes a value for embedding in a double-quoted SPARQL string literal. */
function escapeSparqlStringLiteral(value) {
	return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
}
//#endregion
//#region src/graph-explorer/data/composite/mergeUtils.ts
var DATA_PROVIDER_PROPERTY = "http://graph-explorer.org/property/DataProvider";
function mergeClassTree(composite) {
	const lists = composite.filter((r) => r.response).map(({ useInStats, response }) => ({
		useInStats,
		classes: classTreeToArray(response)
	}));
	const dictionary = {};
	const topLevelModels = {};
	const childrenMap = {};
	for (const { useInStats, classes } of lists) for (const model of classes) {
		const childrenIds = childrenMap[model.id] || [];
		model.children.map((ch) => ch.id).forEach((id) => {
			if (childrenIds.indexOf(id) === -1) childrenIds.push(id);
		});
		model.children = [];
		if (!useInStats) delete model.count;
		if (!dictionary[model.id]) {
			topLevelModels[model.id] = model;
			dictionary[model.id] = model;
			childrenMap[model.id] = childrenIds;
		} else {
			topLevelModels[model.id] = mergeClassModel(dictionary[model.id], model);
			dictionary[model.id] = topLevelModels[model.id];
		}
	}
	const models = Object.keys(dictionary).map((key) => dictionary[key]);
	for (const m of models) m.children = (childrenMap[m.id] || []).map((id) => {
		delete topLevelModels[id];
		return dictionary[id];
	});
	return Object.keys(topLevelModels).map((key) => topLevelModels[key]);
}
function mergePropertyInfo(response) {
	const result = {};
	const props = response.filter((r) => r.response).map((r) => r.response);
	for (const model of props) {
		const keys = Object.keys(model);
		for (const key of keys) {
			const prop = model[key];
			if (!result[key]) result[key] = prop;
			else result[key].label = mergeLabels(result[key].label, prop.label);
		}
	}
	return result;
}
function mergeClassInfo(response) {
	const dictionaries = response.filter((r) => r.response).map((r) => r.response);
	const dictionary = {};
	for (const models of dictionaries) for (const model of models) if (!dictionary[model.id]) dictionary[model.id] = model;
	else dictionary[model.id] = mergeClassModel(dictionary[model.id], model);
	return Object.keys(dictionary).map((key) => dictionary[key]);
}
function mergeLinkTypesInfo(response) {
	const lists = response.filter((r) => r.response).map((r) => r.response);
	const mergeLinkType = (a, b) => {
		return {
			id: a.id,
			label: mergeLabels(a.label, b.label),
			count: a.count + b.count
		};
	};
	const dictionary = {};
	for (const linkTypes of lists) for (const linkType of linkTypes) if (!dictionary[linkType.id]) dictionary[linkType.id] = linkType;
	else dictionary[linkType.id] = mergeLinkType(dictionary[linkType.id], linkType);
	return Object.keys(dictionary).map((key) => dictionary[key]);
}
function mergeLinkTypes(response) {
	return mergeLinkTypesInfo(response);
}
function mergeElementInfo(response) {
	const mergeElementModels = (a, b) => {
		const types = a.types;
		for (const t of b.types) if (types.indexOf(t) === -1) types.push(t);
		const sources = [];
		for (const s of a.sources) if (sources.indexOf(s) === -1) sources.push(s);
		for (const s of b.sources) if (sources.indexOf(s) === -1) sources.push(s);
		return {
			id: a.id,
			label: mergeLabels(a.label, b.label),
			types,
			image: a.image || b.image,
			properties: mergeProperties(a.properties, b.properties),
			sources
		};
	};
	const dictionary = {};
	for (const resp of response) {
		if (!resp.response) continue;
		const list = Object.keys(resp.response).map((k) => resp.response[k]);
		for (const em of list) {
			em.sources = [resp.dataSourceName];
			em.properties[DATA_PROVIDER_PROPERTY] = {
				type: "string",
				values: [{
					value: resp.dataSourceName,
					language: ""
				}]
			};
			if (!dictionary[em.id]) dictionary[em.id] = em;
			else dictionary[em.id] = mergeElementModels(dictionary[em.id], em);
		}
	}
	return dictionary;
}
function mergeProperties(a, b) {
	const aLists = Object.keys(a);
	const bLists = Object.keys(b);
	const result = {};
	function createIdForProperty(baseId) {
		let counter = 1;
		while (result[baseId + "_" + counter]) counter++;
		return baseId + "_" + counter;
	}
	for (const pKey of aLists) {
		const prop = a[pKey];
		if (!result[pKey]) result[pKey] = prop;
		else result[createIdForProperty(pKey)] = prop;
	}
	for (const pKey of bLists) {
		const prop = b[pKey];
		if (!result[pKey]) result[pKey] = prop;
		else result[createIdForProperty(pKey)] = prop;
	}
	return result;
}
function mergeLinksInfo(response) {
	const lists = response.filter((r) => r.response).map((r) => r.response);
	const resultInfo = [];
	function compareLinksInfo(a, b) {
		return a.sourceId === b.sourceId && a.targetId === b.targetId && a.linkTypeId === b.linkTypeId;
	}
	for (const linkInfo of lists) for (const linkModel of linkInfo) if (!resultInfo.some((l) => compareLinksInfo(l, linkModel))) resultInfo.push(linkModel);
	return resultInfo;
}
function mergeLinkTypesOf(response) {
	const lists = response.filter((r) => r.response).map((r) => r.response);
	const dictionary = {};
	const merge = (a, b) => {
		return {
			id: a.id,
			inCount: a.inCount + b.inCount,
			outCount: a.outCount + b.outCount
		};
	};
	for (const linkCount of lists) for (const lCount of linkCount) if (!dictionary[lCount.id]) dictionary[lCount.id] = lCount;
	else dictionary[lCount.id] = merge(lCount, dictionary[lCount.id]);
	return Object.keys(dictionary).map((key) => dictionary[key]);
}
function mergeLinkElements(response) {
	return mergeElementInfo(response);
}
function mergeFilter(response) {
	return mergeElementInfo(response);
}
function classTreeToArray(models) {
	let resultArray = models;
	function getDescendants(model) {
		let descendants = model.children || [];
		for (const descendant of descendants) {
			const nextGeneration = getDescendants(descendant);
			descendants = descendants.concat(nextGeneration);
		}
		return descendants;
	}
	for (const model of models) {
		const descendants = getDescendants(model);
		resultArray = resultArray.concat(descendants);
	}
	return resultArray;
}
function mergeLabels(a, b) {
	function compareLabels(l1, l2) {
		return l1.language === l2.language && l1.value === l2.value;
	}
	const mergedValuesList = a.values;
	for (const locStr of b.values) if (!mergedValuesList.some((l) => compareLabels(l, locStr))) mergedValuesList.push(locStr);
	return { values: mergedValuesList };
}
function mergeCounts(a, b) {
	if (a === void 0 && b === void 0) return;
	return (a || 0) + (b || 0);
}
function mergeClassModel(a, b) {
	const childrenDictionary = {};
	for (const child of a.children.concat(b.children)) if (!childrenDictionary[child.id]) childrenDictionary[child.id] = child;
	return {
		id: a.id,
		label: mergeLabels(a.label, b.label),
		count: mergeCounts(a.count, b.count),
		children: Object.keys(childrenDictionary).map((key) => childrenDictionary[key])
	};
}
//#endregion
//#region src/graph-explorer/data/composite/composite.ts
function isDefinition(dp) {
	const definition = dp;
	return definition.name !== void 0 && definition.dataProvider !== void 0;
}
var CompositeDataProvider = class {
	constructor(dataProviders, params) {
		this.mergeMode = "fetchAll";
		let dpCounter = 1;
		this.dataProviders = dataProviders.map((dp) => {
			if (isDefinition(dp)) return dp;
			else return {
				name: "dataProvider_" + dpCounter++,
				dataProvider: dp
			};
		});
		if (params && params.mergeMode) this.mergeMode = params.mergeMode;
	}
	classTree() {
		return this.fetchSequentially("classTree", mergeClassTree, void 0);
	}
	propertyInfo(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("propertyInfo", mergePropertyInfo, params);
		else {
			let propertyIds = params.propertyIds;
			return this.queueProcessResults((previousResult, dp) => {
				propertyIds = propertyIds.filter((id) => !previousResult || !previousResult[id]);
				return propertyIds.length > 0 ? dp.dataProvider.propertyInfo({ propertyIds }) : void 0;
			}).then(mergePropertyInfo);
		}
	}
	classInfo(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("classInfo", mergeClassInfo, params);
		else {
			let classIds = params.classIds;
			return this.queueProcessResults((previousResult, dp) => {
				classIds = classIds.filter((id) => !previousResult || previousResult.map((cm) => cm.id).indexOf(id) === -1);
				return classIds.length > 0 ? dp.dataProvider.classInfo({ classIds }) : void 0;
			}).then(mergeClassInfo);
		}
	}
	linkTypesInfo(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("linkTypesInfo", mergeLinkTypesInfo, params);
		else {
			let linkTypeIds = params.linkTypeIds;
			return this.queueProcessResults((previousResult, dp) => {
				linkTypeIds = linkTypeIds.filter((id) => !previousResult || previousResult.map((lt) => lt.id).indexOf(id) === -1);
				return linkTypeIds.length > 0 ? dp.dataProvider.linkTypesInfo({ linkTypeIds }) : void 0;
			}).then(mergeLinkTypesInfo);
		}
	}
	linkTypes() {
		return this.fetchSequentially("linkTypes", mergeLinkTypes, void 0);
	}
	elementInfo(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("elementInfo", mergeElementInfo, params);
		else {
			let elementIds = params.elementIds;
			return this.queueProcessResults((previousResult, dp) => {
				elementIds = elementIds.filter((id) => !previousResult || !previousResult[id]);
				return elementIds.length > 0 ? dp.dataProvider.elementInfo({ elementIds }) : void 0;
			}).then(mergeElementInfo);
		}
	}
	linksInfo(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("linksInfo", mergeLinksInfo, params);
		else {
			let elementIds = params.elementIds;
			return this.queueProcessResults((previousResult, dp) => {
				elementIds = elementIds.filter((id) => {
					if (previousResult) {
						for (const linkModel of previousResult) if (linkModel.sourceId === id) return false;
					}
					return true;
				});
				return elementIds.length > 0 ? dp.dataProvider.linksInfo({
					elementIds,
					linkTypeIds: params.linkTypeIds
				}) : void 0;
			}).then(mergeLinksInfo);
		}
	}
	linkTypesOf(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("linkTypesOf", mergeLinkTypesOf, params);
		else return this.queueProcessResults((previousResult, dp) => {
			if (!previousResult || previousResult && previousResult.length === 0) return dp.dataProvider.linkTypesOf(params);
			else return;
		}).then(mergeLinkTypesOf);
	}
	linkElements(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("linkElements", mergeLinkElements, params);
		else return this.queueProcessResults((previousResult, dp) => {
			if (!previousResult || previousResult && Object.keys(previousResult).length === 0) return dp.dataProvider.linkElements(params);
			else return;
		}).then(mergeLinkElements);
	}
	filter(params) {
		if (this.mergeMode === "fetchAll") return this.fetchSequentially("filter", mergeFilter, params);
		else return this.queueProcessResults((previousResult, dp) => {
			if (!previousResult || previousResult && Object.keys(previousResult).length === 0) return dp.dataProvider.filter(params);
			else return;
		}).then(mergeFilter);
	}
	processResults(responsePromise, dpName, useProviderInStats) {
		return responsePromise.then((response) => ({
			dataSourceName: dpName,
			useInStats: useProviderInStats,
			response
		})).catch((error) => {
			console.error(error);
			return {
				dataSourceName: dpName,
				useInStats: useProviderInStats,
				response: void 0
			};
		});
	}
	queueProcessResults(callBack) {
		let counter = 0;
		const responseList = [];
		const recursiveCall = (result) => {
			if (this.dataProviders.length > counter) {
				const dp = this.dataProviders[counter++];
				const callBackResult = callBack(result, dp);
				if (!callBackResult) return Promise.resolve(responseList);
				return callBackResult.then((newResult) => {
					responseList.push({
						dataSourceName: dp.name,
						response: newResult
					});
					return recursiveCall(newResult);
				}).catch((error) => {
					console.error(error);
					return recursiveCall(result);
				});
			} else return Promise.resolve(responseList);
		};
		return recursiveCall();
	}
	fetchSequentially(functionName, mergeFunction, params) {
		const resultPromises = this.dataProviders.map((dp) => {
			const providerMethod = dp.dataProvider[functionName];
			return this.processResults(providerMethod.call(dp.dataProvider, params), dp.name, dp.useInStats);
		});
		return Promise.all(resultPromises).then(mergeFunction);
	}
};
//#endregion
//#region src/graph-explorer/editor/serializedDiagram.ts
var serializedCellProperties = [
	"id",
	"type",
	"size",
	"angle",
	"isExpanded",
	"position",
	"iri",
	"group",
	"typeId",
	"source",
	"target",
	"vertices"
];
function emptyDiagram() {
	return {
		"@context": DIAGRAM_CONTEXT_URL_V1,
		"@type": "Diagram",
		layoutData: emptyLayoutData(),
		linkTypeOptions: []
	};
}
function emptyLayoutData() {
	return {
		"@type": "Layout",
		elements: [],
		links: []
	};
}
function convertToSerializedDiagram(params) {
	const elements = [];
	const links = [];
	for (const cell of params.layoutData.cells) {
		const newCell = pick(cell, serializedCellProperties);
		if (newCell.type === "GraphExplorer.Element" || newCell.type === "element") newCell.type = "Element";
		if (newCell.type === "link") newCell.type = "Link";
		if (!newCell.iri) newCell.iri = newCell.id;
		newCell["@id"] = newCell.id;
		delete newCell.id;
		newCell["@type"] = newCell.type;
		delete newCell.type;
		switch (newCell["@type"]) {
			case "Element":
				elements.push(newCell);
				break;
			case "Link":
				newCell.source["@id"] = newCell.source.id;
				delete newCell.source.id;
				newCell.target["@id"] = newCell.target.id;
				delete newCell.target.id;
				newCell.property = newCell.typeId;
				delete newCell.typeId;
				links.push(newCell);
				break;
		}
	}
	return {
		...emptyDiagram(),
		layoutData: {
			"@type": "Layout",
			elements,
			links
		},
		linkTypeOptions: params.linkTypeOptions
	};
}
function makeSerializedDiagram(params) {
	const diagram = {
		...emptyDiagram(),
		linkTypeOptions: params.linkTypeOptions
	};
	if (params.layoutData) diagram.layoutData = params.layoutData;
	return diagram;
}
function makeLayoutData(modelElements, modelLinks) {
	return {
		"@type": "Layout",
		elements: modelElements.map((element) => ({
			"@type": "Element",
			"@id": element.id,
			iri: element.iri,
			position: element.position,
			size: element.size,
			isExpanded: element.isExpanded,
			group: element.group,
			elementState: element.elementState
		})),
		links: modelLinks.map((link) => ({
			"@type": "Link",
			"@id": link.id,
			property: link.typeId,
			source: { "@id": link.sourceId },
			target: { "@id": link.targetId },
			vertices: [...link.vertices],
			linkState: link.linkState
		}))
	};
}
//#endregion
//#region src/graph-explorer/viewUtils/layout.ts
function groupForceLayout(params) {
	new cola.Layout().nodes(params.nodes).links(params.links).avoidOverlaps(params.avoidOvelaps).convergenceThreshold(1e-9).jaccardLinkLengths(params.preferredLinkLength).handleDisconnected(true).start(30, 0, 10, void 0, false);
}
function groupRemoveOverlaps(nodes) {
	const nodeRectangles = [];
	for (const node of nodes) nodeRectangles.push(new cola.Rectangle(node.x, node.x + node.width, node.y, node.y + node.height));
	cola.removeOverlaps(nodeRectangles);
	for (let i = 0; i < nodeRectangles.length; i++) {
		const node = nodes[i];
		const rectangle = nodeRectangles[i];
		node.x = rectangle.x;
		node.y = rectangle.y;
	}
}
function translateToPositiveQuadrant(positions, offset) {
	let minX = Infinity, minY = Infinity;
	positions.forEach((position) => {
		minX = Math.min(minX, position.x);
		minY = Math.min(minY, position.y);
	});
	const { x, y } = offset;
	positions.forEach((position, key) => {
		positions.set(key, {
			x: position.x - minX + x,
			y: position.y - minY + y
		});
	});
}
function uniformGrid(params) {
	return (cellIndex) => {
		const row = Math.floor(cellIndex / params.rows);
		return {
			x: (cellIndex - row * params.rows) * params.cellSize.x,
			y: row * params.cellSize.y,
			width: params.cellSize.x,
			height: params.cellSize.y
		};
	};
}
function padded(nodes, padding, transform) {
	if (padding) for (const node of nodes) {
		node.x -= padding.x;
		node.y -= padding.y;
		node.width += 2 * padding.x;
		node.height += 2 * padding.y;
	}
	transform();
	if (padding) for (const node of nodes) {
		node.x += padding.x;
		node.y += padding.y;
		node.width -= 2 * padding.x;
		node.height -= 2 * padding.y;
	}
}
function biasFreePadded(nodes, padding, transform) {
	const nodeSizeMap = /* @__PURE__ */ new Map();
	const possibleCompression = {
		x: Infinity,
		y: Infinity
	};
	for (const node of nodes) {
		nodeSizeMap.set(node.id, {
			width: node.width,
			height: node.height
		});
		const maxSide = Math.max(node.width, node.height);
		const compressionX = node.width ? maxSide / node.width : 1;
		const compressionY = node.height ? maxSide / node.height : 1;
		possibleCompression.x = Math.min(1 + (compressionX - 1), possibleCompression.x);
		possibleCompression.y = Math.min(1 + (compressionY - 1), possibleCompression.y);
		node.height = maxSide;
		node.width = maxSide;
	}
	padded(nodes, padding, () => transform());
	const fittingBox = getContentFittingBoxForLayout(nodes);
	for (const node of nodes) {
		const size = nodeSizeMap.get(node.id);
		node.x = (node.x - fittingBox.x) / possibleCompression.x + fittingBox.x;
		node.y = (node.y - fittingBox.y) / possibleCompression.y + fittingBox.y;
		node.height = size.height;
		node.width = size.width;
	}
}
function calculateLayout(params) {
	const grouping = computeGrouping(params.model.elements);
	const { layoutFunction, model, fixedElements, selectedElements } = params;
	if (selectedElements && selectedElements.size <= 1) return {
		positions: /* @__PURE__ */ new Map(),
		nestedLayouts: [],
		keepAveragePosition: false
	};
	return internalRecursion(params.group);
	function internalRecursion(group) {
		const elementsToProcess = group ? grouping.get(group) : model.elements.filter((el) => el.group === void 0);
		const elements = selectedElements ? elementsToProcess.filter((el) => selectedElements.has(el)) : elementsToProcess;
		const nestedLayouts = [];
		for (const element of elements) if (grouping.has(element.id)) nestedLayouts.push(internalRecursion(element.id));
		const nodes = [];
		const nodeById = {};
		for (const element of elements) {
			const { x, y, width, height } = boundsOf(element);
			const node = {
				id: element.id,
				x,
				y,
				width,
				height,
				fixed: fixedElements && fixedElements.has(element) ? 1 : 0
			};
			nodeById[element.id] = node;
			nodes.push(node);
		}
		const links = [];
		for (const link of model.links) {
			if (!model.isSourceAndTargetVisible(link)) continue;
			const source = model.sourceOf(link);
			const target = model.targetOf(link);
			const sourceNode = nodeById[source.id];
			const targetNode = nodeById[target.id];
			if (sourceNode && targetNode) links.push({
				source: sourceNode,
				target: targetNode
			});
		}
		layoutFunction(nodes, links, group);
		const positions = /* @__PURE__ */ new Map();
		for (const node of nodes) positions.set(node.id, {
			x: node.x,
			y: node.y
		});
		return {
			positions,
			group,
			nestedLayouts,
			keepAveragePosition: Boolean(selectedElements)
		};
	}
}
function applyLayout(model, layout) {
	const { positions, group, nestedLayouts, keepAveragePosition } = layout;
	const elements = model.elements.filter(({ id }) => positions.has(id));
	for (const nestedLayout of nestedLayouts) applyLayout(model, nestedLayout);
	if (group) translateToPositiveQuadrant(positions, getContentFittingBox(elements, []));
	const averagePosition = keepAveragePosition ? calculateAveragePosition(elements) : void 0;
	for (const element of elements) element.setPosition(positions.get(element.id));
	if (keepAveragePosition) {
		const newAveragePosition = calculateAveragePosition(elements);
		const averageDiff = {
			x: averagePosition.x - newAveragePosition.x,
			y: averagePosition.y - newAveragePosition.y
		};
		positions.forEach((position, elementId) => {
			model.getElement(elementId).setPosition({
				x: position.x + averageDiff.x,
				y: position.y + averageDiff.y
			});
		});
	}
}
function calculateAveragePosition(position) {
	let xSum = 0;
	let ySum = 0;
	for (const element of position) {
		xSum += element.position.x + element.size.width / 2;
		ySum += element.position.y + element.size.height / 2;
	}
	return {
		x: xSum / position.length,
		y: ySum / position.length
	};
}
function placeElementsAround(params) {
	const { model, elements, targetElement, prefferedLinksLength } = params;
	const targetElementBounds = boundsOf(targetElement);
	const targetPosition = {
		x: targetElementBounds.x + targetElementBounds.width / 2,
		y: targetElementBounds.y + targetElementBounds.height / 2
	};
	let outgoingAngle = 0;
	if (targetElement.links.length > 0) {
		const averageSourcePosition = calculateAveragePosition(targetElement.links.map((link) => {
			const linkSource = model.sourceOf(link);
			return linkSource !== targetElement ? linkSource : model.targetOf(link);
		}));
		const vectorDiff = {
			x: targetPosition.x - averageSourcePosition.x,
			y: targetPosition.y - averageSourcePosition.y
		};
		if (vectorDiff.x !== 0 || vectorDiff.y !== 0) outgoingAngle = Math.atan2(vectorDiff.y, vectorDiff.x);
	}
	const step = Math.min(Math.PI / elements.length, Math.PI / 6);
	const elementsSteck = [].concat(elements);
	const placeElementFromSteck = (curAngle, element) => {
		if (element) {
			const size = element.size;
			element.setPosition({
				x: targetPosition.x + prefferedLinksLength * Math.cos(curAngle) - size.width / 2,
				y: targetPosition.y + prefferedLinksLength * Math.sin(curAngle) - size.height / 2
			});
		}
	};
	if (elementsSteck.length % 2 === 0) for (let angle = step / 2; elementsSteck.length > 0; angle += step) {
		placeElementFromSteck(outgoingAngle - angle, elementsSteck.pop());
		placeElementFromSteck(outgoingAngle + angle, elementsSteck.pop());
	}
	else {
		placeElementFromSteck(outgoingAngle, elementsSteck.pop());
		for (let angle = step; elementsSteck.length > 0; angle += step) {
			placeElementFromSteck(outgoingAngle - angle, elementsSteck.pop());
			placeElementFromSteck(outgoingAngle + angle, elementsSteck.pop());
		}
	}
	return new Promise((resolve) => {
		const listener = new EventObserver();
		listener.listen(model.events, "changeCells", () => {
			listener.stopListening();
			removeOverlaps({
				model,
				padding: {
					x: 15,
					y: 15
				}
			});
			resolve(true);
		});
	});
}
function removeOverlaps(params) {
	const { padding, model, group, fixedElements, selectedElements } = params;
	return calculateLayout({
		model,
		group,
		fixedElements,
		selectedElements,
		layoutFunction: (nodes) => {
			padded(nodes, padding, () => groupRemoveOverlaps(nodes));
		}
	});
}
function forceLayout(params) {
	const { model, group, fixedElements, selectedElements } = params;
	return calculateLayout({
		model,
		group,
		fixedElements,
		selectedElements,
		layoutFunction: (nodes, links) => {
			if (fixedElements && fixedElements.size > 0) biasFreePadded(nodes, {
				x: 50,
				y: 50
			}, () => groupForceLayout({
				nodes,
				links,
				preferredLinkLength: 200,
				avoidOvelaps: true
			}));
			else {
				groupForceLayout({
					nodes,
					links,
					preferredLinkLength: 200
				});
				biasFreePadded(nodes, {
					x: 50,
					y: 50
				}, () => groupRemoveOverlaps(nodes));
			}
		}
	});
}
function getContentFittingBoxForLayout(nodes) {
	let minX = Infinity, minY = Infinity;
	let maxX = -Infinity, maxY = -Infinity;
	for (const node of nodes) {
		const { x, y, width, height } = node;
		minX = Math.min(minX, x);
		minY = Math.min(minY, y);
		maxX = Math.max(maxX, x + width);
		maxY = Math.max(maxY, y + height);
	}
	return {
		x: Number.isFinite(minX) ? minX : 0,
		y: Number.isFinite(minY) ? minY : 0,
		width: Number.isFinite(minX) && Number.isFinite(maxX) ? maxX - minX : 0,
		height: Number.isFinite(minY) && Number.isFinite(maxY) ? maxY - minY : 0
	};
}
//#endregion
//#region src/graph-explorer/data/sparql/graphBuilder.ts
var GREED_STEP = 150;
var GraphBuilder = class {
	constructor(dataProvider) {
		this.dataProvider = dataProvider;
	}
	createGraph(graph) {
		return this.dataProvider.elementInfo({ elementIds: graph.elementIds }).then((elementsInfo) => ({
			preloadedElements: elementsInfo,
			diagram: makeLayout(graph.elementIds, graph.links)
		}));
	}
	getGraphFromRDFGraph(graph) {
		const { elementIds, links } = makeGraphItems(graph);
		return this.createGraph({
			elementIds,
			links
		});
	}
	getGraphFromTurtleGraph(graph) {
		return parseTurtleText(graph).then((triples) => this.getGraphFromRDFGraph(triples));
	}
};
function makeGraphItems(response) {
	const elements = {};
	const links = [];
	for (const { subject, predicate, object } of response) {
		if (subject.type === "uri" && !elements[subject.value]) elements[subject.value] = true;
		if (object.type === "uri" && !elements[object.value]) elements[object.value] = true;
		if (subject.type === "uri" && object.type === "uri") links.push({
			linkTypeId: predicate.value,
			sourceId: subject.value,
			targetId: object.value
		});
	}
	return {
		elementIds: Object.keys(elements),
		links
	};
}
function makeLayout(elementsIds, linksInfo) {
	const grid = uniformGrid({
		rows: Math.ceil(Math.sqrt(elementsIds.length)),
		cellSize: {
			x: GREED_STEP,
			y: GREED_STEP
		}
	});
	const elements = elementsIds.map((id, index) => {
		const { x, y } = grid(index);
		return {
			"@type": "Element",
			"@id": GenerateID.forElement(),
			iri: id,
			position: {
				x,
				y
			}
		};
	});
	const layoutElementsMap = keyBy(elements, "iri");
	const links = [];
	linksInfo.forEach((link, _index) => {
		const source = layoutElementsMap[link.sourceId];
		const target = layoutElementsMap[link.targetId];
		if (!source || !target) return;
		links.push({
			"@type": "Link",
			"@id": GenerateID.forLink(),
			property: link.linkTypeId,
			source: { "@id": source["@id"] },
			target: { "@id": target["@id"] }
		});
	});
	return makeSerializedDiagram({
		layoutData: {
			"@type": "Layout",
			elements,
			links
		},
		linkTypeOptions: []
	});
}
//#endregion
//#region src/graph-explorer/data/sparql/sparqlGraphBuilder.ts
var DEFAULT_PREFIX = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n PREFIX owl:  <http://www.w3.org/2002/07/owl#>\n\n";
var SparqlGraphBuilder = class {
	constructor(dataProvider) {
		this.dataProvider = dataProvider;
		this.graphBuilder = new GraphBuilder(dataProvider);
	}
	getGraphFromConstruct(constructQuery) {
		const query = DEFAULT_PREFIX + constructQuery;
		return this.dataProvider.executeSparqlConstruct(query).then((graph) => this.graphBuilder.getGraphFromRDFGraph(graph));
	}
};
//#endregion
//#region src/graph-explorer/diagram/graph.ts
var Graph = class Graph {
	constructor() {
		this.source = new EventSource();
		this.events = this.source;
		this.elements = new OrderedMap();
		this.links = new OrderedMap();
		this.classesById = /* @__PURE__ */ new Map();
		this.propertiesById = /* @__PURE__ */ new Map();
		this.linkTypes = /* @__PURE__ */ new Map();
		this.onElementEvent = (data, key) => {
			this.source.trigger("elementEvent", {
				key,
				data
			});
		};
		this.onLinkEvent = (data, key) => {
			this.source.trigger("linkEvent", {
				key,
				data
			});
		};
		this.onLinkTypeEvent = (data, key) => {
			this.source.trigger("linkTypeEvent", {
				key,
				data
			});
		};
		this.onClassEvent = (data, key) => {
			this.source.trigger("classEvent", {
				key,
				data
			});
		};
	}
	static {
		this.nextLinkTypeIndex = 0;
	}
	getElements() {
		return this.elements.items;
	}
	getLinks() {
		return this.links.items;
	}
	getLink(linkId) {
		return this.links.get(linkId);
	}
	findLink(linkTypeId, sourceId, targetId) {
		const source = this.getElement(sourceId);
		if (!source) return;
		const index = findLinkIndex(source.links, linkTypeId, sourceId, targetId);
		return index >= 0 ? source.links[index] : void 0;
	}
	sourceOf(link) {
		return this.getElement(link.sourceId);
	}
	targetOf(link) {
		return this.getElement(link.targetId);
	}
	reorderElements(compare) {
		this.elements.reorder(compare);
	}
	getElement(elementId) {
		return this.elements.get(elementId);
	}
	addElement(element) {
		if (this.getElement(element.id)) throw new Error(`Element '${element.id}' already exists.`);
		element.events.onAny(this.onElementEvent);
		this.elements.push(element.id, element);
		this.source.trigger("changeCells", {
			updateAll: false,
			changedElement: element
		});
	}
	removeElement(elementId) {
		const element = this.elements.get(elementId);
		if (element) {
			const options = { silent: true };
			const changedLinks = [...element.links];
			for (const link of changedLinks) this.removeLink(link.id, options);
			this.elements.delete(elementId);
			element.events.offAny(this.onElementEvent);
			this.source.trigger("changeCells", {
				updateAll: false,
				changedElement: element,
				changedLinks
			});
		}
	}
	addLink(link) {
		if (this.getLink(link.id)) throw new Error(`Link '${link.id}' already exists.`);
		if (!this.getLinkType(link.typeId)) throw new Error(`Link type '${link.typeId}' not found.`);
		this.registerLink(link);
	}
	registerLink(link) {
		this.sourceOf(link).links.push(link);
		if (link.sourceId !== link.targetId) this.targetOf(link).links.push(link);
		link.events.onAny(this.onLinkEvent);
		this.links.push(link.id, link);
		this.source.trigger("changeCells", {
			updateAll: false,
			changedLinks: [link]
		});
	}
	removeLink(linkId, options) {
		const link = this.links.delete(linkId);
		if (link) {
			const { typeId, sourceId, targetId } = link;
			link.events.offAny(this.onLinkEvent);
			this.removeLinkReferences(typeId, sourceId, targetId);
			if (!(options && options.silent)) this.source.trigger("changeCells", {
				updateAll: false,
				changedLinks: [link]
			});
		}
	}
	removeLinkReferences(linkTypeId, sourceId, targetId) {
		const source = this.getElement(sourceId);
		if (source) removeLinkFrom(source.links, linkTypeId, sourceId, targetId);
		const target = this.getElement(targetId);
		if (target) removeLinkFrom(target.links, linkTypeId, sourceId, targetId);
	}
	getLinkTypes() {
		const result = [];
		this.linkTypes.forEach((type) => result.push(type));
		return result;
	}
	getLinkType(linkTypeId) {
		return this.linkTypes.get(linkTypeId);
	}
	addLinkType(linkType) {
		if (this.getLinkType(linkType.id)) throw new Error(`Link type '${linkType.id}' already exists.`);
		linkType.setIndex(Graph.nextLinkTypeIndex++);
		linkType.events.onAny(this.onLinkTypeEvent);
		this.linkTypes.set(linkType.id, linkType);
	}
	getProperty(propertyId) {
		return this.propertiesById.get(propertyId);
	}
	addProperty(property) {
		if (this.getProperty(property.id)) throw new Error(`Property '${property.id}' already exists.`);
		this.propertiesById.set(property.id, property);
	}
	getClass(classId) {
		return this.classesById.get(classId);
	}
	getClasses() {
		const classes = [];
		this.classesById.forEach((richClass) => classes.push(richClass));
		return classes;
	}
	addClass(classModel) {
		if (this.getClass(classModel.id)) throw new Error(`Class '${classModel.id}' already exists.`);
		classModel.events.onAny(this.onClassEvent);
		this.classesById.set(classModel.id, classModel);
	}
};
function removeLinkFrom(links, linkTypeId, sourceId, targetId) {
	if (!links) return;
	while (true) {
		const index = findLinkIndex(links, linkTypeId, sourceId, targetId);
		if (index < 0) break;
		links.splice(index, 1);
	}
}
function findLinkIndex(haystack, linkTypeId, sourceId, targetId) {
	for (let i = 0; i < haystack.length; i++) {
		const link = haystack[i];
		if (link.sourceId === sourceId && link.targetId === targetId && link.typeId === linkTypeId) return i;
	}
	return -1;
}
//#endregion
//#region src/graph-explorer/diagram/model.ts
/**
* Model of diagram.
*/
var DiagramModel = class {
	constructor(history) {
		this.history = history;
		this.source = new EventSource();
		this.events = this.source;
		this.graph = new Graph();
		this.graphListener = new EventObserver();
	}
	get elements() {
		return this.graph.getElements();
	}
	get links() {
		return this.graph.getLinks();
	}
	getElement(elementId) {
		return this.graph.getElement(elementId);
	}
	getLinkById(linkId) {
		return this.graph.getLink(linkId);
	}
	linksOfType(linkTypeId) {
		return this.graph.getLinks().filter((link) => link.typeId === linkTypeId);
	}
	findLink(linkTypeId, sourceId, targetId) {
		return this.graph.findLink(linkTypeId, sourceId, targetId);
	}
	sourceOf(link) {
		return this.getElement(link.sourceId);
	}
	targetOf(link) {
		return this.getElement(link.targetId);
	}
	isSourceAndTargetVisible(link) {
		return Boolean(this.sourceOf(link) && this.targetOf(link));
	}
	resetGraph() {
		if (this.graphListener) {
			this.graphListener.stopListening();
			this.graphListener = new EventObserver();
		}
		this.graph = new Graph();
	}
	subscribeGraph() {
		this.graphListener.listen(this.graph.events, "changeCells", (e) => {
			this.source.trigger("changeCells", e);
		});
		this.graphListener.listen(this.graph.events, "elementEvent", (e) => {
			this.source.trigger("elementEvent", e);
		});
		this.graphListener.listen(this.graph.events, "linkEvent", (e) => {
			this.source.trigger("linkEvent", e);
		});
		this.graphListener.listen(this.graph.events, "linkTypeEvent", (e) => {
			this.source.trigger("linkTypeEvent", e);
		});
		this.graphListener.listen(this.graph.events, "classEvent", (e) => {
			this.source.trigger("classEvent", e);
		});
		this.source.trigger("changeCells", { updateAll: true });
	}
	reorderElements(compare) {
		this.graph.reorderElements(compare);
	}
	createElement(elementIriOrModel, group) {
		const elementIri = typeof elementIriOrModel === "string" ? elementIriOrModel : elementIriOrModel.id;
		const elements = this.elements.filter((el) => el.iri === elementIri && el.group === group);
		if (elements.length > 0) return elements[0];
		let data = typeof elementIriOrModel === "string" ? placeholderDataFromIri(elementIri) : elementIriOrModel;
		data = {
			...data,
			id: data.id
		};
		const element = new Element$1({
			id: GenerateID.forElement(),
			data,
			group
		});
		this.addElement(element);
		return element;
	}
	addElement(element) {
		this.history.execute(addElement(this.graph, element, []));
	}
	removeElement(elementId) {
		const element = this.getElement(elementId);
		if (element) this.history.execute(removeElement(this.graph, element));
	}
	addLink(link) {
		const { typeId, sourceId, targetId, data } = link;
		if (data && data.linkTypeId !== typeId) throw new Error("linkTypeId must match linkType.id");
		const existingLink = this.findLink(typeId, sourceId, targetId);
		if (existingLink) {
			if (link.data) {
				existingLink.setLayoutOnly(false);
				existingLink.setData(data);
			}
			return existingLink;
		}
		const linkType = this.createLinkType(link.typeId);
		const source = this.getElement(sourceId);
		const target = this.getElement(targetId);
		if (!(linkType.visible && source && target)) return;
		if (!link.data) link.setData({
			linkTypeId: typeId,
			sourceId: source.iri,
			targetId: target.iri
		});
		this.graph.addLink(link);
		return link;
	}
	removeLink(linkId) {
		this.graph.removeLink(linkId);
	}
	getClass(classIri) {
		return this.graph.getClass(classIri);
	}
	createClass(classIri) {
		const existing = this.graph.getClass(classIri);
		if (existing) return existing;
		const classModel = new FatClassModel({ id: classIri });
		this.addClass(classModel);
		return classModel;
	}
	addClass(model) {
		this.graph.addClass(model);
	}
	getLinkType(linkTypeIri) {
		return this.graph.getLinkType(linkTypeIri);
	}
	createLinkType(linkTypeIri) {
		const existing = this.graph.getLinkType(linkTypeIri);
		if (existing) return existing;
		const linkType = new FatLinkType({ id: linkTypeIri });
		this.graph.addLinkType(linkType);
		return linkType;
	}
	getProperty(propertyTypeIri) {
		return this.graph.getProperty(propertyTypeIri);
	}
	createProperty(propertyIri) {
		const existing = this.graph.getProperty(propertyIri);
		if (existing) return existing;
		const property = new RichProperty({ id: propertyIri });
		this.graph.addProperty(property);
		return property;
	}
	triggerChangeGroupContent(group) {
		this.source.trigger("changeGroupContent", { group });
	}
	createTemporaryElement() {
		const target = new Element$1({
			id: GenerateID.forElement(),
			data: placeholderDataFromIri(""),
			temporary: true
		});
		this.graph.addElement(target);
		return target;
	}
};
function placeholderDataFromIri(iri) {
	return {
		id: iri,
		types: [],
		label: { values: [] },
		properties: {}
	};
}
function addElement(graph, element, connectedLinks) {
	return Command.create("Add element", () => {
		graph.addElement(element);
		for (const link of connectedLinks) if (!(graph.getLink(link.id) || graph.findLink(link.typeId, link.sourceId, link.targetId))) graph.addLink(link);
		return removeElement(graph, element);
	});
}
function removeElement(graph, element) {
	return Command.create("Remove element", () => {
		const connectedLinks = [...element.links];
		graph.removeElement(element.id);
		return addElement(graph, element, connectedLinks);
	});
}
//#endregion
//#region src/graph-explorer/editor/dataFetcher.ts
var DataFetcher = class {
	constructor(graph, dataProvider) {
		this.graph = graph;
		this.dataProvider = dataProvider;
		this.classQueue = new BufferingQueue((classIds) => {
			this.dataProvider.classInfo({ classIds }).then(this.onClassesLoaded);
		});
		this.linkTypeQueue = new BufferingQueue((linkTypeIds) => {
			this.dataProvider.linkTypesInfo({ linkTypeIds }).then(this.onLinkTypesLoaded);
		});
		this.propertyTypeQueue = new BufferingQueue((propertyIds) => {
			this.dataProvider.propertyInfo({ propertyIds }).then(this.onPropertyTypesLoaded);
		});
		this.onElementInfoLoaded = (elements) => {
			for (const element of this.graph.getElements()) {
				const loadedModel = elements[element.iri];
				if (loadedModel) element.setData(loadedModel);
			}
		};
		this.onClassesLoaded = (classInfos) => {
			for (const { id, label, count } of classInfos) {
				const model = this.graph.getClass(id);
				if (!model) continue;
				model.setLabel(label.values);
				if (typeof count === "number") model.setCount(count);
			}
		};
		this.onLinkTypesLoaded = (linkTypesInfo) => {
			for (const { id, label } of linkTypesInfo) {
				const model = this.graph.getLinkType(id);
				if (!model) continue;
				model.setLabel(label.values);
			}
		};
		this.onPropertyTypesLoaded = (propertyModels) => {
			for (const propId in propertyModels) {
				if (!Object.prototype.hasOwnProperty.call(propertyModels, propId)) continue;
				const { id, label } = propertyModels[propId];
				const targetProperty = this.graph.getProperty(id);
				if (targetProperty) targetProperty.setLabel(label.values);
			}
		};
	}
	fetchElementData(elementIris) {
		if (elementIris.length === 0) return Promise.resolve();
		return this.dataProvider.elementInfo({ elementIds: [...elementIris] }).then(this.onElementInfoLoaded);
	}
	fetchClass(model) {
		this.classQueue.push(model.id);
	}
	fetchLinkType(linkType) {
		this.linkTypeQueue.push(linkType.id);
	}
	fetchPropertyType(propertyType) {
		if (!this.dataProvider.propertyInfo) return;
		this.propertyTypeQueue.push(propertyType.id);
	}
};
//#endregion
//#region src/graph-explorer/editor/asyncModel.ts
var AsyncModel = class extends DiagramModel {
	constructor(history, groupByProperties) {
		super(history);
		this.groupByProperties = groupByProperties;
		this.linkSettings = {};
		this.onLinkTypeVisibilityChanged = (e) => {
			if (e.source.visible) {
				if (!e.preventLoading) this.requestLinksOfType([e.source.id]);
			} else for (const link of this.linksOfType(e.source.id)) this.graph.removeLink(link.id);
		};
	}
	get asyncSource() {
		return this.source;
	}
	get dataProvider() {
		return this._dataProvider;
	}
	subscribeGraph() {
		super.subscribeGraph();
		this.graphListener.listen(this.graph.events, "linkTypeEvent", (e) => {
			if (e.key === "changeVisibility") this.onLinkTypeVisibilityChanged(e.data[e.key], e.key);
		});
	}
	setDataProvider(dataProvider) {
		this._dataProvider = dataProvider;
		this.fetcher = new DataFetcher(this.graph, dataProvider);
	}
	createNewDiagram(dataProvider) {
		this.resetGraph();
		this.setDataProvider(dataProvider);
		this.asyncSource.trigger("loadingStart", { source: this });
		return this.dataProvider.linkTypes().then((linkTypes) => {
			const allLinkTypes = this.initLinkTypes(linkTypes);
			return this.loadAndRenderLayout({
				allLinkTypes,
				markLinksAsLayoutOnly: false
			});
		}).catch((error) => {
			console.error(error);
			this.asyncSource.trigger("loadingError", {
				source: this,
				error
			});
			return Promise.reject(error);
		});
	}
	importLayout(params) {
		this.resetGraph();
		this.setDataProvider(params.dataProvider);
		this.asyncSource.trigger("loadingStart", { source: this });
		return this.dataProvider.linkTypes().then((linkTypes) => {
			const allLinkTypes = this.initLinkTypes(linkTypes);
			const diagram = params.diagram ? params.diagram : emptyDiagram();
			this.setLinkSettings(diagram.linkTypeOptions);
			const loadingModels = this.loadAndRenderLayout({
				layoutData: diagram.layoutData,
				preloadedElements: params.preloadedElements || {},
				markLinksAsLayoutOnly: params.validateLinks || false,
				allLinkTypes,
				hideUnusedLinkTypes: params.hideUnusedLinkTypes
			});
			const requestingLinks = params.validateLinks ? this.requestLinksOfType() : Promise.resolve();
			return Promise.all([loadingModels, requestingLinks]);
		}).then(() => {
			this.asyncSource.trigger("loadingSuccess", { source: this });
		}).catch((error) => {
			console.error(error);
			this.asyncSource.trigger("loadingError", {
				source: this,
				error
			});
			return Promise.reject(error);
		});
	}
	exportLayout() {
		return makeSerializedDiagram({
			layoutData: makeLayoutData(this.graph.getElements(), this.graph.getLinks()),
			linkTypeOptions: this.graph.getLinkTypes().filter((linkType) => (!linkType.visible || !linkType.showLabel) && linkType.id !== "http://graph-explorer.org/NewLink").map(({ id, visible, showLabel }) => ({
				"@type": "LinkTypeOptions",
				property: id,
				visible,
				showLabel
			}))
		});
	}
	initLinkTypes(linkTypes) {
		const types = [];
		for (const { id, label } of linkTypes) {
			const linkType = new FatLinkType({
				id,
				label: label.values
			});
			this.graph.addLinkType(linkType);
			types.push(linkType);
		}
		return types;
	}
	setLinkSettings(settings) {
		if (!settings) return;
		for (const setting of settings) {
			const { visible = true, showLabel = true } = setting;
			const linkTypeId = setting.property;
			this.linkSettings[linkTypeId] = {
				"@type": "LinkTypeOptions",
				property: linkTypeId,
				visible,
				showLabel
			};
			const linkType = this.getLinkType(linkTypeId);
			if (linkType) linkType.setVisibility({
				visible,
				showLabel
			});
		}
	}
	loadAndRenderLayout(params) {
		const { layoutData = emptyLayoutData(), preloadedElements = {}, markLinksAsLayoutOnly, hideUnusedLinkTypes } = params;
		const elementIrisToRequestData = [];
		const usedLinkTypes = {};
		for (const layoutElement of layoutData.elements) {
			const { "@id": id, iri, position, size, isExpanded, group, elementState } = layoutElement;
			const template = preloadedElements[iri];
			const element = new Element$1({
				id,
				data: template || placeholderDataFromIri(iri),
				position,
				size,
				expanded: isExpanded,
				group,
				elementState
			});
			this.graph.addElement(element);
			if (!template) elementIrisToRequestData.push(element.iri);
		}
		for (const layoutLink of layoutData.links) {
			const { "@id": id, property, source, target, vertices, linkState } = layoutLink;
			const linkType = this.createLinkType(property);
			usedLinkTypes[linkType.id] = linkType;
			const link = this.addLink(new Link({
				id,
				typeId: linkType.id,
				sourceId: source["@id"],
				targetId: target["@id"],
				vertices,
				linkState
			}));
			if (link) link.setLayoutOnly(markLinksAsLayoutOnly);
		}
		this.subscribeGraph();
		const requestingModels = this.requestElementData(elementIrisToRequestData);
		if (hideUnusedLinkTypes && params.allLinkTypes) this.hideUnusedLinkTypes(params.allLinkTypes, usedLinkTypes);
		return requestingModels;
	}
	hideUnusedLinkTypes(allTypes, usedTypes) {
		for (const linkType of allTypes) if (!usedTypes[linkType.id]) linkType.setVisibility({
			visible: false,
			showLabel: linkType.showLabel
		});
	}
	requestElementData(elementIris) {
		return this.fetcher.fetchElementData(elementIris);
	}
	requestLinksOfType(linkTypeIds) {
		const linkTypes = linkTypeIds || this.graph.getLinkTypes().filter((type) => type.visible).map((type) => type.id);
		return this.dataProvider.linksInfo({
			elementIds: this.graph.getElements().map((element) => element.iri),
			linkTypeIds: linkTypes
		}).then((links) => this.onLinkInfoLoaded(links));
	}
	createClass(classId) {
		if (this.graph.getClass(classId)) return super.getClass(classId);
		const classModel = super.createClass(classId);
		this.fetcher.fetchClass(classModel);
		return classModel;
	}
	createLinkType(linkTypeId) {
		if (this.graph.getLinkType(linkTypeId)) return super.createLinkType(linkTypeId);
		const linkType = super.createLinkType(linkTypeId);
		const setting = this.linkSettings[linkType.id];
		if (setting) {
			const { visible, showLabel } = setting;
			linkType.setVisibility({
				visible,
				showLabel,
				preventLoading: true
			});
		}
		this.fetcher.fetchLinkType(linkType);
		return linkType;
	}
	createProperty(propertyIri) {
		if (this.graph.getProperty(propertyIri)) return super.createProperty(propertyIri);
		const property = super.createProperty(propertyIri);
		this.fetcher.fetchPropertyType(property);
		return property;
	}
	onLinkInfoLoaded(links) {
		let allowToCreate;
		const cancel = () => {
			allowToCreate = false;
		};
		for (const linkModel of links) {
			this.createLinkType(linkModel.linkTypeId);
			allowToCreate = true;
			this.asyncSource.trigger("createLoadedLink", {
				source: this,
				model: linkModel,
				cancel
			});
			if (allowToCreate) this.createLinks(linkModel);
		}
	}
	createLinks(data) {
		const sources = this.graph.getElements().filter((el) => el.iri === data.sourceId);
		const targets = this.graph.getElements().filter((el) => el.iri === data.targetId);
		const typeId = data.linkTypeId;
		for (const source of sources) for (const target of targets) this.addLink(new Link({
			typeId,
			sourceId: source.id,
			targetId: target.id,
			data
		}));
	}
	loadEmbeddedElements(elementIri) {
		const elements = this.groupByProperties.map((groupBy) => this.dataProvider.linkElements({
			elementId: elementIri,
			linkId: groupBy.linkType,
			offset: 0,
			direction: groupBy.linkDirection
		}));
		return Promise.all(elements).then((res) => res.reduce((memo, current) => Object.assign(memo, current), {}));
	}
};
function requestElementData(model, elementIris) {
	return Command.effect("Fetch element data", () => {
		model.requestElementData(elementIris);
	});
}
function restoreLinksBetweenElements(model) {
	return Command.effect("Restore links between elements", () => {
		model.requestLinksOfType();
	});
}
//#endregion
//#region src/graph-explorer/workspace/draggableHandle.tsx
var DraggableHandle = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.isHoldingMouse = false;
		this.onHandleMouseDown = (e) => {
			if (e.target !== e.currentTarget) return;
			if (this.isHoldingMouse) return;
			if (e.button !== 0) return;
			this.isHoldingMouse = true;
			this.originPageX = e.pageX;
			this.originPageY = e.pageY;
			document.addEventListener("mousemove", this.onMouseMove);
			document.addEventListener("mouseup", this.onMouseUp);
			this.props.onBeginDragHandle(e);
		};
		this.onMouseMove = (e) => {
			if (!this.isHoldingMouse) return;
			e.preventDefault();
			this.props.onDragHandle(e, e.pageX - this.originPageX, e.pageY - this.originPageY);
		};
		this.onMouseUp = (e) => {
			this.removeListeners();
			if (this.props.onEndDragHandle) this.props.onEndDragHandle(e);
		};
	}
	render() {
		const { onBeginDragHandle: _onBeginDragHandle, onDragHandle: _onDragHandle, onEndDragHandle: _onEndDragHandle, ...props } = this.props;
		return /* @__PURE__ */ React.createElement("div", {
			...props,
			onMouseDown: this.onHandleMouseDown
		}, this.props.children);
	}
	componentWillUnmount() {
		this.removeListeners();
	}
	removeListeners() {
		if (this.isHoldingMouse) {
			this.isHoldingMouse = false;
			document.removeEventListener("mousemove", this.onMouseMove);
			document.removeEventListener("mouseup", this.onMouseUp);
		}
	}
};
//#endregion
//#region src/graph-explorer/widgets/dialog.tsx
var DEFAULT_WIDTH = 300;
var DEFAULT_HEIGHT = 300;
var MIN_WIDTH = 250;
var MIN_HEIGHT = 250;
var MAX_WIDTH = 800;
var MAX_HEIGHT = 800;
var ELEMENT_OFFSET = 40;
var LINK_OFFSET = 20;
var FOCUS_OFFSET = 20;
var CLASS_NAME$19 = "graph-explorer-dialog";
var Dialog = class extends React.Component {
	static {
		this.defaultProps = { size: {
			width: DEFAULT_WIDTH,
			height: DEFAULT_HEIGHT
		} };
	}
	constructor(props) {
		super(props);
		this.unsubscribeFromTarget = void 0;
		this.handler = new EventObserver();
		this.updateAll = () => this.forceUpdate();
		this.onStartDragging = (_e) => {
			this.preventSelection();
			const { size } = this.props;
			this.startSize = {
				x: this.state.width || size.width,
				y: this.state.height || size.height
			};
		};
		this.onDragHandleBottom = (e, dx, dy) => {
			const height = this.calculateHeight(this.startSize.y + dy);
			this.setState({ height });
		};
		this.onDragHandleRight = (e, dx) => {
			const width = this.calculateWidth(this.startSize.x + dx);
			this.setState({ width });
		};
		this.onDragHandleBottomRight = (e, dx, dy) => {
			const width = this.calculateWidth(this.startSize.x + dx);
			const height = this.calculateHeight(this.startSize.y + dy);
			this.setState({
				width,
				height
			});
		};
		this.preventSelection = () => {
			const onMouseUp = () => {
				document.body.classList.remove("graph-explorer--unselectable");
				document.removeEventListener("mouseup", onMouseUp);
			};
			document.addEventListener("mouseup", onMouseUp);
			document.body.classList.add("graph-explorer--unselectable");
		};
		this.state = {};
	}
	componentDidMount() {
		this.listenToTarget(this.props.target);
		this.focusOn();
	}
	componentDidUpdate(nextProps) {
		if (nextProps.target !== this.props.target) this.listenToTarget(nextProps.target);
	}
	componentWillUnmount() {
		this.listenToTarget(void 0);
	}
	listenToTarget(target) {
		if (this.unsubscribeFromTarget) {
			this.unsubscribeFromTarget();
			this.unsubscribeFromTarget = void 0;
		}
		if (target) {
			const { view } = this.props;
			if (target instanceof Element$1) this.listenToElement(target);
			else if (target instanceof Link) this.listenToLink(target);
			this.handler.listen(view.events, "changeLanguage", this.updateAll);
			this.unsubscribeFromTarget = () => {
				this.handler.stopListening();
			};
		}
	}
	listenToElement(element) {
		this.handler.listen(element.events, "changePosition", this.updateAll);
		this.handler.listen(element.events, "changeSize", this.updateAll);
	}
	listenToLink(link) {
		const { view } = this.props;
		const source = view.model.getElement(link.sourceId);
		const target = view.model.getElement(link.targetId);
		this.listenToElement(source);
		this.listenToElement(target);
		this.handler.listen(link.events, "changeVertices", this.updateAll);
		this.handler.listen(link.events, "changeLabelBounds", this.updateAll);
	}
	calculatePositionForElement(element) {
		const { paperArea, size } = this.props;
		const bbox = boundsOf(element);
		const { y: y0 } = paperArea.paperToScrollablePaneCoords(bbox.x, bbox.y);
		const { x: x1, y: y1 } = paperArea.paperToScrollablePaneCoords(bbox.x + bbox.width, bbox.y + bbox.height);
		return {
			x: x1 + ELEMENT_OFFSET,
			y: (y0 + y1) / 2 - size.height / 2
		};
	}
	calculatePositionForLink(link) {
		const { view, paperArea } = this.props;
		const source = view.model.getElement(link.sourceId);
		const target = view.model.getElement(link.targetId);
		if (!source || !target) throw new Error("Source and target are not specified");
		const route = view.getRouting(link.id);
		const verticesDefinedByUser = link.vertices || [];
		const polyline = computePolyline(source, target, route ? route.vertices : verticesDefinedByUser);
		const targetPoint = getPointAlongPolyline(polyline, computePolylineLength(polyline) / 2);
		const { x, y } = paperArea.paperToScrollablePaneCoords(targetPoint.x, targetPoint.y);
		return {
			y: y + LINK_OFFSET,
			x: x + LINK_OFFSET
		};
	}
	calculatePosition() {
		const { target, paperArea, offset = {
			x: 0,
			y: 0
		}, calculatePosition } = this.props;
		if (calculatePosition) {
			const pos = calculatePosition();
			const { x, y } = paperArea.paperToScrollablePaneCoords(pos.x, pos.y);
			return {
				x: x + offset.x,
				y: y + offset.y
			};
		}
		if (target instanceof Element$1) return this.calculatePositionForElement(target);
		else if (target instanceof Link) return this.calculatePositionForLink(target);
		throw new Error("Unknown target type");
	}
	getViewPortScrollablePoints() {
		const { paperArea } = this.props;
		const paperAreaMetrix = paperArea.getAreaMetrics();
		return {
			min: paperArea.clientToScrollablePaneCoords(0, 0),
			max: paperArea.clientToScrollablePaneCoords(paperAreaMetrix.clientWidth, paperAreaMetrix.clientHeight)
		};
	}
	getDialogScrollablePoints() {
		const { size } = this.props;
		const { x, y } = this.calculatePosition();
		const min = {
			x: x - FOCUS_OFFSET,
			y: y - FOCUS_OFFSET
		};
		return {
			min,
			max: {
				x: min.x + size.width + FOCUS_OFFSET * 2,
				y: min.y + size.height + FOCUS_OFFSET * 2
			}
		};
	}
	focusOn() {
		const { paperArea } = this.props;
		const { min: viewPortMin, max: viewPortMax } = this.getViewPortScrollablePoints();
		const { min, max } = this.getDialogScrollablePoints();
		let xOffset = 0;
		if (min.x < viewPortMin.x) xOffset = min.x - viewPortMin.x;
		else if (max.x > viewPortMax.x) xOffset = max.x - viewPortMax.x;
		let yOffset = 0;
		if (min.y < viewPortMin.y) yOffset = min.y - viewPortMin.y;
		else if (max.y > viewPortMax.y) yOffset = max.y - viewPortMax.y;
		const curScrollableCenter = {
			x: viewPortMin.x + (viewPortMax.x - viewPortMin.x) / 2,
			y: viewPortMin.y + (viewPortMax.y - viewPortMin.y) / 2
		};
		const newScrollabalCenter = {
			x: curScrollableCenter.x + xOffset,
			y: curScrollableCenter.y + yOffset
		};
		const paperCenter = paperArea.scrollablePaneToPaperCoords(newScrollabalCenter.x, newScrollabalCenter.y);
		paperArea.centerTo(paperCenter);
	}
	calculateHeight(height) {
		const { size } = this.props;
		const minHeight = Math.min(size.height, MIN_HEIGHT);
		const maxHeight = Math.max(size.height, MAX_HEIGHT);
		return Math.max(minHeight, Math.min(maxHeight, height));
	}
	calculateWidth(width) {
		const { size } = this.props;
		const minWidth = Math.min(size.width, MIN_WIDTH);
		const maxWidth = Math.max(size.width, MAX_WIDTH);
		return Math.max(minWidth, Math.min(maxWidth, width));
	}
	render() {
		const { size, caption } = this.props;
		const { x, y } = this.calculatePosition();
		const style = {
			top: y,
			left: x,
			width: this.state.width || size.width,
			height: this.state.height || size.height
		};
		return /* @__PURE__ */ React.createElement("div", {
			className: CLASS_NAME$19,
			style
		}, /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$19}__close-button`,
			onClick: () => this.props.onClose()
		}), caption ? /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-dialog__caption" }, caption) : null, this.props.children, /* @__PURE__ */ React.createElement(DraggableHandle, {
			className: `${CLASS_NAME$19}__bottom-handle`,
			onBeginDragHandle: this.onStartDragging,
			onDragHandle: this.onDragHandleBottom
		}), /* @__PURE__ */ React.createElement(DraggableHandle, {
			className: `${CLASS_NAME$19}__right-handle`,
			onBeginDragHandle: this.onStartDragging,
			onDragHandle: this.onDragHandleRight
		}), /* @__PURE__ */ React.createElement(DraggableHandle, {
			className: `${CLASS_NAME$19}__bottom-right-handle`,
			onBeginDragHandle: this.onStartDragging,
			onDragHandle: this.onDragHandleBottomRight
		}));
	}
};
//#endregion
//#region src/graph-explorer/widgets/progressBar.tsx
var ProgressState = /* @__PURE__ */ function(ProgressState) {
	ProgressState["none"] = "none";
	ProgressState["loading"] = "loading";
	ProgressState["error"] = "error";
	ProgressState["completed"] = "completed";
	return ProgressState;
}({});
var CLASS_NAME$18 = "graph-explorer-progress-bar";
var ProgressBar = class extends React.Component {
	render() {
		const { state, percent = 100, height = 20 } = this.props;
		const className = `${CLASS_NAME$18} ${CLASS_NAME$18}--${state}`;
		const showBar = state === "loading" || state === "error";
		return /* @__PURE__ */ React.createElement("div", {
			className,
			style: { height: showBar ? height : 0 }
		}, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$18}__bar`,
			role: "progressbar",
			style: { width: `${percent}%` },
			"aria-valuemin": 0,
			"aria-valuemax": 100,
			"aria-valuenow": percent
		}));
	}
};
//#endregion
//#region src/graph-explorer/widgets/listElementView.tsx
var CLASS_NAME$17 = "graph-explorer-list-element-view";
var ListElementView = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.onClick = (event) => {
			const { disabled, model, onClick } = this.props;
			if (!disabled && onClick) {
				event.persist();
				onClick(event, model);
			}
		};
	}
	render() {
		const { className, view, model, highlightText, disabled, selected, onDragStart } = this.props;
		const { h, c, l } = view.getTypeStyle(model.types).color;
		const frontColor = selected && !disabled ? hcl(h, c, l * 1.2) : hcl("white");
		let classNames = `${CLASS_NAME$17}`;
		classNames += disabled ? ` ${CLASS_NAME$17}--disabled` : "";
		classNames += className ? ` ${className}` : "";
		const localizedText = view.formatLabel(model.label.values, model.id);
		const classesString = model.types.length > 0 ? `\nClasses: ${view.getElementTypeString(model)}` : "";
		return /* @__PURE__ */ React.createElement("li", {
			className: classNames,
			draggable: !disabled && Boolean(onDragStart),
			title: `${localizedText} ${view.formatIri(model.id)}${classesString}`,
			style: { background: hcl(h, c, l).toString() },
			onClick: this.onClick,
			onDragStart
		}, /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$17}__label`,
			style: { background: frontColor.toString() }
		}, highlightSubstring(localizedText, highlightText)));
	}
};
function startDragElements(e, iris) {
	try {
		e.dataTransfer.setData("application/x-graph-explorer-elements", JSON.stringify(iris));
	} catch (_ex) {
		e.dataTransfer.setData("text", JSON.stringify(iris));
	}
	return false;
}
var DEFAULT_HIGHLIGHT_PROPS = { className: `graph-explorer-text-highlight` };
function highlightSubstring(text, substring, highlightProps = DEFAULT_HIGHLIGHT_PROPS) {
	if (!substring) return /* @__PURE__ */ React.createElement("span", null, text);
	const start = text.toLowerCase().indexOf(substring.toLowerCase());
	if (start < 0) return /* @__PURE__ */ React.createElement("span", null, text);
	const end = start + substring.length;
	const before = text.substring(0, start);
	const highlighted = text.substring(start, end);
	const after = text.substring(end);
	return /* @__PURE__ */ React.createElement("span", null, before, /* @__PURE__ */ React.createElement("span", highlightProps, highlighted), after);
}
//#endregion
//#region src/graph-explorer/widgets/searchResults.tsx
var CLASS_NAME$16 = "graph-explorer-search-results";
var SearchResults = class extends React.Component {
	static {
		this.defaultProps = { useDragAndDrop: true };
	}
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.delayedChangeCells = new Debouncer();
		this.startSelection = 0;
		this.endSelection = 0;
		this.onRootMount = (root) => {
			this.root = root;
		};
		this.renderResultItem = (model) => {
			const { useDragAndDrop } = this.props;
			const canBeSelected = this.canBeSelected(model);
			return /* @__PURE__ */ React.createElement(ListElementView, {
				key: model.id,
				model,
				view: this.props.view,
				highlightText: this.props.highlightText,
				disabled: !canBeSelected,
				selected: this.props.selection.has(model.id),
				onClick: canBeSelected ? this.onItemClick : void 0,
				onDragStart: useDragAndDrop ? (e) => {
					const { selection } = this.props;
					const iris = [];
					selection.forEach((iri) => iris.push(iri));
					if (!selection.has(model.id)) iris.push(model.id);
					return startDragElements(e, iris);
				} : void 0
			});
		};
		this.onChangeCells = () => {
			const { items, selection } = this.props;
			if (selection.size === 0) {
				if (items && items.length > 0) this.forceUpdate();
			} else {
				const newSelection = cloneSet(selection);
				for (const element of this.props.view.model.elements) if (element.group === void 0 && selection.has(element.iri)) newSelection.delete(element.iri);
				this.updateSelection(newSelection);
			}
		};
		this.addKeyListener = () => {
			document.addEventListener("keydown", this.onKeyUp);
		};
		this.removeKeyListener = () => {
			document.removeEventListener("keydown", this.onKeyUp);
		};
		this.onKeyUp = (event) => {
			const { items } = this.props;
			const isPressedUp = event.keyCode === 38 || event.which === 38;
			const isPressDown = event.keyCode === 40 || event.which === 40;
			if (isPressedUp || isPressDown) if (event.shiftKey) {
				if (isPressedUp) this.endSelection = this.getNextIndex(this.endSelection, 0);
				else if (isPressDown) this.endSelection = this.getNextIndex(this.endSelection, 1);
				const startIndex = Math.min(this.startSelection, this.endSelection);
				const finishIndex = Math.max(this.startSelection, this.endSelection);
				const selection = this.selectRange(startIndex, finishIndex);
				this.updateSelection(selection);
				this.focusOn(this.endSelection);
			} else {
				const startIndex = Math.min(this.startSelection, this.endSelection);
				const finishIndex = Math.max(this.startSelection, this.endSelection);
				if (isPressedUp) this.startSelection = this.getNextIndex(startIndex, 0);
				else if (isPressDown) this.startSelection = this.getNextIndex(finishIndex, 1);
				this.endSelection = this.startSelection;
				const focusElement = items[this.startSelection];
				const newSelection = /* @__PURE__ */ new Set();
				newSelection.add(focusElement.id);
				this.updateSelection(newSelection);
				this.focusOn(this.startSelection);
			}
			event.preventDefault();
		};
		this.onItemClick = (event, model) => {
			event.preventDefault();
			const { items, selection, onSelectionChanged } = this.props;
			const modelIndex = items.indexOf(model);
			let newSelection;
			if (event.shiftKey && this.startSelection !== -1) {
				const start = Math.min(this.startSelection, modelIndex);
				const end = Math.max(this.startSelection, modelIndex);
				newSelection = this.selectRange(start, end);
			} else {
				this.endSelection = this.startSelection = modelIndex;
				if (event.ctrlKey || event.metaKey) {
					newSelection = cloneSet(selection);
					if (selection.has(model.id)) newSelection.delete(model.id);
					else newSelection.add(model.id);
				} else {
					newSelection = /* @__PURE__ */ new Set();
					newSelection.add(model.id);
				}
			}
			onSelectionChanged(newSelection);
		};
		this.state = { selection: props.selection || {} };
	}
	render() {
		const items = this.props.items || [];
		return /* @__PURE__ */ React.createElement("ul", {
			className: CLASS_NAME$16,
			ref: this.onRootMount,
			tabIndex: -1,
			onFocus: this.addKeyListener,
			onBlur: this.removeKeyListener
		}, items.map(this.renderResultItem));
	}
	componentDidMount() {
		this.listener.listen(this.props.view.model.events, "changeCells", () => {
			this.delayedChangeCells.call(this.onChangeCells);
		});
	}
	UNSAFE_componentWillReceiveProps(props) {
		this.setState({ selection: props.selection || {} });
	}
	componentWillUnmount() {
		this.removeKeyListener();
		this.listener.stopListening();
		this.delayedChangeCells.dispose();
	}
	updateSelection(selection) {
		const { onSelectionChanged } = this.props;
		onSelectionChanged(selection);
	}
	selectRange(start, end) {
		const { items } = this.props;
		const selection = /* @__PURE__ */ new Set();
		for (let i = start; i <= end; i++) {
			const selectedModel = items[i];
			if (this.canBeSelected(selectedModel)) selection.add(selectedModel.id);
		}
		return selection;
	}
	getNextIndex(startIndex, direction) {
		const { items } = this.props;
		if (items.length === 0) return startIndex;
		const indexDelta = direction === 0 ? -1 : 1;
		for (let step = 1; step < items.length; step++) {
			let nextIndex = startIndex + step * indexDelta;
			if (nextIndex < 0) nextIndex += items.length;
			if (nextIndex >= items.length) nextIndex -= items.length;
			if (this.canBeSelected(items[nextIndex])) return nextIndex;
		}
		return startIndex;
	}
	canBeSelected(model) {
		const alreadyOnDiagram = this.props.view.model.elements.findIndex((element) => element.iri === model.id && element.group === void 0) >= 0;
		return !this.props.useDragAndDrop || !alreadyOnDiagram;
	}
	focusOn(index) {
		const scrollableContainer = this.root.parentElement;
		const containerBounds = scrollableContainer.getBoundingClientRect();
		const item = this.root.children.item(index);
		const itemBounds = item.getBoundingClientRect();
		const itemTop = itemBounds.top - containerBounds.top;
		const itemBottom = itemBounds.bottom - containerBounds.top;
		if (itemTop < 0) scrollableContainer.scrollTop += itemTop;
		else if (itemBottom > containerBounds.height) scrollableContainer.scrollTop += itemBottom - containerBounds.height;
		item.focus();
	}
};
//#endregion
//#region src/graph-explorer/widgets/connectionsMenu.tsx
var MAX_LINK_COUNT = 100;
var ALL_RELATED_ELEMENTS_LINK = new FatLinkType({
	id: "allRelatedElements",
	label: [{
		value: "All",
		language: ""
	}]
});
var ConnectionsMenu = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.handler = new EventObserver();
		this.linkTypesListener = new EventObserver();
		this.loadingState = ProgressState.none;
		this.updateAll = () => this.forceUpdate();
		this.addSelectedElements = (selectedObjects) => {
			const { onClose, onAddElements } = this.props;
			const addedElementsIris = selectedObjects.map((item) => item.model.id);
			const linkType = this.linkDataChunk ? this.linkDataChunk.link : void 0;
			onAddElements(addedElementsIris, this.linkDataChunk && linkType !== ALL_RELATED_ELEMENTS_LINK ? linkType : void 0);
			onClose();
		};
		this.onExpandLink = (linkDataChunk) => {
			if (!(this.objects && this.linkDataChunk && this.linkDataChunk.link === linkDataChunk.link && this.linkDataChunk.direction === linkDataChunk.direction)) this.loadObjects(linkDataChunk);
			this.updateAll();
			this.context.workspace.triggerWorkspaceEvent(WorkspaceEventKey.connectionsExpandLink);
		};
		this.onMoveToFilter = (linkDataChunk) => {
			const { view, target } = this.props;
			const { link, direction } = linkDataChunk;
			if (link === ALL_RELATED_ELEMENTS_LINK) target.addToFilter();
			else view.model.getElement(target.id).addToFilter(link, direction);
		};
	}
	static {
		this.contextType = WorkspaceContext;
	}
	componentDidMount() {
		const { view } = this.props;
		this.handler.listen(view.events, "changeLanguage", this.updateAll);
		this.loadLinks();
	}
	componentWillUnmount() {
		this.handler.stopListening();
		this.linkTypesListener.stopListening();
	}
	resubscribeOnLinkTypeEvents(linkTypesOfElement) {
		this.linkTypesListener.stopListening();
		for (const linkType of linkTypesOfElement) {
			this.linkTypesListener.listen(linkType.events, "changeLabel", this.updateAll);
			this.linkTypesListener.listen(linkType.events, "changeVisibility", this.updateAll);
		}
	}
	loadLinks() {
		const { view, editor, target } = this.props;
		this.loadingState = ProgressState.loading;
		this.links = [];
		this.countMap = {};
		editor.model.dataProvider.linkTypesOf({ elementId: target.iri }).then((linkTypes) => {
			this.loadingState = ProgressState.completed;
			const countMap = {};
			const links = [];
			for (const { id: linkTypeId, inCount, outCount } of linkTypes) {
				countMap[linkTypeId] = {
					inCount,
					outCount
				};
				links.push(view.model.createLinkType(linkTypeId));
			}
			countMap[ALL_RELATED_ELEMENTS_LINK.id] = Object.keys(countMap).map((key) => countMap[key]).reduce((a, b) => {
				return {
					inCount: a.inCount + b.inCount,
					outCount: a.outCount + b.outCount
				};
			}, {
				inCount: 0,
				outCount: 0
			});
			this.countMap = countMap;
			this.links = links;
			this.resubscribeOnLinkTypeEvents(this.links);
			this.updateAll();
			this.context.workspace.triggerWorkspaceEvent(WorkspaceEventKey.connectionsLoadLinks);
		}).catch((err) => {
			console.error(err);
			this.loadingState = ProgressState.error;
			this.updateAll();
		});
		this.updateAll();
	}
	loadObjects(linkDataChunk) {
		const { view, editor, target } = this.props;
		const { link, direction } = linkDataChunk;
		const offset = linkDataChunk.offset || 0;
		this.loadingState = ProgressState.loading;
		this.linkDataChunk = linkDataChunk;
		this.objects = [];
		editor.model.dataProvider.linkElements({
			elementId: target.iri,
			linkId: link === ALL_RELATED_ELEMENTS_LINK ? void 0 : link.id,
			limit: offset + MAX_LINK_COUNT,
			offset,
			direction
		}).then((elements) => {
			this.loadingState = ProgressState.completed;
			this.objects = Object.keys(elements).map((iri) => ({
				model: elements[iri],
				presentOnDiagram: view.model.elements.findIndex((element) => element.iri === iri && element.group === void 0) >= 0
			}));
			this.updateAll();
			this.context.workspace.triggerWorkspaceEvent(WorkspaceEventKey.connectionsLoadElements);
		}).catch((err) => {
			console.error(err);
			this.loadingState = ProgressState.error;
			this.updateAll();
		});
	}
	render() {
		const connectionsData = {
			links: this.links || [],
			countMap: this.countMap || {}
		};
		let objectsData = null;
		if (this.linkDataChunk && this.objects) objectsData = {
			linkDataChunk: this.linkDataChunk,
			objects: this.objects
		};
		const { view, target, suggestProperties } = this.props;
		return /* @__PURE__ */ React.createElement(ConnectionsMenuMarkup, {
			target,
			connectionsData,
			objectsData,
			state: this.loadingState,
			view,
			onExpandLink: this.onExpandLink,
			onPressAddSelected: this.addSelectedElements,
			onMoveToFilter: this.onMoveToFilter,
			propertySuggestionCall: suggestProperties
		});
	}
};
var ConnectionsMenuMarkup = class extends React.Component {
	constructor(props) {
		super(props);
		this.onChangeFilter = (e) => {
			const filterKey = e.currentTarget.value;
			this.setState({ filterKey });
		};
		this.getTitle = () => {
			if (this.props.objectsData && this.state.panel === "objects") return "Objects";
			else if (this.props.connectionsData && this.state.panel === "connections") return "Connections";
			return "Error";
		};
		this.onExpandLink = (linkDataChunk) => {
			this.setState({
				filterKey: "",
				panel: "objects"
			});
			this.props.onExpandLink(linkDataChunk);
		};
		this.onCollapseLink = () => {
			this.setState({
				filterKey: "",
				panel: "connections"
			});
		};
		this.getBreadCrumbs = () => {
			if (this.props.objectsData && this.state.panel === "objects") {
				const { link, direction } = this.props.objectsData.linkDataChunk;
				const localizedText = this.props.view.formatLabel(link.label, link.id);
				return /* @__PURE__ */ React.createElement("span", { className: "graph-explorer-connections-menu_bread-crumbs" }, /* @__PURE__ */ React.createElement("a", {
					className: "graph-explorer-connections-menu__link",
					onClick: this.onCollapseLink
				}, "Connections"), "\xA0/\xA0", localizedText, " ", direction ? `(${direction})` : null);
			} else return null;
		};
		this.getBody = () => {
			if (this.props.state === "error") return /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu__error" }, "Error");
			else if (this.props.objectsData && this.state.panel === "objects") return /* @__PURE__ */ React.createElement(ObjectsPanel, {
				data: this.props.objectsData,
				onMoveToFilter: this.props.onMoveToFilter,
				view: this.props.view,
				filterKey: this.state.filterKey,
				loading: this.props.state === ProgressState.loading,
				onPressAddSelected: this.props.onPressAddSelected
			});
			else if (this.props.connectionsData && this.state.panel === "connections") {
				if (this.props.state === ProgressState.loading) return /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu__loading" }, "Loading...");
				return /* @__PURE__ */ React.createElement(ConnectionsList, {
					id: this.props.target.id,
					data: this.props.connectionsData,
					view: this.props.view,
					filterKey: this.state.filterKey,
					onExpandLink: this.onExpandLink,
					onMoveToFilter: this.props.onMoveToFilter,
					propertySuggestionCall: this.props.propertySuggestionCall,
					sortMode: this.state.sortMode
				});
			} else return /* @__PURE__ */ React.createElement("div", null);
		};
		this.onSortChange = (e) => {
			const value = e.target.value;
			if (this.state.sortMode === value) return;
			this.setState({ sortMode: value });
		};
		this.renderSortSwitch = (id, icon, title) => {
			return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("input", {
				type: "radio",
				name: "sort",
				id,
				value: id,
				className: "graph-explorer-connections-menu__sort-switch",
				onChange: this.onSortChange,
				checked: this.state.sortMode === id
			}), /* @__PURE__ */ React.createElement("label", {
				htmlFor: id,
				className: "graph-explorer-connections-menu__sort-switch-label",
				title
			}, /* @__PURE__ */ React.createElement("i", { className: `fa ${icon}` })));
		};
		this.renderSortSwitches = () => {
			if (this.state.panel !== "connections" || !this.props.propertySuggestionCall) return null;
			return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_search-line-sort-switches" }, this.renderSortSwitch("alphabet", "fa-sort-alpha-asc", "Sort alphabetically"), this.renderSortSwitch("smart", "fa-lightbulb-o", "Smart sort"));
		};
		this.state = {
			filterKey: "",
			panel: "connections",
			sortMode: "alphabet"
		};
	}
	render() {
		return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu" }, /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu__title-label" }, this.getTitle()), this.getBreadCrumbs(), /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_search-line" }, /* @__PURE__ */ React.createElement("input", {
			type: "text",
			className: "search-input graph-explorer-form-control graph-explorer-connections-menu__search-line-input",
			value: this.state.filterKey,
			onChange: this.onChangeFilter,
			placeholder: "Search for..."
		}), this.renderSortSwitches()), /* @__PURE__ */ React.createElement(ProgressBar, {
			state: this.props.state,
			height: 10
		}), this.getBody());
	}
};
var ConnectionsList = class extends React.Component {
	constructor(props) {
		super(props);
		this.updateScores = (props) => {
			if (props.propertySuggestionCall && (props.filterKey || props.sortMode === "smart")) {
				const { id, data, view, filterKey } = props;
				const lang = view.getLanguage();
				const token = filterKey.trim();
				const properties = data.links.map((l) => l.id);
				props.propertySuggestionCall({
					elementId: id,
					token,
					properties,
					lang
				}).then((scores) => this.setState({ scores }));
			}
		};
		this.compareLinks = (a, b) => {
			const { view } = this.props;
			const aText = view.formatLabel(a.label, a.id);
			const bText = view.formatLabel(b.label, b.id);
			return aText.localeCompare(bText);
		};
		this.compareLinksByWeight = (a, b) => {
			const { view } = this.props;
			const aText = view.formatLabel(a.label, a.id);
			const bText = view.formatLabel(b.label, b.id);
			const aWeight = this.state.scores[a.id] ? this.state.scores[a.id].score : 0;
			const bWeight = this.state.scores[b.id] ? this.state.scores[b.id].score : 0;
			return aWeight > bWeight ? -1 : aWeight < bWeight ? 1 : aText.localeCompare(bText);
		};
		this.getLinks = () => {
			const { view, data, filterKey } = this.props;
			return (data.links || []).filter((link) => {
				const text = view.formatLabel(link.label, link.id).toLowerCase();
				return !filterKey || text.indexOf(filterKey.toLowerCase()) >= 0;
			}).sort(this.compareLinks);
		};
		this.getProbableLinks = () => {
			const isSmartMode = this.isSmartMode();
			return (this.props.data.links || []).filter((link) => {
				return this.state.scores[link.id] && (this.state.scores[link.id].score > 0 || isSmartMode);
			}).sort(this.compareLinksByWeight);
		};
		this.getViews = (links, notSure) => {
			const { view } = this.props;
			const countMap = this.props.data.countMap || {};
			const views = [];
			const addView = (link, direction) => {
				const count = direction === "in" ? countMap[link.id].inCount : countMap[link.id].outCount;
				if (count === 0) return;
				const postfix = notSure ? "-probable" : "";
				views.push(/* @__PURE__ */ React.createElement(LinkInPopupMenu, {
					key: `${direction}-${link.id}-${postfix}`,
					link,
					onExpandLink: this.props.onExpandLink,
					view,
					count,
					direction,
					filterKey: notSure ? "" : this.props.filterKey,
					onMoveToFilter: this.props.onMoveToFilter,
					probability: this.state.scores[link.id] && notSure ? this.state.scores[link.id].score : 0
				}));
			};
			for (const link of links) {
				addView(link, "in");
				addView(link, "out");
			}
			return views;
		};
		this.state = { scores: {} };
		this.updateScores(props);
	}
	componentDidUpdate(newProps) {
		this.updateScores(newProps);
	}
	isSmartMode() {
		return this.props.sortMode === "smart" && !this.props.filterKey;
	}
	render() {
		const { view } = this.props;
		const isSmartMode = this.isSmartMode();
		const links = isSmartMode ? [] : this.getLinks();
		const probableLinks = this.getProbableLinks().filter((link) => links.indexOf(link) === -1);
		const views = this.getViews(links);
		const probableViews = this.getViews(probableLinks, true);
		let viewList;
		if (views.length === 0 && probableViews.length === 0) viewList = /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu_links-list__empty" }, "List empty");
		else {
			viewList = views;
			if (views.length > 1 || isSmartMode && probableViews.length > 1) {
				const allRelatedElements = (this.props.data.countMap || {})[ALL_RELATED_ELEMENTS_LINK.id];
				viewList = [/* @__PURE__ */ React.createElement(LinkInPopupMenu, {
					key: ALL_RELATED_ELEMENTS_LINK.id,
					link: ALL_RELATED_ELEMENTS_LINK,
					onExpandLink: this.props.onExpandLink,
					view,
					count: allRelatedElements.inCount + allRelatedElements.outCount,
					onMoveToFilter: this.props.onMoveToFilter
				}), /* @__PURE__ */ React.createElement("hr", {
					key: "graph-explorer-hr-line",
					className: "graph-explorer-connections-menu_links-list__hr"
				})].concat(viewList);
			}
		}
		let probablePart = null;
		if (probableViews.length !== 0) probablePart = [isSmartMode ? null : /* @__PURE__ */ React.createElement("li", { key: "probable-links" }, /* @__PURE__ */ React.createElement("span", { className: "graph-explorer-label" }, "Probably, you‘re looking for..")), probableViews];
		return /* @__PURE__ */ React.createElement("ul", { className: "graph-explorer-connections-menu_links-list " + (views.length === 0 && probableViews.length === 0 ? "ocm_links-list-empty" : "") }, viewList, probablePart);
	}
};
var LinkInPopupMenu = class extends React.Component {
	constructor(..._args2) {
		super(..._args2);
		this.onExpandLink = (expectedCount, direction) => {
			this.props.onExpandLink({
				link: this.props.link,
				direction,
				expectedCount
			});
		};
		this.onMoveToFilter = (evt) => {
			evt.stopPropagation();
			this.props.onMoveToFilter({
				link: this.props.link,
				direction: this.props.direction,
				expectedCount: this.props.count
			});
		};
	}
	render() {
		const { view, link } = this.props;
		const fullText = view.formatLabel(link.label, link.id);
		const probability = Math.round(this.props.probability * 100);
		const textLine = highlightSubstring(fullText + (probability > 0 ? " (" + probability + "%)" : ""), this.props.filterKey);
		const directionName = this.props.direction === "in" ? "source" : this.props.direction === "out" ? "target" : "all connected";
		return /* @__PURE__ */ React.createElement("li", {
			"data-linktypeid": this.props.link.id,
			className: "link-in-popup-menu",
			title: `${directionName} of "${fullText}" ${view.formatIri(link.id)}`,
			onClick: () => this.onExpandLink(this.props.count, this.props.direction)
		}, this.props.direction === "in" || this.props.direction === "out" ? /* @__PURE__ */ React.createElement("div", { className: "link-in-popup-menu_direction" }, this.props.direction === "in" && /* @__PURE__ */ React.createElement("div", { className: "link-in-popup-menu_direction__in-direction" }), this.props.direction === "out" && /* @__PURE__ */ React.createElement("div", { className: "link-in-popup-menu_direction__out-direction" })) : null, /* @__PURE__ */ React.createElement("div", { className: "link-in-popup-menu__link-title" }, textLine), /* @__PURE__ */ React.createElement("span", { className: "graph-explorer-badge link-in-popup-menu__count" }, this.props.count <= MAX_LINK_COUNT ? this.props.count : "100+"), /* @__PURE__ */ React.createElement("div", {
			className: "link-in-popup-menu__filter-button",
			onClick: this.onMoveToFilter,
			title: "Set as filter in the Instances panel"
		}), /* @__PURE__ */ React.createElement("div", {
			className: "link-in-popup-menu__navigate-button",
			title: `Navigate to ${directionName} "${fullText}" elements`
		}));
	}
};
var ObjectsPanel = class extends React.Component {
	constructor(props) {
		super(props);
		this.onSelectAll = () => {
			const objects = this.props.data.objects;
			if (objects.length === 0) return;
			const newSelection = allNonPresentedAreSelected(objects, this.state.selection) ? /* @__PURE__ */ new Set() : selectNonPresented(this.props.data.objects);
			this.updateSelection(newSelection);
		};
		this.updateSelection = (newSelection) => {
			this.setState({ selection: newSelection });
		};
		this.counter = (activeObjCount) => {
			const countString = `${activeObjCount}\u00A0of\u00A0${this.props.data.objects.length}`;
			const wrongNodes = Math.min(MAX_LINK_COUNT, this.props.data.linkDataChunk.expectedCount) - this.props.data.objects.length;
			const wrongNodesString = Math.abs(wrongNodes) > MAX_LINK_COUNT ? `${MAX_LINK_COUNT}+` : Math.abs(wrongNodes).toString();
			const wrongNodesCount = wrongNodes === 0 ? "" : wrongNodes < 0 ? `\u00A0(${wrongNodesString})` : `\u00A0(${wrongNodesString})`;
			const wrongNodesTitle = wrongNodes === 0 ? "" : wrongNodes > 0 ? "Unavailable nodes" : "Extra nodes";
			return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-label graph-explorer-connections-menu_objects-panel_bottom-panel__count-label" }, /* @__PURE__ */ React.createElement("span", null, countString), /* @__PURE__ */ React.createElement("span", {
				className: "graph-explorer-connections-menu_objects-panel_bottom-panel__extra-elements",
				title: wrongNodesTitle
			}, wrongNodesCount));
		};
		this.state = { selection: /* @__PURE__ */ new Set() };
	}
	componentDidUpdate(nextProps) {
		if (this.props.data.objects.length < nextProps.data.objects.length) this.setState({ selection: /* @__PURE__ */ new Set() });
	}
	getFilteredObjects() {
		if (!this.props.filterKey) return this.props.data.objects;
		const filterKey = this.props.filterKey.toLowerCase();
		return this.props.data.objects.filter((element) => {
			const text = this.props.view.formatLabel(element.model.label.values, element.model.id).toLowerCase();
			return text && text.indexOf(filterKey) >= 0;
		});
	}
	getItems(list) {
		const added = {};
		const result = [];
		for (const obj of list) {
			if (added[obj.model.id]) continue;
			added[obj.model.id] = true;
			result.push(obj.model);
		}
		return result;
	}
	render() {
		const { onPressAddSelected, filterKey } = this.props;
		const { selection } = this.state;
		const objects = this.getFilteredObjects();
		const isAllSelected = allNonPresentedAreSelected(objects, selection);
		const nonPresented = objects.filter((el) => !el.presentOnDiagram);
		const active = nonPresented.filter((el) => selection.has(el.model.id));
		return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_objects-panel" }, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_objects-panel__select-all" }, /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
			type: "checkbox",
			checked: isAllSelected && nonPresented.length > 0,
			onChange: this.onSelectAll,
			disabled: nonPresented.length === 0
		}), "Select All")), this.props.loading ? /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu__loading-objects" }, "Loading...") : objects.length === 0 ? /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label graph-explorer-connections-menu__loading-objects" }, "No available nodes") : /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_objects-panel_objects-list" }, /* @__PURE__ */ React.createElement(SearchResults, {
			view: this.props.view,
			items: this.getItems(objects),
			selection: this.state.selection,
			onSelectionChanged: this.updateSelection,
			highlightText: filterKey
		}), this.props.data.linkDataChunk.expectedCount > MAX_LINK_COUNT ? /* @__PURE__ */ React.createElement("div", {
			className: "graph-explorer-connections-menu__move-to-filter",
			onClick: () => this.props.onMoveToFilter(this.props.data.linkDataChunk)
		}, "The list was truncated, for more data click here to use the filter panel") : null), /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-connections-menu_objects-panel_bottom-panel" }, this.counter(active.length), /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-primary pull-right graph-explorer-connections-menu_objects-panel_bottom-panel__add-button",
			disabled: this.props.loading || nonPresented.length === 0,
			onClick: () => onPressAddSelected(active.length > 0 ? active : nonPresented)
		}, active.length > 0 ? "Add selected" : "Add all")));
	}
};
function selectNonPresented(objects) {
	const selection = /* @__PURE__ */ new Set();
	for (const object of objects) {
		if (object.presentOnDiagram) continue;
		selection.add(object.model.id);
	}
	return selection;
}
function allNonPresentedAreSelected(objects, selection) {
	let allSelected = true;
	for (const object of objects) {
		if (object.presentOnDiagram) continue;
		allSelected = allSelected && selection.has(object.model.id);
	}
	return allSelected;
}
//#endregion
//#region src/graph-explorer/forms/editEntityForm.tsx
var CLASS_NAME$15 = "graph-explorer-edit-form";
var EditEntityForm = class extends React.Component {
	constructor(props) {
		super(props);
		this.renderProperty = (key, property) => {
			const { view } = this.props;
			const richProperty = view.model.getProperty(key);
			const label = view.formatLabel(richProperty.label, key);
			let values = [];
			if (isLiteralProperty(property)) values = property.values.map(({ value, language }) => {
				return {
					value,
					language
				};
			});
			return /* @__PURE__ */ React.createElement("div", {
				key,
				className: `${CLASS_NAME$15}__form-row`
			}, /* @__PURE__ */ React.createElement("label", null, label, values.map((value, index) => /* @__PURE__ */ React.createElement("input", {
				key: index,
				className: "graph-explorer-form-control",
				defaultValue: value.value,
				lang: value.language,
				onChange: this.onChangeProp,
				"data-iri": key
			}))));
		};
		this.onChangeIri = (e) => {
			const iri = e.target.value;
			this.setState((prevState) => {
				return { elementModel: {
					...prevState.elementModel,
					id: iri
				} };
			});
		};
		this.onChangeLabel = (e) => {
			const target = e.target;
			const labels = target.value.length > 0 ? [{
				value: target.value,
				language: ""
			}] : [];
			this.setState({ elementModel: {
				...this.state.elementModel,
				label: { values: labels }
			} });
		};
		this.onChangeProp = (e) => {
			const target = e.target;
			const values = [];
			target.parentElement.querySelectorAll("[data-iri=\"" + target.dataset["iri"] + "\"]").forEach((Element) => {
				const typedElement = Element;
				values.push({
					value: typedElement.value,
					language: typedElement.lang
				});
			});
			this.setState({ elementModel: {
				...this.state.elementModel,
				properties: {
					...this.state.elementModel.properties,
					[target.dataset["iri"]]: {
						type: "string",
						values
					}
				}
			} });
		};
		this.state = { elementModel: props.entity };
	}
	componentDidUpdate(nextProps) {
		if (this.props.entity !== nextProps.entity) this.setState({ elementModel: nextProps.entity });
	}
	renderProperties() {
		const { properties } = this.props.entity;
		const propertyIris = Object.keys(properties);
		return /* @__PURE__ */ React.createElement("div", null, propertyIris.map((iri) => {
			return this.renderProperty(iri, properties[iri]);
		}));
	}
	renderType() {
		const { view } = this.props;
		const { elementModel } = this.state;
		const label = view.getElementTypeString(elementModel);
		return /* @__PURE__ */ React.createElement("label", null, "Type", /* @__PURE__ */ React.createElement("input", {
			className: "graph-explorer-form-control",
			value: label,
			disabled: true
		}));
	}
	renderIri() {
		const { elementModel } = this.state;
		return /* @__PURE__ */ React.createElement("label", null, "IRI", /* @__PURE__ */ React.createElement("input", {
			className: "graph-explorer-form-control",
			defaultValue: elementModel.id,
			onChange: this.onChangeIri
		}));
	}
	renderLabel() {
		const { view } = this.props;
		const label = view.selectLabel(this.state.elementModel.label.values);
		const text = label ? label.value : "";
		return /* @__PURE__ */ React.createElement("label", null, "Label", /* @__PURE__ */ React.createElement("input", {
			className: "graph-explorer-form-control",
			value: text,
			onChange: this.onChangeLabel
		}));
	}
	render() {
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$15 }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$15}__body` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$15}__form-row` }, this.renderIri()), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$15}__form-row` }, this.renderType()), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$15}__form-row` }, this.renderLabel()), this.renderProperties()), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$15}__controls` }, /* @__PURE__ */ React.createElement("button", {
			className: `graph-explorer-btn graph-explorer-btn-success ${CLASS_NAME$15}__apply-button`,
			onClick: () => this.props.onApply(this.state.elementModel)
		}, "Apply"), /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-danger",
			onClick: this.props.onCancel
		}, "Cancel")));
	}
};
//#endregion
//#region src/graph-explorer/widgets/instancesSearch.tsx
var CLASS_NAME$14 = "graph-explorer-instances-search";
var InstancesSearch = class extends React.Component {
	static {
		this.contextType = WorkspaceContext;
	}
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.onSelectionChanged = (newSelection) => {
			this.setState({ selection: newSelection });
		};
		this.state = {
			resultId: 0,
			selection: /* @__PURE__ */ new Set()
		};
	}
	render() {
		const ENTER_KEY_CODE = 13;
		const className = `${CLASS_NAME$14} ${this.props.className || ""}`;
		const progressState = this.state.quering ? ProgressState.loading : this.state.error ? ProgressState.error : this.state.items ? ProgressState.completed : ProgressState.none;
		const searchTerm = this.state.inputText === void 0 ? this.props.criteria.text : this.state.inputText;
		return /* @__PURE__ */ React.createElement("div", { className }, /* @__PURE__ */ React.createElement(ProgressBar, { state: progressState }), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$14}__criteria` }, this.renderCriteria(), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$14}__text-criteria graph-explorer-input-group` }, /* @__PURE__ */ React.createElement("input", {
			type: "text",
			className: "graph-explorer-form-control",
			placeholder: "Search for...",
			value: searchTerm || "",
			onChange: (e) => this.setState({ inputText: e.currentTarget.value }),
			onKeyUp: (e) => {
				if (e.keyCode === ENTER_KEY_CODE) this.submitCriteriaUpdate();
			}
		}), /* @__PURE__ */ React.createElement("span", { className: "graph-explorer-input-group-btn" }, /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-default",
			type: "button",
			title: "Search",
			onClick: () => this.submitCriteriaUpdate()
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-search",
			"aria-hidden": "true"
		}))))), /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$14}__rest graph-explorer-scrollable`,
			key: this.state.resultId
		}, /* @__PURE__ */ React.createElement(SearchResults, {
			view: this.props.view,
			items: this.state.items,
			highlightText: this.props.criteria.text,
			selection: this.state.selection,
			onSelectionChanged: this.onSelectionChanged
		}), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$14}__rest-end` }, /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: `${CLASS_NAME$14}__load-more graph-explorer-btn graph-explorer-btn-primary`,
			disabled: this.state.quering,
			style: { display: this.state.moreItemsAvailable ? void 0 : "none" },
			onClick: () => this.queryItems(true)
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-chevron-down",
			"aria-hidden": "true"
		}), "\xA0Show more"))));
	}
	renderCriteria() {
		const { criteria = {}, view } = this.props;
		const criterions = [];
		if (criteria.elementType) {
			const classInfo = criteria.elementType;
			const classLabel = view.formatLabel(classInfo.label, classInfo.id);
			criterions.push(/* @__PURE__ */ React.createElement("div", {
				key: "hasType",
				className: `${CLASS_NAME$14}__criterion`
			}, this.renderRemoveCriterionButtons(() => this.props.onCriteriaChanged({
				...this.props.criteria,
				elementType: void 0
			})), "Has type", " ", /* @__PURE__ */ React.createElement("span", {
				className: `${CLASS_NAME$14}__criterion-class`,
				title: classInfo.id
			}, classLabel)));
		} else if (criteria.refElement) {
			const element = criteria.refElement;
			const elementLabel = view.formatLabel(element.data.label.values, element.iri);
			const linkType = criteria.refElementLink;
			const linkTypeLabel = linkType ? view.formatLabel(linkType.label, linkType.id) : void 0;
			criterions.push(/* @__PURE__ */ React.createElement("div", {
				key: "hasLinkedElement",
				className: `${CLASS_NAME$14}__criterion`
			}, this.renderRemoveCriterionButtons(() => this.props.onCriteriaChanged({
				...this.props.criteria,
				refElement: void 0,
				refElementLink: void 0
			})), "Connected to", " ", /* @__PURE__ */ React.createElement("span", {
				className: `${CLASS_NAME$14}__criterion-element`,
				title: element ? element.iri : void 0
			}, elementLabel), linkType && /* @__PURE__ */ React.createElement("span", null, " through ", /* @__PURE__ */ React.createElement("span", {
				className: `${CLASS_NAME$14}__criterion-link-type`,
				title: linkType ? linkType.id : void 0
			}, linkTypeLabel), criteria.linkDirection === "in" && /* @__PURE__ */ React.createElement("span", null, " as ", /* @__PURE__ */ React.createElement("img", {
				className: `${CLASS_NAME$14}__link-direction`,
				src: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAbCAYAAAAOEM1uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAZEQAAGREBkIelaAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAG2SURBVFiFzde9axRRFMbhJ3Hjx0YRgkWElGIRGyVgaaG9XQpBrNIETJHKjxBSJCA2NiIWdhYKgoqCIELq/AU2tiJpAiliDMHEWEyKZfdO5szHrr4wzcx77vnNnXPnnktcK9jBwYCuLcwNBeHGsIGovyltDweNbYOHg9Eo4D9Tq0bsGj40BXKoO5isEjiht4ifHuE/qVpJvO/O049PvIxN/MBMH8ZP6pzeGVxK+C4kfAsl8vTMYBnI1x1Bv3E54bmWSHCAx2KfvBbgKGbxJAfOIcS7HMjnKCqpWoBRtfE5B/IVRsoAtnAGd3GlQchd/NE7Y7dwCtPYiw72xuD216KFk/zN3Ii+SYOajhqHZUU9aK1GjS3M4xumFK+yMuPexLHEsy9YbChPJR3HW+na+yjbBvNU+zdzHbcxfoTnUw7cS8XNSS3AFx1B6zif8FzKgXsmVj6VAduyFrwzcCUHcL/L9yiaJAUYXRRjON1172zC9xX3ZS+ziTk8KAFYWWX7wRGcqJAnudVV1RTu1YhP6WL3jWjXO4HvzbLE9N8fmqKAv/SpNyvQdmorSmlHVvhX1TsJltFPPPwL/+nTC6wUIf8AAAAASUVORK5CYII="
			}), "\xA0source"), criteria.linkDirection === "out" && /* @__PURE__ */ React.createElement("span", null, " as ", /* @__PURE__ */ React.createElement("img", {
				className: `${CLASS_NAME$14}__link-direction`,
				src: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAbCAYAAAAOEM1uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAZEQAAGREBkIelaAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGCSURBVFiFzdi9ShxRFAfwn+uiaAoRVBQbbfMEFqIoFja+QCoLLQQr8R0sbdIJgTQiSgT1AcTKzkdIQhpTaOlX0GyK2WJ2c8d1Pt0/XBjOnTnnP+eerxnYxj0aJa9nfEOvlLirgFx8zaQhV8Ng2jfKiVT2amWxKAr1gOwElwXpH8NWXiXtMbKZV2EMHwP6F2P7dR1O8T2PeBW/8EMHp5TpwWGtJewF06JEuWmzu4ueqgnC55juw6ZsHE8B218F8qJsgkS1b0Grh74EbDdwioGqCYbQj6MEkhcYIlxm3opZrGEyh47eJqH22JvDOZbJ5sEJ4Rgqeh1nLTMr6Mv4bBpMZSV4hj9FMknA96wxeC3qCOvyxWAd88L17wobdHkWV0VwxP+e3ksgd6LiOrgtyvhn7DRlo3gM2K68kwziNqb7QTSC9eN3m9136cWvjVuf8FOHaSZPJ8mLfRw0r/8m3RQiuIQPBZEY67CfSCyOsttV0hG/CV3/0VQTTbxVIrW9rv6z8A+8NRQ5z9bcwQAAAABJRU5ErkJggg=="
			}), "\xA0target"))));
		}
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$14}__criterions` }, criterions);
	}
	renderRemoveCriterionButtons(onClick) {
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$14}__criterion-remove ontoidia-btn-group graph-explorer-btn-group-xs` }, /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Remove criteria",
			onClick
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-times",
			"aria-hidden": "true"
		})));
	}
	submitCriteriaUpdate() {
		let text = this.state.inputText === void 0 ? this.props.criteria.text : this.state.inputText;
		text = text === "" ? void 0 : text;
		this.props.onCriteriaChanged({
			...this.props.criteria,
			text
		});
	}
	componentDidMount() {
		this.listener.listen(this.props.view.events, "changeLanguage", () => this.forceUpdate());
		this.queryItems(false);
	}
	componentDidUpdate(nextProps) {
		const languageChanged = this.currentRequest ? this.currentRequest.languageCode !== nextProps.view.getLanguage() : false;
		if (this.props.criteria !== nextProps.criteria || languageChanged) this.setState({ inputText: void 0 }, () => this.queryItems(false));
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.currentRequest = void 0;
	}
	queryItems(loadMoreItems) {
		let request;
		if (loadMoreItems) {
			if (!this.currentRequest) throw new Error("Cannot request more items without initial request.");
			const { offset, limit } = this.currentRequest;
			request = {
				...this.currentRequest,
				offset: offset + limit
			};
		} else request = createRequest(this.props.criteria, this.props.view.getLanguage());
		if (!(request.text || request.elementTypeId || request.refElementId || request.refElementLinkId)) {
			this.setState({
				quering: false,
				error: void 0,
				items: void 0,
				selection: /* @__PURE__ */ new Set(),
				moreItemsAvailable: false
			});
			return;
		}
		this.currentRequest = request;
		this.setState({
			quering: true,
			error: void 0,
			moreItemsAvailable: false
		});
		this.props.model.dataProvider.filter(request).then((elements) => {
			if (this.currentRequest !== request) return;
			this.processFilterData(elements);
			this.context.workspace.triggerWorkspaceEvent(WorkspaceEventKey.searchQueryItem);
		}).catch((error) => {
			if (this.currentRequest !== request) return;
			console.error(error);
			this.setState({
				quering: false,
				error
			});
		});
	}
	processFilterData(elements) {
		const requestedAdditionalItems = this.currentRequest.offset > 0;
		const existingIris = {};
		if (requestedAdditionalItems) this.state.items.forEach((item) => existingIris[item.id] = true);
		const items = requestedAdditionalItems ? [...this.state.items] : [];
		for (const iri in elements) {
			if (!Object.prototype.hasOwnProperty.call(elements, iri)) continue;
			if (existingIris[iri]) continue;
			items.push(elements[iri]);
		}
		const moreItemsAvailable = Object.keys(elements).length >= this.currentRequest.limit;
		if (requestedAdditionalItems) this.setState({
			quering: false,
			items,
			error: void 0,
			moreItemsAvailable
		});
		else this.setState({
			quering: false,
			resultId: this.state.resultId + 1,
			items,
			selection: /* @__PURE__ */ new Set(),
			error: void 0,
			moreItemsAvailable
		});
	}
};
function createRequest(criteria, language) {
	const { text, elementType, refElement, refElementLink, linkDirection } = criteria;
	return {
		text,
		elementTypeId: elementType ? elementType.id : void 0,
		refElementId: refElement ? refElement.iri : void 0,
		refElementLinkId: refElementLink ? refElementLink.id : void 0,
		linkDirection,
		offset: 0,
		limit: 100,
		languageCode: language || "en"
	};
}
//#endregion
//#region src/graph-explorer/forms/elementTypeSelector.tsx
var CLASS_NAME$13 = "graph-explorer-edit-form";
var ElementTypeSelector = class extends React.Component {
	constructor(props) {
		super(props);
		this.cancellation = new Cancellation();
		this.filterCancellation = new Cancellation();
		this.loadingItemCancellation = new Cancellation();
		this.onElementTypeChange = async (e) => {
			this.setState({ isLoading: true });
			this.loadingItemCancellation.abort();
			this.loadingItemCancellation = new Cancellation();
			const signal = this.loadingItemCancellation.signal;
			const { onChange, metadataApi } = this.props;
			const classId = e.target.value;
			const elementModel = await CancellationToken.mapCancelledToNull(signal, metadataApi.generateNewElement([classId], signal));
			if (elementModel === null) return;
			this.setState({ isLoading: false });
			onChange({
				value: elementModel,
				isNew: true,
				loading: false
			});
		};
		this.renderPossibleElementType = (elementType) => {
			const { view } = this.props;
			const type = view.model.createClass(elementType);
			const label = view.formatLabel(type.label, type.id);
			return /* @__PURE__ */ React.createElement("option", {
				key: elementType,
				value: elementType
			}, label);
		};
		this.state = {
			searchString: "",
			existingElements: []
		};
	}
	componentDidMount() {
		this.fetchPossibleElementTypes();
	}
	componentDidUpdate(prevProps, prevState) {
		const { searchString } = this.state;
		if (searchString !== prevState.searchString) this.searchExistingElements();
	}
	componentWillUnmount() {
		this.cancellation.abort();
		this.filterCancellation.abort();
		this.loadingItemCancellation.abort();
	}
	async fetchPossibleElementTypes() {
		const { view, metadataApi, source } = this.props;
		if (!metadataApi) return;
		const elementTypes = await CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.typesOfElementsDraggedFrom(source, this.cancellation.signal));
		if (elementTypes === null) return;
		elementTypes.sort(makeElementTypeComparatorByLabel(view));
		this.setState({ elementTypes });
	}
	searchExistingElements() {
		const { editor, view } = this.props;
		const { searchString } = this.state;
		this.setState({ existingElements: [] });
		if (searchString.length > 0) {
			this.setState({ isLoading: true });
			this.filterCancellation.abort();
			this.filterCancellation = new Cancellation();
			const signal = this.filterCancellation.signal;
			const request = createRequest({ text: searchString }, view.getLanguage());
			editor.model.dataProvider.filter(request).then((elements) => {
				if (signal.aborted) return;
				const existingElements = Object.keys(elements).map((key) => elements[key]);
				this.setState({
					existingElements,
					isLoading: false
				});
			});
		}
	}
	renderElementTypeSelector() {
		const { elementValue } = this.props;
		const { elementTypes, isLoading } = this.state;
		const value = elementValue.value.types.length ? elementValue.value.types[0] : "";
		if (isLoading) return /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		});
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$13}__control-row` }, /* @__PURE__ */ React.createElement("label", null, "Entity Type"), elementTypes ? /* @__PURE__ */ React.createElement("select", {
			className: "graph-explorer-form-control",
			value,
			onChange: this.onElementTypeChange
		}, /* @__PURE__ */ React.createElement("option", {
			value: PLACEHOLDER_ELEMENT_TYPE,
			disabled: true
		}, "Select entity type"), elementTypes.map(this.renderPossibleElementType)) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		})), elementValue.error ? /* @__PURE__ */ React.createElement("span", { className: `${CLASS_NAME$13}__control-error` }, elementValue.error) : "");
	}
	renderExistingElementsList() {
		const { view, editor, elementValue } = this.props;
		const { elementTypes, isLoading, existingElements } = this.state;
		if (isLoading) return /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		});
		if (existingElements.length > 0) return existingElements.map((element) => {
			const isAlreadyOnDiagram = !editor.temporaryState.elements.has(element.id) && Boolean(editor.model.elements.find(({ iri, group }) => iri === element.id && group === void 0));
			const hasAppropriateType = Boolean(elementTypes.find((type) => element.types.indexOf(type) >= 0));
			return /* @__PURE__ */ React.createElement(ListElementView, {
				key: element.id,
				view,
				model: element,
				disabled: isAlreadyOnDiagram || !hasAppropriateType,
				selected: element.id === elementValue.value.id,
				onClick: (e, model) => this.onSelectExistingItem(model)
			});
		});
		return /* @__PURE__ */ React.createElement("span", null, "No results");
	}
	async onSelectExistingItem(model) {
		const { editor, onChange } = this.props;
		this.loadingItemCancellation.abort();
		this.loadingItemCancellation = new Cancellation();
		const signal = this.loadingItemCancellation.signal;
		onChange({
			value: model,
			isNew: false,
			loading: true
		});
		const result = await editor.model.dataProvider.elementInfo({ elementIds: [model.id] });
		if (signal.aborted) return;
		const loadedModel = result[model.id];
		onChange({
			value: loadedModel,
			isNew: false,
			loading: false
		});
	}
	render() {
		const { searchString } = this.state;
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$13}__form-row ${CLASS_NAME$13}__element-selector` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$13}__search` }, /* @__PURE__ */ React.createElement("i", { className: `fa fa-search ${CLASS_NAME$13}__search-icon` }), /* @__PURE__ */ React.createElement("input", {
			value: searchString,
			onChange: (e) => this.setState({ searchString: e.target.value }),
			className: `graph-explorer-form-control ${CLASS_NAME$13}__search-input`,
			placeholder: "Search for...",
			autoFocus: true
		})), searchString.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$13}__existing-elements-list` }, this.renderExistingElementsList()) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$13}__separator` }, /* @__PURE__ */ React.createElement("i", { className: `${CLASS_NAME$13}__separator-text` }, "or create new entity")), this.renderElementTypeSelector()));
	}
};
function makeElementTypeComparatorByLabel(view) {
	return (a, b) => {
		const typeA = view.model.createClass(a);
		const typeB = view.model.createClass(b);
		const labelA = view.formatLabel(typeA.label, typeA.id);
		const labelB = view.formatLabel(typeB.label, typeB.id);
		return labelA.localeCompare(labelB);
	};
}
function validateElementType(element) {
	const error = !(element.types.indexOf("http://graph-explorer.org/NewEntity") < 0) ? "Required." : void 0;
	return Promise.resolve({
		error,
		allowChange: true
	});
}
//#endregion
//#region src/graph-explorer/forms/linkTypeSelector.tsx
var CLASS_NAME$12 = "graph-explorer-edit-form";
var LinkTypeSelector = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.cancellation = new Cancellation();
		this.updateAll = () => this.forceUpdate();
		this.onChangeType = (e) => {
			const { link: originalLink, direction: originalDirection } = this.props.linkValue.value;
			const index = parseInt(e.currentTarget.value, 10);
			const { fatLinkType, direction } = this.state.fatLinkTypes[index];
			const link = {
				...originalLink,
				linkTypeId: fatLinkType.id
			};
			if (originalDirection !== direction) {
				link.sourceId = originalLink.targetId;
				link.targetId = originalLink.sourceId;
			}
			this.props.onChange({
				link,
				direction
			});
		};
		this.renderPossibleLinkType = ({ fatLinkType, direction }, index) => {
			const { view, source, target } = this.props;
			const label = view.formatLabel(fatLinkType.label, fatLinkType.id);
			let [sourceLabel, targetLabel] = [source, target].map((element) => view.formatLabel(element.label.values, element.id));
			if (direction === LinkDirection.in) [sourceLabel, targetLabel] = [targetLabel, sourceLabel];
			return /* @__PURE__ */ React.createElement("option", {
				key: index,
				value: index
			}, label, " [", sourceLabel, " → ", targetLabel, "]");
		};
		this.state = { fatLinkTypes: [] };
	}
	componentDidMount() {
		this.fetchPossibleLinkTypes();
	}
	componentDidUpdate(prevProps) {
		const { source, target } = this.props;
		if (prevProps.source !== source || prevProps.target !== target) {
			this.setState({ fatLinkTypes: void 0 });
			this.fetchPossibleLinkTypes();
		}
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.cancellation.abort();
	}
	async fetchPossibleLinkTypes() {
		const { view, metadataApi, source, target } = this.props;
		if (!metadataApi) return;
		const linkTypes = await CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.possibleLinkTypes(source, target, this.cancellation.signal));
		if (linkTypes === null) return;
		const fatLinkTypes = [];
		linkTypes.forEach(({ linkTypeIri, direction }) => {
			const fatLinkType = view.model.createLinkType(linkTypeIri);
			fatLinkTypes.push({
				fatLinkType,
				direction
			});
		});
		fatLinkTypes.sort(makeLinkTypeComparatorByLabelAndDirection(view));
		this.setState({ fatLinkTypes });
		this.listenToLinkLabels(fatLinkTypes);
	}
	listenToLinkLabels(fatLinkTypes) {
		fatLinkTypes.forEach(({ fatLinkType }) => this.listener.listen(fatLinkType.events, "changeLabel", this.updateAll));
	}
	render() {
		const { linkValue, disabled } = this.props;
		const { fatLinkTypes } = this.state;
		const value = (fatLinkTypes || []).findIndex(({ fatLinkType, direction }) => fatLinkType.id === linkValue.value.link.linkTypeId && direction === linkValue.value.direction);
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$12}__control-row` }, /* @__PURE__ */ React.createElement("label", null, "Link Type"), fatLinkTypes ? /* @__PURE__ */ React.createElement("select", {
			className: "graph-explorer-form-control",
			value,
			onChange: this.onChangeType,
			disabled
		}, /* @__PURE__ */ React.createElement("option", {
			value: -1,
			disabled: true
		}, "Select link type"), fatLinkTypes.map(this.renderPossibleLinkType)) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		})), linkValue.error ? /* @__PURE__ */ React.createElement("span", { className: `${CLASS_NAME$12}__control-error` }, linkValue.error) : "");
	}
};
function makeLinkTypeComparatorByLabelAndDirection(view) {
	return (a, b) => {
		const labelA = view.formatLabel(a.fatLinkType.label, a.fatLinkType.id);
		const labelB = view.formatLabel(b.fatLinkType.label, b.fatLinkType.id);
		const labelCompareResult = labelA.localeCompare(labelB);
		if (labelCompareResult !== 0) return labelCompareResult;
		if (a.direction === LinkDirection.out && b.direction === LinkDirection.in) return -1;
		if (a.direction === LinkDirection.in && b.direction === LinkDirection.out) return 1;
		return 0;
	};
}
function validateLinkType(editor, currentLink, originalLink) {
	if (currentLink.linkTypeId === "http://graph-explorer.org/NewLink") return Promise.resolve({
		error: "Required.",
		allowChange: true
	});
	if (sameLink(currentLink, originalLink)) return Promise.resolve({
		error: void 0,
		allowChange: true
	});
	if (editor.model.links.find(({ data: { linkTypeId, sourceId, targetId } }) => linkTypeId === currentLink.linkTypeId && sourceId === currentLink.sourceId && targetId === currentLink.targetId && !editor.temporaryState.links.has(currentLink))) return Promise.resolve({
		error: "The link already exists.",
		allowChange: false
	});
	return editor.model.dataProvider.linksInfo({
		elementIds: [currentLink.sourceId, currentLink.targetId],
		linkTypeIds: [currentLink.linkTypeId]
	}).then((links) => {
		return links.some((link) => sameLink(link, currentLink)) ? {
			error: "The link already exists.",
			allowChange: false
		} : {
			error: void 0,
			allowChange: true
		};
	});
}
//#endregion
//#region src/graph-explorer/forms/editElementTypeForm.tsx
var CLASS_NAME$11 = "graph-explorer-edit-form";
var EditElementTypeForm = class extends React.Component {
	constructor(props) {
		super(props);
		this.validationCancellation = new Cancellation();
		const { target, link } = this.props;
		this.state = {
			elementValue: {
				value: target.value,
				isNew: target.isNew,
				loading: false,
				validated: true,
				allowChange: true
			},
			linkValue: {
				value: {
					link,
					direction: LinkDirection.out
				},
				validated: true,
				allowChange: true
			}
		};
	}
	componentDidMount() {
		this.validate();
	}
	componentWillUnmount() {
		this.validationCancellation.abort();
	}
	setElementOrLink({ elementValue, linkValue }) {
		this.setState((state) => ({
			elementValue: elementValue || state.elementValue,
			linkValue: linkValue || state.linkValue
		}), () => {
			if (elementValue && !elementValue.validated || linkValue && !linkValue.validated) this.validate();
			if (elementValue && elementValue.validated && elementValue.allowChange) this.props.onChangeElement(elementValue.value);
			if (linkValue && linkValue.validated && linkValue.allowChange) this.props.onChangeLink(linkValue.value.link);
		});
	}
	validate() {
		const { editor, link: originalLink } = this.props;
		const { elementValue, linkValue } = this.state;
		this.setState({ isValidating: true });
		this.validationCancellation.abort();
		this.validationCancellation = new Cancellation();
		const signal = this.validationCancellation.signal;
		const validateElement = validateElementType(elementValue.value);
		const validateLink = validateLinkType(editor, linkValue.value.link, originalLink);
		Promise.all([validateElement, validateLink]).then(([elementError, linkError]) => {
			if (signal.aborted) return;
			this.setState({ isValidating: false });
			this.setElementOrLink({
				elementValue: {
					...elementValue,
					...elementError,
					validated: true
				},
				linkValue: {
					...linkValue,
					...linkError,
					validated: true
				}
			});
		});
	}
	render() {
		const { editor, view, metadataApi, source, link: originalLink } = this.props;
		const { elementValue, linkValue, isValidating } = this.state;
		const isValid = !elementValue.error && !linkValue.error;
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$11 }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$11}__body` }, /* @__PURE__ */ React.createElement(ElementTypeSelector, {
			editor,
			view,
			metadataApi,
			source,
			elementValue,
			onChange: (newState) => {
				this.setElementOrLink({
					elementValue: {
						value: newState.value,
						isNew: newState.isNew,
						loading: newState.loading,
						error: void 0,
						validated: false,
						allowChange: false
					},
					linkValue: {
						value: {
							link: {
								...originalLink,
								targetId: newState.value.id
							},
							direction: LinkDirection.out
						},
						validated: false,
						allowChange: false
					}
				});
			}
		}), elementValue.loading ? /* @__PURE__ */ React.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		}), "\xA0Loading entity...") : /* @__PURE__ */ React.createElement(LinkTypeSelector, {
			editor,
			view,
			metadataApi,
			linkValue,
			source,
			target: elementValue.value,
			onChange: (value) => this.setElementOrLink({ linkValue: {
				value,
				error: void 0,
				validated: false,
				allowChange: false
			} }),
			disabled: elementValue.error !== void 0
		}), isValidating ? /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$11}__progress` }, /* @__PURE__ */ React.createElement(ProgressBar, {
			state: ProgressState.loading,
			height: 10
		})) : null), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$11}__controls` }, /* @__PURE__ */ React.createElement("button", {
			className: `graph-explorer-btn graph-explorer-btn-success ${CLASS_NAME$11}__apply-button`,
			onClick: () => this.props.onApply(elementValue.value, elementValue.isNew, linkValue.value.link),
			disabled: elementValue.loading || !isValid || isValidating
		}, "Apply"), /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-danger",
			onClick: this.props.onCancel
		}, "Cancel")));
	}
};
//#endregion
//#region src/graph-explorer/forms/editLinkForm.tsx
var CLASS_NAME$10 = "graph-explorer-edit-form";
var EditLinkForm = class extends React.Component {
	constructor(props) {
		super(props);
		this.validationCancellation = new Cancellation();
		this.state = { linkValue: {
			value: {
				link: props.link,
				direction: LinkDirection.out
			},
			validated: true,
			allowChange: true
		} };
	}
	componentDidMount() {
		this.validate();
	}
	componentDidUpdate(prevProps, prevState) {
		const { linkValue } = this.state;
		if (!sameLink(linkValue.value.link, prevState.linkValue.value.link)) this.validate();
		if (linkValue !== prevState.linkValue && linkValue.validated && linkValue.allowChange) this.props.onChange(linkValue.value.link);
	}
	componentWillUnmount() {
		this.validationCancellation.abort();
	}
	validate() {
		const { editor, link: originalLink } = this.props;
		const { linkValue: { value } } = this.state;
		this.setState({ isValidating: true });
		this.validationCancellation.abort();
		this.validationCancellation = new Cancellation();
		const signal = this.validationCancellation.signal;
		validateLinkType(editor, value.link, originalLink).then((error) => {
			if (signal.aborted) return;
			this.setState(({ linkValue }) => ({
				linkValue: {
					...linkValue,
					...error,
					validated: true
				},
				isValidating: false
			}));
		});
	}
	render() {
		const { editor, view, metadataApi, source, target } = this.props;
		const { linkValue, isValidating } = this.state;
		const isValid = !linkValue.error;
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$10 }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$10}__body` }, /* @__PURE__ */ React.createElement(LinkTypeSelector, {
			editor,
			view,
			metadataApi,
			linkValue,
			source,
			target,
			onChange: (value) => this.setState({ linkValue: {
				value,
				error: void 0,
				validated: false,
				allowChange: false
			} })
		}), isValidating ? /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$10}__progress` }, /* @__PURE__ */ React.createElement(ProgressBar, {
			state: ProgressState.loading,
			height: 10
		})) : null), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$10}__controls` }, /* @__PURE__ */ React.createElement("button", {
			className: `graph-explorer-btn graph-explorer-btn-success ${CLASS_NAME$10}__apply-button`,
			onClick: () => this.props.onApply(linkValue.value.link),
			disabled: !isValid || isValidating
		}, "Apply"), /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-danger",
			onClick: this.props.onCancel
		}, "Cancel")));
	}
};
//#endregion
//#region src/graph-explorer/forms/editLinkLabelForm.tsx
var CLASS_NAME$9 = "graph-explorer-edit-form";
var EditLinkLabelForm = class extends React.Component {
	constructor(props) {
		super(props);
		const label = this.computeLabel();
		this.state = { label };
	}
	componentDidUpdate(prevProps) {
		if (this.props.link.typeId !== prevProps.link.typeId) {
			const label = this.computeLabel();
			this.setState({ label });
		}
	}
	computeLabel() {
		const { view, link } = this.props;
		const linkType = view.model.getLinkType(link.typeId);
		const { label = {} } = view.createLinkTemplate(linkType).renderLink(link);
		const labelTexts = label.attrs && label.attrs.text ? label.attrs.text.text : void 0;
		return labelTexts && labelTexts.length > 0 ? view.selectLabel(labelTexts).value : view.formatLabel(linkType.label, linkType.id);
	}
	render() {
		const { onApply, onCancel } = this.props;
		const { label } = this.state;
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$9 }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$9}__body` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$9}__form-row` }, /* @__PURE__ */ React.createElement("label", null, "Link Label"), /* @__PURE__ */ React.createElement("input", {
			className: "graph-explorer-form-control",
			value: label,
			onChange: (e) => this.setState({ label: e.target.value })
		}))), /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$9}__controls` }, /* @__PURE__ */ React.createElement("button", {
			className: `graph-explorer-btn graph-explorer-btn-success ${CLASS_NAME$9}__apply-button`,
			onClick: () => onApply(label)
		}, "Apply"), /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-danger",
			onClick: () => onCancel()
		}, "Cancel")));
	}
};
//#endregion
//#region src/graph-explorer/widgets/halo.tsx
var CLASS_NAME$8 = "graph-explorer-halo";
var Halo = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.targetListener = new EventObserver();
		this.queryDebouncer = new Debouncer();
		this.queryCancellation = new Cancellation();
		this.onElementEvent = (data) => {
			if (data.changePosition || data.changeSize || data.changeExpanded) this.forceUpdate();
			if (data.changeData) this.queryAllowedActions();
		};
		this.onEstablishNewLink = (e) => {
			const point = this.props.paperArea.pageToPaperCoords(e.pageX, e.pageY);
			this.props.onEstablishNewLink(point);
		};
		this.state = {};
	}
	componentDidMount() {
		const { editor, target } = this.props;
		this.listener.listen(editor.events, "changeAuthoringState", () => {
			this.queryAllowedActions();
		});
		this.listenToElement(target);
		this.queryAllowedActions();
	}
	componentDidUpdate(prevProps) {
		if (prevProps.target !== this.props.target) {
			this.listenToElement(this.props.target);
			this.queryAllowedActions();
		}
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.listenToElement(void 0);
		this.queryDebouncer.dispose();
		this.queryCancellation.abort();
	}
	listenToElement(element) {
		this.targetListener.stopListening();
		if (element) this.targetListener.listenAny(element.events, this.onElementEvent);
	}
	queryAllowedActions() {
		this.queryDebouncer.call(() => {
			this.queryCancellation.abort();
			this.queryCancellation = new Cancellation();
			this.canLink(this.props.target);
		});
	}
	canLink(target) {
		const { metadataApi, editor } = this.props;
		if (!metadataApi) {
			this.setState({ canLink: false });
			return;
		}
		const event = editor.authoringState.elements.get(target.iri);
		if (event && event.deleted) this.setState({ canLink: false });
		else {
			this.setState({ canLink: void 0 });
			const signal = this.queryCancellation.signal;
			CancellationToken.mapCancelledToNull(signal, metadataApi.canLinkElement(target.data, signal)).then((canLink) => {
				if (canLink === null) return;
				if (this.props.target.iri === target.iri) this.setState({ canLink });
			});
		}
	}
	render() {
		const { paperArea, editor, target, navigationMenuOpened, onToggleNavigationMenu, onAddToFilter, onExpand, onFollowLink } = this.props;
		if (!target) return /* @__PURE__ */ React.createElement("div", {
			className: CLASS_NAME$8,
			style: { display: "none" }
		});
		const bbox = boundsOf(target);
		const { x: x0, y: y0 } = paperArea.paperToScrollablePaneCoords(bbox.x, bbox.y);
		const { x: x1, y: y1 } = paperArea.paperToScrollablePaneCoords(bbox.x + bbox.width, bbox.y + bbox.height);
		const MARGIN = 5;
		const style = {
			left: x0 - MARGIN,
			top: y0 - MARGIN,
			width: x1 - x0 + MARGIN * 2,
			height: y1 - y0 + MARGIN * 2
		};
		return /* @__PURE__ */ React.createElement("div", {
			className: CLASS_NAME$8,
			style
		}, this.renderRemoveOrDeleteButton(), onToggleNavigationMenu && /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$8}__navigate ${CLASS_NAME$8}__navigate--${navigationMenuOpened ? "closed" : "open"}`,
			role: "button",
			title: "Open a dialog to navigate to connected elements",
			onClick: onToggleNavigationMenu
		}), onFollowLink && /* @__PURE__ */ React.createElement("a", {
			className: `${CLASS_NAME$8}__folow`,
			href: target.iri,
			role: "button",
			title: "Jump to resource",
			onClick: (e) => onFollowLink(target, e)
		}), onAddToFilter && /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$8}__add-to-filter`,
			role: "button",
			title: "Search for connected elements",
			onClick: onAddToFilter
		}), onExpand && /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$8}__expand ${CLASS_NAME$8}__expand--${target.isExpanded ? "closed" : "open"}`,
			role: "button",
			title: `Expand an element to reveal additional properties`,
			onClick: onExpand
		}), editor.inAuthoringMode ? this.renderEstablishNewLinkButton() : null);
	}
	renderRemoveOrDeleteButton() {
		const { editor, target, onRemove } = this.props;
		if (!onRemove) return null;
		const isNewElement = AuthoringState.isNewElement(editor.authoringState, target.iri);
		return /* @__PURE__ */ React.createElement("div", {
			className: isNewElement ? `${CLASS_NAME$8}__delete` : `${CLASS_NAME$8}__remove`,
			role: "button",
			title: isNewElement ? "Delete new element" : "Remove an element from the diagram",
			onClick: onRemove
		});
	}
	renderEstablishNewLinkButton() {
		const { onEstablishNewLink } = this.props;
		const { canLink } = this.state;
		if (!onEstablishNewLink) return null;
		if (canLink === void 0) return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$8}__establish-connection-spinner` }, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		}));
		const title = canLink ? "Establish connection" : "Establishing connection is unavailable for the selected element";
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$8}__establish-connection`,
			title,
			onMouseDown: this.onEstablishNewLink,
			disabled: !canLink
		});
	}
};
//#endregion
//#region src/graph-explorer/widgets/haloLink.tsx
var CLASS_NAME$7 = "graph-explorer-halo-link";
var BUTTON_SIZE = 20;
var HaloLink = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.targetListener = new EventObserver();
		this.queryDebouncer = new Debouncer();
		this.queryCancellation = new Cancellation();
		this.updateAll = () => this.forceUpdate();
		this.onSourceMove = (e) => {
			const point = this.props.paperArea.pageToPaperCoords(e.pageX, e.pageY);
			this.props.onSourceMove(point);
		};
		this.onTargetMove = (e) => {
			const point = this.props.paperArea.pageToPaperCoords(e.pageX, e.pageY);
			this.props.onTargetMove(point);
		};
		this.state = {};
	}
	componentDidMount() {
		const { target, editor } = this.props;
		this.listener.listen(editor.events, "changeAuthoringState", () => {
			this.queryAllowedActions();
		});
		this.listenToTarget(target);
		this.queryAllowedActions();
	}
	componentDidUpdate(prevProps) {
		if (prevProps.target !== this.props.target) {
			this.listenToTarget(this.props.target);
			this.queryAllowedActions();
		}
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.listenToTarget(void 0);
		this.queryDebouncer.dispose();
		this.queryCancellation.abort();
	}
	queryAllowedActions() {
		this.queryDebouncer.call(() => {
			this.queryCancellation.abort();
			this.queryCancellation = new Cancellation();
			this.queryCanDelete(this.props.target);
			this.queryCanEdit(this.props.target);
		});
	}
	queryCanDelete(link) {
		const { metadataApi, editor, view } = this.props;
		if (!metadataApi) {
			this.setState({ canDelete: false });
			return;
		}
		if (isSourceOrTargetDeleted(editor.authoringState, link)) this.setState({ canDelete: false });
		else {
			this.setState({ canDelete: void 0 });
			const source = view.model.getElement(link.sourceId);
			const target = view.model.getElement(link.targetId);
			const signal = this.queryCancellation.signal;
			CancellationToken.mapCancelledToNull(signal, metadataApi.canDeleteLink(link.data, source.data, target.data, signal)).then((canDelete) => {
				if (canDelete === null) return;
				if (this.props.target.id === link.id) this.setState({ canDelete });
			});
		}
	}
	queryCanEdit(link) {
		const { metadataApi, editor, view } = this.props;
		if (!metadataApi) {
			this.setState({ canEdit: false });
			return;
		}
		if (isDeletedLink(editor.authoringState, link)) this.setState({ canEdit: false });
		else {
			this.setState({ canEdit: void 0 });
			const source = view.model.getElement(link.sourceId);
			const target = view.model.getElement(link.targetId);
			const signal = this.queryCancellation.signal;
			CancellationToken.mapCancelledToNull(signal, metadataApi.canEditLink(link.data, source.data, target.data, signal)).then((canEdit) => {
				if (canEdit === null) return;
				if (this.props.target.id === link.id) this.setState({ canEdit });
			});
		}
	}
	listenToTarget(link) {
		const { view } = this.props;
		this.targetListener.stopListening();
		if (link) {
			const source = view.model.getElement(link.sourceId);
			const target = view.model.getElement(link.targetId);
			const listenToElement = (element) => {
				this.targetListener.listen(element.events, "changePosition", this.updateAll);
				this.targetListener.listen(element.events, "changeSize", this.updateAll);
			};
			listenToElement(source);
			listenToElement(target);
			this.targetListener.listen(link.events, "changeVertices", this.updateAll);
			this.targetListener.listen(link.events, "changeLabelBounds", this.updateAll);
		}
	}
	paperToScrollablePaneCoords(point) {
		return this.props.paperArea.paperToScrollablePaneCoords(point.x, point.y);
	}
	computePolyline() {
		const { view, target } = this.props;
		const sourceElement = view.model.getElement(target.sourceId);
		const targetElement = view.model.getElement(target.targetId);
		if (!(sourceElement && targetElement)) return;
		const route = view.getRouting(target.id);
		const verticesDefinedByUser = target.vertices || [];
		return computePolyline(sourceElement, targetElement, route ? route.vertices : verticesDefinedByUser);
	}
	calculateDegree(source, target) {
		const x = target.x - source.x;
		const y = target.y - source.y;
		const r = Math.sqrt(x * x + y * y);
		const unit = {
			x: x / r,
			y: y / r
		};
		return Math.atan2(unit.y, unit.x) * (180 / Math.PI);
	}
	renderSourceButton(polyline) {
		const { editor, target } = this.props;
		const point = getPointAlongPolyline(polyline, 0);
		const { x, y } = this.paperToScrollablePaneCoords(point);
		const style = {
			top: y - BUTTON_SIZE / 2,
			left: x - BUTTON_SIZE / 2
		};
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$7}__button`,
			style,
			disabled: isDeletedLink(editor.authoringState, target),
			onMouseDown: this.onSourceMove
		}, /* @__PURE__ */ React.createElement("svg", {
			width: BUTTON_SIZE,
			height: BUTTON_SIZE
		}, /* @__PURE__ */ React.createElement("g", { transform: `scale(${BUTTON_SIZE})` }, /* @__PURE__ */ React.createElement("circle", {
			r: .5,
			cx: .5,
			cy: .5,
			fill: "#198AD3"
		}))));
	}
	getButtonPosition(polyline, index) {
		const point = getPointAlongPolyline(polyline, computePolylineLength(polyline) - 25 * index);
		const { x, y } = this.paperToScrollablePaneCoords(point);
		return {
			top: y - BUTTON_SIZE / 2,
			left: x - BUTTON_SIZE / 2
		};
	}
	renderTargetButton(polyline) {
		const { editor, target } = this.props;
		const style = this.getButtonPosition(polyline, 0);
		const { length } = polyline;
		const degree = this.calculateDegree(polyline[length - 1], polyline[length - 2]);
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$7}__button`,
			style,
			disabled: isDeletedLink(editor.authoringState, target),
			onMouseDown: this.onTargetMove
		}, /* @__PURE__ */ React.createElement("svg", {
			width: BUTTON_SIZE,
			height: BUTTON_SIZE,
			style: { transform: `rotate(${degree}deg)` }
		}, /* @__PURE__ */ React.createElement("g", { transform: `scale(${BUTTON_SIZE})` }, /* @__PURE__ */ React.createElement("polygon", {
			points: "0,0.5 1,1 1,0",
			fill: "#198AD3"
		}))));
	}
	renderEditButton(polyline) {
		const { canEdit } = this.state;
		const style = this.getButtonPosition(polyline, 1);
		if (canEdit === void 0) return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$7}__spinner`,
			style
		}, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		}));
		const title = canEdit ? "Edit link" : "Editing is unavailable for the selected link";
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$7}__button ${CLASS_NAME$7}__edit`,
			style,
			title,
			onClick: this.props.onEdit,
			disabled: !canEdit
		});
	}
	renderDeleteButton(polyline) {
		const { canDelete } = this.state;
		const style = this.getButtonPosition(polyline, 2);
		if (canDelete === void 0) return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$7}__spinner`,
			style
		}, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 20,
			height: 20
		}));
		const title = canDelete ? "Delete link" : "Deletion is unavailable for the selected link";
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$7}__button ${CLASS_NAME$7}__delete`,
			style,
			title,
			onClick: this.props.onDelete,
			disabled: !canDelete
		});
	}
	renderEditLabelButton() {
		const { view, target, paperArea, onEditLabel } = this.props;
		const linkType = view.model.getLinkType(target.typeId);
		if (!view.createLinkTemplate(linkType).setLinkLabel || !target.labelBounds) return null;
		const { x, y, width, height } = target.labelBounds;
		const { x: left, y: top } = paperArea.paperToScrollablePaneCoords(x + width, y + height / 2);
		const size = {
			width: 15,
			height: 17
		};
		const style = {
			width: size.width,
			height: size.height,
			top: top - size.height / 2,
			left
		};
		return /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$7}__edit-label-button`,
			style,
			onClick: () => onEditLabel(),
			title: "Edit Link Label"
		});
	}
	render() {
		const { editor, target, metadataApi } = this.props;
		const polyline = this.computePolyline();
		if (!polyline) return null;
		const isAuthoringMode = Boolean(metadataApi);
		const deleteButton = isDeletedByItself(editor.authoringState, target) || isSourceOrTargetDeleted(editor.authoringState, target) ? null : this.renderDeleteButton(polyline);
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$7}` }, isAuthoringMode ? this.renderTargetButton(polyline) : null, isAuthoringMode ? this.renderSourceButton(polyline) : null, !isAuthoringMode || isDeletedLink(editor.authoringState, target) ? null : this.renderEditButton(polyline), isAuthoringMode ? deleteButton : null, this.renderEditLabelButton());
	}
};
function isDeletedLink(state, link) {
	return isDeletedByItself(state, link) || isSourceOrTargetDeleted(state, link);
}
function isDeletedByItself(state, link) {
	const event = state.links.get(link.data);
	return event && event.deleted;
}
function isSourceOrTargetDeleted(state, link) {
	const sourceEvent = state.elements.get(link.data.sourceId);
	const targetEvent = state.elements.get(link.data.targetId);
	return sourceEvent && sourceEvent.deleted || targetEvent && targetEvent.deleted;
}
//#endregion
//#region src/graph-explorer/editor/linkStateWidget.tsx
var CLASS_NAME$6 = `graph-explorer-authoring-state`;
var LINK_LABEL_MARGIN = 5;
var LinkStateWidget = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.listener = new EventObserver();
		this.delayedUpdate = new Debouncer();
		this.scheduleUpdate = () => {
			this.delayedUpdate.call(this.performUpdate);
		};
		this.performUpdate = () => {
			this.forceUpdate();
		};
	}
	componentDidMount() {
		this.listenEvents();
	}
	componentDidUpdate(prevProps) {
		if (!(this.props.view === prevProps.view)) {
			this.listener.stopListening();
			this.listenEvents();
		}
	}
	componentWillUnmount() {
		this.listener.stopListening();
	}
	listenEvents() {
		const { editor, view } = this.props;
		this.listener.listen(editor.model.events, "elementEvent", ({ data }) => {
			if (data.changeSize || data.changePosition) this.scheduleUpdate();
		});
		this.listener.listen(editor.model.events, "linkEvent", ({ data }) => {
			if (data.changeVertices || data.changeLabelBounds) this.scheduleUpdate();
		});
		this.listener.listen(editor.model.events, "changeCells", this.scheduleUpdate);
		this.listener.listen(editor.events, "changeAuthoringState", this.scheduleUpdate);
		this.listener.listen(editor.events, "changeTemporaryState", this.scheduleUpdate);
		this.listener.listen(editor.events, "changeValidationState", this.scheduleUpdate);
		this.listener.listen(view.events, "syncUpdate", ({ layer }) => {
			if (layer === RenderingLayer.Editor) this.delayedUpdate.runSynchronously();
		});
	}
	calculateLinkPath(link) {
		return "M" + this.calculatePolyline(link).map(({ x, y }) => `${x},${y}`).join(" L");
	}
	calculatePolyline(link) {
		const { editor, view } = this.props;
		const source = editor.model.getElement(link.sourceId);
		const target = editor.model.getElement(link.targetId);
		const route = view.getRouting(link.id);
		const verticesDefinedByUser = link.vertices || [];
		return computePolyline(source, target, route ? route.vertices : verticesDefinedByUser);
	}
	renderLinkStateLabels() {
		const { editor } = this.props;
		return editor.model.links.map((link) => {
			let renderedState = null;
			const state = editor.authoringState.links.get(link.data);
			if (state) {
				const onCancel = () => editor.discardChange(state);
				let statusText;
				let title;
				if (state.deleted) {
					statusText = "Delete";
					title = "Revert deletion of the link";
				} else if (!state.before) {
					statusText = "New";
					title = "Revert creation of the link";
				} else {
					statusText = "Change";
					title = "Revert all changes in properties of the link";
				}
				if (statusText && title) renderedState = /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", { className: `${CLASS_NAME$6}__state-label` }, statusText), "[", /* @__PURE__ */ React.createElement("span", {
					className: `${CLASS_NAME$6}__state-cancel`,
					onClick: onCancel,
					title
				}, "cancel"), "]");
			}
			const renderedErrors = this.renderLinkErrors(link.data);
			if (renderedState || renderedErrors) {
				const labelPosition = this.getLinkStateLabelPosition(link);
				if (!labelPosition) return null;
				const style = {
					left: labelPosition.x,
					top: labelPosition.y
				};
				return /* @__PURE__ */ React.createElement("div", {
					className: `${CLASS_NAME$6}__state-indicator`,
					key: link.id,
					style
				}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$6}__state-indicator-container` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$6}__state-indicator-body` }, renderedState, renderedErrors)));
			} else return null;
		});
	}
	renderLinkStateHighlighting() {
		const { editor } = this.props;
		return editor.model.links.map((link) => {
			if (editor.temporaryState.links.has(link.data)) {
				const path = this.calculateLinkPath(link);
				return /* @__PURE__ */ React.createElement("path", {
					key: link.id,
					d: path,
					fill: "none",
					stroke: "grey",
					strokeWidth: 5,
					strokeOpacity: .5,
					strokeDasharray: "8 8"
				});
			}
			const event = editor.authoringState.links.get(link.data);
			const isDeletedLink = AuthoringState.isDeletedLink(editor.authoringState, link.data);
			const isUncertainLink = AuthoringState.isUncertainLink(editor.authoringState, link.data);
			if (event || isDeletedLink || isUncertainLink) {
				const path = this.calculateLinkPath(link);
				let color;
				if (isDeletedLink) color = "red";
				else if (isUncertainLink) color = "blue";
				else if (event && event.type === AuthoringKind.ChangeLink) color = event.before ? "blue" : "green";
				return /* @__PURE__ */ React.createElement("path", {
					key: link.id,
					d: path,
					fill: "none",
					stroke: color,
					strokeWidth: 5,
					strokeOpacity: .5
				});
			}
			return null;
		});
	}
	getLinkStateLabelPosition(link) {
		if (link.labelBounds) {
			const { x, y } = link.labelBounds;
			return {
				x,
				y: y - LINK_LABEL_MARGIN / 2
			};
		} else {
			const polyline = this.calculatePolyline(link);
			return getPointAlongPolyline(polyline, computePolylineLength(polyline) / 2);
		}
	}
	renderLinkErrors(linkModel) {
		const { editor } = this.props;
		const { validationState } = editor;
		const validation = validationState.links.get(linkModel);
		if (!validation) return null;
		const title = validation.errors.map((error) => error.message).join("\n");
		return this.renderErrorIcon(title, validation);
	}
	renderErrorIcon(title, validation) {
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$6}__item-error`,
			title
		}, validation.loading ? /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 15,
			height: 17
		}) : /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$6}__item-error-icon` }), !validation.loading && validation.errors.length > 0 ? validation.errors.length : void 0);
	}
	render() {
		const { editor, paperTransform } = this.props;
		const { scale, originX, originY } = paperTransform;
		if (!editor.inAuthoringMode) return null;
		const htmlTransformStyle = {
			position: "absolute",
			left: 0,
			top: 0,
			transform: `scale(${scale},${scale})translate(${originX}px,${originY}px)`
		};
		return /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$6}` }, /* @__PURE__ */ React.createElement(TransformedSvgCanvas, {
			paperTransform,
			style: {
				overflow: "visible",
				pointerEvents: "none"
			}
		}, this.renderLinkStateHighlighting()), /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$6}__validation-layer`,
			style: htmlTransformStyle
		}, this.renderLinkStateLabels()));
	}
};
//#endregion
//#region src/graph-explorer/editor/elementDecorator.tsx
var CLASS_NAME$5 = `graph-explorer-authoring-state`;
var ElementDecorator = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		const { model, editor } = props;
		this.state = {
			state: editor.authoringState.elements.get(model.iri),
			validation: editor.validationState.elements.get(model.iri),
			isTemporary: editor.temporaryState.elements.has(model.iri)
		};
	}
	componentDidMount() {
		const { model, editor } = this.props;
		this.listener.listen(model.events, "changeSize", () => this.forceUpdate());
		this.listener.listen(editor.events, "changeAuthoringState", (e) => {
			const state = editor.authoringState.elements.get(model.iri);
			if (state === e.previous.elements.get(model.iri)) return;
			this.setState({ state });
		});
		this.listener.listen(editor.events, "changeValidationState", (e) => {
			const validation = editor.validationState.elements.get(model.iri);
			if (validation === e.previous.elements.get(model.iri)) return;
			this.setState({ validation });
		});
		this.listener.listen(editor.events, "changeTemporaryState", (e) => {
			const isTemporary = editor.temporaryState.elements.has(model.iri);
			if (isTemporary === e.previous.elements.has(model.iri)) return;
			this.setState({ isTemporary });
		});
		this.listener.listen(model.events, "changeData", (e) => {
			if (e.previous.id !== model.iri) this.setState({
				isTemporary: editor.temporaryState.elements.has(model.iri),
				validation: editor.validationState.elements.get(model.iri),
				state: editor.authoringState.elements.get(model.iri)
			});
		});
	}
	componentWillUnmount() {
		this.listener.stopListening();
	}
	shouldComponentUpdate(nextProps, nextState) {
		return this.state.state !== nextState.state || this.state.validation !== nextState.validation || this.state.isTemporary !== nextState.isTemporary || this.props.position !== nextProps.position;
	}
	renderElementOutlines() {
		const { model } = this.props;
		const { state, isTemporary } = this.state;
		const { width, height } = model.size;
		if (isTemporary) return [/* @__PURE__ */ React.createElement("rect", {
			key: `${model.id}-opacity`,
			x: 0,
			y: 0,
			width,
			height,
			fill: "rgba(255, 255, 255, 0.5)"
		}), /* @__PURE__ */ React.createElement("rect", {
			key: `${model.id}-stripes`,
			x: 0,
			y: 0,
			width,
			height,
			fill: "url(#stripe-pattern)"
		})];
		if (state && state.deleted) {
			const right = width;
			const bottom = height;
			return /* @__PURE__ */ React.createElement("g", { key: model.id }, /* @__PURE__ */ React.createElement("rect", {
				x: 0,
				y: 0,
				width,
				height,
				fill: "white",
				fillOpacity: .5
			}), /* @__PURE__ */ React.createElement("line", {
				x1: 0,
				y1: 0,
				x2: right,
				y2: bottom,
				stroke: "red"
			}), /* @__PURE__ */ React.createElement("line", {
				x1: right,
				y1: 0,
				x2: 0,
				y2: bottom,
				stroke: "red"
			}));
		}
		return null;
	}
	renderErrorIcon(title, validation) {
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$5}__item-error`,
			title
		}, validation.loading ? /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 15,
			height: 17
		}) : /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$5}__item-error-icon` }), !validation.loading && validation.errors.length > 0 ? validation.errors.length : void 0);
	}
	renderElementErrors() {
		const { view } = this.props;
		const { validation } = this.state;
		if (!validation) return null;
		const title = validation.errors.map((error) => {
			if (error.propertyType) {
				const { id, label } = view.model.createProperty(error.propertyType);
				return `${view.formatLabel(label, id)}: ${error.message}`;
			} else return error.message;
		}).join("\n");
		return this.renderErrorIcon(title, validation);
	}
	renderElementState() {
		const { model, editor } = this.props;
		const { state } = this.state;
		if (state) {
			const onCancel = () => editor.discardChange(state);
			let renderedState;
			let statusText;
			let title;
			if (state.deleted) {
				statusText = "Delete";
				title = "Revert deletion of the element";
			} else if (!state.before) {
				statusText = "New";
				title = "Revert creation of the element";
			} else {
				statusText = "Change";
				title = "Revert all changes in properties of the element";
			}
			if (statusText && title) renderedState = /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", { className: `${CLASS_NAME$5}__state-label` }, statusText), "[", /* @__PURE__ */ React.createElement("span", {
				className: `${CLASS_NAME$5}__state-cancel`,
				onClick: onCancel,
				title
			}, "cancel"), "]");
			const renderedErrors = this.renderElementErrors();
			if (renderedState || renderedErrors) return /* @__PURE__ */ React.createElement("div", {
				className: `${CLASS_NAME$5}__state-indicator`,
				key: model.id,
				style: {
					left: 0,
					top: 0
				}
			}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$5}__state-indicator-container` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$5}__state-indicator-body` }, renderedState, renderedErrors)));
		}
		return null;
	}
	render() {
		const { position, size } = this.props.model;
		const transform = `translate(${position.x}px,${position.y}px)`;
		const outlines = this.renderElementOutlines();
		const state = this.renderElementState();
		if (!outlines && !state) return null;
		return /* @__PURE__ */ React.createElement("div", { style: {
			position: "absolute",
			transform
		} }, outlines ? /* @__PURE__ */ React.createElement("svg", {
			width: size.width,
			height: size.height,
			style: {
				position: "absolute",
				pointerEvents: "none",
				overflow: "visible"
			}
		}, /* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("pattern", {
			id: "stripe-pattern",
			patternUnits: "userSpaceOnUse",
			width: 13,
			height: 13,
			patternTransform: "rotate(45)"
		}, /* @__PURE__ */ React.createElement("line", {
			x1: 0,
			y: 0,
			x2: 0,
			y2: 13,
			stroke: "#ddd",
			strokeWidth: 10,
			strokeOpacity: .2
		}))), this.renderElementOutlines()) : null, state);
	}
};
//#endregion
//#region src/graph-explorer/editor/temporaryState.ts
var TemporaryState = {
	empty: {
		elements: /* @__PURE__ */ new Map(),
		links: new HashMap(hashLink, sameLink)
	},
	addElement(state, element) {
		const elements = cloneMap(state.elements);
		elements.set(element.id, element);
		return {
			...state,
			elements
		};
	},
	deleteElement(state, element) {
		const elements = cloneMap(state.elements);
		elements.delete(element.id);
		return {
			...state,
			elements
		};
	},
	addLink(state, link) {
		const links = state.links.clone();
		links.set(link, link);
		return {
			...state,
			links
		};
	},
	deleteLink(state, link) {
		const links = state.links.clone();
		links.delete(link);
		return {
			...state,
			links
		};
	}
};
//#endregion
//#region src/graph-explorer/editor/editLayer.tsx
var EditLayerMode = /* @__PURE__ */ function(EditLayerMode) {
	EditLayerMode[EditLayerMode["establishLink"] = 0] = "establishLink";
	EditLayerMode[EditLayerMode["moveLinkSource"] = 1] = "moveLinkSource";
	EditLayerMode[EditLayerMode["moveLinkTarget"] = 2] = "moveLinkTarget";
	return EditLayerMode;
}({});
var EditLayer = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.cancellation = new Cancellation();
		this.canDropOnElementCancellation = new Cancellation();
		this.beginCreatingLink = (params) => {
			const { editor } = this.props;
			const { sourceId, point } = params;
			const temporaryElement = this.createTemporaryElement(point);
			const linkTemplate = new Link({
				typeId: PLACEHOLDER_LINK_TYPE,
				sourceId,
				targetId: temporaryElement.id
			});
			const temporaryLink = editor.createNewLink({
				link: linkTemplate,
				temporary: true
			});
			editor.model.createLinkType(temporaryLink.typeId).setVisibility({
				visible: true,
				showLabel: false
			});
			this.temporaryElement = temporaryElement;
			this.temporaryLink = temporaryLink;
		};
		this.onMouseMove = (e) => {
			const { view, paperArea } = this.props;
			const { targetElement, waitingForMetadata } = this.state;
			e.preventDefault();
			e.stopPropagation();
			if (waitingForMetadata) return;
			const point = paperArea.pageToPaperCoords(e.pageX, e.pageY);
			this.temporaryElement.setPosition(point);
			const newTargetElement = findElementAtPoint(view.model.elements, point);
			if (newTargetElement !== targetElement) this.queryCanDropOnElement(newTargetElement);
			this.setState({ targetElement: newTargetElement });
		};
		this.onMouseUp = (e) => {
			if (this.state.waitingForMetadata) return;
			this.setState({ waitingForMetadata: true });
			const selectedPosition = this.props.paperArea.pageToPaperCoords(e.pageX, e.pageY);
			this.executeEditOperation(selectedPosition);
		};
		this.createNewElement = async (source) => {
			const { editor, metadataApi } = this.props;
			if (!metadataApi) return;
			const elementTypes = await CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.typesOfElementsDraggedFrom(source, this.cancellation.signal));
			if (elementTypes === null) return;
			const classId = elementTypes.length === 1 ? elementTypes[0] : PLACEHOLDER_ELEMENT_TYPE;
			const elementModel = await CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.generateNewElement([classId], this.cancellation.signal));
			if (elementModel === null) return;
			return editor.createNewEntity({
				elementModel,
				temporary: true
			});
		};
		this.state = {};
	}
	componentDidMount() {
		const { mode, target, point } = this.props;
		if (mode === 0) this.beginCreatingLink({
			sourceId: target.id,
			point
		});
		else if (mode === 1 || mode === 2) this.beginMovingLink(target, point);
		else throw new Error("Unknown edit mode");
		this.forceUpdate();
		this.queryCanLinkFrom();
		this.queryCanDropOnCanvas();
		document.addEventListener("mousemove", this.onMouseMove);
		document.addEventListener("mouseup", this.onMouseUp);
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.cancellation.abort();
		this.canDropOnElementCancellation.abort();
		document.removeEventListener("mousemove", this.onMouseMove);
		document.removeEventListener("mouseup", this.onMouseUp);
	}
	beginMovingLink(target, startingPoint) {
		const { editor, mode } = this.props;
		if (!(mode === 1 || mode === 2)) throw new Error("Unexpected edit mode for moving link");
		this.oldLink = target;
		editor.model.removeLink(target.id);
		const { id: _id, typeId, sourceId, targetId, ...otherProps } = target;
		const temporaryElement = this.createTemporaryElement(startingPoint);
		const linkTemplate = new Link({
			typeId,
			sourceId: mode === 1 ? temporaryElement.id : sourceId,
			targetId: mode === 2 ? temporaryElement.id : targetId,
			...otherProps
		});
		const temporaryLink = editor.createNewLink({
			link: linkTemplate,
			temporary: true
		});
		this.temporaryElement = temporaryElement;
		this.temporaryLink = temporaryLink;
	}
	createTemporaryElement(point) {
		const temporaryElement = this.props.view.model.createTemporaryElement();
		temporaryElement.setPosition(point);
		return temporaryElement;
	}
	queryCanLinkFrom() {
		const { editor, metadataApi } = this.props;
		if (!metadataApi) {
			this.setState({ canLinkFrom: false });
			return;
		}
		this.setState({ canLinkFrom: void 0 });
		const source = editor.model.getElement(this.temporaryLink.sourceId);
		CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.canLinkElement(source.data, this.cancellation.signal)).then((canLinkFrom) => {
			if (canLinkFrom === null) return;
			this.setState({ canLinkFrom });
		}, (error) => {
			console.error("Error calling canLinkElement:", error);
			this.setState({ canLinkFrom: false });
		});
	}
	queryCanDropOnCanvas() {
		const { mode, editor, metadataApi } = this.props;
		if (!metadataApi || mode !== 0) {
			this.setState({ canDropOnCanvas: false });
			return;
		}
		this.setState({ canDropOnCanvas: void 0 });
		const source = editor.model.getElement(this.temporaryLink.sourceId);
		CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.canDropOnCanvas(source.data, this.cancellation.signal)).then((canDropOnCanvas) => {
			if (canDropOnCanvas === null) return;
			this.setState({ canDropOnCanvas });
		}, (error) => {
			console.error("Error calling canDropOnCanvas:", error);
			this.setState({ canDropOnCanvas: false });
		});
	}
	queryCanDropOnElement(targetElement) {
		const { mode, editor, metadataApi } = this.props;
		this.canDropOnElementCancellation.abort();
		this.canDropOnElementCancellation = new Cancellation();
		if (!(metadataApi && targetElement)) {
			this.setState({ canDropOnElement: false });
			return;
		}
		this.setState({ canDropOnElement: void 0 });
		let source;
		let target;
		if (mode === 0 || mode === 2) {
			source = editor.model.getElement(this.temporaryLink.sourceId).data;
			target = targetElement.data;
		} else if (mode === 1) {
			source = targetElement.data;
			target = editor.model.getElement(this.temporaryLink.targetId).data;
		}
		const signal = this.canDropOnElementCancellation.signal;
		CancellationToken.mapCancelledToNull(signal, metadataApi.canDropOnElement(source, target, signal)).then((canDropOnElement) => {
			if (canDropOnElement === null) return;
			this.setState({ canDropOnElement });
		});
	}
	async executeEditOperation(selectedPosition) {
		const { view, editor, mode } = this.props;
		try {
			const { targetElement, canLinkFrom, canDropOnCanvas, canDropOnElement } = this.state;
			if (this.oldLink) editor.model.addLink(this.oldLink);
			if (canLinkFrom && (targetElement ? canDropOnElement : canDropOnCanvas)) {
				let modifiedLink;
				let createdTarget = targetElement;
				switch (mode) {
					case 0: {
						if (!createdTarget) {
							const source = editor.model.getElement(this.temporaryLink.sourceId);
							createdTarget = await this.createNewElement(source.data);
							createdTarget.setPosition(selectedPosition);
							view.performSyncUpdate();
							centerElementAtPoint(createdTarget, selectedPosition);
						}
						const sourceElement = editor.model.getElement(this.temporaryLink.sourceId);
						modifiedLink = await this.createNewLink(sourceElement, createdTarget);
						break;
					}
					case 1:
						modifiedLink = editor.moveLinkSource({
							link: this.oldLink,
							newSource: targetElement
						});
						break;
					case 2:
						modifiedLink = editor.moveLinkTarget({
							link: this.oldLink,
							newTarget: targetElement
						});
						break;
					default: throw new Error("Unknown edit mode");
				}
				if (targetElement) {
					const focusedLink = modifiedLink || this.oldLink;
					editor.setSelection([focusedLink]);
					editor.showEditLinkForm(focusedLink);
				} else if (createdTarget && modifiedLink) {
					editor.setSelection([createdTarget]);
					const source = editor.model.getElement(modifiedLink.sourceId);
					editor.showEditElementTypeForm({
						link: modifiedLink,
						source,
						target: createdTarget,
						targetIsNew: true
					});
				}
			}
		} finally {
			this.cleanupAndFinish();
		}
	}
	async createNewLink(source, target) {
		const { editor, metadataApi } = this.props;
		if (!metadataApi) return;
		const linkTypes = await CancellationToken.mapCancelledToNull(this.cancellation.signal, metadataApi.possibleLinkTypes(source.data, target.data, this.cancellation.signal));
		if (linkTypes === null) return;
		const placeholder = {
			linkTypeIri: PLACEHOLDER_LINK_TYPE,
			direction: LinkDirection.out
		};
		const { linkTypeIri: typeId, direction } = linkTypes.length === 1 ? linkTypes[0] : placeholder;
		const data = {
			linkTypeId: typeId,
			sourceId: source.iri,
			targetId: target.iri
		};
		let [sourceId, targetId] = [source.id, target.id];
		if (direction === LinkDirection.in) {
			data.sourceId = target.iri;
			data.targetId = source.iri;
			[sourceId, targetId] = [targetId, sourceId];
		}
		const link = new Link({
			typeId,
			sourceId,
			targetId,
			data
		});
		return editor.model.findLink(link.typeId, link.sourceId, link.targetId) || editor.createNewLink({
			link,
			temporary: true
		});
	}
	cleanupAndFinish() {
		const { editor, onFinishEditing } = this.props;
		const batch = editor.model.history.startBatch();
		editor.model.removeElement(this.temporaryElement.id);
		editor.model.removeLink(this.temporaryLink.id);
		editor.setTemporaryState(TemporaryState.deleteLink(editor.temporaryState, this.temporaryLink.data));
		batch.discard();
		onFinishEditing();
	}
	render() {
		const { view, paperTransform } = this.props;
		const { waitingForMetadata } = this.state;
		if (!this.temporaryLink) return null;
		return /* @__PURE__ */ React.createElement(TransformedSvgCanvas, {
			paperTransform,
			style: { overflow: "visible" }
		}, /* @__PURE__ */ React.createElement(LinkMarkers, { view }), this.renderHighlight(), this.renderCanDropIndicator(), waitingForMetadata ? null : /* @__PURE__ */ React.createElement(LinkLayer, {
			view,
			links: [this.temporaryLink]
		}));
	}
	renderHighlight() {
		const { targetElement, canLinkFrom, canDropOnElement, waitingForMetadata } = this.state;
		if (!targetElement) return null;
		const { x, y, width, height } = boundsOf(targetElement);
		if (canLinkFrom === void 0 || canDropOnElement === void 0 || waitingForMetadata) return /* @__PURE__ */ React.createElement("g", { transform: `translate(${x},${y})` }, /* @__PURE__ */ React.createElement("rect", {
			width,
			height,
			fill: "white",
			fillOpacity: .5
		}), /* @__PURE__ */ React.createElement(Spinner, {
			size: 30,
			position: {
				x: width / 2,
				y: height / 2
			}
		}));
		const stroke = canLinkFrom && canDropOnElement ? "#5cb85c" : "#c9302c";
		return /* @__PURE__ */ React.createElement("rect", {
			x,
			y,
			width,
			height,
			fill: "transparent",
			stroke,
			strokeWidth: 3
		});
	}
	renderCanDropIndicator() {
		const { targetElement, canLinkFrom, canDropOnCanvas, waitingForMetadata } = this.state;
		if (targetElement) return null;
		const { x, y } = this.temporaryElement.position;
		let indicator;
		if (canLinkFrom === void 0 || canDropOnCanvas === void 0) indicator = /* @__PURE__ */ React.createElement(Spinner, {
			size: 1.2,
			position: {
				x: .5,
				y: -.5
			}
		});
		else if (canLinkFrom && canDropOnCanvas) indicator = /* @__PURE__ */ React.createElement("path", {
			d: "M0.5,0 L0.5,-1 M0,-0.5 L1,-0.5",
			strokeWidth: .2,
			stroke: "#5cb85c"
		});
		else indicator = /* @__PURE__ */ React.createElement("g", null, /* @__PURE__ */ React.createElement("circle", {
			cx: "0.5",
			cy: "-0.5",
			r: "0.5",
			fill: "none",
			strokeWidth: .2,
			stroke: "#c9302c"
		}), /* @__PURE__ */ React.createElement("path", {
			d: "M0.5,0 L0.5,-1",
			strokeWidth: .2,
			stroke: "#c9302c",
			transform: "rotate(-45 0.5 -0.5)"
		}));
		return /* @__PURE__ */ React.createElement("g", { transform: `translate(${x} ${y})scale(40)` }, /* @__PURE__ */ React.createElement("rect", {
			x: -.5,
			y: -.5,
			width: 1,
			height: 1,
			fill: "rgba(0, 0, 0, 0.1)",
			rx: .25,
			ry: .25
		}), waitingForMetadata ? /* @__PURE__ */ React.createElement(Spinner, { size: .8 }) : /* @__PURE__ */ React.createElement("g", { transform: `translate(0.5, -0.5)scale(0.25)` }, indicator));
	}
};
function centerElementAtPoint(element, point) {
	element.setPosition({
		x: point.x - element.size.width / 2,
		y: point.y - element.size.height / 2
	});
}
//#endregion
//#region src/graph-explorer/editor/validation.ts
var empty = createMutable();
var emptyElement = {
	loading: false,
	errors: []
};
var emptyLink = {
	loading: false,
	errors: []
};
function createMutable() {
	return {
		elements: /* @__PURE__ */ new Map(),
		links: new HashMap(hashLink, sameLink)
	};
}
function setElementErrors(state, target, errors) {
	const elements = cloneMap(state.elements);
	if (errors.length > 0) elements.set(target, {
		loading: false,
		errors
	});
	else elements.delete(target);
	return {
		...state,
		elements
	};
}
function setLinkErrors(state, target, errors) {
	const links = state.links.clone();
	if (errors.length > 0) links.set(target, {
		loading: false,
		errors
	});
	else links.delete(target);
	return {
		...state,
		links
	};
}
var ValidationState = {
	empty,
	emptyElement,
	emptyLink,
	createMutable,
	setElementErrors,
	setLinkErrors
};
function changedElementsToValidate(previousAuthoring, editor) {
	const currentAuthoring = editor.authoringState;
	const links = new HashMap(hashLink, sameLink);
	previousAuthoring.links.forEach((e, model) => links.set(model, true));
	currentAuthoring.links.forEach((e, model) => links.set(model, true));
	const toValidate = /* @__PURE__ */ new Set();
	links.forEach((value, linkModel) => {
		if (currentAuthoring.links.get(linkModel) !== previousAuthoring.links.get(linkModel)) toValidate.add(linkModel.sourceId);
	});
	for (const element of editor.model.elements) {
		const current = currentAuthoring.elements.get(element.iri);
		const previous = previousAuthoring.elements.get(element.iri);
		if (current !== previous) {
			toValidate.add(element.iri);
			if ((current || previous).deleted) {
				for (const link of element.links) if (link.data.sourceId !== element.iri) toValidate.add(link.data.sourceId);
			}
		}
	}
	return toValidate;
}
function validateElements(targets, validationApi, editor, cancellationToken) {
	const previousState = editor.validationState;
	const newState = ValidationState.createMutable();
	for (const element of editor.model.elements) {
		if (newState.elements.has(element.iri)) continue;
		const outboundLinks = element.links.reduce((acc, link) => {
			if (link.sourceId === element.id) acc.push(link.data);
			return acc;
		}, []);
		if (targets.has(element.iri)) {
			const event = {
				target: element.data,
				outboundLinks,
				state: editor.authoringState,
				model: editor.model,
				cancellation: cancellationToken
			};
			const result = CancellationToken.mapCancelledToNull(cancellationToken, validationApi.validate(event));
			const loadingElement = {
				loading: true,
				errors: []
			};
			const loadingLink = {
				loading: true,
				errors: []
			};
			newState.elements.set(element.iri, loadingElement);
			outboundLinks.forEach((link) => newState.links.set(link, loadingLink));
			processValidationResult(result, loadingElement, loadingLink, event, editor);
		} else {
			newState.elements.set(element.iri, previousState.elements.get(element.iri));
			for (const link of outboundLinks) newState.links.set(link, previousState.links.get(link));
		}
	}
	editor.setValidationState(newState);
}
async function processValidationResult(result, previousElement, previousLink, e, editor) {
	let allErrors;
	try {
		allErrors = await result;
		if (allErrors === null) return;
	} catch (err) {
		console.error(`Failed to validate element`, e.target, err);
		allErrors = [{
			type: "element",
			target: e.target.id,
			message: `Failed to validate element`
		}];
	}
	const elementErrors = [];
	const linkErrors = new HashMap(hashLink, sameLink);
	e.outboundLinks.forEach((link) => linkErrors.set(link, []));
	for (const error of allErrors) if (error.type === "element" && error.target === e.target.id) elementErrors.push(error);
	else if (error.type === "link" && linkErrors.has(error.target)) linkErrors.get(error.target).push(error);
	let state = editor.validationState;
	if (state.elements.get(e.target.id) === previousElement) state = ValidationState.setElementErrors(state, e.target.id, elementErrors);
	linkErrors.forEach((errors, link) => {
		if (state.links.get(link) === previousLink) state = ValidationState.setLinkErrors(state, link, errors);
	});
	editor.setValidationState(state);
}
//#endregion
//#region src/graph-explorer/editor/editorController.tsx
var EditorController = class {
	constructor(props) {
		this.listener = new EventObserver();
		this.source = new EventSource();
		this.events = this.source;
		this._authoringState = AuthoringState.empty;
		this._validationState = ValidationState.empty;
		this._temporaryState = TemporaryState.empty;
		this._selection = [];
		this.cancellation = new Cancellation();
		this.onKeyUp = (e) => {
			if (e.keyCode === 46 && document.activeElement.localName !== "input") this.removeSelectedElements();
		};
		const { model, view, ...options } = props;
		this.model = model;
		this.view = view;
		this.options = options;
		this.listener.listen(this.events, "changeValidationState", (e) => {
			for (const element of this.model.elements) {
				const previous = e.previous.elements.get(element.iri);
				if (this.validationState.elements.get(element.iri) !== previous) element.redraw();
			}
		});
		this.listener.listen(this.events, "changeAuthoringState", (e) => {
			if (this.options.validationApi) validateElements(changedElementsToValidate(e.previous, this), this.options.validationApi, this, this.cancellation.signal);
		});
		this.view._setElementDecorator((element) => /* @__PURE__ */ React.createElement(ElementDecorator, {
			model: element,
			view: this.view,
			editor: this,
			position: element.position
		}));
	}
	_initializePaperComponents(paperArea) {
		this.listener.listen(paperArea.events, "pointerUp", (e) => this.onPaperPointerUp(e));
		this.listener.listen(this.model.events, "changeCells", () => this.onCellsChanged());
		this.listener.listen(this.model.events, "elementEvent", (e) => {
			if (e.key === "requestedGroupContent") this.loadGroupContent(e.data.requestedGroupContent.source);
		});
		this.listener.listen(this.model.events, "loadingStart", () => this.setSpinner({}));
		this.listener.listen(this.model.events, "loadingSuccess", () => {
			this.setSpinner(void 0);
			const widget = /* @__PURE__ */ React.createElement(LinkStateWidget, {
				view: this.view,
				editor: this
			});
			this.view.setPaperWidget({
				key: "states",
				widget,
				attachment: WidgetAttachment.OverLinks
			});
		});
		this.listener.listen(this.model.events, "loadingError", ({ error }) => {
			const statusText = error ? error.message : void 0;
			this.setSpinner({
				statusText,
				errorOccured: true
			});
		});
		if (!this.options.disableHalo) {
			this.configureHalo();
			document.addEventListener("keyup", this.onKeyUp);
			this.listener.listen(this.view.events, "dispose", () => {
				document.removeEventListener("keyup", this.onKeyUp);
			});
		}
	}
	get inAuthoringMode() {
		return Boolean(this._metadataApi);
	}
	get metadataApi() {
		return this._metadataApi;
	}
	setMetadataApi(value) {
		const previous = this._metadataApi;
		if (value === previous) return;
		this._metadataApi = value;
		if (Boolean(value) !== Boolean(previous)) this.source.trigger("changeMode", { source: this });
	}
	get authoringState() {
		return this._authoringState;
	}
	setAuthoringState(value) {
		if (this._authoringState === value) return;
		this.model.history.execute(this.updateAuthoringState(value));
	}
	updateAuthoringState(state) {
		const previous = this._authoringState;
		return Command.create("Create or delete entities and links", () => {
			this._authoringState = state;
			this.source.trigger("changeAuthoringState", {
				source: this,
				previous
			});
			return this.updateAuthoringState(previous);
		});
	}
	get validationState() {
		return this._validationState;
	}
	setValidationState(value) {
		const previous = this._validationState;
		if (value === previous) return;
		this._validationState = value;
		this.source.trigger("changeValidationState", {
			source: this,
			previous
		});
	}
	get temporaryState() {
		return this._temporaryState;
	}
	setTemporaryState(value) {
		const previous = this._temporaryState;
		if (value === previous) return;
		this._temporaryState = value;
		this.source.trigger("changeTemporaryState", {
			source: this,
			previous
		});
	}
	get selection() {
		return this._selection;
	}
	setSelection(value) {
		const previous = this._selection;
		if (previous === value) return;
		this._selection = value;
		this.source.trigger("changeSelection", {
			source: this,
			previous
		});
	}
	cancelSelection() {
		this.setSelection([]);
	}
	removeSelectedElements() {
		const itemsToRemove = this.selection;
		if (itemsToRemove.length === 0) return;
		this.cancelSelection();
		this.removeItems(itemsToRemove);
	}
	removeItems(items) {
		const batch = this.model.history.startBatch();
		const deletedElementIris = /* @__PURE__ */ new Set();
		for (const item of items) if (item instanceof Element$1) {
			const event = this.authoringState.elements.get(item.iri);
			if (event) this.discardChange(event);
			this.model.removeElement(item.id);
			deletedElementIris.add(item.iri);
		} else if (item instanceof Link) {
			if (AuthoringState.isNewLink(this.authoringState, item.data)) this.deleteLink(item.data);
		}
		if (deletedElementIris.size > 0) {
			const newState = AuthoringState.deleteNewLinksConnectedToElements(this.authoringState, deletedElementIris);
			this.setAuthoringState(newState);
		}
		batch.store();
	}
	onPaperPointerUp(event) {
		if (this.options.disableHalo) return;
		const { sourceEvent, target, triggerAsClick } = event;
		if (sourceEvent.ctrlKey || sourceEvent.shiftKey || sourceEvent.metaKey) return;
		if (this.dialogTarget && this.dialogType === 1) return;
		if (target instanceof Element$1) {
			this.setSelection([target]);
			target.focus();
		} else if (target instanceof Link) this.setSelection([target]);
		else if (target instanceof LinkVertex) this.setSelection([target.link]);
		else if (!target && triggerAsClick) {
			this.setSelection([]);
			this.hideDialog();
			if (document.activeElement) document.activeElement.blur();
		}
	}
	onCellsChanged() {
		if (this.selection.length === 0) return;
		const newSelection = this.selection.filter((item) => item instanceof Element$1 ? this.model.getElement(item.id) : item instanceof Link ? this.model.getLinkById(item.id) : false);
		if (newSelection.length < this.selection.length) this.setSelection(newSelection);
	}
	setSpinner(props) {
		const widget = props ? /* @__PURE__ */ React.createElement(LoadingWidget, { spinnerProps: props }) : void 0;
		this.view.setPaperWidget({
			key: LoadingWidget.Key,
			widget,
			attachment: WidgetAttachment.Viewport
		});
	}
	configureHalo() {
		if (this.options.disableHalo) return;
		this.listener.listen(this.events, "changeSelection", () => {
			const selected = this.selection.length === 1 ? this.selection[0] : void 0;
			if (this.dialogTarget && selected !== this.dialogTarget) this.hideDialog();
			this.bringSelectedElementsToFront();
			this.renderDefaultHalo();
		});
		this.listener.listen(this.events, "toggleDialog", ({ isOpened: _isOpened }) => {
			this.renderDefaultHalo();
		});
		this.renderDefaultHalo();
	}
	bringSelectedElementsToFront() {
		if (this.selection.length === 0) return;
		this.model.reorderElements(makeMoveComparator(this.model.elements, this.selection.filter((item) => item instanceof Element$1), MoveDirection.ToEnd));
	}
	renderDefaultHalo() {
		const selected = this.selection.length === 1 ? this.selection[0] : void 0;
		let halo;
		if (selected instanceof Element$1) halo = /* @__PURE__ */ React.createElement(Halo, {
			editor: this,
			metadataApi: this.metadataApi,
			target: selected,
			onRemove: () => this.removeSelectedElements(),
			onExpand: () => {
				this.model.history.execute(setElementExpanded(selected, !selected.isExpanded));
			},
			navigationMenuOpened: this.dialogType === 0,
			onToggleNavigationMenu: () => {
				if (this.dialogTarget && this.dialogType === 0) this.hideDialog();
				else this.showConnectionsMenu(selected);
				this.renderDefaultHalo();
			},
			onAddToFilter: () => selected.addToFilter(),
			onEstablishNewLink: (point) => this.startEditing({
				target: selected,
				mode: EditLayerMode.establishLink,
				point
			}),
			onFollowLink: (element, e) => this.view.onIriClick(element.iri, element, IriClickIntent.JumpToEntity, e)
		});
		else if (selected instanceof Link) halo = /* @__PURE__ */ React.createElement(HaloLink, {
			view: this.view,
			editor: this,
			metadataApi: this.metadataApi,
			target: selected,
			onEdit: () => this.showEditLinkForm(selected),
			onDelete: () => this.deleteLink(selected.data),
			onSourceMove: (point) => this.startEditing({
				target: selected,
				mode: EditLayerMode.moveLinkSource,
				point
			}),
			onTargetMove: (point) => this.startEditing({
				target: selected,
				mode: EditLayerMode.moveLinkTarget,
				point
			}),
			onEditLabel: () => this.showEditLinkLabelForm(selected)
		});
		this.view.setPaperWidget({
			key: "halo",
			widget: halo,
			attachment: WidgetAttachment.OverElements
		});
	}
	showConnectionsMenu(target) {
		const dialogType = 0;
		const onClose = () => this.hideDialog();
		const content = /* @__PURE__ */ React.createElement(ConnectionsMenu, {
			view: this.view,
			editor: this,
			target,
			onAddElements: (iris, linkType) => this.onAddElementsInConnectionMenu(iris, target, linkType),
			onClose,
			suggestProperties: this.options.suggestProperties
		});
		this.showDialog({
			target,
			dialogType,
			content,
			onClose
		});
	}
	showEditEntityForm(target) {
		const { propertyEditor } = this.options;
		const dialogType = 1;
		const onSubmit = (newData) => {
			this.hideDialog();
			this.changeEntityData(target.data.id, newData);
		};
		const isIriModified = AuthoringState.isElementWithModifiedIri(this.authoringState, target.data.id);
		let modelToEdit;
		if (isIriModified) {
			const relatedEvent = this.authoringState.elements.get(target.data.id);
			modelToEdit = {
				...target.data,
				id: relatedEvent.newIri
			};
		} else modelToEdit = target.data;
		const onCancel = () => this.hideDialog();
		const content = propertyEditor ? propertyEditor({
			elementData: target.data,
			onSubmit,
			onCancel
		}) : /* @__PURE__ */ React.createElement(EditEntityForm, {
			view: this.view,
			entity: modelToEdit,
			onApply: onSubmit,
			onCancel
		});
		this.showDialog({
			target,
			dialogType,
			content,
			onClose: onCancel
		});
	}
	showEditElementTypeForm({ link, source, target, targetIsNew }) {
		const dialogType = 3;
		const onCancel = () => {
			this.removeTemporaryElement(target);
			this.removeTemporaryLink(link);
			this.hideDialog();
		};
		const content = /* @__PURE__ */ React.createElement(EditElementTypeForm, {
			editor: this,
			view: this.view,
			metadataApi: this.metadataApi,
			link: link.data,
			source: source.data,
			target: {
				value: target.data,
				isNew: targetIsNew
			},
			onChangeElement: (data) => {
				const previous = target.data;
				this.setTemporaryState(TemporaryState.deleteElement(this.temporaryState, previous));
				target.setData(data);
				this.setTemporaryState(TemporaryState.addElement(this.temporaryState, data));
			},
			onChangeLink: (data) => {
				this.removeTemporaryLink(link);
				const newLink = makeLinkWithDirection(new Link({
					typeId: data.linkTypeId,
					sourceId: source.id,
					targetId: target.id,
					data: {
						...data,
						sourceId: source.iri,
						targetId: target.iri
					}
				}), data);
				link = this.createNewLink({
					link: newLink,
					temporary: true
				});
			},
			onApply: (elementData, isNewElement, linkData) => {
				this.removeTemporaryElement(target);
				this.removeTemporaryLink(link);
				const batch = this.model.history.startBatch(isNewElement ? "Create new entity" : "Link to entity");
				this.model.addElement(target);
				if (isNewElement) {
					target.setExpanded(true);
					this.setAuthoringState(AuthoringState.addElement(this._authoringState, target.data));
				} else this.model.requestLinksOfType();
				const newLink = makeLinkWithDirection(new Link({
					typeId: link.typeId,
					sourceId: source.id,
					targetId: target.id,
					data: {
						...link.data,
						sourceId: source.iri,
						targetId: target.iri
					}
				}), linkData);
				this.createNewLink({ link: newLink });
				batch.store();
				this.hideDialog();
				if (isNewElement) this.showEditEntityForm(target);
			},
			onCancel
		});
		this.showDialog({
			target,
			dialogType,
			content,
			caption: "Establish New Connection",
			onClose: onCancel
		});
	}
	showEditLinkForm(link) {
		const dialogType = 2;
		const source = this.model.getElement(link.sourceId).data;
		const target = this.model.getElement(link.targetId).data;
		const onCancel = () => {
			if (this.temporaryState.links.has(link.data)) this.removeTemporaryLink(link);
			this.hideDialog();
		};
		const content = /* @__PURE__ */ React.createElement(EditLinkForm, {
			editor: this,
			view: this.view,
			metadataApi: this.metadataApi,
			link: link.data,
			source,
			target,
			onChange: (data) => {
				if (this.temporaryState.links.has(link.data)) {
					this.removeTemporaryLink(link);
					const newLink = makeLinkWithDirection(link, data);
					this.showEditLinkForm(this.createNewLink({
						link: newLink,
						temporary: true
					}));
				}
			},
			onApply: (data) => {
				if (this.temporaryState.links.has(link.data)) {
					this.removeTemporaryLink(link);
					const newLink = makeLinkWithDirection(link, data);
					this.createNewLink({ link: newLink });
				} else this.changeLink(link.data, data);
				this.hideDialog();
			},
			onCancel
		});
		const caption = this.temporaryState.links.has(link.data) ? "Establish New Connection" : "Edit Connection";
		this.showDialog({
			target: link,
			dialogType,
			content,
			size: {
				width: 300,
				height: 160
			},
			caption,
			onClose: onCancel
		});
	}
	showEditLinkLabelForm(link) {
		const linkType = this.view.model.getLinkType(link.typeId);
		const template = this.view.createLinkTemplate(linkType);
		const size = {
			width: 300,
			height: 145
		};
		const onCancel = () => this.hideDialog();
		this.showDialog({
			target: link,
			dialogType: 4,
			content: /* @__PURE__ */ React.createElement(EditLinkLabelForm, {
				view: this.view,
				link,
				onApply: (label) => {
					template.setLinkLabel(link, label);
					this.hideDialog();
				},
				onCancel
			}),
			size,
			caption: "Edit Link Label",
			offset: {
				x: 25,
				y: -size.height / 2
			},
			calculatePosition: () => {
				const { x, y, width, height } = link.labelBounds;
				return {
					x: x + width,
					y: y + height / 2
				};
			},
			onClose: onCancel
		});
	}
	showDialog(params) {
		const { target, dialogType, content, size, caption, offset, calculatePosition, onClose } = params;
		this.dialogTarget = target;
		this.dialogType = dialogType;
		const dialog = /* @__PURE__ */ React.createElement(Dialog, {
			view: this.view,
			target,
			size,
			caption,
			offset,
			calculatePosition,
			onClose
		}, content);
		this.view.setPaperWidget({
			key: "dialog",
			widget: dialog,
			attachment: WidgetAttachment.OverElements
		});
		this.source.trigger("toggleDialog", { isOpened: true });
	}
	hideDialog() {
		if (this.dialogTarget) {
			const isTemporaryElement = this.dialogTarget instanceof Element$1 && this.temporaryState.elements.has(this.dialogTarget.iri);
			const isTemporaryLink = this.dialogTarget instanceof Link && this.temporaryState.links.has(this.dialogTarget.data);
			if (isTemporaryElement || isTemporaryLink) this.resetTemporaryState();
			this.dialogType = void 0;
			this.dialogTarget = void 0;
			this.view.setPaperWidget({
				key: "dialog",
				widget: void 0,
				attachment: WidgetAttachment.OverElements
			});
			this.source.trigger("toggleDialog", { isOpened: false });
		}
	}
	onDragDrop(dragged, paperPosition) {
		const batch = this.model.history.startBatch("Drag and drop onto diagram");
		const placedElements = placeElements(this.view, dragged, paperPosition);
		const irisToLoad = placedElements.map((elem) => elem.iri);
		batch.history.execute(requestElementData(this.model, irisToLoad));
		batch.history.execute(restoreLinksBetweenElements(this.model));
		batch.store();
		if (placedElements.length > 0) placedElements[placedElements.length - 1].focus();
		this.setSelection(placedElements);
		this.source.trigger("addElements", { elements: placedElements });
	}
	onAddElementsInConnectionMenu(elementIris, targetElement, linkType) {
		const batch = this.view.model.history.startBatch();
		const elements = elementIris.map((iri) => this.model.createElement(iri));
		this.view.performSyncUpdate();
		placeElementsAround({
			model: this.model,
			elements,
			targetElement,
			prefferedLinksLength: 300
		}).then(() => {
			this.source.trigger("addElements", { elements });
		});
		if (linkType && !linkType.visible) batch.history.execute(changeLinkTypeVisibility({
			linkType,
			visible: true,
			showLabel: true,
			preventLoading: true
		}));
		batch.history.execute(requestElementData(this.model, elementIris));
		batch.history.execute(restoreLinksBetweenElements(this.model));
		batch.store();
	}
	loadGroupContent(element) {
		return this.model.loadEmbeddedElements(element.iri).then((models) => {
			const batch = this.model.history.startBatch();
			const elementIris = Object.keys(models);
			elementIris.map((key) => this.model.createElement(models[key], element.id));
			batch.discard();
			return Promise.all([this.model.requestElementData(elementIris), this.model.requestLinksOfType()]).then(() => {
				this.view.performSyncUpdate();
				applyLayout(this.model, forceLayout({
					model: this.model,
					group: element.id
				}));
				this.model.triggerChangeGroupContent(element.id);
			});
		});
	}
	createNewEntity({ elementModel, temporary }) {
		const batch = this.model.history.startBatch("Create new entity");
		const element = this.model.createElement(elementModel);
		element.setExpanded(true);
		if (temporary) {
			this.setTemporaryState(TemporaryState.addElement(this.temporaryState, element.data));
			batch.discard();
		} else {
			this.setAuthoringState(AuthoringState.addElement(this._authoringState, element.data));
			batch.store();
		}
		return element;
	}
	changeEntityData(targetIri, newData) {
		const elements = this.model.elements.filter((el) => el.iri === targetIri);
		if (elements.length === 0) return;
		const oldData = elements[0].data;
		const batch = this.model.history.startBatch("Edit entity");
		const newState = AuthoringState.changeElement(this._authoringState, oldData, newData);
		const event = newState.elements.get(targetIri) || newState.elements.get(newData.id);
		this.model.history.execute(setElementData(this.model, targetIri, event.after));
		this.setAuthoringState(newState);
		batch.store();
	}
	deleteEntity(elementIri) {
		const state = this.authoringState;
		const elements = this.model.elements.filter((el) => el.iri === elementIri);
		if (elements.length === 0) return;
		const batch = this.model.history.startBatch("Delete entity");
		const model = elements[0].data;
		const event = state.elements.get(elementIri);
		const linksToRemove = /* @__PURE__ */ new Set();
		for (const element of elements) for (const link of element.links) if (link.data && AuthoringState.isNewLink(state, link.data)) linksToRemove.add(link.id);
		linksToRemove.forEach((linkId) => this.model.removeLink(linkId));
		if (event) this.discardChange(event);
		this.setAuthoringState(AuthoringState.deleteElement(state, model));
		batch.store();
	}
	createNewLink(params) {
		const { link: base, temporary } = params;
		if (this.model.findLink(base.typeId, base.sourceId, base.targetId)) throw Error("The link already exists");
		const batch = this.model.history.startBatch("Create new link");
		const addedLink = this.model.addLink(base);
		if (!temporary) this.model.createLinks(base.data);
		if (this.model.links.filter((link) => sameLink(link.data, base.data)).length > 0) if (temporary) {
			this.setTemporaryState(TemporaryState.addLink(this.temporaryState, base.data));
			batch.discard();
		} else {
			this.setAuthoringState(AuthoringState.addLink(this._authoringState, base.data));
			batch.store();
		}
		else batch.discard();
		return addedLink;
	}
	changeLink(oldData, newData) {
		const batch = this.model.history.startBatch("Change link");
		if (sameLink(oldData, newData)) {
			this.model.history.execute(setLinkData(this.model, oldData, newData));
			this.setAuthoringState(AuthoringState.changeLink(this._authoringState, oldData, newData));
		} else {
			let newState = this._authoringState;
			newState = AuthoringState.deleteLink(newState, oldData);
			newState = AuthoringState.addLink(newState, newData);
			if (AuthoringState.isNewLink(this._authoringState, oldData)) this.model.links.filter((link) => sameLink(link.data, oldData)).forEach((link) => this.model.removeLink(link.id));
			this.model.createLinks(newData);
			this.setAuthoringState(newState);
		}
		batch.store();
	}
	moveLinkSource(params) {
		const { link, newSource } = params;
		const batch = this.model.history.startBatch("Move link to another element");
		this.changeLink(link.data, {
			...link.data,
			sourceId: newSource.iri
		});
		const newLink = this.model.findLink(link.typeId, newSource.id, link.targetId);
		newLink.setVertices(link.vertices);
		batch.store();
		return newLink;
	}
	moveLinkTarget(params) {
		const { link, newTarget } = params;
		const batch = this.model.history.startBatch("Move link to another element");
		this.changeLink(link.data, {
			...link.data,
			targetId: newTarget.iri
		});
		const newLink = this.model.findLink(link.typeId, link.sourceId, newTarget.id);
		newLink.setVertices(link.vertices);
		batch.store();
		return newLink;
	}
	deleteLink(model) {
		const state = this.authoringState;
		if (AuthoringState.isDeletedLink(state, model)) return;
		const batch = this.model.history.startBatch("Delete link");
		const newState = AuthoringState.deleteLink(state, model);
		if (AuthoringState.isNewLink(state, model)) this.model.links.filter(({ data }) => sameLink(data, model)).forEach((link) => this.model.removeLink(link.id));
		this.setAuthoringState(newState);
		batch.store();
	}
	startEditing(params) {
		const { target, mode, point } = params;
		const onFinishEditing = () => {
			this.view.setPaperWidget({
				key: "editLayer",
				widget: void 0,
				attachment: WidgetAttachment.OverElements
			});
		};
		const editLayer = /* @__PURE__ */ React.createElement(EditLayer, {
			view: this.view,
			editor: this,
			metadataApi: this.metadataApi,
			mode,
			target,
			point,
			onFinishEditing
		});
		this.view.setPaperWidget({
			key: "editLayer",
			widget: editLayer,
			attachment: WidgetAttachment.OverElements
		});
	}
	resetTemporaryState() {
		if (this.temporaryState.elements.size) this.model.elements.forEach((element) => {
			if (this.temporaryState.elements.has(element.iri)) this.removeTemporaryElement(element);
		});
		if (this.temporaryState.links.size) this.model.links.forEach((link) => {
			if (this.temporaryState.links.get(link.data)) this.removeTemporaryLink(link);
		});
	}
	removeTemporaryElement(element) {
		const batch = this.model.history.startBatch();
		this.model.removeElement(element.id);
		batch.discard();
		this.setTemporaryState(TemporaryState.deleteElement(this.temporaryState, element.data));
	}
	removeTemporaryLink(link) {
		this.model.removeLink(link.id);
		this.setTemporaryState(TemporaryState.deleteLink(this.temporaryState, link.data));
	}
	discardChange(event) {
		const newState = AuthoringState.discard(this._authoringState, event);
		if (newState === this._authoringState) return;
		const batch = this.model.history.startBatch("Discard change");
		if (event.type === AuthoringKind.ChangeElement) if (event.deleted) {} else if (event.before) this.model.history.execute(setElementData(this.model, event.after.id, event.before));
		else this.model.elements.filter((el) => el.iri === event.after.id).forEach((el) => this.model.removeElement(el.id));
		else if (event.type === AuthoringKind.ChangeLink) if (event.deleted) {} else if (event.before) this.model.history.execute(setLinkData(this.model, event.after, event.before));
		else this.model.links.filter(({ data }) => sameLink(data, event.after)).forEach((link) => this.model.removeLink(link.id));
		this.setAuthoringState(newState);
		batch.store();
	}
};
var LoadingWidget = class extends React.Component {
	static {
		this.Key = "loadingWidget";
	}
	render() {
		const { spinnerProps, paperArea } = this.props;
		const areaMetrics = paperArea.getAreaMetrics();
		const paneWidth = areaMetrics.clientWidth;
		const paneHeight = areaMetrics.clientHeight;
		const position = {
			x: spinnerProps.statusText ? paneWidth / 3 : paneWidth / 2,
			y: paneHeight / 2
		};
		return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-loading-widget" }, /* @__PURE__ */ React.createElement("svg", {
			width: paneWidth,
			height: paneHeight
		}, /* @__PURE__ */ React.createElement(Spinner, {
			position,
			...spinnerProps
		})));
	}
};
function placeElements(view, dragged, position) {
	const elements = dragged.map((item) => view.model.createElement(item));
	for (const element of elements) element.setPosition(position);
	view.performSyncUpdate();
	let { x, y } = position;
	let isFirst = true;
	for (const element of elements) {
		let { width, height } = boundsOf(element);
		if (width === 0) width = 100;
		if (height === 0) height = 50;
		if (isFirst) {
			isFirst = false;
			x -= width / 2;
			y -= height / 2;
		}
		element.setPosition({
			x,
			y
		});
		y += height + 20;
	}
	return elements;
}
function makeLinkWithDirection(original, data) {
	if (!(data.sourceId === original.data.sourceId || data.sourceId === original.data.targetId)) throw new Error("New link source IRI is unrelated to original link");
	if (!(data.targetId === original.data.sourceId || data.targetId === original.data.targetId)) throw new Error("New link target IRI is unrelated to original link");
	const sourceId = data.sourceId === original.data.sourceId ? original.sourceId : original.targetId;
	const targetId = data.targetId === original.data.targetId ? original.targetId : original.sourceId;
	return new Link({
		typeId: data.linkTypeId,
		sourceId,
		targetId,
		data
	});
}
//#endregion
//#region src/graph-explorer/workspace/toolbar.tsx
var CLASS_NAME$4 = "graph-explorer-toolbar";
var CLEAR_ALL_ARM_TIMEOUT = 4e3;
var DefaultToolbar = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.state = {};
		this.onClearAllClick = () => {
			if (this.state.clearAllArmed) {
				this.clearClearAllTimeout();
				this.setState({ clearAllArmed: false });
				this.props.onClearAll();
			} else {
				this.clearClearAllTimeout();
				this.clearAllTimeout = setTimeout(() => {
					this.setState({ clearAllArmed: false });
				}, CLEAR_ALL_ARM_TIMEOUT);
				this.setState({ clearAllArmed: true });
			}
		};
		this.onChangeLanguage = (event) => {
			const value = event.currentTarget.value;
			this.props.onChangeLanguage(value);
		};
		this.onExportSVG = () => {
			this.props.onExportSVG();
		};
		this.onExportPNG = () => {
			this.props.onExportPNG();
		};
	}
	componentWillUnmount() {
		this.clearClearAllTimeout();
	}
	clearClearAllTimeout() {
		if (this.clearAllTimeout !== void 0) {
			clearTimeout(this.clearAllTimeout);
			this.clearAllTimeout = void 0;
		}
	}
	renderSaveDiagramButton() {
		if (!this.props.onSaveDiagram) return null;
		return /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "saveDiagramButton graph-explorer-btn graph-explorer-btn-primary",
			disabled: this.props.canSaveDiagram === false,
			onClick: this.props.onSaveDiagram
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-floppy-o",
			"aria-hidden": "true"
		}), " Save diagram");
	}
	renderPersistAuthoredChangesButton() {
		if (!this.props.onPersistChanges) return null;
		return /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "saveDiagramButton graph-explorer-btn graph-explorer-btn-success",
			disabled: this.props.canPersistChanges === false,
			onClick: this.props.onPersistChanges
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-floppy-o",
			"aria-hidden": "true"
		}), " Save data");
	}
	renderLanguages() {
		const { selectedLanguage, languages } = this.props;
		if (languages.length <= 1) return null;
		return /* @__PURE__ */ React.createElement("span", { className: `graph-explorer-btn-group ${CLASS_NAME$4}__language-selector` }, /* @__PURE__ */ React.createElement("label", { className: "graph-explorer-label" }, /* @__PURE__ */ React.createElement("span", null, "Data Language")), /* @__PURE__ */ React.createElement("select", {
			value: selectedLanguage,
			onChange: this.onChangeLanguage
		}, languages.map(({ code, label }) => /* @__PURE__ */ React.createElement("option", {
			key: code,
			value: code
		}, label))));
	}
	render() {
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$4 }, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-btn-group graph-explorer-btn-group-sm" }, this.renderSaveDiagramButton(), this.renderPersistAuthoredChangesButton(), this.props.onClearAll ? /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: this.state.clearAllArmed ? "graph-explorer-btn graph-explorer-btn-danger" : "graph-explorer-btn graph-explorer-btn-default",
			title: this.state.clearAllArmed ? "Click again to confirm" : "Clear All",
			onClick: this.onClearAllClick,
			onBlur: () => this.setState({ clearAllArmed: false })
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-trash",
			"aria-hidden": "true"
		}), "\xA0", this.state.clearAllArmed ? "Are you sure?" : "Clear All") : null, /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Force layout",
			onClick: this.props.onForceLayout
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-sitemap",
			"aria-hidden": "true"
		}), " Layout"), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Zoom In",
			onClick: this.props.onZoomIn
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-search-plus",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Zoom Out",
			onClick: this.props.onZoomOut
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-search-minus",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Fit to Screen",
			onClick: this.props.onZoomToFit
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-arrows-alt",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Export diagram as PNG",
			onClick: this.onExportPNG
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-picture-o",
			"aria-hidden": "true"
		}), " PNG"), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Export diagram as SVG",
			onClick: this.onExportSVG
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-picture-o",
			"aria-hidden": "true"
		}), " SVG"), /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Print diagram",
			onClick: this.props.onPrint
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-print",
			"aria-hidden": "true"
		})), this.renderLanguages()));
	}
};
//#endregion
//#region src/graph-explorer/widgets/navigator.tsx
var CLASS_NAME$3 = "graph-explorer-navigator";
var MIN_SCALE = .25;
var Navigator = class extends React.Component {
	static {
		this.defaultProps = {
			width: 300,
			height: 160,
			scalePadding: .2,
			expanded: true
		};
	}
	constructor(props, context) {
		super(props, context);
		this.delayedRedraw = new Debouncer();
		this.listener = new EventObserver();
		this.scheduleRedraw = () => {
			if (this.state.expanded) this.delayedRedraw.call(this.draw);
		};
		this.draw = () => {
			const { paperTransform: pt, width, height } = this.props;
			this.calculateTransform();
			const ctx = this.canvas.getContext("2d");
			ctx.fillStyle = "#EEEEEE";
			ctx.clearRect(0, 0, width, height);
			ctx.fillRect(0, 0, width, height);
			const paneStart = paneTopLeft(pt);
			const paneSize = totalPaneSize(pt);
			const paneEnd = {
				x: paneStart.x + paneSize.x,
				y: paneStart.y + paneSize.y
			};
			const start = canvasFromPaneCoords(paneStart, pt, this.transform);
			const end = canvasFromPaneCoords(paneEnd, pt, this.transform);
			ctx.fillStyle = "white";
			ctx.fillRect(start.x, start.y, end.x - start.x, end.y - start.y);
			ctx.save();
			this.drawElements(ctx);
			this.drawViewport(ctx);
			ctx.restore();
		};
		this.onDragViewport = (e) => {
			e.preventDefault();
			if (this.isDraggingViewport) {
				const paper = paperFromCanvasCoords(this.canvasFromPageCoords(e.pageX, e.pageY), this.props.paperTransform, this.transform);
				this.props.paperArea.centerTo(paper);
			}
		};
		this.onMouseUp = () => {
			this.stopDraggingViewport();
		};
		this.onWheel = (e) => {
			e.preventDefault();
			const delta = Math.max(-1, Math.min(1, e.deltaY || e.deltaX));
			this.props.paperArea.zoomBy(-delta * .1);
		};
		this.onToggleClick = () => {
			this.setState((state) => ({ expanded: !state.expanded }), this.scheduleRedraw);
		};
		this.state = { expanded: this.props.expanded };
	}
	componentDidMount() {
		const { view, paperArea } = this.props;
		this.listener.listen(view.events, "changeHighlight", this.scheduleRedraw);
		this.listener.listen(view.model.events, "changeCells", this.scheduleRedraw);
		this.listener.listen(view.model.events, "elementEvent", this.scheduleRedraw);
		this.listener.listen(paperArea.events, "pointerMove", this.scheduleRedraw);
		this.listener.listen(paperArea.events, "scroll", this.scheduleRedraw);
	}
	shouldComponentUpdate(nextProps, nextState) {
		return nextState !== this.state;
	}
	componentWillUnmount() {
		this.delayedRedraw.dispose();
		this.listener.stopListening();
		this.stopDraggingViewport();
	}
	drawElements(ctx) {
		const { view, paperTransform: pt } = this.props;
		view.model.elements.forEach((element) => {
			const { position, size } = element;
			ctx.fillStyle = this.chooseElementColor(element);
			const { x: x1, y: y1 } = canvasFromPaperCoords(position, pt, this.transform);
			const { x: x2, y: y2 } = canvasFromPaperCoords({
				x: position.x + size.width,
				y: position.y + size.height
			}, pt, this.transform);
			ctx.fillRect(x1, y1, x2 - x1, y2 - y1);
		});
	}
	chooseElementColor(element) {
		const { view } = this.props;
		if (view.highlighter && !view.highlighter(element)) return "lightgray";
		const { color: { h, c, l } } = view.getTypeStyle(element.data.types);
		return hcl(h, c, l).toString();
	}
	drawViewport(ctx) {
		const { paperArea, paperTransform: pt, width, height } = this.props;
		ctx.strokeStyle = "#337ab7";
		ctx.lineWidth = 2;
		const { clientWidth, clientHeight } = paperArea.getAreaMetrics();
		const viewportStart = paperArea.clientToScrollablePaneCoords(0, 0);
		const viewportEnd = paperArea.clientToScrollablePaneCoords(clientWidth, clientHeight);
		const { x: x1, y: y1 } = canvasFromPaneCoords(viewportStart, pt, this.transform);
		const { x: x2, y: y2 } = canvasFromPaneCoords(viewportEnd, pt, this.transform);
		ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
		ctx.beginPath();
		if (x1 < 0) {
			ctx.moveTo(0, y1);
			ctx.lineTo(0, y2);
		}
		if (y1 < 0) {
			ctx.moveTo(x1, 0);
			ctx.lineTo(x2, 0);
		}
		if (x2 > width) {
			ctx.moveTo(width, y1);
			ctx.lineTo(width, y2);
		}
		if (y2 > height) {
			ctx.moveTo(x1, height);
			ctx.lineTo(x2, height);
		}
		ctx.lineWidth = 4;
		ctx.strokeStyle = "#a0d2ff";
		ctx.setLineDash([5, 5]);
		ctx.stroke();
	}
	calculateTransform() {
		const { paperArea, paperTransform: pt, width, height, scalePadding } = this.props;
		const box = paperArea.getContentFittingBox();
		const displayPadding = {
			x: Math.max(box.width, width / MIN_SCALE) * scalePadding,
			y: Math.max(box.height, height / MIN_SCALE) * scalePadding
		};
		const displayStart = paneFromPaperCoords({
			x: box.x - displayPadding.x,
			y: box.y - displayPadding.y
		}, pt);
		const displayEnd = paneFromPaperCoords({
			x: box.x + box.width + displayPadding.x,
			y: box.y + box.height + displayPadding.y
		}, pt);
		const displaySize = {
			x: displayEnd.x - displayStart.x,
			y: displayEnd.y - displayStart.y
		};
		const scale = Math.min(width / displaySize.x, height / displaySize.y);
		const canvasOffset = {
			x: (width - displaySize.x * scale) / 2,
			y: (height - displaySize.y * scale) / 2
		};
		this.transform = {
			scale,
			canvasOffset,
			paneOffset: displayStart
		};
	}
	canvasFromPageCoords(pageX, pageY) {
		const { top, left } = this.canvas.getBoundingClientRect();
		return {
			x: pageX - left - window.pageXOffset,
			y: pageY - top - window.pageYOffset
		};
	}
	render() {
		const { width, height } = this.props;
		const { expanded } = this.state;
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$3} ${CLASS_NAME$3}--${expanded ? "expanded" : "collapsed"}`,
			style: expanded ? {
				width,
				height
			} : void 0
		}, /* @__PURE__ */ React.createElement("canvas", {
			ref: (canvas) => {
				this.canvas = canvas;
			},
			width,
			height,
			onMouseDown: (e) => {
				this.startDragginViewport();
				this.onDragViewport(e);
			},
			onWheel: this.onWheel
		}), /* @__PURE__ */ React.createElement("button", {
			className: `${CLASS_NAME$3}__toggle`,
			title: expanded ? "Collapse navigator" : "Expand navigator",
			onClick: this.onToggleClick
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$3}__toggle-icon` })));
	}
	startDragginViewport() {
		if (!this.isDraggingViewport) {
			this.isDraggingViewport = true;
			document.addEventListener("mousemove", this.onDragViewport);
			document.addEventListener("mouseup", this.onMouseUp);
		}
	}
	stopDraggingViewport() {
		if (this.isDraggingViewport) {
			this.isDraggingViewport = false;
			document.removeEventListener("mousemove", this.onDragViewport);
			document.removeEventListener("mouseup", this.onMouseUp);
		}
	}
};
function canvasFromPaneCoords(pane, pt, nt) {
	return {
		x: nt.canvasOffset.x + (pane.x - nt.paneOffset.x) * nt.scale,
		y: nt.canvasOffset.y + (pane.y - nt.paneOffset.y) * nt.scale
	};
}
function canvasFromPaperCoords(paper, pt, nt) {
	return canvasFromPaneCoords(paneFromPaperCoords(paper, pt), pt, nt);
}
function paperFromCanvasCoords(canvas, pt, nt) {
	return paperFromPaneCoords({
		x: nt.paneOffset.x + (canvas.x - nt.canvasOffset.x) / nt.scale,
		y: nt.paneOffset.y + (canvas.y - nt.canvasOffset.y) / nt.scale
	}, pt);
}
//#endregion
//#region src/graph-explorer/widgets/classTree/treeModel.ts
var TreeNode = { setDerived: (node, derived) => ({
	...node,
	derived
}) };
//#endregion
//#region images/tree/expand-toggle.svg
var expand_toggle_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='128'%20height='128'%20viewbox='0%200%20128%20128'%3e%3cellipse%20stroke='%23000'%20ry='60'%20rx='60'%20cy='64'%20cx='64'%20stroke-width='5'%20fill='none'/%3e%3cline%20y2='63.4375'%20x2='104.5'%20y1='63.4375'%20x1='22.5'%20stroke-width='5'%20stroke='%23000'%20fill='none'/%3e%3cline%20y2='102.444349'%20x2='63.5'%20y1='29.4375'%20x1='63.5'%20stroke-width='5'%20stroke='%23000'%20fill='none'/%3e%3c/svg%3e";
//#endregion
//#region images/tree/collapse-toggle.svg
var collapse_toggle_default = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='128'%20height='128'%20viewbox='0%200%20128%20128'%3e%3cellipse%20stroke='%23000'%20ry='60'%20rx='60'%20cy='64'%20cx='64'%20stroke-width='5'%20fill='none'/%3e%3cline%20y2='63.4375'%20x2='104.5'%20y1='63.4375'%20x1='22.5'%20stroke-width='5'%20stroke='%23000'%20fill='none'/%3e%3c/svg%3e";
//#endregion
//#region images/tree/leaf-default.svg
var leaf_default_default = "data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'%20standalone='no'?%3e%3csvg%20xmlns:svg='http://www.w3.org/2000/svg'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%20xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%20width='128'%20height='128'%20viewbox='0%200%20128%20128'%20version='1.1'%20id='svg4507'%20sodipodi:docname='tree-leaf.svg'%20inkscape:version='0.92.1%20r15371'%3e%3cdefs%20id='defs4511'%20/%3e%3csodipodi:namedview%20pagecolor='%23ffffff'%20bordercolor='%23666666'%20borderopacity='1'%20objecttolerance='10'%20gridtolerance='10'%20guidetolerance='10'%20inkscape:pageopacity='0'%20inkscape:pageshadow='2'%20inkscape:window-width='1920'%20inkscape:window-height='1017'%20id='namedview4509'%20showgrid='false'%20inkscape:zoom='0.90509668'%20inkscape:cx='-272.6847'%20inkscape:cy='-5.8596487'%20inkscape:window-x='-8'%20inkscape:window-y='-8'%20inkscape:window-maximized='1'%20inkscape:current-layer='svg4507'%20/%3e%3cg%20id='g4505'%3e%3ccircle%20id='svg_1'%20cy='64'%20cx='64'%20stroke-opacity='null'%20style='fill:none;stroke:%231573b0;stroke-width:5'%20r='60'%20/%3e%3ccircle%20id='svg_3'%20cy='64'%20cx='64'%20stroke-opacity='null'%20style='fill:%231573b0;stroke:%231573b0;stroke-width:5.71026325'%20r='37'%20/%3e%3c/g%3e%3c/svg%3e";
//#endregion
//#region images/tree/leaf-folder.svg
var leaf_folder_default = "data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'%20standalone='no'?%3e%3csvg%20xmlns:svg='http://www.w3.org/2000/svg'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%20xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%20width='128'%20height='128'%20viewbox='0%200%20128%20128'%20version='1.1'%20id='svg5088'%20sodipodi:docname='tree-leaf-folder.svg'%20inkscape:version='0.92.1%20r15371'%3e%3cdefs%20id='defs5092'%20/%3e%3csodipodi:namedview%20pagecolor='%23ffffff'%20bordercolor='%23666666'%20borderopacity='1'%20objecttolerance='10'%20gridtolerance='10'%20guidetolerance='10'%20inkscape:pageopacity='0'%20inkscape:pageshadow='2'%20inkscape:window-width='1920'%20inkscape:window-height='1017'%20id='namedview5090'%20showgrid='false'%20inkscape:zoom='2.6074563'%20inkscape:cx='128.74614'%20inkscape:cy='30.905472'%20inkscape:window-x='-8'%20inkscape:window-y='-8'%20inkscape:window-maximized='1'%20inkscape:current-layer='svg5088'%20/%3e%3cg%20id='g5086'%3e%3ccircle%20id='svg_1'%20cy='64'%20cx='64'%20style='fill:none;stroke:%231573b0;stroke-width:5'%20r='60'%20/%3e%3ccircle%20id='svg_3'%20cy='64'%20cx='64'%20stroke-opacity='null'%20style='fill:%231573b0;stroke:%231573b0;stroke-width:5'%20r='37'%20/%3e%3cpath%20id='svg_5'%20d='m%20127.2258,86.546643%20c%20-0.0105,-5.971065%20-4.72314,-10.809034%20-10.54009,-10.817147%20v%20-0.0027%20H%2084.380152%20c%20-1.33102,-4.386353%20-5.300357,-7.593637%20-10.028771,-7.60175%20h%20-7.577587%20c%20-5.819586,0.0054%20-10.534822,4.846082%20-10.545365,10.817147%20v%2038.368417%20c%200.01054,5.96565%204.725778,10.80362%2010.545365,10.81444%20h%2049.914556%20c%205.81167,-0.0108%2010.52955,-4.84879%2010.54009,-10.81444%20V%2086.546643%20Z'%20inkscape:connector-curvature='0'%20style='fill:%230f5376'%20sodipodi:nodetypes='ccccccccccccc'%20/%3e%3c/g%3e%3c/svg%3e";
//#endregion
//#region src/graph-explorer/widgets/classTree/leaf.tsx
var LEAF_CLASS = "graph-explorer-class-leaf";
var Leaf = class extends React.Component {
	constructor(props) {
		super(props);
		this.onClick = (e) => {
			e.preventDefault();
			const { node, onSelect } = this.props;
			onSelect(node);
		};
		this.toggle = () => {
			this.setState((state) => ({ expanded: !state.expanded }));
		};
		this.onClickCreate = () => {
			this.props.onClickCreate(this.props.node);
		};
		this.onDragCreate = (e) => {
			e.dataTransfer.setData("text", "");
			this.props.onDragCreate(this.props.node);
		};
		this.state = { expanded: Boolean(this.props.searchText) };
	}
	componentDidUpdate(nextProps) {
		if (this.props.searchText !== nextProps.searchText) this.setState({ expanded: Boolean(nextProps.searchText) });
	}
	render() {
		const { node, ...otherProps } = this.props;
		const { view, selectedNode, searchText, creatableClasses } = otherProps;
		const { expanded } = this.state;
		let toggleIcon;
		if (node.derived.length > 0) toggleIcon = expanded ? collapse_toggle_default : expand_toggle_default;
		let { icon } = view.getTypeStyle([node.model.id]);
		if (!icon) icon = node.derived.length === 0 ? leaf_default_default : leaf_folder_default;
		let bodyClass = `${LEAF_CLASS}__body`;
		if (selectedNode && selectedNode.model === node.model) bodyClass += ` ${LEAF_CLASS}__body--selected`;
		const label = highlightSubstring(node.label, searchText, { className: `${LEAF_CLASS}__highlighted-term` });
		return /* @__PURE__ */ React.createElement("div", {
			className: LEAF_CLASS,
			role: "tree-item"
		}, /* @__PURE__ */ React.createElement("div", { className: `${LEAF_CLASS}__row` }, /* @__PURE__ */ React.createElement("div", {
			className: `${LEAF_CLASS}__toggle`,
			onClick: this.toggle,
			role: "button"
		}, toggleIcon ? /* @__PURE__ */ React.createElement("img", {
			className: `${LEAF_CLASS}__toggle-icon`,
			src: toggleIcon
		}) : null), /* @__PURE__ */ React.createElement("a", {
			className: bodyClass,
			href: node.model.id,
			onClick: this.onClick
		}, /* @__PURE__ */ React.createElement("div", { className: `${LEAF_CLASS}__icon-container` }, /* @__PURE__ */ React.createElement("img", {
			className: `${LEAF_CLASS}__icon`,
			src: icon
		})), /* @__PURE__ */ React.createElement("span", { className: `${LEAF_CLASS}__label` }, label), node.model.count ? /* @__PURE__ */ React.createElement("span", { className: `${LEAF_CLASS}__count graph-explorer-badge` }, node.model.count) : null), creatableClasses.get(node.model.id) ? /* @__PURE__ */ React.createElement("div", { className: `${LEAF_CLASS}__create graph-explorer-btn-group graph-explorer-btn-group-xs` }, /* @__PURE__ */ React.createElement("button", {
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Click or drag to create new entity of this type",
			draggable: true,
			onClick: this.onClickCreate,
			onDragStart: this.onDragCreate
		}, "+")) : null), expanded && node.derived.length > 0 ? /* @__PURE__ */ React.createElement(Forest, {
			className: `${LEAF_CLASS}__children`,
			nodes: node.derived,
			...otherProps
		}) : null);
	}
};
var Forest = class extends React.Component {
	render() {
		const { nodes, className, ...otherProps } = this.props;
		return /* @__PURE__ */ React.createElement("div", {
			className,
			role: "tree"
		}, nodes.map((node) => /* @__PURE__ */ React.createElement(Leaf, {
			key: `node-${node.model.id}`,
			node,
			...otherProps
		})));
	}
};
//#endregion
//#region src/graph-explorer/widgets/classTree/classTree.tsx
var CLASS_NAME$2 = "graph-explorer-class-tree";
var MIN_TERM_LENGTH = 3;
var ClassTree = class extends React.Component {
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this.delayedClassUpdate = new Debouncer();
		this.delayedSearch = new Debouncer(200);
		this.loadClassesOperation = new Cancellation();
		this.refreshOperation = new Cancellation();
		this.onSearchTextChange = (e) => {
			const requestedSearchText = e.currentTarget.value;
			this.setState({ requestedSearchText });
			this.delayedSearch.call(this.performSearch);
		};
		this.performSearch = () => {
			const { requestedSearchText } = this.state;
			const requested = normalizeSearchText(requestedSearchText);
			if (requested === this.state.appliedSearchText) return;
			const appliedSearchText = requested.length < MIN_TERM_LENGTH ? void 0 : requested;
			this.setState((state) => applyFilters({
				...state,
				appliedSearchText
			}));
		};
		this.onShowOnlyCreatableChange = (_e) => {
			this.setState((state) => applyFilters({
				...state,
				showOnlyConstructible: !state.showOnlyConstructible
			}));
		};
		this.onSelectNode = (node) => {
			const { onClassSelected } = this.props;
			this.setState({ selectedNode: node });
			onClassSelected(node.model.id);
		};
		this.onCreateInstance = (node) => {
			const { onCreateInstance } = this.props;
			onCreateInstance(node.model.id);
		};
		this.onDragCreate = (node) => {
			const { view, onCreateInstance } = this.props;
			view.setHandlerForNextDropOnPaper((e) => {
				onCreateInstance(node.model.id, e.paperPosition);
			});
		};
		this.refreshClassTree = () => {
			const cancellation = new Cancellation();
			const { editor } = this.props;
			this.refreshOperation.abort();
			this.refreshOperation = cancellation;
			this.setState((state, props) => {
				if (!this.classTree) return { refreshingState: ProgressState.none };
				let refreshingState = ProgressState.none;
				if (editor.inAuthoringMode) {
					const newIris = getNewClassIris(state.constructibleClasses, this.classTree);
					if (newIris.size > 0) {
						refreshingState = ProgressState.loading;
						this.queryCreatableTypes(newIris, cancellation.signal);
					}
				}
				const roots = createRoots(this.classTree, props.view);
				return applyFilters({
					...state,
					roots: sortTree(roots),
					refreshingState
				});
			});
		};
		this.state = {
			refreshingState: ProgressState.none,
			roots: [],
			filteredRoots: [],
			requestedSearchText: "",
			appliedSearchText: "",
			constructibleClasses: /* @__PURE__ */ new Map(),
			showOnlyConstructible: false
		};
	}
	render() {
		const { view, editor } = this.props;
		const { refreshingState, requestedSearchText, appliedSearchText, filteredRoots, selectedNode, constructibleClasses, showOnlyConstructible } = this.state;
		const normalizedSearchText = normalizeSearchText(requestedSearchText);
		const searchText = appliedSearchText ? normalizedSearchText : void 0;
		return /* @__PURE__ */ React.createElement("div", { className: CLASS_NAME$2 }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$2}__filter` }, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$2}__filter-group` }, /* @__PURE__ */ React.createElement("input", {
			type: "text",
			className: "search-input graph-explorer-form-control",
			placeholder: "Search for...",
			value: this.state.requestedSearchText,
			onChange: this.onSearchTextChange
		}), editor.inAuthoringMode ? /* @__PURE__ */ React.createElement("label", { className: `${CLASS_NAME$2}__only-creatable` }, /* @__PURE__ */ React.createElement("input", {
			type: "checkbox",
			checked: showOnlyConstructible,
			onChange: this.onShowOnlyCreatableChange
		}), " ", "Show only constructible") : null)), /* @__PURE__ */ React.createElement(ProgressBar, { state: refreshingState }), this.classTree ? /* @__PURE__ */ React.createElement(Forest, {
			className: `${CLASS_NAME$2}__tree graph-explorer-scrollable`,
			view,
			nodes: filteredRoots,
			searchText,
			selectedNode,
			onSelect: this.onSelectNode,
			creatableClasses: constructibleClasses,
			onClickCreate: this.onCreateInstance,
			onDragCreate: this.onDragCreate
		}) : /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME$2}__spinner` }, /* @__PURE__ */ React.createElement(HtmlSpinner, {
			width: 30,
			height: 30
		})));
	}
	componentDidMount() {
		const { view, editor } = this.props;
		this.listener.listen(view.events, "changeLanguage", () => this.refreshClassTree());
		this.listener.listen(editor.model.events, "loadingStart", () => {
			this.initClassTree();
		});
		this.listener.listen(editor.model.events, "classEvent", ({ data }) => {
			if (data.changeLabel || data.changeCount) this.delayedClassUpdate.call(this.refreshClassTree);
		});
		this.initClassTree();
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.delayedClassUpdate.dispose();
		this.delayedSearch.dispose();
		this.loadClassesOperation.abort();
		this.refreshOperation.abort();
	}
	async initClassTree() {
		if (this.dataProvider !== this.props.editor.model.dataProvider) {
			this.dataProvider = this.props.editor.model.dataProvider;
			this.classTree = void 0;
			const cancellation = new Cancellation();
			this.loadClassesOperation.abort();
			this.loadClassesOperation = cancellation;
			const classes = await this.dataProvider.classTree();
			if (cancellation.signal.aborted) return;
			this.setClassTree(classes);
		}
		this.refreshClassTree();
	}
	setClassTree(roots) {
		const diagramModel = this.props.editor.model;
		const visiting = /* @__PURE__ */ new Set();
		const reduceNonCycle = (acc, model) => {
			if (!visiting.has(model.id)) {
				visiting.add(model.id);
				const children = model.children.reduce(reduceNonCycle, []);
				acc.push({
					...model,
					children
				});
				visiting.delete(model.id);
			}
			return acc;
		};
		this.classTree = roots.reduce(reduceNonCycle, []);
		const addClass = (model) => {
			if (!diagramModel.getClass(model.id)) {
				const { id, label, count, children } = model;
				const richClass = new FatClassModel({
					id,
					label: label.values,
					count
				});
				diagramModel.addClass(richClass);
				children.forEach(addClass);
			}
		};
		this.classTree.forEach(addClass);
		this.refreshClassTree();
	}
	async queryCreatableTypes(typeIris, ct) {
		try {
			const result = await CancellationToken.mapCancelledToNull(ct, this.props.editor.metadataApi.filterConstructibleTypes(typeIris, ct));
			if (result === null) return;
			this.setState((state) => {
				const constructibleClasses = cloneMap(state.constructibleClasses);
				typeIris.forEach((type) => {
					constructibleClasses.set(type, result.has(type));
				});
				return applyFilters({
					...state,
					constructibleClasses,
					refreshingState: ProgressState.completed
				});
			});
		} catch (err) {
			console.error(err);
			if (ct.aborted) return;
			this.setState((state) => applyFilters({
				...state,
				refreshingState: ProgressState.error
			}));
		}
	}
};
function createRoots(classTree, view) {
	const mapClass = (model) => {
		const richClass = view.model.createClass(model.id);
		return {
			model: richClass,
			label: view.formatLabel(richClass.label, richClass.id),
			derived: model.children.map(mapClass)
		};
	};
	return classTree.map(mapClass);
}
function getNewClassIris(existingClasses, classTree) {
	const classIris = /* @__PURE__ */ new Set();
	const visitClass = (model) => {
		if (!existingClasses.has(model.id)) classIris.add(model.id);
		model.children.forEach(visitClass);
	};
	classTree.forEach(visitClass);
	return classIris;
}
function normalizeSearchText(text) {
	return text.trim().toLowerCase();
}
function sortTree(roots) {
	function mapNodes(nodes) {
		if (nodes.length === 0) return nodes;
		const mapped = nodes.map(mapNode);
		mapped.sort(compareByLabel);
		return mapped;
	}
	function mapNode(node) {
		return TreeNode.setDerived(node, mapNodes(node.derived));
	}
	function compareByLabel(left, right) {
		return left.label.localeCompare(right.label);
	}
	return mapNodes(roots);
}
function applyFilters(state) {
	let filteredRoots = state.roots;
	if (state.appliedSearchText) filteredRoots = filterByKeyword(filteredRoots, state.appliedSearchText);
	if (state.showOnlyConstructible) filteredRoots = filterOnlyCreatable(filteredRoots, state.constructibleClasses);
	return {
		...state,
		filteredRoots
	};
}
function filterByKeyword(roots, searchText) {
	if (roots.length === 0) return roots;
	function collectByKeyword(acc, node) {
		const derived = node.derived.reduce(collectByKeyword, []);
		if (derived.length > 0 || node.label.toLowerCase().indexOf(searchText) >= 0) acc.push(TreeNode.setDerived(node, derived));
		return acc;
	}
	return roots.reduce(collectByKeyword, []);
}
function filterOnlyCreatable(roots, creatableClasses) {
	function collectOnlyCreatable(acc, node) {
		const derived = node.derived.reduce(collectOnlyCreatable, []);
		if (derived.length > 0 || creatableClasses.get(node.model.id)) acc.push(TreeNode.setDerived(node, derived));
		return acc;
	}
	return roots.reduce(collectOnlyCreatable, []);
}
//#endregion
//#region src/graph-explorer/widgets/linksToolbox.tsx
var LinkInToolBox = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.onPressFilter = () => {
			if (this.props.onPressFilter) this.props.onPressFilter(this.props.link);
		};
		this.changeState = (state) => {
			const history = this.props.view.model.history;
			changeLinkTypeState(history, state, [this.props.link]);
		};
		this.isChecked = (stateName) => {
			let curState;
			if (!this.props.link.visible) curState = "invisible";
			else if (!this.props.link.showLabel) curState = "withoutLabels";
			else curState = "allVisible";
			return stateName === curState;
		};
		this.getText = () => {
			const { link: linkType, view, filterKey } = this.props;
			return highlightSubstring(view.formatLabel(linkType.label, linkType.id), filterKey);
		};
	}
	render() {
		const newIcon = this.props.link.isNew ? /* @__PURE__ */ React.createElement("span", { className: "linkInToolBox__new-tag" }, "new") : "";
		const countIcon = this.props.count > 0 ? /* @__PURE__ */ React.createElement("span", { className: "graph-explorer-badge" }, this.props.count) : "";
		const badgeContainer = newIcon || countIcon ? /* @__PURE__ */ React.createElement("div", null, newIcon, countIcon) : "";
		return /* @__PURE__ */ React.createElement("li", {
			"data-linktypeid": this.props.link.id,
			className: "graph-explorer-list-group-item linkInToolBox clearfix"
		}, /* @__PURE__ */ React.createElement("span", {
			className: "graph-explorer-btn-group graph-explorer-btn-group-xs",
			"data-toggle": "buttons"
		}, /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default" + (this.isChecked("invisible") ? " active" : ""),
			id: "invisible",
			title: "Hide links and labels",
			onClick: () => this.changeState("invisible")
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-times",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default" + (this.isChecked("withoutLabels") ? " active" : ""),
			id: "withoutLabels",
			title: "Show links without labels",
			onClick: () => this.changeState("withoutLabels")
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-arrows-h",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default" + (this.isChecked("allVisible") ? " active" : ""),
			id: "allVisible",
			title: "Show links with labels",
			onClick: () => this.changeState("allVisible")
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-text-width",
			"aria-hidden": "true"
		}))), /* @__PURE__ */ React.createElement("div", { className: "link-title" }, this.getText()), badgeContainer, /* @__PURE__ */ React.createElement("div", {
			className: "linkInToolBox__filter-button",
			onClick: this.onPressFilter
		}));
	}
};
var LinkTypesToolboxView = class extends React.Component {
	constructor(props) {
		super(props);
		this.compareLinks = (a, b) => {
			const { view } = this.props;
			const aText = view.formatLabel(a.label, a.id);
			const bText = view.formatLabel(b.label, b.id);
			return aText.localeCompare(bText);
		};
		this.onChangeInput = (e) => {
			this.setState({ filterKey: e.currentTarget.value });
		};
		this.onDropFilter = () => {
			this.setState({ filterKey: "" });
		};
		this.getLinks = () => {
			const { view, links = [] } = this.props;
			return links.filter((linkType) => {
				const text = view.formatLabel(linkType.label, linkType.id).toLowerCase();
				return !this.state.filterKey || text.indexOf(this.state.filterKey.toLowerCase()) >= 0;
			}).sort(this.compareLinks);
		};
		this.getViews = (links) => {
			const countMap = this.props.countMap || {};
			const views = [];
			for (const link of links) views.push(/* @__PURE__ */ React.createElement(LinkInToolBox, {
				key: link.id,
				view: this.props.view,
				link,
				onPressFilter: this.props.filterCallback,
				count: countMap[link.id] || 0,
				filterKey: this.state.filterKey
			}));
			return views;
		};
		this.state = { filterKey: "" };
	}
	render() {
		const className = "link-types-toolbox";
		const { view, dataState, selectedElement } = this.props;
		const history = view.model.history;
		const links = this.getLinks();
		const views = this.getViews(links);
		let connectedTo = null;
		if (selectedElement) {
			const selectedElementLabel = view.formatLabel(selectedElement.data.label.values, selectedElement.iri);
			connectedTo = /* @__PURE__ */ React.createElement("h4", {
				className: "links-heading",
				style: { display: "block" }
			}, "Connected to", "\xA0", /* @__PURE__ */ React.createElement("span", null, selectedElementLabel));
		}
		let dropButton = null;
		if (this.state.filterKey) dropButton = /* @__PURE__ */ React.createElement("button", {
			type: "button",
			className: `${className}__clearSearch`,
			onClick: this.onDropFilter
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-times",
			"aria-hidden": "true"
		}));
		return /* @__PURE__ */ React.createElement("div", { className }, /* @__PURE__ */ React.createElement("div", { className: `${className}__heading` }, /* @__PURE__ */ React.createElement("div", { className: `${className}__searching-box` }, /* @__PURE__ */ React.createElement("input", {
			className: "search-input graph-explorer-form-control",
			type: "text",
			value: this.state.filterKey,
			onChange: this.onChangeInput,
			placeholder: "Search for..."
		}), dropButton), /* @__PURE__ */ React.createElement("div", { className: `${className}__switch-all` }, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-btn-group graph-explorer-btn-group-xs" }, /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Hide links and labels",
			onClick: () => changeLinkTypeState(history, "invisible", links)
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-times",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Show links without labels",
			onClick: () => changeLinkTypeState(history, "withoutLabels", links)
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-arrows-h",
			"aria-hidden": "true"
		})), /* @__PURE__ */ React.createElement("label", {
			className: "graph-explorer-btn graph-explorer-btn-default",
			title: "Show links with labels",
			onClick: () => changeLinkTypeState(history, "allVisible", links)
		}, /* @__PURE__ */ React.createElement("span", {
			className: "fa fa-text-width",
			"aria-hidden": "true"
		}))), /* @__PURE__ */ React.createElement("span", null, "\xA0Switch all"))), /* @__PURE__ */ React.createElement(ProgressBar, { state: dataState }), /* @__PURE__ */ React.createElement("div", { className: `${className}__rest` }, connectedTo, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer-scrollable" }, /* @__PURE__ */ React.createElement("ul", { className: "graph-explorer-list-group connected-links" }, views))));
	}
};
var LinkTypesToolbox = class extends React.Component {
	constructor(props, context) {
		super(props, context);
		this.listener = new EventObserver();
		this.linkListener = new EventObserver();
		this.debounceSelection = new Debouncer(50);
		this.updateOnCurrentSelection = () => {
			const { editor } = this.props;
			const single = editor.selection.length === 1 ? editor.selection[0] : null;
			if (single !== this.state.selectedElement && single instanceof Element$1) this.requestLinksOf(single);
		};
		this.onLinkChanged = () => {
			this.forceUpdate();
		};
		this.onAddToFilter = (linkType) => {
			const { selectedElement } = this.state;
			selectedElement.addToFilter(linkType);
		};
		const { view, editor } = this.props;
		this.listener.listen(view.events, "changeLanguage", () => this.updateOnCurrentSelection());
		this.listener.listen(editor.model.events, "loadingSuccess", () => this.updateOnCurrentSelection());
		this.listener.listen(editor.events, "changeSelection", () => {
			this.debounceSelection.call(this.updateOnCurrentSelection);
		});
		this.state = { dataState: ProgressState.none };
	}
	componentDidMount() {
		this.updateOnCurrentSelection();
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.linkListener.stopListening();
		this.debounceSelection.dispose();
	}
	requestLinksOf(selectedElement) {
		if (selectedElement) {
			const request = { elementId: selectedElement.iri };
			this.currentRequest = request;
			this.setState({
				dataState: ProgressState.loading,
				selectedElement
			});
			this.props.editor.model.dataProvider.linkTypesOf(request).then((linkTypes) => {
				if (this.currentRequest !== request) return;
				const { linksOfElement, countMap } = this.computeStateFromRequestResult(linkTypes);
				this.subscribeOnLinksEvents(linksOfElement);
				this.setState({
					dataState: ProgressState.completed,
					linksOfElement,
					countMap
				});
			}).catch((error) => {
				if (this.currentRequest !== request) return;
				console.error(error);
				this.setState({
					dataState: ProgressState.error,
					linksOfElement: void 0,
					countMap: {}
				});
			});
		} else {
			this.currentRequest = null;
			this.setState({
				dataState: ProgressState.completed,
				selectedElement,
				linksOfElement: void 0,
				countMap: {}
			});
		}
	}
	computeStateFromRequestResult(linkTypes) {
		const linksOfElement = [];
		const countMap = {};
		const model = this.props.editor.model;
		for (const linkType of linkTypes) {
			const type = model.createLinkType(linkType.id);
			linksOfElement.push(type);
			countMap[linkType.id] = linkType.inCount + linkType.outCount;
		}
		return {
			linksOfElement,
			countMap
		};
	}
	subscribeOnLinksEvents(linksOfElement) {
		this.linkListener.stopListening();
		const listener = this.linkListener;
		for (const link of linksOfElement) {
			listener.listen(link.events, "changeLabel", this.onLinkChanged);
			listener.listen(link.events, "changeVisibility", this.onLinkChanged);
		}
	}
	render() {
		const { view } = this.props;
		const { selectedElement, dataState, linksOfElement, countMap } = this.state;
		return /* @__PURE__ */ React.createElement(LinkTypesToolboxView, {
			view,
			dataState,
			links: linksOfElement,
			countMap,
			filterCallback: this.onAddToFilter,
			selectedElement
		});
	}
};
function changeLinkTypeState(history, state, links) {
	const batch = history.startBatch();
	const { visible, showLabel } = state === "invisible" ? {
		visible: false,
		showLabel: false
	} : state === "withoutLabels" ? {
		visible: true,
		showLabel: false
	} : state === "allVisible" ? {
		visible: true,
		showLabel: true
	} : void 0;
	for (const linkType of links) history.execute(changeLinkTypeVisibility({
		linkType,
		visible,
		showLabel
	}));
	batch.store();
}
//#endregion
//#region src/graph-explorer/workspace/accordion.tsx
var CLASS_NAME$1 = "graph-explorer-accordion";
var Accordion = class extends React.Component {
	static {
		this.defaultProps = {
			direction: "vertical",
			animationDuration: 300
		};
	}
	constructor(props) {
		super(props);
		this.items = [];
		this.isScrollable = false;
		this.updateSizes = () => {
			const { children } = this.props;
			const defaultProps = /* @__PURE__ */ new Map();
			React.Children.forEach(children, (child, index) => {
				if (typeof child !== "object") return;
				const { defaultSize, defaultCollapsed, collapsedSize, minSize } = child.props;
				if (minSize !== void 0) this.isScrollable = true;
				defaultProps.set(index, {
					defaultSize,
					defaultCollapsed,
					collapsedSize,
					minSize
				});
			});
			this.defaultProps = defaultProps;
			this.setState(({ collapsed }) => {
				const totalSize = this.clientSize(this.element.parentElement);
				let leftSize = totalSize;
				let leftChildCount = React.Children.count(children);
				const newCollapsed = [];
				this.defaultProps.forEach(({ defaultSize, defaultCollapsed = false }, index) => {
					let itemCollapsed = collapsed[index] === void 0 ? defaultCollapsed : collapsed[index];
					const isLastItem = index === this.defaultProps.size - 1;
					const noExpandedItems = newCollapsed.findIndex((c) => !c) < 0;
					if (isLastItem && noExpandedItems) itemCollapsed = false;
					const size = itemCollapsed ? this.sizeWhenCollapsed(index) : defaultSize;
					if (size) {
						leftSize = leftSize - size;
						leftChildCount = leftChildCount - 1;
					}
					newCollapsed.push(itemCollapsed);
				});
				const newSizes = [];
				const newPercents = [];
				this.defaultProps.forEach(({ defaultSize, minSize }, index) => {
					let size = leftSize / leftChildCount;
					const collapsedSize = this.sizeWhenCollapsed(index);
					if (newCollapsed[index]) size = collapsedSize;
					else if (defaultSize !== void 0) size = defaultSize;
					else if (size < minSize) size = collapsedSize + minSize;
					if (size < collapsedSize) {
						size = collapsedSize;
						newCollapsed[index] = true;
					}
					const percent = `${100 * size / totalSize}%`;
					newSizes.push(size);
					newPercents.push(percent);
				});
				return {
					sizes: newSizes,
					percents: newPercents,
					collapsed: newCollapsed
				};
			});
		};
		this.onBeginDragHandle = (_itemIndex) => {
			this.originTotalSize = this.clientSize(this.element);
			this.originSizes = this.computeEffectiveItemSizes();
			this.originCollapsed = [...this.state.collapsed];
			this.setState({ resizing: true }, () => {
				const { direction, onStartResize } = this.props;
				if (onStartResize) onStartResize(direction);
			});
		};
		this.onEndDragHandle = () => {
			this.setState({ resizing: false });
		};
		this.sizeWhenCollapsed = (index) => {
			const item = this.items[index];
			const { collapsedSize } = this.defaultProps.get(index);
			if (collapsedSize !== void 0) return collapsedSize;
			return (item.header ? this.clientSize(item.header) : 0) + (this.offsetSize(item.element) - this.clientSize(item.element));
		};
		this.onDragHandle = (itemIndex, dx, dy) => {
			const sizes = [...this.originSizes];
			const collapsed = [...this.originCollapsed];
			new SizeDistributor(sizes, collapsed, this.originTotalSize, this.sizeWhenCollapsed).distribute(itemIndex + 1, this.isVertical ? dy : dx);
			const percents = sizes.map((size) => `${100 * size / this.originTotalSize}%`);
			this.setState({
				sizes,
				percents,
				collapsed
			});
		};
		const childCount = React.Children.count(this.props.children);
		this.state = {
			collapsed: [],
			resizing: false,
			percents: React.Children.map(this.props.children, () => `${100 / childCount}%`)
		};
	}
	componentDidMount() {
		this.updateSizes();
	}
	componentDidUpdate(prevProps, prevState) {
		const { direction, children, onResize, animationDuration } = this.props;
		if (React.Children.count(children) !== React.Children.count(prevProps.children)) this.updateSizes();
		const { sizes, resizing } = this.state;
		if (sizes !== prevState.sizes && onResize) if (resizing) onResize(direction);
		else setTimeout(() => onResize(direction), animationDuration);
	}
	get isVertical() {
		return this.props.direction === "vertical";
	}
	clientSize(element) {
		const { clientWidth, clientHeight } = element;
		return this.isVertical ? clientHeight : clientWidth;
	}
	offsetSize(element) {
		const { offsetWidth, offsetHeight } = element;
		return this.isVertical ? offsetHeight : offsetWidth;
	}
	render() {
		const { direction } = this.props;
		const { resizing } = this.state;
		const resizingClassName = resizing ? `${CLASS_NAME$1}--resizing` : "";
		const scrollableClassName = this.isScrollable ? `${CLASS_NAME$1}--scrollable` : "";
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME$1} ${CLASS_NAME$1}--${direction} ${resizingClassName} ${scrollableClassName}`,
			ref: (element) => {
				this.element = element;
			}
		}, this.renderItems());
	}
	renderItems() {
		const { sizes, percents, collapsed } = this.state;
		const { children, direction } = this.props;
		return React.Children.map(children, (child, index) => {
			if (typeof child !== "object") throw new Error("Accordion should have only AccordionItem elements as children");
			const lastChild = index === React.Children.count(children) - 1;
			const size = collapsed[index] ? sizes[index] : percents[index];
			const additionalProps = {
				ref: (element) => {
					this.items[index] = element;
				},
				collapsed: collapsed[index],
				size,
				direction,
				onChangeCollapsed: (itemCollapsed) => this.onItemChangeCollapsed({
					itemIndex: index,
					itemCollapsed
				}),
				onBeginDragHandle: lastChild ? void 0 : () => this.onBeginDragHandle(index),
				onDragHandle: lastChild ? void 0 : (dx, dy) => this.onDragHandle(index, dx, dy),
				onEndDragHandle: this.onEndDragHandle
			};
			return React.cloneElement(child, additionalProps);
		});
	}
	computeEffectiveItemSizes() {
		const sizes = [];
		this.items.forEach((item, index) => {
			if (!item) return;
			if (this.state.collapsed[index]) {
				const collapsedSize = this.sizeWhenCollapsed(index);
				sizes.push(collapsedSize);
			} else sizes.push(this.offsetSize(item.element));
		});
		return sizes;
	}
	onItemChangeCollapsed({ itemIndex, itemCollapsed }) {
		const totalSize = this.clientSize(this.element);
		const sizes = this.computeEffectiveItemSizes();
		if (sizes.length === 1) return;
		const collapsed = [...this.state.collapsed];
		const effectiveSize = sizes[itemIndex];
		const collapsedSize = this.sizeWhenCollapsed(itemIndex);
		const distributor = new SizeDistributor(sizes, collapsed, totalSize, this.sizeWhenCollapsed);
		if (itemCollapsed) {
			const splitShift = Math.max(effectiveSize - collapsedSize, 0);
			sizes[itemIndex] = collapsedSize;
			if (itemIndex === sizes.length - 1) distributor.expand(splitShift, itemIndex - 1);
			else distributor.expand(splitShift, itemIndex + 1);
		} else {
			const { defaultSize, minSize } = this.defaultProps.get(itemIndex);
			const shift = (defaultSize || totalSize / sizes.length) - collapsedSize;
			let freeSize;
			if (itemIndex === sizes.length - 1) freeSize = distributor.collapseForward({
				shift,
				from: itemIndex - 1,
				to: itemIndex
			});
			else freeSize = distributor.collapseForward({
				shift,
				from: itemIndex + 1,
				to: sizes.length
			});
			freeSize = Math.max(freeSize, distributor.leftoverSize());
			if (freeSize < shift) freeSize += distributor.collapseForward({
				shift: shift - freeSize,
				from: 0,
				to: itemIndex
			});
			if (freeSize < minSize) freeSize = minSize;
			sizes[itemIndex] = Math.round(collapsedSize + freeSize);
		}
		collapsed[itemIndex] = itemCollapsed;
		const percents = sizes.map((size) => `${100 * size / totalSize}%`);
		this.setState({
			sizes,
			percents,
			collapsed
		});
	}
};
var SizeDistributor = class {
	constructor(sizes, collapsed, totalSize, sizeWhenCollapsed) {
		this.sizes = sizes;
		this.collapsed = collapsed;
		this.totalSize = totalSize;
		this.sizeWhenCollapsed = sizeWhenCollapsed;
	}
	distribute(splitIndex, splitShift) {
		if (splitShift > 0) {
			let freeSize = this.collapseForward({
				shift: splitShift,
				from: splitIndex,
				to: this.sizes.length
			});
			freeSize = Math.max(freeSize, this.leftoverSize());
			this.expand(freeSize, splitIndex - 1);
		} else {
			let freeSize = this.collapseBackward({
				shift: -splitShift,
				from: 0,
				to: splitIndex
			});
			freeSize = Math.max(freeSize, this.leftoverSize());
			this.expand(freeSize, splitIndex);
		}
	}
	collapseForward({ shift, from, to }) {
		if (shift <= 0) return 0;
		let shiftLeft = shift;
		for (let i = from; i < to; i++) shiftLeft = this.collapse(shiftLeft, i);
		return shift - shiftLeft;
	}
	collapseBackward({ shift, from, to }) {
		if (shift <= 0) return 0;
		let shiftLeft = shift;
		for (let i = to - 1; i >= from; i--) shiftLeft = this.collapse(shiftLeft, i);
		return shift - shiftLeft;
	}
	collapse(shift, index) {
		if (this.collapsed[index]) return shift;
		const size = this.sizes[index];
		const collapsedSize = this.sizeWhenCollapsed(index);
		const newSize = Math.round(Math.max(size - shift, collapsedSize));
		this.sizes[index] = newSize;
		this.collapsed[index] = newSize <= collapsedSize;
		return shift - (size - newSize);
	}
	expand(shift, index) {
		if (shift <= 0) return 0;
		const oldSize = this.sizes[index];
		const newSize = Math.round(oldSize + shift);
		this.sizes[index] = newSize;
		this.collapsed[index] = newSize <= this.sizeWhenCollapsed(index);
		return newSize - oldSize;
	}
	leftoverSize() {
		const sizeSum = this.sizes.reduce((sum, size) => sum + size, 0);
		return Math.max(this.totalSize - sizeSum, 0);
	}
};
//#endregion
//#region src/graph-explorer/workspace/accordionItem.tsx
var DockSide = /* @__PURE__ */ function(DockSide) {
	DockSide[DockSide["Left"] = 1] = "Left";
	DockSide[DockSide["Right"] = 2] = "Right";
	return DockSide;
}({});
var CLASS_NAME = "graph-explorer-accordion-item";
var AccordionItem = class extends React.Component {
	static {
		this.defaultProps = { direction: "vertical" };
	}
	constructor(props) {
		super(props);
		this.state = { resizing: false };
	}
	get element() {
		return this._element;
	}
	get header() {
		return this._header;
	}
	get isVertical() {
		return this.props.direction === "vertical";
	}
	renderToggleButton() {
		const { collapsed, dockSide, onChangeCollapsed } = this.props;
		if (!dockSide) return null;
		const side = dockSide === 1 ? "left" : "right";
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME}__handle-btn ${CLASS_NAME}__handle-btn-${side}`,
			onClick: () => onChangeCollapsed(!collapsed)
		});
	}
	render() {
		const { heading, bodyClassName, children, bodyRef, collapsed, size, direction, onBeginDragHandle, onDragHandle, onEndDragHandle, dockSide } = this.props;
		const { resizing } = this.state;
		const shouldRenderHandle = onBeginDragHandle && onDragHandle && onEndDragHandle;
		const style = this.isVertical ? { height: size } : { width: size };
		const isMounted = !(collapsed && dockSide);
		return /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME} ${CLASS_NAME}--${collapsed ? "collapsed" : "expanded"} ${CLASS_NAME}--${direction}
                ${resizing ? `${CLASS_NAME}--resizing` : ""}`,
			ref: (element) => {
				this._element = element;
			},
			style
		}, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME}__inner` }, heading ? /* @__PURE__ */ React.createElement("div", {
			className: `${CLASS_NAME}__header`,
			ref: (header) => {
				this._header = header;
			},
			onClick: () => this.props.onChangeCollapsed(!collapsed)
		}, heading) : null, /* @__PURE__ */ React.createElement("div", { className: `${CLASS_NAME}__body` }, children && isMounted ? children : /* @__PURE__ */ React.createElement("div", {
			ref: bodyRef,
			className: `${bodyClassName || ""}`
		}))), shouldRenderHandle ? /* @__PURE__ */ React.createElement(DraggableHandle, {
			className: `${CLASS_NAME}__handle ${CLASS_NAME}__handle-${direction}`,
			onBeginDragHandle: (_e) => {
				this.setState({ resizing: true });
				onBeginDragHandle();
			},
			onDragHandle: (_e, x, y) => onDragHandle(x, y),
			onEndDragHandle: (_e) => {
				this.setState({ resizing: false });
				onEndDragHandle();
			}
		}) : null, this.renderToggleButton());
	}
};
//#endregion
//#region src/graph-explorer/workspace/layout/layout.tsx
var DEFAULT_HORIZONTAL_COLLAPSED_SIZE = 28;
var WorkspaceLayoutType = /* @__PURE__ */ function(WorkspaceLayoutType) {
	WorkspaceLayoutType["Row"] = "row";
	WorkspaceLayoutType["Column"] = "column";
	WorkspaceLayoutType["Component"] = "component";
	return WorkspaceLayoutType;
}({});
var WorkspaceLayout = class extends React.Component {
	renderAccordion({ children, direction, animationDuration }) {
		const { _onStartResize, _onResize } = this.props;
		const items = children.map((child, index) => {
			let dockSide;
			if (direction === "horizontal" && !child.undocked) {
				if (index === 0) dockSide = DockSide.Left;
				else if (index === children.length - 1) dockSide = DockSide.Right;
			}
			let collapsedSize = child.collapsedSize;
			if (collapsedSize === void 0 && direction === "horizontal") collapsedSize = DEFAULT_HORIZONTAL_COLLAPSED_SIZE;
			return /* @__PURE__ */ React.createElement(AccordionItem, {
				key: child.type === "component" ? child.id : index,
				heading: child.type === "component" ? child.heading : void 0,
				dockSide,
				defaultSize: child.defaultSize,
				defaultCollapsed: child.defaultCollapsed,
				collapsedSize,
				minSize: child.minSize
			}, this.renderLayout(child));
		});
		return /* @__PURE__ */ React.createElement(Accordion, {
			direction,
			onStartResize: _onStartResize,
			onResize: _onResize,
			animationDuration
		}, items);
	}
	renderLayout(layout) {
		if (layout.type === "row") return this.renderAccordion({
			children: layout.children,
			direction: "horizontal",
			animationDuration: layout.animationDuration
		});
		if (layout.type === "column") return this.renderAccordion({
			children: layout.children,
			direction: "vertical",
			animationDuration: layout.animationDuration
		});
		if (layout.type === "component") return React.Children.only(layout.content);
		return null;
	}
	render() {
		const { layout } = this.props;
		return this.renderLayout(layout);
	}
};
//#endregion
//#region src/graph-explorer/workspace/workspaceMarkup.tsx
var WorkspaceMarkup = class extends React.Component {
	constructor(..._args) {
		super(..._args);
		this.untilMouseUpClasses = [];
		this.cancellation = new Cancellation();
		this.triggerWorkspaceEvent = (key) => {
			const { onWorkspaceEvent } = this.props;
			if (onWorkspaceEvent) onWorkspaceEvent(key);
		};
		this.onCreateInstance = async (classId, position) => {
			const { editor, view, model, metadataApi } = this.props;
			await forceNonReactExecutionContext();
			const batch = model.history.startBatch();
			const signal = this.cancellation.signal;
			const elementModel = await CancellationToken.mapCancelledToNull(signal, metadataApi.generateNewElement([classId], signal));
			if (elementModel === null) return;
			const element = editor.createNewEntity({ elementModel });
			const targetPosition = position || getViewportCenterInPaperCoords(this.paperArea);
			element.setPosition(targetPosition);
			view.performSyncUpdate();
			centerElementToPosition(element, targetPosition);
			batch.store();
			editor.setSelection([element]);
			editor.showEditEntityForm(element);
		};
		this.onDocumentMouseUp = () => {
			for (const className of this.untilMouseUpClasses) this.element.classList.remove(className);
			this.untilMouseUpClasses = [];
		};
		this.onDropOnPaper = (e, paperPosition) => {
			e.preventDefault();
			const event = {
				dragEvent: e,
				paperPosition
			};
			if (this.props.view._tryHandleDropOnPaper(event)) return;
			const iris = tryParseDefaultDragAndDropData(e);
			if (iris.length > 0) this.props.editor.onDragDrop(iris, paperPosition);
		};
	}
	addToolbarWidgetToPaper() {
		const { hideToolbar, view, toolbar } = this.props;
		if (!hideToolbar) view.setPaperWidget({
			key: "toolbar",
			widget: /* @__PURE__ */ React.createElement(ToolbarWidget, null, toolbar),
			attachment: WidgetAttachment.Viewport
		});
	}
	getLeftPanelLayout() {
		const { view, editor, model, searchCriteria, onSearchCriteriaChanged } = this.props;
		const classTree = /* @__PURE__ */ React.createElement(ClassTree, {
			view,
			editor,
			onClassSelected: (classId) => {
				const elementType = model.createClass(classId);
				onSearchCriteriaChanged({ elementType });
			},
			onCreateInstance: this.onCreateInstance
		});
		const instancesSearch = /* @__PURE__ */ React.createElement(InstancesSearch, {
			view,
			model,
			criteria: searchCriteria || {},
			onCriteriaChanged: onSearchCriteriaChanged
		});
		return {
			type: WorkspaceLayoutType.Column,
			children: [{
				id: "classes",
				type: WorkspaceLayoutType.Component,
				content: classTree,
				heading: "Classes"
			}, {
				id: "instances",
				type: WorkspaceLayoutType.Component,
				content: instancesSearch,
				heading: "Instances"
			}],
			defaultSize: 275,
			defaultCollapsed: !this.props.isLeftPanelOpen
		};
	}
	getRightPanelLayout() {
		const { view, editor, elementsSearchPanel } = this.props;
		const rightPanel = {
			type: WorkspaceLayoutType.Column,
			children: [{
				id: "connections",
				type: WorkspaceLayoutType.Component,
				content: /* @__PURE__ */ React.createElement(LinkTypesToolbox, {
					view,
					editor
				}),
				heading: "Connections"
			}],
			defaultSize: 275,
			defaultCollapsed: !this.props.isRightPanelOpen
		};
		if (elementsSearchPanel) rightPanel.children = [...rightPanel.children, {
			id: "search",
			type: WorkspaceLayoutType.Component,
			content: React.cloneElement(elementsSearchPanel, {
				view,
				editor
			}),
			heading: "Search in diagram"
		}];
		return rightPanel;
	}
	render() {
		const paper = {
			id: "paper",
			type: WorkspaceLayoutType.Component,
			content: /* @__PURE__ */ React.createElement("div", {
				className: "graph-explorer__main-panel",
				style: {
					flex: "1 1 0px",
					width: "100%"
				}
			}, /* @__PURE__ */ React.createElement(PaperArea, {
				ref: (el) => {
					this.paperArea = el;
				},
				view: this.props.view,
				zoomOptions: this.props.zoomOptions,
				hideScrollBars: this.props.hideScrollBars,
				watermarkSvg: this.props.watermarkSvg,
				watermarkUrl: this.props.watermarkUrl,
				onDragDrop: this.onDropOnPaper,
				onZoom: this.props.onZoom
			}))
		};
		const workspaceLayout = this.props.hidePanels ? paper : {
			type: WorkspaceLayoutType.Row,
			children: [
				this.getLeftPanelLayout(),
				paper,
				this.getRightPanelLayout()
			]
		};
		return /* @__PURE__ */ React.createElement(WorkspaceContext.Provider, { value: { workspace: {
			editor: this.props.editor,
			triggerWorkspaceEvent: this.triggerWorkspaceEvent
		} } }, /* @__PURE__ */ React.createElement("div", {
			ref: (e) => {
				this.element = e;
			},
			className: "graph-explorer"
		}, /* @__PURE__ */ React.createElement("div", { className: "graph-explorer__workspace" }, /* @__PURE__ */ React.createElement(WorkspaceLayout, {
			layout: workspaceLayout,
			_onStartResize: (direction) => this.untilMouseUp({
				preventTextSelection: true,
				verticalResizing: direction === "vertical",
				horizontalResizing: direction === "horizontal"
			})
		}))));
	}
	componentDidMount() {
		document.addEventListener("mouseup", this.onDocumentMouseUp);
		this.addToolbarWidgetToPaper();
	}
	componentWillUnmount() {
		document.removeEventListener("mouseup", this.onDocumentMouseUp);
		this.cancellation.abort();
	}
	preventTextSelection() {
		this.untilMouseUp({ preventTextSelection: true });
	}
	untilMouseUp(params) {
		this.untilMouseUpClasses = [];
		if (params.preventTextSelection) this.untilMouseUpClasses.push("graph-explorer--unselectable");
		if (params.horizontalResizing) this.untilMouseUpClasses.push("graph-explorer--horizontal-resizing");
		if (params.verticalResizing) this.untilMouseUpClasses.push("graph-explorer--vertical-resizing");
		for (const className of this.untilMouseUpClasses) this.element.classList.add(className);
	}
};
var ToolbarWidget = class extends React.Component {
	render() {
		return /* @__PURE__ */ React.createElement("div", { className: "graph-explorer__toolbar-widget" }, this.props.children);
	}
};
function forceNonReactExecutionContext() {
	return Promise.resolve();
}
function getViewportCenterInPaperCoords(paperArea) {
	const viewport = paperArea.getAreaMetrics();
	return paperArea.clientToPaperCoords(viewport.clientWidth / 2, viewport.clientHeight / 2);
}
function centerElementToPosition(element, center) {
	const position = {
		x: center.x - element.size.width / 2,
		y: center.y - element.size.height / 2
	};
	element.setPosition(position);
}
function tryParseDefaultDragAndDropData(e) {
	const tryGetIri = (type, decode = false) => {
		try {
			const iriString = e.dataTransfer.getData(type);
			if (!iriString) return;
			let iris;
			try {
				iris = JSON.parse(iriString);
			} catch (_e) {
				iris = [decode ? decodeURI(iriString) : iriString];
			}
			return iris.length === 0 ? void 0 : iris;
		} catch (_e) {
			return;
		}
	};
	return tryGetIri("application/x-graph-explorer-elements") || tryGetIri("text/uri-list", true) || tryGetIri("text") || [];
}
//#endregion
//#region src/graph-explorer/workspace/workspace.ts
var GRAPH_EXPLORER_WEBSITE = "https://graph-explorer.org/";
var GRAPH_EXPLORER_LOGO_SVG = void 0;
var Workspace = class extends Component {
	static {
		this.defaultProps = {
			hideTutorial: true,
			collapseNavigator: false,
			leftPanelInitiallyOpen: true,
			rightPanelInitiallyOpen: false,
			languages: [{
				code: "en",
				label: "English"
			}, {
				code: "ru",
				label: "Russian"
			}],
			language: "en"
		};
	}
	constructor(props) {
		super(props);
		this.listener = new EventObserver();
		this._watermarkSvg = GRAPH_EXPLORER_LOGO_SVG;
		this._watermarkUrl = GRAPH_EXPLORER_WEBSITE;
		this.zoomToFit = () => {
			this.markup.paperArea.zoomToFit();
		};
		this.zoomToFitRect = (bbox) => {
			this.markup.paperArea.zoomToFitRect(bbox);
		};
		this.clearAll = () => {
			this.editor.removeItems([...this.model.elements]);
		};
		this.forceLayout = () => {
			const batch = this.model.history.startBatch("Force layout");
			batch.history.registerToUndo(RestoreGeometry.capture(this.model));
			applyLayout(this.model, forceLayout({ model: this.model }));
			for (const link of this.model.links) link.setVertices([]);
			batch.store();
		};
		this.exportSvg = (fileName) => {
			this.markup.paperArea.exportSVG().then((svg) => {
				fileName = fileName || "diagram.svg";
				saveAs(new Blob(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + svg], { type: "image/svg+xml" }), fileName);
			});
		};
		this.exportPng = (fileName) => {
			fileName = fileName || "diagram.png";
			this.markup.paperArea.exportPNG({ backgroundColor: "white" }).then((dataUri) => {
				saveAs(dataURLToBlob(dataUri), fileName);
			});
		};
		this.undo = () => {
			this.model.history.undo();
		};
		this.redo = () => {
			this.model.history.redo();
		};
		this.zoomBy = (value) => {
			this.markup.paperArea.zoomBy(value);
		};
		this.zoomIn = () => {
			this.markup.paperArea.zoomIn();
		};
		this.zoomOut = () => {
			this.markup.paperArea.zoomOut();
		};
		this.print = () => {
			this.markup.paperArea.exportSVG().then((svg) => {
				const printWindow = window.open("", void 0, "width=1280,height=720");
				printWindow.document.write(svg);
				printWindow.document.close();
				printWindow.print();
			});
		};
		this.changeLanguage = (language) => {
			const { onLanguageChange } = this.props;
			if (onLanguageChange) onLanguageChange(language);
			else {
				this.view.setLanguage(language);
				this.forceUpdate();
			}
		};
		this.centerTo = (paperPosition) => {
			this.markup.paperArea.centerTo(paperPosition);
		};
		const { hideHalo, history, viewOptions = {}, metadataApi, validationApi, propertyEditor, elementTemplateResolver, linkTemplateResolver, typeStyleResolver, selectLabelLanguage } = this.props;
		const { linkRouter, onIriClick, disableDefaultHalo, suggestProperties, groupBy } = viewOptions;
		this.model = new AsyncModel(history || new NonRememberingHistory(), groupBy || []);
		this.view = new DiagramView(this.model, {
			elementTemplateResolver,
			linkTemplateResolver,
			typeStyleResolver,
			selectLabelLanguage,
			linkRouter,
			onIriClick
		});
		this.editor = new EditorController({
			model: this.model,
			view: this.view,
			disableHalo: hideHalo || disableDefaultHalo,
			suggestProperties,
			validationApi,
			propertyEditor
		});
		this.editor.setMetadataApi(metadataApi);
		this.view.setLanguage(this.props.language);
		this.state = {};
	}
	_getPaperArea() {
		return this.markup ? this.markup.paperArea : void 0;
	}
	_setWatermark(watermarkSvg, watermarkUrl) {
		this._watermarkSvg = watermarkSvg;
		this._watermarkUrl = watermarkUrl;
		this.forceUpdate();
	}
	render() {
		const { hidePanels, hideToolbar, metadataApi, hideScrollBars, onWorkspaceEvent, _elementsSearchPanel } = this.props;
		return createElement(WorkspaceMarkup, {
			ref: (markup) => {
				this.markup = markup;
			},
			hidePanels,
			hideToolbar,
			hideScrollBars,
			model: this.model,
			view: this.view,
			editor: this.editor,
			metadataApi,
			leftPanelInitiallyOpen: this.props.leftPanelInitiallyOpen,
			rightPanelInitiallyOpen: this.props.rightPanelInitiallyOpen,
			searchCriteria: this.state.criteria,
			onSearchCriteriaChanged: (criteria) => this.setState({ criteria }),
			zoomOptions: this.props.zoomOptions,
			onZoom: this.props.onZoom,
			isLeftPanelOpen: this.props.leftPanelInitiallyOpen,
			isRightPanelOpen: this.props.rightPanelInitiallyOpen,
			toolbar: createElement(ToolbarWrapper, { workspace: this }),
			onWorkspaceEvent,
			watermarkSvg: this._watermarkSvg,
			watermarkUrl: this._watermarkUrl,
			elementsSearchPanel: _elementsSearchPanel
		});
	}
	componentDidMount() {
		const { onWorkspaceEvent } = this.props;
		this.editor._initializePaperComponents(this.markup.paperArea);
		this.updateNavigator(!this.props.hideNavigator);
		this.listener.listen(this.model.events, "loadingSuccess", () => {
			this.view.performSyncUpdate();
			this.markup.paperArea.centerContent();
		});
		this.listener.listen(this.model.events, "elementEvent", ({ key: _key, data }) => {
			if (!data.requestedAddToFilter) return;
			const { source, linkType, direction } = data.requestedAddToFilter;
			this.setState({ criteria: {
				refElement: source,
				refElementLink: linkType,
				linkDirection: direction
			} });
			if (onWorkspaceEvent) onWorkspaceEvent(WorkspaceEventKey.searchUpdateCriteria);
		});
		this.listener.listen(this.markup.paperArea.events, "pointerUp", (e) => {
			if (this.props.onPointerUp) this.props.onPointerUp(e);
		});
		this.listener.listen(this.markup.paperArea.events, "pointerMove", (e) => {
			if (this.props.onPointerMove) this.props.onPointerMove(e);
		});
		this.listener.listen(this.markup.paperArea.events, "pointerDown", (e) => {
			if (this.props.onPointerDown) this.props.onPointerDown(e);
		});
		if (onWorkspaceEvent) {
			this.listener.listen(this.editor.events, "changeSelection", () => onWorkspaceEvent(WorkspaceEventKey.editorChangeSelection));
			this.listener.listen(this.editor.events, "toggleDialog", () => onWorkspaceEvent(WorkspaceEventKey.editorToggleDialog));
			this.listener.listen(this.editor.events, "addElements", () => onWorkspaceEvent(WorkspaceEventKey.editorAddElements));
		}
	}
	componentDidUpdate(nextProps) {
		if (Boolean(nextProps.onLanguageChange) && nextProps.language !== this.view.getLanguage()) this.view.setLanguage(nextProps.language);
		if (nextProps.metadataApi !== this.editor.metadataApi) this.editor.setMetadataApi(nextProps.metadataApi);
		if (nextProps.hideNavigator !== this.props.hideNavigator) this.updateNavigator(!nextProps.hideNavigator);
	}
	componentWillUnmount() {
		this.listener.stopListening();
		this.view.dispose();
	}
	updateNavigator(showNavigator) {
		if (showNavigator) {
			const widget = createElement(Navigator, {
				view: this.view,
				expanded: !this.props.collapseNavigator
			});
			this.view.setPaperWidget({
				key: "navigator",
				widget,
				attachment: WidgetAttachment.Viewport
			});
		} else this.view.setPaperWidget({
			key: "navigator",
			widget: void 0,
			attachment: WidgetAttachment.Viewport
		});
	}
	getModel() {
		return this.model;
	}
	getDiagram() {
		return this.view;
	}
	getEditor() {
		return this.editor;
	}
	preventTextSelectionUntilMouseUp() {
		this.markup.preventTextSelection();
	}
	showWaitIndicatorWhile(operation) {
		this.editor.setSpinner({});
		if (operation) operation.then(() => {
			this.editor.setSpinner(void 0);
		}).catch((error) => {
			console.error(error);
			this.editor.setSpinner({
				statusText: "Unknown error occured",
				errorOccured: true
			});
		});
	}
};
var ToolbarWrapper = class extends Component {
	constructor(..._args) {
		super(..._args);
		this.listener = new EventObserver();
	}
	render() {
		const { workspace } = this.props;
		const view = workspace.getDiagram();
		const editor = workspace.getEditor();
		const { languages, onSaveDiagram, onPersistChanges, hidePanels, toolbar } = workspace.props;
		const canPersistChanges = onPersistChanges ? !AuthoringState.isEmpty(editor.authoringState) : void 0;
		const canSaveDiagram = !canPersistChanges;
		const defaultToolbarProps = {
			onZoomIn: workspace.zoomIn,
			onZoomOut: workspace.zoomOut,
			onZoomToFit: workspace.zoomToFit,
			onPrint: workspace.print,
			onExportSVG: workspace.exportSvg,
			onExportPNG: workspace.exportPng,
			canSaveDiagram,
			onSaveDiagram: onSaveDiagram ? () => onSaveDiagram(workspace) : void 0,
			canPersistChanges,
			onPersistChanges: onPersistChanges ? () => onPersistChanges(workspace) : void 0,
			onForceLayout: () => {
				workspace.forceLayout();
				workspace.getDiagram().performSyncUpdate();
				workspace.zoomToFit();
			},
			onClearAll: workspace.clearAll,
			languages,
			selectedLanguage: view.getLanguage(),
			onChangeLanguage: workspace.changeLanguage,
			hidePanels
		};
		if (toolbar) return cloneElement(toolbar, {
			...defaultToolbarProps,
			...toolbar.props
		});
		else return createElement(DefaultToolbar, defaultToolbarProps);
	}
	componentDidMount() {
		const { workspace } = this.props;
		const editor = workspace.getEditor();
		const view = workspace.getDiagram();
		this.listener.listen(editor.events, "changeAuthoringState", () => {
			this.forceUpdate();
		});
		this.listener.listen(view.events, "changeLanguage", () => {
			this.forceUpdate();
		});
	}
	componentWillUnmount() {
		this.listener.stopListening();
	}
};
function renderTo(workspace, container, props) {
	createRoot(container).render(createElement(workspace, props));
}
//#endregion
//#region src/graph-explorer/internalApi.ts
var internalApi_exports = /* @__PURE__ */ __exportAll({
	BatchingScheduler: () => BatchingScheduler,
	BufferingQueue: () => BufferingQueue,
	Cancellation: () => Cancellation,
	CancellationToken: () => CancellationToken,
	CancelledError: () => CancelledError,
	Debouncer: () => Debouncer,
	HashMap: () => HashMap,
	HtmlSpinner: () => HtmlSpinner,
	KeyedObserver: () => KeyedObserver,
	LINK_SHOW_IRI: () => LINK_SHOW_IRI,
	ListElementView: () => ListElementView,
	MoveDirection: () => MoveDirection,
	OrderedMap: () => OrderedMap,
	Paper: () => Paper,
	PaperArea: () => PaperArea,
	PaperAreaContext: () => PaperAreaContext,
	SearchResults: () => SearchResults,
	Spinner: () => Spinner,
	TemplateProperties: () => TemplateProperties,
	TransformedSvgCanvas: () => TransformedSvgCanvas,
	WorkspaceContext: () => WorkspaceContext,
	animateInterval: () => animateInterval,
	biasFreePadded: () => biasFreePadded,
	cloneMap: () => cloneMap,
	cloneSet: () => cloneSet,
	delay: () => delay,
	easeInOutBezier: () => easeInOutBezier,
	getContentFittingBox: () => getContentFittingBox,
	getContentFittingBoxForLayout: () => getContentFittingBoxForLayout,
	getOrCreateArrayInMap: () => getOrCreateArrayInMap,
	getOrCreateSetInMap: () => getOrCreateSetInMap,
	groupForceLayout: () => groupForceLayout,
	groupRemoveOverlaps: () => groupRemoveOverlaps,
	highlightSubstring: () => highlightSubstring,
	isEmptyMap: () => isEmptyMap,
	makeMoveComparator: () => makeMoveComparator,
	objectValues: () => objectValues,
	observeElementTypes: () => observeElementTypes,
	observeLinkTypes: () => observeLinkTypes,
	observeProperties: () => observeProperties,
	padded: () => padded,
	paneFromPaperCoords: () => paneFromPaperCoords,
	paneTopLeft: () => paneTopLeft,
	paperFromPaneCoords: () => paperFromPaneCoords,
	startDragElements: () => startDragElements,
	totalPaneSize: () => totalPaneSize
});
//#endregion
export { AsyncModel, AuthoredEntity, AuthoringKind, AuthoringState, Cancellation, CancellationToken, CancelledError, Command, CompositeDataProvider, DBPediaSettings, DIAGRAM_CONTEXT_URL_V1, DefaultElementTemplate, DefaultElementTemplateBundle, DefaultToolbar, DemoDataProvider, DiagramModel, DiagramView, DraggableHandle, EditorController, Element$1 as Element, EmbeddedLayer, EventObserver, EventSource, GraphBuilder, GroupTemplate, internalApi_exports as InternalApi, IriClickIntent, Link, LinkDirection, LinkVertex, NonRememberingHistory, OWLRDFSSettings, OWLRDFSSettingsOverride, OWLStatsSettings, PLACEHOLDER_ELEMENT_TYPE, PLACEHOLDER_LINK_TYPE, QLeverSettings, RDFSettings, Rect, RenderingLayer, RestoreGeometry, SparqlDataProvider, SparqlGraphBuilder, SparqlQueryMethod, StandardTemplate, ValidationState, Vector, WidgetAttachment, WikidataSettings, Workspace, WorkspaceEventKey, WorkspaceLayout, WorkspaceLayoutType, applyLayout, boundsOf, calculateLayout, computeGrouping, computePolyline, computePolylineLength, convertToSerializedDiagram, executeSparqlConstruct, executeSparqlQuery, findElementAtPoint, findNearestSegmentIndex, forceLayout, getContentFittingBox, getPointAlongPolyline, hashLink, isIriProperty, isLinkConnectedToElement, isLiteralProperty, isPolylineEqual, makeGraphItems, makeLayout, makeLayoutData, makeSerializedDiagram, removeOverlaps, renderTo, requestElementData, restoreLinksBetweenElements, sameElement, sameLink, setElementData, setElementExpanded, setLinkData };

//# sourceMappingURL=graph-explorer.mjs.map