@xenosystem/blocks 0.13.10 → 0.13.11

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.
@@ -1,7 +1,7 @@
1
1
  import { PanelModule, PanelManifest, BlockDeclaration, LogSink } from '@xenosystem/block-sdk';
2
2
  import * as _xenosystem_data_core from '@xenosystem/data-core';
3
3
  import { XenoColumn, XenoQuery, XenoResultSet, XenoValue, XenoRow, XenoAggFn, XenoValueFormat, XenoFilterGroup, XenoColumnRole, XenoSchemaCatalog, XenoFilter, XenoSourceSchema } from '@xenosystem/data-core';
4
- import { ReactNode } from 'react';
4
+ import { ReactNode, ReactElement } from 'react';
5
5
  import { C as ConnectorExecuteInput, a as ConnectorExecuteOutput, b as ConnectorsPanelState, S as SubstrateFacilities, c as ConnectorsViewState, d as XenoConnection, e as XenoCredentialFormSpec, f as XenoCredentialResult, g as XenoConnectionStatus, P as PushdownSplit, h as XenoConnectorQueryRequest, i as XenoRestPaging, j as XenoConnectorFetch, k as XenoResolverErrorCode, l as XenoConnectorFileReader, X as XenoSqlEngine, m as ConnectorTransport, n as XenoCredentialField } from '../transport-B1cdciP8.js';
6
6
  export { B as BrowserFetchOptions, o as ConnectorTransportError, p as SECRET_HEADER_NAMES, q as XenoConnectionConfig, r as XenoConnectionHealth, s as XenoConnectionKind, t as XenoConnectionState, u as XenoConnectorCapabilities, v as XenoCredentialSubmission, w as XenoFetchRequest, x as XenoFetchResponse, y as XenoFileReadRequest, z as XenoFileReadResponse, A as XenoRefreshPolicy, D as XenoSqlTable, E as browserFetch, F as classifyBrowserFetchFailure, G as defaultCapabilitiesFor, H as errorResult, I as evaluateSupport, J as facilitiesOf, K as normalizePaging, L as secretHeaderNames } from '../transport-B1cdciP8.js';
7
7
 
@@ -1107,25 +1107,79 @@ declare function buildChartData(result: XenoResultSet, encoding: XenoChartEncodi
1107
1107
  declare function rowsForMark(result: XenoResultSet, encoding: XenoChartEncoding, label: string, seriesId?: string): string[];
1108
1108
 
1109
1109
  /**
1110
- * The Chart panel view.
1110
+ * The Chart panel AS A DECLARATION — the thirteenth declared block.
1111
1111
  *
1112
- * Composes `@xenosystem/components/chrome`; the host must ensure `@xenosystem/workbench/primitives.css` is
1113
- * present. The plot area delegates to the installed renderer (see `renderer.ts`) — this view owns
1114
- * the chrome and the states, not the marks.
1112
+ * Everything drawn is data: the chart-type control, the partial / aggregating badges and the export
1113
+ * button in the toolbar, the four body states (error, no data, nothing to plot, no renderer), the
1114
+ * status bar. The PLOT is the one thing a declaration cannot hold — `chart/Plot` is the runtime-bound
1115
+ * unit: the element the host's renderer (Chart.js or another) draws the marks into, re-rendered
1116
+ * from the controller's data and highlights. The panel ships the model; the host ships the marks.
1117
+ */
1118
+
1119
+ declare const CHART_TYPE_LABELS: Record<string, string>;
1120
+ declare const DEFAULT_CHART_OPTIONS: ChartRenderOptions;
1121
+ interface ChartViewModel {
1122
+ types: {
1123
+ value: string;
1124
+ label: string;
1125
+ }[];
1126
+ type: string;
1127
+ partial: boolean;
1128
+ aggregating: boolean;
1129
+ aggregatingHint?: string;
1130
+ errorMessage?: string;
1131
+ errored: boolean;
1132
+ empty: boolean;
1133
+ emptyHint: string;
1134
+ unplottable: boolean;
1135
+ encodingProblem?: string;
1136
+ noRenderer: boolean;
1137
+ plot: boolean;
1138
+ countLabel?: string;
1139
+ highlightLabel?: string;
1140
+ }
1141
+ type ChartUiIntent = {
1142
+ kind: 'type';
1143
+ type: XenoChartType;
1144
+ } | {
1145
+ kind: 'export';
1146
+ };
1147
+ interface ChartViewOptions {
1148
+ emptyHint?: string;
1149
+ }
1150
+ /** Derive the view from the live controller — the runtime calls this on every draw. */
1151
+ declare function chartViewState(c: ChartController, options?: ChartViewOptions): ChartViewModel;
1152
+ declare function applyChartUi(c: ChartController, intent: ChartUiIntent): void;
1153
+ declare const chartViewManifest: PanelManifest;
1154
+ declare const BEHAVIOURS$2: {
1155
+ 'data/chartPanelView': (inputs: Record<string, unknown>) => ChartViewModel;
1156
+ };
1157
+ /** The runtime-bound unit: the plot surface the host renderer draws into. */
1158
+ declare const CHART_RUNTIME_UNITS: readonly ["chart/Plot"];
1159
+ declare const CHART_DECLARATION: BlockDeclaration;
1160
+
1161
+ /**
1162
+ * The Chart panel view — the CODE VIEW of `CHART_DECLARATION`, drawing the same `ChartViewModel`
1163
+ * byte-identical (the equivalence suite holds the two together). The one thing this file owns that
1164
+ * the declaration cannot is `chart/Plot`: the element the host renderer draws the marks into.
1115
1165
  *
1116
- * **There is no shelf UI here.** The encoding editor is `xeno.core.fields` with chart shelves,
1117
- * wired as a sibling panel; building a second shelf UI is exactly what sequencing chart after fields
1118
- * was meant to avoid.
1166
+ * Composes `@xenosystem/components/chrome`; the host must ensure `@xenosystem/workbench/primitives.css` is
1167
+ * present.
1119
1168
  *
1120
1169
  * @module
1121
1170
  */
1122
1171
 
1123
1172
  /** Props for {@link ChartPanelView}. */
1124
- interface ChartPanelViewProps {
1173
+ interface ChartPanelViewProps extends ChartViewOptions {
1125
1174
  controller: ChartController;
1126
1175
  options?: Partial<ChartRenderOptions>;
1127
- emptyHint?: string;
1128
1176
  }
1177
+ /** `chart/Plot` — the plot surface. The runtime registers it bound to its controller and render options. */
1178
+ declare function ChartPlot({ controller, options }: {
1179
+ controller: ChartController;
1180
+ options?: Partial<ChartRenderOptions>;
1181
+ }): ReactElement;
1182
+ declare function chartRuntimeComponents(controller: ChartController, options?: Partial<ChartRenderOptions>): Record<(typeof CHART_RUNTIME_UNITS)[number], React.ComponentType<any>>;
1129
1183
  /** The Chart panel view. */
1130
1184
  declare function ChartPanelView({ controller, options, emptyHint }: ChartPanelViewProps): ReactNode;
1131
1185
 
@@ -3447,4 +3501,4 @@ interface ConnectorsPanelViewProps {
3447
3501
  /** The Connectors panel view. */
3448
3502
  declare function ConnectorsPanelView({ controller, emptyHint, }: ConnectorsPanelViewProps): ReactNode;
3449
3503
 
3450
- export { AGENT_HIDDEN_COMMANDS, ALL_AGGREGATES, ALL_CHART_TYPES, type BuildChartOptions, type BuildSelectOptions, type BuildSelectResult, CHART_EMPTY_FILL, CHART_PALETTE_STEPS, CHART_PANEL_ID, CONNECTORS_PANEL_ID, type CellAddress, ChartController, type ChartControllerOptions, type ChartHostBridge, type ChartPanelState, ChartPanelView, type ChartPanelViewProps, type ChartRenderContext, type ChartRenderInput, type ChartRenderOptions, type ChartRenderer, type ChartViewState, type ColumnLayout, type ColumnWindow, ConnectorExecuteInput, ConnectorExecuteOutput, ConnectorTransport, ConnectorsController, type ConnectorsControllerOptions, type ConnectorsHostBridge, ConnectorsPanelState, ConnectorsPanelView, type ConnectorsPanelViewProps, type ConnectorsRenderContext, ConnectorsViewState, type CreateChartPanelOptions, type CreateConnectorExecutorOptions, type CreateConnectorsPanelOptions, type CreateFieldsPanelOptions, type CreateMetricsPanelOptions, type CreateTablePanelOptions, type CredentialDraft, type CredentialErrors, DEFAULT_COLUMN_WIDTH, DEFAULT_PAGE_SIZE, DEFAULT_RANGES, type DeltaDirection, EMPTY_LAYOUT, EXPIRY_SKEW_MS, type ExecuteError, BEHAVIOURS as FIELDS_BEHAVIOURS, FIELDS_DECLARATION, FIELDS_PANEL_ID, FIELDS_RUNTIME_UNITS, FieldsController, type FieldsControllerOptions, type FieldsHostBridge, type FieldsPanelState, FieldsPanelView, type FieldsPanelViewProps, type FieldsRenderContext, type FieldsUiIntent, type FieldsViewColumn, type FieldsViewEntry, type FieldsViewFilter, type FieldsViewModel, type FieldsViewOptions, type FieldsViewShelf, type FieldsViewState, type HostSqlResolver, IMPLEMENTED_VIEW_MODES, type LoopbackRequest, type LoopbackVerdict, BEHAVIOURS$1 as METRICS_BEHAVIOURS, METRICS_DECLARATION, METRICS_PANEL_ID, METRICS_RUNTIME_UNITS, MIN_COLUMN_WIDTH, MONO_FILL_PALETTE, MONO_PALETTE, MetricsController, type MetricsControllerOptions, type MetricsHostBridge, type MetricsPanelState, MetricsPanelView, type MetricsPanelViewProps, type MetricsRenderContext, type MetricsUiIntent, type MetricsViewModel, type MetricsViewOptions, type MetricsViewState, type MetricsViewTile, type NumericConstraints, type OAuthStateRecord, type OAuthStateStore, type OAuthStateStoreOptions, type ParseCsvOptions, type ParseResult, type ParsedCsv, type PkcePair, PushdownSplit, type RefreshCoordinator, type ResolvedColumn, SHELF_PRESETS, type StoredOAuthToken, SubstrateFacilities, TABLE_PANEL_ID, TableController, type TableControllerOptions, type TableHostBridge, type TablePanelState, TablePanelView, type TablePanelViewProps, type TableRenderContext, type TableViewMode, type TableViewState, type TokenEndpointResponse, type VirtualWindow, type XenoAlertLevel, type XenoCalculatedFieldRequest, type XenoCellEdit, type XenoChartData, type XenoChartDrillDown, type XenoChartEncoding, type XenoChartExportRequest, type XenoChartHighlight, type XenoChartSeries, type XenoChartType, XenoConnection, XenoConnectionStatus, XenoConnectorFetch, XenoConnectorFileReader, XenoConnectorQueryRequest, XenoCredentialField, XenoCredentialFormSpec, XenoCredentialResult, type XenoFieldStat, type XenoMetricAlert, type XenoMetricRange, type XenoMetricSpec, type XenoMetricThreshold, type XenoMetricValue, XenoResolverErrorCode, XenoRestPaging, type XenoRowActivate, type XenoShelfEntry, type XenoShelfSpec, XenoSqlEngine, applyFieldsUi, applyMetricsUi, applyPrecision, base64Url, breachSideOf, buildChartData, buildRestUrl, buildSelect, chartManifest, chartPanel, clamp, classifyHttpStatus, coerceCsvValues, columnIndexAt, columnsOf, compileForHost, computeColumnWindow, computeWindow, connectorsManifest, connectorsPanel, constraintsOfColumn, createChartPanel, createConnectorExecutor, createConnectorsPanel, createFieldsPanel, createMetricsPanel, createOAuthStateStore, createPkcePair, createRefreshCoordinator, createTablePanel, credentialSpecProblem, defaultAggregateFor, defaultEncoding, deltaToneOf, emptyFilterGroup, entityOf, escapeLikePattern, executeCsvFile, executeDuckDb, executeGraphql, executeJsonFile, executeRest, executeSql, extractJsonPath, extractRows, fieldsManifest, fieldsPanel, fieldsViewManifest, fieldsViewState, firstGraphqlError, frozenWidth, getChartRenderer, isCategorical, isFieldVisible, isFilled, isLeafFilter, isLoopbackHost, isSafeTableName, mergeRefreshResponse, metricsManifest, metricsPanel, metricsViewManifest, metricsViewState, moveCell, moveColumn, needsRefresh, nextPageToken, normalizeLayout, normalizeNumeric, offerableAggregates, offerableFilterOps, parseCsv, parseJsonBody, parseJsonPath, parseLinkHeader, parseNumeric, pruneHiddenValues, queriesEqual, quoteIdent, quoteLiteral, redirectUriFor, renderFilterGroup, resolveChartColors, resolveColumns, rowsForMark, scrollLeftToReveal, scrollTopToReveal, setChartRenderer, setColumnVisible, setColumnWidth, setFrozenCount, sniffDelimiter, suggestedShelfFor, tableManifest, tablePanel, toChartJsConfig, toExecuteError, totalWidth, uniqueTableName, unsupportedMessage, validateCredentialDraft, validateEncoding, validateLoopbackRequest, visibleFields };
3504
+ export { AGENT_HIDDEN_COMMANDS, ALL_AGGREGATES, ALL_CHART_TYPES, type BuildChartOptions, type BuildSelectOptions, type BuildSelectResult, BEHAVIOURS$2 as CHART_BEHAVIOURS, CHART_DECLARATION, CHART_EMPTY_FILL, CHART_PALETTE_STEPS, CHART_PANEL_ID, CHART_RUNTIME_UNITS, CHART_TYPE_LABELS, CONNECTORS_PANEL_ID, type CellAddress, ChartController, type ChartControllerOptions, type ChartHostBridge, type ChartPanelState, ChartPanelView, type ChartPanelViewProps, ChartPlot, type ChartRenderContext, type ChartRenderInput, type ChartRenderOptions, type ChartRenderer, type ChartUiIntent, type ChartViewModel, type ChartViewOptions, type ChartViewState, type ColumnLayout, type ColumnWindow, ConnectorExecuteInput, ConnectorExecuteOutput, ConnectorTransport, ConnectorsController, type ConnectorsControllerOptions, type ConnectorsHostBridge, ConnectorsPanelState, ConnectorsPanelView, type ConnectorsPanelViewProps, type ConnectorsRenderContext, ConnectorsViewState, type CreateChartPanelOptions, type CreateConnectorExecutorOptions, type CreateConnectorsPanelOptions, type CreateFieldsPanelOptions, type CreateMetricsPanelOptions, type CreateTablePanelOptions, type CredentialDraft, type CredentialErrors, DEFAULT_CHART_OPTIONS, DEFAULT_COLUMN_WIDTH, DEFAULT_PAGE_SIZE, DEFAULT_RANGES, type DeltaDirection, EMPTY_LAYOUT, EXPIRY_SKEW_MS, type ExecuteError, BEHAVIOURS as FIELDS_BEHAVIOURS, FIELDS_DECLARATION, FIELDS_PANEL_ID, FIELDS_RUNTIME_UNITS, FieldsController, type FieldsControllerOptions, type FieldsHostBridge, type FieldsPanelState, FieldsPanelView, type FieldsPanelViewProps, type FieldsRenderContext, type FieldsUiIntent, type FieldsViewColumn, type FieldsViewEntry, type FieldsViewFilter, type FieldsViewModel, type FieldsViewOptions, type FieldsViewShelf, type FieldsViewState, type HostSqlResolver, IMPLEMENTED_VIEW_MODES, type LoopbackRequest, type LoopbackVerdict, BEHAVIOURS$1 as METRICS_BEHAVIOURS, METRICS_DECLARATION, METRICS_PANEL_ID, METRICS_RUNTIME_UNITS, MIN_COLUMN_WIDTH, MONO_FILL_PALETTE, MONO_PALETTE, MetricsController, type MetricsControllerOptions, type MetricsHostBridge, type MetricsPanelState, MetricsPanelView, type MetricsPanelViewProps, type MetricsRenderContext, type MetricsUiIntent, type MetricsViewModel, type MetricsViewOptions, type MetricsViewState, type MetricsViewTile, type NumericConstraints, type OAuthStateRecord, type OAuthStateStore, type OAuthStateStoreOptions, type ParseCsvOptions, type ParseResult, type ParsedCsv, type PkcePair, PushdownSplit, type RefreshCoordinator, type ResolvedColumn, SHELF_PRESETS, type StoredOAuthToken, SubstrateFacilities, TABLE_PANEL_ID, TableController, type TableControllerOptions, type TableHostBridge, type TablePanelState, TablePanelView, type TablePanelViewProps, type TableRenderContext, type TableViewMode, type TableViewState, type TokenEndpointResponse, type VirtualWindow, type XenoAlertLevel, type XenoCalculatedFieldRequest, type XenoCellEdit, type XenoChartData, type XenoChartDrillDown, type XenoChartEncoding, type XenoChartExportRequest, type XenoChartHighlight, type XenoChartSeries, type XenoChartType, XenoConnection, XenoConnectionStatus, XenoConnectorFetch, XenoConnectorFileReader, XenoConnectorQueryRequest, XenoCredentialField, XenoCredentialFormSpec, XenoCredentialResult, type XenoFieldStat, type XenoMetricAlert, type XenoMetricRange, type XenoMetricSpec, type XenoMetricThreshold, type XenoMetricValue, XenoResolverErrorCode, XenoRestPaging, type XenoRowActivate, type XenoShelfEntry, type XenoShelfSpec, XenoSqlEngine, applyChartUi, applyFieldsUi, applyMetricsUi, applyPrecision, base64Url, breachSideOf, buildChartData, buildRestUrl, buildSelect, chartManifest, chartPanel, chartRuntimeComponents, chartViewManifest, chartViewState, clamp, classifyHttpStatus, coerceCsvValues, columnIndexAt, columnsOf, compileForHost, computeColumnWindow, computeWindow, connectorsManifest, connectorsPanel, constraintsOfColumn, createChartPanel, createConnectorExecutor, createConnectorsPanel, createFieldsPanel, createMetricsPanel, createOAuthStateStore, createPkcePair, createRefreshCoordinator, createTablePanel, credentialSpecProblem, defaultAggregateFor, defaultEncoding, deltaToneOf, emptyFilterGroup, entityOf, escapeLikePattern, executeCsvFile, executeDuckDb, executeGraphql, executeJsonFile, executeRest, executeSql, extractJsonPath, extractRows, fieldsManifest, fieldsPanel, fieldsViewManifest, fieldsViewState, firstGraphqlError, frozenWidth, getChartRenderer, isCategorical, isFieldVisible, isFilled, isLeafFilter, isLoopbackHost, isSafeTableName, mergeRefreshResponse, metricsManifest, metricsPanel, metricsViewManifest, metricsViewState, moveCell, moveColumn, needsRefresh, nextPageToken, normalizeLayout, normalizeNumeric, offerableAggregates, offerableFilterOps, parseCsv, parseJsonBody, parseJsonPath, parseLinkHeader, parseNumeric, pruneHiddenValues, queriesEqual, quoteIdent, quoteLiteral, redirectUriFor, renderFilterGroup, resolveChartColors, resolveColumns, rowsForMark, scrollLeftToReveal, scrollTopToReveal, setChartRenderer, setColumnVisible, setColumnWidth, setFrozenCount, sniffDelimiter, suggestedShelfFor, tableManifest, tablePanel, toChartJsConfig, toExecuteError, totalWidth, uniqueTableName, unsupportedMessage, validateCredentialDraft, validateEncoding, validateLoopbackRequest, visibleFields };
@@ -11,7 +11,6 @@ import {
11
11
  } from "../chunk-W4PTX2Y4.js";
12
12
  import {
13
13
  ChevronGlyph,
14
- DownloadGlyph,
15
14
  PlugGlyph,
16
15
  RefreshGlyph,
17
16
  SortAscGlyph,
@@ -198,8 +197,8 @@ function moveCell(from, delta, bounds) {
198
197
  }
199
198
 
200
199
  // src/data/table/numeric.ts
201
- function parseNumeric(text3) {
202
- const trimmed = String(text3).trim();
200
+ function parseNumeric(text4) {
201
+ const trimmed = String(text4).trim();
203
202
  if (trimmed.length === 0) return { ok: false, reason: "empty" };
204
203
  const match = /^[+-]?(\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/.exec(trimmed);
205
204
  if (!match) return { ok: false, reason: "nan" };
@@ -553,11 +552,11 @@ var TableController = class {
553
552
  return true;
554
553
  }
555
554
  /** Update the in-flight draft. Emits `editPreview` only when `livePreview` is on. */
556
- updateDraft(text3) {
555
+ updateDraft(text4) {
557
556
  if (!this.editing) return;
558
- this.editing = { ...this.editing, draft: text3 };
557
+ this.editing = { ...this.editing, draft: text4 };
559
558
  if (this.livePreview) {
560
- const parsed = this.parseDraft(this.editing.columnId, text3);
559
+ const parsed = this.parseDraft(this.editing.columnId, text4);
561
560
  if (parsed.ok) {
562
561
  this.host.emit("editPreview", this.buildEdit(this.editing, parsed.value));
563
562
  }
@@ -609,12 +608,12 @@ var TableController = class {
609
608
  };
610
609
  }
611
610
  /** Parse a draft according to the column's declared type. */
612
- parseDraft(columnId, text3) {
611
+ parseDraft(columnId, text4) {
613
612
  const column = this.columnById(columnId);
614
- const trimmed = text3.trim();
613
+ const trimmed = text4.trim();
615
614
  if (column?.type === "number" || column?.type === "integer" || column?.type === "duration") {
616
615
  if (trimmed === "") return { ok: true, value: null };
617
- const parsed = parseNumeric(text3);
616
+ const parsed = parseNumeric(text4);
618
617
  if (!parsed.ok) return { ok: false, reason: parsed.reason };
619
618
  return { ok: true, value: normalizeNumeric(parsed.value, constraintsOfColumn(column)) };
620
619
  }
@@ -631,7 +630,7 @@ var TableController = class {
631
630
  value: trimmed === "" ? [] : trimmed.split(",").map((part) => part.trim()).filter(Boolean)
632
631
  };
633
632
  }
634
- return { ok: true, value: trimmed === "" ? null : text3 };
633
+ return { ok: true, value: trimmed === "" ? null : text4 };
635
634
  }
636
635
  rowById(rowId) {
637
636
  return this.result?.rows.find((r) => r.id === rowId);
@@ -2205,16 +2204,7 @@ var chartManifest = {
2205
2204
 
2206
2205
  // src/data/chart/react/ChartPanelView.tsx
2207
2206
  import { useEffect as useEffect2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
2208
- import {
2209
- Badge as Badge2,
2210
- EmptyState as EmptyState2,
2211
- ErrorState as ErrorState2,
2212
- IconButton as IconButton2,
2213
- SegmentedControl as SegmentedControl2,
2214
- StatusBar as StatusBar2,
2215
- Toolbar as Toolbar2,
2216
- ToolbarGroup as ToolbarGroup2
2217
- } from "@xenosystem/components/chrome";
2207
+ import { Badge as Badge2, Column, EmptyState as EmptyState2, ErrorState as ErrorState2, IconButton as IconButton2, PlotSurface, SegmentedControl as SegmentedControl2, StatusBar as StatusBar2, Toolbar as Toolbar2, ToolbarGroup as ToolbarGroup2 } from "@xenosystem/components/chrome";
2218
2208
 
2219
2209
  // src/data/chart/renderer.ts
2220
2210
  var renderer = null;
@@ -2268,19 +2258,102 @@ function shade(index) {
2268
2258
  return MONO_PALETTE[index % MONO_PALETTE.length];
2269
2259
  }
2270
2260
 
2261
+ // src/data/chart/declaration.ts
2262
+ var CHART_TYPE_LABELS = { bar: "Bar", horizontalBar: "H-Bar", line: "Line", area: "Area", scatter: "Scatter", pie: "Pie", doughnut: "Ring" };
2263
+ var DEFAULT_CHART_OPTIONS = { showLegend: true, showGrid: true, showTooltip: true, stacked: false, smoothing: 0 };
2264
+ function chartViewState(c, options = {}) {
2265
+ const s = c.getState();
2266
+ const errored = !!s.errorMessage;
2267
+ const empty = !errored && s.empty;
2268
+ const unplottable = !errored && !empty && !!s.encodingProblem;
2269
+ const noRenderer = !errored && !empty && !unplottable && !getChartRenderer();
2270
+ return {
2271
+ types: s.allowedTypes.map((t) => ({ value: t, label: CHART_TYPE_LABELS[t] ?? t })),
2272
+ type: s.encoding.type,
2273
+ partial: s.partial,
2274
+ aggregating: !!s.data?.tooDense,
2275
+ aggregatingHint: s.data?.tooDense ? `${s.data.tooDense.points} points exceeds the ${s.data.tooDense.limit} plot limit \u2014 an aggregated query was requested.` : void 0,
2276
+ errorMessage: s.errorMessage ?? void 0,
2277
+ errored,
2278
+ empty,
2279
+ emptyHint: options.emptyHint ?? "Wire a result into this chart to plot it.",
2280
+ unplottable,
2281
+ encodingProblem: s.encodingProblem ?? void 0,
2282
+ noRenderer,
2283
+ plot: !errored && !empty && !unplottable && !noRenderer,
2284
+ countLabel: s.data ? `${s.data.series.length} series \xB7 ${s.data.labels.length} points` : void 0,
2285
+ highlightLabel: s.highlightedRowIds.length > 0 ? `${s.highlightedRowIds.length} highlighted` : void 0
2286
+ };
2287
+ }
2288
+ function applyChartUi(c, intent) {
2289
+ switch (intent.kind) {
2290
+ case "type":
2291
+ c.setType(intent.type);
2292
+ break;
2293
+ case "export":
2294
+ c.requestExport("png");
2295
+ break;
2296
+ }
2297
+ }
2298
+ var chartViewManifest = {
2299
+ id: chartManifest.id,
2300
+ version: "1.0.0",
2301
+ title: "Chart",
2302
+ category: "data",
2303
+ layout: { slot: "center" },
2304
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The ChartViewModel the runtime derives from the controller on every draw." }],
2305
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind: type | export, \u2026 } \u2014 applied by the runtime to the controller." }],
2306
+ commands: []
2307
+ };
2308
+ var EMPTY = { types: [], type: "bar", partial: false, aggregating: false, errored: false, empty: true, emptyHint: "Wire a result into this chart to plot it.", unplottable: false, noRenderer: false, plot: false };
2309
+ var BEHAVIOURS = {
2310
+ "data/chartPanelView": (inputs) => inputs.view ?? EMPTY
2311
+ };
2312
+ var CHART_RUNTIME_UNITS = ["chart/Plot"];
2313
+ var text = (b) => ({ component: "text", props: { text: b } });
2314
+ var ui = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
2315
+ var CHART_DECLARATION = {
2316
+ format: "xeno.block@1",
2317
+ manifest: chartViewManifest,
2318
+ behaviour: "data/chartPanelView",
2319
+ composition: {
2320
+ component: "chrome/Column",
2321
+ children: [
2322
+ {
2323
+ component: "chrome/Toolbar",
2324
+ props: {
2325
+ left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Chart type" }, options: { input: "view.types" }, value: { input: "view.type" } }, on: { onChange: ui("type", { type: { arg: "" } }) } } },
2326
+ right: {
2327
+ node: {
2328
+ component: "chrome/ToolbarGroup",
2329
+ props: { end: { value: true } },
2330
+ children: [
2331
+ { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { value: "Some measures have not synced yet." } }, children: [text({ value: "partial" })] },
2332
+ { component: "chrome/Badge", when: { input: "view.aggregating" }, props: { tone: { value: "warning" }, title: { input: "view.aggregatingHint" } }, children: [text({ value: "aggregating" })] },
2333
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Download" } }, label: { value: "Export chart" } }, on: { onClick: ui("export") } }
2334
+ ]
2335
+ }
2336
+ }
2337
+ }
2338
+ },
2339
+ { component: "chrome/ErrorState", when: { input: "view.errored" }, props: { title: { value: "Could not load data" }, message: { input: "view.errorMessage" } } },
2340
+ { component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { value: "No data" }, hint: { input: "view.emptyHint" } } },
2341
+ { component: "chrome/EmptyState", when: { input: "view.unplottable" }, props: { title: { value: "Nothing to plot" }, hint: { input: "view.encodingProblem" } } },
2342
+ { component: "chrome/EmptyState", when: { input: "view.noRenderer" }, props: { title: { value: "No renderer installed" }, hint: { value: "Call setChartRenderer() with a Chart.js (or other) renderer \u2014 the panel ships the model, the host ships the marks." } } },
2343
+ { component: "chart/Plot", when: { input: "view.plot" } },
2344
+ { component: "chrome/StatusBar", props: { left: { input: "view.countLabel" }, right: { input: "view.highlightLabel" } } }
2345
+ ]
2346
+ }
2347
+ };
2348
+
2271
2349
  // src/data/chart/react/ChartPanelView.tsx
2272
2350
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2273
- var DEFAULT_OPTIONS = {
2274
- showLegend: true,
2275
- showGrid: true,
2276
- showTooltip: true,
2277
- stacked: false,
2278
- smoothing: 0
2279
- };
2280
- function ChartPanelView({ controller, options, emptyHint }) {
2351
+ var DownloadGlyph = ICONS["icons/Download"];
2352
+ function ChartPlot({ controller, options }) {
2281
2353
  const state = useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
2282
2354
  const plotRef = useRef2(null);
2283
- const resolved = { ...DEFAULT_OPTIONS, ...options };
2355
+ const resolved = { ...DEFAULT_CHART_OPTIONS, ...options };
2356
+ const resolvedKey = JSON.stringify(resolved);
2284
2357
  useEffect2(() => {
2285
2358
  const element = plotRef.current;
2286
2359
  const renderer2 = getChartRenderer();
@@ -2293,83 +2366,38 @@ function ChartPanelView({ controller, options, emptyHint }) {
2293
2366
  highlightedRowIds: state.highlightedRowIds,
2294
2367
  onMarkActivate: (label, seriesId) => controller.activateMark(label, seriesId)
2295
2368
  });
2296
- }, [state.data, state.highlightedRowIds, controller, JSON.stringify(resolved)]);
2297
- const toolbar = /* @__PURE__ */ jsx2(
2298
- Toolbar2,
2299
- {
2300
- left: /* @__PURE__ */ jsx2(
2301
- SegmentedControl2,
2302
- {
2303
- size: "sm",
2304
- label: "Chart type",
2305
- options: state.allowedTypes.map((t) => ({ value: t, label: LABELS[t] ?? t })),
2306
- value: state.encoding.type,
2307
- onChange: (t) => controller.setType(t)
2308
- }
2309
- ),
2310
- right: /* @__PURE__ */ jsxs2(ToolbarGroup2, { end: true, children: [
2311
- state.partial ? /* @__PURE__ */ jsx2(Badge2, { tone: "warning", title: "Some measures have not synced yet.", children: "partial" }) : null,
2312
- state.data?.tooDense ? /* @__PURE__ */ jsx2(
2313
- Badge2,
2314
- {
2315
- tone: "warning",
2316
- title: `${state.data.tooDense.points} points exceeds the ${state.data.tooDense.limit} plot limit \u2014 an aggregated query was requested.`,
2317
- children: "aggregating"
2318
- }
2319
- ) : null,
2320
- /* @__PURE__ */ jsx2(
2321
- IconButton2,
2322
- {
2323
- icon: /* @__PURE__ */ jsx2(DownloadGlyph, {}),
2324
- label: "Export chart",
2325
- onClick: () => controller.requestExport("png")
2326
- }
2327
- )
2328
- ] })
2329
- }
2330
- );
2331
- const body = (() => {
2332
- if (state.errorMessage) {
2333
- return /* @__PURE__ */ jsx2(ErrorState2, { title: "Could not load data", message: state.errorMessage });
2334
- }
2335
- if (state.empty) {
2336
- return /* @__PURE__ */ jsx2(EmptyState2, { title: "No data", hint: emptyHint ?? "Wire a result into this chart to plot it." });
2337
- }
2338
- if (state.encodingProblem) {
2339
- return /* @__PURE__ */ jsx2(EmptyState2, { title: "Nothing to plot", hint: state.encodingProblem });
2340
- }
2341
- if (!getChartRenderer()) {
2342
- return /* @__PURE__ */ jsx2(
2343
- EmptyState2,
2344
- {
2345
- title: "No renderer installed",
2346
- hint: "Call setChartRenderer() with a Chart.js (or other) renderer \u2014 the panel ships the model, the host ships the marks."
2347
- }
2348
- );
2349
- }
2350
- return /* @__PURE__ */ jsx2("div", { ref: plotRef, style: { flex: "1 1 0", minHeight: 0, position: "relative" } });
2351
- })();
2352
- return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
2353
- toolbar,
2354
- body,
2369
+ }, [state.data, state.highlightedRowIds, controller, resolvedKey]);
2370
+ return /* @__PURE__ */ jsx2(PlotSurface, { ref: plotRef, label: "Chart" });
2371
+ }
2372
+ function chartRuntimeComponents(controller, options) {
2373
+ return {
2374
+ "chart/Plot": () => /* @__PURE__ */ jsx2(ChartPlot, { controller, options })
2375
+ };
2376
+ }
2377
+ function ChartPanelView({ controller, options, emptyHint }) {
2378
+ useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
2379
+ const view = chartViewState(controller, { emptyHint });
2380
+ const ui4 = (intent) => applyChartUi(controller, intent);
2381
+ return /* @__PURE__ */ jsxs2(Column, { children: [
2355
2382
  /* @__PURE__ */ jsx2(
2356
- StatusBar2,
2383
+ Toolbar2,
2357
2384
  {
2358
- left: state.data ? `${state.data.series.length} series \xB7 ${state.data.labels.length} points` : void 0,
2359
- right: state.highlightedRowIds.length > 0 ? `${state.highlightedRowIds.length} highlighted` : void 0
2385
+ left: /* @__PURE__ */ jsx2(SegmentedControl2, { size: "sm", label: "Chart type", options: view.types, value: view.type, onChange: (type) => ui4({ kind: "type", type }) }),
2386
+ right: /* @__PURE__ */ jsxs2(ToolbarGroup2, { end: true, children: [
2387
+ view.partial ? /* @__PURE__ */ jsx2(Badge2, { tone: "warning", title: "Some measures have not synced yet.", children: "partial" }) : null,
2388
+ view.aggregating ? /* @__PURE__ */ jsx2(Badge2, { tone: "warning", title: view.aggregatingHint, children: "aggregating" }) : null,
2389
+ /* @__PURE__ */ jsx2(IconButton2, { icon: /* @__PURE__ */ jsx2(DownloadGlyph, {}), label: "Export chart", onClick: () => ui4({ kind: "export" }) })
2390
+ ] })
2360
2391
  }
2361
- )
2392
+ ),
2393
+ view.errored ? /* @__PURE__ */ jsx2(ErrorState2, { title: "Could not load data", message: view.errorMessage }) : null,
2394
+ view.empty ? /* @__PURE__ */ jsx2(EmptyState2, { title: "No data", hint: view.emptyHint }) : null,
2395
+ view.unplottable ? /* @__PURE__ */ jsx2(EmptyState2, { title: "Nothing to plot", hint: view.encodingProblem }) : null,
2396
+ view.noRenderer ? /* @__PURE__ */ jsx2(EmptyState2, { title: "No renderer installed", hint: "Call setChartRenderer() with a Chart.js (or other) renderer \u2014 the panel ships the model, the host ships the marks." }) : null,
2397
+ view.plot ? /* @__PURE__ */ jsx2(ChartPlot, { controller, options }) : null,
2398
+ /* @__PURE__ */ jsx2(StatusBar2, { left: view.countLabel, right: view.highlightLabel })
2362
2399
  ] });
2363
2400
  }
2364
- var LABELS = {
2365
- bar: "Bar",
2366
- horizontalBar: "H-Bar",
2367
- line: "Line",
2368
- area: "Area",
2369
- scatter: "Scatter",
2370
- pie: "Pie",
2371
- doughnut: "Ring"
2372
- };
2373
2401
 
2374
2402
  // src/data/chart/panel.ts
2375
2403
  function createChartPanel(options = {}) {
@@ -2912,7 +2940,7 @@ var metricsManifest = {
2912
2940
  import { useSyncExternalStore as useSyncExternalStore3 } from "react";
2913
2941
  import {
2914
2942
  Badge as Badge3,
2915
- Column,
2943
+ Column as Column2,
2916
2944
  Delta,
2917
2945
  EmptyState as EmptyState3,
2918
2946
  ErrorState as ErrorState3,
@@ -2994,13 +3022,13 @@ var metricsViewManifest = {
2994
3022
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind: range | activate, \u2026 } \u2014 applied by the runtime to the controller." }],
2995
3023
  commands: []
2996
3024
  };
2997
- var EMPTY = { hasRanges: false, ranges: [], rangeId: "", partial: false, partialHint: "", errored: false, empty: true, emptyHint: "Configure a metric, or wire a result into this panel.", ready: false, layout: "grid", columns: 4, tiles: [], countLabel: "0 metrics" };
2998
- var BEHAVIOURS = {
2999
- "data/metricsPanelView": (inputs) => inputs.view ?? EMPTY
3025
+ var EMPTY2 = { hasRanges: false, ranges: [], rangeId: "", partial: false, partialHint: "", errored: false, empty: true, emptyHint: "Configure a metric, or wire a result into this panel.", ready: false, layout: "grid", columns: 4, tiles: [], countLabel: "0 metrics" };
3026
+ var BEHAVIOURS2 = {
3027
+ "data/metricsPanelView": (inputs) => inputs.view ?? EMPTY2
3000
3028
  };
3001
3029
  var METRICS_RUNTIME_UNITS = [];
3002
- var text = (b) => ({ component: "text", props: { text: b } });
3003
- var ui = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
3030
+ var text2 = (b) => ({ component: "text", props: { text: b } });
3031
+ var ui2 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
3004
3032
  var METRICS_DECLARATION = {
3005
3033
  format: "xeno.block@1",
3006
3034
  manifest: metricsViewManifest,
@@ -3012,8 +3040,8 @@ var METRICS_DECLARATION = {
3012
3040
  component: "chrome/Toolbar",
3013
3041
  when: { input: "view.hasRanges" },
3014
3042
  props: {
3015
- left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Range" }, options: { input: "view.ranges" }, value: { input: "view.rangeId" } }, on: { onChange: ui("range", { rangeId: { arg: "" } }) } } },
3016
- right: { node: { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { input: "view.partialHint" } }, children: [text({ value: "partial" })] } }
3043
+ left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Range" }, options: { input: "view.ranges" }, value: { input: "view.rangeId" } }, on: { onChange: ui2("range", { rangeId: { arg: "" } }) } } },
3044
+ right: { node: { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { input: "view.partialHint" } }, children: [text2({ value: "partial" })] } }
3017
3045
  }
3018
3046
  },
3019
3047
  { component: "chrome/ErrorState", when: { input: "view.errored" }, props: { title: { value: "Could not load metrics" }, message: { input: "view.errorMessage" } } },
@@ -3033,20 +3061,20 @@ var METRICS_DECLARATION = {
3033
3061
  title: { item: "title" },
3034
3062
  label: { item: "label" },
3035
3063
  value: { item: "value" },
3036
- icon: { node: { component: "chrome/Badge", when: { item: "hasLevel" }, props: { tone: { item: "tone" } }, children: [text({ item: "level" })] } },
3064
+ icon: { node: { component: "chrome/Badge", when: { item: "hasLevel" }, props: { tone: { item: "tone" } }, children: [text2({ item: "level" })] } },
3037
3065
  sub: {
3038
3066
  node: {
3039
3067
  component: "chrome/Stack",
3040
3068
  props: { direction: { value: "row" }, pad: { value: "none" } },
3041
3069
  children: [
3042
3070
  { component: "chrome/Delta", when: { item: "hasDelta" }, props: { value: { item: "delta" }, tone: { item: "deltaTone" } } },
3043
- { component: "chrome/Text", when: { item: "partial" }, props: { role: { value: "meta" } }, children: [text({ input: "view.partialHint" })] },
3071
+ { component: "chrome/Text", when: { item: "partial" }, props: { role: { value: "meta" } }, children: [text2({ input: "view.partialHint" })] },
3044
3072
  { component: "chrome/Sparkline", when: { item: "hasSpark" }, props: { data: { item: "spark" }, label: { item: "sparkLabel" } } }
3045
3073
  ]
3046
3074
  }
3047
3075
  }
3048
3076
  },
3049
- on: { onActivate: ui("activate", { metricId: { item: "id" } }) }
3077
+ on: { onActivate: ui2("activate", { metricId: { item: "id" } }) }
3050
3078
  }
3051
3079
  ]
3052
3080
  }
@@ -3062,12 +3090,12 @@ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
3062
3090
  function MetricsPanelView({ controller, ...options }) {
3063
3091
  useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
3064
3092
  const view = metricsViewState(controller, options);
3065
- const ui3 = (intent) => applyMetricsUi(controller, intent);
3066
- return /* @__PURE__ */ jsxs3(Column, { children: [
3093
+ const ui4 = (intent) => applyMetricsUi(controller, intent);
3094
+ return /* @__PURE__ */ jsxs3(Column2, { children: [
3067
3095
  view.hasRanges ? /* @__PURE__ */ jsx3(
3068
3096
  Toolbar3,
3069
3097
  {
3070
- left: /* @__PURE__ */ jsx3(SegmentedControl3, { size: "sm", label: "Range", options: view.ranges, value: view.rangeId, onChange: (rangeId) => ui3({ kind: "range", rangeId }) }),
3098
+ left: /* @__PURE__ */ jsx3(SegmentedControl3, { size: "sm", label: "Range", options: view.ranges, value: view.rangeId, onChange: (rangeId) => ui4({ kind: "range", rangeId }) }),
3071
3099
  right: view.partial ? /* @__PURE__ */ jsx3(Badge3, { tone: "warning", title: view.partialHint, children: "partial" }) : null
3072
3100
  }
3073
3101
  ) : null,
@@ -3085,7 +3113,7 @@ function MetricsPanelView({ controller, ...options }) {
3085
3113
  tile.partial ? /* @__PURE__ */ jsx3(Text, { role: "meta", children: view.partialHint }) : null,
3086
3114
  tile.hasSpark ? /* @__PURE__ */ jsx3(Sparkline, { data: tile.spark, label: tile.sparkLabel }) : null
3087
3115
  ] }),
3088
- onActivate: () => ui3({ kind: "activate", metricId: tile.id })
3116
+ onActivate: () => ui4({ kind: "activate", metricId: tile.id })
3089
3117
  },
3090
3118
  tile.id
3091
3119
  )) }) }) : null,
@@ -3287,7 +3315,7 @@ function emptyFilterGroup() {
3287
3315
  function offerableFilterOps(column, sourceOps = []) {
3288
3316
  const common = ["eq", "ne", "isEmpty", "isNotEmpty", "in", "notIn"];
3289
3317
  const ordered = ["gt", "gte", "lt", "lte", "between"];
3290
- const text3 = ["contains", "notContains", "startsWith", "endsWith"];
3318
+ const text4 = ["contains", "notContains", "startsWith", "endsWith"];
3291
3319
  const temporal = ["relative"];
3292
3320
  let ops = [...common];
3293
3321
  switch (column?.type) {
@@ -3305,10 +3333,10 @@ function offerableFilterOps(column, sourceOps = []) {
3305
3333
  case "url":
3306
3334
  case "select":
3307
3335
  case "multiselect":
3308
- ops = [...ops, ...text3];
3336
+ ops = [...ops, ...text4];
3309
3337
  break;
3310
3338
  default:
3311
- ops = [...ops, ...text3, ...ordered];
3339
+ ops = [...ops, ...text4, ...ordered];
3312
3340
  }
3313
3341
  if (sourceOps.length === 0) return ops;
3314
3342
  return ops.filter((op) => sourceOps.includes(op));
@@ -3939,7 +3967,7 @@ var fieldsManifest = {
3939
3967
  import { useSyncExternalStore as useSyncExternalStore4 } from "react";
3940
3968
  import {
3941
3969
  Badge as Badge4,
3942
- Column as Column2,
3970
+ Column as Column3,
3943
3971
  EmptyState as EmptyState4,
3944
3972
  IconButton as IconButton3,
3945
3973
  Note,
@@ -4074,13 +4102,13 @@ var fieldsViewManifest = {
4074
4102
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
4075
4103
  commands: []
4076
4104
  };
4077
- var EMPTY2 = { hasColumns: false, noColumns: true, sampled: false, manualApply: false, applyDisabled: true, columns: [], shelves: [], filters: [], filterCount: 0, hasFilters: false, noFilters: true, combinator: "and", countLabel: "0 fields" };
4078
- var BEHAVIOURS2 = {
4079
- "data/fieldsPanelView": (inputs) => inputs.view ?? EMPTY2
4105
+ var EMPTY3 = { hasColumns: false, noColumns: true, sampled: false, manualApply: false, applyDisabled: true, columns: [], shelves: [], filters: [], filterCount: 0, hasFilters: false, noFilters: true, combinator: "and", countLabel: "0 fields" };
4106
+ var BEHAVIOURS3 = {
4107
+ "data/fieldsPanelView": (inputs) => inputs.view ?? EMPTY3
4080
4108
  };
4081
4109
  var FIELDS_RUNTIME_UNITS = [];
4082
- var text2 = (b) => ({ component: "text", props: { text: b } });
4083
- var ui2 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
4110
+ var text3 = (b) => ({ component: "text", props: { text: b } });
4111
+ var ui3 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
4084
4112
  var removeButton = (label, on) => ({
4085
4113
  component: "chrome/IconButton",
4086
4114
  props: { size: { value: "sm" }, icon: { node: { component: "icons/Close", props: { size: { value: 11 } } } }, label },
@@ -4101,14 +4129,14 @@ var FIELDS_DECLARATION = {
4101
4129
  {
4102
4130
  component: "chrome/Toolbar",
4103
4131
  props: {
4104
- left: { node: { component: "chrome/Badge", when: { input: "view.sampled" }, props: { tone: { value: "warning" }, title: { input: "view.sampleWarning" } }, children: [text2({ value: "sampled schema" })] } },
4132
+ left: { node: { component: "chrome/Badge", when: { input: "view.sampled" }, props: { tone: { value: "warning" }, title: { input: "view.sampleWarning" } }, children: [text3({ value: "sampled schema" })] } },
4105
4133
  right: {
4106
4134
  node: {
4107
4135
  component: "chrome/ToolbarGroup",
4108
4136
  props: { end: { value: true } },
4109
4137
  children: [
4110
- { component: "chrome/TextButton", on: { onClick: ui2("autoAssign") }, children: [text2({ value: "Auto-assign" })] },
4111
- { component: "chrome/TextButton", when: { input: "view.manualApply" }, props: { strong: { value: true }, disabled: { input: "view.applyDisabled" } }, on: { onClick: ui2("apply") }, children: [text2({ value: "Apply" })] }
4138
+ { component: "chrome/TextButton", on: { onClick: ui3("autoAssign") }, children: [text3({ value: "Auto-assign" })] },
4139
+ { component: "chrome/TextButton", when: { input: "view.manualApply" }, props: { strong: { value: true }, disabled: { input: "view.applyDisabled" } }, on: { onClick: ui3("apply") }, children: [text3({ value: "Apply" })] }
4112
4140
  ]
4113
4141
  }
4114
4142
  }
@@ -4128,8 +4156,8 @@ var FIELDS_DECLARATION = {
4128
4156
  {
4129
4157
  component: "chrome/Row",
4130
4158
  each: { input: "view.columns", key: "id" },
4131
- props: { label: { item: "name" }, meta: { item: "role" }, selected: { item: "focused" }, trailing: { node: { component: "chrome/Badge", when: { item: "stat" }, props: { title: { item: "statTitle" } }, children: [text2({ item: "stat" })] } } },
4132
- on: { onClick: ui2("focus", { columnId: { item: "id" } }) }
4159
+ props: { label: { item: "name" }, meta: { item: "role" }, selected: { item: "focused" }, trailing: { node: { component: "chrome/Badge", when: { item: "stat" }, props: { title: { item: "statTitle" } }, children: [text3({ item: "stat" })] } } },
4160
+ on: { onClick: ui3("focus", { columnId: { item: "id" } }) }
4133
4161
  }
4134
4162
  ]
4135
4163
  }
@@ -4138,9 +4166,9 @@ var FIELDS_DECLARATION = {
4138
4166
  {
4139
4167
  component: "chrome/Section",
4140
4168
  each: { input: "view.shelves", key: "id" },
4141
- props: { title: { item: "label" }, flush: { value: true }, badge: { node: { component: "chrome/Badge", when: { item: "hasEntries" }, children: [text2({ item: "count" })] } } },
4169
+ props: { title: { item: "label" }, flush: { value: true }, badge: { node: { component: "chrome/Badge", when: { item: "hasEntries" }, children: [text3({ item: "count" })] } } },
4142
4170
  children: [
4143
- { component: "chrome/Note", when: { item: "empty" }, children: [text2({ item: "hint" })] },
4171
+ { component: "chrome/Note", when: { item: "empty" }, children: [text3({ item: "hint" })] },
4144
4172
  {
4145
4173
  component: "chrome/RowList",
4146
4174
  when: { item: "hasEntries" },
@@ -4155,13 +4183,13 @@ var FIELDS_DECLARATION = {
4155
4183
  node: {
4156
4184
  component: "fragment",
4157
4185
  children: [
4158
- { component: "chrome/Select", when: { item: "aggregated" }, props: { size: { value: "sm" }, label: { value: "Aggregate" }, options: { item: "aggregates" }, value: { item: "fn" } }, on: { onChange: ui2("aggregate", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" }, fn: { arg: "" } }) } },
4159
- { component: "chrome/TextButton", when: { item: "sortable" }, on: { onClick: ui2("direction", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" } }) }, children: [text2({ item: "direction" })] },
4160
- { component: "chrome/Badge", when: { item: "granularity" }, children: [text2({ item: "granularity" })] }
4186
+ { component: "chrome/Select", when: { item: "aggregated" }, props: { size: { value: "sm" }, label: { value: "Aggregate" }, options: { item: "aggregates" }, value: { item: "fn" } }, on: { onChange: ui3("aggregate", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" }, fn: { arg: "" } }) } },
4187
+ { component: "chrome/TextButton", when: { item: "sortable" }, on: { onClick: ui3("direction", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" } }) }, children: [text3({ item: "direction" })] },
4188
+ { component: "chrome/Badge", when: { item: "granularity" }, children: [text3({ item: "granularity" })] }
4161
4189
  ]
4162
4190
  }
4163
4191
  },
4164
- trailing: { node: removeButton({ item: "removeLabel" }, ui2("remove", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" } })) }
4192
+ trailing: { node: removeButton({ item: "removeLabel" }, ui3("remove", { shelfId: { item: "shelfId" }, columnId: { item: "columnId" } })) }
4165
4193
  }
4166
4194
  }
4167
4195
  ]
@@ -4173,11 +4201,11 @@ var FIELDS_DECLARATION = {
4173
4201
  props: {
4174
4202
  title: { value: "Filters" },
4175
4203
  flush: { value: true },
4176
- badge: { node: { component: "chrome/Badge", when: { input: "view.hasFilters" }, children: [text2({ input: "view.filterCount" })] } },
4177
- actions: { node: { component: "chrome/IconButton", props: { size: { value: "sm" }, icon: { node: { component: "icons/Plus", props: { size: { value: 11 } } } }, label: { value: "Add filter" } }, on: { onClick: ui2("addFilter") } } }
4204
+ badge: { node: { component: "chrome/Badge", when: { input: "view.hasFilters" }, children: [text3({ input: "view.filterCount" })] } },
4205
+ actions: { node: { component: "chrome/IconButton", props: { size: { value: "sm" }, icon: { node: { component: "icons/Plus", props: { size: { value: 11 } } } }, label: { value: "Add filter" } }, on: { onClick: ui3("addFilter") } } }
4178
4206
  },
4179
4207
  children: [
4180
- { component: "chrome/Note", when: { input: "view.noFilters" }, children: [text2({ value: "No filters. Everything passes." })] },
4208
+ { component: "chrome/Note", when: { input: "view.noFilters" }, children: [text3({ value: "No filters. Everything passes." })] },
4181
4209
  {
4182
4210
  component: "chrome/RowList",
4183
4211
  when: { input: "view.hasFilters" },
@@ -4187,8 +4215,8 @@ var FIELDS_DECLARATION = {
4187
4215
  each: { input: "view.filters", key: "key" },
4188
4216
  props: {
4189
4217
  label: { item: "label" },
4190
- meta: { node: { component: "chrome/Select", when: { item: "leaf" }, props: { size: { value: "sm" }, label: { value: "Operator" }, options: { item: "ops" }, value: { item: "op" } }, on: { onChange: ui2("filterOp", { index: { item: "index" }, op: { arg: "" } }) } } },
4191
- trailing: { node: removeButton({ item: "removeLabel" }, ui2("removeFilter", { index: { item: "index" } })) }
4218
+ meta: { node: { component: "chrome/Select", when: { item: "leaf" }, props: { size: { value: "sm" }, label: { value: "Operator" }, options: { item: "ops" }, value: { item: "op" } }, on: { onChange: ui3("filterOp", { index: { item: "index" }, op: { arg: "" } }) } } },
4219
+ trailing: { node: removeButton({ item: "removeLabel" }, ui3("removeFilter", { index: { item: "index" } })) }
4192
4220
  }
4193
4221
  }
4194
4222
  ]
@@ -4197,8 +4225,8 @@ var FIELDS_DECLARATION = {
4197
4225
  component: "chrome/Toolbar",
4198
4226
  props: {
4199
4227
  divided: { value: false },
4200
- left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Combinator" }, options: { value: COMBINATORS }, value: { input: "view.combinator" } }, on: { onChange: ui2("combinator", { combinator: { arg: "" } }) } } },
4201
- right: { node: { component: "chrome/TextButton", on: { onClick: ui2("addGroup") }, children: [text2({ value: "+ group" })] } }
4228
+ left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Combinator" }, options: { value: COMBINATORS }, value: { input: "view.combinator" } }, on: { onChange: ui3("combinator", { combinator: { arg: "" } }) } } },
4229
+ right: { node: { component: "chrome/TextButton", on: { onClick: ui3("addGroup") }, children: [text3({ value: "+ group" })] } }
4202
4230
  }
4203
4231
  }
4204
4232
  ]
@@ -4220,18 +4248,18 @@ var COMBINATORS2 = [{ value: "and", label: "All" }, { value: "or", label: "Any"
4220
4248
  function FieldsPanelView({ controller, showStats, manualApply }) {
4221
4249
  useSyncExternalStore4(controller.subscribe, controller.getState, controller.getState);
4222
4250
  const view = fieldsViewState(controller, { showStats, manualApply });
4223
- const ui3 = (intent) => applyFieldsUi(controller, intent);
4251
+ const ui4 = (intent) => applyFieldsUi(controller, intent);
4224
4252
  if (view.noColumns) {
4225
4253
  return /* @__PURE__ */ jsx4(EmptyState4, { title: "No fields", hint: "Connect a source \u2014 its columns appear here, ready to drop onto a shelf." });
4226
4254
  }
4227
- return /* @__PURE__ */ jsxs4(Column2, { children: [
4255
+ return /* @__PURE__ */ jsxs4(Column3, { children: [
4228
4256
  /* @__PURE__ */ jsx4(
4229
4257
  Toolbar4,
4230
4258
  {
4231
4259
  left: view.sampled ? /* @__PURE__ */ jsx4(Badge4, { tone: "warning", title: view.sampleWarning, children: "sampled schema" }) : null,
4232
4260
  right: /* @__PURE__ */ jsxs4(ToolbarGroup3, { end: true, children: [
4233
- /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui3({ kind: "autoAssign" }), children: "Auto-assign" }),
4234
- view.manualApply ? /* @__PURE__ */ jsx4(TextButton, { strong: true, disabled: view.applyDisabled, onClick: () => ui3({ kind: "apply" }), children: "Apply" }) : null
4261
+ /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui4({ kind: "autoAssign" }), children: "Auto-assign" }),
4262
+ view.manualApply ? /* @__PURE__ */ jsx4(TextButton, { strong: true, disabled: view.applyDisabled, onClick: () => ui4({ kind: "apply" }), children: "Apply" }) : null
4235
4263
  ] })
4236
4264
  }
4237
4265
  ),
@@ -4243,7 +4271,7 @@ function FieldsPanelView({ controller, showStats, manualApply }) {
4243
4271
  meta: column.role,
4244
4272
  selected: column.focused,
4245
4273
  trailing: column.stat ? /* @__PURE__ */ jsx4(Badge4, { title: column.statTitle, children: column.stat }) : null,
4246
- onClick: () => ui3({ kind: "focus", columnId: column.id })
4274
+ onClick: () => ui4({ kind: "focus", columnId: column.id })
4247
4275
  },
4248
4276
  column.id
4249
4277
  )) }) }),
@@ -4255,11 +4283,11 @@ function FieldsPanelView({ controller, showStats, manualApply }) {
4255
4283
  label: entry.label,
4256
4284
  dimmed: entry.suggested,
4257
4285
  meta: /* @__PURE__ */ jsxs4(Fragment2, { children: [
4258
- entry.aggregated ? /* @__PURE__ */ jsx4(Select, { size: "sm", label: "Aggregate", options: entry.aggregates, value: entry.fn, onChange: (fn) => ui3({ kind: "aggregate", shelfId: entry.shelfId, columnId: entry.columnId, fn }) }) : null,
4259
- entry.sortable ? /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui3({ kind: "direction", shelfId: entry.shelfId, columnId: entry.columnId }), children: entry.direction }) : null,
4286
+ entry.aggregated ? /* @__PURE__ */ jsx4(Select, { size: "sm", label: "Aggregate", options: entry.aggregates, value: entry.fn, onChange: (fn) => ui4({ kind: "aggregate", shelfId: entry.shelfId, columnId: entry.columnId, fn }) }) : null,
4287
+ entry.sortable ? /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui4({ kind: "direction", shelfId: entry.shelfId, columnId: entry.columnId }), children: entry.direction }) : null,
4260
4288
  entry.granularity ? /* @__PURE__ */ jsx4(Badge4, { children: entry.granularity }) : null
4261
4289
  ] }),
4262
- trailing: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(CloseGlyph, { size: 11 }), label: entry.removeLabel, onClick: () => ui3({ kind: "remove", shelfId: entry.shelfId, columnId: entry.columnId }) })
4290
+ trailing: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(CloseGlyph, { size: 11 }), label: entry.removeLabel, onClick: () => ui4({ kind: "remove", shelfId: entry.shelfId, columnId: entry.columnId }) })
4263
4291
  },
4264
4292
  entry.columnId
4265
4293
  )) }) : null
@@ -4270,15 +4298,15 @@ function FieldsPanelView({ controller, showStats, manualApply }) {
4270
4298
  title: "Filters",
4271
4299
  flush: true,
4272
4300
  badge: view.hasFilters ? /* @__PURE__ */ jsx4(Badge4, { children: view.filterCount }) : null,
4273
- actions: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(PlusGlyph, { size: 11 }), label: "Add filter", onClick: () => ui3({ kind: "addFilter" }) }),
4301
+ actions: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(PlusGlyph, { size: 11 }), label: "Add filter", onClick: () => ui4({ kind: "addFilter" }) }),
4274
4302
  children: [
4275
4303
  view.noFilters ? /* @__PURE__ */ jsx4(Note, { children: "No filters. Everything passes." }) : null,
4276
4304
  view.hasFilters ? /* @__PURE__ */ jsx4(RowList, { children: view.filters.map((filter) => /* @__PURE__ */ jsx4(
4277
4305
  Row,
4278
4306
  {
4279
4307
  label: filter.label,
4280
- meta: filter.leaf ? /* @__PURE__ */ jsx4(Select, { size: "sm", label: "Operator", options: filter.ops, value: filter.op, onChange: (op) => ui3({ kind: "filterOp", index: filter.index, op }) }) : null,
4281
- trailing: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(CloseGlyph, { size: 11 }), label: filter.removeLabel, onClick: () => ui3({ kind: "removeFilter", index: filter.index }) })
4308
+ meta: filter.leaf ? /* @__PURE__ */ jsx4(Select, { size: "sm", label: "Operator", options: filter.ops, value: filter.op, onChange: (op) => ui4({ kind: "filterOp", index: filter.index, op }) }) : null,
4309
+ trailing: /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(CloseGlyph, { size: 11 }), label: filter.removeLabel, onClick: () => ui4({ kind: "removeFilter", index: filter.index }) })
4282
4310
  },
4283
4311
  filter.key
4284
4312
  )) }) : null,
@@ -4286,8 +4314,8 @@ function FieldsPanelView({ controller, showStats, manualApply }) {
4286
4314
  Toolbar4,
4287
4315
  {
4288
4316
  divided: false,
4289
- left: /* @__PURE__ */ jsx4(SegmentedControl4, { size: "sm", label: "Combinator", options: COMBINATORS2, value: view.combinator, onChange: (combinator) => ui3({ kind: "combinator", combinator }) }),
4290
- right: /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui3({ kind: "addGroup" }), children: "+ group" })
4317
+ left: /* @__PURE__ */ jsx4(SegmentedControl4, { size: "sm", label: "Combinator", options: COMBINATORS2, value: view.combinator, onChange: (combinator) => ui4({ kind: "combinator", combinator }) }),
4318
+ right: /* @__PURE__ */ jsx4(TextButton, { onClick: () => ui4({ kind: "addGroup" }), children: "+ group" })
4291
4319
  }
4292
4320
  )
4293
4321
  ]
@@ -5423,10 +5451,10 @@ function parseJsonPath(path) {
5423
5451
  }
5424
5452
  return steps;
5425
5453
  }
5426
- function findBracketEnd(text3, start) {
5454
+ function findBracketEnd(text4, start) {
5427
5455
  let quote = null;
5428
- for (let i = start + 1; i < text3.length; i += 1) {
5429
- const char = text3[i];
5456
+ for (let i = start + 1; i < text4.length; i += 1) {
5457
+ const char = text4[i];
5430
5458
  if (quote) {
5431
5459
  if (char === "\\") i += 1;
5432
5460
  else if (char === quote) quote = null;
@@ -5850,9 +5878,9 @@ function firstGraphqlError(errors) {
5850
5878
  }
5851
5879
 
5852
5880
  // src/data/connectors/executors/csv.ts
5853
- function sniffDelimiter(text3) {
5881
+ function sniffDelimiter(text4) {
5854
5882
  const candidates = [",", ";", " ", "|"];
5855
- const line = firstLogicalLine(text3);
5883
+ const line = firstLogicalLine(text4);
5856
5884
  let best = ",";
5857
5885
  let bestCount = 0;
5858
5886
  for (const candidate of candidates) {
@@ -5874,21 +5902,21 @@ function sniffDelimiter(text3) {
5874
5902
  }
5875
5903
  return best;
5876
5904
  }
5877
- function firstLogicalLine(text3) {
5905
+ function firstLogicalLine(text4) {
5878
5906
  let inQuotes = false;
5879
- for (let i = 0; i < text3.length; i += 1) {
5880
- const char = text3[i];
5907
+ for (let i = 0; i < text4.length; i += 1) {
5908
+ const char = text4[i];
5881
5909
  if (char === '"') {
5882
- if (inQuotes && text3[i + 1] === '"') i += 1;
5910
+ if (inQuotes && text4[i + 1] === '"') i += 1;
5883
5911
  else inQuotes = !inQuotes;
5884
5912
  } else if ((char === "\n" || char === "\r") && !inQuotes) {
5885
- return text3.slice(0, i);
5913
+ return text4.slice(0, i);
5886
5914
  }
5887
5915
  }
5888
- return text3;
5916
+ return text4;
5889
5917
  }
5890
- function parseCsv(text3, options = {}) {
5891
- const source = text3.charCodeAt(0) === 65279 ? text3.slice(1) : text3;
5918
+ function parseCsv(text4, options = {}) {
5919
+ const source = text4.charCodeAt(0) === 65279 ? text4.slice(1) : text4;
5892
5920
  const delimiter = options.delimiter && options.delimiter.length > 0 ? options.delimiter : sniffDelimiter(source);
5893
5921
  const quote = options.quote && options.quote.length > 0 ? options.quote : '"';
5894
5922
  const hasHeader = options.hasHeader ?? true;
@@ -5923,17 +5951,17 @@ function dedupe(names) {
5923
5951
  return count === 0 ? name : `${name}_${count + 1}`;
5924
5952
  });
5925
5953
  }
5926
- function scanRecords(text3, delimiter, quote) {
5954
+ function scanRecords(text4, delimiter, quote) {
5927
5955
  const records = [];
5928
5956
  let fields = [];
5929
5957
  let field = "";
5930
5958
  let inQuotes = false;
5931
5959
  let i = 0;
5932
- while (i < text3.length) {
5933
- const char = text3[i];
5960
+ while (i < text4.length) {
5961
+ const char = text4[i];
5934
5962
  if (inQuotes) {
5935
5963
  if (char === quote) {
5936
- if (text3[i + 1] === quote) {
5964
+ if (text4[i + 1] === quote) {
5937
5965
  field += quote;
5938
5966
  i += 2;
5939
5967
  continue;
@@ -5951,7 +5979,7 @@ function scanRecords(text3, delimiter, quote) {
5951
5979
  i += 1;
5952
5980
  continue;
5953
5981
  }
5954
- if (text3.startsWith(delimiter, i)) {
5982
+ if (text4.startsWith(delimiter, i)) {
5955
5983
  fields.push(field);
5956
5984
  field = "";
5957
5985
  i += delimiter.length;
@@ -5962,7 +5990,7 @@ function scanRecords(text3, delimiter, quote) {
5962
5990
  records.push(fields);
5963
5991
  fields = [];
5964
5992
  field = "";
5965
- i += char === "\r" && text3[i + 1] === "\n" ? 2 : 1;
5993
+ i += char === "\r" && text4[i + 1] === "\n" ? 2 : 1;
5966
5994
  continue;
5967
5995
  }
5968
5996
  field += char;
@@ -7099,28 +7127,34 @@ export {
7099
7127
  AGENT_HIDDEN_COMMANDS,
7100
7128
  ALL_AGGREGATES,
7101
7129
  ALL_CHART_TYPES,
7130
+ BEHAVIOURS as CHART_BEHAVIOURS,
7131
+ CHART_DECLARATION,
7102
7132
  CHART_EMPTY_FILL,
7103
7133
  CHART_PALETTE_STEPS,
7104
7134
  CHART_PANEL_ID,
7135
+ CHART_RUNTIME_UNITS,
7136
+ CHART_TYPE_LABELS,
7105
7137
  CONNECTORS_PANEL_ID,
7106
7138
  ChartController,
7107
7139
  ChartPanelView,
7140
+ ChartPlot,
7108
7141
  ConnectorTransportError,
7109
7142
  ConnectorsController,
7110
7143
  ConnectorsPanelView,
7144
+ DEFAULT_CHART_OPTIONS,
7111
7145
  DEFAULT_COLUMN_WIDTH,
7112
7146
  DEFAULT_PAGE_SIZE,
7113
7147
  DEFAULT_RANGES,
7114
7148
  EMPTY_LAYOUT,
7115
7149
  EXPIRY_SKEW_MS,
7116
- BEHAVIOURS2 as FIELDS_BEHAVIOURS,
7150
+ BEHAVIOURS3 as FIELDS_BEHAVIOURS,
7117
7151
  FIELDS_DECLARATION,
7118
7152
  FIELDS_PANEL_ID,
7119
7153
  FIELDS_RUNTIME_UNITS,
7120
7154
  FieldsController,
7121
7155
  FieldsPanelView,
7122
7156
  IMPLEMENTED_VIEW_MODES,
7123
- BEHAVIOURS as METRICS_BEHAVIOURS,
7157
+ BEHAVIOURS2 as METRICS_BEHAVIOURS,
7124
7158
  METRICS_DECLARATION,
7125
7159
  METRICS_PANEL_ID,
7126
7160
  METRICS_RUNTIME_UNITS,
@@ -7134,6 +7168,7 @@ export {
7134
7168
  TABLE_PANEL_ID,
7135
7169
  TableController,
7136
7170
  TablePanelView,
7171
+ applyChartUi,
7137
7172
  applyFieldsUi,
7138
7173
  applyMetricsUi,
7139
7174
  applyPrecision,
@@ -7145,6 +7180,9 @@ export {
7145
7180
  buildSelect,
7146
7181
  chartManifest,
7147
7182
  chartPanel,
7183
+ chartRuntimeComponents,
7184
+ chartViewManifest,
7185
+ chartViewState,
7148
7186
  clamp,
7149
7187
  classifyBrowserFetchFailure,
7150
7188
  classifyHttpStatus,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.13.10",
3
+ "version": "0.13.11",
4
4
  "description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -64,7 +64,7 @@
64
64
  "peerDependencies": {
65
65
  "@duckdb/duckdb-wasm": ">=1.28.0",
66
66
  "@xenosystem/block-sdk": ">=0.3.4 <1",
67
- "@xenosystem/components": ">=0.21.0 <1",
67
+ "@xenosystem/components": ">=0.21.1 <1",
68
68
  "@xenosystem/data-core": "^0.1.0",
69
69
  "@xenosystem/elements": ">=0.0.1",
70
70
  "@xenosystem/elements-react": ">=0.0.1",
@@ -81,7 +81,7 @@
81
81
  "@types/react": "^19.0.0",
82
82
  "@types/react-dom": "^19.0.0",
83
83
  "@xenosystem/block-sdk": "^0.3.4",
84
- "@xenosystem/components": "^0.21.0",
84
+ "@xenosystem/components": "^0.21.1",
85
85
  "@xenosystem/data-core": "^0.1.0",
86
86
  "@xenosystem/elements": "0.0.1",
87
87
  "@xenosystem/elements-react": "0.0.1",