@bitcobblers/wod-wiki-ui 0.48.2175 → 0.49.2177

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.
@@ -9,7 +9,7 @@ export { blockContentId } from '@bitcobblers/wod-wiki-core';
9
9
  import { invertedEffects, history, defaultKeymap, historyKeymap, indentWithTab, cursorPageUp, cursorPageDown, cursorDocStart, cursorDocEnd } from '@codemirror/commands';
10
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, wqlLanguage, parseFrontmatterBody, wqlCompletionSource, parseQuery, isFindQuery, isDashboardWidgetType, unknownWidgetTypeMessage, resolveWidgetType, PLANNED_WIDGET_TYPES, notebookSlugOfSourceId, isPipelineQuery, wqlGroupingDimensions, isAggregateQuery, serialize, allowedFilterTypesForTarget, CONTENT_GROUPING_DIMENSIONS, substituteTokens, unknownTokensMessage, wql, WQL_NOTE_DEFAULT_SOURCES, wqlHighlightStyle, supportsWqlFilterKey } from '@bitcobblers/wod-wiki-wql';
11
11
  export { CONTENT_GROUPING_DIMENSIONS } from '@bitcobblers/wod-wiki-wql';
12
- import { snippet, autocompletion, CompletionContext, closeBrackets, closeBracketsKeymap, completionStatus, startCompletion, moveCompletionSelection, setSelectedCompletion, currentCompletions, acceptCompletion, closeCompletion, ifNotIn, completeFromList, snippetCompletion } from '@codemirror/autocomplete';
12
+ import { snippet, autocompletion, CompletionContext, closeBrackets, closeBracketsKeymap, completionStatus, closeCompletion, startCompletion, moveCompletionSelection, setSelectedCompletion, currentCompletions, acceptCompletion, ifNotIn, completeFromList, snippetCompletion } from '@codemirror/autocomplete';
13
13
  import { createRoot } from 'react-dom/client';
14
14
  import * as React2 from 'react';
15
15
  import React2__default, { createElement, useMemo, useState, useCallback, useEffect, useId, useRef, useSyncExternalStore } from 'react';
@@ -5482,7 +5482,7 @@ function InlineClauseEditor({
5482
5482
  const meta = getClauseMeta(clause2.type);
5483
5483
  const current = clause2.value.trim();
5484
5484
  const typedIdx = filteredItems.length;
5485
- const shownValues = selectedValues.length > 0 ? selectedValues : !isMulti && current ? [current] : [];
5485
+ const shownValues = selectedValues;
5486
5486
  const reorder = (i, dir) => {
5487
5487
  if (!onReorder) return;
5488
5488
  const to = i + dir;
@@ -5494,24 +5494,15 @@ function InlineClauseEditor({
5494
5494
  return /* @__PURE__ */ jsxs(
5495
5495
  "div",
5496
5496
  {
5497
- className: "mx-0.5 rounded-xl border border-border bg-popover shadow-md p-1",
5497
+ className: "min-w-0 pt-0.5",
5498
5498
  "data-testid": "wql-clause-editor",
5499
5499
  "data-clause-type": clause2.type,
5500
5500
  children: [
5501
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2 pt-1 pb-1.5", children: [
5502
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[11px]", children: meta.icon }),
5503
- /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[11px] font-semibold text-foreground font-mono", children: meta.label }),
5504
- /* @__PURE__ */ jsxs("span", { className: "hidden sm:block ml-auto text-[10px] text-muted-foreground/70 font-mono truncate", children: [
5505
- "\u2191\u2193 move \xB7 Enter ",
5506
- isMulti ? "add/remove" : "set",
5507
- " \xB7 Esc done \xB7 Tab exits"
5508
- ] })
5509
- ] }),
5510
- shownValues.length > 0 && /* @__PURE__ */ jsxs("div", { className: cn("px-2 pb-1.5", isMulti && "border-b border-border/50"), children: [
5501
+ isMulti && shownValues.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-b border-border/50 px-2 pb-1.5", children: [
5511
5502
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 sm:gap-1 max-h-24 overflow-y-auto overscroll-contain touch-pan-y sm:max-h-none sm:overflow-visible", children: shownValues.map((v, i) => /* @__PURE__ */ jsxs(
5512
5503
  "span",
5513
5504
  {
5514
- className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-primary/20 text-primary text-xs sm:text-[10px] font-mono min-h-11 sm:min-h-0",
5505
+ className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-primary/15 text-primary text-xs sm:text-[10px] font-mono min-h-8 sm:min-h-0",
5515
5506
  children: [
5516
5507
  /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate", children: v }),
5517
5508
  onReorder && shownValues.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -5561,7 +5552,7 @@ function InlineClauseEditor({
5561
5552
  role: "listbox",
5562
5553
  "aria-label": `${meta.label} options`,
5563
5554
  "aria-multiselectable": isMulti || void 0,
5564
- className: "max-h-[min(45svh,20rem)] sm:max-h-44 overflow-y-auto overscroll-contain touch-pan-y flex flex-col gap-0.5",
5555
+ className: "max-h-[min(38svh,16rem)] sm:max-h-36 overflow-y-auto overscroll-contain touch-pan-y flex flex-col gap-0.5 pt-1",
5565
5556
  children: [
5566
5557
  canCommitTyped && /* @__PURE__ */ jsxs(
5567
5558
  "button",
@@ -5575,19 +5566,19 @@ function InlineClauseEditor({
5575
5566
  onClick: () => onCommitTyped(typedValue),
5576
5567
  "data-testid": `clause-commit-typed-${clause2.type}`,
5577
5568
  className: cn(
5578
- "flex items-center justify-between px-2 py-2 sm:py-1 text-sm sm:text-xs text-left rounded hover:bg-muted/60 transition-colors font-mono min-h-12 sm:min-h-0",
5579
- highlightIdx === typedIdx && "bg-muted/60"
5569
+ "flex items-center justify-between px-2.5 py-2 sm:py-1.5 text-sm sm:text-xs text-left rounded-md hover:bg-muted/60 transition-colors font-mono min-h-11 sm:min-h-0",
5570
+ highlightIdx === typedIdx && "bg-muted/70 ring-1 ring-border"
5580
5571
  ),
5581
5572
  children: [
5582
5573
  /* @__PURE__ */ jsxs("span", { className: "truncate", children: [
5583
5574
  "Search for ",
5584
- /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
5575
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-foreground", children: [
5585
5576
  "\u201C",
5586
5577
  typedValue,
5587
5578
  "\u201D"
5588
5579
  ] })
5589
5580
  ] }),
5590
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 ml-1 shrink-0", children: "\u21B5" })
5581
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60 ml-1 shrink-0 font-sans text-xs", children: "\u21B5" })
5591
5582
  ]
5592
5583
  }
5593
5584
  ),
@@ -5606,29 +5597,39 @@ function InlineClauseEditor({
5606
5597
  onMouseEnter: () => onHighlight(idx),
5607
5598
  onClick: () => onCommitValue(item.value),
5608
5599
  className: cn(
5609
- "flex items-center justify-between px-2 py-2 sm:py-1 text-sm sm:text-xs text-left rounded transition-colors font-mono min-h-12 sm:min-h-0",
5610
- active ? "bg-primary/15 font-semibold" : "hover:bg-muted/60",
5611
- selected && "text-primary"
5600
+ "flex items-center justify-between px-2.5 py-2 sm:py-1.5 text-sm sm:text-xs text-left rounded-md transition-colors min-h-11 sm:min-h-0",
5601
+ active ? "bg-primary/10 text-foreground font-medium" : "hover:bg-muted/60 text-muted-foreground hover:text-foreground",
5602
+ selected && "text-primary font-medium"
5612
5603
  ),
5613
5604
  children: [
5614
- /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label }),
5615
- selected && /* @__PURE__ */ jsx(Check, { className: "w-3 h-3 shrink-0" })
5605
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2 min-w-0 flex-1", children: [
5606
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label }),
5607
+ item.label !== item.value && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "font-mono text-[11px] text-muted-foreground/70 shrink-0", children: item.value })
5608
+ ] }),
5609
+ selected && /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 text-primary shrink-0 ml-1.5" })
5616
5610
  ]
5617
5611
  },
5618
5612
  item.value
5619
5613
  );
5620
5614
  }),
5621
- emptyText && /* @__PURE__ */ jsx("div", { className: "px-2 py-2 sm:py-1.5 text-sm sm:text-xs text-muted-foreground italic", children: emptyText })
5615
+ emptyText && /* @__PURE__ */ jsx("div", { className: "px-2.5 py-2 text-sm sm:text-xs text-muted-foreground italic", children: emptyText })
5622
5616
  ]
5623
5617
  }
5624
5618
  ),
5625
- isMulti && onDone && /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 -mx-1 -mb-1 px-3 pt-1.5 pb-[max(0.375rem,env(safe-area-inset-bottom))] bg-popover rounded-b-xl flex justify-end", children: /* @__PURE__ */ jsxs(
5619
+ (filteredItems.length > 0 || canCommitTyped) && /* @__PURE__ */ jsxs("div", { className: "hidden sm:flex items-center justify-between px-2 pt-2 text-[10px] text-muted-foreground/70 font-mono border-t border-border/40 mt-1", children: [
5620
+ /* @__PURE__ */ jsxs("span", { children: [
5621
+ "\u2191\u2193 choose \xB7 Enter ",
5622
+ isMulti ? "toggle" : "set"
5623
+ ] }),
5624
+ /* @__PURE__ */ jsx("span", { children: "Tab next segment \xB7 Esc close" })
5625
+ ] }),
5626
+ isMulti && onDone && /* @__PURE__ */ jsx("div", { className: "pt-2 flex justify-end", children: /* @__PURE__ */ jsxs(
5626
5627
  "button",
5627
5628
  {
5628
5629
  type: "button",
5629
5630
  onClick: onDone,
5630
5631
  "data-testid": "wql-clause-editor-done",
5631
- className: "inline-flex w-full sm:w-auto items-center justify-center min-h-12 sm:min-h-9 px-3 rounded-lg bg-primary text-primary-foreground text-sm sm:text-xs font-semibold hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5632
+ className: "inline-flex w-full sm:w-auto items-center justify-center min-h-10 sm:min-h-7 px-3 rounded-md bg-primary text-primary-foreground text-xs font-semibold hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5632
5633
  children: [
5633
5634
  "Done",
5634
5635
  shownValues.length > 0 ? ` \xB7 ${shownValues.length} selected` : ""
@@ -5667,7 +5668,11 @@ var STATIC_OPTIONS = {
5667
5668
  groupby: GROUPBY_OPTIONS,
5668
5669
  metric: METRIC_OPTIONS,
5669
5670
  unit: UNIT_OPTIONS,
5670
- intensity: WQL_INTENSITY_TIERS.map((v) => ({ value: v, label: v }))
5671
+ intensity: WQL_INTENSITY_TIERS.map((v) => ({ value: v, label: v })),
5672
+ subscribed: [
5673
+ { value: "true", label: "Subscribed" },
5674
+ { value: "false", label: "All / unsubscribed" }
5675
+ ]
5671
5676
  };
5672
5677
  function tagsFromStaticBlocks(blocks) {
5673
5678
  const set = /* @__PURE__ */ new Set();
@@ -5965,7 +5970,7 @@ function WqlDiagnosticsStrip({
5965
5970
  "aria-live": "polite",
5966
5971
  className: cn(
5967
5972
  "flex flex-wrap items-center justify-between gap-x-4 gap-y-1.5 px-3 py-1.5 text-xs font-mono transition-colors",
5968
- header ? valid ? "border-b border-primary/30 text-muted-foreground" : "border-b border-destructive/50 bg-destructive/5 text-destructive" : cn(
5973
+ header ? valid ? "border-b border-border/60 bg-muted/20 text-muted-foreground" : "border-b border-destructive/40 bg-destructive/5 text-destructive" : cn(
5969
5974
  "rounded-lg border",
5970
5975
  valid ? "bg-muted/30 border-border text-muted-foreground" : "bg-destructive/5 border-destructive/30 text-destructive"
5971
5976
  ),
@@ -6295,23 +6300,128 @@ var completionIcons = {
6295
6300
  value: renderToStaticMarkup(createElement(Tag, { size: 16 }))
6296
6301
  };
6297
6302
  var SLOT_NODES = { Head: true, Filter: true, TagValue: true, Rollup: true };
6303
+ var activeSegmentEffect = StateEffect.define();
6304
+ var activeSegmentField = StateField.define({
6305
+ create: () => Decoration.none,
6306
+ update(decorations, transaction) {
6307
+ const mapped = decorations.map(transaction.changes);
6308
+ for (const effect of transaction.effects) {
6309
+ if (!effect.is(activeSegmentEffect)) continue;
6310
+ const range = effect.value;
6311
+ if (!range || range.from >= range.to) return Decoration.none;
6312
+ return Decoration.set([Decoration.mark({ class: "wql-active-segment" }).range(range.from, range.to)]);
6313
+ }
6314
+ return mapped;
6315
+ },
6316
+ provide: (field) => EditorView.decorations.from(field)
6317
+ });
6318
+ function findClauseRange(state, clause2) {
6319
+ if (!clause2) return void 0;
6320
+ let range;
6321
+ const tree = syntaxTree(state);
6322
+ if (clause2.filterIndex !== void 0) {
6323
+ let index = 0;
6324
+ tree.iterate({
6325
+ enter: (node) => {
6326
+ if (node.name === "Filter") {
6327
+ if (index === clause2.filterIndex) {
6328
+ range = { from: node.from, to: node.to };
6329
+ return false;
6330
+ }
6331
+ index++;
6332
+ }
6333
+ return true;
6334
+ }
6335
+ });
6336
+ return range;
6337
+ }
6338
+ if (["kind", "target", "agg", "metric"].includes(clause2.type)) {
6339
+ tree.iterate({
6340
+ enter: (node) => {
6341
+ if (node.name === "Head") {
6342
+ range = { from: node.from, to: node.to };
6343
+ return false;
6344
+ }
6345
+ return true;
6346
+ }
6347
+ });
6348
+ return range;
6349
+ }
6350
+ if (clause2.type === "groupby") {
6351
+ tree.iterate({
6352
+ enter: (node) => {
6353
+ if (node.name === "GroupBy") {
6354
+ range = { from: node.from, to: node.to };
6355
+ return false;
6356
+ }
6357
+ return true;
6358
+ }
6359
+ });
6360
+ return range;
6361
+ }
6362
+ if (clause2.type === "rollup") {
6363
+ tree.iterate({
6364
+ enter: (node) => {
6365
+ if (node.name === "Rollup") {
6366
+ range = { from: node.from, to: node.to };
6367
+ return false;
6368
+ }
6369
+ return true;
6370
+ }
6371
+ });
6372
+ return range;
6373
+ }
6374
+ if (clause2.type === "time") {
6375
+ const doc = state.doc.toString();
6376
+ const match = /\b(last\s+\d+[dw]|from\s+\S+(?:\s+to\s+\S+)?)/i.exec(doc);
6377
+ if (match) return { from: match.index, to: match.index + match[0].length };
6378
+ }
6379
+ return void 0;
6380
+ }
6298
6381
  function slotPositions(state) {
6299
6382
  const slots = [];
6300
6383
  syntaxTree(state).iterate({
6301
6384
  enter: (node) => {
6302
6385
  if (SLOT_NODES[node.name]) slots.push(node.from);
6303
- else if (node.name === "Word" && node.node.parent?.name === "GroupBy") slots.push(node.from);
6386
+ else if (node.name === "Word" && ["GroupBy", "Dimension"].includes(node.node.parent?.name ?? "")) slots.push(node.from);
6304
6387
  return true;
6305
6388
  }
6306
6389
  });
6307
6390
  return slots.sort((a, b) => a - b);
6308
6391
  }
6309
- function advanceSlot(view, dir) {
6392
+ function activateSlot(view, position, onActivate) {
6393
+ if (!onActivate) return;
6394
+ let node = syntaxTree(view.state).resolveInner(position, 1);
6395
+ while (node.parent && !["Head", "Filter", "GroupBy", "Rollup"].includes(node.name)) node = node.parent;
6396
+ if (!["Head", "Filter", "GroupBy", "Rollup"].includes(node.name)) return;
6397
+ let filterIndex;
6398
+ if (node.name === "Filter") {
6399
+ filterIndex = 0;
6400
+ syntaxTree(view.state).iterate({
6401
+ enter: (candidate) => {
6402
+ if (candidate.name === "Filter") {
6403
+ if (candidate.from === node.from) return false;
6404
+ if (candidate.from < node.from) filterIndex += 1;
6405
+ }
6406
+ return true;
6407
+ }
6408
+ });
6409
+ }
6410
+ let text = view.state.sliceDoc(node.from, node.to);
6411
+ if (node.name === "Head") {
6412
+ const line = view.state.doc.lineAt(position);
6413
+ const word = Array.from(line.text.matchAll(/[\w.*-]+/g)).find((match) => line.from + match.index <= position && position <= line.from + match.index + match[0].length);
6414
+ if (word) text = word[0];
6415
+ }
6416
+ onActivate({ node: node.name, filterIndex, from: node.from, to: node.to, text });
6417
+ }
6418
+ function advanceSlot(view, dir, onActivate) {
6310
6419
  const head = view.state.selection.main.head;
6311
6420
  const slots = slotPositions(view.state);
6312
6421
  const next = dir > 0 ? slots.find((slot) => slot > head) : [...slots].reverse().find((slot) => slot < head);
6313
6422
  if (next === void 0) return false;
6314
6423
  view.dispatch({ selection: { anchor: next }, scrollIntoView: true });
6424
+ activateSlot(view, next, onActivate);
6315
6425
  return true;
6316
6426
  }
6317
6427
  function wqlLint(view) {
@@ -6354,7 +6464,7 @@ function wqlLint(view) {
6354
6464
  });
6355
6465
  return out;
6356
6466
  }
6357
- function wqlEditorKeymap(onSubmit, onEscape) {
6467
+ function wqlEditorKeymap(onSubmit, onEscape, onSlotActivate) {
6358
6468
  return [
6359
6469
  { key: "Mod-Enter", run: () => {
6360
6470
  onSubmit();
@@ -6378,7 +6488,7 @@ function wqlEditorKeymap(onSubmit, onEscape) {
6378
6488
  run: (view) => {
6379
6489
  if (view.compositionStarted) return false;
6380
6490
  const accepted = acceptCompletion(view);
6381
- return advanceSlot(view, 1) || accepted;
6491
+ return advanceSlot(view, 1, onSlotActivate) || accepted;
6382
6492
  }
6383
6493
  },
6384
6494
  {
@@ -6386,7 +6496,7 @@ function wqlEditorKeymap(onSubmit, onEscape) {
6386
6496
  run: (view) => {
6387
6497
  if (view.compositionStarted) return false;
6388
6498
  const accepted = acceptCompletion(view);
6389
- return advanceSlot(view, -1) || accepted;
6499
+ return advanceSlot(view, -1, onSlotActivate) || accepted;
6390
6500
  }
6391
6501
  },
6392
6502
  {
@@ -6405,11 +6515,11 @@ function wqlEditorKeymap(onSubmit, onEscape) {
6405
6515
  ...historyKeymap
6406
6516
  ];
6407
6517
  }
6408
- function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: placeholder$1, autoFocus = false, dense = false }) {
6518
+ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: placeholder$1, autoFocus = false, dense = false, onSlotActivate, activeRange, activeClause, className }) {
6409
6519
  const host = useRef(null);
6410
6520
  const view = useRef(void 0);
6411
- const callbacks = useRef({ onChange, onSubmit, onEscape });
6412
- callbacks.current = { onChange, onSubmit, onEscape };
6521
+ const callbacks = useRef({ onChange, onSubmit, onEscape, onSlotActivate });
6522
+ callbacks.current = { onChange, onSubmit, onEscape, onSlotActivate };
6413
6523
  const replacing = useRef(false);
6414
6524
  const initialValue = useRef(value);
6415
6525
  useEffect(() => {
@@ -6426,6 +6536,7 @@ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: place
6426
6536
  syntaxHighlighting(wqlHighlightStyle),
6427
6537
  history(),
6428
6538
  EditorView.lineWrapping,
6539
+ activeSegmentField,
6429
6540
  ...placeholder$1 ? [placeholder(placeholder$1)] : [],
6430
6541
  EditorView.contentAttributes.of({ "aria-label": "WQL", "data-testid": "wql-text-input" }),
6431
6542
  autocompletion({
@@ -6446,11 +6557,12 @@ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: place
6446
6557
  linter(wqlLint),
6447
6558
  keymap.of(wqlEditorKeymap(
6448
6559
  () => callbacks.current.onSubmit(),
6449
- () => callbacks.current.onEscape()
6560
+ () => callbacks.current.onEscape(),
6561
+ (slot) => callbacks.current.onSlotActivate?.(slot)
6450
6562
  )),
6451
6563
  EditorView.domEventHandlers({
6452
- // Clicking a head/target/filter token selects it and lists its alternatives;
6453
- // typing then replaces it, picking swaps it.
6564
+ // Host composers open the contextual writer; standalone editors
6565
+ // retain token selection and in-row completion.
6454
6566
  mouseup: (event, editor2) => {
6455
6567
  if (event.button !== 0) return false;
6456
6568
  let { from, to } = editor2.state.selection.main;
@@ -6461,11 +6573,18 @@ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: place
6461
6573
  from = line.from + word.index;
6462
6574
  to = from + word[0].length;
6463
6575
  let node = syntaxTree(editor2.state).resolveInner(to, -1);
6464
- while (node.parent && !["Head", "Filter"].includes(node.name)) node = node.parent;
6465
- if (!["Head", "Filter"].includes(node.name)) return false;
6466
- editor2.dispatch({ selection: { anchor: from, head: to } });
6576
+ while (node.parent && !["Head", "Filter", "GroupBy", "Rollup"].includes(node.name)) node = node.parent;
6577
+ if (!["Head", "Filter", "GroupBy", "Rollup"].includes(node.name)) return false;
6578
+ if (!callbacks.current.onSlotActivate) {
6579
+ editor2.dispatch({ selection: { anchor: from, head: to } });
6580
+ }
6581
+ }
6582
+ if (callbacks.current.onSlotActivate) {
6583
+ closeCompletion(editor2);
6584
+ activateSlot(editor2, from, (slot) => callbacks.current.onSlotActivate?.(slot));
6585
+ } else {
6586
+ startCompletion(editor2);
6467
6587
  }
6468
- startCompletion(editor2);
6469
6588
  return false;
6470
6589
  },
6471
6590
  keydown: (event, editor2) => {
@@ -6485,7 +6604,8 @@ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: place
6485
6604
  '.cm-line span[class*="tok-"]:hover, .cm-line span[class^="tok-"]:hover': { fontWeight: "700", textShadow: "0 0 0.5px currentColor", cursor: "pointer" },
6486
6605
  ".cm-scroller": { overflow: "auto" },
6487
6606
  ".cm-placeholder": { color: "hsl(var(--muted-foreground))" },
6488
- ".wql-completion-icon": { display: "inline-flex", flexShrink: "0", color: "hsl(var(--primary))" }
6607
+ ".wql-completion-icon": { display: "inline-flex", flexShrink: "0", color: "hsl(var(--primary))" },
6608
+ ".wql-active-segment": { backgroundColor: "hsl(var(--primary) / 0.16)", boxShadow: "inset 0 -2px hsl(var(--primary))", borderRadius: "4px", padding: "1px 2px", margin: "0 -2px", fontWeight: "600" }
6489
6609
  }),
6490
6610
  autocompleteTooltipTheme
6491
6611
  ]
@@ -6505,7 +6625,13 @@ function WqlTextEditor({ value, onChange, onSubmit, onEscape, placeholder: place
6505
6625
  editor.dispatch({ changes: { from: 0, to: editor.state.doc.length, insert: value } });
6506
6626
  replacing.current = false;
6507
6627
  }, [value]);
6508
- return /* @__PURE__ */ jsx("div", { ref: host, className: "min-w-0 w-full rounded-lg border border-border bg-background focus-within:ring-2 focus-within:ring-ring", "data-testid": "wql-text-editor" });
6628
+ useEffect(() => {
6629
+ const editor = view.current;
6630
+ if (!editor) return;
6631
+ const resolvedRange = activeRange ?? findClauseRange(editor.state, activeClause);
6632
+ editor.dispatch({ effects: activeSegmentEffect.of(resolvedRange ?? null) });
6633
+ }, [activeRange, activeClause, value]);
6634
+ return /* @__PURE__ */ jsx("div", { ref: host, className: className ?? "min-w-0 w-full rounded-lg border border-border bg-background focus-within:ring-2 focus-within:ring-ring", "data-testid": "wql-text-editor" });
6509
6635
  }
6510
6636
  function WqlComposer({
6511
6637
  initialQuery,
@@ -6527,7 +6653,8 @@ function WqlComposer({
6527
6653
  preferredChoices,
6528
6654
  autoFocus = false,
6529
6655
  placeholder = "Search text or enter WQL",
6530
- className
6656
+ className,
6657
+ segmentEditRequest
6531
6658
  }) {
6532
6659
  const [desktop, setDesktop] = useState(false);
6533
6660
  const [base, setBase] = useState(query ?? initialQuery ?? ":note");
@@ -6609,7 +6736,7 @@ function WqlComposer({
6609
6736
  }, [autoFocus]);
6610
6737
  useEffect(() => {
6611
6738
  if (active.kind === "value") pickerRef.current?.focus();
6612
- }, [active.kind]);
6739
+ }, [active]);
6613
6740
  useEffect(() => {
6614
6741
  if (highlight >= 0) document.getElementById(`${listId}-option-${highlight}`)?.scrollIntoView?.({ block: "nearest" });
6615
6742
  }, [highlight, listId]);
@@ -6635,14 +6762,14 @@ function WqlComposer({
6635
6762
  if (openerRef.current?.isConnected) openerRef.current.focus();
6636
6763
  else inputRef.current?.focus();
6637
6764
  };
6638
- const openEditor = (clause2) => {
6765
+ const openEditor = (clause2, range) => {
6639
6766
  if (pending && currentRef.current.valid) commit(currentRef.current);
6640
6767
  openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
6641
6768
  if (clause2.type === "where" || clause2.type === "pipes") {
6642
6769
  setActive({ kind: "wql" });
6643
6770
  commit(currentRef.current);
6644
6771
  } else {
6645
- setActive({ kind: "value", clause: clause2 });
6772
+ setActive({ kind: "value", clause: clause2, range });
6646
6773
  setSearch("");
6647
6774
  }
6648
6775
  setHighlight(-1);
@@ -6653,6 +6780,24 @@ function WqlComposer({
6653
6780
  if (pending) commit(resolveQueryDraft(base));
6654
6781
  openEditor(existing ?? { id: `new-${type}`, type, ...getClauseMeta(type), value: "" });
6655
6782
  };
6783
+ const openFieldRef = useRef(openField);
6784
+ openFieldRef.current = openField;
6785
+ useEffect(() => {
6786
+ if (segmentEditRequest) openFieldRef.current(segmentEditRequest.type);
6787
+ }, [segmentEditRequest]);
6788
+ const activateWqlSlot = (slot) => {
6789
+ const clause2 = slot.filterIndex !== void 0 ? pills.find((pill) => pill.filterIndex === slot.filterIndex) : slot.node === "GroupBy" ? pills.find((pill) => pill.type === "groupby") : slot.node === "Rollup" ? pills.find((pill) => pill.type === "rollup") : slot.node === "Head" ? pills.find((pill) => ["kind", "target", "agg", "metric"].includes(pill.type) && pill.value === slot.text) : void 0;
6790
+ if (clause2) openEditor(clause2, { from: slot.from, to: slot.to });
6791
+ };
6792
+ const moveEditor = (direction) => {
6793
+ if (active.kind !== "value") return false;
6794
+ const visible = pills.filter((pill) => !hidden.has(pill.type));
6795
+ const index = visible.findIndex((pill) => pill.id === active.clause.id);
6796
+ const next = visible[index + direction];
6797
+ if (!next) return false;
6798
+ openEditor(next);
6799
+ return true;
6800
+ };
6656
6801
  const updateClause = (clause2, value) => {
6657
6802
  if (clause2.type === "kind" || clause2.type === "target") {
6658
6803
  const next2 = pivotQuery(currentRef.current.wql, clause2.type, value ?? "");
@@ -6704,6 +6849,13 @@ function WqlComposer({
6704
6849
  onSubmit?.(draft.wql);
6705
6850
  };
6706
6851
  const handleKeys = (event) => {
6852
+ if (active.kind === "value" && event.key === "Tab" && !event.nativeEvent.isComposing) {
6853
+ if (moveEditor(event.shiftKey ? -1 : 1)) {
6854
+ event.preventDefault();
6855
+ event.stopPropagation();
6856
+ }
6857
+ return;
6858
+ }
6707
6859
  if (event.nativeEvent.isComposing) return;
6708
6860
  if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
6709
6861
  event.preventDefault();
@@ -6768,119 +6920,285 @@ function WqlComposer({
6768
6920
  diagnosticsActions
6769
6921
  ] });
6770
6922
  const diagnostics = { ...resolved, valid: resolved.valid && !error, error: error ?? resolved.error };
6771
- return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0 space-y-2", desktop && compact && "flex flex-wrap items-center gap-2 space-y-0 [&>:not([data-wql-inline])]:w-full", className), "data-testid": "wql-composer-root", children: [
6772
- diagnosticsPosition === "top" && showDiagnostics && /* @__PURE__ */ jsx(WqlDiagnosticsStrip, { diagnostics, stages, actions: action, variant: "header" }),
6773
- (desktop || active.kind === "wql" || !guided) && /* @__PURE__ */ jsx("div", { "data-wql-inline": true, className: cn("min-w-0", desktop && compact ? "flex-1" : "w-full"), children: /* @__PURE__ */ jsx(WqlTextEditor, { value: resolved.wql, placeholder, dense: desktop && compact, onChange: (text) => commit(resolveQueryDraft(text)), onSubmit: submit, onEscape: () => {
6774
- if (active.kind === "closed") return false;
6775
- closeEditor();
6776
- return true;
6777
- }, autoFocus }) }),
6778
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 flex-wrap items-center gap-1", !desktop && "rounded-xl border border-border p-2", desktop && compact && "hidden"), "data-testid": "wql-composer", onKeyDown: (event) => {
6779
- if (!["Delete", "Backspace"].includes(event.key) || !(event.target instanceof HTMLButtonElement)) return;
6780
- const buttons = Array.from(event.currentTarget.querySelectorAll('[data-testid^="token-slot-"]:not([data-testid^="token-slot-remove-"]):not([data-testid^="token-slot-value-"])'));
6781
- const pill = pills.filter((item) => !hidden.has(item.type))[buttons.indexOf(event.target)];
6782
- if (!pill || ["kind", "target", "agg", "metric"].includes(pill.type)) return;
6783
- event.preventDefault();
6784
- event.stopPropagation();
6785
- setUndo(currentRef.current.wql);
6786
- updateClause(pill, null);
6787
- inputRef.current?.focus();
6788
- }, children: [
6789
- guided && active.kind !== "wql" && pills.filter((pill) => !hidden.has(pill.type)).map((pill) => /* @__PURE__ */ jsx(TokenSlotPill, { clause: pill, compact, isActive: active.kind === "value" && active.clause.id === pill.id, onClick: () => openEditor(pill), onRemove: ["kind", "target", "agg", "metric"].includes(pill.type) ? void 0 : () => {
6790
- setUndo(currentRef.current.wql);
6791
- updateClause(pill, null);
6792
- } }, pill.id)),
6793
- !desktop && active.kind !== "wql" && guided && /* @__PURE__ */ jsx("input", { ref: inputRef, type: "text", role: "combobox", "aria-label": "Search text or WQL", "aria-controls": suggesting ? listId : void 0, "aria-expanded": suggesting, "aria-activedescendant": suggesting && highlight >= 0 ? `${listId}-option-${highlight}` : void 0, value: pending, placeholder, onChange: (event) => {
6794
- const text = event.target.value;
6795
- setPending(text);
6796
- setHighlight(-1);
6797
- setError(void 0);
6798
- notify(resolveQueryDraft(base, text));
6799
- }, onKeyDown: handleKeys, className: "min-h-12 min-w-0 flex-[1_1_140px] bg-transparent font-mono text-base outline-none", "data-testid": "wql-composer-input" }),
6800
- customSlots
6801
- ] }),
6802
- (!desktop || undo) && /* @__PURE__ */ jsxs("div", { "data-wql-inline": desktop && compact ? "" : void 0, className: "flex flex-wrap items-center gap-2", children: [
6803
- !desktop && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
6804
- commit(currentRef.current);
6805
- if (active.kind === "wql") closeEditor();
6806
- else setActive({ kind: "wql" });
6807
- }, disabled: active.kind === "wql" && !guided, className: "min-h-12 rounded-lg px-3", children: active.kind === "wql" ? "Guided controls" : "Edit WQL" }),
6808
- undo && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
6809
- commit(resolveQueryDraft(undo));
6810
- setUndo(void 0);
6811
- }, className: cn("rounded-lg", desktop && compact ? "min-h-9 px-2.5 text-xs text-muted-foreground hover:text-foreground" : "min-h-12 px-3"), children: "Undo removal" })
6812
- ] }),
6813
- active.kind === "value" && /* @__PURE__ */ jsxs("div", { "data-testid": "wql-field-picker", className: "min-w-0 rounded-xl border border-border p-2 focus-within:ring-2 focus-within:ring-ring", onKeyDown: (event) => {
6814
- if (event.key === "Escape" || event.key === "Enter" && (event.ctrlKey || event.metaKey)) handleKeys(event);
6815
- }, children: [
6816
- /* @__PURE__ */ jsx("button", { type: "button", onClick: closeEditor, className: "min-h-12 px-3", children: "Back" }),
6817
- /* @__PURE__ */ jsxs("label", { className: "block text-sm", children: [
6818
- "Search ",
6819
- getClauseMeta(active.clause.type).label,
6820
- /* @__PURE__ */ jsx("input", { ref: pickerRef, type: "search", role: "combobox", "aria-label": `Search ${getClauseMeta(active.clause.type).label}`, "aria-controls": listId, "aria-expanded": "true", "aria-activedescendant": highlight >= 0 ? `${listId}-option-${highlight}` : void 0, value: search, onChange: (event) => {
6821
- setSearch(event.target.value);
6822
- setHighlight(-1);
6823
- setError(void 0);
6824
- }, onKeyDown: handleKeys, className: "min-h-12 w-full rounded border border-border bg-background px-3 text-base", "data-testid": "wql-picker-search" })
6825
- ] }),
6826
- active.kind === "value" && active.clause.filterIndex !== void 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
6827
- /* @__PURE__ */ jsxs("label", { className: "flex min-h-12 items-center gap-2", children: [
6828
- /* @__PURE__ */ jsx("input", { type: "checkbox", checked: active.clause.negate ?? false, onChange: (event) => updateClause({ ...active.clause, negate: event.target.checked }, active.clause.value) }),
6829
- "Exclude"
6923
+ const visiblePills = pills.filter((pill) => !hidden.has(pill.type));
6924
+ const activePillIndex = active.kind === "value" ? visiblePills.findIndex((pill) => pill.id === active.clause.id) : -1;
6925
+ return /* @__PURE__ */ jsxs(
6926
+ "div",
6927
+ {
6928
+ className: cn(
6929
+ "min-w-0",
6930
+ compact ? "flex flex-col overflow-hidden rounded-xl border border-border bg-card shadow-xs transition-shadow focus-within:ring-2 focus-within:ring-ring" : "space-y-2",
6931
+ className
6932
+ ),
6933
+ "data-testid": "wql-composer-root",
6934
+ children: [
6935
+ diagnosticsPosition === "top" && showDiagnostics && /* @__PURE__ */ jsx(WqlDiagnosticsStrip, { diagnostics, stages, actions: action, variant: "header" }),
6936
+ (desktop || compact || active.kind === "wql" || !guided) && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 w-full items-center gap-2", children: [
6937
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
6938
+ WqlTextEditor,
6939
+ {
6940
+ value: resolved.wql,
6941
+ placeholder,
6942
+ dense: compact,
6943
+ className: compact ? "min-w-0 w-full bg-transparent" : void 0,
6944
+ activeRange: active.kind === "value" ? active.range : void 0,
6945
+ activeClause: active.kind === "value" ? active.clause : void 0,
6946
+ onSlotActivate: activateWqlSlot,
6947
+ onChange: (text) => commit(resolveQueryDraft(text)),
6948
+ onSubmit: submit,
6949
+ onEscape: () => {
6950
+ if (active.kind === "closed") return false;
6951
+ closeEditor();
6952
+ return true;
6953
+ },
6954
+ autoFocus
6955
+ }
6956
+ ) }),
6957
+ desktop && compact && undo && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
6958
+ commit(resolveQueryDraft(undo));
6959
+ setUndo(void 0);
6960
+ }, className: "min-h-9 shrink-0 rounded-lg px-2.5 text-xs text-muted-foreground hover:text-foreground", children: "Undo removal" })
6830
6961
  ] }),
6831
- /* @__PURE__ */ jsxs("label", { className: "flex min-h-12 items-center gap-2", children: [
6832
- /* @__PURE__ */ jsx("input", { type: "checkbox", checked: active.clause.value.split("|").every((value) => value.endsWith("*")), onChange: (event) => updateClause(active.clause, active.clause.value.split("|").map((value) => `${value.replace(/\*$/, "")}${event.target.checked ? "*" : ""}`).join("|")) }),
6833
- "Starts with"
6834
- ] })
6835
- ] }),
6836
- active.kind === "value" && active.clause.type === "time" && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: [
6837
- /* @__PURE__ */ jsxs("label", { children: [
6838
- "Start date",
6839
- /* @__PURE__ */ jsx("input", { type: "date", "aria-label": "Start date", className: "min-h-12 w-full bg-background text-base", onChange: (event) => {
6840
- const end = draftWindow();
6841
- updateClause(active.clause, `from ${event.target.value}${end?.kind === "range" && end.end ? ` to ${end.end}` : ""}`);
6842
- }, value: astWindow?.kind === "range" ? astWindow.start : "" })
6962
+ /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 flex-wrap items-center gap-1", !desktop && !compact && "rounded-xl border border-border p-2", compact && "hidden"), "data-testid": "wql-composer", onKeyDown: (event) => {
6963
+ if (!["Delete", "Backspace"].includes(event.key) || !(event.target instanceof HTMLButtonElement)) return;
6964
+ const buttons = Array.from(event.currentTarget.querySelectorAll('[data-testid^="token-slot-"]:not([data-testid^="token-slot-remove-"]):not([data-testid^="token-slot-value-"])'));
6965
+ const pill = visiblePills[buttons.indexOf(event.target)];
6966
+ if (!pill || ["kind", "target", "agg", "metric"].includes(pill.type)) return;
6967
+ event.preventDefault();
6968
+ event.stopPropagation();
6969
+ setUndo(currentRef.current.wql);
6970
+ updateClause(pill, null);
6971
+ inputRef.current?.focus();
6972
+ }, children: [
6973
+ guided && active.kind !== "wql" && visiblePills.map((pill) => /* @__PURE__ */ jsx(TokenSlotPill, { clause: pill, compact, isActive: active.kind === "value" && active.clause.id === pill.id, onClick: () => openEditor(pill), onRemove: ["kind", "target", "agg", "metric"].includes(pill.type) ? void 0 : () => {
6974
+ setUndo(currentRef.current.wql);
6975
+ updateClause(pill, null);
6976
+ } }, pill.id)),
6977
+ !desktop && !compact && active.kind !== "wql" && guided && /* @__PURE__ */ jsx("input", { ref: inputRef, type: "text", role: "combobox", "aria-label": "Search text or WQL", "aria-controls": suggesting ? listId : void 0, "aria-expanded": suggesting, "aria-activedescendant": suggesting && highlight >= 0 ? `${listId}-option-${highlight}` : void 0, value: pending, placeholder, onChange: (event) => {
6978
+ const text = event.target.value;
6979
+ setPending(text);
6980
+ setHighlight(-1);
6981
+ setError(void 0);
6982
+ notify(resolveQueryDraft(base, text));
6983
+ }, onKeyDown: handleKeys, className: "min-h-12 min-w-0 flex-[1_1_140px] bg-transparent font-mono text-base outline-none", "data-testid": "wql-composer-input" }),
6984
+ customSlots
6843
6985
  ] }),
6844
- /* @__PURE__ */ jsxs("label", { children: [
6845
- "End date",
6846
- /* @__PURE__ */ jsx("input", { type: "date", "aria-label": "End date", className: "min-h-12 w-full bg-background text-base", onChange: (event) => {
6847
- const window2 = draftWindow();
6848
- if (window2?.kind === "range") updateClause(active.clause, `from ${window2.start}${event.target.value ? ` to ${event.target.value}` : ""}`);
6849
- else setError("Choose a start date first");
6850
- }, value: astWindow?.kind === "range" ? astWindow.end ?? "" : "" })
6851
- ] })
6852
- ] }),
6853
- active.kind === "value" && (customEditor ? /* @__PURE__ */ jsx(customEditor.Editor, { value: customEditor.parseValue ? customEditor.parseValue(active.clause.value) : active.clause.value, onChange: (value) => updateClause(active.clause, customEditor.formatValue ? customEditor.formatValue(value) : String(value)), onClose: closeEditor }) : /* @__PURE__ */ jsx(InlineClauseEditor, { clause: active.clause, filteredItems: preferredItems, selectedValues: values2.selectedValues, isMulti: values2.isMulti, typedValue: values2.typedValue, canCommitTyped: values2.canCommitTyped, emptyText: values2.emptyText, highlightIdx: highlight, onHighlight: setHighlight, onCommitValue: chooseValue, onCommitTyped: chooseValue, listId, onDone: closeEditor, onReorder: (dimensions) => updateClause(active.clause, dimensions.join("|")) }))
6854
- ] }),
6855
- suggesting && /* @__PURE__ */ jsxs("div", { id: listId, role: "listbox", "aria-label": "Query conditions", className: "max-h-64 overflow-y-auto rounded-xl border border-border p-1", "data-testid": "wql-filter-typeahead", children: [
6856
- catalog.map((type, index) => /* @__PURE__ */ jsxs("button", { id: `${listId}-option-${index}`, type: "button", role: "option", "aria-selected": false, onMouseEnter: () => setHighlight(index), onClick: () => openField(type), className: cn("flex min-h-12 w-full items-center gap-2 rounded px-3 text-left", index === highlight && "bg-muted"), "data-testid": `wql-filter-typeahead-${type}`, children: [
6857
- /* @__PURE__ */ jsxs("span", { children: [
6858
- pills.some((pill) => pill.type === type) ? "Edit" : "Add",
6859
- " ",
6860
- getClauseMeta(type).label
6986
+ (!desktop && !compact || !compact && undo) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
6987
+ !desktop && !compact && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
6988
+ commit(currentRef.current);
6989
+ if (active.kind === "wql") closeEditor();
6990
+ else setActive({ kind: "wql" });
6991
+ }, disabled: active.kind === "wql" && !guided, className: "min-h-12 rounded-lg px-3", children: active.kind === "wql" ? "Guided controls" : "Edit WQL" }),
6992
+ undo && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
6993
+ commit(resolveQueryDraft(undo));
6994
+ setUndo(void 0);
6995
+ }, className: "min-h-12 rounded-lg px-3", children: "Undo removal" })
6861
6996
  ] }),
6862
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: type })
6863
- ] }, type)),
6864
- textAction && /* @__PURE__ */ jsxs("button", { id: `${listId}-option-${catalog.length}`, type: "button", role: "option", "aria-selected": false, onMouseEnter: () => setHighlight(catalog.length), className: cn("min-h-12 w-full rounded px-3 text-left", highlight === catalog.length && "bg-muted"), onClick: submit, children: [
6865
- "Search text ",
6866
- pending
6867
- ] })
6868
- ] }),
6869
- pivot && /* @__PURE__ */ jsxs("div", { role: "alertdialog", "aria-label": "Confirm query pivot", className: "rounded-xl border border-border p-3", children: [
6870
- /* @__PURE__ */ jsx("p", { children: "Changing the query removes incompatible clauses:" }),
6871
- /* @__PURE__ */ jsx("ul", { children: pivot.removed.map((item) => /* @__PURE__ */ jsx("li", { children: item }, item)) }),
6872
- /* @__PURE__ */ jsx("button", { type: "button", className: "min-h-12 px-3", onClick: () => setPivot(void 0), children: "Cancel" }),
6873
- /* @__PURE__ */ jsx("button", { type: "button", className: "min-h-12 px-3", onClick: () => {
6874
- commit(pivot.draft);
6875
- setPivot(void 0);
6876
- closeEditor();
6877
- }, children: "Change query" })
6878
- ] }),
6879
- !showDiagnostics && (error ?? resolved.error) && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: error ?? resolved.error }),
6880
- !guided && !resolved.error && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Use Edit WQL to preserve every clause." }),
6881
- pending && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": "wql-composer-pending", children: resolved.valid ? "Current draft includes this text" : resolved.error }),
6882
- showDiagnostics && diagnosticsPosition === "bottom" ? /* @__PURE__ */ jsx(WqlDiagnosticsStrip, { diagnostics, stages, actions: action }) : diagnosticsPosition !== "top" || !showDiagnostics ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-2", children: action }) : null
6883
- ] });
6997
+ active.kind === "value" && /* @__PURE__ */ jsxs(
6998
+ "div",
6999
+ {
7000
+ "data-testid": "wql-field-picker",
7001
+ className: cn(
7002
+ "min-w-0",
7003
+ compact ? "border-t border-border/70 bg-muted/20 px-2.5 py-2 space-y-1.5" : "space-y-2 rounded-xl border border-border/80 bg-muted/30 p-2 sm:p-2.5 shadow-xs backdrop-blur-sm"
7004
+ ),
7005
+ onKeyDown: (event) => {
7006
+ if (event.key === "Escape" || event.key === "Enter" && (event.ctrlKey || event.metaKey)) handleKeys(event);
7007
+ },
7008
+ children: [
7009
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
7010
+ /* @__PURE__ */ jsxs("div", { className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border/70 bg-background/80 px-2.5 py-1 text-xs font-semibold text-foreground font-mono", children: [
7011
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-xs", children: getClauseMeta(active.clause.type).icon }),
7012
+ /* @__PURE__ */ jsx("span", { children: getClauseMeta(active.clause.type).label })
7013
+ ] }),
7014
+ /* @__PURE__ */ jsxs("label", { className: "sr-only", children: [
7015
+ "Search ",
7016
+ getClauseMeta(active.clause.type).label
7017
+ ] }),
7018
+ /* @__PURE__ */ jsx(
7019
+ "input",
7020
+ {
7021
+ ref: pickerRef,
7022
+ type: "search",
7023
+ role: "combobox",
7024
+ "aria-label": `Search ${getClauseMeta(active.clause.type).label}`,
7025
+ "aria-controls": listId,
7026
+ "aria-expanded": "true",
7027
+ "aria-activedescendant": highlight >= 0 ? `${listId}-option-${highlight}` : void 0,
7028
+ value: search,
7029
+ placeholder: active.clause.value ? `Current: ${active.clause.value}` : `Type value for ${getClauseMeta(active.clause.type).label}\u2026`,
7030
+ onChange: (event) => {
7031
+ setSearch(event.target.value);
7032
+ setHighlight(-1);
7033
+ setError(void 0);
7034
+ },
7035
+ onKeyDown: handleKeys,
7036
+ className: "min-h-10 sm:min-h-8 min-w-0 flex-1 rounded-lg border border-border/80 bg-background px-2.5 font-mono text-sm sm:text-xs text-foreground placeholder:text-muted-foreground/60 focus:outline-none focus:ring-1 focus:ring-primary shadow-xs",
7037
+ "data-testid": "wql-picker-search"
7038
+ }
7039
+ ),
7040
+ active.clause.filterIndex !== void 0 && /* @__PURE__ */ jsxs("div", { className: "order-last flex w-full items-center gap-1.5 sm:order-none sm:w-auto", children: [
7041
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer select-none items-center gap-1.5 px-2 py-0.5 rounded-md border border-border/60 bg-background/70 text-[11px] text-muted-foreground hover:text-foreground transition-colors", children: [
7042
+ /* @__PURE__ */ jsx(
7043
+ "input",
7044
+ {
7045
+ type: "checkbox",
7046
+ checked: active.clause.negate ?? false,
7047
+ onChange: (event) => updateClause({ ...active.clause, negate: event.target.checked }, active.clause.value),
7048
+ className: "size-3 rounded border-border text-primary focus:ring-primary"
7049
+ }
7050
+ ),
7051
+ /* @__PURE__ */ jsx("span", { children: "Exclude" })
7052
+ ] }),
7053
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer select-none items-center gap-1.5 px-2 py-0.5 rounded-md border border-border/60 bg-background/70 text-[11px] text-muted-foreground hover:text-foreground transition-colors", children: [
7054
+ /* @__PURE__ */ jsx(
7055
+ "input",
7056
+ {
7057
+ type: "checkbox",
7058
+ checked: active.clause.value.split("|").every((value) => value.endsWith("*")),
7059
+ onChange: (event) => updateClause(active.clause, active.clause.value.split("|").map((value) => `${value.replace(/\*$/, "")}${event.target.checked ? "*" : ""}`).join("|")),
7060
+ className: "size-3 rounded border-border text-primary focus:ring-primary"
7061
+ }
7062
+ ),
7063
+ /* @__PURE__ */ jsx("span", { children: "Starts with" })
7064
+ ] })
7065
+ ] }),
7066
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
7067
+ /* @__PURE__ */ jsx(
7068
+ "button",
7069
+ {
7070
+ type: "button",
7071
+ "aria-label": "Previous WQL segment",
7072
+ "data-testid": "wql-segment-previous",
7073
+ disabled: activePillIndex <= 0,
7074
+ onClick: () => {
7075
+ if (moveEditor(-1)) pickerRef.current?.focus();
7076
+ },
7077
+ className: "flex items-center justify-center min-h-9 min-w-9 sm:min-h-7 sm:min-w-7 rounded-md border border-border/70 bg-background/80 text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:pointer-events-none text-xs transition-colors",
7078
+ children: "\u2190"
7079
+ }
7080
+ ),
7081
+ /* @__PURE__ */ jsx(
7082
+ "button",
7083
+ {
7084
+ type: "button",
7085
+ "aria-label": "Next WQL segment",
7086
+ "data-testid": "wql-segment-next",
7087
+ disabled: activePillIndex < 0 || activePillIndex >= visiblePills.length - 1,
7088
+ onClick: () => {
7089
+ if (moveEditor(1)) pickerRef.current?.focus();
7090
+ },
7091
+ className: "flex items-center justify-center min-h-9 min-w-9 sm:min-h-7 sm:min-w-7 rounded-md border border-border/70 bg-background/80 text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:pointer-events-none text-xs transition-colors",
7092
+ children: "\u2192"
7093
+ }
7094
+ ),
7095
+ /* @__PURE__ */ jsx(
7096
+ "button",
7097
+ {
7098
+ type: "button",
7099
+ "aria-label": "Close segment editor",
7100
+ onClick: closeEditor,
7101
+ className: "flex items-center justify-center min-h-9 min-w-9 sm:min-h-7 sm:min-w-7 rounded-md text-muted-foreground hover:bg-muted hover:text-foreground text-xs transition-colors",
7102
+ children: "\u2715"
7103
+ }
7104
+ )
7105
+ ] })
7106
+ ] }),
7107
+ active.kind === "value" && active.clause.type === "time" && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 pt-0.5 text-xs", children: [
7108
+ /* @__PURE__ */ jsxs("label", { className: "block text-muted-foreground", children: [
7109
+ "Start date",
7110
+ /* @__PURE__ */ jsx(
7111
+ "input",
7112
+ {
7113
+ type: "date",
7114
+ "aria-label": "Start date",
7115
+ className: "mt-1 min-h-8 w-full rounded-md border border-border/80 bg-background px-2.5 text-xs text-foreground",
7116
+ onChange: (event) => {
7117
+ const end = draftWindow();
7118
+ updateClause(active.clause, `from ${event.target.value}${end?.kind === "range" && end.end ? ` to ${end.end}` : ""}`);
7119
+ },
7120
+ value: astWindow?.kind === "range" ? astWindow.start : ""
7121
+ }
7122
+ )
7123
+ ] }),
7124
+ /* @__PURE__ */ jsxs("label", { className: "block text-muted-foreground", children: [
7125
+ "End date",
7126
+ /* @__PURE__ */ jsx(
7127
+ "input",
7128
+ {
7129
+ type: "date",
7130
+ "aria-label": "End date",
7131
+ className: "mt-1 min-h-8 w-full rounded-md border border-border/80 bg-background px-2.5 text-xs text-foreground",
7132
+ onChange: (event) => {
7133
+ const window2 = draftWindow();
7134
+ if (window2?.kind === "range") updateClause(active.clause, `from ${window2.start}${event.target.value ? ` to ${event.target.value}` : ""}`);
7135
+ else setError("Choose a start date first");
7136
+ },
7137
+ value: astWindow?.kind === "range" ? astWindow.end ?? "" : ""
7138
+ }
7139
+ )
7140
+ ] })
7141
+ ] }),
7142
+ active.kind === "value" && (customEditor ? /* @__PURE__ */ jsx(
7143
+ customEditor.Editor,
7144
+ {
7145
+ value: customEditor.parseValue ? customEditor.parseValue(active.clause.value) : active.clause.value,
7146
+ onChange: (value) => updateClause(active.clause, customEditor.formatValue ? customEditor.formatValue(value) : String(value)),
7147
+ onClose: closeEditor
7148
+ }
7149
+ ) : /* @__PURE__ */ jsx(
7150
+ InlineClauseEditor,
7151
+ {
7152
+ clause: active.clause,
7153
+ filteredItems: preferredItems,
7154
+ selectedValues: values2.selectedValues,
7155
+ isMulti: values2.isMulti,
7156
+ typedValue: values2.typedValue,
7157
+ canCommitTyped: values2.canCommitTyped,
7158
+ emptyText: values2.emptyText,
7159
+ highlightIdx: highlight,
7160
+ onHighlight: setHighlight,
7161
+ onCommitValue: chooseValue,
7162
+ onCommitTyped: chooseValue,
7163
+ listId,
7164
+ onDone: closeEditor,
7165
+ onReorder: (dimensions) => updateClause(active.clause, dimensions.join("|"))
7166
+ }
7167
+ ))
7168
+ ]
7169
+ }
7170
+ ),
7171
+ suggesting && /* @__PURE__ */ jsxs("div", { id: listId, role: "listbox", "aria-label": "Query conditions", className: "max-h-64 overflow-y-auto rounded-xl border border-border p-1", "data-testid": "wql-filter-typeahead", children: [
7172
+ catalog.map((type, index) => /* @__PURE__ */ jsxs("button", { id: `${listId}-option-${index}`, type: "button", role: "option", "aria-selected": false, onMouseEnter: () => setHighlight(index), onClick: () => openField(type), className: cn("flex min-h-12 w-full items-center gap-2 rounded px-3 text-left", index === highlight && "bg-muted"), "data-testid": `wql-filter-typeahead-${type}`, children: [
7173
+ /* @__PURE__ */ jsxs("span", { children: [
7174
+ pills.some((pill) => pill.type === type) ? "Edit" : "Add",
7175
+ " ",
7176
+ getClauseMeta(type).label
7177
+ ] }),
7178
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: type })
7179
+ ] }, type)),
7180
+ textAction && /* @__PURE__ */ jsxs("button", { id: `${listId}-option-${catalog.length}`, type: "button", role: "option", "aria-selected": false, onMouseEnter: () => setHighlight(catalog.length), className: cn("min-h-12 w-full rounded px-3 text-left", highlight === catalog.length && "bg-muted"), onClick: submit, children: [
7181
+ "Search text ",
7182
+ pending
7183
+ ] })
7184
+ ] }),
7185
+ pivot && /* @__PURE__ */ jsxs("div", { role: "alertdialog", "aria-label": "Confirm query pivot", className: "rounded-xl border border-border p-3", children: [
7186
+ /* @__PURE__ */ jsx("p", { children: "Changing the query removes incompatible clauses:" }),
7187
+ /* @__PURE__ */ jsx("ul", { children: pivot.removed.map((item) => /* @__PURE__ */ jsx("li", { children: item }, item)) }),
7188
+ /* @__PURE__ */ jsx("button", { type: "button", className: "min-h-12 px-3", onClick: () => setPivot(void 0), children: "Cancel" }),
7189
+ /* @__PURE__ */ jsx("button", { type: "button", className: "min-h-12 px-3", onClick: () => {
7190
+ commit(pivot.draft);
7191
+ setPivot(void 0);
7192
+ closeEditor();
7193
+ }, children: "Change query" })
7194
+ ] }),
7195
+ !showDiagnostics && (error ?? resolved.error) && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: error ?? resolved.error }),
7196
+ !guided && !resolved.error && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Use Edit WQL to preserve every clause." }),
7197
+ pending && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": "wql-composer-pending", children: resolved.valid ? "Current draft includes this text" : resolved.error }),
7198
+ showDiagnostics && diagnosticsPosition === "bottom" ? /* @__PURE__ */ jsx(WqlDiagnosticsStrip, { diagnostics, stages, actions: action }) : diagnosticsPosition !== "top" || !showDiagnostics ? Boolean(actionLabel || diagnosticsActions) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-2", children: action }) : null
7199
+ ]
7200
+ }
7201
+ );
6884
7202
  }
6885
7203
 
6886
7204
  // src/composer/filterTypeahead.ts
@@ -13350,5 +13668,5 @@ function editorPreset(optionsOrDialect = "markdown") {
13350
13668
  }
13351
13669
 
13352
13670
  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, autocompleteTooltipTheme, blockTypesFromBlocks, canonicalSuggestionItems, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, customCompletionSources, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editQueryClause, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, extractMetricsByCategory, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatClockTime, formatMMSS, formatTimestamp, frontmatterDetailed, frontmatterPreview, frontmatterPreviewField, frontmatterReferenceIndex, frontmatterSource, frontmatterSuggestions, frontmatterVisibility, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, linkPreview, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, matchFilterTypeahead, mergeSeries, mergeSuggestionItems, mergeTagSuggestions, navigationFacet, nestedCompletion, nestedCompletionOptions, normalizeOutputFilter, notebookSlugsFromBlocks, patchBlockQuery, presentBadges, previewDecorations, queryBlockPreview, readSessionRpe, referenceIndexReload, registeredSectionWidgets, removeRuntimePanel, resolveCodeLanguage, resolveQueryDraft, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sectionIdentity, sectionIdentityHistory, sectionMove, sectionRestore, sectionSaved, sessionQueryInsert, sessionQueryWql, setFrontmatterDetailed, setFrontmatterSource, setGutterHighlights, setSuggestionBinding, smartIncrement, summarizeAggregate, summarizeFind, summarizePipeline, tagsFromStaticBlocks, toChartResult, toggleWidgetEdit, tooltipTimestamp, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useVisualViewportRect, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodCompletionSource, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToPills, wrapInTimeFence };
13353
- //# sourceMappingURL=chunk-6NFNCUZU.mjs.map
13354
- //# sourceMappingURL=chunk-6NFNCUZU.mjs.map
13671
+ //# sourceMappingURL=chunk-2XY6AZR6.mjs.map
13672
+ //# sourceMappingURL=chunk-2XY6AZR6.mjs.map