@praxisui/rich-content 10.0.0-rc.40 → 10.0.0-rc.41

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
@@ -130,6 +130,12 @@ then resolves bindings and Json Logic without mutating the authored document.
130
130
 
131
131
  The runtime supports semantic presentation nodes such as text, badges, icons, cards, callouts, key/value lists, stats, tabs, timelines, lookup surfaces, record summaries, action cards, media blocks and presets. Use official docs for the full node vocabulary.
132
132
 
133
+ Relational and summary nodes can attach governed `ResourceQuickViewBinding` (`[praxisQuickView]`) so operators can inspect referenced entities in place without leaving the document surface:
134
+ - `recordReference` nodes (`data-testid="rich-record-reference-trigger"`) and `timeline` item/sub-item badges (`item.quickView`).
135
+ - `keyValueList` items (`item.quickView`, `data-testid="rich-key-value-quick-view-trigger"`).
136
+ - `propertySheet` / `dynamicForm` items (`item.quickView`, `data-testid="rich-property-sheet-quick-view-trigger"`), including automatic synthesis via `resolveFieldQuickViewBinding(field)` when items are resolved from a resource schema.
137
+ - `recordSummary` fields (`field.quickView`, `data-testid="rich-record-summary-field-quick-view-trigger"`).
138
+
133
139
  Card nodes (`type: 'card'`) support `media.kind` values `'image'`, `'video'`, `'icon'`, `'avatar'`, `'telemetry'`, `'lottie'`, and `'component'`. When `media.kind === 'component'`, the runtime materializes the component registered in `ComponentMetadataRegistry` under `media.componentId` via `DynamicWidgetLoaderDirective`, forwarding `media.componentInputs` and the active `RichContent` `[context]` so `${...}` template expressions inside `componentInputs` resolve reactively against host/page data sources. Optional `media.width`, `media.height`, `media.aspectRatio`, `media.placement`, and `media.verticalAlign` govern the media slot geometry without custom CSS:
134
140
 
135
141
  ```json
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-26T18:09:20.136Z",
3
+ "generatedAt": "2026-10-27T22:14:23.237Z",
4
4
  "packageName": "@praxisui/rich-content",
5
- "packageVersion": "10.0.0-rc.40",
5
+ "packageVersion": "10.0.0-rc.41",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -781,6 +781,12 @@ function validateKeyValueItems(value, path, issues) {
781
781
  validateOptionalString(item, 'badge', `${path}[${index}]`, issues);
782
782
  validateOptionalExpressionPath(item, 'badgeExpr', `${path}[${index}]`, issues);
783
783
  validateOptionalString(item, 'icon', `${path}[${index}]`, issues);
784
+ if (item['quickView'] !== undefined) {
785
+ const qvValidation = validateResourceQuickViewBinding(item['quickView']);
786
+ if (!qvValidation.valid) {
787
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
788
+ }
789
+ }
784
790
  });
785
791
  }
786
792
  function validateRecordSummaryFields(value, path, issues) {
@@ -798,6 +804,12 @@ function validateRecordSummaryFields(value, path, issues) {
798
804
  validateOptionalExpressionPath(field, 'labelExpr', `${path}[${index}]`, issues);
799
805
  validateOptionalString(field, 'value', `${path}[${index}]`, issues);
800
806
  validateOptionalExpressionPath(field, 'valueExpr', `${path}[${index}]`, issues);
807
+ if (field['quickView'] !== undefined) {
808
+ const qvValidation = validateResourceQuickViewBinding(field['quickView']);
809
+ if (!qvValidation.valid) {
810
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
811
+ }
812
+ }
801
813
  });
802
814
  }
803
815
  function validateLookupResultFields(value, path, issues) {
@@ -838,6 +850,12 @@ function validatePropertySheetItems(value, path, issues) {
838
850
  validateOptionalExpressionPath(item, 'hintExpr', `${path}[${index}]`, issues);
839
851
  validateOptionalString(item, 'icon', `${path}[${index}]`, issues);
840
852
  validateEnum(item, 'tone', ['neutral', 'info', 'success', 'warning', 'danger'], `${path}[${index}]`, issues, false);
853
+ if (item['quickView'] !== undefined) {
854
+ const qvValidation = validateResourceQuickViewBinding(item['quickView']);
855
+ if (!qvValidation.valid) {
856
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
857
+ }
858
+ }
841
859
  });
842
860
  }
843
861
  function validateStatGroupItems(value, path, issues) {
@@ -1003,6 +1021,12 @@ function validateTimelineItem(item, itemPath, issues, state, depth = 1) {
1003
1021
  if (record['action'] !== undefined) {
1004
1022
  validateActionRef(record['action'], `${itemPath}.action`, issues);
1005
1023
  }
1024
+ if (record['quickView'] !== undefined) {
1025
+ const qvValidation = validateResourceQuickViewBinding(record['quickView']);
1026
+ if (!qvValidation.valid) {
1027
+ addIssue(issues, `${itemPath}.quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
1028
+ }
1029
+ }
1006
1030
  if (record['children'] !== undefined) {
1007
1031
  validateTimelineItems(record['children'], `${itemPath}.children`, issues, state, depth + 1);
1008
1032
  }
@@ -4,7 +4,7 @@ import * as i2 from '@angular/material/menu';
4
4
  import { MatMenuModule } from '@angular/material/menu';
5
5
  import * as i0 from '@angular/core';
6
6
  import { InjectionToken, inject, Injectable, LOCALE_ID, signal, input, EventEmitter, computed, Output, Input, ChangeDetectionStrategy, Component, ChangeDetectorRef, ENVIRONMENT_INITIALIZER } from '@angular/core';
7
- import { providePraxisI18n, PraxisI18nService, PraxisJsonLogicService, GlobalActionService, SchemaNormalizerService, GenericCrudService, ResourceDiscoveryService, SCHEMA_METADATA_CLIENT_OPTIONS, normalizeCardMediaAspectRatio, MemoryCacheAdapter, SchemaMetadataClient, isUnresolvedTemplateToken, applyDeclarativeValuePipe, DynamicWidgetLoaderDirective, PraxisQuickViewTriggerDirective, validateResourceQuickViewBinding, ComponentMetadataRegistry, SETTINGS_PANEL_DATA, generateId, PRAXIS_QUICK_VIEW_BODY_RENDERER } from '@praxisui/core';
7
+ import { providePraxisI18n, PraxisI18nService, PraxisJsonLogicService, GlobalActionService, SchemaNormalizerService, GenericCrudService, ResourceDiscoveryService, SCHEMA_METADATA_CLIENT_OPTIONS, normalizeCardMediaAspectRatio, resolveFieldQuickViewBinding, MemoryCacheAdapter, SchemaMetadataClient, isUnresolvedTemplateToken, applyDeclarativeValuePipe, DynamicWidgetLoaderDirective, PraxisQuickViewTriggerDirective, validateResourceQuickViewBinding, ComponentMetadataRegistry, SETTINGS_PANEL_DATA, generateId, PRAXIS_QUICK_VIEW_BODY_RENDERER } from '@praxisui/core';
8
8
  import { firstValueFrom, BehaviorSubject } from 'rxjs';
9
9
  import * as i2$1 from '@angular/forms';
10
10
  import { FormsModule } from '@angular/forms';
@@ -2006,7 +2006,10 @@ class PraxisRichContent {
2006
2006
  seenIds.add(id);
2007
2007
  const rawValue = dataRecord[id];
2008
2008
  const formatted = this.formatPropertyValue(rawValue, field);
2009
- items.push({
2009
+ const fieldQuickView = rawValue !== undefined && rawValue !== null && rawValue !== ''
2010
+ ? (resolveFieldQuickViewBinding(field) ?? undefined)
2011
+ : undefined;
2012
+ const generatedItem = {
2010
2013
  id,
2011
2014
  label: field.label || this.formatCamelCaseLabel(id),
2012
2015
  value: formatted.value,
@@ -2015,7 +2018,13 @@ class PraxisRichContent {
2015
2018
  tone: formatted.tone ??
2016
2019
  field.presentation?.tone ??
2017
2020
  'neutral',
2018
- });
2021
+ ...(fieldQuickView ? { quickView: fieldQuickView } : {}),
2022
+ };
2023
+ if (fieldQuickView && Object.keys(dataRecord).length > 0) {
2024
+ generatedItem['sourceRecord'] =
2025
+ dataRecord;
2026
+ }
2027
+ items.push(generatedItem);
2019
2028
  }
2020
2029
  }
2021
2030
  else if (!hasExplicitItems && Object.keys(dataRecord).length > 0) {
@@ -2043,7 +2052,8 @@ class PraxisRichContent {
2043
2052
  const existingIdx = items.findIndex((it) => it.id === explicitId);
2044
2053
  if (existingIdx !== -1) {
2045
2054
  const existing = items[existingIdx];
2046
- items[existingIdx] = {
2055
+ const mergedQuickView = explicitItem.quickView ?? existing.quickView;
2056
+ const mergedItem = {
2047
2057
  ...existing,
2048
2058
  label: (explicitItem.label !== undefined && explicitItem.label !== '') ||
2049
2059
  explicitItem.labelExpr
@@ -2056,18 +2066,35 @@ class PraxisRichContent {
2056
2066
  hint: explicitHint ?? existing.hint,
2057
2067
  icon: explicitItem.icon ?? existing.icon,
2058
2068
  tone: explicitItem.tone ?? existing.tone,
2069
+ ...(mergedQuickView ? { quickView: mergedQuickView } : {}),
2059
2070
  };
2071
+ const sourceRec = explicitItem['sourceRecord'] ??
2072
+ existing['sourceRecord'] ??
2073
+ (Object.keys(dataRecord).length > 0 ? dataRecord : undefined);
2074
+ if (mergedQuickView && sourceRec) {
2075
+ mergedItem['sourceRecord'] =
2076
+ sourceRec;
2077
+ }
2078
+ items[existingIdx] = mergedItem;
2060
2079
  }
2061
2080
  }
2062
2081
  else {
2063
- items.push({
2082
+ const createdItem = {
2064
2083
  id: explicitId,
2065
2084
  label: explicitLabel,
2066
2085
  value: explicitValue,
2067
2086
  hint: explicitHint ?? undefined,
2068
2087
  icon: explicitItem.icon,
2069
2088
  tone: explicitItem.tone ?? 'neutral',
2070
- });
2089
+ ...(explicitItem.quickView ? { quickView: explicitItem.quickView } : {}),
2090
+ };
2091
+ const sourceRec = explicitItem['sourceRecord'] ??
2092
+ (Object.keys(dataRecord).length > 0 ? dataRecord : undefined);
2093
+ if (explicitItem.quickView && sourceRec) {
2094
+ createdItem['sourceRecord'] =
2095
+ sourceRec;
2096
+ }
2097
+ items.push(createdItem);
2071
2098
  }
2072
2099
  }
2073
2100
  }
@@ -2314,9 +2341,32 @@ class PraxisRichContent {
2314
2341
  '');
2315
2342
  }
2316
2343
  resolveStatItemValue(item) {
2317
- return (this.resolveValue(item.valueExpr) ??
2344
+ const raw = this.resolveValue(item.valueExpr) ??
2318
2345
  this.resolveLiteralText(item.value) ??
2319
- '');
2346
+ '';
2347
+ if (!raw) {
2348
+ return '';
2349
+ }
2350
+ const normalized = raw.trim().toLowerCase();
2351
+ const statusMap = {
2352
+ success: 'Atualizado',
2353
+ loading: 'Carregando',
2354
+ empty: 'Sem registros',
2355
+ error: 'Erro',
2356
+ cancelled: 'Cancelado',
2357
+ idle: 'Pronto',
2358
+ };
2359
+ if (statusMap[normalized]) {
2360
+ return statusMap[normalized];
2361
+ }
2362
+ const format = item.format;
2363
+ if (format === 'integer') {
2364
+ const numeric = Number(raw);
2365
+ if (Number.isFinite(numeric)) {
2366
+ return new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 0 }).format(Math.round(numeric));
2367
+ }
2368
+ }
2369
+ return raw;
2320
2370
  }
2321
2371
  resolveStatItemCaption(item) {
2322
2372
  return (this.resolveValue(item.captionExpr) ??
@@ -2909,6 +2959,8 @@ class PraxisRichContent {
2909
2959
  else {
2910
2960
  delete materialized.children;
2911
2961
  }
2962
+ materialized.sourceRecord =
2963
+ entry;
2912
2964
  return materialized;
2913
2965
  }
2914
2966
  interpolateScopedPayload(scopedCtx, payload) {
@@ -3081,7 +3133,8 @@ class PraxisRichContent {
3081
3133
  return null;
3082
3134
  }
3083
3135
  const children = this.resolveTimelineItemChildren(item);
3084
- if (children.some((child) => !!child.action)) {
3136
+ if (item.quickView ||
3137
+ children.some((child) => !!child.action || !!child.quickView)) {
3085
3138
  return 'group';
3086
3139
  }
3087
3140
  return 'button';
@@ -4144,15 +4197,38 @@ class PraxisRichContent {
4144
4197
  {{ resolveKeyValueLabel(item) }}
4145
4198
  </dt>
4146
4199
  <dd class="prx-rich-key-value-list__value">
4147
- @if (resolveKeyValueIcon(item); as kvIcon) {
4148
- <span
4149
- class="material-symbols-outlined prx-rich-key-value-list__icon"
4150
- aria-hidden="true"
4200
+ @if (item.quickView) {
4201
+ <button
4202
+ type="button"
4203
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
4204
+ [praxisQuickView]="item.quickView"
4205
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? $any(node).sourceRecord ?? context()"
4206
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
4207
+ data-testid="rich-key-value-quick-view-trigger"
4151
4208
  >
4152
- {{ kvIcon }}
4153
- </span>
4209
+ @if (resolveKeyValueIcon(item); as kvIcon) {
4210
+ <span
4211
+ class="material-symbols-outlined prx-rich-key-value-list__icon"
4212
+ aria-hidden="true"
4213
+ >
4214
+ {{ kvIcon }}
4215
+ </span>
4216
+ }
4217
+ <span class="prx-rich-record-reference__label">{{
4218
+ resolveKeyValueValue(item)
4219
+ }}</span>
4220
+ </button>
4221
+ } @else {
4222
+ @if (resolveKeyValueIcon(item); as kvIcon) {
4223
+ <span
4224
+ class="material-symbols-outlined prx-rich-key-value-list__icon"
4225
+ aria-hidden="true"
4226
+ >
4227
+ {{ kvIcon }}
4228
+ </span>
4229
+ }
4230
+ {{ resolveKeyValueValue(item) }}
4154
4231
  }
4155
- {{ resolveKeyValueValue(item) }}
4156
4232
  @if (resolveKeyValueBadge(item); as kvBadge) {
4157
4233
  <span class="prx-rich-badge">{{ kvBadge }}</span>
4158
4234
  }
@@ -4227,7 +4303,22 @@ class PraxisRichContent {
4227
4303
  {{ resolvePropertySheetLabel(item) }}
4228
4304
  </dt>
4229
4305
  <dd class="prx-rich-property-sheet__value">
4230
- {{ resolvePropertySheetValue(item) }}
4306
+ @if (item.quickView) {
4307
+ <button
4308
+ type="button"
4309
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
4310
+ [praxisQuickView]="item.quickView"
4311
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? $any(node).sourceRecord ?? context()"
4312
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
4313
+ data-testid="rich-property-sheet-quick-view-trigger"
4314
+ >
4315
+ <span class="prx-rich-record-reference__label">{{
4316
+ resolvePropertySheetValue(item)
4317
+ }}</span>
4318
+ </button>
4319
+ } @else {
4320
+ {{ resolvePropertySheetValue(item) }}
4321
+ }
4231
4322
  </dd>
4232
4323
  @if (resolvePropertySheetHint(item); as propertyHint) {
4233
4324
  <div class="prx-rich-property-sheet__hint">
@@ -4496,7 +4587,24 @@ class PraxisRichContent {
4496
4587
  ) {
4497
4588
  <div class="prx-rich-record-summary__field">
4498
4589
  <dt>{{ resolveRecordSummaryFieldLabel(field) }}</dt>
4499
- <dd>{{ resolveRecordSummaryFieldValue(field) }}</dd>
4590
+ <dd>
4591
+ @if (field.quickView) {
4592
+ <button
4593
+ type="button"
4594
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
4595
+ [praxisQuickView]="field.quickView"
4596
+ [praxisQuickViewRecord]="$any(field).sourceRecord ?? $any(node).sourceRecord ?? context()"
4597
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
4598
+ data-testid="rich-record-summary-field-quick-view-trigger"
4599
+ >
4600
+ <span class="prx-rich-record-reference__label">{{
4601
+ resolveRecordSummaryFieldValue(field)
4602
+ }}</span>
4603
+ </button>
4604
+ } @else {
4605
+ {{ resolveRecordSummaryFieldValue(field) }}
4606
+ }
4607
+ </dd>
4500
4608
  </div>
4501
4609
  }
4502
4610
  </dl>
@@ -5868,18 +5976,37 @@ class PraxisRichContent {
5868
5976
  <div
5869
5977
  class="prx-rich-timeline__item-badge"
5870
5978
  >
5871
- <span
5872
- class="prx-rich-badge"
5873
- [attr.data-tone]="
5874
- resolveTimelineItemBadgeTone(item)
5875
- "
5876
- [ngClass]="
5877
- resolveTimelineItemBadgeClasses(
5878
- item
5879
- )
5880
- "
5881
- >{{ itemBadge }}</span
5882
- >
5979
+ @if (item.quickView) {
5980
+ <button
5981
+ type="button"
5982
+ class="prx-rich-badge prx-rich-badge--interactive"
5983
+ [attr.data-tone]="
5984
+ resolveTimelineItemBadgeTone(item)
5985
+ "
5986
+ [ngClass]="
5987
+ resolveTimelineItemBadgeClasses(
5988
+ item
5989
+ )
5990
+ "
5991
+ [praxisQuickView]="item.quickView"
5992
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? context()"
5993
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
5994
+ data-testid="rich-timeline-badge-quick-view-trigger"
5995
+ >{{ itemBadge }}</button>
5996
+ } @else {
5997
+ <span
5998
+ class="prx-rich-badge"
5999
+ [attr.data-tone]="
6000
+ resolveTimelineItemBadgeTone(item)
6001
+ "
6002
+ [ngClass]="
6003
+ resolveTimelineItemBadgeClasses(
6004
+ item
6005
+ )
6006
+ "
6007
+ >{{ itemBadge }}</span
6008
+ >
6009
+ }
5883
6010
  </div>
5884
6011
  }
5885
6012
  @if (
@@ -5955,16 +6082,33 @@ class PraxisRichContent {
5955
6082
  as itemBadge
5956
6083
  ) {
5957
6084
  <div class="prx-rich-timeline__item-badge">
5958
- <span
5959
- class="prx-rich-badge"
5960
- [attr.data-tone]="
5961
- resolveTimelineItemBadgeTone(item)
5962
- "
5963
- [ngClass]="
5964
- resolveTimelineItemBadgeClasses(item)
5965
- "
5966
- >{{ itemBadge }}</span
5967
- >
6085
+ @if (item.quickView) {
6086
+ <button
6087
+ type="button"
6088
+ class="prx-rich-badge prx-rich-badge--interactive"
6089
+ [attr.data-tone]="
6090
+ resolveTimelineItemBadgeTone(item)
6091
+ "
6092
+ [ngClass]="
6093
+ resolveTimelineItemBadgeClasses(item)
6094
+ "
6095
+ [praxisQuickView]="item.quickView"
6096
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? context()"
6097
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
6098
+ data-testid="rich-timeline-badge-quick-view-trigger"
6099
+ >{{ itemBadge }}</button>
6100
+ } @else {
6101
+ <span
6102
+ class="prx-rich-badge"
6103
+ [attr.data-tone]="
6104
+ resolveTimelineItemBadgeTone(item)
6105
+ "
6106
+ [ngClass]="
6107
+ resolveTimelineItemBadgeClasses(item)
6108
+ "
6109
+ >{{ itemBadge }}</span
6110
+ >
6111
+ }
5968
6112
  </div>
5969
6113
  }
5970
6114
  }
@@ -6945,15 +7089,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6945
7089
  {{ resolveKeyValueLabel(item) }}
6946
7090
  </dt>
6947
7091
  <dd class="prx-rich-key-value-list__value">
6948
- @if (resolveKeyValueIcon(item); as kvIcon) {
6949
- <span
6950
- class="material-symbols-outlined prx-rich-key-value-list__icon"
6951
- aria-hidden="true"
7092
+ @if (item.quickView) {
7093
+ <button
7094
+ type="button"
7095
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
7096
+ [praxisQuickView]="item.quickView"
7097
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? $any(node).sourceRecord ?? context()"
7098
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
7099
+ data-testid="rich-key-value-quick-view-trigger"
6952
7100
  >
6953
- {{ kvIcon }}
6954
- </span>
7101
+ @if (resolveKeyValueIcon(item); as kvIcon) {
7102
+ <span
7103
+ class="material-symbols-outlined prx-rich-key-value-list__icon"
7104
+ aria-hidden="true"
7105
+ >
7106
+ {{ kvIcon }}
7107
+ </span>
7108
+ }
7109
+ <span class="prx-rich-record-reference__label">{{
7110
+ resolveKeyValueValue(item)
7111
+ }}</span>
7112
+ </button>
7113
+ } @else {
7114
+ @if (resolveKeyValueIcon(item); as kvIcon) {
7115
+ <span
7116
+ class="material-symbols-outlined prx-rich-key-value-list__icon"
7117
+ aria-hidden="true"
7118
+ >
7119
+ {{ kvIcon }}
7120
+ </span>
7121
+ }
7122
+ {{ resolveKeyValueValue(item) }}
6955
7123
  }
6956
- {{ resolveKeyValueValue(item) }}
6957
7124
  @if (resolveKeyValueBadge(item); as kvBadge) {
6958
7125
  <span class="prx-rich-badge">{{ kvBadge }}</span>
6959
7126
  }
@@ -7028,7 +7195,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7028
7195
  {{ resolvePropertySheetLabel(item) }}
7029
7196
  </dt>
7030
7197
  <dd class="prx-rich-property-sheet__value">
7031
- {{ resolvePropertySheetValue(item) }}
7198
+ @if (item.quickView) {
7199
+ <button
7200
+ type="button"
7201
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
7202
+ [praxisQuickView]="item.quickView"
7203
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? $any(node).sourceRecord ?? context()"
7204
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
7205
+ data-testid="rich-property-sheet-quick-view-trigger"
7206
+ >
7207
+ <span class="prx-rich-record-reference__label">{{
7208
+ resolvePropertySheetValue(item)
7209
+ }}</span>
7210
+ </button>
7211
+ } @else {
7212
+ {{ resolvePropertySheetValue(item) }}
7213
+ }
7032
7214
  </dd>
7033
7215
  @if (resolvePropertySheetHint(item); as propertyHint) {
7034
7216
  <div class="prx-rich-property-sheet__hint">
@@ -7297,7 +7479,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7297
7479
  ) {
7298
7480
  <div class="prx-rich-record-summary__field">
7299
7481
  <dt>{{ resolveRecordSummaryFieldLabel(field) }}</dt>
7300
- <dd>{{ resolveRecordSummaryFieldValue(field) }}</dd>
7482
+ <dd>
7483
+ @if (field.quickView) {
7484
+ <button
7485
+ type="button"
7486
+ class="prx-rich-record-reference prx-rich-record-reference--inline"
7487
+ [praxisQuickView]="field.quickView"
7488
+ [praxisQuickViewRecord]="$any(field).sourceRecord ?? $any(node).sourceRecord ?? context()"
7489
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
7490
+ data-testid="rich-record-summary-field-quick-view-trigger"
7491
+ >
7492
+ <span class="prx-rich-record-reference__label">{{
7493
+ resolveRecordSummaryFieldValue(field)
7494
+ }}</span>
7495
+ </button>
7496
+ } @else {
7497
+ {{ resolveRecordSummaryFieldValue(field) }}
7498
+ }
7499
+ </dd>
7301
7500
  </div>
7302
7501
  }
7303
7502
  </dl>
@@ -8669,18 +8868,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8669
8868
  <div
8670
8869
  class="prx-rich-timeline__item-badge"
8671
8870
  >
8672
- <span
8673
- class="prx-rich-badge"
8674
- [attr.data-tone]="
8675
- resolveTimelineItemBadgeTone(item)
8676
- "
8677
- [ngClass]="
8678
- resolveTimelineItemBadgeClasses(
8679
- item
8680
- )
8681
- "
8682
- >{{ itemBadge }}</span
8683
- >
8871
+ @if (item.quickView) {
8872
+ <button
8873
+ type="button"
8874
+ class="prx-rich-badge prx-rich-badge--interactive"
8875
+ [attr.data-tone]="
8876
+ resolveTimelineItemBadgeTone(item)
8877
+ "
8878
+ [ngClass]="
8879
+ resolveTimelineItemBadgeClasses(
8880
+ item
8881
+ )
8882
+ "
8883
+ [praxisQuickView]="item.quickView"
8884
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? context()"
8885
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
8886
+ data-testid="rich-timeline-badge-quick-view-trigger"
8887
+ >{{ itemBadge }}</button>
8888
+ } @else {
8889
+ <span
8890
+ class="prx-rich-badge"
8891
+ [attr.data-tone]="
8892
+ resolveTimelineItemBadgeTone(item)
8893
+ "
8894
+ [ngClass]="
8895
+ resolveTimelineItemBadgeClasses(
8896
+ item
8897
+ )
8898
+ "
8899
+ >{{ itemBadge }}</span
8900
+ >
8901
+ }
8684
8902
  </div>
8685
8903
  }
8686
8904
  @if (
@@ -8756,16 +8974,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8756
8974
  as itemBadge
8757
8975
  ) {
8758
8976
  <div class="prx-rich-timeline__item-badge">
8759
- <span
8760
- class="prx-rich-badge"
8761
- [attr.data-tone]="
8762
- resolveTimelineItemBadgeTone(item)
8763
- "
8764
- [ngClass]="
8765
- resolveTimelineItemBadgeClasses(item)
8766
- "
8767
- >{{ itemBadge }}</span
8768
- >
8977
+ @if (item.quickView) {
8978
+ <button
8979
+ type="button"
8980
+ class="prx-rich-badge prx-rich-badge--interactive"
8981
+ [attr.data-tone]="
8982
+ resolveTimelineItemBadgeTone(item)
8983
+ "
8984
+ [ngClass]="
8985
+ resolveTimelineItemBadgeClasses(item)
8986
+ "
8987
+ [praxisQuickView]="item.quickView"
8988
+ [praxisQuickViewRecord]="$any(item).sourceRecord ?? context()"
8989
+ [praxisQuickViewTriggerMode]="'hover-and-click'"
8990
+ data-testid="rich-timeline-badge-quick-view-trigger"
8991
+ >{{ itemBadge }}</button>
8992
+ } @else {
8993
+ <span
8994
+ class="prx-rich-badge"
8995
+ [attr.data-tone]="
8996
+ resolveTimelineItemBadgeTone(item)
8997
+ "
8998
+ [ngClass]="
8999
+ resolveTimelineItemBadgeClasses(item)
9000
+ "
9001
+ >{{ itemBadge }}</span
9002
+ >
9003
+ }
8769
9004
  </div>
8770
9005
  }
8771
9006
  }
@@ -9915,6 +10150,12 @@ function validateKeyValueItems(value, path, issues) {
9915
10150
  validateOptionalString(item, 'badge', `${path}[${index}]`, issues);
9916
10151
  validateOptionalExpressionPath(item, 'badgeExpr', `${path}[${index}]`, issues);
9917
10152
  validateOptionalString(item, 'icon', `${path}[${index}]`, issues);
10153
+ if (item['quickView'] !== undefined) {
10154
+ const qvValidation = validateResourceQuickViewBinding(item['quickView']);
10155
+ if (!qvValidation.valid) {
10156
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
10157
+ }
10158
+ }
9918
10159
  });
9919
10160
  }
9920
10161
  function validateRecordSummaryFields(value, path, issues) {
@@ -9932,6 +10173,12 @@ function validateRecordSummaryFields(value, path, issues) {
9932
10173
  validateOptionalExpressionPath(field, 'labelExpr', `${path}[${index}]`, issues);
9933
10174
  validateOptionalString(field, 'value', `${path}[${index}]`, issues);
9934
10175
  validateOptionalExpressionPath(field, 'valueExpr', `${path}[${index}]`, issues);
10176
+ if (field['quickView'] !== undefined) {
10177
+ const qvValidation = validateResourceQuickViewBinding(field['quickView']);
10178
+ if (!qvValidation.valid) {
10179
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
10180
+ }
10181
+ }
9935
10182
  });
9936
10183
  }
9937
10184
  function validateLookupResultFields(value, path, issues) {
@@ -9972,6 +10219,12 @@ function validatePropertySheetItems(value, path, issues) {
9972
10219
  validateOptionalExpressionPath(item, 'hintExpr', `${path}[${index}]`, issues);
9973
10220
  validateOptionalString(item, 'icon', `${path}[${index}]`, issues);
9974
10221
  validateEnum(item, 'tone', ['neutral', 'info', 'success', 'warning', 'danger'], `${path}[${index}]`, issues, false);
10222
+ if (item['quickView'] !== undefined) {
10223
+ const qvValidation = validateResourceQuickViewBinding(item['quickView']);
10224
+ if (!qvValidation.valid) {
10225
+ addIssue(issues, `${path}[${index}].quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
10226
+ }
10227
+ }
9975
10228
  });
9976
10229
  }
9977
10230
  function validateStatGroupItems(value, path, issues) {
@@ -10137,6 +10390,12 @@ function validateTimelineItem(item, itemPath, issues, state, depth = 1) {
10137
10390
  if (record['action'] !== undefined) {
10138
10391
  validateActionRef(record['action'], `${itemPath}.action`, issues);
10139
10392
  }
10393
+ if (record['quickView'] !== undefined) {
10394
+ const qvValidation = validateResourceQuickViewBinding(record['quickView']);
10395
+ if (!qvValidation.valid) {
10396
+ addIssue(issues, `${itemPath}.quickView`, 'editor.validation.quickViewBinding', qvValidation.diagnostics.join(' ') || 'Quick View binding is invalid.');
10397
+ }
10398
+ }
10140
10399
  if (record['children'] !== undefined) {
10141
10400
  validateTimelineItems(record['children'], `${itemPath}.children`, issues, state, depth + 1);
10142
10401
  }
@@ -28783,7 +29042,18 @@ function validateAndExpandPrimitiveNode(node, registry, ancestry, presetDepth, a
28783
29042
  */
28784
29043
  class PraxisQuickViewRichContentBodyComponent {
28785
29044
  presetRegistry = inject(RichContentPresetRegistryService);
29045
+ i18n = inject(PraxisI18nService, { optional: true });
28786
29046
  resolution = input(null, ...(ngDevMode ? [{ debugName: "resolution" }] : /* istanbul ignore next */ []));
29047
+ invalidPresetMessage = computed(() => {
29048
+ const fallback = 'O conteúdo resumido deste preset não pôde ser validado com segurança.';
29049
+ if (!this.i18n) {
29050
+ return fallback;
29051
+ }
29052
+ const translated = this.i18n.t('quickView.invalidPresetContent', undefined, fallback);
29053
+ return typeof translated === 'string' && translated.trim().length > 0
29054
+ ? translated
29055
+ : fallback;
29056
+ }, ...(ngDevMode ? [{ debugName: "invalidPresetMessage" }] : /* istanbul ignore next */ []));
28787
29057
  restrictedHostCapabilities = {
28788
29058
  isActionAvailable: () => false,
28789
29059
  dispatchAction: () => {
@@ -28851,7 +29121,7 @@ class PraxisQuickViewRichContentBodyComponent {
28851
29121
  </div>
28852
29122
  } @else {
28853
29123
  <p class="prx-quick-view-rich-body__invalid" data-testid="quick-view-rich-body-invalid">
28854
- O conteúdo resumido deste preset não pôde ser validado com segurança.
29124
+ {{ invalidPresetMessage() }}
28855
29125
  </p>
28856
29126
  }
28857
29127
  `, isInline: true, styles: [":host{display:block;min-width:0}.prx-quick-view-rich-body__invalid{margin:0;font-size:.8125rem;color:var(--md-sys-color-error, #b91c1c)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"], outputs: ["nodeAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
@@ -28869,7 +29139,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
28869
29139
  </div>
28870
29140
  } @else {
28871
29141
  <p class="prx-quick-view-rich-body__invalid" data-testid="quick-view-rich-body-invalid">
28872
- O conteúdo resumido deste preset não pôde ser validado com segurança.
29142
+ {{ invalidPresetMessage() }}
28873
29143
  </p>
28874
29144
  }
28875
29145
  `, styles: [":host{display:block;min-width:0}.prx-quick-view-rich-body__invalid{margin:0;font-size:.8125rem;color:var(--md-sys-color-error, #b91c1c)}\n"] }]
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@praxisui/rich-content",
3
- "version": "10.0.0-rc.40",
3
+ "version": "10.0.0-rc.41",
4
4
  "description": "Rich content rendering and authoring primitives for Praxis UI surfaces, including semantic blocks and page-builder integration.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
8
  "@angular/material": "^21.0.0",
9
- "@praxisui/core": "^10.0.0-rc.40",
9
+ "@praxisui/core": "^10.0.0-rc.41",
10
10
  "@angular/forms": "^21.0.0",
11
11
  "rxjs": "~7.8.0"
12
12
  },
@@ -1,4 +1,4 @@
1
- import * as i0 from '@angular/core';
1
+ import * as _angular_core from '@angular/core';
2
2
  import { EventEmitter, OnChanges, OnInit, SimpleChanges, InjectionToken, Provider } from '@angular/core';
3
3
  import { RichContentDocument, RichPrimitiveNode, RichPresetReferenceNode, JsonLogicDataRecord, RichBlockHostCapabilities, RichActionRef, RichBlockNode, RichActionButtonNode, RichPageHeaderNode, RichPresenterNode, RichRecordReferenceNode, RichComposeNode, RichCardNode, RichCardMedia, WidgetDefinition, RichCalloutNode, RichCtaGroupNode, RichKeyValueListNode, RichKeyValueItem, RichEmptyStateNode, RichPropertySheetNode, RichPropertySheetItem, RichDynamicFormNode, RichStatGroupNode, RichStatItem, RichTabsNode, RichTabsItem, RichRecordSummaryNode, RichRecordSummaryField, RichLookupResultNode, RichLookupResultField, RichLookupCardNode, RichRelatedRecordNode, RichActionCardNode, RichDecisionPackageNode, RichDecisionPackageEvidence, RichCollapsibleCardNode, RichFormLauncherNode, RichDisclosureNode, RichAccordionNode, RichAccordionItem, RichMediaBlockNode, RichTimelineNode, RichTimelineItem, RichTextNode, RichBadgeNode, RichIconNode, RichAvatarNode, RichImageNode, RichLinkNode, RichMetricNode, RichProgressNode, SettingsValueProvider, CorePresetRef, CorePresetDescriptor, ResourceQuickViewPresetRef, ResourceQuickViewResolution, PraxisQuickViewBodyRenderer, PraxisQuickViewBodyRenderContext, PraxisQuickViewPresetValidationResult, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, PraxisI18nDictionary, PraxisI18nConfig, PraxisI18nService } from '@praxisui/core';
4
4
  import * as _praxisui_rich_content from '@praxisui/rich-content';
@@ -18,11 +18,11 @@ declare class PraxisRichContent {
18
18
  private readonly localSchemaMap;
19
19
  private readonly schemaVersion;
20
20
  private readonly inFlightSchemaRequests;
21
- readonly document: i0.InputSignal<RichContentDocument>;
22
- readonly nodes: i0.InputSignal<RenderableNode[]>;
23
- readonly context: i0.InputSignal<JsonLogicDataRecord>;
24
- readonly hostCapabilities: i0.InputSignal<RichBlockHostCapabilities>;
25
- readonly layout: i0.InputSignal<"block" | "inline">;
21
+ readonly document: _angular_core.InputSignal<RichContentDocument>;
22
+ readonly nodes: _angular_core.InputSignal<RenderableNode[]>;
23
+ readonly context: _angular_core.InputSignal<JsonLogicDataRecord>;
24
+ readonly hostCapabilities: _angular_core.InputSignal<RichBlockHostCapabilities>;
25
+ readonly layout: _angular_core.InputSignal<"block" | "inline">;
26
26
  rootClassName: string | null | undefined;
27
27
  nodeAction: EventEmitter<RichActionRef>;
28
28
  get safeRootClassName(): string;
@@ -30,7 +30,7 @@ declare class PraxisRichContent {
30
30
  private readonly timelineExpanded;
31
31
  private readonly runtimeNodeIds;
32
32
  private nextRuntimeNodeId;
33
- readonly renderableNodes: i0.Signal<RenderableNode[]>;
33
+ readonly renderableNodes: _angular_core.Signal<RenderableNode[]>;
34
34
  visiblePageHeaderNodes<T extends RichBlockNode>(nodes?: T[]): T[];
35
35
  resolvePageHeaderMenuLabel(action: RichActionButtonNode): string;
36
36
  visiblePageHeaderOverflow(node: RichPageHeaderNode): RichActionButtonNode[];
@@ -332,8 +332,8 @@ declare class PraxisRichContent {
332
332
  private getByPath;
333
333
  private applyDeclarativePipe;
334
334
  private resolveInitials;
335
- static ɵfac: i0.ɵɵFactoryDeclaration<PraxisRichContent, never>;
336
- static ɵcmp: i0.ɵɵComponentDeclaration<PraxisRichContent, "praxis-rich-content", never, { "document": { "alias": "document"; "required": false; "isSignal": true; }; "nodes": { "alias": "nodes"; "required": false; "isSignal": true; }; "context": { "alias": "context"; "required": false; "isSignal": true; }; "hostCapabilities": { "alias": "hostCapabilities"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "rootClassName": { "alias": "rootClassName"; "required": false; }; }, { "nodeAction": "nodeAction"; }, never, never, true, never>;
335
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisRichContent, never>;
336
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisRichContent, "praxis-rich-content", never, { "document": { "alias": "document"; "required": false; "isSignal": true; }; "nodes": { "alias": "nodes"; "required": false; "isSignal": true; }; "context": { "alias": "context"; "required": false; "isSignal": true; }; "hostCapabilities": { "alias": "hostCapabilities"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "rootClassName": { "alias": "rootClassName"; "required": false; }; }, { "nodeAction": "nodeAction"; }, never, never, true, never>;
337
337
  }
338
338
 
339
339
  declare function isSafeRichContentClassName(value: unknown): boolean;
@@ -815,8 +815,8 @@ declare class PraxisRichContentConfigEditor implements SettingsValueProvider, On
815
815
  private cloneInputs;
816
816
  private cloneValue;
817
817
  private stringify;
818
- static ɵfac: i0.ɵɵFactoryDeclaration<PraxisRichContentConfigEditor, never>;
819
- static ɵcmp: i0.ɵɵComponentDeclaration<PraxisRichContentConfigEditor, "praxis-rich-content-config-editor", never, { "inputs": { "alias": "inputs"; "required": false; }; }, {}, never, never, true, never>;
818
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisRichContentConfigEditor, never>;
819
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisRichContentConfigEditor, "praxis-rich-content-config-editor", never, { "inputs": { "alias": "inputs"; "required": false; }; }, {}, never, never, true, never>;
820
820
  }
821
821
 
822
822
  interface RichBlockPresetDefinition extends CorePresetDescriptor {
@@ -830,8 +830,8 @@ declare class RichContentPresetRegistryService {
830
830
  private readonly presetDefinitions;
831
831
  list(): RichBlockPresetDefinition[];
832
832
  get(ref: CorePresetRef): RichBlockPresetDefinition | null;
833
- static ɵfac: i0.ɵɵFactoryDeclaration<RichContentPresetRegistryService, never>;
834
- static ɵprov: i0.ɵɵInjectableDeclaration<RichContentPresetRegistryService>;
833
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RichContentPresetRegistryService, never>;
834
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<RichContentPresetRegistryService>;
835
835
  }
836
836
  declare function providePraxisDefaultRichBlockPresets(): Provider;
837
837
 
@@ -867,20 +867,22 @@ declare function expandAndValidateQuickViewPreset(ref: ResourceQuickViewPresetRe
867
867
  */
868
868
  declare class PraxisQuickViewRichContentBodyComponent {
869
869
  private readonly presetRegistry;
870
- readonly resolution: i0.InputSignal<ResourceQuickViewResolution>;
870
+ private readonly i18n;
871
+ readonly resolution: _angular_core.InputSignal<ResourceQuickViewResolution>;
872
+ protected readonly invalidPresetMessage: _angular_core.Signal<string>;
871
873
  protected readonly restrictedHostCapabilities: RichBlockHostCapabilities;
872
- protected readonly expandedDocument: i0.Signal<RichContentDocument>;
873
- protected readonly evaluationData: i0.Signal<Record<string, unknown>>;
874
- static ɵfac: i0.ɵɵFactoryDeclaration<PraxisQuickViewRichContentBodyComponent, never>;
875
- static ɵcmp: i0.ɵɵComponentDeclaration<PraxisQuickViewRichContentBodyComponent, "praxis-quick-view-rich-content-body", never, { "resolution": { "alias": "resolution"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
874
+ protected readonly expandedDocument: _angular_core.Signal<RichContentDocument>;
875
+ protected readonly evaluationData: _angular_core.Signal<Record<string, unknown>>;
876
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisQuickViewRichContentBodyComponent, never>;
877
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisQuickViewRichContentBodyComponent, "praxis-quick-view-rich-content-body", never, { "resolution": { "alias": "resolution"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
876
878
  }
877
879
  declare class QuickViewRichContentBodyRendererService implements PraxisQuickViewBodyRenderer {
878
880
  private readonly presetRegistry;
879
881
  readonly component: typeof PraxisQuickViewRichContentBodyComponent;
880
882
  buildInputs(context: PraxisQuickViewBodyRenderContext): Record<string, unknown>;
881
883
  validatePreset(ref: ResourceQuickViewPresetRef): PraxisQuickViewPresetValidationResult;
882
- static ɵfac: i0.ɵɵFactoryDeclaration<QuickViewRichContentBodyRendererService, never>;
883
- static ɵprov: i0.ɵɵInjectableDeclaration<QuickViewRichContentBodyRendererService>;
884
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuickViewRichContentBodyRendererService, never>;
885
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<QuickViewRichContentBodyRendererService>;
884
886
  }
885
887
  declare function providePraxisQuickViewRichContentRenderer(): Provider;
886
888
 
@@ -913,7 +915,7 @@ interface PraxisRichContentI18nOptions {
913
915
  dictionaries?: Record<string, PraxisI18nDictionary>;
914
916
  }
915
917
  declare function createPraxisRichContentI18nConfig(options?: PraxisRichContentI18nOptions): Partial<PraxisI18nConfig>;
916
- declare function providePraxisRichContentI18n(options?: PraxisRichContentI18nOptions): i0.Provider[];
918
+ declare function providePraxisRichContentI18n(options?: PraxisRichContentI18nOptions): _angular_core.Provider[];
917
919
  declare function resolvePraxisRichContentText(i18n: PraxisI18nService, key: string, fallback: string): string;
918
920
 
919
921
  export { PRAXIS_RICH_BLOCK_PRESETS, PRAXIS_RICH_CONTENT_AUTHORING_MANIFEST, PRAXIS_RICH_CONTENT_COMPONENT_METADATA, PraxisQuickViewRichContentBodyComponent, PraxisRichContent, PraxisRichContent as PraxisRichContentComponent, PraxisRichContentConfigEditor, QUICK_VIEW_MAX_AST_DEPTH, QUICK_VIEW_MAX_PRESET_EXPANSION_DEPTH, QUICK_VIEW_MAX_TOTAL_NODES, QuickViewRichContentBodyRendererService, RICH_CONTENT_AI_CAPABILITIES, RichContentPresetRegistryService, createPraxisRichContentI18nConfig, expandAndValidateQuickViewPreset, isSafeRichContentClassName, isValidRichContentDocument, providePraxisDefaultRichBlockPresets, providePraxisQuickViewRichContentRenderer, providePraxisRichContentI18n, providePraxisRichContentMetadata, resolvePraxisRichContentText, validateRichContentDocument };