@praxisui/charts 9.0.34 → 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-29T01:52:55.015Z",
3
+ "generatedAt": "2026-08-29T20:24:51.350Z",
4
4
  "packageName": "@praxisui/charts",
5
- "packageVersion": "9.0.34",
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"
@@ -482,6 +482,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
482
482
  args: [{ providedIn: 'root' }]
483
483
  }] });
484
484
 
485
+ const PRAXIS_CHARTS_I18N_NAMESPACE = 'charts';
486
+
485
487
  class ChartContractNormalizerService {
486
488
  normalize(input) {
487
489
  let document = structuredClone(input);
@@ -1564,7 +1566,7 @@ class PraxisChartCanonicalContractMapperService {
1564
1566
  ? 'praxis.charts.runtime.comparisonCurrent'
1565
1567
  : 'praxis.charts.runtime.comparisonPrevious';
1566
1568
  const fallback = period === 'current' ? 'Current' : 'Previous';
1567
- return this.i18n?.t(key, undefined, fallback, 'charts') ?? fallback;
1569
+ return this.i18n?.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE) ?? fallback;
1568
1570
  }
1569
1571
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisChartCanonicalContractMapperService, deps: [{ token: ChartContractNormalizerService }, { token: ChartContractValidationService }, { token: i1.PraxisI18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
1570
1572
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisChartCanonicalContractMapperService, providedIn: 'root' });
@@ -1675,7 +1677,7 @@ class PraxisChartStatsApiService {
1675
1677
  }
1676
1678
  return value
1677
1679
  ? axisLabel
1678
- : this.i18n.t('praxis.charts.runtime.booleanFalseLabel', { label: axisLabel }, `Não ${axisLabel}`, 'charts');
1680
+ : this.i18n.t('praxis.charts.runtime.booleanFalseLabel', { label: axisLabel }, `Não ${axisLabel}`, PRAXIS_CHARTS_I18N_NAMESPACE);
1679
1681
  }
1680
1682
  readBooleanBucketValue(bucket) {
1681
1683
  if (typeof bucket.key === 'boolean') {
@@ -1875,6 +1877,7 @@ class PraxisChartComponent {
1875
1877
  runtimeChartDocument = signal(null, ...(ngDevMode ? [{ debugName: "runtimeChartDocument" }] : /* istanbul ignore next */ []));
1876
1878
  mappedRuntimeConfig = signal(null, ...(ngDevMode ? [{ debugName: "mappedRuntimeConfig" }] : /* istanbul ignore next */ []));
1877
1879
  chartDocumentMappingError = signal(null, ...(ngDevMode ? [{ debugName: "chartDocumentMappingError" }] : /* istanbul ignore next */ []));
1880
+ activeSelectionSignature = signal(null, ...(ngDevMode ? [{ debugName: "activeSelectionSignature" }] : /* istanbul ignore next */ []));
1878
1881
  fillContainerHeight = signal(false, ...(ngDevMode ? [{ debugName: "fillContainerHeight" }] : /* istanbul ignore next */ []));
1879
1882
  renderAttempt = signal(0, ...(ngDevMode ? [{ debugName: "renderAttempt" }] : /* istanbul ignore next */ []));
1880
1883
  resizeFrameId = null;
@@ -1887,6 +1890,7 @@ class PraxisChartComponent {
1887
1890
  editorSessionSubscriptions = [];
1888
1891
  remoteRequestSubscription = null;
1889
1892
  remoteRequestSequence = 0;
1893
+ previousSelectionScopeSignature = null;
1890
1894
  effectiveConfig = computed(() => {
1891
1895
  const base = this.applyInheritedTheme(this.mappedRuntimeConfig() ?? this.config(), this.inheritedTheme());
1892
1896
  const runtimeQueryContext = normalizePraxisDataQueryContext(this.queryContext());
@@ -2010,33 +2014,18 @@ class PraxisChartComponent {
2010
2014
  emptyTitle = computed(() => this.i18n.resolve(this.renderConfig().emptyState?.title), ...(ngDevMode ? [{ debugName: "emptyTitle" }] : /* istanbul ignore next */ []));
2011
2015
  emptyDescription = computed(() => this.i18n.resolve(this.renderConfig().emptyState?.description), ...(ngDevMode ? [{ debugName: "emptyDescription" }] : /* istanbul ignore next */ []));
2012
2016
  errorTitle = computed(() => this.chartDocumentMappingError()
2013
- ? this.i18n.resolve({
2014
- key: 'praxis.charts.runtime.invalidDocumentTitle',
2015
- text: 'Chart configuration is invalid',
2016
- })
2017
+ ? this.t('praxis.charts.runtime.invalidDocumentTitle', 'Chart configuration is invalid')
2017
2018
  : this.dataDiagnostic()
2018
- ? this.i18n.resolve({
2019
- key: 'praxis.charts.runtime.invalidDataTitle',
2020
- text: 'Chart data is incompatible with its canonical configuration',
2021
- })
2019
+ ? this.t('praxis.charts.runtime.invalidDataTitle', 'Chart data is incompatible with its canonical configuration')
2022
2020
  : this.i18n.resolve(this.renderConfig().state?.error?.title)
2023
- || this.i18n.resolve({
2024
- key: 'praxis.charts.runtime.remoteErrorTitle',
2025
- text: 'Não foi possível carregar os dados do gráfico',
2026
- }), ...(ngDevMode ? [{ debugName: "errorTitle" }] : /* istanbul ignore next */ []));
2021
+ || this.t('praxis.charts.runtime.remoteErrorTitle', 'Não foi possível carregar os dados do gráfico'), ...(ngDevMode ? [{ debugName: "errorTitle" }] : /* istanbul ignore next */ []));
2027
2022
  errorDescription = computed(() => this.chartDocumentMappingError()
2028
- ? this.i18n.resolve({
2029
- key: 'praxis.charts.runtime.invalidDocumentDescription',
2030
- text: 'The canonical chart document could not be mapped to the Praxis chart runtime. Review the chart contract before continuing.',
2031
- })
2023
+ ? this.t('praxis.charts.runtime.invalidDocumentDescription', 'The canonical chart document could not be mapped to the Praxis chart runtime. Review the chart contract before continuing.')
2032
2024
  : this.dataDiagnostic()
2033
2025
  ? this.resolveDataDiagnosticDescription(this.dataDiagnostic())
2034
2026
  : this.i18n.resolve(this.renderConfig().state?.error?.description)
2035
- || this.i18n.resolve({
2036
- key: 'praxis.charts.runtime.remoteErrorDescription',
2037
- text: 'Revise a fonte de dados e os filtros antes de continuar.',
2038
- }), ...(ngDevMode ? [{ debugName: "errorDescription" }] : /* istanbul ignore next */ []));
2039
- editChartLabel = computed(() => this.i18n.resolve({ key: 'praxis.charts.runtime.editChart', text: 'Edit chart settings' }), ...(ngDevMode ? [{ debugName: "editChartLabel" }] : /* istanbul ignore next */ []));
2027
+ || this.t('praxis.charts.runtime.remoteErrorDescription', 'Revise a fonte de dados e os filtros antes de continuar.'), ...(ngDevMode ? [{ debugName: "errorDescription" }] : /* istanbul ignore next */ []));
2028
+ editChartLabel = computed(() => this.t('praxis.charts.runtime.editChart', 'Edit chart settings'), ...(ngDevMode ? [{ debugName: "editChartLabel" }] : /* istanbul ignore next */ []));
2040
2029
  loadState = computed(() => {
2041
2030
  if (this.chartDocumentMappingError()) {
2042
2031
  return 'error';
@@ -2114,6 +2103,14 @@ class PraxisChartComponent {
2114
2103
  this.remoteRuntimeState.set('idle');
2115
2104
  this.remoteTechnicalError.set(null);
2116
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
+ });
2117
2114
  effect(() => {
2118
2115
  const nextState = this.loadState();
2119
2116
  if (this.currentLoadState() !== nextState) {
@@ -2232,7 +2229,11 @@ class PraxisChartComponent {
2232
2229
  text: 'The gauge value is outside the configured scale. Review the metric and scale instead of clamping the value.',
2233
2230
  },
2234
2231
  };
2235
- return this.i18n.resolve(descriptions[diagnostic.code]);
2232
+ const description = descriptions[diagnostic.code];
2233
+ return this.t(description.key, description.text);
2234
+ }
2235
+ t(key, fallback) {
2236
+ return this.i18n.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE);
2236
2237
  }
2237
2238
  canOpenConfigEditor() {
2238
2239
  return this.enableCustomization() && !!this.settingsPanel && !!this.runtimeChartDocument();
@@ -2371,7 +2372,9 @@ class PraxisChartComponent {
2371
2372
  const crossFilterAction = interactions.eventActions?.crossFilter;
2372
2373
  this.crossFilter.emit({
2373
2374
  chartId: config.id ?? event.chartId,
2374
- filters: this.buildEventFilters(config, event, crossFilterAction?.mapping),
2375
+ filters: selectionEvent.selected
2376
+ ? this.buildEventFilters(config, event, crossFilterAction?.mapping)
2377
+ : {},
2375
2378
  target: crossFilterAction?.target,
2376
2379
  action: crossFilterAction,
2377
2380
  source: selectionEvent,
@@ -2381,15 +2384,43 @@ class PraxisChartComponent {
2381
2384
  buildSelectionEvent(config, event) {
2382
2385
  const action = config.interactions?.eventActions?.selectionChange;
2383
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);
2384
2390
  return {
2385
2391
  ...event,
2386
2392
  chartId: config.id ?? event.chartId,
2387
- selected: true,
2393
+ selected,
2388
2394
  mode: 'single',
2389
- filters,
2395
+ filters: selected ? filters : {},
2390
2396
  action,
2391
2397
  };
2392
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
+ }
2393
2424
  buildEventFilters(config, event, mapping) {
2394
2425
  const sourceValues = this.extractPointSourceValues(config, event);
2395
2426
  if (!mapping || !Object.keys(mapping).length) {
@@ -4133,7 +4164,7 @@ class AnalyticsChartConfigAdapterService {
4133
4164
  ? 'praxis.charts.runtime.comparisonCurrent'
4134
4165
  : 'praxis.charts.runtime.comparisonPrevious';
4135
4166
  const fallback = period === 'current' ? 'Current' : 'Previous';
4136
- return this.i18n?.t(key, undefined, fallback, 'charts') ?? fallback;
4167
+ return this.i18n?.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE) ?? fallback;
4137
4168
  }
4138
4169
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnalyticsChartConfigAdapterService, deps: [{ token: i1.PraxisI18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
4139
4170
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AnalyticsChartConfigAdapterService, providedIn: 'root' });
@@ -4365,7 +4396,7 @@ class PraxisAnalyticsPresentationComponent {
4365
4396
  return resolved || null;
4366
4397
  }
4367
4398
  t(key, fallback) {
4368
- return this.i18n.t(key, undefined, fallback, 'charts');
4399
+ return this.i18n.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE);
4369
4400
  }
4370
4401
  message(key, fallback, values) {
4371
4402
  return Object.entries(values).reduce((message, [name, value]) => message.replaceAll(`{${name}}`, value), this.t(key, fallback));
@@ -5902,7 +5933,7 @@ function createPraxisChartsI18nConfig(options = {}) {
5902
5933
  locale: options.locale,
5903
5934
  fallbackLocale: options.fallbackLocale ?? 'pt-BR',
5904
5935
  namespaces: {
5905
- charts: localeDictionaries,
5936
+ [PRAXIS_CHARTS_I18N_NAMESPACE]: localeDictionaries,
5906
5937
  },
5907
5938
  };
5908
5939
  }
@@ -7874,7 +7905,7 @@ class PraxisChartConfigEditor {
7874
7905
  return `${issue.code}:${issue.field}`;
7875
7906
  }
7876
7907
  t(key, fallback) {
7877
- return this.i18n.resolve(resolvePraxisChartsText({ key, text: fallback }, fallback));
7908
+ return this.i18n.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE);
7878
7909
  }
7879
7910
  doc() {
7880
7911
  return this.currentDocument();
@@ -8305,7 +8336,7 @@ class PraxisChartWidgetConfigEditor {
8305
8336
  this.updateValidity();
8306
8337
  }
8307
8338
  t(key, fallback) {
8308
- return this.i18n.resolve(resolvePraxisChartsText({ key, text: fallback }, fallback));
8339
+ return this.i18n.t(key, undefined, fallback, PRAXIS_CHARTS_I18N_NAMESPACE);
8309
8340
  }
8310
8341
  contextDiagnosticText(diagnostic) {
8311
8342
  switch (diagnostic.code) {
@@ -8688,7 +8719,7 @@ const PRAXIS_CHART_PHASE1_PORTS = [
8688
8719
  label: 'Selection Change',
8689
8720
  direction: 'output',
8690
8721
  semanticKind: 'event',
8691
- 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.',
8692
8723
  cardinality: 'stream',
8693
8724
  schema: {
8694
8725
  id: 'PraxisChartSelectionEvent',
@@ -9515,6 +9546,7 @@ function provideChartEngineFactory(options) {
9515
9546
  }
9516
9547
  function providePraxisCharts(options = {}) {
9517
9548
  return [
9549
+ ...providePraxisChartsI18n(),
9518
9550
  provideChartEngineFactory(options),
9519
9551
  providePraxisChartsMetadata(),
9520
9552
  providePraxisChartDrilldownPanelMetadata(),
@@ -11467,7 +11499,7 @@ const PRAXIS_CHARTS_AUTHORING_MANIFEST = {
11467
11499
  identityKeys: ['availableTargets[].id'],
11468
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' } } } },
11469
11501
  failureModes: ['target-not-in-catalog', 'mapping-source-field-missing', 'mapping-target-invalid', 'unsafe-event-action'],
11470
- 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.',
11471
11503
  } }],
11472
11504
  destructive: false,
11473
11505
  requiresConfirmation: false,
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@praxisui/charts",
3
- "version": "9.0.34",
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.34",
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.34",
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>;
@@ -627,6 +629,7 @@ declare class PraxisChartComponent {
627
629
  readonly loadState: _angular_core.Signal<PraxisChartLoadState>;
628
630
  constructor();
629
631
  private resolveDataDiagnosticDescription;
632
+ private t;
630
633
  canOpenConfigEditor(): boolean;
631
634
  openConfigEditor(): Promise<void>;
632
635
  private resolveConfigEditorContext;
@@ -635,6 +638,8 @@ declare class PraxisChartComponent {
635
638
  private asRecord;
636
639
  private handlePointClick;
637
640
  private buildSelectionEvent;
641
+ private buildPointSelectionSignature;
642
+ private buildSelectionScopeSignature;
638
643
  private buildEventFilters;
639
644
  private extractPointSourceValues;
640
645
  private extractPointMetricValue;