@praxisui/charts 9.0.35 → 9.0.36

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/README.md CHANGED
@@ -125,7 +125,7 @@ Use the component with either local data or governed remote execution:
125
125
  - `pointClick`: raw renderer-neutral point evidence. Configured click actions are emitted separately through `pointAction`.
126
126
  - For categorical `praxis.stats` points, `data.key` remains the canonical bucket identity while `label` and the category field remain presentation evidence, including when distinct buckets share the same display label.
127
127
  - For time-series `praxis.stats` points, `data.start` (falling back to a valid temporal `data.key`) drives the time coordinate, `data.end` preserves the inclusive bucket boundary, and `data.label` remains presentation evidence. After the target is grounded from the governed filter schema, Page Builder composition can materialize a range input as `[data.start, data.end]`, guarded on both boundaries. Repeated labels therefore do not collapse distinct periods.
128
- - `selectionChange`: single-point selection evidence with canonical filters. Toggle, replacement and multi-select are not advertised by this runtime contract.
128
+ - `selectionChange`: single-point selection evidence with canonical filters. A repeated click on the active point emits `selected: false` with empty filters; clicking another point replaces the selection. Multi-select is not advertised by this runtime contract.
129
129
  - `drillDown` and `crossFilter`: structured action/filter payloads intended for Page Builder composition links and governed host orchestration.
130
130
  - Analytics projections with `crossFilter=true` must publish `bindings.primaryDimension.keyFilterField`. The analytics adapter maps the preserved raw row `key` to that public request field and fails closed when the binding is absent; labels and dimension naming conventions are never used as filter identity.
131
131
 
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-29T11:06:11.218Z",
3
+ "generatedAt": "2026-08-29T20:24:51.350Z",
4
4
  "packageName": "@praxisui/charts",
5
- "packageVersion": "9.0.35",
5
+ "packageVersion": "9.0.36",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 3,
@@ -720,7 +720,7 @@
720
720
  "label": "Selection Change",
721
721
  "direction": "output",
722
722
  "semanticKind": "event",
723
- "description": "Canonical selected point payload emitted when declarative chart selection is enabled.",
723
+ "description": "Canonical single-point selection payload. Repeating the active point emits selected=false with empty filters; selecting another point replaces it.",
724
724
  "cardinality": "stream",
725
725
  "schema": {
726
726
  "id": "PraxisChartSelectionEvent",
@@ -2541,7 +2541,7 @@
2541
2541
  "mapping-target-invalid",
2542
2542
  "unsafe-event-action"
2543
2543
  ],
2544
- "description": "Configures selectionChange as single-point selection evidence whose event key is governed by the operation."
2544
+ "description": "Configures selectionChange as single-point selection evidence whose event key is governed by the operation. Repeating the active point clears the selection and emits empty filters; selecting another point replaces it."
2545
2545
  }
2546
2546
  }
2547
2547
  ],
@@ -3305,9 +3305,9 @@
3305
3305
  {
3306
3306
  "chunkIndex": 20,
3307
3307
  "chunkKind": "authoring_manifest",
3308
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.4.0\",\"componentId\":\"praxis-chart\",\"ownerPackage\":\"@praxisui/charts\",\"configSchemaId\":\"PraxisXUiChartContract\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"pointClick.configure\",\"title\":\"Configure chart point click\",\"scope\":\"eventMapping\",\"targetKind\":\"pointClick\",\"target\":{\"kind\":\"pointClick\",\"resolver\":\"x-ui-chart-events-point-click\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-point-click-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.pointClick\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.pointClick\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures pointClick through the pointAction output while keeping pointClick as raw point evidence.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"point-click-action-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.pointClick\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"crossFilter.configure\",\"title\":\"Configure chart cross-filter\",\"scope\":\"eventMapping\",\"targetKind\":\"crossFilter\",\"target\":{\"kind\":\"crossFilter\",\"resolver\":\"x-ui-chart-events-cross-filter\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-cross-filter-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.crossFilter\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.crossFilter\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures crossFilter as a structured event action emitted through the crossFilter output with safe query-context filters to a governed target. For praxis.stats rows, key is governed bucket identity and label is presentation evidence; mappings may use key when the target schema accepts that identity.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"cross-filter-output-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.crossFilter\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"drilldown.configure\",\"title\":\"Configure chart drilldown\",\"scope\":\"eventMapping\",\"targetKind\":\"drilldown\",\"target\":{\"kind\":\"drilldown\",\"resolver\":\"x-ui-chart-events-drill-down\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-drilldown-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.drillDown\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.drillDown\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"drilldown-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures drillDown through the dedicated drillDown output with governed route/widget targets and structured field mappings.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"drilldown-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.drillDown\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"selection.configure\",\"title\":\"Configure chart selection\",\"scope\":\"selection\",\"targetKind\":\"selection\",\"target\":{\"kind\":\"selection\",\"resolver\":\"x-ui-chart-events-selection-change\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-selection-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.selectionChange\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.selectionChange\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures selectionChange as single-point selection evidence whose event key is governed by the operation.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"selection-output-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.selectionChange\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"legend.configure\",\"title\":\"Configure chart legend\",\"scope\":\"skin\",\"targetKind\":\"legend\",\"target\":{\"kind\":\"legend\",\"resolver\":\"x-ui-chart-legend-feature\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"enabled\"],\"properties\":{\"enabled\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"set-value\",\"path\":\"chartDocument.legend\"}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"feature-toggle-valid\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.legend\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]}]}",
3308
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.4.0\",\"componentId\":\"praxis-chart\",\"ownerPackage\":\"@praxisui/charts\",\"configSchemaId\":\"PraxisXUiChartContract\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"pointClick.configure\",\"title\":\"Configure chart point click\",\"scope\":\"eventMapping\",\"targetKind\":\"pointClick\",\"target\":{\"kind\":\"pointClick\",\"resolver\":\"x-ui-chart-events-point-click\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-point-click-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.pointClick\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.pointClick\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures pointClick through the pointAction output while keeping pointClick as raw point evidence.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"point-click-action-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.pointClick\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"crossFilter.configure\",\"title\":\"Configure chart cross-filter\",\"scope\":\"eventMapping\",\"targetKind\":\"crossFilter\",\"target\":{\"kind\":\"crossFilter\",\"resolver\":\"x-ui-chart-events-cross-filter\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-cross-filter-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.crossFilter\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.crossFilter\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures crossFilter as a structured event action emitted through the crossFilter output with safe query-context filters to a governed target. For praxis.stats rows, key is governed bucket identity and label is presentation evidence; mappings may use key when the target schema accepts that identity.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"cross-filter-output-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.crossFilter\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"drilldown.configure\",\"title\":\"Configure chart drilldown\",\"scope\":\"eventMapping\",\"targetKind\":\"drilldown\",\"target\":{\"kind\":\"drilldown\",\"resolver\":\"x-ui-chart-events-drill-down\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-drilldown-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.drillDown\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.drillDown\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"drilldown-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures drillDown through the dedicated drillDown output with governed route/widget targets and structured field mappings.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"drilldown-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.drillDown\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"selection.configure\",\"title\":\"Configure chart selection\",\"scope\":\"selection\",\"targetKind\":\"selection\",\"target\":{\"kind\":\"selection\",\"resolver\":\"x-ui-chart-events-selection-change\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"chart-event-selection-configure\",\"handlerContract\":{\"reads\":[\"chartDocument.events.selectionChange\",\"chartDocument.dimensions[]\",\"availableTargets[]\"],\"writes\":[\"chartDocument.events.selectionChange\"],\"identityKeys\":[\"availableTargets[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"action\"],\"properties\":{\"action\":{\"enum\":[\"filter-widget\",\"open-detail\",\"navigate\",\"update-context\",\"emit\"]},\"target\":{\"type\":\"string\"},\"mapping\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}},\"failureModes\":[\"target-not-in-catalog\",\"mapping-source-field-missing\",\"mapping-target-invalid\",\"unsafe-event-action\"],\"description\":\"Configures selectionChange as single-point selection evidence whose event key is governed by the operation. Repeating the active point clears the selection and emits empty filters; selecting another point replaces it.\"}}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"selection-output-structured\",\"event-target-governed\",\"event-mapping-fields-exist\",\"event-action-supported\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.events.selectionChange\"],\"submissionImpact\":\"affects-schema-backed-data\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"legend.configure\",\"title\":\"Configure chart legend\",\"scope\":\"skin\",\"targetKind\":\"legend\",\"target\":{\"kind\":\"legend\",\"resolver\":\"x-ui-chart-legend-feature\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"enabled\"],\"properties\":{\"enabled\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"set-value\",\"path\":\"chartDocument.legend\"}],\"destructive\":false,\"requiresConfirmation\":false,\"validators\":[\"feature-toggle-valid\",\"editor-runtime-round-trip\"],\"affectedPaths\":[\"chartDocument.legend\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]}]}",
3309
3309
  "sourcePointer": "projects/praxis-charts/src/lib/ai/praxis-charts-authoring-manifest.ts",
3310
- "contentHash": "293a0ff43d1ec235b6f145ed522fb38f769f9e458ffdd316df7a062d9e52e2d7",
3310
+ "contentHash": "86035e3cd9743a4412118dc65c4da27402520fd20b4540380941c2400fcc5024",
3311
3311
  "sourceKind": "component_definition",
3312
3312
  "sourceId": "praxis-chart",
3313
3313
  "corpusVersion": "1.0.0"
@@ -1877,6 +1877,7 @@ class PraxisChartComponent {
1877
1877
  runtimeChartDocument = signal(null, ...(ngDevMode ? [{ debugName: "runtimeChartDocument" }] : /* istanbul ignore next */ []));
1878
1878
  mappedRuntimeConfig = signal(null, ...(ngDevMode ? [{ debugName: "mappedRuntimeConfig" }] : /* istanbul ignore next */ []));
1879
1879
  chartDocumentMappingError = signal(null, ...(ngDevMode ? [{ debugName: "chartDocumentMappingError" }] : /* istanbul ignore next */ []));
1880
+ activeSelectionSignature = signal(null, ...(ngDevMode ? [{ debugName: "activeSelectionSignature" }] : /* istanbul ignore next */ []));
1880
1881
  fillContainerHeight = signal(false, ...(ngDevMode ? [{ debugName: "fillContainerHeight" }] : /* istanbul ignore next */ []));
1881
1882
  renderAttempt = signal(0, ...(ngDevMode ? [{ debugName: "renderAttempt" }] : /* istanbul ignore next */ []));
1882
1883
  resizeFrameId = null;
@@ -1889,6 +1890,7 @@ class PraxisChartComponent {
1889
1890
  editorSessionSubscriptions = [];
1890
1891
  remoteRequestSubscription = null;
1891
1892
  remoteRequestSequence = 0;
1893
+ previousSelectionScopeSignature = null;
1892
1894
  effectiveConfig = computed(() => {
1893
1895
  const base = this.applyInheritedTheme(this.mappedRuntimeConfig() ?? this.config(), this.inheritedTheme());
1894
1896
  const runtimeQueryContext = normalizePraxisDataQueryContext(this.queryContext());
@@ -2101,6 +2103,14 @@ class PraxisChartComponent {
2101
2103
  this.remoteRuntimeState.set('idle');
2102
2104
  this.remoteTechnicalError.set(null);
2103
2105
  });
2106
+ effect(() => {
2107
+ const signature = this.buildSelectionScopeSignature();
2108
+ if (signature === this.previousSelectionScopeSignature) {
2109
+ return;
2110
+ }
2111
+ this.previousSelectionScopeSignature = signature;
2112
+ this.activeSelectionSignature.set(null);
2113
+ });
2104
2114
  effect(() => {
2105
2115
  const nextState = this.loadState();
2106
2116
  if (this.currentLoadState() !== nextState) {
@@ -2362,7 +2372,9 @@ class PraxisChartComponent {
2362
2372
  const crossFilterAction = interactions.eventActions?.crossFilter;
2363
2373
  this.crossFilter.emit({
2364
2374
  chartId: config.id ?? event.chartId,
2365
- filters: this.buildEventFilters(config, event, crossFilterAction?.mapping),
2375
+ filters: selectionEvent.selected
2376
+ ? this.buildEventFilters(config, event, crossFilterAction?.mapping)
2377
+ : {},
2366
2378
  target: crossFilterAction?.target,
2367
2379
  action: crossFilterAction,
2368
2380
  source: selectionEvent,
@@ -2372,15 +2384,43 @@ class PraxisChartComponent {
2372
2384
  buildSelectionEvent(config, event) {
2373
2385
  const action = config.interactions?.eventActions?.selectionChange;
2374
2386
  const filters = this.buildEventFilters(config, event, action?.mapping);
2387
+ const signature = this.buildPointSelectionSignature(config, event);
2388
+ const selected = this.activeSelectionSignature() !== signature;
2389
+ this.activeSelectionSignature.set(selected ? signature : null);
2375
2390
  return {
2376
2391
  ...event,
2377
2392
  chartId: config.id ?? event.chartId,
2378
- selected: true,
2393
+ selected,
2379
2394
  mode: 'single',
2380
- filters,
2395
+ filters: selected ? filters : {},
2381
2396
  action,
2382
2397
  };
2383
2398
  }
2399
+ buildPointSelectionSignature(config, event) {
2400
+ const sourceValues = Object.entries(this.extractPointSourceValues(config, event))
2401
+ .sort(([left], [right]) => left.localeCompare(right));
2402
+ return JSON.stringify({
2403
+ chartId: config.id ?? event.chartId,
2404
+ seriesId: event.seriesId,
2405
+ seriesName: event.seriesName,
2406
+ category: event.category,
2407
+ sourceValues,
2408
+ });
2409
+ }
2410
+ buildSelectionScopeSignature() {
2411
+ const config = this.renderConfig();
2412
+ return JSON.stringify({
2413
+ id: config.id,
2414
+ type: config.type,
2415
+ axes: config.axes,
2416
+ series: config.series,
2417
+ dataSource: config.dataSource,
2418
+ interactions: config.interactions,
2419
+ filterCriteria: this.filterCriteria(),
2420
+ queryContext: normalizePraxisDataQueryContext(this.queryContext()),
2421
+ data: this.resolvedData(),
2422
+ });
2423
+ }
2384
2424
  buildEventFilters(config, event, mapping) {
2385
2425
  const sourceValues = this.extractPointSourceValues(config, event);
2386
2426
  if (!mapping || !Object.keys(mapping).length) {
@@ -8679,7 +8719,7 @@ const PRAXIS_CHART_PHASE1_PORTS = [
8679
8719
  label: 'Selection Change',
8680
8720
  direction: 'output',
8681
8721
  semanticKind: 'event',
8682
- description: 'Canonical selected point payload emitted when declarative chart selection is enabled.',
8722
+ description: 'Canonical single-point selection payload. Repeating the active point emits selected=false with empty filters; selecting another point replaces it.',
8683
8723
  cardinality: 'stream',
8684
8724
  schema: {
8685
8725
  id: 'PraxisChartSelectionEvent',
@@ -11459,7 +11499,7 @@ const PRAXIS_CHARTS_AUTHORING_MANIFEST = {
11459
11499
  identityKeys: ['availableTargets[].id'],
11460
11500
  inputSchema: { type: 'object', required: ['action'], properties: { action: { enum: ['filter-widget', 'open-detail', 'navigate', 'update-context', 'emit'] }, target: { type: 'string' }, mapping: { type: 'object', additionalProperties: { type: 'string' } } } },
11461
11501
  failureModes: ['target-not-in-catalog', 'mapping-source-field-missing', 'mapping-target-invalid', 'unsafe-event-action'],
11462
- description: 'Configures selectionChange as single-point selection evidence whose event key is governed by the operation.',
11502
+ description: 'Configures selectionChange as single-point selection evidence whose event key is governed by the operation. Repeating the active point clears the selection and emits empty filters; selecting another point replaces it.',
11463
11503
  } }],
11464
11504
  destructive: false,
11465
11505
  requiresConfirmation: false,
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@praxisui/charts",
3
- "version": "9.0.35",
3
+ "version": "9.0.36",
4
4
  "description": "Metadata-driven charts library for Praxis UI Angular with engine adapters and Apache ECharts as the initial renderer.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/core": "^9.0.35",
8
+ "@praxisui/core": "^9.0.36",
9
9
  "@angular/forms": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
- "@praxisui/table": "^9.0.35",
11
+ "@praxisui/table": "^9.0.36",
12
12
  "rxjs": "~7.8.0"
13
13
  },
14
14
  "dependencies": {
@@ -590,6 +590,7 @@ declare class PraxisChartComponent {
590
590
  private readonly runtimeChartDocument;
591
591
  private readonly mappedRuntimeConfig;
592
592
  private readonly chartDocumentMappingError;
593
+ private readonly activeSelectionSignature;
593
594
  private readonly fillContainerHeight;
594
595
  private readonly renderAttempt;
595
596
  private resizeFrameId;
@@ -602,6 +603,7 @@ declare class PraxisChartComponent {
602
603
  private editorSessionSubscriptions;
603
604
  private remoteRequestSubscription;
604
605
  private remoteRequestSequence;
606
+ private previousSelectionScopeSignature;
605
607
  readonly effectiveConfig: _angular_core.Signal<PraxisChartConfig>;
606
608
  readonly resolvedData: _angular_core.Signal<PraxisChartDataRow[]>;
607
609
  readonly resolvedHeight: _angular_core.Signal<string>;
@@ -636,6 +638,8 @@ declare class PraxisChartComponent {
636
638
  private asRecord;
637
639
  private handlePointClick;
638
640
  private buildSelectionEvent;
641
+ private buildPointSelectionSignature;
642
+ private buildSelectionScopeSignature;
639
643
  private buildEventFilters;
640
644
  private extractPointSourceValues;
641
645
  private extractPointMetricValue;