@bitcobblers/wod-wiki-ui 0.10.42 → 0.11.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -299,7 +299,9 @@ declare const DEFAULT_DIAGNOSTICS_DEBOUNCE_MS = 150;
299
299
  declare function useWqlStageCounts(ast: AnyParsedQuery, valid: boolean, execute: WqlExecutor | undefined, debounceMs?: number): WqlStageCounts | undefined;
300
300
 
301
301
  /**
302
- * Shared query-clause model + WQL compiler for the WqlComposer.
302
+ * The WqlComposer pill vocabulary — types, metadata, and option lists.
303
+ * Compilation and restore live in `./queryAst` (ticket 013): composer state
304
+ * is the C6 AST; strings are produced only through the engine serializer.
303
305
  *
304
306
  * Source-pivot model (issue #838, decision #836): a single `source` head
305
307
  * slot — journal | collections | feeds | notes | blocks | efforts | metrics —
@@ -378,68 +380,6 @@ interface ClauseMeta {
378
380
  prefix?: string;
379
381
  required?: boolean;
380
382
  }
381
- declare const CLAUSE_META: Record<ClauseType, ClauseMeta>;
382
- /**
383
- * Metadata lookup for pills, popovers, and menus: built-in clauses come from
384
- * CLAUSE_META; custom slot types resolve through the ComposerRegistry;
385
- * anything else gets a generic fallback so a stale clause still renders.
386
- */
387
- declare function getClauseMeta(type: string): ClauseMeta;
388
- /**
389
- * Maps a single clause to its WQL fragment syntax.
390
- */
391
- declare function clauseToWql(clause: QueryClause): {
392
- key?: string;
393
- filterStr?: string;
394
- };
395
- /**
396
- * Composes a full WQL string from an array of QueryClauses.
397
- *
398
- * Content planes: find:<target>{<filters>} in <scope> [last <n><unit>] [where <join>]
399
- * — target/scope derived from `source` (journal|collections|feeds → note in
400
- * <source>; notes → note in all; blocks → block in all; anything else →
401
- * note in <verbatim value>, the salvage path for exotic scopes).
402
- * Metrics plane: <agg>:<metric>{<filters>} [by {<dims>}] [.rollup(<p>)] [in <unit>] [where <find join>]
403
- */
404
- declare function clausesToWql(clauses: QueryClause[]): string;
405
- /**
406
- * Restore composer clauses from a WQL string — the inverse of
407
- * `clausesToWql`, used to hydrate composer state from the URL.
408
- *
409
- * Unlike `parseQuery`, this is a *salvage* parser: it mirrors the compiler's
410
- * structure on both planes without validating the fragments, so composer-
411
- * reachable states that are WQL-invalid (e.g. `text:hello world`, a `1m`
412
- * rollup period, an empty metric) still restore exactly — the diagnostics
413
- * strip then attributes the parse error to the offending slot.
414
- *
415
- * Returns null when the string cannot be a composer product: a negated
416
- * filter, or an unknown/custom-less filter key.
417
- */
418
- declare function wqlToClauses(wql: string): QueryClause[] | null;
419
- /**
420
- * Set the aggregate metric, re-basing the clause list on the metrics plane
421
- * when needed (sidebar / launcher flows, issue #839): content planes pivot
422
- * via `pivotClauses` (shared filters survive), a missing source or metric
423
- * clause is seeded, and the metric value lands on the first metric clause.
424
- */
425
- declare function setMetricClause(clauses: QueryClause[], metric: string): QueryClause[];
426
- /**
427
- * Re-base the clause list on a new source value (decision #836): shared
428
- * filter clauses survive the pivot; kind-specific clauses are dropped
429
- * (content plane: time/where and any metrics head; metrics plane: time/
430
- * where). Pivoting to metrics seeds the head slots (agg=sum, metric empty
431
- * for placeholder guidance).
432
- */
433
- declare function pivotClauses(clauses: QueryClause[], source: string): QueryClause[];
434
- declare function defaultClauses(): QueryClause[];
435
- /** Default clauses for aggregate/metrics queries (source=metrics, agg=sum, empty metric). */
436
- declare function defaultMetricsClauses(): QueryClause[];
437
- /**
438
- * Value of the first clause of `type`, trimmed, or `fallback` when absent or
439
- * empty. Mirrors the lookup/defaulting `clausesToWql` performs, so consumers
440
- * (e.g. the Library shelf) share one defaulting rule with the compiler.
441
- */
442
- declare function clauseValue(clauses: QueryClause[], type: string, fallback?: string): string;
443
383
 
444
384
  interface WqlValidationState {
445
385
  /** True when the composed WQL parses without error. */
@@ -448,17 +388,15 @@ interface WqlValidationState {
448
388
  error?: string;
449
389
  }
450
390
  interface WqlComposerProps {
451
- /** Seed clauses for uncontrolled usage. Defaults to source/time. */
452
- initialClauses?: QueryClause[];
453
- /** Controlled clauses. When provided, the component does not own clause state. */
454
- clauses?: QueryClause[];
455
- /** Fired whenever the clause list changes (add / edit / remove). */
456
- onClausesChange?: (clauses: QueryClause[]) => void;
457
- /** Fired (including on mount) with the composed WQL string. */
458
- onWqlChange?: (wql: string) => void;
391
+ /** Seed query for uncontrolled usage. Defaults to the content-plane default. */
392
+ initialQuery?: string;
393
+ /** Controlled WQL text. When provided, the component does not own query state. */
394
+ query?: string;
395
+ /** Fired whenever the composed query changes (add / edit / remove a pill). */
396
+ onQueryChange?: (wql: string) => void;
459
397
  /** Fired (including on mount) with parse validation state. */
460
398
  onValidationChange?: (state: WqlValidationState) => void;
461
- /** Fired (including on mount) with the parsed AST. */
399
+ /** Fired (including on mount) with the parsed AST — the composer state. */
462
400
  onAstChange?: (ast: AnyParsedQuery) => void;
463
401
  /**
464
402
  * Fired on Enter when no free text is pending — the run-on-submit signal
@@ -478,7 +416,7 @@ interface WqlComposerProps {
478
416
  /** Host actions appended on the diagnostics line. */
479
417
  diagnosticsActions?: ReactNode;
480
418
  /**
481
- * Clause types kept in the model but NOT rendered as pills.
419
+ * Pill types kept in the model but NOT rendered as pills.
482
420
  */
483
421
  hiddenClauseTypes?: ClauseType[];
484
422
  /** Focus the free-text input on mount. */
@@ -487,7 +425,7 @@ interface WqlComposerProps {
487
425
  placeholder?: string;
488
426
  className?: string;
489
427
  }
490
- declare function WqlComposer({ initialClauses, clauses: controlledClauses, onClausesChange, onWqlChange, onValidationChange, onAstChange, onSubmit, showDiagnostics, execute, debounceMs, customSlots, diagnosticsActions, hiddenClauseTypes, autoFocus, placeholder, className, }: WqlComposerProps): react.JSX.Element;
428
+ declare function WqlComposer({ initialQuery, query: controlledQuery, onQueryChange, onValidationChange, onAstChange, onSubmit, showDiagnostics, execute, debounceMs, customSlots, diagnosticsActions, hiddenClauseTypes, autoFocus, placeholder, className, }: WqlComposerProps): react.JSX.Element;
491
429
 
492
430
  interface CustomSlotEditorProps<TValue> {
493
431
  value: TValue | undefined;
@@ -599,7 +537,7 @@ declare function useSuggestions(type: string): ClauseSuggestions;
599
537
 
600
538
  interface WqlDiagnostics {
601
539
  valid: boolean;
602
- /** The composed WQL string for the current clause set. */
540
+ /** The composed WQL string (serializer output) for the current pills. */
603
541
  wql: string;
604
542
  ast: AnyParsedQuery;
605
543
  error?: string;
@@ -624,7 +562,6 @@ interface WqlAggregateSummary {
624
562
  filterCount: number;
625
563
  }
626
564
  declare function summarizeAggregate(ast: ParsedAggregateQuery): WqlAggregateSummary;
627
- declare function diagnoseClauses(clauses: QueryClause[]): WqlDiagnostics;
628
565
 
629
566
  interface WqlDiagnosticsStripProps {
630
567
  diagnostics: WqlDiagnostics;
@@ -658,13 +595,13 @@ declare function patchBlockQuery(blockContent: string, newQuery: string, queryIn
658
595
  * Auto-generated build version metadata.
659
596
  * Do not edit directly; updated by scripts/stamp-version.ts
660
597
  */
661
- declare const VERSION = "0.10.42";
662
- declare const GIT_SHA = "79c6d18";
663
- declare const BUILD_TIME = "2026-08-26T04:44:54.356Z";
598
+ declare const VERSION = "0.11.43";
599
+ declare const GIT_SHA = "ed28149";
600
+ declare const BUILD_TIME = "2026-08-26T16:34:15.927Z";
664
601
  declare const SEMVER: {
665
- readonly version: "0.10.42";
666
- readonly gitSha: "79c6d18";
667
- readonly buildTime: "2026-08-26T04:44:54.356Z";
602
+ readonly version: "0.11.43";
603
+ readonly gitSha: "ed28149";
604
+ readonly buildTime: "2026-08-26T16:34:15.927Z";
668
605
  };
669
606
 
670
- export { AGG_OPTIONS, ANALYTICS_UNIT_STORAGE_KEY, AddCalcDropdown, AddFilterDropdown, type AnalyticsQueriesState, type AnalyticsQueryDef, type AnalyticsRangeWeeks, type AnalyticsUnit, AnalyticsUnitPreference, type AnalyticsUnitPreferenceProps, BUILD_TIME, CLAUSE_META, CODEMIRROR_SINGLETON_DEPS, CONTENT_SOURCES, type ChartShape, type ClauseMeta, ClausePopover, type ClauseSuggestions, type ClauseType, ComposerRegistry, type CustomSlotDefinition, type CustomSlotEditorProps, CustomSlotPopover, DEFAULT_ANALYTICS_UNIT, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DashboardTokenControls, type DashboardTokenControlsProps, DashboardView, type DashboardViewProps, type DateRange, type ExtractedQuery, GIT_SHA, GROUPBY_OPTIONS, GoalRings, type GoalRingsProps, METRIC_OPTIONS, MULTI_VALUE_TYPES, type MergedPoint, ProposedMetricBadge, QueryBlockView, type QueryBlockViewProps, type QueryClause, QueryExecutor, QueryValue, type QueryValueProps, ROLLUP_OPTIONS, RangeSelector, type RangeSelectorProps, RowsResultsChrome, type RowsResultsChromeProps, RowsTable, type RowsTableProps, SEMVER, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, type StackedBarProps, type StorageLike, type SuggestionBinding, type SuggestionCachePolicy, type SuggestionItem, TIME_OPTIONS, TokenSlotPill, type TokenSlotPillProps, TopList, type TopListProps, UNIT_OPTIONS, VERSION, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, type WidgetChartProps, WidgetFrame, type WidgetFrameProps, WidgetProblemBadge, type WqlAggregateSummary, WqlBars, type WqlBarsProps, WqlComposer, type WqlComposerProps, type WqlDiagnostics, WqlDiagnosticsStrip, type WqlDiagnosticsStripProps, WqlEmptyState, type WqlEmptyStateProps, type WqlExecutor, type WqlFindSummary, WqlQueryInspectorModal, type WqlQueryInspectorModalProps, type WqlStageCounts, WqlTable, type WqlTableProps, WqlTimeseries, type WqlTimeseriesProps, type WqlValidationState, ZoneDistribution, type ZoneDistributionProps, blockTypesFromBlocks, catalogIdsFromBlocks, clauseToWql, clauseValue, clausesToWql, cn, compactNumber, composerRegistry, dateRangeSlot, defaultClauses, defaultMetricsClauses, diagnoseClauses, extractBlockQueries, formatTimestamp, getClauseMeta, getDashboardEffectiveUnit, getEffectiveAnalyticsUnit, getSuggestionBinding, hashCode, invalidateSuggestions, loadSuggestions, mergeSeries, mergeTagSuggestions, patchBlockQuery, pivotClauses, readSessionRpe, readStoredUnit, setMetricClause, setSuggestionBinding, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, tooltipTimestamp, useAnalyticsQueries, useAnalyticsUnitPreference, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts, wqlToClauses };
607
+ export { AGG_OPTIONS, ANALYTICS_UNIT_STORAGE_KEY, AddCalcDropdown, AddFilterDropdown, type AnalyticsQueriesState, type AnalyticsQueryDef, type AnalyticsRangeWeeks, type AnalyticsUnit, AnalyticsUnitPreference, type AnalyticsUnitPreferenceProps, BUILD_TIME, CODEMIRROR_SINGLETON_DEPS, CONTENT_SOURCES, type ChartShape, type ClauseMeta, ClausePopover, type ClauseSuggestions, type ClauseType, ComposerRegistry, type CustomSlotDefinition, type CustomSlotEditorProps, CustomSlotPopover, DEFAULT_ANALYTICS_UNIT, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DashboardTokenControls, type DashboardTokenControlsProps, DashboardView, type DashboardViewProps, type DateRange, type ExtractedQuery, GIT_SHA, GROUPBY_OPTIONS, GoalRings, type GoalRingsProps, METRIC_OPTIONS, MULTI_VALUE_TYPES, type MergedPoint, ProposedMetricBadge, QueryBlockView, type QueryBlockViewProps, type QueryClause, QueryExecutor, QueryValue, type QueryValueProps, ROLLUP_OPTIONS, RangeSelector, type RangeSelectorProps, RowsResultsChrome, type RowsResultsChromeProps, RowsTable, type RowsTableProps, SEMVER, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, type StackedBarProps, type StorageLike, type SuggestionBinding, type SuggestionCachePolicy, type SuggestionItem, TIME_OPTIONS, TokenSlotPill, type TokenSlotPillProps, TopList, type TopListProps, UNIT_OPTIONS, VERSION, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, type WidgetChartProps, WidgetFrame, type WidgetFrameProps, WidgetProblemBadge, type WqlAggregateSummary, WqlBars, type WqlBarsProps, WqlComposer, type WqlComposerProps, type WqlDiagnostics, WqlDiagnosticsStrip, type WqlDiagnosticsStripProps, WqlEmptyState, type WqlEmptyStateProps, type WqlExecutor, type WqlFindSummary, WqlQueryInspectorModal, type WqlQueryInspectorModalProps, type WqlStageCounts, WqlTable, type WqlTableProps, WqlTimeseries, type WqlTimeseriesProps, type WqlValidationState, ZoneDistribution, type ZoneDistributionProps, blockTypesFromBlocks, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, dateRangeSlot, extractBlockQueries, formatTimestamp, getDashboardEffectiveUnit, getEffectiveAnalyticsUnit, getSuggestionBinding, hashCode, invalidateSuggestions, loadSuggestions, mergeSeries, mergeTagSuggestions, patchBlockQuery, readSessionRpe, readStoredUnit, setSuggestionBinding, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, tooltipTimestamp, useAnalyticsQueries, useAnalyticsUnitPreference, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts };
package/dist/index.d.ts CHANGED
@@ -299,7 +299,9 @@ declare const DEFAULT_DIAGNOSTICS_DEBOUNCE_MS = 150;
299
299
  declare function useWqlStageCounts(ast: AnyParsedQuery, valid: boolean, execute: WqlExecutor | undefined, debounceMs?: number): WqlStageCounts | undefined;
300
300
 
301
301
  /**
302
- * Shared query-clause model + WQL compiler for the WqlComposer.
302
+ * The WqlComposer pill vocabulary — types, metadata, and option lists.
303
+ * Compilation and restore live in `./queryAst` (ticket 013): composer state
304
+ * is the C6 AST; strings are produced only through the engine serializer.
303
305
  *
304
306
  * Source-pivot model (issue #838, decision #836): a single `source` head
305
307
  * slot — journal | collections | feeds | notes | blocks | efforts | metrics —
@@ -378,68 +380,6 @@ interface ClauseMeta {
378
380
  prefix?: string;
379
381
  required?: boolean;
380
382
  }
381
- declare const CLAUSE_META: Record<ClauseType, ClauseMeta>;
382
- /**
383
- * Metadata lookup for pills, popovers, and menus: built-in clauses come from
384
- * CLAUSE_META; custom slot types resolve through the ComposerRegistry;
385
- * anything else gets a generic fallback so a stale clause still renders.
386
- */
387
- declare function getClauseMeta(type: string): ClauseMeta;
388
- /**
389
- * Maps a single clause to its WQL fragment syntax.
390
- */
391
- declare function clauseToWql(clause: QueryClause): {
392
- key?: string;
393
- filterStr?: string;
394
- };
395
- /**
396
- * Composes a full WQL string from an array of QueryClauses.
397
- *
398
- * Content planes: find:<target>{<filters>} in <scope> [last <n><unit>] [where <join>]
399
- * — target/scope derived from `source` (journal|collections|feeds → note in
400
- * <source>; notes → note in all; blocks → block in all; anything else →
401
- * note in <verbatim value>, the salvage path for exotic scopes).
402
- * Metrics plane: <agg>:<metric>{<filters>} [by {<dims>}] [.rollup(<p>)] [in <unit>] [where <find join>]
403
- */
404
- declare function clausesToWql(clauses: QueryClause[]): string;
405
- /**
406
- * Restore composer clauses from a WQL string — the inverse of
407
- * `clausesToWql`, used to hydrate composer state from the URL.
408
- *
409
- * Unlike `parseQuery`, this is a *salvage* parser: it mirrors the compiler's
410
- * structure on both planes without validating the fragments, so composer-
411
- * reachable states that are WQL-invalid (e.g. `text:hello world`, a `1m`
412
- * rollup period, an empty metric) still restore exactly — the diagnostics
413
- * strip then attributes the parse error to the offending slot.
414
- *
415
- * Returns null when the string cannot be a composer product: a negated
416
- * filter, or an unknown/custom-less filter key.
417
- */
418
- declare function wqlToClauses(wql: string): QueryClause[] | null;
419
- /**
420
- * Set the aggregate metric, re-basing the clause list on the metrics plane
421
- * when needed (sidebar / launcher flows, issue #839): content planes pivot
422
- * via `pivotClauses` (shared filters survive), a missing source or metric
423
- * clause is seeded, and the metric value lands on the first metric clause.
424
- */
425
- declare function setMetricClause(clauses: QueryClause[], metric: string): QueryClause[];
426
- /**
427
- * Re-base the clause list on a new source value (decision #836): shared
428
- * filter clauses survive the pivot; kind-specific clauses are dropped
429
- * (content plane: time/where and any metrics head; metrics plane: time/
430
- * where). Pivoting to metrics seeds the head slots (agg=sum, metric empty
431
- * for placeholder guidance).
432
- */
433
- declare function pivotClauses(clauses: QueryClause[], source: string): QueryClause[];
434
- declare function defaultClauses(): QueryClause[];
435
- /** Default clauses for aggregate/metrics queries (source=metrics, agg=sum, empty metric). */
436
- declare function defaultMetricsClauses(): QueryClause[];
437
- /**
438
- * Value of the first clause of `type`, trimmed, or `fallback` when absent or
439
- * empty. Mirrors the lookup/defaulting `clausesToWql` performs, so consumers
440
- * (e.g. the Library shelf) share one defaulting rule with the compiler.
441
- */
442
- declare function clauseValue(clauses: QueryClause[], type: string, fallback?: string): string;
443
383
 
444
384
  interface WqlValidationState {
445
385
  /** True when the composed WQL parses without error. */
@@ -448,17 +388,15 @@ interface WqlValidationState {
448
388
  error?: string;
449
389
  }
450
390
  interface WqlComposerProps {
451
- /** Seed clauses for uncontrolled usage. Defaults to source/time. */
452
- initialClauses?: QueryClause[];
453
- /** Controlled clauses. When provided, the component does not own clause state. */
454
- clauses?: QueryClause[];
455
- /** Fired whenever the clause list changes (add / edit / remove). */
456
- onClausesChange?: (clauses: QueryClause[]) => void;
457
- /** Fired (including on mount) with the composed WQL string. */
458
- onWqlChange?: (wql: string) => void;
391
+ /** Seed query for uncontrolled usage. Defaults to the content-plane default. */
392
+ initialQuery?: string;
393
+ /** Controlled WQL text. When provided, the component does not own query state. */
394
+ query?: string;
395
+ /** Fired whenever the composed query changes (add / edit / remove a pill). */
396
+ onQueryChange?: (wql: string) => void;
459
397
  /** Fired (including on mount) with parse validation state. */
460
398
  onValidationChange?: (state: WqlValidationState) => void;
461
- /** Fired (including on mount) with the parsed AST. */
399
+ /** Fired (including on mount) with the parsed AST — the composer state. */
462
400
  onAstChange?: (ast: AnyParsedQuery) => void;
463
401
  /**
464
402
  * Fired on Enter when no free text is pending — the run-on-submit signal
@@ -478,7 +416,7 @@ interface WqlComposerProps {
478
416
  /** Host actions appended on the diagnostics line. */
479
417
  diagnosticsActions?: ReactNode;
480
418
  /**
481
- * Clause types kept in the model but NOT rendered as pills.
419
+ * Pill types kept in the model but NOT rendered as pills.
482
420
  */
483
421
  hiddenClauseTypes?: ClauseType[];
484
422
  /** Focus the free-text input on mount. */
@@ -487,7 +425,7 @@ interface WqlComposerProps {
487
425
  placeholder?: string;
488
426
  className?: string;
489
427
  }
490
- declare function WqlComposer({ initialClauses, clauses: controlledClauses, onClausesChange, onWqlChange, onValidationChange, onAstChange, onSubmit, showDiagnostics, execute, debounceMs, customSlots, diagnosticsActions, hiddenClauseTypes, autoFocus, placeholder, className, }: WqlComposerProps): react.JSX.Element;
428
+ declare function WqlComposer({ initialQuery, query: controlledQuery, onQueryChange, onValidationChange, onAstChange, onSubmit, showDiagnostics, execute, debounceMs, customSlots, diagnosticsActions, hiddenClauseTypes, autoFocus, placeholder, className, }: WqlComposerProps): react.JSX.Element;
491
429
 
492
430
  interface CustomSlotEditorProps<TValue> {
493
431
  value: TValue | undefined;
@@ -599,7 +537,7 @@ declare function useSuggestions(type: string): ClauseSuggestions;
599
537
 
600
538
  interface WqlDiagnostics {
601
539
  valid: boolean;
602
- /** The composed WQL string for the current clause set. */
540
+ /** The composed WQL string (serializer output) for the current pills. */
603
541
  wql: string;
604
542
  ast: AnyParsedQuery;
605
543
  error?: string;
@@ -624,7 +562,6 @@ interface WqlAggregateSummary {
624
562
  filterCount: number;
625
563
  }
626
564
  declare function summarizeAggregate(ast: ParsedAggregateQuery): WqlAggregateSummary;
627
- declare function diagnoseClauses(clauses: QueryClause[]): WqlDiagnostics;
628
565
 
629
566
  interface WqlDiagnosticsStripProps {
630
567
  diagnostics: WqlDiagnostics;
@@ -658,13 +595,13 @@ declare function patchBlockQuery(blockContent: string, newQuery: string, queryIn
658
595
  * Auto-generated build version metadata.
659
596
  * Do not edit directly; updated by scripts/stamp-version.ts
660
597
  */
661
- declare const VERSION = "0.10.42";
662
- declare const GIT_SHA = "79c6d18";
663
- declare const BUILD_TIME = "2026-08-26T04:44:54.356Z";
598
+ declare const VERSION = "0.11.43";
599
+ declare const GIT_SHA = "ed28149";
600
+ declare const BUILD_TIME = "2026-08-26T16:34:15.927Z";
664
601
  declare const SEMVER: {
665
- readonly version: "0.10.42";
666
- readonly gitSha: "79c6d18";
667
- readonly buildTime: "2026-08-26T04:44:54.356Z";
602
+ readonly version: "0.11.43";
603
+ readonly gitSha: "ed28149";
604
+ readonly buildTime: "2026-08-26T16:34:15.927Z";
668
605
  };
669
606
 
670
- export { AGG_OPTIONS, ANALYTICS_UNIT_STORAGE_KEY, AddCalcDropdown, AddFilterDropdown, type AnalyticsQueriesState, type AnalyticsQueryDef, type AnalyticsRangeWeeks, type AnalyticsUnit, AnalyticsUnitPreference, type AnalyticsUnitPreferenceProps, BUILD_TIME, CLAUSE_META, CODEMIRROR_SINGLETON_DEPS, CONTENT_SOURCES, type ChartShape, type ClauseMeta, ClausePopover, type ClauseSuggestions, type ClauseType, ComposerRegistry, type CustomSlotDefinition, type CustomSlotEditorProps, CustomSlotPopover, DEFAULT_ANALYTICS_UNIT, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DashboardTokenControls, type DashboardTokenControlsProps, DashboardView, type DashboardViewProps, type DateRange, type ExtractedQuery, GIT_SHA, GROUPBY_OPTIONS, GoalRings, type GoalRingsProps, METRIC_OPTIONS, MULTI_VALUE_TYPES, type MergedPoint, ProposedMetricBadge, QueryBlockView, type QueryBlockViewProps, type QueryClause, QueryExecutor, QueryValue, type QueryValueProps, ROLLUP_OPTIONS, RangeSelector, type RangeSelectorProps, RowsResultsChrome, type RowsResultsChromeProps, RowsTable, type RowsTableProps, SEMVER, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, type StackedBarProps, type StorageLike, type SuggestionBinding, type SuggestionCachePolicy, type SuggestionItem, TIME_OPTIONS, TokenSlotPill, type TokenSlotPillProps, TopList, type TopListProps, UNIT_OPTIONS, VERSION, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, type WidgetChartProps, WidgetFrame, type WidgetFrameProps, WidgetProblemBadge, type WqlAggregateSummary, WqlBars, type WqlBarsProps, WqlComposer, type WqlComposerProps, type WqlDiagnostics, WqlDiagnosticsStrip, type WqlDiagnosticsStripProps, WqlEmptyState, type WqlEmptyStateProps, type WqlExecutor, type WqlFindSummary, WqlQueryInspectorModal, type WqlQueryInspectorModalProps, type WqlStageCounts, WqlTable, type WqlTableProps, WqlTimeseries, type WqlTimeseriesProps, type WqlValidationState, ZoneDistribution, type ZoneDistributionProps, blockTypesFromBlocks, catalogIdsFromBlocks, clauseToWql, clauseValue, clausesToWql, cn, compactNumber, composerRegistry, dateRangeSlot, defaultClauses, defaultMetricsClauses, diagnoseClauses, extractBlockQueries, formatTimestamp, getClauseMeta, getDashboardEffectiveUnit, getEffectiveAnalyticsUnit, getSuggestionBinding, hashCode, invalidateSuggestions, loadSuggestions, mergeSeries, mergeTagSuggestions, patchBlockQuery, pivotClauses, readSessionRpe, readStoredUnit, setMetricClause, setSuggestionBinding, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, tooltipTimestamp, useAnalyticsQueries, useAnalyticsUnitPreference, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts, wqlToClauses };
607
+ export { AGG_OPTIONS, ANALYTICS_UNIT_STORAGE_KEY, AddCalcDropdown, AddFilterDropdown, type AnalyticsQueriesState, type AnalyticsQueryDef, type AnalyticsRangeWeeks, type AnalyticsUnit, AnalyticsUnitPreference, type AnalyticsUnitPreferenceProps, BUILD_TIME, CODEMIRROR_SINGLETON_DEPS, CONTENT_SOURCES, type ChartShape, type ClauseMeta, ClausePopover, type ClauseSuggestions, type ClauseType, ComposerRegistry, type CustomSlotDefinition, type CustomSlotEditorProps, CustomSlotPopover, DEFAULT_ANALYTICS_UNIT, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DashboardTokenControls, type DashboardTokenControlsProps, DashboardView, type DashboardViewProps, type DateRange, type ExtractedQuery, GIT_SHA, GROUPBY_OPTIONS, GoalRings, type GoalRingsProps, METRIC_OPTIONS, MULTI_VALUE_TYPES, type MergedPoint, ProposedMetricBadge, QueryBlockView, type QueryBlockViewProps, type QueryClause, QueryExecutor, QueryValue, type QueryValueProps, ROLLUP_OPTIONS, RangeSelector, type RangeSelectorProps, RowsResultsChrome, type RowsResultsChromeProps, RowsTable, type RowsTableProps, SEMVER, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, type StackedBarProps, type StorageLike, type SuggestionBinding, type SuggestionCachePolicy, type SuggestionItem, TIME_OPTIONS, TokenSlotPill, type TokenSlotPillProps, TopList, type TopListProps, UNIT_OPTIONS, VERSION, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, type WidgetChartProps, WidgetFrame, type WidgetFrameProps, WidgetProblemBadge, type WqlAggregateSummary, WqlBars, type WqlBarsProps, WqlComposer, type WqlComposerProps, type WqlDiagnostics, WqlDiagnosticsStrip, type WqlDiagnosticsStripProps, WqlEmptyState, type WqlEmptyStateProps, type WqlExecutor, type WqlFindSummary, WqlQueryInspectorModal, type WqlQueryInspectorModalProps, type WqlStageCounts, WqlTable, type WqlTableProps, WqlTimeseries, type WqlTimeseriesProps, type WqlValidationState, ZoneDistribution, type ZoneDistributionProps, blockTypesFromBlocks, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, dateRangeSlot, extractBlockQueries, formatTimestamp, getDashboardEffectiveUnit, getEffectiveAnalyticsUnit, getSuggestionBinding, hashCode, invalidateSuggestions, loadSuggestions, mergeSeries, mergeTagSuggestions, patchBlockQuery, readSessionRpe, readStoredUnit, setSuggestionBinding, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, tooltipTimestamp, useAnalyticsQueries, useAnalyticsUnitPreference, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { cn, WidgetProblemBadge, WidgetChart } from './chunk-S77JRUQM.mjs';
2
- export { AGG_OPTIONS, AddCalcDropdown, AddFilterDropdown, CLAUSE_META, CONTENT_SOURCES, ClausePopover, ComposerRegistry, CustomSlotPopover, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DefaultFrontmatterWidget, GROUPBY_OPTIONS, GoalRings, METRIC_OPTIONS, MULTI_VALUE_TYPES, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TIME_OPTIONS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockContentId, blockTypesFromBlocks, catalogIdsFromBlocks, clauseToWql, clauseValue, clausesToWql, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, defaultClauses, defaultMetricsClauses, diagnoseClauses, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatTimestamp, frontmatterPreview, frontmatterPreviewField, getClauseMeta, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, mergeSeries, mergeTagSuggestions, navigationFacet, patchBlockQuery, pivotClauses, previewDecorations, queryBlockPreview, readSessionRpe, removeRuntimePanel, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setMetricClause, setSuggestionBinding, smartIncrement, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, toggleWidgetEdit, tooltipTimestamp, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wqlToClauses, wrapInTimeFence } from './chunk-S77JRUQM.mjs';
1
+ import { cn, WidgetProblemBadge, WidgetChart } from './chunk-PZXX6GBK.mjs';
2
+ export { AGG_OPTIONS, AddCalcDropdown, AddFilterDropdown, CONTENT_SOURCES, ClausePopover, ComposerRegistry, CustomSlotPopover, DEFAULT_DIAGNOSTICS_DEBOUNCE_MS, DefaultFrontmatterWidget, GROUPBY_OPTIONS, GoalRings, METRIC_OPTIONS, MULTI_VALUE_TYPES, ProposedMetricBadge, QueryBlockView, QueryValue, ROLLUP_OPTIONS, RowsResultsChrome, RowsTable, SERIES_COLORS, SOURCE_OPTIONS, SUGGESTION_BINDINGS, StackedBar, TIME_OPTIONS, TokenSlotPill, TopList, UNIT_OPTIONS, WHERE_AGGREGATORS, WHERE_METRICS, WHERE_OPERATORS, WidgetChart, WidgetProblemBadge, WqlBars, WqlComposer, WqlDiagnosticsStrip, WqlEmptyState, WqlQueryInspectorModal, WqlTable, WqlTimeseries, ZoneDistribution, activeCursorSection, addRuntimePanel, blockContentId, blockTypesFromBlocks, catalogIdsFromBlocks, cn, compactNumber, composerRegistry, configureOverlayActions, cursorFocusExtension, dateRangeSlot, dispatchAddRuntimePanel, dispatchExpandRuntimePanel, dispatchGutterHighlights, dispatchRemoveRuntimePanel, editingWidgetsField, editorPreset, editorTheme, embedPreviewDecorations, expandRuntimePanel, extractBlockQueries, fenceCompletion, findQueryBlockSection, findWorkoutErrors, forceSectionParse, formatTimestamp, frontmatterPreview, frontmatterPreviewField, getCursorFocusState, getOverlayActions, getSuggestionBinding, gutterHighlightsField, gutterUnified, handleFenceAutoWrap, hashCode, inlineButtonDecoration, invalidateSuggestions, lineIdsExtension, linkOpen, loadSuggestions, markdownSyntaxHiding, markdownTablePreview, mergeSeries, mergeTagSuggestions, navigationFacet, patchBlockQuery, previewDecorations, queryBlockPreview, readSessionRpe, removeRuntimePanel, runtimePanelField, saveBlockQuerySource, sectionAtPos, sectionField, sectionGeometry, sessionQueryInsert, sessionQueryWql, setGutterHighlights, setSuggestionBinding, smartIncrement, sourcePlane, summarizeAggregate, summarizeFind, tagsFromStaticBlocks, toggleWidgetEdit, tooltipTimestamp, urlAtPos, useChartShape, useComposerSlots, useSuggestions, useWqlStageCounts, widgetBlockPreview, wodAutoWrap, wodAutocompletion, wodEditorKeymap, wodLinter, wodOverlayPanel, workoutLintSource, wrapInTimeFence } from './chunk-PZXX6GBK.mjs';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { useMemo, useState, useEffect, useCallback } from 'react';
5
5
  import { Edit3 } from 'lucide-react';
@@ -405,13 +405,13 @@ function AnalyticsUnitPreference({ className, unit: unitProp, forced = false, st
405
405
  }
406
406
 
407
407
  // src/version.ts
408
- var VERSION = "0.10.42";
409
- var GIT_SHA = "79c6d18";
410
- var BUILD_TIME = "2026-08-26T04:44:54.356Z";
408
+ var VERSION = "0.11.43";
409
+ var GIT_SHA = "ed28149";
410
+ var BUILD_TIME = "2026-08-26T16:34:15.927Z";
411
411
  var SEMVER = {
412
- version: "0.10.42",
413
- gitSha: "79c6d18",
414
- buildTime: "2026-08-26T04:44:54.356Z"
412
+ version: "0.11.43",
413
+ gitSha: "ed28149",
414
+ buildTime: "2026-08-26T16:34:15.927Z"
415
415
  };
416
416
 
417
417
  export { ANALYTICS_UNIT_STORAGE_KEY, AnalyticsUnitPreference, BUILD_TIME, CODEMIRROR_SINGLETON_DEPS, DEFAULT_ANALYTICS_UNIT, DashboardTokenControls, DashboardView, GIT_SHA, RangeSelector, SEMVER, VERSION, WidgetFrame, getDashboardEffectiveUnit, getEffectiveAnalyticsUnit, readStoredUnit, useAnalyticsQueries, useAnalyticsUnitPreference };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contracts/dedupe.ts","../src/widgets/WidgetFrame.tsx","../src/widgets/DashboardTokenControls.tsx","../src/widgets/DashboardView.tsx","../src/widgets/RangeSelector.tsx","../src/widgets/useAnalyticsQueries.ts","../src/widgets/useAnalyticsUnitPreference.tsx","../src/version.ts"],"names":["jsx","jsxs","useState","useEffect","parseQuery"],"mappings":";;;;;;;;AAAO,IAAM,yBAAA,GAA4B;AAAA,EACvC,0BAAA;AAAA,EACA,sBAAA;AAAA,EACA,2BAAA;AAAA,EACA,sBAAA;AAAA,EACA,kBAAA;AAAA,EACA,oBAAA;AAAA,EACA,mBAAA;AAAA,EACA,4BAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF;ACHO,SAAS,YAAY,EAAE,KAAA,EAAO,UAAU,KAAA,EAAO,IAAA,EAAM,UAAS,EAAqB;AACxF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,mEAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gDAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,+CAAA,EACX,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,0BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uFAAA,EACb,QAAA,EAAA,QAAA,EACH;AAAA,SAAA,EACF,CAAA;AAAA,wBAIA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6GAAA,EACZ,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EAAkB,QAAA,EAAS;AAAA;AAAA;AAAA,GAC5C;AAEJ;ACnBO,SAAS,sBAAA,CAAuB,EAAE,MAAA,EAAQ,MAAA,EAAQ,UAAS,EAAgC;AAChG,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,MAAM,WAAW,CAAC,QAAA;AAElB,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,0BAAA;AAAA,MACZ,SAAA,EAAU,kDAAA;AAAA,MAET,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACrB,QAAA,MAAM,UAAU,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,IAAK,KAAA,CAAM,OAAO,CAAC,CAAA;AACpD,QAAA,uBACEC,IAAAA,CAAC,KAAA,EAAA,EAAqB,SAAA,EAAU,yBAAA,EAC9B,QAAA,EAAA;AAAA,0BAAAA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6CAAA,EAA8C,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YAAE,KAAA,CAAM;AAAA,WAAA,EAAK,CAAA;AAAA,UAC1E,KAAA,CAAM,MAAA,mBACLD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4EAAA,EACZ,QAAA,EAAA,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,MAAA,qBACjBA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,QAAA;AAAA,cACL,QAAA,EAAU,QAAA;AAAA,cACV,OAAA,EAAS,MAAM,QAAA,GAAW,KAAA,CAAM,MAAM,MAAM,CAAA;AAAA,cAC5C,SAAA,EAAW,EAAA;AAAA,gBACT,kDAAA;AAAA,gBACA,MAAA,KAAW,UACP,gDAAA,GACA,4DAAA;AAAA,gBACJ,QAAA,IAAY;AAAA,eACd;AAAA,cAEC,QAAA,EAAA;AAAA,aAAA;AAAA,YAZI;AAAA,WAcR,CAAA,EACH,CAAA,GACE,QAAA,mBACFA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,QAAA,EAAA,OAAA,EAAQ,CAAA,mBAE7DA,GAAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,MAAA;AAAA,cACL,KAAA,EAAO,OAAA;AAAA,cACP,QAAA,EAAU,CAAC,CAAA,KAAM,QAAA,CAAS,MAAM,IAAA,EAAM,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,cACpD,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EAAA,EA9BM,MAAM,IAgChB,CAAA;AAAA,MAEJ,CAAC;AAAA;AAAA,GACH;AAEJ;ACjCA,SAAS,UAAU,MAAA,EAAiC;AAClD,EAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,MAAA,CAAO,IAAI,CAAA;AAC9C,EAAA,IAAI,QAAA,KAAa,SAAS,OAAO,YAAA;AACjC,EAAA,IAAI,QAAA,KAAa,SAAS,OAAO,0BAAA;AACjC,EAAA,OAAO,wCAAA;AACT;AAQO,SAAS,aAAA,CAAc;AAAA,EAC5B,QAAA;AAAA,EACA,QAAA;AAAA,EACA,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAuB;AACrB,EAAA,MAAM,MAAA,GAAS,OAAA;AAAA,IACb,OAAO,EAAE,GAAG,kBAAA,CAAmB,SAAS,MAAM,CAAA,EAAG,GAAG,WAAA,EAAY,CAAA;AAAA,IAChE,CAAC,QAAA,CAAS,MAAA,EAAQ,WAAW;AAAA,GAC/B;AAEA,EAAA,MAAM,QAAA,GAAW,OAAA;AAAA,IACf,MACE,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AAC/B,MAAA,MAAM,EAAE,KAAA,EAAO,OAAA,KAAY,gBAAA,CAAiB,MAAA,CAAO,OAAO,MAAM,CAAA;AAChE,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAQ;AAAA,IAClC,CAAC,CAAA;AAAA,IACH,CAAC,QAAA,CAAS,OAAA,EAAS,MAAM;AAAA,GAC3B;AAEA,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAoC,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,WAAA,GAAc,OAAA;AAAA,IAClB,MAAM,QAAA,CAAS,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,MAAA,CAAO,GAAG,IAAI,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IAChE,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AAEf,IAAA,eAAe,IAAA,GAAO;AACpB,MAAA,MAAM,OAAkC,EAAC;AACzC,MAAA,MAAM,WAA8D,EAAC;AAErE,MAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,MAAa,QAAA,EAAU;AACjD,QAAA,IAAI,OAAO,IAAA,KAAS,EAAA,IAAM,CAAC,qBAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AAC7D,UAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,OAAO,wBAAA,CAAyB,MAAA,CAAO,IAAI,CAAA,EAAE;AAClE,UAAA;AAAA,QACF;AACA,QAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,UAAA,IAAA,CAAK,OAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,oBAAA,CAAqB,OAAO,CAAA,EAAE;AAC1D,UAAA;AAAA,QACF;AACA,QAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,IAAA,CAAK,OAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,OAAO,KAAA,EAAM;AACzC,UAAA;AAAA,QACF;AACA,QAAA,IAAI,WAAA,CAAY,MAAM,CAAA,EAAG;AACvB,UAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,OAAO,gEAAA,EAAiE;AAC7F,UAAA;AAAA,QACF;AACA,QAAA,QAAA,CAAS,IAAA,CAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAAA,MACjC;AAEA,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,IAAI,CAAC,SAAA,EAAW;AACd,UAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,UAAA,UAAA,CAAW,KAAK,CAAA;AAAA,QAClB;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,eAAA,GAAkB,SAAS,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,QAAA,CAAS,OAAO,CAAC,CAAA;AACtE,MAAA,IAAI,mBAAmB,mBAAA,EAAqB;AAC1C,QAAA,MAAM,mBAAA,EAAoB,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,QACZ,SAAS,GAAA,CAAI,OAAO,EAAE,MAAA,EAAQ,OAAM,KAAM;AACxC,UAAA,IAAI;AACF,YAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI;AAAA,cACjB,MAAA,EAAQ,MAAM,QAAA,CAAS,QAAA,CAAS,OAAO,EAAE,UAAA,EAAY,QAAA,EAAU,aAAA,EAAe;AAAA,aAChF;AAAA,UACF,SAAS,GAAA,EAAK;AACZ,YAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAA,EAAE;AAAA,UAC/E;AAAA,QACF,CAAC;AAAA,OACH;AAEA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF;AAEA,IAAA,KAAK,IAAA,EAAK;AACV,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,WAAA,EAAa,QAAA,EAAU,qBAAqB,UAAA,EAAY,QAAA,EAAU,aAAa,CAAC,CAAA;AAEpF,EAAA,uBACEC,IAAAA,CAAC,KAAA,EAAA,EAAI,aAAA,EAAY,gBAAA,EACf,QAAA,EAAA;AAAA,oBAAAD,IAAC,sBAAA,EAAA,EAAuB,MAAA,EAAQ,SAAS,MAAA,EAAQ,MAAA,EAAgB,UAAU,aAAA,EAAe,CAAA;AAAA,IAEzF,2BAAWA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sCAAqC,QAAA,EAAA,uBAAA,EAAgB,CAAA;AAAA,oBAEhFA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACZ,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,EAAE,MAAA,EAAQ,KAAA,EAAM,KAAM;AACnC,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAC3B,MAAA,uBACEA,GAAAA;AAAA,QAAC,WAAA;AAAA,QAAA;AAAA,UAEC,KAAA,EAAO,OAAO,KAAA,IAAS,EAAA;AAAA,UACvB,QAAA,EAAU,OAAO,QAAA,IAAY,EAAA;AAAA,UAC7B,KAAA;AAAA,UACA,IAAA,EAAM,UAAU,MAAM,CAAA;AAAA,UAEtB,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0CAAA,EACZ,QAAA,EAAA;AAAA,YAAA,WAAA,oBACCD,GAAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,MAAM,WAAA,CAAY,MAAM,CAAA;AAAA,gBACjC,KAAA,EAAM,mBAAA;AAAA,gBACN,YAAA,EAAY,CAAA,eAAA,EAAkB,MAAA,CAAO,KAAA,IAAS,QAAQ,CAAA,CAAA;AAAA,gBACtD,SAAA,EAAU,2JAAA;AAAA,gBAEV,QAAA,kBAAAA,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,aAAA,EAAc;AAAA;AAAA,aACjC;AAAA,YAED,GAAA,EAAK,wBACJA,GAAAA,CAAC,sBAAmB,OAAA,EAAS,GAAA,CAAI,KAAA,EAAO,CAAA,mBAExCA,GAAAA;AAAA,cAAC,WAAA;AAAA,cAAA;AAAA,gBACC,MAAM,MAAA,CAAO,IAAA;AAAA,gBACb,QAAQ,GAAA,EAAK,MAAA;AAAA,gBACb,OAAO,MAAA,CAAO,KAAA;AAAA,gBACd,IAAA,EAAM,aAAA;AAAA,gBACN,QAAQ,MAAA,CAAO;AAAA;AAAA;AACjB,WAAA,EAEJ;AAAA,SAAA;AAAA,QA7BK,MAAA,CAAO;AAAA,OA8Bd;AAAA,IAEJ,CAAC,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ;ACrLO,SAAS,cAAc,EAAE,KAAA,EAAO,SAAA,EAAW,aAAA,EAAe,WAAU,EAAuB;AAChG,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIE,SAAiB,EAAE,CAAA;AAC7D,EAAA,MAAM,eAAe,SAAA,IAAa,aAAA;AAElC,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAc;AAClC,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,aAAA,CAAc,CAAC,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,gBAAA,CAAiB,CAAC,CAAA;AAAA,IACpB;AAAA,EACF,CAAA;AAEA,EAAA,uBACEF,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,8EAA8E,SAAS,CAAA,EACvG,QAAA,EAAA,CAAC,CAAA,EAAG,GAAG,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,sBACfC,IAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MAEC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,MAAM,YAAA,CAAa,CAAC,CAAA;AAAA,MAC7B,SAAA,EAAW,EAAA;AAAA,QACT,kDAAA;AAAA,QACA,YAAA,KAAiB,IACb,gDAAA,GACA;AAAA,OACN;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,CAAA;AAAA,QAAE;AAAA;AAAA,KAAA;AAAA,IAVE;AAAA,GAYR,CAAA,EACH,CAAA;AAEJ;ACtCA,IAAM,GAAA,GAAM,KAAA;AACZ,IAAM,OAAO,CAAA,GAAI,GAAA;AAYV,SAAS,oBACd,OAAA,EACA,KAAA,EACA,UACA,UAAA,GAAa,CAAA,EACb,eACA,mBAAA,EACuB;AACvB,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIC,QAAAA,CAAsC,EAAE,CAAA;AACtE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAE3C,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,IAAA,eAAe,IAAA,GAAO;AACpB,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAChC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,UAAA,GAAa,MAAM,KAAA,GAAQ,IAAA;AACjC,MAAA,MAAM,eAAA,GAAkB,QAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,QAAA,CAAS,OAAO,CAAC,CAAA;AACrE,MAAA,IAAI;AACF,QAAA,IAAI,mBAAmB,mBAAA,EAAqB;AAC1C,UAAA,MAAM,mBAAA,EAAoB,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AAAA,QACnD;AACA,QAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA;AAAA,UAC5B,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,KAAM;AAAA,YACvB,CAAA,CAAE,GAAA;AAAA,YACF,MAAM,QAAA,CAAS,QAAA,CAAS,CAAA,CAAE,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAU,GAAA,EAAK,aAAA,EAAe;AAAA,WACrE;AAAA,SACZ;AACA,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,MAAA,CAAO,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,MACxD,CAAA,SAAE;AACA,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,KAAK,IAAA,EAAK;AAEV,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,KAAA,EAAO,UAAU,UAAA,EAAY,aAAA,EAAe,mBAAmB,CAAC,CAAA;AAE7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B;AC1DO,IAAM,0BAAA,GAA6B;AACnC,IAAM,sBAAA,GAAyB;AAGtC,IAAM,WAAA,GAAwC,CAAC,IAAA,EAAM,IAAI,CAAA;AAEzD,IAAM,WAAA,uBAAkB,GAAA,EAAoB;AAC5C,IAAM,eAAA,GAA+B;AAAA,EACnC,SAAS,CAAC,GAAA,KAAgB,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,EAClD,OAAA,EAAS,CAAC,GAAA,EAAa,KAAA,KAAkB;AACvC,IAAA,WAAA,CAAY,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,EAC5B,CAAA;AAAA,EACA,UAAA,EAAY,CAAC,GAAA,KAAgB;AAC3B,IAAA,WAAA,CAAY,OAAO,GAAG,CAAA;AAAA,EACxB;AACF,CAAA;AAEA,IAAM,aAAA,uBAAoB,GAAA,EAAgB;AAC1C,SAAS,gBAAA,GAAmB;AAC1B,EAAA,KAAA,MAAW,CAAA,IAAK,eAAe,CAAA,EAAE;AACnC;AAEA,SAAS,eAAe,MAAA,EAAmC;AACzD,EAAA,OAAO,MAAA,IAAU,eAAA;AACnB;AAEO,SAAS,eAAe,OAAA,EAAsC;AACnE,EAAA,MAAM,KAAA,GAAQ,eAAe,OAAO,CAAA;AACpC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,0BAA0B,CAAA;AACvD,EAAA,OAAQ,WAAA,CAAkC,QAAA,CAAS,MAAA,IAAU,EAAE,IAC1D,MAAA,GACD,sBAAA;AACN;AAEO,SAAS,2BAA2B,aAAA,EAA6B;AACtE,EAAA,MAAM,OAAA,GAAU,eAAe,aAAa,CAAA;AAC5C,EAAA,MAAM,CAAC,MAAM,YAAY,CAAA,GAAID,SAAwB,MAAM,cAAA,CAAe,OAAO,CAAC,CAAA;AAElF,EAAAC,UAAU,MAAM;AACd,IAAA,YAAA,CAAa,cAAA,CAAe,OAAO,CAAC,CAAA;AACpC,IAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,cAAA,CAAe,OAAO,CAAC,CAAA;AACvD,IAAA,aAAA,CAAc,IAAI,IAAI,CAAA;AACtB,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,OAAO,IAAI,CAAA;AAAA,IAC3B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,CAAC,IAAA,KAAwB;AACvB,MAAA,OAAA,CAAQ,OAAA,CAAQ,4BAA4B,IAAI,CAAA;AAChD,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,gBAAA,EAAiB;AAAA,IACnB,CAAA;AAAA,IACA,CAAC,OAAO;AAAA,GACV;AAEA,EAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,MAAM,IAAA,GAAsB,IAAA,KAAS,IAAA,GAAO,IAAA,GAAO,IAAA;AACnD,IAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,EACd,CAAA,EAAG,CAAC,IAAA,EAAM,OAAO,CAAC,CAAA;AAElB,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,UAAA,EAAW;AACrC;AAEO,SAAS,yBAAA,CACd,OACA,aAAA,EAC0C;AAC1C,EAAA,MAAM,MAAA,GAASC,WAAW,KAAK,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,aAAA,IAAiB,MAAA,GAAU,MAAA,CAAe,WAAA,GAAc,MAAA;AAC5E,EAAA,IAAI,WAAA,KAAgB,IAAA,IAAQ,WAAA,KAAgB,IAAA,EAAM;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAA8B,MAAA,EAAQ,IAAA,EAAK;AAAA,EAC5D;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,MAAA,EAAQ,KAAA,EAAM;AAC9C;AAEO,SAAS,yBAAA,CACd,SACA,aAAA,EAC0C;AAC1C,EAAA,MAAM,KAAA,GAAQ,OAAA,CACX,GAAA,CAAI,CAAC,CAAA,KAAM;AACV,IAAA,MAAM,MAAA,GAASA,UAAAA,CAAW,CAAA,CAAE,KAAK,CAAA;AACjC,IAAA,OAAO,aAAA,IAAiB,MAAA,GAAU,MAAA,CAAe,WAAA,GAAc,MAAA;AAAA,EACjE,CAAC,EACA,MAAA,CAAO,CAAC,MAAmB,CAAA,KAAM,IAAA,IAAQ,MAAM,IAAI,CAAA;AAEtD,EAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AACxC,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,CAAC,CAAA,EAAoB,QAAQ,IAAA,EAAK;AAAA,EAC1D;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,MAAA,EAAQ,KAAA,EAAM;AAC9C;AAQO,SAAS,uBAAA,CAAwB,EAAE,SAAA,EAAW,IAAA,EAAM,UAAU,MAAA,GAAS,KAAA,EAAO,SAAQ,EAAiC;AAC5H,EAAA,MAAM,EAAE,IAAA,EAAM,UAAA,EAAY,OAAA,EAAQ,GAAI,2BAA2B,OAAO,CAAA;AACxE,EAAA,MAAM,aAAa,QAAA,IAAY,UAAA;AAE/B,EAAA,uBACEH,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,2BAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,wCAAA,EAA0C,SAAS,CAAA;AAAA,MAEjE,QAAA,EAAA;AAAA,wBAAAA,IAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,sEAAA;AAAA,cACA,MAAA,IAAU;AAAA,aACZ;AAAA,YACA,KAAA,EAAO,SAAS,6CAAA,GAAgD,yBAAA;AAAA,YAEhE,QAAA,EAAA;AAAA,8BAAAD,GAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,QAAA;AAAA,kBACL,QAAA,EAAU,MAAA;AAAA,kBACV,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,kBAC3B,SAAA,EAAW,EAAA;AAAA,oBACT,4DAAA;AAAA,oBACA,UAAA,KAAe,OACX,gDAAA,GACA,4DAAA;AAAA,oBACJ,MAAA,IAAU;AAAA,mBACZ;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA,eAED;AAAA,8BACAA,GAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,QAAA;AAAA,kBACL,QAAA,EAAU,MAAA;AAAA,kBACV,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,kBAC3B,SAAA,EAAW,EAAA;AAAA,oBACT,4DAAA;AAAA,oBACA,UAAA,KAAe,OACX,gDAAA,GACA,4DAAA;AAAA,oBACJ,MAAA,IAAU;AAAA,mBACZ;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,SACF;AAAA,QACC,0BACCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4CAA2C,QAAA,EAAA,gBAAA,EAAc;AAAA;AAAA;AAAA,GAE7E;AAEJ;;;ACxJO,IAAM,OAAA,GAAU;AAChB,IAAM,OAAA,GAAU;AAChB,IAAM,UAAA,GAAa;AACnB,IAAM,MAAA,GAAS;AAAA,EACpB,OAAA,EAAS,SAAA;AAAA,EACT,MAAA,EAAQ,SAAA;AAAA,EACR,SAAA,EAAW;AACb","file":"index.mjs","sourcesContent":["export const CODEMIRROR_SINGLETON_DEPS = [\n '@codemirror/autocomplete',\n '@codemirror/commands',\n '@codemirror/lang-markdown',\n '@codemirror/language',\n '@codemirror/lint',\n '@codemirror/search',\n '@codemirror/state',\n '@codemirror/theme-one-dark',\n '@codemirror/view',\n '@lezer/common',\n '@lezer/highlight',\n '@lezer/lr',\n '@lezer/markdown',\n] as const;\n","import type { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface WidgetFrameProps {\n title: string;\n question: string;\n query: string;\n span?: string;\n children: ReactNode;\n}\n\nexport function WidgetFrame({ title, question, query, span, children }: WidgetFrameProps) {\n return (\n <div\n className={cn(\n 'bg-card border border-border rounded-lg p-4 flex flex-col min-h-0',\n span,\n )}\n >\n <div className=\"flex items-baseline justify-between gap-3 mb-1\">\n <h3 className=\"text-sm font-semibold text-foreground min-w-0\">\n {title}\n </h3>\n <span className=\"text-[11px] text-muted-foreground italic text-right max-w-[60%] line-clamp-2 shrink-0\">\n {question}\n </span>\n </div>\n {/* Long WQL wraps in place - an in-card horizontal scrollbar reads as\n a layout bug (dogfood #4). `break-all` covers spaceless fragments\n like `sum:totalVolume{effort:bench-press}`. */}\n <div className=\"font-mono text-[11px] text-primary/90 bg-background/60 rounded px-2 py-1 mb-3 whitespace-pre-wrap break-all\">\n {query}\n </div>\n <div className=\"flex-1 min-h-0\">{children}</div>\n </div>\n );\n}\n","import type { DashboardToken } from '@bitcobblers/wod-wiki-wql';\nimport { cn } from '../utils/cn';\n\nexport interface DashboardTokenControlsProps {\n tokens: DashboardToken[];\n /** Current value per token name (defaults applied by the caller). */\n values: Record<string, string>;\n /** Present when the note is editable — changes write back to frontmatter. */\n onChange?: (name: string, value: string) => void;\n}\n\n/**\n * DashboardTokenControls — the control row a dashboard note's frontmatter\n * tokens render as (#899): scalar tokens become inputs, list tokens segmented\n * controls (first entry = default). Read-only views (no onChange) render the\n * current values as static text.\n */\nexport function DashboardTokenControls({ tokens, values, onChange }: DashboardTokenControlsProps) {\n if (tokens.length === 0) return null;\n const readOnly = !onChange;\n\n return (\n <div\n data-testid=\"dashboard-token-controls\"\n className=\"flex flex-wrap items-center gap-x-5 gap-y-2 mb-4\"\n >\n {tokens.map((token) => {\n const current = values[token.name] ?? token.values[0];\n return (\n <div key={token.name} className=\"flex items-center gap-2\">\n <span className=\"font-mono text-[11px] text-muted-foreground\">${token.name}</span>\n {token.isList ? (\n <div className=\"inline-flex items-center gap-1 rounded-lg border border-border bg-card p-1\">\n {token.values.map((option) => (\n <button\n key={option}\n type=\"button\"\n disabled={readOnly}\n onClick={() => onChange?.(token.name, option)}\n className={cn(\n 'text-xs px-2.5 py-1 rounded-md transition-colors',\n option === current\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n readOnly && 'cursor-default',\n )}\n >\n {option}\n </button>\n ))}\n </div>\n ) : readOnly ? (\n <span className=\"text-xs text-foreground font-mono\">{current}</span>\n ) : (\n <input\n type=\"text\"\n value={current}\n onChange={(e) => onChange(token.name, e.target.value)}\n className=\"w-20 rounded-lg border border-border bg-card px-2 py-1 text-xs font-mono text-foreground focus:outline-none focus:border-primary\"\n />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { Edit3 } from 'lucide-react';\nimport { isFindQuery, parseQuery, type QueryResult, defaultTokenValues, isDashboardWidgetType, resolveWidgetType, substituteTokens, unknownTokensMessage, unknownWidgetTypeMessage, type DashboardDocument, type DashboardWidget } from '@bitcobblers/wod-wiki-wql';\nimport type { QueryExecutor } from '../contracts/query';\nimport { WidgetFrame } from './WidgetFrame';\nimport { WidgetChart, WidgetProblemBadge } from './WidgetChart';\nimport { DashboardTokenControls } from './DashboardTokenControls';\n\nexport interface DashboardViewProps {\n /** Parsed dashboard note (buildDashboardDocument). */\n document: DashboardDocument;\n /** Injected QueryExecutor for executing WQL queries. Zero singleton coupling. */\n executor?: QueryExecutor;\n /** Optional rollup fact warmer callback. */\n onEnsureRollupFacts?: () => Promise<void>;\n /** Current token values; defaults to each token's declared default. */\n tokenValues?: Record<string, string>;\n /** Present when the note is editable — control changes write back to frontmatter. */\n onTokenChange?: (name: string, value: string) => void;\n /** Present when the host offers query editing (composer modal owned by the host). */\n onEditQuery?: (widget: DashboardWidget) => void;\n /** Optional execution range (ms epoch). Omit to use each query's own window. */\n rangeStart?: number;\n rangeEnd?: number;\n preferredUnit?: string;\n}\n\ninterface WidgetRun {\n result?: QueryResult;\n error?: string;\n}\n\n/** Grid span classes for a widget on the 1 / 2 / 4-column responsive grid. */\nfunction spanClass(widget: DashboardWidget): string {\n const resolved = resolveWidgetType(widget.type);\n if (resolved === 'value') return 'col-span-1';\n if (resolved === 'table') return 'col-span-1 md:col-span-2';\n return 'col-span-1 md:col-span-2 lg:col-span-4';\n}\n\n/**\n * DashboardView — the state-free dashboard renderer (#900, format locked in #899).\n *\n * Takes a parsed DashboardDocument + current token values, runs all widget\n * queries concurrently via the injected QueryExecutor, and renders the responsive CSS grid.\n */\nexport function DashboardView({\n document,\n executor,\n onEnsureRollupFacts,\n tokenValues,\n onTokenChange,\n onEditQuery,\n rangeStart,\n rangeEnd,\n preferredUnit,\n}: DashboardViewProps) {\n const values = useMemo(\n () => ({ ...defaultTokenValues(document.tokens), ...tokenValues }),\n [document.tokens, tokenValues],\n );\n\n const resolved = useMemo(\n () =>\n document.widgets.map((widget) => {\n const { query, missing } = substituteTokens(widget.query, values);\n return { widget, query, missing };\n }),\n [document.widgets, values],\n );\n\n const [runs, setRuns] = useState<Record<string, WidgetRun>>({});\n const [loading, setLoading] = useState(true);\n\n const resolvedKey = useMemo(\n () => resolved.map((r) => `${r.widget.key}:${r.query}`).join('|'),\n [resolved],\n );\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n\n async function load() {\n const next: Record<string, WidgetRun> = {};\n const runnable: Array<{ widget: DashboardWidget; query: string }> = [];\n\n for (const { widget, query, missing } of resolved) {\n if (widget.type !== '' && !isDashboardWidgetType(widget.type)) {\n next[widget.key] = { error: unknownWidgetTypeMessage(widget.type) };\n continue;\n }\n if (missing.length > 0) {\n next[widget.key] = { error: unknownTokensMessage(missing) };\n continue;\n }\n const parsed = parseQuery(query);\n if (parsed.error) {\n next[widget.key] = { error: parsed.error };\n continue;\n }\n if (isFindQuery(parsed)) {\n next[widget.key] = { error: 'find: queries render inline in notes, not as dashboard widgets' };\n continue;\n }\n runnable.push({ widget, query });\n }\n\n if (!executor) {\n if (!cancelled) {\n setRuns(next);\n setLoading(false);\n }\n return;\n }\n\n const consumesRollups = runnable.some((r) => r.query.includes('calc.'));\n if (consumesRollups && onEnsureRollupFacts) {\n await onEnsureRollupFacts().catch(() => undefined);\n }\n\n await Promise.all(\n runnable.map(async ({ widget, query }) => {\n try {\n next[widget.key] = {\n result: await executor.runQuery(query, { rangeStart, rangeEnd, preferredUnit }),\n };\n } catch (err) {\n next[widget.key] = { error: err instanceof Error ? err.message : String(err) };\n }\n }),\n );\n\n if (!cancelled) {\n setRuns(next);\n setLoading(false);\n }\n }\n\n void load();\n return () => {\n cancelled = true;\n };\n }, [resolvedKey, executor, onEnsureRollupFacts, rangeStart, rangeEnd, preferredUnit]);\n\n return (\n <div data-testid=\"dashboard-view\">\n <DashboardTokenControls tokens={document.tokens} values={values} onChange={onTokenChange} />\n\n {loading && <div className=\"text-sm text-muted-foreground mb-3\">Loading widgets…</div>}\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n {resolved.map(({ widget, query }) => {\n const run = runs[widget.key];\n return (\n <WidgetFrame\n key={widget.key}\n title={widget.title ?? ''}\n question={widget.question ?? ''}\n query={query}\n span={spanClass(widget)}\n >\n <div className=\"relative group/card h-full min-h-[160px]\">\n {onEditQuery && (\n <button\n type=\"button\"\n onClick={() => onEditQuery(widget)}\n title=\"Edit widget query\"\n aria-label={`Edit query for ${widget.title ?? 'widget'}`}\n className=\"absolute top-0 right-0 p-1 rounded bg-muted/80 text-muted-foreground hover:text-foreground opacity-0 group-hover/card:opacity-100 transition-opacity z-10\"\n >\n <Edit3 className=\"w-3.5 h-3.5\" />\n </button>\n )}\n {run?.error ? (\n <WidgetProblemBadge message={run.error} />\n ) : (\n <WidgetChart\n type={widget.type}\n result={run?.result}\n label={widget.title}\n unit={preferredUnit}\n params={widget.params}\n />\n )}\n </div>\n </WidgetFrame>\n );\n })}\n </div>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '../utils/cn';\n\nexport type AnalyticsRangeWeeks = 4 | 8 | 16;\n\nexport interface RangeSelectorProps {\n weeks?: number;\n onWeeksChange?: (weeks: number) => void;\n className?: string;\n}\n\nexport function RangeSelector({ weeks: weeksProp, onWeeksChange, className }: RangeSelectorProps) {\n const [internalWeeks, setInternalWeeks] = useState<number>(16);\n const currentWeeks = weeksProp ?? internalWeeks;\n\n const handleSelect = (w: number) => {\n if (onWeeksChange) {\n onWeeksChange(w);\n } else {\n setInternalWeeks(w);\n }\n };\n\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg border border-border bg-card p-1', className)}>\n {[4, 8, 16].map((w) => (\n <button\n key={w}\n type=\"button\"\n onClick={() => handleSelect(w)}\n className={cn(\n 'text-xs px-2.5 py-1 rounded-md transition-colors',\n currentWeeks === w\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n )}\n >\n {w}w\n </button>\n ))}\n </div>\n );\n}\n","import { useEffect, useState } from 'react';\nimport type { QueryResult } from '@bitcobblers/wod-wiki-wql';\nimport type { QueryExecutor } from '../contracts/query';\n\nconst DAY = 86_400_000;\nconst WEEK = 7 * DAY;\n\nexport interface AnalyticsQueryDef {\n key: string;\n query: string;\n}\n\nexport interface AnalyticsQueriesState {\n results: Record<string, QueryResult>;\n loading: boolean;\n}\n\nexport function useAnalyticsQueries(\n queries: AnalyticsQueryDef[],\n weeks: number,\n executor?: QueryExecutor,\n refreshKey = 0,\n preferredUnit?: string,\n onEnsureRollupFacts?: () => Promise<void>,\n): AnalyticsQueriesState {\n const [results, setResults] = useState<Record<string, QueryResult>>({});\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n\n async function load() {\n if (!executor) {\n if (!cancelled) setLoading(false);\n return;\n }\n\n const now = Date.now();\n const rangeStart = now - weeks * WEEK;\n const consumesRollups = queries.some((q) => q.query.includes('calc.'));\n try {\n if (consumesRollups && onEnsureRollupFacts) {\n await onEnsureRollupFacts().catch(() => undefined);\n }\n const settled = await Promise.all(\n queries.map(async (q) => [\n q.key,\n await executor.runQuery(q.query, { rangeStart, rangeEnd: now, preferredUnit }),\n ] as const),\n );\n if (!cancelled) setResults(Object.fromEntries(settled));\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n void load();\n\n return () => {\n cancelled = true;\n };\n }, [queries, weeks, executor, refreshKey, preferredUnit, onEnsureRollupFacts]);\n\n return { results, loading };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { cn } from '../utils/cn';\nimport { parseQuery } from '@bitcobblers/wod-wiki-wql';\nimport type { AnalyticsQueryDef } from './useAnalyticsQueries';\nimport type { StorageLike } from '../contracts/storage';\n\nexport const ANALYTICS_UNIT_STORAGE_KEY = 'wod.analytics.unit';\nexport const DEFAULT_ANALYTICS_UNIT = 'kg';\nexport type AnalyticsUnit = 'kg' | 'lb';\n\nconst VALID_UNITS: readonly AnalyticsUnit[] = ['kg', 'lb'];\n\nconst memoryStore = new Map<string, string>();\nconst inMemoryStorage: StorageLike = {\n getItem: (key: string) => memoryStore.get(key) ?? null,\n setItem: (key: string, value: string) => {\n memoryStore.set(key, value);\n },\n removeItem: (key: string) => {\n memoryStore.delete(key);\n },\n};\n\nconst unitListeners = new Set<() => void>();\nfunction notifyUnitChange() {\n for (const l of unitListeners) l();\n}\n\nfunction resolveStorage(custom?: StorageLike): StorageLike {\n return custom ?? inMemoryStorage;\n}\n\nexport function readStoredUnit(storage?: StorageLike): AnalyticsUnit {\n const store = resolveStorage(storage);\n const stored = store.getItem(ANALYTICS_UNIT_STORAGE_KEY);\n return (VALID_UNITS as readonly string[]).includes(stored ?? '')\n ? (stored as AnalyticsUnit)\n : DEFAULT_ANALYTICS_UNIT;\n}\n\nexport function useAnalyticsUnitPreference(customStorage?: StorageLike) {\n const storage = resolveStorage(customStorage);\n const [unit, setUnitState] = useState<AnalyticsUnit>(() => readStoredUnit(storage));\n\n useEffect(() => {\n setUnitState(readStoredUnit(storage));\n const sync = () => setUnitState(readStoredUnit(storage));\n unitListeners.add(sync);\n return () => {\n unitListeners.delete(sync);\n };\n }, [storage]);\n\n const setUnit = useCallback(\n (next: AnalyticsUnit) => {\n storage.setItem(ANALYTICS_UNIT_STORAGE_KEY, next);\n setUnitState(next);\n notifyUnitChange();\n },\n [storage],\n );\n\n const toggleUnit = useCallback(() => {\n const next: AnalyticsUnit = unit === 'kg' ? 'lb' : 'kg';\n setUnit(next);\n }, [unit, setUnit]);\n\n return { unit, setUnit, toggleUnit };\n}\n\nexport function getEffectiveAnalyticsUnit(\n query: string,\n preferredUnit: AnalyticsUnit,\n): { unit: AnalyticsUnit; forced: boolean } {\n const parsed = parseQuery(query);\n const displayUnit = 'displayUnit' in parsed ? (parsed as any).displayUnit : undefined;\n if (displayUnit === 'lb' || displayUnit === 'kg') {\n return { unit: displayUnit as AnalyticsUnit, forced: true };\n }\n return { unit: preferredUnit, forced: false };\n}\n\nexport function getDashboardEffectiveUnit(\n queries: AnalyticsQueryDef[],\n preferredUnit: AnalyticsUnit,\n): { unit: AnalyticsUnit; forced: boolean } {\n const units = queries\n .map((q) => {\n const parsed = parseQuery(q.query);\n return 'displayUnit' in parsed ? (parsed as any).displayUnit : undefined;\n })\n .filter((u): u is string => u === 'kg' || u === 'lb');\n\n const unique = Array.from(new Set(units));\n if (unique.length === 1) {\n return { unit: unique[0] as AnalyticsUnit, forced: true };\n }\n return { unit: preferredUnit, forced: false };\n}\nexport interface AnalyticsUnitPreferenceProps {\n className?: string;\n unit?: AnalyticsUnit;\n forced?: boolean;\n storage?: StorageLike;\n}\n\nexport function AnalyticsUnitPreference({ className, unit: unitProp, forced = false, storage }: AnalyticsUnitPreferenceProps) {\n const { unit: storedUnit, setUnit } = useAnalyticsUnitPreference(storage);\n const activeUnit = unitProp ?? storedUnit;\n\n return (\n <div\n data-testid=\"analytics-unit-preference\"\n className={cn('inline-flex items-center gap-1 text-xs', className)}\n >\n <div\n className={cn(\n 'inline-flex items-center rounded-lg border border-border bg-card p-1',\n forced && 'opacity-70',\n )}\n title={forced ? 'Unit forced by query directive in this view' : 'Display unit preference'}\n >\n <button\n type=\"button\"\n disabled={forced}\n onClick={() => setUnit('kg')}\n className={cn(\n 'px-2.5 py-1 rounded-md transition-colors text-xs font-mono',\n activeUnit === 'kg'\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n forced && 'cursor-default hover:bg-transparent hover:text-muted-foreground',\n )}\n >\n kg\n </button>\n <button\n type=\"button\"\n disabled={forced}\n onClick={() => setUnit('lb')}\n className={cn(\n 'px-2.5 py-1 rounded-md transition-colors text-xs font-mono',\n activeUnit === 'lb'\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n forced && 'cursor-default hover:bg-transparent hover:text-muted-foreground',\n )}\n >\n lb\n </button>\n </div>\n {forced && (\n <span className=\"text-[11px] text-muted-foreground italic\">forced by note</span>\n )}\n </div>\n );\n}\n","/**\n * Auto-generated build version metadata.\n * Do not edit directly; updated by scripts/stamp-version.ts\n */\nexport const VERSION = '0.10.42';\nexport const GIT_SHA = '79c6d18';\nexport const BUILD_TIME = '2026-08-26T04:44:54.356Z';\nexport const SEMVER = {\n version: '0.10.42',\n gitSha: '79c6d18',\n buildTime: '2026-08-26T04:44:54.356Z',\n} as const;\n"]}
1
+ {"version":3,"sources":["../src/contracts/dedupe.ts","../src/widgets/WidgetFrame.tsx","../src/widgets/DashboardTokenControls.tsx","../src/widgets/DashboardView.tsx","../src/widgets/RangeSelector.tsx","../src/widgets/useAnalyticsQueries.ts","../src/widgets/useAnalyticsUnitPreference.tsx","../src/version.ts"],"names":["jsx","jsxs","useState","useEffect","parseQuery"],"mappings":";;;;;;;;AAAO,IAAM,yBAAA,GAA4B;AAAA,EACvC,0BAAA;AAAA,EACA,sBAAA;AAAA,EACA,2BAAA;AAAA,EACA,sBAAA;AAAA,EACA,kBAAA;AAAA,EACA,oBAAA;AAAA,EACA,mBAAA;AAAA,EACA,4BAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF;ACHO,SAAS,YAAY,EAAE,KAAA,EAAO,UAAU,KAAA,EAAO,IAAA,EAAM,UAAS,EAAqB;AACxF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,mEAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gDAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,+CAAA,EACX,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,0BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uFAAA,EACb,QAAA,EAAA,QAAA,EACH;AAAA,SAAA,EACF,CAAA;AAAA,wBAIA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6GAAA,EACZ,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EAAkB,QAAA,EAAS;AAAA;AAAA;AAAA,GAC5C;AAEJ;ACnBO,SAAS,sBAAA,CAAuB,EAAE,MAAA,EAAQ,MAAA,EAAQ,UAAS,EAAgC;AAChG,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,MAAM,WAAW,CAAC,QAAA;AAElB,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,0BAAA;AAAA,MACZ,SAAA,EAAU,kDAAA;AAAA,MAET,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACrB,QAAA,MAAM,UAAU,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,IAAK,KAAA,CAAM,OAAO,CAAC,CAAA;AACpD,QAAA,uBACEC,IAAAA,CAAC,KAAA,EAAA,EAAqB,SAAA,EAAU,yBAAA,EAC9B,QAAA,EAAA;AAAA,0BAAAA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6CAAA,EAA8C,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YAAE,KAAA,CAAM;AAAA,WAAA,EAAK,CAAA;AAAA,UAC1E,KAAA,CAAM,MAAA,mBACLD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4EAAA,EACZ,QAAA,EAAA,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,MAAA,qBACjBA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,QAAA;AAAA,cACL,QAAA,EAAU,QAAA;AAAA,cACV,OAAA,EAAS,MAAM,QAAA,GAAW,KAAA,CAAM,MAAM,MAAM,CAAA;AAAA,cAC5C,SAAA,EAAW,EAAA;AAAA,gBACT,kDAAA;AAAA,gBACA,MAAA,KAAW,UACP,gDAAA,GACA,4DAAA;AAAA,gBACJ,QAAA,IAAY;AAAA,eACd;AAAA,cAEC,QAAA,EAAA;AAAA,aAAA;AAAA,YAZI;AAAA,WAcR,CAAA,EACH,CAAA,GACE,QAAA,mBACFA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,QAAA,EAAA,OAAA,EAAQ,CAAA,mBAE7DA,GAAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,MAAA;AAAA,cACL,KAAA,EAAO,OAAA;AAAA,cACP,QAAA,EAAU,CAAC,CAAA,KAAM,QAAA,CAAS,MAAM,IAAA,EAAM,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,cACpD,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EAAA,EA9BM,MAAM,IAgChB,CAAA;AAAA,MAEJ,CAAC;AAAA;AAAA,GACH;AAEJ;ACjCA,SAAS,UAAU,MAAA,EAAiC;AAClD,EAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,MAAA,CAAO,IAAI,CAAA;AAC9C,EAAA,IAAI,QAAA,KAAa,SAAS,OAAO,YAAA;AACjC,EAAA,IAAI,QAAA,KAAa,SAAS,OAAO,0BAAA;AACjC,EAAA,OAAO,wCAAA;AACT;AAQO,SAAS,aAAA,CAAc;AAAA,EAC5B,QAAA;AAAA,EACA,QAAA;AAAA,EACA,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAuB;AACrB,EAAA,MAAM,MAAA,GAAS,OAAA;AAAA,IACb,OAAO,EAAE,GAAG,kBAAA,CAAmB,SAAS,MAAM,CAAA,EAAG,GAAG,WAAA,EAAY,CAAA;AAAA,IAChE,CAAC,QAAA,CAAS,MAAA,EAAQ,WAAW;AAAA,GAC/B;AAEA,EAAA,MAAM,QAAA,GAAW,OAAA;AAAA,IACf,MACE,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AAC/B,MAAA,MAAM,EAAE,KAAA,EAAO,OAAA,KAAY,gBAAA,CAAiB,MAAA,CAAO,OAAO,MAAM,CAAA;AAChE,MAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAQ;AAAA,IAClC,CAAC,CAAA;AAAA,IACH,CAAC,QAAA,CAAS,OAAA,EAAS,MAAM;AAAA,GAC3B;AAEA,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAoC,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,WAAA,GAAc,OAAA;AAAA,IAClB,MAAM,QAAA,CAAS,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,MAAA,CAAO,GAAG,IAAI,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IAChE,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AAEf,IAAA,eAAe,IAAA,GAAO;AACpB,MAAA,MAAM,OAAkC,EAAC;AACzC,MAAA,MAAM,WAA8D,EAAC;AAErE,MAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,MAAa,QAAA,EAAU;AACjD,QAAA,IAAI,OAAO,IAAA,KAAS,EAAA,IAAM,CAAC,qBAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AAC7D,UAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,OAAO,wBAAA,CAAyB,MAAA,CAAO,IAAI,CAAA,EAAE;AAClE,UAAA;AAAA,QACF;AACA,QAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,UAAA,IAAA,CAAK,OAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,oBAAA,CAAqB,OAAO,CAAA,EAAE;AAC1D,UAAA;AAAA,QACF;AACA,QAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,IAAA,CAAK,OAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,OAAO,KAAA,EAAM;AACzC,UAAA;AAAA,QACF;AACA,QAAA,IAAI,WAAA,CAAY,MAAM,CAAA,EAAG;AACvB,UAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,OAAO,gEAAA,EAAiE;AAC7F,UAAA;AAAA,QACF;AACA,QAAA,QAAA,CAAS,IAAA,CAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAAA,MACjC;AAEA,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,IAAI,CAAC,SAAA,EAAW;AACd,UAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,UAAA,UAAA,CAAW,KAAK,CAAA;AAAA,QAClB;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,eAAA,GAAkB,SAAS,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,QAAA,CAAS,OAAO,CAAC,CAAA;AACtE,MAAA,IAAI,mBAAmB,mBAAA,EAAqB;AAC1C,QAAA,MAAM,mBAAA,EAAoB,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,QACZ,SAAS,GAAA,CAAI,OAAO,EAAE,MAAA,EAAQ,OAAM,KAAM;AACxC,UAAA,IAAI;AACF,YAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI;AAAA,cACjB,MAAA,EAAQ,MAAM,QAAA,CAAS,QAAA,CAAS,OAAO,EAAE,UAAA,EAAY,QAAA,EAAU,aAAA,EAAe;AAAA,aAChF;AAAA,UACF,SAAS,GAAA,EAAK;AACZ,YAAA,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAA,EAAE;AAAA,UAC/E;AAAA,QACF,CAAC;AAAA,OACH;AAEA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF;AAEA,IAAA,KAAK,IAAA,EAAK;AACV,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,WAAA,EAAa,QAAA,EAAU,qBAAqB,UAAA,EAAY,QAAA,EAAU,aAAa,CAAC,CAAA;AAEpF,EAAA,uBACEC,IAAAA,CAAC,KAAA,EAAA,EAAI,aAAA,EAAY,gBAAA,EACf,QAAA,EAAA;AAAA,oBAAAD,IAAC,sBAAA,EAAA,EAAuB,MAAA,EAAQ,SAAS,MAAA,EAAQ,MAAA,EAAgB,UAAU,aAAA,EAAe,CAAA;AAAA,IAEzF,2BAAWA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sCAAqC,QAAA,EAAA,uBAAA,EAAgB,CAAA;AAAA,oBAEhFA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACZ,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,EAAE,MAAA,EAAQ,KAAA,EAAM,KAAM;AACnC,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAC3B,MAAA,uBACEA,GAAAA;AAAA,QAAC,WAAA;AAAA,QAAA;AAAA,UAEC,KAAA,EAAO,OAAO,KAAA,IAAS,EAAA;AAAA,UACvB,QAAA,EAAU,OAAO,QAAA,IAAY,EAAA;AAAA,UAC7B,KAAA;AAAA,UACA,IAAA,EAAM,UAAU,MAAM,CAAA;AAAA,UAEtB,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0CAAA,EACZ,QAAA,EAAA;AAAA,YAAA,WAAA,oBACCD,GAAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,MAAM,WAAA,CAAY,MAAM,CAAA;AAAA,gBACjC,KAAA,EAAM,mBAAA;AAAA,gBACN,YAAA,EAAY,CAAA,eAAA,EAAkB,MAAA,CAAO,KAAA,IAAS,QAAQ,CAAA,CAAA;AAAA,gBACtD,SAAA,EAAU,2JAAA;AAAA,gBAEV,QAAA,kBAAAA,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,aAAA,EAAc;AAAA;AAAA,aACjC;AAAA,YAED,GAAA,EAAK,wBACJA,GAAAA,CAAC,sBAAmB,OAAA,EAAS,GAAA,CAAI,KAAA,EAAO,CAAA,mBAExCA,GAAAA;AAAA,cAAC,WAAA;AAAA,cAAA;AAAA,gBACC,MAAM,MAAA,CAAO,IAAA;AAAA,gBACb,QAAQ,GAAA,EAAK,MAAA;AAAA,gBACb,OAAO,MAAA,CAAO,KAAA;AAAA,gBACd,IAAA,EAAM,aAAA;AAAA,gBACN,QAAQ,MAAA,CAAO;AAAA;AAAA;AACjB,WAAA,EAEJ;AAAA,SAAA;AAAA,QA7BK,MAAA,CAAO;AAAA,OA8Bd;AAAA,IAEJ,CAAC,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ;ACrLO,SAAS,cAAc,EAAE,KAAA,EAAO,SAAA,EAAW,aAAA,EAAe,WAAU,EAAuB;AAChG,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIE,SAAiB,EAAE,CAAA;AAC7D,EAAA,MAAM,eAAe,SAAA,IAAa,aAAA;AAElC,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAc;AAClC,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,aAAA,CAAc,CAAC,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,gBAAA,CAAiB,CAAC,CAAA;AAAA,IACpB;AAAA,EACF,CAAA;AAEA,EAAA,uBACEF,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,8EAA8E,SAAS,CAAA,EACvG,QAAA,EAAA,CAAC,CAAA,EAAG,GAAG,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,sBACfC,IAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MAEC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAS,MAAM,YAAA,CAAa,CAAC,CAAA;AAAA,MAC7B,SAAA,EAAW,EAAA;AAAA,QACT,kDAAA;AAAA,QACA,YAAA,KAAiB,IACb,gDAAA,GACA;AAAA,OACN;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,CAAA;AAAA,QAAE;AAAA;AAAA,KAAA;AAAA,IAVE;AAAA,GAYR,CAAA,EACH,CAAA;AAEJ;ACtCA,IAAM,GAAA,GAAM,KAAA;AACZ,IAAM,OAAO,CAAA,GAAI,GAAA;AAYV,SAAS,oBACd,OAAA,EACA,KAAA,EACA,UACA,UAAA,GAAa,CAAA,EACb,eACA,mBAAA,EACuB;AACvB,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIC,QAAAA,CAAsC,EAAE,CAAA;AACtE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAE3C,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,IAAA,eAAe,IAAA,GAAO;AACpB,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAChC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,UAAA,GAAa,MAAM,KAAA,GAAQ,IAAA;AACjC,MAAA,MAAM,eAAA,GAAkB,QAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,QAAA,CAAS,OAAO,CAAC,CAAA;AACrE,MAAA,IAAI;AACF,QAAA,IAAI,mBAAmB,mBAAA,EAAqB;AAC1C,UAAA,MAAM,mBAAA,EAAoB,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AAAA,QACnD;AACA,QAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA;AAAA,UAC5B,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,KAAM;AAAA,YACvB,CAAA,CAAE,GAAA;AAAA,YACF,MAAM,QAAA,CAAS,QAAA,CAAS,CAAA,CAAE,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAU,GAAA,EAAK,aAAA,EAAe;AAAA,WACrE;AAAA,SACZ;AACA,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,MAAA,CAAO,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,MACxD,CAAA,SAAE;AACA,QAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,KAAK,IAAA,EAAK;AAEV,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,KAAA,EAAO,UAAU,UAAA,EAAY,aAAA,EAAe,mBAAmB,CAAC,CAAA;AAE7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B;AC1DO,IAAM,0BAAA,GAA6B;AACnC,IAAM,sBAAA,GAAyB;AAGtC,IAAM,WAAA,GAAwC,CAAC,IAAA,EAAM,IAAI,CAAA;AAEzD,IAAM,WAAA,uBAAkB,GAAA,EAAoB;AAC5C,IAAM,eAAA,GAA+B;AAAA,EACnC,SAAS,CAAC,GAAA,KAAgB,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,EAClD,OAAA,EAAS,CAAC,GAAA,EAAa,KAAA,KAAkB;AACvC,IAAA,WAAA,CAAY,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,EAC5B,CAAA;AAAA,EACA,UAAA,EAAY,CAAC,GAAA,KAAgB;AAC3B,IAAA,WAAA,CAAY,OAAO,GAAG,CAAA;AAAA,EACxB;AACF,CAAA;AAEA,IAAM,aAAA,uBAAoB,GAAA,EAAgB;AAC1C,SAAS,gBAAA,GAAmB;AAC1B,EAAA,KAAA,MAAW,CAAA,IAAK,eAAe,CAAA,EAAE;AACnC;AAEA,SAAS,eAAe,MAAA,EAAmC;AACzD,EAAA,OAAO,MAAA,IAAU,eAAA;AACnB;AAEO,SAAS,eAAe,OAAA,EAAsC;AACnE,EAAA,MAAM,KAAA,GAAQ,eAAe,OAAO,CAAA;AACpC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,0BAA0B,CAAA;AACvD,EAAA,OAAQ,WAAA,CAAkC,QAAA,CAAS,MAAA,IAAU,EAAE,IAC1D,MAAA,GACD,sBAAA;AACN;AAEO,SAAS,2BAA2B,aAAA,EAA6B;AACtE,EAAA,MAAM,OAAA,GAAU,eAAe,aAAa,CAAA;AAC5C,EAAA,MAAM,CAAC,MAAM,YAAY,CAAA,GAAID,SAAwB,MAAM,cAAA,CAAe,OAAO,CAAC,CAAA;AAElF,EAAAC,UAAU,MAAM;AACd,IAAA,YAAA,CAAa,cAAA,CAAe,OAAO,CAAC,CAAA;AACpC,IAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,cAAA,CAAe,OAAO,CAAC,CAAA;AACvD,IAAA,aAAA,CAAc,IAAI,IAAI,CAAA;AACtB,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,OAAO,IAAI,CAAA;AAAA,IAC3B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,CAAC,IAAA,KAAwB;AACvB,MAAA,OAAA,CAAQ,OAAA,CAAQ,4BAA4B,IAAI,CAAA;AAChD,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,gBAAA,EAAiB;AAAA,IACnB,CAAA;AAAA,IACA,CAAC,OAAO;AAAA,GACV;AAEA,EAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,MAAM,IAAA,GAAsB,IAAA,KAAS,IAAA,GAAO,IAAA,GAAO,IAAA;AACnD,IAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,EACd,CAAA,EAAG,CAAC,IAAA,EAAM,OAAO,CAAC,CAAA;AAElB,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,UAAA,EAAW;AACrC;AAEO,SAAS,yBAAA,CACd,OACA,aAAA,EAC0C;AAC1C,EAAA,MAAM,MAAA,GAASC,WAAW,KAAK,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,aAAA,IAAiB,MAAA,GAAU,MAAA,CAAe,WAAA,GAAc,MAAA;AAC5E,EAAA,IAAI,WAAA,KAAgB,IAAA,IAAQ,WAAA,KAAgB,IAAA,EAAM;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAA8B,MAAA,EAAQ,IAAA,EAAK;AAAA,EAC5D;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,MAAA,EAAQ,KAAA,EAAM;AAC9C;AAEO,SAAS,yBAAA,CACd,SACA,aAAA,EAC0C;AAC1C,EAAA,MAAM,KAAA,GAAQ,OAAA,CACX,GAAA,CAAI,CAAC,CAAA,KAAM;AACV,IAAA,MAAM,MAAA,GAASA,UAAAA,CAAW,CAAA,CAAE,KAAK,CAAA;AACjC,IAAA,OAAO,aAAA,IAAiB,MAAA,GAAU,MAAA,CAAe,WAAA,GAAc,MAAA;AAAA,EACjE,CAAC,EACA,MAAA,CAAO,CAAC,MAAmB,CAAA,KAAM,IAAA,IAAQ,MAAM,IAAI,CAAA;AAEtD,EAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AACxC,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,CAAC,CAAA,EAAoB,QAAQ,IAAA,EAAK;AAAA,EAC1D;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,aAAA,EAAe,MAAA,EAAQ,KAAA,EAAM;AAC9C;AAQO,SAAS,uBAAA,CAAwB,EAAE,SAAA,EAAW,IAAA,EAAM,UAAU,MAAA,GAAS,KAAA,EAAO,SAAQ,EAAiC;AAC5H,EAAA,MAAM,EAAE,IAAA,EAAM,UAAA,EAAY,OAAA,EAAQ,GAAI,2BAA2B,OAAO,CAAA;AACxE,EAAA,MAAM,aAAa,QAAA,IAAY,UAAA;AAE/B,EAAA,uBACEH,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,2BAAA;AAAA,MACZ,SAAA,EAAW,EAAA,CAAG,wCAAA,EAA0C,SAAS,CAAA;AAAA,MAEjE,QAAA,EAAA;AAAA,wBAAAA,IAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,sEAAA;AAAA,cACA,MAAA,IAAU;AAAA,aACZ;AAAA,YACA,KAAA,EAAO,SAAS,6CAAA,GAAgD,yBAAA;AAAA,YAEhE,QAAA,EAAA;AAAA,8BAAAD,GAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,QAAA;AAAA,kBACL,QAAA,EAAU,MAAA;AAAA,kBACV,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,kBAC3B,SAAA,EAAW,EAAA;AAAA,oBACT,4DAAA;AAAA,oBACA,UAAA,KAAe,OACX,gDAAA,GACA,4DAAA;AAAA,oBACJ,MAAA,IAAU;AAAA,mBACZ;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA,eAED;AAAA,8BACAA,GAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,QAAA;AAAA,kBACL,QAAA,EAAU,MAAA;AAAA,kBACV,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AAAA,kBAC3B,SAAA,EAAW,EAAA;AAAA,oBACT,4DAAA;AAAA,oBACA,UAAA,KAAe,OACX,gDAAA,GACA,4DAAA;AAAA,oBACJ,MAAA,IAAU;AAAA,mBACZ;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,SACF;AAAA,QACC,0BACCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4CAA2C,QAAA,EAAA,gBAAA,EAAc;AAAA;AAAA;AAAA,GAE7E;AAEJ;;;ACxJO,IAAM,OAAA,GAAU;AAChB,IAAM,OAAA,GAAU;AAChB,IAAM,UAAA,GAAa;AACnB,IAAM,MAAA,GAAS;AAAA,EACpB,OAAA,EAAS,SAAA;AAAA,EACT,MAAA,EAAQ,SAAA;AAAA,EACR,SAAA,EAAW;AACb","file":"index.mjs","sourcesContent":["export const CODEMIRROR_SINGLETON_DEPS = [\n '@codemirror/autocomplete',\n '@codemirror/commands',\n '@codemirror/lang-markdown',\n '@codemirror/language',\n '@codemirror/lint',\n '@codemirror/search',\n '@codemirror/state',\n '@codemirror/theme-one-dark',\n '@codemirror/view',\n '@lezer/common',\n '@lezer/highlight',\n '@lezer/lr',\n '@lezer/markdown',\n] as const;\n","import type { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface WidgetFrameProps {\n title: string;\n question: string;\n query: string;\n span?: string;\n children: ReactNode;\n}\n\nexport function WidgetFrame({ title, question, query, span, children }: WidgetFrameProps) {\n return (\n <div\n className={cn(\n 'bg-card border border-border rounded-lg p-4 flex flex-col min-h-0',\n span,\n )}\n >\n <div className=\"flex items-baseline justify-between gap-3 mb-1\">\n <h3 className=\"text-sm font-semibold text-foreground min-w-0\">\n {title}\n </h3>\n <span className=\"text-[11px] text-muted-foreground italic text-right max-w-[60%] line-clamp-2 shrink-0\">\n {question}\n </span>\n </div>\n {/* Long WQL wraps in place - an in-card horizontal scrollbar reads as\n a layout bug (dogfood #4). `break-all` covers spaceless fragments\n like `sum:totalVolume{effort:bench-press}`. */}\n <div className=\"font-mono text-[11px] text-primary/90 bg-background/60 rounded px-2 py-1 mb-3 whitespace-pre-wrap break-all\">\n {query}\n </div>\n <div className=\"flex-1 min-h-0\">{children}</div>\n </div>\n );\n}\n","import type { DashboardToken } from '@bitcobblers/wod-wiki-wql';\nimport { cn } from '../utils/cn';\n\nexport interface DashboardTokenControlsProps {\n tokens: DashboardToken[];\n /** Current value per token name (defaults applied by the caller). */\n values: Record<string, string>;\n /** Present when the note is editable — changes write back to frontmatter. */\n onChange?: (name: string, value: string) => void;\n}\n\n/**\n * DashboardTokenControls — the control row a dashboard note's frontmatter\n * tokens render as (#899): scalar tokens become inputs, list tokens segmented\n * controls (first entry = default). Read-only views (no onChange) render the\n * current values as static text.\n */\nexport function DashboardTokenControls({ tokens, values, onChange }: DashboardTokenControlsProps) {\n if (tokens.length === 0) return null;\n const readOnly = !onChange;\n\n return (\n <div\n data-testid=\"dashboard-token-controls\"\n className=\"flex flex-wrap items-center gap-x-5 gap-y-2 mb-4\"\n >\n {tokens.map((token) => {\n const current = values[token.name] ?? token.values[0];\n return (\n <div key={token.name} className=\"flex items-center gap-2\">\n <span className=\"font-mono text-[11px] text-muted-foreground\">${token.name}</span>\n {token.isList ? (\n <div className=\"inline-flex items-center gap-1 rounded-lg border border-border bg-card p-1\">\n {token.values.map((option) => (\n <button\n key={option}\n type=\"button\"\n disabled={readOnly}\n onClick={() => onChange?.(token.name, option)}\n className={cn(\n 'text-xs px-2.5 py-1 rounded-md transition-colors',\n option === current\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n readOnly && 'cursor-default',\n )}\n >\n {option}\n </button>\n ))}\n </div>\n ) : readOnly ? (\n <span className=\"text-xs text-foreground font-mono\">{current}</span>\n ) : (\n <input\n type=\"text\"\n value={current}\n onChange={(e) => onChange(token.name, e.target.value)}\n className=\"w-20 rounded-lg border border-border bg-card px-2 py-1 text-xs font-mono text-foreground focus:outline-none focus:border-primary\"\n />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { Edit3 } from 'lucide-react';\nimport { isFindQuery, parseQuery, type QueryResult, defaultTokenValues, isDashboardWidgetType, resolveWidgetType, substituteTokens, unknownTokensMessage, unknownWidgetTypeMessage, type DashboardDocument, type DashboardWidget } from '@bitcobblers/wod-wiki-wql';\nimport type { QueryExecutor } from '../contracts/query';\nimport { WidgetFrame } from './WidgetFrame';\nimport { WidgetChart, WidgetProblemBadge } from './WidgetChart';\nimport { DashboardTokenControls } from './DashboardTokenControls';\n\nexport interface DashboardViewProps {\n /** Parsed dashboard note (buildDashboardDocument). */\n document: DashboardDocument;\n /** Injected QueryExecutor for executing WQL queries. Zero singleton coupling. */\n executor?: QueryExecutor;\n /** Optional rollup fact warmer callback. */\n onEnsureRollupFacts?: () => Promise<void>;\n /** Current token values; defaults to each token's declared default. */\n tokenValues?: Record<string, string>;\n /** Present when the note is editable — control changes write back to frontmatter. */\n onTokenChange?: (name: string, value: string) => void;\n /** Present when the host offers query editing (composer modal owned by the host). */\n onEditQuery?: (widget: DashboardWidget) => void;\n /** Optional execution range (ms epoch). Omit to use each query's own window. */\n rangeStart?: number;\n rangeEnd?: number;\n preferredUnit?: string;\n}\n\ninterface WidgetRun {\n result?: QueryResult;\n error?: string;\n}\n\n/** Grid span classes for a widget on the 1 / 2 / 4-column responsive grid. */\nfunction spanClass(widget: DashboardWidget): string {\n const resolved = resolveWidgetType(widget.type);\n if (resolved === 'value') return 'col-span-1';\n if (resolved === 'table') return 'col-span-1 md:col-span-2';\n return 'col-span-1 md:col-span-2 lg:col-span-4';\n}\n\n/**\n * DashboardView — the state-free dashboard renderer (#900, format locked in #899).\n *\n * Takes a parsed DashboardDocument + current token values, runs all widget\n * queries concurrently via the injected QueryExecutor, and renders the responsive CSS grid.\n */\nexport function DashboardView({\n document,\n executor,\n onEnsureRollupFacts,\n tokenValues,\n onTokenChange,\n onEditQuery,\n rangeStart,\n rangeEnd,\n preferredUnit,\n}: DashboardViewProps) {\n const values = useMemo(\n () => ({ ...defaultTokenValues(document.tokens), ...tokenValues }),\n [document.tokens, tokenValues],\n );\n\n const resolved = useMemo(\n () =>\n document.widgets.map((widget) => {\n const { query, missing } = substituteTokens(widget.query, values);\n return { widget, query, missing };\n }),\n [document.widgets, values],\n );\n\n const [runs, setRuns] = useState<Record<string, WidgetRun>>({});\n const [loading, setLoading] = useState(true);\n\n const resolvedKey = useMemo(\n () => resolved.map((r) => `${r.widget.key}:${r.query}`).join('|'),\n [resolved],\n );\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n\n async function load() {\n const next: Record<string, WidgetRun> = {};\n const runnable: Array<{ widget: DashboardWidget; query: string }> = [];\n\n for (const { widget, query, missing } of resolved) {\n if (widget.type !== '' && !isDashboardWidgetType(widget.type)) {\n next[widget.key] = { error: unknownWidgetTypeMessage(widget.type) };\n continue;\n }\n if (missing.length > 0) {\n next[widget.key] = { error: unknownTokensMessage(missing) };\n continue;\n }\n const parsed = parseQuery(query);\n if (parsed.error) {\n next[widget.key] = { error: parsed.error };\n continue;\n }\n if (isFindQuery(parsed)) {\n next[widget.key] = { error: 'find: queries render inline in notes, not as dashboard widgets' };\n continue;\n }\n runnable.push({ widget, query });\n }\n\n if (!executor) {\n if (!cancelled) {\n setRuns(next);\n setLoading(false);\n }\n return;\n }\n\n const consumesRollups = runnable.some((r) => r.query.includes('calc.'));\n if (consumesRollups && onEnsureRollupFacts) {\n await onEnsureRollupFacts().catch(() => undefined);\n }\n\n await Promise.all(\n runnable.map(async ({ widget, query }) => {\n try {\n next[widget.key] = {\n result: await executor.runQuery(query, { rangeStart, rangeEnd, preferredUnit }),\n };\n } catch (err) {\n next[widget.key] = { error: err instanceof Error ? err.message : String(err) };\n }\n }),\n );\n\n if (!cancelled) {\n setRuns(next);\n setLoading(false);\n }\n }\n\n void load();\n return () => {\n cancelled = true;\n };\n }, [resolvedKey, executor, onEnsureRollupFacts, rangeStart, rangeEnd, preferredUnit]);\n\n return (\n <div data-testid=\"dashboard-view\">\n <DashboardTokenControls tokens={document.tokens} values={values} onChange={onTokenChange} />\n\n {loading && <div className=\"text-sm text-muted-foreground mb-3\">Loading widgets…</div>}\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n {resolved.map(({ widget, query }) => {\n const run = runs[widget.key];\n return (\n <WidgetFrame\n key={widget.key}\n title={widget.title ?? ''}\n question={widget.question ?? ''}\n query={query}\n span={spanClass(widget)}\n >\n <div className=\"relative group/card h-full min-h-[160px]\">\n {onEditQuery && (\n <button\n type=\"button\"\n onClick={() => onEditQuery(widget)}\n title=\"Edit widget query\"\n aria-label={`Edit query for ${widget.title ?? 'widget'}`}\n className=\"absolute top-0 right-0 p-1 rounded bg-muted/80 text-muted-foreground hover:text-foreground opacity-0 group-hover/card:opacity-100 transition-opacity z-10\"\n >\n <Edit3 className=\"w-3.5 h-3.5\" />\n </button>\n )}\n {run?.error ? (\n <WidgetProblemBadge message={run.error} />\n ) : (\n <WidgetChart\n type={widget.type}\n result={run?.result}\n label={widget.title}\n unit={preferredUnit}\n params={widget.params}\n />\n )}\n </div>\n </WidgetFrame>\n );\n })}\n </div>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { cn } from '../utils/cn';\n\nexport type AnalyticsRangeWeeks = 4 | 8 | 16;\n\nexport interface RangeSelectorProps {\n weeks?: number;\n onWeeksChange?: (weeks: number) => void;\n className?: string;\n}\n\nexport function RangeSelector({ weeks: weeksProp, onWeeksChange, className }: RangeSelectorProps) {\n const [internalWeeks, setInternalWeeks] = useState<number>(16);\n const currentWeeks = weeksProp ?? internalWeeks;\n\n const handleSelect = (w: number) => {\n if (onWeeksChange) {\n onWeeksChange(w);\n } else {\n setInternalWeeks(w);\n }\n };\n\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg border border-border bg-card p-1', className)}>\n {[4, 8, 16].map((w) => (\n <button\n key={w}\n type=\"button\"\n onClick={() => handleSelect(w)}\n className={cn(\n 'text-xs px-2.5 py-1 rounded-md transition-colors',\n currentWeeks === w\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n )}\n >\n {w}w\n </button>\n ))}\n </div>\n );\n}\n","import { useEffect, useState } from 'react';\nimport type { QueryResult } from '@bitcobblers/wod-wiki-wql';\nimport type { QueryExecutor } from '../contracts/query';\n\nconst DAY = 86_400_000;\nconst WEEK = 7 * DAY;\n\nexport interface AnalyticsQueryDef {\n key: string;\n query: string;\n}\n\nexport interface AnalyticsQueriesState {\n results: Record<string, QueryResult>;\n loading: boolean;\n}\n\nexport function useAnalyticsQueries(\n queries: AnalyticsQueryDef[],\n weeks: number,\n executor?: QueryExecutor,\n refreshKey = 0,\n preferredUnit?: string,\n onEnsureRollupFacts?: () => Promise<void>,\n): AnalyticsQueriesState {\n const [results, setResults] = useState<Record<string, QueryResult>>({});\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n\n async function load() {\n if (!executor) {\n if (!cancelled) setLoading(false);\n return;\n }\n\n const now = Date.now();\n const rangeStart = now - weeks * WEEK;\n const consumesRollups = queries.some((q) => q.query.includes('calc.'));\n try {\n if (consumesRollups && onEnsureRollupFacts) {\n await onEnsureRollupFacts().catch(() => undefined);\n }\n const settled = await Promise.all(\n queries.map(async (q) => [\n q.key,\n await executor.runQuery(q.query, { rangeStart, rangeEnd: now, preferredUnit }),\n ] as const),\n );\n if (!cancelled) setResults(Object.fromEntries(settled));\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n void load();\n\n return () => {\n cancelled = true;\n };\n }, [queries, weeks, executor, refreshKey, preferredUnit, onEnsureRollupFacts]);\n\n return { results, loading };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { cn } from '../utils/cn';\nimport { parseQuery } from '@bitcobblers/wod-wiki-wql';\nimport type { AnalyticsQueryDef } from './useAnalyticsQueries';\nimport type { StorageLike } from '../contracts/storage';\n\nexport const ANALYTICS_UNIT_STORAGE_KEY = 'wod.analytics.unit';\nexport const DEFAULT_ANALYTICS_UNIT = 'kg';\nexport type AnalyticsUnit = 'kg' | 'lb';\n\nconst VALID_UNITS: readonly AnalyticsUnit[] = ['kg', 'lb'];\n\nconst memoryStore = new Map<string, string>();\nconst inMemoryStorage: StorageLike = {\n getItem: (key: string) => memoryStore.get(key) ?? null,\n setItem: (key: string, value: string) => {\n memoryStore.set(key, value);\n },\n removeItem: (key: string) => {\n memoryStore.delete(key);\n },\n};\n\nconst unitListeners = new Set<() => void>();\nfunction notifyUnitChange() {\n for (const l of unitListeners) l();\n}\n\nfunction resolveStorage(custom?: StorageLike): StorageLike {\n return custom ?? inMemoryStorage;\n}\n\nexport function readStoredUnit(storage?: StorageLike): AnalyticsUnit {\n const store = resolveStorage(storage);\n const stored = store.getItem(ANALYTICS_UNIT_STORAGE_KEY);\n return (VALID_UNITS as readonly string[]).includes(stored ?? '')\n ? (stored as AnalyticsUnit)\n : DEFAULT_ANALYTICS_UNIT;\n}\n\nexport function useAnalyticsUnitPreference(customStorage?: StorageLike) {\n const storage = resolveStorage(customStorage);\n const [unit, setUnitState] = useState<AnalyticsUnit>(() => readStoredUnit(storage));\n\n useEffect(() => {\n setUnitState(readStoredUnit(storage));\n const sync = () => setUnitState(readStoredUnit(storage));\n unitListeners.add(sync);\n return () => {\n unitListeners.delete(sync);\n };\n }, [storage]);\n\n const setUnit = useCallback(\n (next: AnalyticsUnit) => {\n storage.setItem(ANALYTICS_UNIT_STORAGE_KEY, next);\n setUnitState(next);\n notifyUnitChange();\n },\n [storage],\n );\n\n const toggleUnit = useCallback(() => {\n const next: AnalyticsUnit = unit === 'kg' ? 'lb' : 'kg';\n setUnit(next);\n }, [unit, setUnit]);\n\n return { unit, setUnit, toggleUnit };\n}\n\nexport function getEffectiveAnalyticsUnit(\n query: string,\n preferredUnit: AnalyticsUnit,\n): { unit: AnalyticsUnit; forced: boolean } {\n const parsed = parseQuery(query);\n const displayUnit = 'displayUnit' in parsed ? (parsed as any).displayUnit : undefined;\n if (displayUnit === 'lb' || displayUnit === 'kg') {\n return { unit: displayUnit as AnalyticsUnit, forced: true };\n }\n return { unit: preferredUnit, forced: false };\n}\n\nexport function getDashboardEffectiveUnit(\n queries: AnalyticsQueryDef[],\n preferredUnit: AnalyticsUnit,\n): { unit: AnalyticsUnit; forced: boolean } {\n const units = queries\n .map((q) => {\n const parsed = parseQuery(q.query);\n return 'displayUnit' in parsed ? (parsed as any).displayUnit : undefined;\n })\n .filter((u): u is string => u === 'kg' || u === 'lb');\n\n const unique = Array.from(new Set(units));\n if (unique.length === 1) {\n return { unit: unique[0] as AnalyticsUnit, forced: true };\n }\n return { unit: preferredUnit, forced: false };\n}\nexport interface AnalyticsUnitPreferenceProps {\n className?: string;\n unit?: AnalyticsUnit;\n forced?: boolean;\n storage?: StorageLike;\n}\n\nexport function AnalyticsUnitPreference({ className, unit: unitProp, forced = false, storage }: AnalyticsUnitPreferenceProps) {\n const { unit: storedUnit, setUnit } = useAnalyticsUnitPreference(storage);\n const activeUnit = unitProp ?? storedUnit;\n\n return (\n <div\n data-testid=\"analytics-unit-preference\"\n className={cn('inline-flex items-center gap-1 text-xs', className)}\n >\n <div\n className={cn(\n 'inline-flex items-center rounded-lg border border-border bg-card p-1',\n forced && 'opacity-70',\n )}\n title={forced ? 'Unit forced by query directive in this view' : 'Display unit preference'}\n >\n <button\n type=\"button\"\n disabled={forced}\n onClick={() => setUnit('kg')}\n className={cn(\n 'px-2.5 py-1 rounded-md transition-colors text-xs font-mono',\n activeUnit === 'kg'\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n forced && 'cursor-default hover:bg-transparent hover:text-muted-foreground',\n )}\n >\n kg\n </button>\n <button\n type=\"button\"\n disabled={forced}\n onClick={() => setUnit('lb')}\n className={cn(\n 'px-2.5 py-1 rounded-md transition-colors text-xs font-mono',\n activeUnit === 'lb'\n ? 'bg-primary text-primary-foreground font-medium'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted',\n forced && 'cursor-default hover:bg-transparent hover:text-muted-foreground',\n )}\n >\n lb\n </button>\n </div>\n {forced && (\n <span className=\"text-[11px] text-muted-foreground italic\">forced by note</span>\n )}\n </div>\n );\n}\n","/**\n * Auto-generated build version metadata.\n * Do not edit directly; updated by scripts/stamp-version.ts\n */\nexport const VERSION = '0.11.43';\nexport const GIT_SHA = 'ed28149';\nexport const BUILD_TIME = '2026-08-26T16:34:15.927Z';\nexport const SEMVER = {\n version: '0.11.43',\n gitSha: 'ed28149',\n buildTime: '2026-08-26T16:34:15.927Z',\n} as const;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitcobblers/wod-wiki-ui",
3
- "version": "0.10.42",
3
+ "version": "0.11.43",
4
4
  "description": "Interactive presentation, CodeMirror editor extensions, and WQL diagram widgets",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,9 +27,9 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@bitcobblers/wod-wiki-core": "^0.10.42",
31
- "@bitcobblers/wod-wiki-lang": "^0.10.42",
32
- "@bitcobblers/wod-wiki-wql": "^0.10.42",
30
+ "@bitcobblers/wod-wiki-core": "^0.11.43",
31
+ "@bitcobblers/wod-wiki-lang": "^0.11.43",
32
+ "@bitcobblers/wod-wiki-wql": "^0.11.43",
33
33
  "clsx": "^2.1.1",
34
34
  "tailwind-merge": "^3.6.0",
35
35
  "@heroicons/react": "^2.2.0"