@bitcobblers/wod-wiki-ui 0.35.2116 → 0.35.2117

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.
@@ -4,8 +4,9 @@ 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
6
  import { whiteboardScriptLanguage, createParser, metricPresentation, EFFORT_DISCIPLINES, whiteboardScript } from '@bitcobblers/wod-wiki-lang';
7
- import { blockContentId, matchDialectFence as matchDialectFence$1, generateSectionId as generateSectionId$1, MetricType } from '@bitcobblers/wod-wiki-core';
7
+ import { mapNoteBlockChanges, validateNoteBlocks, reconcileNoteBlocks, parseDocumentSections, actionableSectionKind, MetricType } from '@bitcobblers/wod-wiki-core';
8
8
  export { blockContentId } from '@bitcobblers/wod-wiki-core';
9
+ import { invertedEffects, history, defaultKeymap, historyKeymap, indentWithTab, cursorPageUp, cursorPageDown, cursorDocStart, cursorDocEnd } from '@codemirror/commands';
9
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
11
  export { CONTENT_GROUPING_DIMENSIONS } from '@bitcobblers/wod-wiki-wql';
11
12
  import { snippet, autocompletion, closeBrackets, closeBracketsKeymap, completionStatus, startCompletion, moveCompletionSelection, setSelectedCompletion, currentCompletions, acceptCompletion, closeCompletion, CompletionContext, ifNotIn, completeFromList, snippetCompletion } from '@codemirror/autocomplete';
@@ -19,7 +20,6 @@ import { twMerge } from 'tailwind-merge';
19
20
  import { ResponsiveContainer, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Line, BarChart, Bar, Cell, PieChart, Pie } from 'recharts';
20
21
  import { createPortal } from 'react-dom';
21
22
  import { renderToStaticMarkup } from 'react-dom/server';
22
- import { history, defaultKeymap, historyKeymap, indentWithTab, cursorPageUp, cursorPageDown, cursorDocStart, cursorDocEnd } from '@codemirror/commands';
23
23
  import { PencilSquareIcon, CheckIcon, ArrowUturnLeftIcon } from '@heroicons/react/20/solid';
24
24
  import { NodeType, NodeProp, NodeSet, Parser, Tree, parseMixed, NodeWeakMap, IterMode } from '@lezer/common';
25
25
  import { ContextTracker, ExternalTokenizer, LRParser, LocalTokenGroup } from '@lezer/lr';
@@ -367,255 +367,202 @@ var linkOpen = [
367
367
  ctrlClickPlugin,
368
368
  linkCursorTheme
369
369
  ];
370
- var VALID_DIALECTS = ["time", "log"];
370
+ var sectionIdentity = Facet.define({ combine: (values2) => values2[0] });
371
+ var registeredSectionWidgets = Facet.define({ combine: (values2) => values2.length ? values2.flat() : void 0 });
371
372
  var forceSectionParse = StateEffect.define();
372
- function generateSectionId(type, cmStartLine, content) {
373
- return generateSectionId$1(type, cmStartLine - 1, content);
374
- }
375
- function mapIdentities(oldSections, newSections) {
376
- return newSections.map((nSec) => {
377
- const match = oldSections.find(
378
- (oSec) => oSec.type === nSec.type && Math.abs(oSec.startLine - nSec.startLine) <= 2
379
- );
380
- return match ? { ...nSec, id: match.id } : nSec;
381
- });
382
- }
383
- function matchDialectFence(trimmed) {
384
- const match = matchDialectFence$1(trimmed);
385
- if (!match) return null;
386
- return { dialect: match.dialect, sport: match.sport };
387
- }
388
- function matchWidgetFence(trimmed) {
389
- const match = trimmed.match(/^```\s*widget:([\w-]+)\s*$/);
390
- return match ? match[1] : null;
391
- }
392
- function matchContentFence(trimmed) {
393
- const match = trimmed.match(/^```\s*query(?:[:\s](.*))?$/i);
394
- if (!match) return null;
395
- const rawSuffix = (match[1] ?? "").trim();
396
- if (rawSuffix === "") return { kind: "query" };
397
- const parsed = parseQueryWidgetSuffix(rawSuffix.replace(/^:/, ""));
398
- return {
399
- kind: "query",
400
- widgetType: parsed.type,
401
- widgetError: parsed.error
402
- };
403
- }
404
- function matchGenericFence(trimmed) {
405
- const match = trimmed.match(/^```\s*(\S+)\s*$/);
406
- if (!match) return null;
407
- const tag = match[1].toLowerCase();
408
- if (VALID_DIALECTS.includes(tag)) return null;
409
- if (tag.startsWith("widget:")) return null;
410
- if (tag.startsWith("query")) return null;
411
- return match[1];
412
- }
413
- function matchMarkdownEmbed(trimmed) {
414
- const imgMatch = trimmed.match(/^!\[([^\]]*)\]\(([^)]+)\)$/);
415
- if (imgMatch) {
416
- const label = imgMatch[1];
417
- const url = imgMatch[2];
418
- return { type: "image", url, label };
419
- }
420
- const linkMatch = trimmed.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
421
- if (linkMatch) {
422
- const label = linkMatch[1];
423
- const url = linkMatch[2];
424
- return { type: "link", url, label };
373
+ var sectionSaved = StateEffect.define();
374
+ var sectionRestore = StateEffect.define();
375
+ var sectionMove = StateEffect.define();
376
+ var restoreHistoryIdentity = StateEffect.define({
377
+ map(value, changes) {
378
+ const blocks = {};
379
+ for (const block of Object.values(value.blocks)) {
380
+ const from = changes.mapPos(block.from, 1);
381
+ const to = changes.mapPos(block.to, -1);
382
+ if (from < to) blocks[block.id] = { ...block, from, to };
383
+ }
384
+ return { rawContent: value.rawContent, blocks };
425
385
  }
426
- return null;
386
+ });
387
+ function sourceCoordinates(rawContent) {
388
+ const rawStarts = [0];
389
+ const editorStarts = [0];
390
+ let removed = 0;
391
+ for (const match of rawContent.matchAll(/\r\n|\r|\n/g)) {
392
+ removed += match[0].length - 1;
393
+ rawStarts.push(match.index + match[0].length);
394
+ editorStarts.push(match.index + match[0].length - removed);
395
+ }
396
+ return { rawStarts, editorStarts };
397
+ }
398
+ function toSourcePosition(state, rawStarts, position) {
399
+ const line = state.doc.lineAt(position);
400
+ return rawStarts[line.number - 1] + position - line.from;
401
+ }
402
+ function toEditorBlocks(state) {
403
+ const blocks = {};
404
+ for (const block of Object.values(state.noteBlocks)) {
405
+ const section = state.sections.find((section2) => section2.id === block.id);
406
+ if (section) blocks[block.id] = { ...block, from: section.from, to: section.to };
407
+ }
408
+ return blocks;
409
+ }
410
+ function deriveState(state, rawContent, sourceRevision, lineage, savedVersions, previousSections = []) {
411
+ const registeredWidgets = state.facet(registeredSectionWidgets);
412
+ const noteBlocks = reconcileNoteBlocks(rawContent, { sourceRevision, blocks: lineage, registeredWidgets });
413
+ const coordinates = sourceCoordinates(rawContent);
414
+ const sections = parseDocumentSections(rawContent, { registeredWidgets }).map((section) => {
415
+ const start = coordinates.editorStarts[section.startLine];
416
+ const end = coordinates.editorStarts[section.endLine] + section.to - coordinates.rawStarts[section.endLine];
417
+ const block = actionableSectionKind(section) ? Object.values(noteBlocks).find((block2) => block2.from === section.from && block2.to === section.to) : void 0;
418
+ const prior = previousSections.find((prior2) => prior2.from === start && prior2.to === end && prior2.type === (section.type === "title" ? "markdown" : section.type));
419
+ const query = section.querySuffix ? parseQueryWidgetSuffix(section.querySuffix) : void 0;
420
+ const subtype = section.subtype;
421
+ return {
422
+ id: block?.id ?? prior?.id ?? section.id,
423
+ type: section.type === "title" ? "markdown" : section.type,
424
+ ...subtype === "heading" || subtype === "paragraph" || subtype === "list" || subtype === "blockquote" || subtype === "table" ? { subtype } : {},
425
+ from: start,
426
+ to: end,
427
+ startLine: section.startLine + 1,
428
+ endLine: section.endLine + 1,
429
+ ...section.contentFrom !== void 0 ? { contentFrom: coordinates.editorStarts[section.startLine + 1] ?? end } : {},
430
+ ...section.contentTo !== void 0 ? { contentTo: coordinates.editorStarts[section.endLine] - (section.type === "frontmatter" ? 1 : 0) } : {},
431
+ sport: section.sport,
432
+ widgetName: section.widgetName,
433
+ contentId: section.contentId,
434
+ queryType: query?.type,
435
+ queryError: query?.error,
436
+ embed: section.embed
437
+ };
438
+ });
439
+ for (const block of Object.values(noteBlocks)) block.version = savedVersions[block.id] ?? block.version;
440
+ return { sections, rawContent, sourceRevision, noteBlocks, savedVersions };
427
441
  }
428
- function detectMarkdownSubtype(lines) {
429
- const first = lines.find((l) => l.trim().length > 0)?.trim() ?? "";
430
- if (/^#{1,6}\s/.test(first)) return "heading";
431
- if (/^[-*+]\s|^\d+\.\s/.test(first)) return "list";
432
- if (/^>\s?/.test(first)) return "blockquote";
433
- if (first.startsWith("|") && lines.some((l) => /^\|[\s:]*-+/.test(l.trim()))) return "table";
434
- return "paragraph";
435
- }
436
- function scanFenced(state, openLineNum) {
437
- const openLine = state.doc.line(openLineNum);
438
- const contentFrom = openLine.to + 1;
439
- for (let i = openLineNum + 1; i <= state.doc.lines; i++) {
440
- const l = state.doc.line(i);
441
- if (l.text.trim().startsWith("```")) {
442
- return { closeLine: i, contentFrom, contentTo: l.from };
443
- }
444
- }
445
- const last = state.doc.line(state.doc.lines);
446
- return { closeLine: state.doc.lines, contentFrom, contentTo: last.to };
447
- }
448
- function parseSections(state) {
449
- const sections = [];
450
- let currentMdLines = [];
451
- let mdStartLine = 1;
452
- let mdStartPos = 0;
453
- function flushMarkdown(endLine, endPos) {
454
- if (currentMdLines.length === 0) return;
455
- const content = currentMdLines.join("\n");
456
- if (content.trim().length > 0) {
457
- const embed = currentMdLines.length === 1 ? matchMarkdownEmbed(content.trim()) : null;
458
- if (embed) {
459
- sections.push({
460
- id: generateSectionId("embed", mdStartLine, content),
461
- type: "embed",
462
- from: mdStartPos,
463
- to: endPos,
464
- startLine: mdStartLine,
465
- endLine,
466
- embed
467
- });
468
- } else {
469
- sections.push({
470
- id: generateSectionId("markdown", mdStartLine, content),
471
- type: "markdown",
472
- subtype: detectMarkdownSubtype(currentMdLines),
473
- from: mdStartPos,
474
- to: endPos,
475
- startLine: mdStartLine,
476
- endLine
477
- });
478
- }
479
- }
480
- currentMdLines = [];
481
- }
482
- let lineNum = 1;
483
- while (lineNum <= state.doc.lines) {
484
- const line = state.doc.line(lineNum);
485
- const trimmed = line.text.trim();
486
- const dialectMatch = matchDialectFence(trimmed);
487
- const widgetMatch = matchWidgetFence(trimmed);
488
- const contentMatch = matchContentFence(trimmed);
489
- const genericFence = matchGenericFence(trimmed);
490
- if (dialectMatch || widgetMatch || contentMatch || genericFence) {
491
- flushMarkdown(lineNum - 1, line.from);
492
- const { closeLine, contentFrom, contentTo } = scanFenced(state, lineNum);
493
- const closeLineObj = state.doc.line(closeLine);
494
- const innerContent = state.doc.sliceString(contentFrom, contentTo);
495
- if (dialectMatch) {
496
- sections.push({
497
- id: generateSectionId(dialectMatch.dialect, lineNum, innerContent),
498
- type: dialectMatch.dialect,
499
- from: line.from,
500
- to: closeLineObj.to,
501
- startLine: lineNum,
502
- endLine: closeLine,
503
- contentFrom,
504
- contentTo,
505
- sport: dialectMatch.sport,
506
- contentId: blockContentId(innerContent)
507
- });
508
- } else if (widgetMatch) {
509
- sections.push({
510
- id: generateSectionId("widget", lineNum, innerContent),
511
- type: "widget",
512
- widgetName: widgetMatch,
513
- from: line.from,
514
- to: closeLineObj.to,
515
- startLine: lineNum,
516
- endLine: closeLine,
517
- contentFrom,
518
- contentTo
519
- });
520
- } else if (contentMatch) {
521
- sections.push({
522
- id: generateSectionId("query", lineNum, innerContent),
523
- type: "query",
524
- from: line.from,
525
- to: closeLineObj.to,
526
- startLine: lineNum,
527
- endLine: closeLine,
528
- contentFrom,
529
- contentTo,
530
- queryType: contentMatch.widgetType,
531
- queryError: contentMatch.widgetError
532
- });
533
- } else if (genericFence) {
534
- sections.push({
535
- id: generateSectionId("code", lineNum, innerContent),
536
- type: "code",
537
- from: line.from,
538
- to: closeLineObj.to,
539
- startLine: lineNum,
540
- endLine: closeLine,
541
- contentFrom,
542
- contentTo
543
- });
544
- }
545
- lineNum = closeLine + 1;
546
- mdStartLine = lineNum;
547
- mdStartPos = lineNum <= state.doc.lines ? state.doc.line(lineNum).from : state.doc.length;
548
- continue;
549
- }
550
- if (trimmed === "---") {
551
- const lineCount = state.doc.lines;
552
- const nextLineText = lineNum < lineCount ? state.doc.line(lineNum + 1).text.trim() : "";
553
- if (nextLineText !== "") {
554
- let foundClose = false;
555
- let closeLine = lineNum;
556
- let hasKeyValueLine = false;
557
- for (let j = lineNum + 1; j <= lineCount; j++) {
558
- const jTrimmed = state.doc.line(j).text.trim();
559
- if (matchDialectFence(jTrimmed) || matchGenericFence(jTrimmed)) break;
560
- if (jTrimmed === "---") {
561
- closeLine = j;
562
- foundClose = true;
563
- break;
564
- }
565
- if (/^[A-Za-z_][\w-]*\s*:/.test(jTrimmed)) {
566
- hasKeyValueLine = true;
442
+ var sectionField = StateField.define({
443
+ create(state) {
444
+ const initial = state.facet(sectionIdentity);
445
+ const rawContent = initial?.rawContent ?? state.doc.toString();
446
+ if (rawContent.replace(/\r\n|\r/g, "\n") !== state.doc.toString()) throw new Error("Editor source and identity map disagree");
447
+ if (initial) validateNoteBlocks(rawContent, initial.blocks, initial.sourceRevision, { registeredWidgets: state.facet(registeredSectionWidgets) });
448
+ const savedVersions = Object.fromEntries(Object.values(initial?.blocks ?? {}).map((block) => [block.id, block.version]));
449
+ return deriveState(state, rawContent, initial?.sourceRevision ?? 1, initial?.blocks ?? {}, savedVersions);
450
+ },
451
+ update(value, tr) {
452
+ let rawContent = value.rawContent;
453
+ let lineage = value.noteBlocks;
454
+ let sourceRevision = value.sourceRevision;
455
+ let savedVersions = value.savedVersions;
456
+ if (tr.docChanged) {
457
+ const { rawStarts } = sourceCoordinates(rawContent);
458
+ const changes = [];
459
+ const lineBreak = rawContent.includes("\r\n") ? "\r\n" : rawContent.includes("\r") ? "\r" : "\n";
460
+ tr.changes.iterChanges((fromA, toA, fromB, toB) => changes.push({
461
+ from: toSourcePosition(tr.startState, rawStarts, fromA),
462
+ to: toSourcePosition(tr.startState, rawStarts, toA),
463
+ insert: tr.newDoc.sliceString(fromB, toB, lineBreak)
464
+ }));
465
+ lineage = mapNoteBlockChanges(lineage, changes);
466
+ for (let i = changes.length - 1; i >= 0; i--) {
467
+ const change = changes[i];
468
+ rawContent = rawContent.slice(0, change.from) + change.insert + rawContent.slice(change.to);
469
+ }
470
+ if (tr.isUserEvent("move.drop")) {
471
+ const moves = [];
472
+ tr.changes.iterChanges((fromA, toA, fromB, toB) => moves.push({ fromA, toA, fromB, toB }));
473
+ const deletion = moves.filter((change) => change.toA > change.fromA && change.fromB === change.toB);
474
+ const insertion = moves.filter((change) => change.fromA === change.toA && change.toB > change.fromB);
475
+ if (deletion.length === 1 && insertion.length === 1) {
476
+ const removed = deletion[0];
477
+ const added = insertion[0];
478
+ if (tr.startState.doc.sliceString(removed.fromA, removed.toA) === tr.newDoc.sliceString(added.fromB, added.toB)) {
479
+ const currentStarts = sourceCoordinates(rawContent).rawStarts;
480
+ for (const section of value.sections) {
481
+ const block = value.noteBlocks[section.id];
482
+ if (block && section.from >= removed.fromA && section.to <= removed.toA) {
483
+ lineage[block.id] = {
484
+ ...block,
485
+ from: toSourcePosition(tr.state, currentStarts, added.fromB + section.from - removed.fromA),
486
+ to: toSourcePosition(tr.state, currentStarts, added.fromB + section.to - removed.fromA)
487
+ };
488
+ }
489
+ }
567
490
  }
568
491
  }
569
- if (foundClose && hasKeyValueLine) {
570
- flushMarkdown(lineNum - 1, line.from);
571
- const closeLineObj = state.doc.line(closeLine);
572
- const content = state.doc.sliceString(line.from, closeLineObj.to);
573
- sections.push({
574
- id: generateSectionId("frontmatter", lineNum, content),
575
- type: "frontmatter",
576
- from: line.from,
577
- to: closeLineObj.to,
578
- startLine: lineNum,
579
- endLine: closeLine,
580
- contentFrom: line.to + 1,
581
- contentTo: closeLineObj.from - 1
582
- });
583
- lineNum = closeLine + 1;
584
- mdStartLine = lineNum;
585
- mdStartPos = lineNum <= lineCount ? state.doc.line(lineNum).from : state.doc.length;
586
- continue;
492
+ }
493
+ if (tr.isUserEvent("move.line")) {
494
+ const currentStarts = sourceCoordinates(rawContent).rawStarts;
495
+ for (let i = 0; i < tr.startState.selection.ranges.length; i++) {
496
+ const before = tr.startState.selection.ranges[i];
497
+ const after = tr.newSelection.ranges[i];
498
+ if (!after) continue;
499
+ const firstLine = tr.startState.doc.lineAt(before.from);
500
+ const lastLine = tr.startState.doc.lineAt(before.to > before.from && tr.startState.doc.lineAt(before.to).from === before.to ? before.to - 1 : before.to);
501
+ const delta = after.anchor - before.anchor;
502
+ for (const section of value.sections) {
503
+ const block = value.noteBlocks[section.id];
504
+ if (block && section.from >= firstLine.from && section.to <= lastLine.to) {
505
+ lineage[block.id] = {
506
+ ...block,
507
+ from: toSourcePosition(tr.state, currentStarts, section.from + delta),
508
+ to: toSourcePosition(tr.state, currentStarts, section.to + delta)
509
+ };
510
+ }
511
+ }
587
512
  }
588
513
  }
589
514
  }
590
- if (currentMdLines.length === 0) {
591
- mdStartLine = lineNum;
592
- mdStartPos = line.from;
593
- }
594
- currentMdLines.push(line.text);
595
- lineNum++;
596
- }
597
- flushMarkdown(state.doc.lines, state.doc.length);
598
- return sections;
599
- }
600
- var sectionField = StateField.define({
601
- create(state) {
602
- return { sections: parseSections(state) };
603
- },
604
- update(value, tr) {
605
- if (tr.docChanged || tr.effects.some((e) => e.is(forceSectionParse))) {
606
- const newSections = parseSections(tr.state);
607
- return { sections: mapIdentities(value.sections, newSections) };
515
+ for (const effect of tr.effects) {
516
+ if (effect.is(sectionSaved)) {
517
+ sourceRevision = Math.max(sourceRevision, effect.value.sourceRevision);
518
+ savedVersions = { ...savedVersions };
519
+ for (const block of Object.values(effect.value.blocks)) savedVersions[block.id] = Math.max(savedVersions[block.id] ?? 1, block.version);
520
+ }
521
+ if (effect.is(sectionRestore)) {
522
+ if (effect.value.rawContent.replace(/\r\n|\r/g, "\n") !== tr.newDoc.toString()) throw new Error("Restored source does not match editor");
523
+ validateNoteBlocks(effect.value.rawContent, effect.value.blocks, effect.value.sourceRevision, { registeredWidgets: tr.state.facet(registeredSectionWidgets) });
524
+ rawContent = effect.value.rawContent;
525
+ lineage = effect.value.blocks;
526
+ sourceRevision = effect.value.sourceRevision;
527
+ savedVersions = { ...savedVersions, ...Object.fromEntries(Object.values(lineage).map((block) => [block.id, block.version])) };
528
+ }
529
+ if (effect.is(restoreHistoryIdentity)) {
530
+ const exactHistory = tr.effects.some((candidate) => candidate.is(restoreHistoryIdentity) && candidate.value.rawContent.replace(/\r\n|\r/g, "\n") === tr.newDoc.toString());
531
+ if (exactHistory && effect.value.rawContent.replace(/\r\n|\r/g, "\n") !== tr.newDoc.toString()) continue;
532
+ if (effect.value.rawContent.replace(/\r\n|\r/g, "\n") === tr.newDoc.toString()) rawContent = effect.value.rawContent;
533
+ const { rawStarts } = sourceCoordinates(rawContent);
534
+ lineage = Object.fromEntries(Object.values(effect.value.blocks).map((block) => [block.id, {
535
+ ...block,
536
+ from: toSourcePosition(tr.state, rawStarts, block.from),
537
+ to: toSourcePosition(tr.state, rawStarts, block.to)
538
+ }]));
539
+ }
540
+ if (effect.is(sectionMove)) {
541
+ const prior = value.noteBlocks[effect.value.id];
542
+ if (!prior || lineage[prior.id]) throw new Error("Explicit move must remove the original occurrence");
543
+ const { rawStarts } = sourceCoordinates(rawContent);
544
+ const from = toSourcePosition(tr.state, rawStarts, effect.value.from);
545
+ const to = toSourcePosition(tr.state, rawStarts, effect.value.to);
546
+ if (rawContent.slice(from, to) !== value.rawContent.slice(prior.from, prior.to)) throw new Error("Explicit move changed source");
547
+ lineage = { ...lineage, [prior.id]: { ...prior, from, to } };
548
+ }
549
+ }
550
+ if (tr.docChanged || tr.effects.some((effect) => effect.is(forceSectionParse) || effect.is(sectionRestore) || effect.is(sectionSaved) || effect.is(restoreHistoryIdentity))) {
551
+ const previous = value.sections.map((section) => ({ ...section, from: tr.changes.mapPos(section.from, 1), to: tr.changes.mapPos(section.to, -1) }));
552
+ return deriveState(tr.state, rawContent, sourceRevision, lineage, savedVersions, previous);
608
553
  }
609
554
  return value;
610
555
  }
611
556
  });
557
+ var sectionIdentityHistory = invertedEffects.of((tr) => {
558
+ const value = tr.startState.field(sectionField, false);
559
+ return value && tr.docChanged ? [restoreHistoryIdentity.of({ rawContent: value.rawContent, blocks: toEditorBlocks(value) })] : [];
560
+ });
612
561
  function sectionAtPos(state, pos) {
613
- const { sections } = state.field(sectionField);
614
- return sections.find((s) => pos >= s.from && pos <= s.to) ?? null;
562
+ return state.field(sectionField).sections.find((section) => pos >= section.from && pos <= section.to) ?? null;
615
563
  }
616
564
  function activeCursorSection(state) {
617
- const pos = state.selection.main.head;
618
- return sectionAtPos(state, pos);
565
+ return sectionAtPos(state, state.selection.main.head);
619
566
  }
620
567
 
621
568
  // src/extensions/whiteboard-linter.ts
@@ -2489,18 +2436,9 @@ function dispatchExpandRuntimePanel(view, sectionId, expanded) {
2489
2436
  function sessionQueryWql(resultId) {
2490
2437
  return `:session{result:${resultId}}`;
2491
2438
  }
2492
- function sessionQueryInsert(state, blockId, resultId, runBlock) {
2439
+ function sessionQueryInsert(state, blockId, resultId) {
2493
2440
  const sections = state.field(sectionField).sections;
2494
- let section = sections.find((s) => s.id === blockId);
2495
- if (!section && runBlock?.contentId) {
2496
- section = sections.find((s) => s.contentId === runBlock.contentId);
2497
- }
2498
- if (!section && runBlock?.id) {
2499
- section = sections.find((s) => s.id === runBlock.id);
2500
- }
2501
- if (!section && runBlock) {
2502
- section = sections.find((s) => s.type === "time" || s.type === "log");
2503
- }
2441
+ const section = sections.find((s) => s.id === blockId);
2504
2442
  if (!section || section.type !== "time" && section.type !== "log") {
2505
2443
  return null;
2506
2444
  }
@@ -4728,7 +4666,7 @@ function mergeTagSuggestions(userLabels, corpusLabels) {
4728
4666
  []
4729
4667
  ).map((item) => item.value);
4730
4668
  }
4731
- var CANONICAL_BLOCK_TYPES = ["wod", "movement", "workout"];
4669
+ var CANONICAL_BLOCK_TYPES = ["wod", "query", "widget", "embed"];
4732
4670
  function canonicalSuggestionItems(values2) {
4733
4671
  return values2.map((value) => ({ value, label: value.charAt(0).toUpperCase() + value.slice(1) }));
4734
4672
  }
@@ -12365,6 +12303,7 @@ function editorPreset(optionsOrDialect = "markdown") {
12365
12303
  extensions.push(
12366
12304
  markdown({ codeLanguages: resolveCodeLanguage }),
12367
12305
  sectionField,
12306
+ sectionIdentityHistory,
12368
12307
  previewDecorations,
12369
12308
  wodLinter,
12370
12309
  wodAutocompletion,
@@ -12383,6 +12322,6 @@ function editorPreset(optionsOrDialect = "markdown") {
12383
12322
  return extensions;
12384
12323
  }
12385
12324
 
12386
- 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, removeRuntimePanel, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, 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 };
12387
- //# sourceMappingURL=chunk-GUN6PZNI.mjs.map
12388
- //# sourceMappingURL=chunk-GUN6PZNI.mjs.map
12325
+ 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 };
12326
+ //# sourceMappingURL=chunk-4WX7YECS.mjs.map
12327
+ //# sourceMappingURL=chunk-4WX7YECS.mjs.map