@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/{chunk-S77JRUQM.mjs → chunk-PZXX6GBK.mjs} +375 -343
- package/dist/chunk-PZXX6GBK.mjs.map +1 -0
- package/dist/extensions/index.cjs +371 -334
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.mjs +1 -1
- package/dist/index.cjs +377 -356
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -83
- package/dist/index.d.ts +20 -83
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-S77JRUQM.mjs.map +0 -1
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
|
-
*
|
|
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
|
|
452
|
-
|
|
453
|
-
/** Controlled
|
|
454
|
-
|
|
455
|
-
/** Fired whenever the
|
|
456
|
-
|
|
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
|
-
*
|
|
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({
|
|
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
|
|
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.
|
|
662
|
-
declare const GIT_SHA = "
|
|
663
|
-
declare const BUILD_TIME = "2026-08-
|
|
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.
|
|
666
|
-
readonly gitSha: "
|
|
667
|
-
readonly buildTime: "2026-08-
|
|
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,
|
|
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
|
-
*
|
|
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
|
|
452
|
-
|
|
453
|
-
/** Controlled
|
|
454
|
-
|
|
455
|
-
/** Fired whenever the
|
|
456
|
-
|
|
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
|
-
*
|
|
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({
|
|
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
|
|
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.
|
|
662
|
-
declare const GIT_SHA = "
|
|
663
|
-
declare const BUILD_TIME = "2026-08-
|
|
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.
|
|
666
|
-
readonly gitSha: "
|
|
667
|
-
readonly buildTime: "2026-08-
|
|
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,
|
|
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-
|
|
2
|
-
export { AGG_OPTIONS, AddCalcDropdown, AddFilterDropdown,
|
|
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.
|
|
409
|
-
var GIT_SHA = "
|
|
410
|
-
var BUILD_TIME = "2026-08-
|
|
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.
|
|
413
|
-
gitSha: "
|
|
414
|
-
buildTime: "2026-08-
|
|
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 };
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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","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":"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","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.
|
|
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.
|
|
31
|
-
"@bitcobblers/wod-wiki-lang": "^0.
|
|
32
|
-
"@bitcobblers/wod-wiki-wql": "^0.
|
|
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"
|