@bitcobblers/wod-wiki-ui 0.44.2155 → 0.44.2156
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.
- package/dist/{chunk-K35IEZWM.mjs → chunk-NQMMGF3R.mjs} +251 -80
- package/dist/chunk-NQMMGF3R.mjs.map +1 -0
- package/dist/extensions/index.cjs +249 -78
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.mjs +1 -1
- package/dist/index.cjs +258 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.mjs +11 -11
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +11 -1
- package/package.json +4 -4
- package/dist/chunk-K35IEZWM.mjs.map +0 -1
|
@@ -1035,6 +1035,143 @@ var embedPreviewField = state.StateField.define({
|
|
|
1035
1035
|
var embedPreviewDecorations = [
|
|
1036
1036
|
embedPreviewField
|
|
1037
1037
|
];
|
|
1038
|
+
|
|
1039
|
+
// src/extensions/frontmatter-suggestions.ts
|
|
1040
|
+
var POPOVER_MIN_WIDTH = 192;
|
|
1041
|
+
var POPOVER_MAX_WIDTH = 320;
|
|
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);
|
|
1048
|
+
return {
|
|
1049
|
+
width,
|
|
1050
|
+
offsetLeft,
|
|
1051
|
+
maxHeight: Math.max(96, Math.min(POPOVER_MAX_HEIGHT, belowField))
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
var panelId = 0;
|
|
1055
|
+
var SuggestionPanel = class {
|
|
1056
|
+
element;
|
|
1057
|
+
inputElement;
|
|
1058
|
+
onPick;
|
|
1059
|
+
view;
|
|
1060
|
+
host;
|
|
1061
|
+
listId;
|
|
1062
|
+
currentChoices = [];
|
|
1063
|
+
currentIndex = -1;
|
|
1064
|
+
isOpen = false;
|
|
1065
|
+
constructor(input, options) {
|
|
1066
|
+
this.inputElement = input;
|
|
1067
|
+
this.onPick = options.onPick;
|
|
1068
|
+
this.view = options.view;
|
|
1069
|
+
this.host = options.host;
|
|
1070
|
+
this.listId = `frontmatter-suggestions-${++panelId}`;
|
|
1071
|
+
const list = document.createElement("div");
|
|
1072
|
+
list.id = this.listId;
|
|
1073
|
+
list.setAttribute("role", "listbox");
|
|
1074
|
+
list.setAttribute("aria-label", options.label);
|
|
1075
|
+
list.tabIndex = -1;
|
|
1076
|
+
list.className = "mt-1 overflow-auto rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs";
|
|
1077
|
+
list.hidden = true;
|
|
1078
|
+
this.element = list;
|
|
1079
|
+
this.attach();
|
|
1080
|
+
input.setAttribute("role", "combobox");
|
|
1081
|
+
input.setAttribute("aria-haspopup", "listbox");
|
|
1082
|
+
input.setAttribute("aria-autocomplete", "list");
|
|
1083
|
+
input.setAttribute("aria-controls", this.listId);
|
|
1084
|
+
input.setAttribute("aria-expanded", "false");
|
|
1085
|
+
}
|
|
1086
|
+
get choices() {
|
|
1087
|
+
return this.currentChoices;
|
|
1088
|
+
}
|
|
1089
|
+
get activeIndex() {
|
|
1090
|
+
return this.currentIndex;
|
|
1091
|
+
}
|
|
1092
|
+
setChoices(choices) {
|
|
1093
|
+
this.currentChoices = choices;
|
|
1094
|
+
this.currentIndex = -1;
|
|
1095
|
+
this.inputElement.removeAttribute("aria-activedescendant");
|
|
1096
|
+
this.element.replaceChildren();
|
|
1097
|
+
choices.forEach((choice, index) => {
|
|
1098
|
+
const option = document.createElement("div");
|
|
1099
|
+
option.id = `${this.listId}-${index}`;
|
|
1100
|
+
option.setAttribute("role", "option");
|
|
1101
|
+
option.setAttribute("aria-selected", "false");
|
|
1102
|
+
option.className = "cursor-pointer px-2 py-1.5 hover:bg-muted";
|
|
1103
|
+
option.textContent = choice.label;
|
|
1104
|
+
option.addEventListener("mousedown", (event) => event.preventDefault());
|
|
1105
|
+
option.addEventListener("click", () => this.pick(choice));
|
|
1106
|
+
this.element.appendChild(option);
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
open() {
|
|
1110
|
+
if (this.isOpen) return;
|
|
1111
|
+
this.isOpen = true;
|
|
1112
|
+
this.element.hidden = false;
|
|
1113
|
+
this.attach();
|
|
1114
|
+
this.position();
|
|
1115
|
+
this.inputElement.setAttribute("aria-expanded", "true");
|
|
1116
|
+
this.view.requestMeasure();
|
|
1117
|
+
}
|
|
1118
|
+
close() {
|
|
1119
|
+
if (!this.isOpen) return;
|
|
1120
|
+
this.isOpen = false;
|
|
1121
|
+
this.element.hidden = true;
|
|
1122
|
+
this.currentIndex = -1;
|
|
1123
|
+
this.inputElement.setAttribute("aria-expanded", "false");
|
|
1124
|
+
this.inputElement.removeAttribute("aria-activedescendant");
|
|
1125
|
+
this.view.requestMeasure();
|
|
1126
|
+
}
|
|
1127
|
+
destroy() {
|
|
1128
|
+
this.close();
|
|
1129
|
+
}
|
|
1130
|
+
activate(index) {
|
|
1131
|
+
this.currentIndex = index;
|
|
1132
|
+
Array.from(this.element.children).forEach((option2, i) => {
|
|
1133
|
+
option2.setAttribute("aria-selected", String(i === index));
|
|
1134
|
+
option2.classList.toggle("bg-muted", i === index);
|
|
1135
|
+
});
|
|
1136
|
+
const option = this.element.children[index];
|
|
1137
|
+
if (!option) return;
|
|
1138
|
+
this.inputElement.setAttribute("aria-activedescendant", option.id);
|
|
1139
|
+
if (option instanceof HTMLElement) option.scrollIntoView?.({ block: "nearest" });
|
|
1140
|
+
}
|
|
1141
|
+
/** Move the highlighted option; the first/last option wraps around. */
|
|
1142
|
+
moveActive(delta) {
|
|
1143
|
+
if (this.currentChoices.length === 0) return;
|
|
1144
|
+
const next = this.currentIndex < 0 ? delta > 0 ? 0 : this.currentChoices.length - 1 : (this.currentIndex + delta + this.currentChoices.length) % this.currentChoices.length;
|
|
1145
|
+
this.activate(next);
|
|
1146
|
+
}
|
|
1147
|
+
pickActive() {
|
|
1148
|
+
const choice = this.currentChoices[this.currentIndex];
|
|
1149
|
+
if (choice) this.pick(choice);
|
|
1150
|
+
}
|
|
1151
|
+
pick(choice) {
|
|
1152
|
+
this.inputElement.value = choice.value;
|
|
1153
|
+
this.close();
|
|
1154
|
+
this.onPick(choice);
|
|
1155
|
+
}
|
|
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. */
|
|
1162
|
+
position() {
|
|
1163
|
+
const box = computeInlinePanelBox(
|
|
1164
|
+
this.inputElement.getBoundingClientRect(),
|
|
1165
|
+
this.host.getBoundingClientRect(),
|
|
1166
|
+
window.innerHeight
|
|
1167
|
+
);
|
|
1168
|
+
this.element.style.width = `${box.width}px`;
|
|
1169
|
+
this.element.style.marginLeft = `${box.offsetLeft}px`;
|
|
1170
|
+
this.element.style.maxHeight = `${box.maxHeight}px`;
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
// src/extensions/frontmatter-preview.ts
|
|
1038
1175
|
var frontmatterSuggestions = state.Facet.define({ combine: (providers) => providers[0] ?? null });
|
|
1039
1176
|
var frontmatterReferenceIndex = state.Facet.define({ combine: (providers) => providers[0] ?? null });
|
|
1040
1177
|
var referenceIndexReload = state.StateEffect.define();
|
|
@@ -1043,52 +1180,52 @@ var frontmatterVisibility = state.Facet.define({
|
|
|
1043
1180
|
});
|
|
1044
1181
|
var pendingFocus = /* @__PURE__ */ new WeakMap();
|
|
1045
1182
|
var widgetCleanup = /* @__PURE__ */ new WeakMap();
|
|
1046
|
-
var
|
|
1183
|
+
var helperId = 0;
|
|
1047
1184
|
function isTagProperty(key) {
|
|
1048
1185
|
return ["tag", "tags", "category"].includes(key.trim().toLowerCase());
|
|
1049
1186
|
}
|
|
1187
|
+
function appendFieldHelper(parent, text) {
|
|
1188
|
+
const helper = document.createElement("span");
|
|
1189
|
+
helper.id = `frontmatter-hint-${++helperId}`;
|
|
1190
|
+
helper.className = "sr-only";
|
|
1191
|
+
helper.textContent = text;
|
|
1192
|
+
parent.appendChild(helper);
|
|
1193
|
+
return helper;
|
|
1194
|
+
}
|
|
1195
|
+
function createColumnHeader() {
|
|
1196
|
+
const header = document.createElement("div");
|
|
1197
|
+
header.className = "flex items-center border-b border-border text-[11px] font-semibold uppercase tracking-wide text-muted-foreground";
|
|
1198
|
+
const key = document.createElement("div");
|
|
1199
|
+
key.dataset.frontmatterColumn = "key";
|
|
1200
|
+
key.className = "px-3 py-1.5 w-36 shrink-0 border-r border-border max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
1201
|
+
key.textContent = "Key";
|
|
1202
|
+
const value = document.createElement("div");
|
|
1203
|
+
value.dataset.frontmatterColumn = "value";
|
|
1204
|
+
value.className = "px-3 py-1.5 flex-1 min-w-0";
|
|
1205
|
+
value.textContent = "Value";
|
|
1206
|
+
const actions = document.createElement("div");
|
|
1207
|
+
actions.className = "w-9 shrink-0";
|
|
1208
|
+
header.append(key, value, actions);
|
|
1209
|
+
return header;
|
|
1210
|
+
}
|
|
1211
|
+
function ensureColumnHeader(box, before) {
|
|
1212
|
+
if (box.querySelector("[data-frontmatter-column]")) return;
|
|
1213
|
+
box.insertBefore(createColumnHeader(), before);
|
|
1214
|
+
}
|
|
1050
1215
|
function attachSuggestions(input, view, root, kind, key, excluded, commit, valueKind = "tags") {
|
|
1051
1216
|
const provider = view.state.facet(frontmatterSuggestions);
|
|
1052
1217
|
if (!provider || !input.parentElement) return;
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
parent.appendChild(list);
|
|
1061
|
-
input.setAttribute("role", "combobox");
|
|
1062
|
-
input.setAttribute("aria-autocomplete", "list");
|
|
1063
|
-
input.setAttribute("aria-controls", list.id);
|
|
1064
|
-
input.setAttribute("aria-expanded", "false");
|
|
1218
|
+
const host = input.closest("[data-frontmatter-row]") ?? input.parentElement;
|
|
1219
|
+
const panel = new SuggestionPanel(input, {
|
|
1220
|
+
label: kind === "key" ? "Suggested properties" : suggestionListLabel(valueKind),
|
|
1221
|
+
onPick: () => commit(),
|
|
1222
|
+
view,
|
|
1223
|
+
host
|
|
1224
|
+
});
|
|
1065
1225
|
let generation = 0;
|
|
1066
|
-
let choices = [];
|
|
1067
|
-
let active = -1;
|
|
1068
1226
|
const close = () => {
|
|
1069
1227
|
generation++;
|
|
1070
|
-
|
|
1071
|
-
active = -1;
|
|
1072
|
-
list.hidden = true;
|
|
1073
|
-
input.setAttribute("aria-expanded", "false");
|
|
1074
|
-
input.removeAttribute("aria-activedescendant");
|
|
1075
|
-
};
|
|
1076
|
-
const select = (choice) => {
|
|
1077
|
-
input.value = choice.value;
|
|
1078
|
-
close();
|
|
1079
|
-
commit();
|
|
1080
|
-
};
|
|
1081
|
-
const activate = (index) => {
|
|
1082
|
-
active = index;
|
|
1083
|
-
Array.from(list.children).forEach((option2, i) => {
|
|
1084
|
-
option2.setAttribute("aria-selected", String(i === active));
|
|
1085
|
-
option2.classList.toggle("bg-muted", i === active);
|
|
1086
|
-
});
|
|
1087
|
-
const option = list.children[active];
|
|
1088
|
-
if (option) {
|
|
1089
|
-
input.setAttribute("aria-activedescendant", option.id);
|
|
1090
|
-
if (option instanceof HTMLElement) option.scrollIntoView?.({ block: "nearest" });
|
|
1091
|
-
}
|
|
1228
|
+
panel.close();
|
|
1092
1229
|
};
|
|
1093
1230
|
const refresh = async (showAll = false) => {
|
|
1094
1231
|
close();
|
|
@@ -1111,25 +1248,11 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit, value
|
|
|
1111
1248
|
candidates = catalog.tags.filter((tag) => isTagProperty(key) || tag.type?.toLowerCase() === key.trim().toLowerCase()).map((tag) => ({ value: tag.label, label: tag.label, haystack: tag.label.toLowerCase() }));
|
|
1112
1249
|
}
|
|
1113
1250
|
const selected = new Set(excluded.map((label) => label.toLowerCase()));
|
|
1114
|
-
choices = candidates.filter(
|
|
1251
|
+
const choices = candidates.filter(
|
|
1115
1252
|
(candidate) => (query === "" || candidate.haystack.includes(query)) && !selected.has(candidate.value.toLowerCase())
|
|
1116
|
-
);
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
list.replaceChildren();
|
|
1120
|
-
choices.forEach((choice, index) => {
|
|
1121
|
-
const option = document.createElement("div");
|
|
1122
|
-
option.id = `${list.id}-${index}`;
|
|
1123
|
-
option.setAttribute("role", "option");
|
|
1124
|
-
option.setAttribute("aria-selected", "false");
|
|
1125
|
-
option.className = "cursor-pointer px-2 py-1.5 hover:bg-muted";
|
|
1126
|
-
option.textContent = choice.label;
|
|
1127
|
-
option.addEventListener("mousedown", (event) => event.preventDefault());
|
|
1128
|
-
option.addEventListener("click", () => select(choice));
|
|
1129
|
-
list.appendChild(option);
|
|
1130
|
-
});
|
|
1131
|
-
list.hidden = choices.length === 0;
|
|
1132
|
-
input.setAttribute("aria-expanded", String(choices.length > 0));
|
|
1253
|
+
).map((candidate) => ({ value: candidate.value, label: candidate.label }));
|
|
1254
|
+
panel.setChoices(choices);
|
|
1255
|
+
if (choices.length > 0) panel.open();
|
|
1133
1256
|
} catch {
|
|
1134
1257
|
if (request === generation) close();
|
|
1135
1258
|
}
|
|
@@ -1144,16 +1267,22 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit, value
|
|
|
1144
1267
|
} else if (event.key === "Escape") {
|
|
1145
1268
|
event.preventDefault();
|
|
1146
1269
|
close();
|
|
1147
|
-
} else if (
|
|
1270
|
+
} else if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
1271
|
+
if (panel.choices.length === 0) return;
|
|
1148
1272
|
event.preventDefault();
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1273
|
+
panel.moveActive(event.key === "ArrowDown" ? 1 : -1);
|
|
1274
|
+
} else if (event.key === "Enter" || event.key === "Tab") {
|
|
1275
|
+
if (panel.activeIndex < 0) return;
|
|
1152
1276
|
event.preventDefault();
|
|
1153
|
-
|
|
1277
|
+
panel.pickActive();
|
|
1154
1278
|
}
|
|
1155
1279
|
});
|
|
1156
|
-
widgetCleanup.get(root)?.push(
|
|
1280
|
+
widgetCleanup.get(root)?.push(() => panel.destroy());
|
|
1281
|
+
}
|
|
1282
|
+
function suggestionListLabel(valueKind) {
|
|
1283
|
+
if (valueKind === "effort") return "Suggested efforts";
|
|
1284
|
+
if (valueKind === "equipment") return "Suggested equipment";
|
|
1285
|
+
return "Suggested tags";
|
|
1157
1286
|
}
|
|
1158
1287
|
function parseTagList(val) {
|
|
1159
1288
|
if (Array.isArray(val)) {
|
|
@@ -1231,10 +1360,11 @@ function isReferenceKey(key, docKind) {
|
|
|
1231
1360
|
}
|
|
1232
1361
|
function createTagDraftRow(view, root, key, onCommit) {
|
|
1233
1362
|
const row = document.createElement("div");
|
|
1234
|
-
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border
|
|
1363
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1235
1364
|
row.setAttribute("data-frontmatter-tag-draft", "true");
|
|
1365
|
+
row.dataset.frontmatterRow = key;
|
|
1236
1366
|
const keyCol = document.createElement("div");
|
|
1237
|
-
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border
|
|
1367
|
+
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
1238
1368
|
keyCol.appendChild(createTagIcon());
|
|
1239
1369
|
const keyLabel = document.createElement("span");
|
|
1240
1370
|
keyLabel.className = "truncate font-medium text-foreground/90";
|
|
@@ -1244,9 +1374,15 @@ function createTagDraftRow(view, root, key, onCommit) {
|
|
|
1244
1374
|
const valCol = document.createElement("div");
|
|
1245
1375
|
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
1246
1376
|
const input = document.createElement("input");
|
|
1247
|
-
input.className = "flex-
|
|
1377
|
+
input.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
1248
1378
|
input.placeholder = "Add tag\u2026";
|
|
1249
|
-
input.setAttribute("aria-label", `
|
|
1379
|
+
input.setAttribute("aria-label", `Value for ${key}`);
|
|
1380
|
+
input.dataset.frontmatterField = "value";
|
|
1381
|
+
input.dataset.frontmatterProperty = key;
|
|
1382
|
+
input.setAttribute(
|
|
1383
|
+
"aria-describedby",
|
|
1384
|
+
appendFieldHelper(valCol, "Press Enter to add the value.").id
|
|
1385
|
+
);
|
|
1250
1386
|
valCol.appendChild(input);
|
|
1251
1387
|
row.appendChild(valCol);
|
|
1252
1388
|
let settled = false;
|
|
@@ -1325,8 +1461,9 @@ var METRIC_DRAFT_KINDS = {
|
|
|
1325
1461
|
};
|
|
1326
1462
|
function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
1327
1463
|
const row = document.createElement("div");
|
|
1328
|
-
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border
|
|
1464
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1329
1465
|
row.setAttribute("data-frontmatter-metric-draft", "true");
|
|
1466
|
+
row.dataset.frontmatterRow = "metric";
|
|
1330
1467
|
const select = document.createElement("select");
|
|
1331
1468
|
select.setAttribute("aria-label", "Metric kind");
|
|
1332
1469
|
select.className = "mx-3 my-1.5 h-7 w-28 shrink-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
|
|
@@ -1340,9 +1477,14 @@ function createMetricDraftRow(view, root, referenceProvider, commit) {
|
|
|
1340
1477
|
const valCol = document.createElement("div");
|
|
1341
1478
|
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
1342
1479
|
const input = document.createElement("input");
|
|
1343
|
-
input.className = "flex-
|
|
1480
|
+
input.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
1344
1481
|
input.placeholder = "Value\u2026";
|
|
1345
1482
|
input.setAttribute("aria-label", "Metric value");
|
|
1483
|
+
input.dataset.frontmatterField = "value";
|
|
1484
|
+
input.setAttribute(
|
|
1485
|
+
"aria-describedby",
|
|
1486
|
+
appendFieldHelper(valCol, "Press Enter to apply the metric value.").id
|
|
1487
|
+
);
|
|
1346
1488
|
valCol.appendChild(input);
|
|
1347
1489
|
row.appendChild(valCol);
|
|
1348
1490
|
let settled = false;
|
|
@@ -1534,6 +1676,7 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1534
1676
|
const docKind = detectDefinitionKind(meta);
|
|
1535
1677
|
const referenceProvider = view.state.facet(frontmatterReferenceIndex)?.() ?? null;
|
|
1536
1678
|
const base = docKind === "effort" ? readBaseAttributes(body) : {};
|
|
1679
|
+
box.appendChild(createColumnHeader());
|
|
1537
1680
|
if (entries.length === 0) {
|
|
1538
1681
|
const emptyRow = document.createElement("div");
|
|
1539
1682
|
emptyRow.className = "px-3 py-2 text-xs text-muted-foreground/60 italic";
|
|
@@ -1546,10 +1689,12 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1546
1689
|
const isReferenceList = (isReferenceKey(key, docKind) || key === "aliases") && Array.isArray(value);
|
|
1547
1690
|
const nested = value === "" && ownsNestedBlock(body, key);
|
|
1548
1691
|
const row = document.createElement("div");
|
|
1549
|
-
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border
|
|
1692
|
+
row.className = "flex items-center min-h-[34px] border-b border-dashed border-border last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
|
|
1693
|
+
row.dataset.frontmatterRow = key;
|
|
1550
1694
|
box.appendChild(row);
|
|
1551
1695
|
const keyCol = document.createElement("div");
|
|
1552
|
-
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border
|
|
1696
|
+
keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
|
|
1697
|
+
row.appendChild(keyCol);
|
|
1553
1698
|
keyCol.appendChild(isTags || isReferenceList ? createTagIcon() : createListIcon());
|
|
1554
1699
|
if (this.readOnly || nested) {
|
|
1555
1700
|
const keyLabel = document.createElement("span");
|
|
@@ -1561,7 +1706,16 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1561
1706
|
keyInput.className = "w-full bg-transparent text-xs text-foreground/90 font-medium outline-none truncate hover:bg-muted/30 focus:bg-background focus:ring-1 focus:ring-ring rounded px-1 -mx-1";
|
|
1562
1707
|
keyInput.value = key;
|
|
1563
1708
|
keyInput.spellcheck = false;
|
|
1564
|
-
keyInput.setAttribute("aria-label", `Property
|
|
1709
|
+
keyInput.setAttribute("aria-label", `Property key: ${key}`);
|
|
1710
|
+
keyInput.dataset.frontmatterField = "key";
|
|
1711
|
+
keyInput.dataset.frontmatterProperty = key;
|
|
1712
|
+
keyInput.setAttribute(
|
|
1713
|
+
"aria-describedby",
|
|
1714
|
+
appendFieldHelper(
|
|
1715
|
+
keyCol,
|
|
1716
|
+
"Property name. Press Enter to apply. Arrow keys browse suggested property names."
|
|
1717
|
+
).id
|
|
1718
|
+
);
|
|
1565
1719
|
let currentKey = key;
|
|
1566
1720
|
const commitKey = () => {
|
|
1567
1721
|
const nextKey = keyInput.value.trim();
|
|
@@ -1602,9 +1756,9 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1602
1756
|
pendingFocus.delete(view);
|
|
1603
1757
|
}
|
|
1604
1758
|
}
|
|
1605
|
-
row.appendChild(keyCol);
|
|
1606
1759
|
const valCol = document.createElement("div");
|
|
1607
1760
|
valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
|
|
1761
|
+
row.appendChild(valCol);
|
|
1608
1762
|
const commitList = (next) => {
|
|
1609
1763
|
meta[key] = next;
|
|
1610
1764
|
patchPropertyInView(view, this.sectionId, [key], next.length > 0 ? next : "");
|
|
@@ -1650,9 +1804,18 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1650
1804
|
}
|
|
1651
1805
|
if (!this.readOnly) {
|
|
1652
1806
|
const chipInput = document.createElement("input");
|
|
1653
|
-
chipInput.className = "flex-
|
|
1807
|
+
chipInput.className = "flex-none w-44 max-w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring";
|
|
1654
1808
|
chipInput.placeholder = chips.length === 0 ? isReferenceList ? `Add ${valueKind === "effort" ? "effort" : "equipment"}\u2026` : "Add tags\u2026" : isTags ? "Add tag\u2026" : "Add\u2026";
|
|
1655
|
-
chipInput.setAttribute("aria-label",
|
|
1809
|
+
chipInput.setAttribute("aria-label", `Value for ${key}`);
|
|
1810
|
+
chipInput.dataset.frontmatterField = "value";
|
|
1811
|
+
chipInput.dataset.frontmatterProperty = key;
|
|
1812
|
+
chipInput.setAttribute(
|
|
1813
|
+
"aria-describedby",
|
|
1814
|
+
appendFieldHelper(
|
|
1815
|
+
valCol,
|
|
1816
|
+
"Press Enter or comma to add a value. Arrow keys browse the suggestions."
|
|
1817
|
+
).id
|
|
1818
|
+
);
|
|
1656
1819
|
const commitNewChip = () => {
|
|
1657
1820
|
const val = chipInput.value.trim().replace(/^,|,$/g, "");
|
|
1658
1821
|
if (val && !chips.some((chip) => chip.toLowerCase() === val.toLowerCase())) {
|
|
@@ -1725,10 +1888,16 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1725
1888
|
valCol.appendChild(valSpan);
|
|
1726
1889
|
} else {
|
|
1727
1890
|
const valInput = document.createElement("input");
|
|
1728
|
-
valInput.className = "w-full bg-
|
|
1891
|
+
valInput.className = "w-full rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring transition-colors";
|
|
1729
1892
|
valInput.value = strVal;
|
|
1730
1893
|
valInput.spellcheck = false;
|
|
1731
1894
|
valInput.setAttribute("aria-label", `Value for ${key}`);
|
|
1895
|
+
valInput.dataset.frontmatterField = "value";
|
|
1896
|
+
valInput.dataset.frontmatterProperty = key;
|
|
1897
|
+
valInput.setAttribute(
|
|
1898
|
+
"aria-describedby",
|
|
1899
|
+
appendFieldHelper(valCol, "Property value. Press Enter to apply.").id
|
|
1900
|
+
);
|
|
1732
1901
|
let committedVal = strVal;
|
|
1733
1902
|
const commitVal = () => {
|
|
1734
1903
|
const cur = valInput.value.trim();
|
|
@@ -1779,7 +1948,7 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1779
1948
|
openLink.appendChild(createExternalIcon());
|
|
1780
1949
|
pill.appendChild(openLink);
|
|
1781
1950
|
valCol.insertBefore(pill, valInput);
|
|
1782
|
-
valInput.className = "flex-1 min-w-[70px] bg-
|
|
1951
|
+
valInput.className = "flex-1 min-w-[70px] rounded-md border border-field-border bg-background/60 px-2 py-1 text-xs text-foreground outline-none placeholder:text-field-placeholder focus:border-ring focus:ring-1 focus:ring-ring transition-colors";
|
|
1783
1952
|
}
|
|
1784
1953
|
const diag = renderEffortValueDiagnostics(
|
|
1785
1954
|
referenceProvider,
|
|
@@ -1804,14 +1973,13 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1804
1973
|
valCol.appendChild(openLink);
|
|
1805
1974
|
}
|
|
1806
1975
|
}
|
|
1807
|
-
row.appendChild(valCol);
|
|
1808
1976
|
if (!this.readOnly && !nested) {
|
|
1809
1977
|
const actionsCol = document.createElement("div");
|
|
1810
1978
|
actionsCol.className = "flex items-center pr-2";
|
|
1811
1979
|
const delBtn = document.createElement("button");
|
|
1812
1980
|
delBtn.type = "button";
|
|
1813
1981
|
delBtn.setAttribute("aria-label", `Remove property ${key}`);
|
|
1814
|
-
delBtn.className = "opacity-0 group-hover:opacity-100 text-muted-foreground/
|
|
1982
|
+
delBtn.className = "opacity-0 group-hover:opacity-100 focus-visible:opacity-100 text-muted-foreground/70 hover:text-destructive p-1 rounded transition-opacity cursor-pointer";
|
|
1815
1983
|
delBtn.appendChild(createCloseIcon("md"));
|
|
1816
1984
|
delBtn.addEventListener("click", (e) => {
|
|
1817
1985
|
e.preventDefault();
|
|
@@ -1891,7 +2059,9 @@ var DefaultFrontmatterWidget = class extends view.WidgetType {
|
|
|
1891
2059
|
e.preventDefault();
|
|
1892
2060
|
e.stopPropagation();
|
|
1893
2061
|
if (existingTagKey) {
|
|
1894
|
-
const input = Array.from(root.querySelectorAll(
|
|
2062
|
+
const input = Array.from(root.querySelectorAll(
|
|
2063
|
+
'[data-frontmatter-field="value"]'
|
|
2064
|
+
)).find((element) => element.dataset.frontmatterProperty === existingTagKey);
|
|
1895
2065
|
input?.focus();
|
|
1896
2066
|
return;
|
|
1897
2067
|
}
|
|
@@ -2067,6 +2237,7 @@ var EmptyFrontmatterWidget = class extends view.WidgetType {
|
|
|
2067
2237
|
patchPropertyInView(view, "new", ["tags"], [val]);
|
|
2068
2238
|
});
|
|
2069
2239
|
root.appendChild(draftRow);
|
|
2240
|
+
ensureColumnHeader(root, draftRow);
|
|
2070
2241
|
draftRow.querySelector("input")?.focus();
|
|
2071
2242
|
view.requestMeasure();
|
|
2072
2243
|
});
|