@bitcobblers/wod-wiki-ui 0.36.2136 → 0.37.2139

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.
@@ -3,11 +3,11 @@ import { HighlightStyle, syntaxTree, sublanguageProp, LRLanguage, indentNodeProp
3
3
  import { tags, styleTags, Tag as Tag$1 } from '@lezer/highlight';
4
4
  import { RangeSetBuilder, Facet, StateEffect, StateField, Prec, EditorState, EditorSelection, countColumn } from '@codemirror/state';
5
5
  import { linter, forEachDiagnostic } from '@codemirror/lint';
6
- import { whiteboardScriptLanguage, createParser, metricPresentation, EFFORT_DISCIPLINES, whiteboardScript } from '@bitcobblers/wod-wiki-lang';
7
- import { mapNoteBlockChanges, validateNoteBlocks, reconcileNoteBlocks, parseDocumentSections, actionableSectionKind, MetricType } from '@bitcobblers/wod-wiki-core';
6
+ import { whiteboardScriptLanguage, EFFORT_DISCIPLINES, createParser, metricPresentation, whiteboardScript } from '@bitcobblers/wod-wiki-lang';
7
+ import { mapNoteBlockChanges, validateNoteBlocks, reconcileNoteBlocks, parseDocumentSections, actionableSectionKind, patchFrontmatterProperty, MetricType } from '@bitcobblers/wod-wiki-core';
8
8
  export { blockContentId } from '@bitcobblers/wod-wiki-core';
9
9
  import { invertedEffects, history, defaultKeymap, historyKeymap, indentWithTab, cursorPageUp, cursorPageDown, cursorDocStart, cursorDocEnd } from '@codemirror/commands';
10
- import { WQL_FIND_TARGETS, WQL_SOURCE_VALUES, WQL_RESULT_PLANES, WQL_AGGREGATORS, WQL_VIRTUAL_DIMS, WQL_TAG_KEYS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_CALC_TARGETS, WQL_DISPLAY_UNITS, WQL_INTENSITY_TIERS, parseQueryWidgetSuffix, serializeFrontmatter, parseFrontmatterBody, parseQuery, isFindQuery, isDashboardWidgetType, unknownWidgetTypeMessage, resolveWidgetType, PLANNED_WIDGET_TYPES, catalogOfItem, isPipelineQuery, wqlGroupingDimensions, isAggregateQuery, serialize, allowedFilterTypesForTarget, CONTENT_GROUPING_DIMENSIONS, substituteTokens, unknownTokensMessage, wql, WQL_NOTE_DEFAULT_SOURCES, wqlCompletionSource, wqlLanguage, wqlHighlightStyle, supportsWqlFilterKey } from '@bitcobblers/wod-wiki-wql';
10
+ import { WQL_FIND_TARGETS, WQL_SOURCE_VALUES, WQL_RESULT_PLANES, WQL_AGGREGATORS, WQL_VIRTUAL_DIMS, WQL_TAG_KEYS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_CALC_TARGETS, WQL_DISPLAY_UNITS, WQL_INTENSITY_TIERS, parseQueryWidgetSuffix, parseFrontmatterBody, parseQuery, isFindQuery, isDashboardWidgetType, unknownWidgetTypeMessage, resolveWidgetType, PLANNED_WIDGET_TYPES, catalogOfItem, isPipelineQuery, wqlGroupingDimensions, isAggregateQuery, serialize, allowedFilterTypesForTarget, CONTENT_GROUPING_DIMENSIONS, substituteTokens, unknownTokensMessage, wql, WQL_NOTE_DEFAULT_SOURCES, wqlCompletionSource, wqlLanguage, wqlHighlightStyle, supportsWqlFilterKey } from '@bitcobblers/wod-wiki-wql';
11
11
  export { CONTENT_GROUPING_DIMENSIONS } from '@bitcobblers/wod-wiki-wql';
12
12
  import { snippet, autocompletion, closeBrackets, closeBracketsKeymap, completionStatus, startCompletion, moveCompletionSelection, setSelectedCompletion, currentCompletions, acceptCompletion, closeCompletion, CompletionContext, ifNotIn, completeFromList, snippetCompletion } from '@codemirror/autocomplete';
13
13
  import { createRoot } from 'react-dom/client';
@@ -1016,6 +1016,8 @@ var embedPreviewDecorations = [
1016
1016
  embedPreviewField
1017
1017
  ];
1018
1018
  var frontmatterSuggestions = Facet.define({ combine: (providers) => providers[0] ?? null });
1019
+ var frontmatterReferenceIndex = Facet.define({ combine: (providers) => providers[0] ?? null });
1020
+ var referenceIndexReload = StateEffect.define();
1019
1021
  var frontmatterVisibility = Facet.define({
1020
1022
  combine: (values2) => values2[0] ?? true
1021
1023
  });
@@ -1025,7 +1027,7 @@ var suggestionId = 0;
1025
1027
  function isTagProperty(key) {
1026
1028
  return ["tag", "tags", "category"].includes(key.trim().toLowerCase());
1027
1029
  }
1028
- function attachSuggestions(input, view, root, kind, key, excluded, commit) {
1030
+ function attachSuggestions(input, view, root, kind, key, excluded, commit, valueKind = "tags") {
1029
1031
  const provider = view.state.facet(frontmatterSuggestions);
1030
1032
  if (!provider || !input.parentElement) return;
1031
1033
  const parent = input.parentElement;
@@ -1051,8 +1053,8 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit) {
1051
1053
  input.setAttribute("aria-expanded", "false");
1052
1054
  input.removeAttribute("aria-activedescendant");
1053
1055
  };
1054
- const select = (label) => {
1055
- input.value = label;
1056
+ const select = (choice) => {
1057
+ input.value = choice.value;
1056
1058
  close();
1057
1059
  commit();
1058
1060
  };
@@ -1075,21 +1077,35 @@ function attachSuggestions(input, view, root, kind, key, excluded, commit) {
1075
1077
  try {
1076
1078
  const catalog = await provider();
1077
1079
  if (request !== generation || !input.isConnected || document.activeElement !== input) return;
1078
- const candidates = kind === "key" ? catalog.types : catalog.tags.filter((tag) => isTagProperty(key) || tag.type?.toLowerCase() === key.trim().toLowerCase()).map((tag) => tag.label);
1080
+ let candidates;
1081
+ if (kind === "key") {
1082
+ candidates = catalog.types.map((name) => ({ value: name, label: name, haystack: name }));
1083
+ } else if (valueKind === "effort" || valueKind === "equipment") {
1084
+ const entries = valueKind === "effort" ? catalog.efforts ?? [] : catalog.equipment ?? [];
1085
+ candidates = entries.map((entry) => ({
1086
+ value: entry.slug,
1087
+ label: `${entry.label} (${entry.slug})`,
1088
+ haystack: [entry.label, entry.slug, ...entry.aliases].join(" ").toLowerCase()
1089
+ }));
1090
+ } else {
1091
+ 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() }));
1092
+ }
1079
1093
  const selected = new Set(excluded.map((label) => label.toLowerCase()));
1080
- choices = [...new Set(candidates)].filter((label) => label.toLowerCase().includes(query) && !selected.has(label.toLowerCase()));
1094
+ choices = candidates.filter(
1095
+ (candidate) => (query === "" || candidate.haystack.includes(query)) && !selected.has(candidate.value.toLowerCase())
1096
+ );
1081
1097
  active = -1;
1082
1098
  input.removeAttribute("aria-activedescendant");
1083
1099
  list.replaceChildren();
1084
- choices.forEach((label, index) => {
1100
+ choices.forEach((choice, index) => {
1085
1101
  const option = document.createElement("div");
1086
1102
  option.id = `${list.id}-${index}`;
1087
1103
  option.setAttribute("role", "option");
1088
1104
  option.setAttribute("aria-selected", "false");
1089
1105
  option.className = "cursor-pointer px-2 py-1.5 hover:bg-muted";
1090
- option.textContent = label;
1106
+ option.textContent = choice.label;
1091
1107
  option.addEventListener("mousedown", (event) => event.preventDefault());
1092
- option.addEventListener("click", () => select(label));
1108
+ option.addEventListener("click", () => select(choice));
1093
1109
  list.appendChild(option);
1094
1110
  });
1095
1111
  list.hidden = choices.length === 0;
@@ -1132,45 +1148,66 @@ function parseTagList(val) {
1132
1148
  }
1133
1149
  return [];
1134
1150
  }
1135
- function updateFrontmatter(view, sectionId, meta) {
1151
+ function patchPropertyInView(view, _sectionId, path, value) {
1136
1152
  if (view.state.readOnly) return;
1137
- const { sections } = view.state.field(sectionField);
1138
- const section = sections.find((s) => s.id === sectionId && s.type === "frontmatter") || sections.find((s) => s.type === "frontmatter");
1139
- if (!section) {
1140
- const nextBody2 = serializeFrontmatter(meta);
1141
- view.dispatch({
1142
- changes: {
1143
- from: 0,
1144
- to: 0,
1145
- insert: `---
1146
- ${nextBody2}
1147
- ---
1148
-
1149
- `
1150
- }
1151
- });
1152
- return;
1153
- }
1154
- const nextBody = serializeFrontmatter(meta);
1155
- if (section.contentFrom !== void 0 && section.contentTo !== void 0) {
1156
- view.dispatch({
1157
- changes: {
1158
- from: section.contentFrom,
1159
- to: section.contentTo,
1160
- insert: nextBody
1161
- }
1162
- });
1163
- } else {
1164
- view.dispatch({
1165
- changes: {
1166
- from: section.from,
1167
- to: section.to,
1168
- insert: `---
1169
- ${nextBody}
1170
- ---`
1171
- }
1172
- });
1153
+ const wholeDoc = view.state.doc.toString();
1154
+ const next = patchFrontmatterProperty(wholeDoc, path, value);
1155
+ if (next === wholeDoc) return;
1156
+ view.dispatch({ changes: { from: 0, to: wholeDoc.length, insert: next } });
1157
+ }
1158
+ function renamePropertyInView(view, _sectionId, fromKey, toKey, value) {
1159
+ if (view.state.readOnly) return;
1160
+ const wholeDoc = view.state.doc.toString();
1161
+ const next = patchFrontmatterProperty(
1162
+ patchFrontmatterProperty(wholeDoc, [toKey], value),
1163
+ [fromKey],
1164
+ null
1165
+ );
1166
+ if (next === wholeDoc) return;
1167
+ view.dispatch({ changes: { from: 0, to: wholeDoc.length, insert: next } });
1168
+ }
1169
+ function detectDefinitionKind(meta) {
1170
+ const type = typeof meta.type === "string" ? meta.type.trim().toLowerCase() : "";
1171
+ if (type === "effort") return "effort";
1172
+ if (type === "equipment") return "equipment";
1173
+ if (meta.registrySource !== void 0 || meta.baseAttributes !== void 0) return "effort";
1174
+ return null;
1175
+ }
1176
+ function readBaseAttributes(body) {
1177
+ const out = {};
1178
+ let inBase = false;
1179
+ for (const line of body.split(/\r?\n/)) {
1180
+ if (/^baseAttributes:\s*(#.*)?$/.test(line)) {
1181
+ inBase = true;
1182
+ continue;
1183
+ }
1184
+ if (!inBase) continue;
1185
+ if (/^\S/.test(line)) break;
1186
+ const match = line.match(/^\s+([\w-]+):\s*(.*)$/);
1187
+ if (!match) continue;
1188
+ if (match[1] === "met" || match[1] === "discipline" || match[1] === "intensityTier") {
1189
+ out[match[1]] = unquoteYamlScalar(match[2].trim());
1190
+ }
1173
1191
  }
1192
+ return out;
1193
+ }
1194
+ function unquoteYamlScalar(val) {
1195
+ if (val.startsWith('"') && val.endsWith('"')) return val.slice(1, -1).replace(/\\(["\\])/g, "$1");
1196
+ if (val.startsWith("'") && val.endsWith("'")) return val.slice(1, -1).replace(/\\'/g, "'");
1197
+ return val;
1198
+ }
1199
+ function referenceValueKind(key, docKind) {
1200
+ const normalized = key.trim().toLowerCase();
1201
+ if (normalized === "metrics.effort") return "effort";
1202
+ if (normalized === "metrics.equipment" || normalized === "equipment") return "equipment";
1203
+ if (normalized === "aliases" && docKind === "equipment") return "equipment";
1204
+ if (normalized === "aliases" && docKind === "effort") return "effort";
1205
+ return "tags";
1206
+ }
1207
+ function isReferenceKey(key, docKind) {
1208
+ const normalized = key.trim().toLowerCase();
1209
+ if (normalized === "metrics.effort" || normalized === "metrics.equipment") return true;
1210
+ return normalized === "equipment" && docKind === "effort";
1174
1211
  }
1175
1212
  function createTagDraftRow(view, root, key, onCommit) {
1176
1213
  const row = document.createElement("div");
@@ -1225,6 +1262,117 @@ function createTagDraftRow(view, root, key, onCommit) {
1225
1262
  }));
1226
1263
  return row;
1227
1264
  }
1265
+ function ownsNestedBlock(body, key) {
1266
+ const lines = body.split(/\r?\n/);
1267
+ for (let i = 0; i < lines.length; i++) {
1268
+ if (!new RegExp(`^${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*$`).test(lines[i])) continue;
1269
+ return i + 1 < lines.length && /^\s+\S/.test(lines[i + 1]);
1270
+ }
1271
+ return false;
1272
+ }
1273
+ function renderEffortValueDiagnostics(provider, token, onPick) {
1274
+ const trimmed = token.trim();
1275
+ if (!trimmed || provider.resolveEffort(trimmed)) return null;
1276
+ const diagnostics = provider.resolve(trimmed).diagnostics;
1277
+ const box = document.createElement("div");
1278
+ box.setAttribute("data-testid", "editor-ref-unknown");
1279
+ box.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
1280
+ const message = document.createElement("span");
1281
+ message.textContent = diagnostics[0]?.message || `Unknown effort: ${trimmed}`;
1282
+ box.appendChild(message);
1283
+ for (const candidate of diagnostics[0]?.candidates ?? []) {
1284
+ const pickBtn = document.createElement("button");
1285
+ pickBtn.type = "button";
1286
+ pickBtn.textContent = `Use ${candidate}`;
1287
+ pickBtn.className = "underline hover:text-foreground cursor-pointer";
1288
+ pickBtn.addEventListener("click", (e) => {
1289
+ e.preventDefault();
1290
+ onPick(candidate);
1291
+ });
1292
+ box.appendChild(pickBtn);
1293
+ }
1294
+ const createLink = document.createElement("a");
1295
+ createLink.href = provider.createHref("effort");
1296
+ createLink.textContent = "Create page";
1297
+ createLink.className = "underline hover:text-foreground";
1298
+ box.appendChild(createLink);
1299
+ return box;
1300
+ }
1301
+ var METRIC_DRAFT_KINDS = {
1302
+ effort: { label: "Effort", path: "metrics.effort", kind: "effort" },
1303
+ equipment: { label: "Equipment", path: "metrics.equipment", kind: "equipment" },
1304
+ rpe: { label: "RPE", path: "metrics.rpe", kind: "number" }
1305
+ };
1306
+ function createMetricDraftRow(view, root, referenceProvider, commit) {
1307
+ const row = document.createElement("div");
1308
+ row.className = "flex items-center min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
1309
+ row.setAttribute("data-frontmatter-metric-draft", "true");
1310
+ const select = document.createElement("select");
1311
+ select.setAttribute("aria-label", "Metric kind");
1312
+ 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";
1313
+ for (const [value, spec] of Object.entries(METRIC_DRAFT_KINDS)) {
1314
+ const option = document.createElement("option");
1315
+ option.value = value;
1316
+ option.textContent = spec.label;
1317
+ select.appendChild(option);
1318
+ }
1319
+ row.appendChild(select);
1320
+ const valCol = document.createElement("div");
1321
+ valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
1322
+ const input = document.createElement("input");
1323
+ input.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none px-1 py-0.5 placeholder:text-muted-foreground/40";
1324
+ input.placeholder = "Value\u2026";
1325
+ input.setAttribute("aria-label", "Metric value");
1326
+ valCol.appendChild(input);
1327
+ row.appendChild(valCol);
1328
+ let settled = false;
1329
+ const settle = (doCommit) => {
1330
+ if (settled) return;
1331
+ settled = true;
1332
+ const spec = METRIC_DRAFT_KINDS[select.value];
1333
+ const raw = input.value.trim();
1334
+ if (doCommit && spec && raw) {
1335
+ if (spec.kind === "equipment") commit([spec.path], [raw]);
1336
+ else if (spec.kind === "number") {
1337
+ const num = Number(raw);
1338
+ if (!Number.isNaN(num)) commit([spec.path], num);
1339
+ } else commit([spec.path], raw);
1340
+ }
1341
+ row.remove();
1342
+ view.requestMeasure();
1343
+ };
1344
+ const attachFor = () => {
1345
+ const spec = METRIC_DRAFT_KINDS[select.value];
1346
+ if (spec && (spec.kind === "effort" || spec.kind === "equipment") && referenceProvider) {
1347
+ attachSuggestions(input, view, root, "value", spec.path, [], () => settle(true), spec.kind);
1348
+ }
1349
+ };
1350
+ attachFor();
1351
+ select.addEventListener("change", attachFor);
1352
+ input.addEventListener("keydown", (e) => {
1353
+ if (e.defaultPrevented && e.key !== "Escape") return;
1354
+ if (e.key === "Escape") {
1355
+ e.preventDefault();
1356
+ settle(false);
1357
+ return;
1358
+ }
1359
+ if (e.key === "Enter") {
1360
+ e.preventDefault();
1361
+ settle(true);
1362
+ }
1363
+ });
1364
+ input.addEventListener("blur", () => queueMicrotask(() => {
1365
+ if (!input.isConnected) return;
1366
+ settle(input.value.trim().length > 0);
1367
+ }));
1368
+ select.addEventListener("keydown", (e) => {
1369
+ if (e.key === "Escape") {
1370
+ e.preventDefault();
1371
+ settle(false);
1372
+ }
1373
+ });
1374
+ return row;
1375
+ }
1228
1376
  function createTagIcon() {
1229
1377
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
1230
1378
  svg.setAttribute("viewBox", "0 0 24 24");
@@ -1337,26 +1485,11 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1337
1485
  sectionId;
1338
1486
  rawContent;
1339
1487
  readOnly;
1340
- constructor(sectionIdOrProps, rawContent, readOnly = false) {
1488
+ constructor(sectionId, rawContent, readOnly = false) {
1341
1489
  super();
1342
- if (typeof sectionIdOrProps === "string") {
1343
- this.sectionId = sectionIdOrProps;
1344
- this.rawContent = rawContent ?? "";
1345
- this.readOnly = readOnly;
1346
- } else {
1347
- this.sectionId = "legacy";
1348
- this.rawContent = serializeFrontmatter(sectionIdOrProps);
1349
- this.readOnly = readOnly;
1350
- }
1351
- }
1352
- get props() {
1353
- const body = this.rawContent.replace(/^---\r?\n?/, "").replace(/\r?\n?---\r?$/, "");
1354
- const meta = parseFrontmatterBody(body);
1355
- const result = {};
1356
- for (const [k, v] of Object.entries(meta)) {
1357
- result[k] = Array.isArray(v) ? v.join(", ") : String(v ?? "");
1358
- }
1359
- return result;
1490
+ this.sectionId = sectionId;
1491
+ this.rawContent = rawContent ?? "";
1492
+ this.readOnly = readOnly;
1360
1493
  }
1361
1494
  eq(other) {
1362
1495
  return this.sectionId === other.sectionId && this.rawContent === other.rawContent && this.readOnly === other.readOnly;
@@ -1378,6 +1511,9 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1378
1511
  const body = this.rawContent.replace(/^---\r?\n?/, "").replace(/\r?\n?---\r?$/, "");
1379
1512
  const meta = parseFrontmatterBody(body);
1380
1513
  const entries = Object.entries(meta);
1514
+ const docKind = detectDefinitionKind(meta);
1515
+ const referenceProvider = view.state.facet(frontmatterReferenceIndex)?.() ?? null;
1516
+ const base = docKind === "effort" ? readBaseAttributes(body) : {};
1381
1517
  if (entries.length === 0) {
1382
1518
  const emptyRow = document.createElement("div");
1383
1519
  emptyRow.className = "px-3 py-2 text-xs text-muted-foreground/60 italic";
@@ -1386,13 +1522,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1386
1522
  }
1387
1523
  for (const [key, value] of entries) {
1388
1524
  const isTags = isTagProperty(key);
1525
+ const valueKind = referenceValueKind(key, docKind);
1526
+ const isReferenceList = (isReferenceKey(key, docKind) || key === "aliases") && Array.isArray(value);
1527
+ const nested = value === "" && ownsNestedBlock(body, key);
1389
1528
  const row = document.createElement("div");
1390
1529
  row.className = "flex items-center min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 group hover:bg-muted/10 transition-colors max-[479px]:flex-col max-[479px]:items-stretch";
1391
1530
  box.appendChild(row);
1392
1531
  const keyCol = document.createElement("div");
1393
1532
  keyCol.className = "flex items-center gap-2 px-3 py-1.5 w-36 shrink-0 border-r border-dashed border-border/60 text-muted-foreground max-[479px]:w-auto max-[479px]:border-r-0 max-[479px]:border-b";
1394
- keyCol.appendChild(isTags ? createTagIcon() : createListIcon());
1395
- if (this.readOnly) {
1533
+ keyCol.appendChild(isTags || isReferenceList ? createTagIcon() : createListIcon());
1534
+ if (this.readOnly || nested) {
1396
1535
  const keyLabel = document.createElement("span");
1397
1536
  keyLabel.className = "truncate font-medium text-foreground/90";
1398
1537
  keyLabel.textContent = key;
@@ -1414,15 +1553,10 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1414
1553
  keyInput.value = currentKey;
1415
1554
  return;
1416
1555
  }
1417
- const newMeta = {};
1418
- for (const [k, v] of Object.entries(meta)) {
1419
- if (k === currentKey) newMeta[nextKey] = v;
1420
- else newMeta[k] = v;
1421
- }
1556
+ renamePropertyInView(view, this.sectionId, currentKey, nextKey, value);
1422
1557
  delete meta[currentKey];
1423
- meta[nextKey] = newMeta[nextKey];
1558
+ meta[nextKey] = value;
1424
1559
  currentKey = nextKey;
1425
- updateFrontmatter(view, this.sectionId, newMeta);
1426
1560
  };
1427
1561
  const commitKeyIfAttached = () => queueMicrotask(() => {
1428
1562
  if (keyInput.isConnected) commitKey();
@@ -1451,71 +1585,117 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1451
1585
  row.appendChild(keyCol);
1452
1586
  const valCol = document.createElement("div");
1453
1587
  valCol.className = "flex items-center flex-wrap gap-1.5 px-3 py-1.5 flex-1 min-w-0";
1454
- if (isTags) {
1455
- const tags7 = parseTagList(value);
1456
- for (let idx = 0; idx < tags7.length; idx++) {
1457
- const tag = tags7[idx];
1588
+ const commitList = (next) => {
1589
+ meta[key] = next;
1590
+ patchPropertyInView(view, this.sectionId, [key], next.length > 0 ? next : "");
1591
+ };
1592
+ const refMatch = (token) => {
1593
+ if (!referenceProvider) return null;
1594
+ return valueKind === "effort" ? referenceProvider.resolveEffort(token) : valueKind === "equipment" ? referenceProvider.resolveEquipment(token) : null;
1595
+ };
1596
+ if (isTags || isReferenceList) {
1597
+ const chips = parseTagList(value);
1598
+ const chipIsReference = valueKind !== "tags";
1599
+ for (let idx = 0; idx < chips.length; idx++) {
1600
+ const chip = chips[idx];
1601
+ const match = chipIsReference ? refMatch(chip) : null;
1458
1602
  const pill = document.createElement("span");
1459
- pill.className = "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-amber-500/10 text-amber-800 dark:text-amber-300 border border-amber-500/20 dark:border-amber-500/30";
1460
- const tagText = document.createElement("span");
1461
- tagText.textContent = tag;
1462
- pill.appendChild(tagText);
1603
+ pill.className = match ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60" : chipIsReference ? "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-destructive/10 text-destructive border border-destructive/30" : "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-amber-500/10 text-amber-800 dark:text-amber-300 border border-amber-500/20 dark:border-amber-500/30";
1604
+ const pillText = document.createElement("span");
1605
+ pillText.textContent = match ? match.label : chip;
1606
+ pill.appendChild(pillText);
1607
+ if (match && referenceProvider) {
1608
+ const openLink = document.createElement("a");
1609
+ openLink.href = referenceProvider.openHref(valueKind, match.slug);
1610
+ openLink.title = `Open ${match.label} page`;
1611
+ openLink.setAttribute("aria-label", `Open ${match.label} page`);
1612
+ openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
1613
+ openLink.appendChild(createExternalIcon());
1614
+ pill.appendChild(openLink);
1615
+ }
1463
1616
  if (!this.readOnly) {
1464
1617
  const rmBtn = document.createElement("button");
1465
1618
  rmBtn.type = "button";
1466
- rmBtn.setAttribute("aria-label", `Remove tag ${tag}`);
1467
- rmBtn.className = "inline-flex items-center justify-center text-amber-700/60 hover:text-amber-950 dark:text-amber-400/60 dark:hover:text-amber-100 cursor-pointer";
1619
+ rmBtn.setAttribute("aria-label", isTags ? `Remove tag ${chip}` : `Remove ${chip}`);
1620
+ rmBtn.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground dark:hover:text-foreground cursor-pointer";
1468
1621
  rmBtn.appendChild(createCloseIcon("sm"));
1469
1622
  rmBtn.addEventListener("click", (e) => {
1470
1623
  e.preventDefault();
1471
1624
  e.stopPropagation();
1472
- const nextTags = tags7.filter((_, i) => i !== idx);
1473
- meta[key] = nextTags;
1474
- updateFrontmatter(view, this.sectionId, meta);
1625
+ commitList(chips.filter((_, i) => i !== idx));
1475
1626
  });
1476
1627
  pill.appendChild(rmBtn);
1477
1628
  }
1478
1629
  valCol.appendChild(pill);
1479
1630
  }
1480
1631
  if (!this.readOnly) {
1481
- const tagInput = document.createElement("input");
1482
- tagInput.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none px-1 py-0.5 placeholder:text-muted-foreground/40";
1483
- tagInput.placeholder = tags7.length === 0 ? "Add tags\u2026" : "Add tag\u2026";
1484
- tagInput.setAttribute("aria-label", `Add tag to ${key}`);
1485
- const commitNewTag = () => {
1486
- const val = tagInput.value.trim().replace(/^,|,$/g, "");
1487
- if (val && !tags7.some((tag) => tag.toLowerCase() === val.toLowerCase())) {
1488
- meta[key] = [...tags7, val];
1489
- tagInput.value = "";
1632
+ const chipInput = document.createElement("input");
1633
+ chipInput.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none px-1 py-0.5 placeholder:text-muted-foreground/40";
1634
+ chipInput.placeholder = chips.length === 0 ? isReferenceList ? `Add ${valueKind === "effort" ? "effort" : "equipment"}\u2026` : "Add tags\u2026" : isTags ? "Add tag\u2026" : "Add\u2026";
1635
+ chipInput.setAttribute("aria-label", isTags ? `Add tag to ${key}` : `Add to ${key}`);
1636
+ const commitNewChip = () => {
1637
+ const val = chipInput.value.trim().replace(/^,|,$/g, "");
1638
+ if (val && !chips.some((chip) => chip.toLowerCase() === val.toLowerCase())) {
1639
+ chipInput.value = "";
1490
1640
  pendingFocus.set(view, { kind: "tag", key });
1491
- updateFrontmatter(view, this.sectionId, meta);
1641
+ commitList([...chips, val]);
1492
1642
  }
1493
1643
  };
1494
- valCol.appendChild(tagInput);
1495
- attachSuggestions(tagInput, view, root, "value", key, tags7, commitNewTag);
1496
- tagInput.addEventListener("keydown", (e) => {
1644
+ valCol.appendChild(chipInput);
1645
+ attachSuggestions(chipInput, view, root, "value", key, chips, commitNewChip, valueKind);
1646
+ chipInput.addEventListener("keydown", (e) => {
1497
1647
  if (e.defaultPrevented) return;
1498
1648
  if (e.key === "Enter" || e.key === ",") {
1499
1649
  e.preventDefault();
1500
- commitNewTag();
1501
- } else if (e.key === "Backspace" && !tagInput.value && tags7.length > 0) {
1650
+ commitNewChip();
1651
+ } else if (e.key === "Backspace" && !chipInput.value && chips.length > 0) {
1502
1652
  e.preventDefault();
1503
- meta[key] = tags7.slice(0, -1);
1504
1653
  pendingFocus.set(view, { kind: "tag", key });
1505
- updateFrontmatter(view, this.sectionId, meta);
1654
+ commitList(chips.slice(0, -1));
1506
1655
  }
1507
1656
  });
1508
- tagInput.addEventListener("blur", () => queueMicrotask(() => {
1509
- if (tagInput.isConnected && tagInput.value.trim()) commitNewTag();
1657
+ chipInput.addEventListener("blur", () => queueMicrotask(() => {
1658
+ if (chipInput.isConnected && chipInput.value.trim()) commitNewChip();
1510
1659
  }));
1511
1660
  const focus = pendingFocus.get(view);
1512
1661
  if (focus?.kind === "tag" && focus.key === key) {
1513
1662
  setTimeout(() => {
1514
- if (tagInput.isConnected) tagInput.focus();
1663
+ if (chipInput.isConnected) chipInput.focus();
1515
1664
  }, 0);
1516
1665
  pendingFocus.delete(view);
1517
1666
  }
1667
+ if (chipIsReference && referenceProvider) {
1668
+ const unknown = chips.filter((chip) => !refMatch(chip));
1669
+ if (unknown.length > 0) {
1670
+ const diag = document.createElement("div");
1671
+ diag.setAttribute("data-testid", "editor-ref-unknown");
1672
+ diag.className = "w-full basis-full flex flex-wrap items-center gap-2 text-[10px] text-destructive";
1673
+ const label = document.createElement("span");
1674
+ label.textContent = `Unknown ${valueKind === "effort" ? "effort" : "equipment"}: ${unknown.join(", ")}`;
1675
+ diag.appendChild(label);
1676
+ const selectBtn = document.createElement("button");
1677
+ selectBtn.type = "button";
1678
+ selectBtn.textContent = "Select existing";
1679
+ selectBtn.className = "underline hover:text-foreground cursor-pointer";
1680
+ selectBtn.addEventListener("click", (e) => {
1681
+ e.preventDefault();
1682
+ chipInput.focus();
1683
+ });
1684
+ diag.appendChild(selectBtn);
1685
+ const createLink = document.createElement("a");
1686
+ createLink.href = referenceProvider.createHref(valueKind);
1687
+ createLink.textContent = "Create page";
1688
+ createLink.className = "underline hover:text-foreground";
1689
+ diag.appendChild(createLink);
1690
+ valCol.appendChild(diag);
1691
+ }
1692
+ }
1518
1693
  }
1694
+ } else if (nested) {
1695
+ const valSpan = document.createElement("span");
1696
+ valSpan.className = "text-xs text-muted-foreground/60 italic py-0.5 truncate";
1697
+ valSpan.textContent = "Nested block \u2014 edit in YAML";
1698
+ valCol.appendChild(valSpan);
1519
1699
  } else {
1520
1700
  const strVal = Array.isArray(value) ? value.join(", ") : String(value ?? "");
1521
1701
  if (this.readOnly) {
@@ -1535,8 +1715,9 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1535
1715
  if (cur !== committedVal) {
1536
1716
  committedVal = cur;
1537
1717
  const num = Number(cur);
1538
- meta[key] = cur !== "" && !isNaN(num) ? num : cur;
1539
- updateFrontmatter(view, this.sectionId, meta);
1718
+ const next = cur !== "" && !isNaN(num) ? num : cur;
1719
+ meta[key] = next;
1720
+ patchPropertyInView(view, this.sectionId, [key], next);
1540
1721
  }
1541
1722
  };
1542
1723
  const commitValIfAttached = () => queueMicrotask(() => {
@@ -1544,7 +1725,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1544
1725
  });
1545
1726
  valInput.addEventListener("change", commitValIfAttached);
1546
1727
  valCol.appendChild(valInput);
1547
- attachSuggestions(valInput, view, root, "value", key, [strVal], commitVal);
1728
+ attachSuggestions(
1729
+ valInput,
1730
+ view,
1731
+ root,
1732
+ "value",
1733
+ key,
1734
+ [strVal],
1735
+ commitVal,
1736
+ key.trim().toLowerCase() === "metrics.effort" ? "effort" : "tags"
1737
+ );
1548
1738
  valInput.addEventListener("blur", commitValIfAttached);
1549
1739
  valInput.addEventListener("keydown", (e) => {
1550
1740
  if (e.defaultPrevented) return;
@@ -1553,6 +1743,34 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1553
1743
  valInput.blur();
1554
1744
  }
1555
1745
  });
1746
+ if (key.trim().toLowerCase() === "metrics.effort" && referenceProvider) {
1747
+ const match = referenceProvider.resolveEffort(strVal);
1748
+ if (match) {
1749
+ const pill = document.createElement("span");
1750
+ pill.className = "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-muted/60 text-foreground border border-border/60 shrink-0";
1751
+ const pillText = document.createElement("span");
1752
+ pillText.textContent = match.label;
1753
+ pill.appendChild(pillText);
1754
+ const openLink = document.createElement("a");
1755
+ openLink.href = referenceProvider.openHref("effort", match.slug);
1756
+ openLink.title = `Open ${match.label} page`;
1757
+ openLink.setAttribute("aria-label", `Open ${match.label} page`);
1758
+ openLink.className = "inline-flex items-center justify-center text-muted-foreground/60 hover:text-foreground cursor-pointer";
1759
+ openLink.appendChild(createExternalIcon());
1760
+ pill.appendChild(openLink);
1761
+ valCol.insertBefore(pill, valInput);
1762
+ valInput.className = "flex-1 min-w-[70px] bg-transparent text-xs text-foreground outline-none py-0.5 hover:bg-muted/20 focus:bg-background focus:ring-1 focus:ring-ring rounded px-1 -mx-1 transition-colors";
1763
+ }
1764
+ const diag = renderEffortValueDiagnostics(
1765
+ referenceProvider,
1766
+ strVal,
1767
+ (slug) => {
1768
+ meta[key] = slug;
1769
+ patchPropertyInView(view, this.sectionId, [key], slug);
1770
+ }
1771
+ );
1772
+ if (diag) valCol.appendChild(diag);
1773
+ }
1556
1774
  }
1557
1775
  if (/^https?:\/\/\S+$/i.test(strVal)) {
1558
1776
  const openLink = document.createElement("a");
@@ -1567,7 +1785,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1567
1785
  }
1568
1786
  }
1569
1787
  row.appendChild(valCol);
1570
- if (!this.readOnly) {
1788
+ if (!this.readOnly && !nested) {
1571
1789
  const actionsCol = document.createElement("div");
1572
1790
  actionsCol.className = "flex items-center pr-2";
1573
1791
  const delBtn = document.createElement("button");
@@ -1578,14 +1796,16 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1578
1796
  delBtn.addEventListener("click", (e) => {
1579
1797
  e.preventDefault();
1580
1798
  e.stopPropagation();
1581
- const newMeta = { ...meta };
1582
- delete newMeta[key];
1583
- updateFrontmatter(view, this.sectionId, newMeta);
1799
+ delete meta[key];
1800
+ patchPropertyInView(view, this.sectionId, [key], null);
1584
1801
  });
1585
1802
  actionsCol.appendChild(delBtn);
1586
1803
  row.appendChild(actionsCol);
1587
1804
  }
1588
1805
  }
1806
+ if (docKind === "effort" && !this.readOnly) {
1807
+ box.appendChild(this.buildDefinitionRows(view, base));
1808
+ }
1589
1809
  if (!this.readOnly) {
1590
1810
  const existingTagKey = entries.find(([key]) => isTagProperty(key))?.[0];
1591
1811
  const actionsRow = document.createElement("div");
@@ -1608,10 +1828,36 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1608
1828
  newKey = `property_${count2}`;
1609
1829
  }
1610
1830
  pendingFocus.set(view, { kind: "key", key: newKey });
1611
- const newMeta = { ...meta, [newKey]: "" };
1612
- updateFrontmatter(view, this.sectionId, newMeta);
1831
+ patchPropertyInView(view, this.sectionId, [newKey], "");
1613
1832
  });
1614
1833
  actionsRow.appendChild(addBtn);
1834
+ {
1835
+ const addMetricBtn = document.createElement("button");
1836
+ addMetricBtn.type = "button";
1837
+ addMetricBtn.setAttribute("aria-label", "Add metric");
1838
+ addMetricBtn.setAttribute("data-testid", "editor-add-metric-note");
1839
+ addMetricBtn.className = "inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground px-1 py-1 cursor-pointer transition-colors select-none";
1840
+ addMetricBtn.appendChild(createPlusIcon());
1841
+ const addMetricLabel = document.createElement("span");
1842
+ addMetricLabel.textContent = "Add metric";
1843
+ addMetricBtn.appendChild(addMetricLabel);
1844
+ addMetricBtn.addEventListener("click", (e) => {
1845
+ e.preventDefault();
1846
+ e.stopPropagation();
1847
+ const existing = root.querySelector("[data-frontmatter-metric-draft] input");
1848
+ if (existing) {
1849
+ existing.focus();
1850
+ return;
1851
+ }
1852
+ const draftRow = createMetricDraftRow(view, root, referenceProvider, (path, value) => {
1853
+ patchPropertyInView(view, this.sectionId, path, value);
1854
+ });
1855
+ box.appendChild(draftRow);
1856
+ draftRow.querySelector("input")?.focus();
1857
+ view.requestMeasure();
1858
+ });
1859
+ actionsRow.appendChild(addMetricBtn);
1860
+ }
1615
1861
  {
1616
1862
  const addTagBtn = document.createElement("button");
1617
1863
  addTagBtn.type = "button";
@@ -1636,7 +1882,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1636
1882
  }
1637
1883
  const draftRow = createTagDraftRow(view, root, "tags", (val) => {
1638
1884
  pendingFocus.set(view, { kind: "tag", key: "tags" });
1639
- updateFrontmatter(view, this.sectionId, { ...meta, tags: [val] });
1885
+ patchPropertyInView(view, this.sectionId, ["tags"], [val]);
1640
1886
  });
1641
1887
  box.appendChild(draftRow);
1642
1888
  draftRow.querySelector("input")?.focus();
@@ -1648,6 +1894,7 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1648
1894
  const editYamlBtn = document.createElement("button");
1649
1895
  editYamlBtn.type = "button";
1650
1896
  editYamlBtn.setAttribute("aria-label", "Edit YAML");
1897
+ editYamlBtn.setAttribute("data-testid", "editor-property-edit-yaml");
1651
1898
  editYamlBtn.className = "inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground px-1 py-1 cursor-pointer transition-colors select-none";
1652
1899
  const editYamlLabel = document.createElement("span");
1653
1900
  editYamlLabel.textContent = "Edit YAML";
@@ -1667,6 +1914,82 @@ var DefaultFrontmatterWidget = class extends WidgetType {
1667
1914
  }
1668
1915
  return root;
1669
1916
  }
1917
+ /**
1918
+ * Effort-definition attribute rows (MET / discipline / intensity tier).
1919
+ * Values live in the nested baseAttributes block; each edit patches that
1920
+ * one path, so unknown sibling keys and comments elsewhere survive.
1921
+ */
1922
+ buildDefinitionRows(view, base) {
1923
+ const wrap = document.createElement("div");
1924
+ wrap.setAttribute("data-frontmatter-definition", "true");
1925
+ wrap.className = "border-t border-dashed border-border/60";
1926
+ const header = document.createElement("div");
1927
+ header.className = "px-3 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground";
1928
+ header.textContent = "Definition";
1929
+ wrap.appendChild(header);
1930
+ const commitField = (field, raw) => {
1931
+ if (field === "met") {
1932
+ const num = Number(raw);
1933
+ patchPropertyInView(view, this.sectionId, ["baseAttributes", "met"], raw !== "" && !Number.isNaN(num) ? num : null);
1934
+ return;
1935
+ }
1936
+ patchPropertyInView(view, this.sectionId, ["baseAttributes", field], raw === "" ? null : raw);
1937
+ };
1938
+ const fieldRow = (label, child) => {
1939
+ const row = document.createElement("label");
1940
+ row.className = "flex items-center gap-2 px-3 py-1.5 min-h-[34px] border-b border-dashed border-border/60 last:border-b-0 max-[479px]:flex-col max-[479px]:items-stretch";
1941
+ const name = document.createElement("span");
1942
+ name.className = "w-28 shrink-0 text-muted-foreground";
1943
+ name.textContent = label;
1944
+ row.appendChild(name);
1945
+ child.className = "flex-1 min-w-0 bg-transparent text-xs text-foreground outline-none py-0.5";
1946
+ row.appendChild(child);
1947
+ wrap.appendChild(row);
1948
+ };
1949
+ const met = document.createElement("input");
1950
+ met.type = "number";
1951
+ met.step = "0.1";
1952
+ met.inputMode = "decimal";
1953
+ met.value = base.met ?? "";
1954
+ met.setAttribute("aria-label", "MET value");
1955
+ met.addEventListener("change", () => queueMicrotask(() => {
1956
+ if (met.isConnected) commitField("met", met.value.trim());
1957
+ }));
1958
+ fieldRow("MET", met);
1959
+ const discipline = document.createElement("select");
1960
+ discipline.setAttribute("aria-label", "Discipline");
1961
+ discipline.className = "flex-1 min-w-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
1962
+ const unset = document.createElement("option");
1963
+ unset.value = "";
1964
+ unset.textContent = "Unset";
1965
+ discipline.appendChild(unset);
1966
+ for (const option of EFFORT_DISCIPLINES) {
1967
+ const opt = document.createElement("option");
1968
+ opt.value = option;
1969
+ opt.textContent = option;
1970
+ discipline.appendChild(opt);
1971
+ }
1972
+ discipline.value = base.discipline ?? "";
1973
+ discipline.addEventListener("change", () => commitField("discipline", discipline.value));
1974
+ fieldRow("Discipline", discipline);
1975
+ const tier = document.createElement("select");
1976
+ tier.setAttribute("aria-label", "Intensity tier");
1977
+ tier.className = "flex-1 min-w-0 rounded-md border border-input bg-background px-1.5 text-[11px] text-muted-foreground outline-none";
1978
+ const tierUnset = document.createElement("option");
1979
+ tierUnset.value = "";
1980
+ tierUnset.textContent = "Unset";
1981
+ tier.appendChild(tierUnset);
1982
+ for (const option of ["low", "moderate", "high"]) {
1983
+ const opt = document.createElement("option");
1984
+ opt.value = option;
1985
+ opt.textContent = option;
1986
+ tier.appendChild(opt);
1987
+ }
1988
+ tier.value = base.intensityTier ?? "";
1989
+ tier.addEventListener("change", () => commitField("intensityTier", tier.value));
1990
+ fieldRow("Intensity tier", tier);
1991
+ return wrap;
1992
+ }
1670
1993
  destroy(dom) {
1671
1994
  widgetCleanup.get(dom)?.forEach((close) => close());
1672
1995
  widgetCleanup.delete(dom);
@@ -1700,7 +2023,7 @@ var EmptyFrontmatterWidget = class extends WidgetType {
1700
2023
  e.preventDefault();
1701
2024
  e.stopPropagation();
1702
2025
  pendingFocus.set(view, { kind: "key", key: "property" });
1703
- updateFrontmatter(view, "new", { property: "" });
2026
+ patchPropertyInView(view, "new", ["property"], "");
1704
2027
  });
1705
2028
  actionsRow.appendChild(addBtn);
1706
2029
  const addTagBtn = document.createElement("button");
@@ -1721,7 +2044,7 @@ var EmptyFrontmatterWidget = class extends WidgetType {
1721
2044
  }
1722
2045
  const draftRow = createTagDraftRow(view, root, "tags", (val) => {
1723
2046
  pendingFocus.set(view, { kind: "tag", key: "tags" });
1724
- updateFrontmatter(view, "new", { tags: [val] });
2047
+ patchPropertyInView(view, "new", ["tags"], [val]);
1725
2048
  });
1726
2049
  root.appendChild(draftRow);
1727
2050
  draftRow.querySelector("input")?.focus();
@@ -1775,7 +2098,7 @@ var frontmatterPreviewField = StateField.define({
1775
2098
  return buildFrontmatterDecos(state);
1776
2099
  },
1777
2100
  update(deco, tr) {
1778
- if (tr.docChanged || tr.reconfigured || tr.selection) {
2101
+ if (tr.docChanged || tr.reconfigured || tr.selection || tr.effects.some((e) => e.is(referenceIndexReload))) {
1779
2102
  return buildFrontmatterDecos(tr.state);
1780
2103
  }
1781
2104
  return deco;
@@ -4291,7 +4614,8 @@ var SOURCE_OPTIONS = WQL_SOURCE_VALUES.map((s) => ({
4291
4614
  guides: "Static guide pages",
4292
4615
  playground: "Playground scratch pages",
4293
4616
  dashboards: "Dashboard notes",
4294
- efforts: "Exercise library notes"
4617
+ efforts: "Exercise library notes",
4618
+ equipment: "Equipment library notes"
4295
4619
  }[s]
4296
4620
  }));
4297
4621
  var PLANE_OPTIONS = WQL_RESULT_PLANES.map((v) => ({ value: v, label: v }));
@@ -12333,6 +12657,6 @@ function editorPreset(optionsOrDialect = "markdown") {
12333
12657
  return extensions;
12334
12658
  }
12335
12659
 
12336
- export { AGG_OPTIONS, CANONICAL_BLOCK_TYPES, CLAUSE_META, ComposerRegistry, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DEFAULT_OUTPUT_FILTERS, DEFAULT_PRIMARY_FILTER, DefaultFrontmatterWidget, EditorDialog, GROUPBY_OPTIONS, GoalRings, KIND_OPTIONS, METRIC_OPTIONS, MULTI_VALUE_TYPES, MetricBadge, OUTPUT_TYPE_CLASS, OUTPUT_TYPE_DOT, OutputFilterPills, OutputStatementsTable, PLANE_OPTIONS, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TARGET_OPTIONS, TIME_OPTIONS, TONE_CLASS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockTypesFromBlocks, canonicalSuggestionItems, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editQueryClause, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, extractMetricsByCategory, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatClockTime, formatMMSS, formatTimestamp, frontmatterPreview, frontmatterPreviewField, frontmatterSuggestions, frontmatterVisibility, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, linkPreview, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, matchFilterTypeahead, mergeSeries, mergeSuggestionItems, mergeTagSuggestions, navigationFacet, normalizeOutputFilter, patchBlockQuery, presentBadges, previewDecorations, queryBlockPreview, readSessionRpe, registerCustomCompletionSource, registeredSectionWidgets, removeRuntimePanel, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sectionIdentity, sectionIdentityHistory, sectionMove, sectionRestore, sectionSaved, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setSuggestionBinding, smartIncrement, summarizeAggregate, summarizeFind, summarizePipeline, tagsFromStaticBlocks, toChartResult, toggleWidgetEdit, tooltipTimestamp, unregisterCustomCompletionSource, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useVisualViewportRect, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToPills, wrapInTimeFence };
12337
- //# sourceMappingURL=chunk-RAM3QIP4.mjs.map
12338
- //# sourceMappingURL=chunk-RAM3QIP4.mjs.map
12660
+ export { AGG_OPTIONS, CANONICAL_BLOCK_TYPES, CLAUSE_META, ComposerRegistry, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DEFAULT_OUTPUT_FILTERS, DEFAULT_PRIMARY_FILTER, DefaultFrontmatterWidget, EditorDialog, GROUPBY_OPTIONS, GoalRings, KIND_OPTIONS, METRIC_OPTIONS, MULTI_VALUE_TYPES, MetricBadge, OUTPUT_TYPE_CLASS, OUTPUT_TYPE_DOT, OutputFilterPills, OutputStatementsTable, PLANE_OPTIONS, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TARGET_OPTIONS, TIME_OPTIONS, TONE_CLASS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockTypesFromBlocks, canonicalSuggestionItems, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editQueryClause, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, extractMetricsByCategory, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatClockTime, formatMMSS, formatTimestamp, frontmatterPreview, frontmatterPreviewField, frontmatterReferenceIndex, frontmatterSuggestions, frontmatterVisibility, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, linkPreview, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, matchFilterTypeahead, mergeSeries, mergeSuggestionItems, mergeTagSuggestions, navigationFacet, normalizeOutputFilter, patchBlockQuery, presentBadges, previewDecorations, queryBlockPreview, readSessionRpe, referenceIndexReload, registerCustomCompletionSource, registeredSectionWidgets, removeRuntimePanel, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sectionIdentity, sectionIdentityHistory, sectionMove, sectionRestore, sectionSaved, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setSuggestionBinding, smartIncrement, summarizeAggregate, summarizeFind, summarizePipeline, tagsFromStaticBlocks, toChartResult, toggleWidgetEdit, tooltipTimestamp, unregisterCustomCompletionSource, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useVisualViewportRect, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToPills, wrapInTimeFence };
12661
+ //# sourceMappingURL=chunk-SNG34RG2.mjs.map
12662
+ //# sourceMappingURL=chunk-SNG34RG2.mjs.map