@bitcobblers/wod-wiki-ui 0.44.2157 → 0.44.2159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1040,15 +1040,22 @@ var embedPreviewDecorations = [
1040
1040
  var POPOVER_MIN_WIDTH = 192;
1041
1041
  var POPOVER_MAX_WIDTH = 320;
1042
1042
  var POPOVER_MAX_HEIGHT = 256;
1043
- function computeInlinePanelBox(field, host, viewportHeight) {
1044
- const offsetLeft = Math.max(0, Math.min(field.left - host.left, Math.max(0, host.width - POPOVER_MIN_WIDTH)));
1045
- const room = Math.max(host.width - offsetLeft, POPOVER_MIN_WIDTH);
1046
- const width = Math.min(Math.max(field.width, POPOVER_MIN_WIDTH), POPOVER_MAX_WIDTH, room);
1047
- const belowField = Math.max(0, viewportHeight - field.top - 64);
1043
+ var POPOVER_GAP = 8;
1044
+ function computeFloatingPlacement(field, viewport, panelHeight, avoid, gap = POPOVER_GAP) {
1045
+ const width = Math.min(Math.max(field.width, POPOVER_MIN_WIDTH), POPOVER_MAX_WIDTH);
1046
+ const height = Math.min(Math.max(panelHeight, 0), POPOVER_MAX_HEIGHT);
1047
+ const below = { top: field.bottom + gap, bottom: field.bottom + gap + height };
1048
+ const above = { top: field.top - gap - height};
1049
+ const fitsBelow = below.bottom <= viewport.height;
1050
+ const fitsAbove = above.top >= 0;
1051
+ const coversActions = avoid ? below.bottom > avoid.top && below.top < avoid.bottom : false;
1052
+ const placement = (coversActions || !fitsBelow) && fitsAbove ? "above" : "below";
1053
+ const chosen = placement === "below" ? below : above;
1048
1054
  return {
1055
+ left: Math.min(Math.max(gap, field.left), Math.max(gap, viewport.width - width - gap)),
1056
+ top: Math.min(Math.max(gap, chosen.top), Math.max(gap, viewport.height - height - gap)),
1049
1057
  width,
1050
- offsetLeft,
1051
- maxHeight: Math.max(96, Math.min(POPOVER_MAX_HEIGHT, belowField))
1058
+ placement
1052
1059
  };
1053
1060
  }
1054
1061
  var panelId = 0;
@@ -1056,8 +1063,7 @@ var SuggestionPanel = class {
1056
1063
  element;
1057
1064
  inputElement;
1058
1065
  onPick;
1059
- view;
1060
- host;
1066
+ avoid;
1061
1067
  listId;
1062
1068
  currentChoices = [];
1063
1069
  currentIndex = -1;
@@ -1065,18 +1071,17 @@ var SuggestionPanel = class {
1065
1071
  constructor(input, options) {
1066
1072
  this.inputElement = input;
1067
1073
  this.onPick = options.onPick;
1068
- this.view = options.view;
1069
- this.host = options.host;
1074
+ this.avoid = options.avoid;
1070
1075
  this.listId = `frontmatter-suggestions-${++panelId}`;
1071
1076
  const list = document.createElement("div");
1072
1077
  list.id = this.listId;
1073
1078
  list.setAttribute("role", "listbox");
1074
1079
  list.setAttribute("aria-label", options.label);
1075
1080
  list.tabIndex = -1;
1076
- list.className = "mt-1 overflow-auto rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs";
1081
+ list.className = "fixed z-[60] max-h-64 overflow-auto rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs";
1077
1082
  list.hidden = true;
1078
1083
  this.element = list;
1079
- this.attach();
1084
+ document.body.appendChild(list);
1080
1085
  input.setAttribute("role", "combobox");
1081
1086
  input.setAttribute("aria-haspopup", "listbox");
1082
1087
  input.setAttribute("aria-autocomplete", "list");
@@ -1110,10 +1115,10 @@ var SuggestionPanel = class {
1110
1115
  if (this.isOpen) return;
1111
1116
  this.isOpen = true;
1112
1117
  this.element.hidden = false;
1113
- this.attach();
1114
1118
  this.position();
1115
1119
  this.inputElement.setAttribute("aria-expanded", "true");
1116
- this.view.requestMeasure();
1120
+ window.addEventListener("scroll", this.handleViewportChange, true);
1121
+ window.addEventListener("resize", this.handleViewportChange);
1117
1122
  }
1118
1123
  close() {
1119
1124
  if (!this.isOpen) return;
@@ -1122,10 +1127,12 @@ var SuggestionPanel = class {
1122
1127
  this.currentIndex = -1;
1123
1128
  this.inputElement.setAttribute("aria-expanded", "false");
1124
1129
  this.inputElement.removeAttribute("aria-activedescendant");
1125
- this.view.requestMeasure();
1130
+ window.removeEventListener("scroll", this.handleViewportChange, true);
1131
+ window.removeEventListener("resize", this.handleViewportChange);
1126
1132
  }
1127
1133
  destroy() {
1128
1134
  this.close();
1135
+ this.element.remove();
1129
1136
  }
1130
1137
  activate(index) {
1131
1138
  this.currentIndex = index;
@@ -1153,21 +1160,31 @@ var SuggestionPanel = class {
1153
1160
  this.close();
1154
1161
  this.onPick(choice);
1155
1162
  }
1156
- /** Join the DOM under its host row (idempotent). */
1157
- attach() {
1158
- if (this.element.parentElement) return;
1159
- this.host.after(this.element);
1160
- }
1161
- /** Anchor the panel to the field inside its row. */
1163
+ handleViewportChange = () => {
1164
+ if (this.isOpen) this.position();
1165
+ };
1166
+ /** Anchor the panel to the field, flipped away from the metadata actions. */
1162
1167
  position() {
1163
- const box = computeInlinePanelBox(
1164
- this.inputElement.getBoundingClientRect(),
1165
- this.host.getBoundingClientRect(),
1166
- window.innerHeight
1168
+ const field = this.inputElement.getBoundingClientRect();
1169
+ const avoidElement = this.avoid?.() ?? null;
1170
+ const avoidRect = avoidElement?.getBoundingClientRect();
1171
+ const height = Math.min(this.element.scrollHeight, POPOVER_MAX_HEIGHT);
1172
+ const placement = computeFloatingPlacement(
1173
+ { top: field.top, bottom: field.bottom, left: field.left, width: field.width },
1174
+ { width: window.innerWidth, height: window.innerHeight },
1175
+ height,
1176
+ avoidRect ? {
1177
+ top: avoidRect.top,
1178
+ bottom: avoidRect.bottom,
1179
+ left: avoidRect.left,
1180
+ right: avoidRect.right
1181
+ } : void 0
1167
1182
  );
1168
- this.element.style.width = `${box.width}px`;
1169
- this.element.style.marginLeft = `${box.offsetLeft}px`;
1170
- this.element.style.maxHeight = `${box.maxHeight}px`;
1183
+ this.element.style.width = `${placement.width}px`;
1184
+ this.element.style.maxHeight = `${height}px`;
1185
+ this.element.style.left = `${placement.left}px`;
1186
+ this.element.style.top = `${placement.top}px`;
1187
+ this.element.dataset.placement = placement.placement;
1171
1188
  }
1172
1189
  };
1173
1190
 
@@ -1215,12 +1232,12 @@ function ensureColumnHeader(box, before) {
1215
1232
  function attachSuggestions(input, view, root, kind, key, excluded, commit, valueKind = "tags") {
1216
1233
  const provider = view.state.facet(frontmatterSuggestions);
1217
1234
  if (!provider || !input.parentElement) return;
1218
- const host = input.closest("[data-frontmatter-row]") ?? input.parentElement;
1219
1235
  const panel = new SuggestionPanel(input, {
1220
1236
  label: kind === "key" ? "Suggested properties" : suggestionListLabel(valueKind),
1221
1237
  onPick: () => commit(),
1222
- view,
1223
- host
1238
+ // The popup floats over the properties panel; it must never cover the
1239
+ // metadata actions below it.
1240
+ avoid: () => root.querySelector("[data-frontmatter-actions]")
1224
1241
  });
1225
1242
  let generation = 0;
1226
1243
  const close = () => {
@@ -1995,9 +2012,10 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
1995
2012
  box.appendChild(this.buildDefinitionRows(view, base));
1996
2013
  }
1997
2014
  if (!this.readOnly) {
1998
- const existingTagKey = entries.find(([key]) => isTagProperty(key))?.[0];
2015
+ const existingTagKey = entries.find(([key]) => key.trim().toLowerCase() === "tags")?.[0] ?? entries.find(([key]) => isTagProperty(key))?.[0];
1999
2016
  const actionsRow = document.createElement("div");
2000
2017
  actionsRow.className = "mt-2 flex items-center gap-3";
2018
+ actionsRow.dataset.frontmatterActions = "true";
2001
2019
  const addBtn = document.createElement("button");
2002
2020
  addBtn.type = "button";
2003
2021
  addBtn.setAttribute("aria-label", "Add property");
@@ -2070,9 +2088,9 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
2070
2088
  existingDraft.focus();
2071
2089
  return;
2072
2090
  }
2073
- const draftRow = createTagDraftRow(view, root, "tags", (val) => {
2074
- pendingFocus.set(view, { kind: "tag", key: "tags" });
2075
- patchPropertyInView(view, this.sectionId, ["tags"], [val]);
2091
+ const draftRow = createTagDraftRow(view, root, "category", (val) => {
2092
+ pendingFocus.set(view, { kind: "tag", key: "category" });
2093
+ patchPropertyInView(view, this.sectionId, ["category"], [val]);
2076
2094
  });
2077
2095
  box.appendChild(draftRow);
2078
2096
  draftRow.querySelector("input")?.focus();
@@ -2201,6 +2219,7 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
2201
2219
  root.appendChild(heading);
2202
2220
  const actionsRow = document.createElement("div");
2203
2221
  actionsRow.className = "flex items-center gap-3";
2222
+ actionsRow.dataset.frontmatterActions = "true";
2204
2223
  const addBtn = document.createElement("button");
2205
2224
  addBtn.type = "button";
2206
2225
  addBtn.setAttribute("aria-label", "Add property");
@@ -2232,9 +2251,9 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
2232
2251
  existingDraft.focus();
2233
2252
  return;
2234
2253
  }
2235
- const draftRow = createTagDraftRow(view, root, "tags", (val) => {
2236
- pendingFocus.set(view, { kind: "tag", key: "tags" });
2237
- patchPropertyInView(view, "new", ["tags"], [val]);
2254
+ const draftRow = createTagDraftRow(view, root, "category", (val) => {
2255
+ pendingFocus.set(view, { kind: "tag", key: "category" });
2256
+ patchPropertyInView(view, "new", ["category"], [val]);
2238
2257
  });
2239
2258
  root.appendChild(draftRow);
2240
2259
  ensureColumnHeader(root, draftRow);