@praxisui/table 9.0.4-rc.47 → 9.0.4-rc.49

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.
@@ -3121,6 +3121,56 @@ function validateTableAuthoringDocument(doc, context) {
3121
3121
  diagnostics.push(errorDiagnostic('table.config.columns.field.required', 'Column field is required', `config.columns[${index}].field`));
3122
3122
  }
3123
3123
  });
3124
+ if ('columnProjection' in rawConfig) {
3125
+ const projection = asRecord(rawConfig.columnProjection);
3126
+ if (!rawConfig.columnProjection
3127
+ || typeof rawConfig.columnProjection !== 'object'
3128
+ || Array.isArray(rawConfig.columnProjection)) {
3129
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.invalid', 'config.columnProjection must be an object', 'config.columnProjection'));
3130
+ }
3131
+ else if (projection.source !== 'schema') {
3132
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.source.invalid', 'config.columnProjection.source must be schema', 'config.columnProjection.source'));
3133
+ }
3134
+ if ('include' in projection) {
3135
+ if (!Array.isArray(projection.include)
3136
+ || projection.include.some((field) => typeof field !== 'string' || !field.trim())
3137
+ || new Set(projection.include).size !== projection.include.length) {
3138
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.include.invalid', 'config.columnProjection.include must be an ordered array of unique canonical field names', 'config.columnProjection.include'));
3139
+ }
3140
+ }
3141
+ if ('overrides' in projection) {
3142
+ const overrides = asRecord(projection.overrides);
3143
+ if (!projection.overrides
3144
+ || typeof projection.overrides !== 'object'
3145
+ || Array.isArray(projection.overrides)) {
3146
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.overrides.invalid', 'config.columnProjection.overrides must be an object keyed by canonical field name', 'config.columnProjection.overrides'));
3147
+ }
3148
+ else {
3149
+ Object.entries(overrides).forEach(([field, override]) => {
3150
+ if (!field.trim() || !override || typeof override !== 'object' || Array.isArray(override)) {
3151
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.override.invalid', 'Each column projection override must be an object keyed by canonical field name', `config.columnProjection.overrides.${field}`));
3152
+ return;
3153
+ }
3154
+ if (hasOwnProperty(override, 'field')) {
3155
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.override.field.forbidden', 'A schema column projection override cannot change the canonical field identity', `config.columnProjection.overrides.${field}.field`));
3156
+ }
3157
+ });
3158
+ }
3159
+ }
3160
+ if ('additions' in projection) {
3161
+ if (!Array.isArray(projection.additions)) {
3162
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.additions.invalid', 'config.columnProjection.additions must be an array of editorial columns', 'config.columnProjection.additions'));
3163
+ }
3164
+ else {
3165
+ const fields = projection.additions
3166
+ .map((column) => trimString(asRecord(column).field));
3167
+ if (fields.some((field) => !field)
3168
+ || new Set(fields).size !== fields.length) {
3169
+ diagnostics.push(errorDiagnostic('table.config.columnProjection.additions.field.invalid', 'Each editorial addition must have a unique field', 'config.columnProjection.additions'));
3170
+ }
3171
+ }
3172
+ }
3173
+ }
3124
3174
  const bindings = normalized.bindings || {};
3125
3175
  const metaIdField = trimString(normalized.config?.meta?.idField);
3126
3176
  if ('horizontalScroll' in rawBindings &&
@@ -3133,6 +3183,9 @@ function validateTableAuthoringDocument(doc, context) {
3133
3183
  diagnostics.push(errorDiagnostic('table.bindings.horizontalScroll.invalid', 'horizontalScroll must be auto, wrap or none', 'bindings.horizontalScroll'));
3134
3184
  }
3135
3185
  const effectiveMode = resolveEffectiveDataMode(normalized, context);
3186
+ if (rawConfig.columnProjection && effectiveMode !== 'remote') {
3187
+ diagnostics.push(warnDiagnostic('table.config.columnProjection.remote-schema.required', 'Schema column projection requires a remote resourcePath at runtime', 'config.columnProjection'));
3188
+ }
3136
3189
  if (effectiveMode === 'local') {
3137
3190
  if (normalized.config.behavior?.pagination?.strategy === 'server') {
3138
3191
  diagnostics.push(warnDiagnostic('table.behavior.pagination.strategy.invalid-for-local', 'Server pagination will be projected to client in local mode', 'config.behavior.pagination.strategy'));
@@ -41906,6 +41959,7 @@ class PraxisTable {
41906
41959
  paginatorIntl = inject(MatPaginatorIntl);
41907
41960
  schemaNormalizer = inject(SchemaNormalizerService);
41908
41961
  schemaFieldsSnapshot = [];
41962
+ schemaColumnFieldsSnapshot = [];
41909
41963
  filterSchemaFieldsSnapshot = [];
41910
41964
  runtimeSchemaMeta = {};
41911
41965
  schemaError = false;
@@ -43269,8 +43323,12 @@ class PraxisTable {
43269
43323
  setSchemaFieldsSnapshot(fields) {
43270
43324
  if (!Array.isArray(fields) || fields.length === 0) {
43271
43325
  this.schemaFieldsSnapshot = [];
43326
+ this.schemaColumnFieldsSnapshot = [];
43272
43327
  return;
43273
43328
  }
43329
+ this.schemaColumnFieldsSnapshot = fields
43330
+ .map((field) => this.clonePlainObject(field))
43331
+ .filter((field) => String(field?.name || '').trim().length > 0);
43274
43332
  this.schemaFieldsSnapshot = fields
43275
43333
  .map((field) => ({
43276
43334
  name: (field?.name || '').toString(),
@@ -43423,6 +43481,7 @@ class PraxisTable {
43423
43481
  }
43424
43482
  clearSchemaFieldsSnapshot() {
43425
43483
  this.schemaFieldsSnapshot = [];
43484
+ this.schemaColumnFieldsSnapshot = [];
43426
43485
  }
43427
43486
  componentKeyId() {
43428
43487
  try {
@@ -44054,7 +44113,7 @@ class PraxisTable {
44054
44113
  if (this.aiAdapter || this.aiAdapterLoadStarted)
44055
44114
  return;
44056
44115
  this.aiAdapterLoadStarted = true;
44057
- import('./praxisui-table-table-ai.adapter-B3JduSXn.mjs')
44116
+ import('./praxisui-table-table-ai.adapter-iUYC2oD5.mjs')
44058
44117
  .then(({ TableAiAdapter }) => {
44059
44118
  if (!this.isAiAssistantEnabled()) {
44060
44119
  this.aiAssistantOpenAfterAdapterLoad = false;
@@ -44800,7 +44859,7 @@ class PraxisTable {
44800
44859
  initializeAiAssistantController() {
44801
44860
  if (!this.aiAdapter || this.aiAssistantController)
44802
44861
  return;
44803
- import('./praxisui-table-table-agentic-authoring-turn-flow-DsM7fuli.mjs')
44862
+ import('./praxisui-table-table-agentic-authoring-turn-flow-Cz_xmaGA.mjs')
44804
44863
  .then(({ TableAgenticAuthoringTurnFlow }) => {
44805
44864
  if (this.aiAssistantController || !this.aiAdapter)
44806
44865
  return;
@@ -51077,7 +51136,7 @@ class PraxisTable {
51077
51136
  col.visible = visible;
51078
51137
  this.setupColumns();
51079
51138
  this.cdr.markForCheck();
51080
- this.configChange.emit(this.config);
51139
+ this.configChange.emit(this.toPortableTableConfig());
51081
51140
  }
51082
51141
  onDensityChange(density) {
51083
51142
  if (density !== 'compact' && density !== 'comfortable' && density !== 'spacious')
@@ -51094,7 +51153,7 @@ class PraxisTable {
51094
51153
  };
51095
51154
  this.applyAppearanceVariables();
51096
51155
  this.cdr.markForCheck();
51097
- this.configChange.emit(this.config);
51156
+ this.configChange.emit(this.toPortableTableConfig());
51098
51157
  }
51099
51158
  isCustomizationAvailable() {
51100
51159
  if (!this.enableCustomization) {
@@ -51197,6 +51256,11 @@ class PraxisTable {
51197
51256
  applyTableConfig(cfg, options) {
51198
51257
  this.debugLog('[PraxisTable] Applying table config', cfg);
51199
51258
  this.config = { ...cfg };
51259
+ if (this.usesSchemaColumnProjection(this.config)
51260
+ && this.schemaColumnFieldsSnapshot.length > 0
51261
+ && (this.config.columns?.length ?? 0) === 0) {
51262
+ this.config.columns = this.projectSchemaColumns(this.schemaColumnFieldsSnapshot, this.config.columnProjection);
51263
+ }
51200
51264
  this.syncRuntimeSchemaMetaFromConfig();
51201
51265
  this.ensureConfigDefaults();
51202
51266
  this.enforceUnsupportedFeatureGuards();
@@ -51246,13 +51310,17 @@ class PraxisTable {
51246
51310
  }
51247
51311
  emitWidgetInputPatch(inputPatch, trigger) {
51248
51312
  try {
51313
+ const portablePatch = this.cloneInputPatch(inputPatch);
51314
+ if (Object.prototype.hasOwnProperty.call(portablePatch, 'config')) {
51315
+ portablePatch['config'] = this.toPortableTableConfig(portablePatch['config']);
51316
+ }
51249
51317
  this.widgetEvent.emit({
51250
51318
  sourceComponentId: 'praxis-table',
51251
51319
  output: 'tableInputPatch',
51252
51320
  payload: {
51253
51321
  trigger,
51254
51322
  tableId: this.tableId,
51255
- inputPatch: JSON.parse(JSON.stringify(inputPatch)),
51323
+ inputPatch: portablePatch,
51256
51324
  },
51257
51325
  });
51258
51326
  }
@@ -51263,7 +51331,7 @@ class PraxisTable {
51263
51331
  setTimeout(() => {
51264
51332
  this.emitWidgetInputPatch(clonedPatch, trigger);
51265
51333
  if (Object.prototype.hasOwnProperty.call(clonedPatch, 'config')) {
51266
- this.configChange.emit(clonedPatch['config']);
51334
+ this.configChange.emit(this.toPortableTableConfig(clonedPatch['config']));
51267
51335
  }
51268
51336
  }, 0);
51269
51337
  }
@@ -51313,7 +51381,8 @@ class PraxisTable {
51313
51381
  this.persistHorizontalScrollInput(inputsKey, nextHs, trigger);
51314
51382
  }
51315
51383
  }
51316
- const cfg = this.attachRuntimeMetadataToEditorConfig(plan.canonicalConfig, plan.metadata?.attachServerMeta === true && !shouldReloadSchema, plan.persistence?.saveConfig === true);
51384
+ const compactConfig = this.toPortableTableConfig(plan.canonicalConfig);
51385
+ const cfg = this.attachRuntimeMetadataToEditorConfig(compactConfig, plan.metadata?.attachServerMeta === true && !shouldReloadSchema, plan.persistence?.saveConfig === true);
51317
51386
  if (plan.persistence?.saveConfig) {
51318
51387
  const cfgKey = this.tableConfigKey();
51319
51388
  if (cfgKey) {
@@ -52951,17 +53020,23 @@ class PraxisTable {
52951
53020
  this.emitSchemaStatus({ outdated: false, serverHash: this.runtimeSchemaMeta.serverHash, lastVerifiedAt: this.runtimeSchemaMeta.lastVerifiedAt, resourcePath: this.resourcePath }, 'verification-304');
52952
53021
  return;
52953
53022
  }
52954
- // status === 200: server hash changed or first verification without hash. Do not
52955
- // replace the column list, but keep existing columns enriched with safe schema
52956
- // presentation metadata such as semantic renderers, masks, and value mappings.
53023
+ // status === 200: server hash changed or first verification without hash.
53024
+ // Explicit column contracts remain stable and receive safe presentation metadata.
53025
+ // Schema projections are rebuilt so newly published fields and governed defaults
53026
+ // are reflected before their editorial overrides are reapplied.
52957
53027
  const newHash = res.schemaHash;
52958
53028
  try {
52959
53029
  const fields = this.schemaNormalizer.normalizeSchema(res.schema);
52960
53030
  this.setSchemaFieldsSnapshot(fields);
52961
- this.applySchemaFieldPresentationsToExistingColumns(fields);
53031
+ if (this.usesSchemaColumnProjection()) {
53032
+ this.config.columns = this.projectSchemaColumns(fields);
53033
+ }
53034
+ else {
53035
+ this.applySchemaFieldPresentationsToExistingColumns(fields);
53036
+ }
52962
53037
  this.loadFilterSchemaSnapshot();
52963
53038
  this.setupColumns();
52964
- this.configChange.emit(this.config);
53039
+ this.configChange.emit(this.toPortableTableConfig());
52965
53040
  }
52966
53041
  catch { }
52967
53042
  this.runtimeSchemaMeta = {
@@ -53035,10 +53110,10 @@ class PraxisTable {
53035
53110
  }
53036
53111
  catch { }
53037
53112
  const existing = this.config?.columns ?? [];
53038
- if (options?.replaceColumns === true || existing.length === 0) {
53039
- this.config.columns = fields
53040
- .filter((f) => !f.tableHidden && !f.hidden)
53041
- .map((f) => this.convertFieldToColumn(f));
53113
+ if (this.usesSchemaColumnProjection()
53114
+ || options?.replaceColumns === true
53115
+ || existing.length === 0) {
53116
+ this.config.columns = this.projectSchemaColumns(fields);
53042
53117
  }
53043
53118
  else {
53044
53119
  this.applySchemaFieldPresentationsToExistingColumns(fields);
@@ -53048,7 +53123,7 @@ class PraxisTable {
53048
53123
  resourcePath: this.resourcePath,
53049
53124
  horizontalScroll: this.horizontalScroll,
53050
53125
  }, 'schema-loaded');
53051
- this.configChange.emit(this.config);
53126
+ this.configChange.emit(this.toPortableTableConfig());
53052
53127
  const mountCtx = this.buildLoadingContext('mount', 'Montando colunas…', false);
53053
53128
  this.beginLoading(mountCtx);
53054
53129
  try {
@@ -53142,6 +53217,163 @@ class PraxisTable {
53142
53217
  catch { }
53143
53218
  return col;
53144
53219
  }
53220
+ usesSchemaColumnProjection(config = this.config) {
53221
+ return config?.columnProjection?.source === 'schema';
53222
+ }
53223
+ /**
53224
+ * Materializa a projeção efetiva sem promover o JSON da página a fonte de
53225
+ * verdade estrutural. Overrides desconhecidos não criam colunas e `field`
53226
+ * nunca pode ser substituído pelo consumidor.
53227
+ */
53228
+ projectSchemaColumns(fields, projection = this.usesSchemaColumnProjection()
53229
+ ? this.config?.columnProjection
53230
+ : undefined) {
53231
+ const overrides = projection?.overrides ?? {};
53232
+ const include = Array.isArray(projection?.include)
53233
+ ? projection.include
53234
+ .map((field) => String(field || '').trim())
53235
+ .filter((field, index, values) => !!field && values.indexOf(field) === index)
53236
+ : [];
53237
+ const includeOrder = new Map(include.map((field, index) => [field, index]));
53238
+ const schemaColumns = (Array.isArray(fields) ? fields : [])
53239
+ .filter((field) => !field.tableHidden && !field.hidden)
53240
+ .filter((field) => include.length === 0 || includeOrder.has(field.name))
53241
+ .sort((left, right) => {
53242
+ if (include.length === 0)
53243
+ return 0;
53244
+ return (includeOrder.get(left.name) ?? Number.MAX_SAFE_INTEGER)
53245
+ - (includeOrder.get(right.name) ?? Number.MAX_SAFE_INTEGER);
53246
+ })
53247
+ .map((field) => {
53248
+ const base = this.convertFieldToColumn(field);
53249
+ const override = overrides[field.name];
53250
+ if (!override || typeof override !== 'object' || Array.isArray(override)) {
53251
+ return base;
53252
+ }
53253
+ const merged = deepMerge(base, override);
53254
+ return {
53255
+ ...merged,
53256
+ field: base.field,
53257
+ _isApiField: base._isApiField,
53258
+ _originalApiType: base._originalApiType,
53259
+ };
53260
+ });
53261
+ const canonicalFields = new Set((Array.isArray(fields) ? fields : [])
53262
+ .map((field) => String(field?.name || '').trim())
53263
+ .filter(Boolean));
53264
+ const additions = Array.isArray(projection?.additions)
53265
+ ? projection.additions
53266
+ .filter((column) => {
53267
+ const field = String(column?.field || '').trim();
53268
+ return !!field && !canonicalFields.has(field);
53269
+ })
53270
+ .map((column) => this.toPortableColumnDefinition(column))
53271
+ : [];
53272
+ return [...schemaColumns, ...additions];
53273
+ }
53274
+ /**
53275
+ * Converte a configuração materializada usada pelo renderer de volta ao
53276
+ * contrato compacto e persistível. O schema continua sendo a fonte
53277
+ * estrutural; somente ordem/allowlist, diferenças editoriais e colunas sem
53278
+ * correspondente canônico são serializadas.
53279
+ */
53280
+ toPortableTableConfig(config = this.config) {
53281
+ const cloned = this.clonePlainObject(config);
53282
+ if (!this.usesSchemaColumnProjection(cloned)
53283
+ || this.schemaColumnFieldsSnapshot.length === 0
53284
+ || !Array.isArray(cloned.columns)
53285
+ || cloned.columns.length === 0) {
53286
+ return cloned;
53287
+ }
53288
+ const projection = this.clonePlainObject(cloned.columnProjection);
53289
+ const visibleSchemaFields = this.schemaColumnFieldsSnapshot
53290
+ .filter((field) => !field.tableHidden && !field.hidden);
53291
+ const canonicalFieldNames = new Set(visibleSchemaFields
53292
+ .map((field) => String(field?.name || '').trim())
53293
+ .filter(Boolean));
53294
+ const authoredColumns = cloned.columns
53295
+ .filter((column) => !!String(column?.field || '').trim());
53296
+ const include = authoredColumns
53297
+ .map((column) => String(column.field).trim())
53298
+ .filter((field, index, values) => (canonicalFieldNames.has(field) && values.indexOf(field) === index));
53299
+ const effectiveProjection = {
53300
+ ...projection,
53301
+ include,
53302
+ overrides: {},
53303
+ additions: [],
53304
+ };
53305
+ const baseColumns = this.projectSchemaColumns(visibleSchemaFields, effectiveProjection);
53306
+ const baseByField = new Map(baseColumns.map((column) => [column.field, column]));
53307
+ const previousOverrides = projection.overrides ?? {};
53308
+ const overrides = {};
53309
+ // Overrides de campos ausentes no snapshot são preservados, porém nunca
53310
+ // criam uma coluna por conta própria.
53311
+ Object.entries(previousOverrides).forEach(([field, override]) => {
53312
+ if (!canonicalFieldNames.has(field) && override && typeof override === 'object') {
53313
+ const safeOverride = this.clonePlainObject(override);
53314
+ delete safeOverride['field'];
53315
+ overrides[field] = safeOverride;
53316
+ }
53317
+ });
53318
+ authoredColumns.forEach((column) => {
53319
+ const field = String(column.field).trim();
53320
+ const base = baseByField.get(field);
53321
+ if (!base)
53322
+ return;
53323
+ const override = this.diffPortableColumnDefinition(base, column);
53324
+ if (Object.keys(override).length > 0) {
53325
+ overrides[field] = override;
53326
+ }
53327
+ });
53328
+ const additions = authoredColumns
53329
+ .filter((column) => !canonicalFieldNames.has(String(column.field).trim()))
53330
+ .map((column) => this.toPortableColumnDefinition(column));
53331
+ cloned.columns = [];
53332
+ cloned.columnProjection = {
53333
+ ...projection,
53334
+ source: 'schema',
53335
+ include,
53336
+ ...(Object.keys(overrides).length > 0 ? { overrides } : { overrides: undefined }),
53337
+ ...(additions.length > 0 ? { additions } : { additions: undefined }),
53338
+ };
53339
+ return cloned;
53340
+ }
53341
+ diffPortableColumnDefinition(base, authored) {
53342
+ const portableBase = this.toPortableColumnDefinition(base);
53343
+ const portableAuthored = this.toPortableColumnDefinition(authored);
53344
+ const override = {};
53345
+ Object.entries(portableAuthored).forEach(([key, value]) => {
53346
+ if (key === 'field' || value === undefined)
53347
+ return;
53348
+ if (!this.arePortableValuesEqual(portableBase[key], value)) {
53349
+ override[key] = this.clonePlainObject(value);
53350
+ }
53351
+ });
53352
+ return override;
53353
+ }
53354
+ toPortableColumnDefinition(column) {
53355
+ const cloned = this.clonePlainObject(column);
53356
+ delete cloned['_isApiField'];
53357
+ delete cloned['_originalApiType'];
53358
+ return cloned;
53359
+ }
53360
+ arePortableValuesEqual(left, right) {
53361
+ const canonicalize = (value) => {
53362
+ if (Array.isArray(value))
53363
+ return value.map(canonicalize);
53364
+ if (!value || typeof value !== 'object')
53365
+ return value;
53366
+ return Object.keys(value)
53367
+ .sort()
53368
+ .reduce((result, key) => {
53369
+ const candidate = value[key];
53370
+ if (candidate !== undefined)
53371
+ result[key] = canonicalize(candidate);
53372
+ return result;
53373
+ }, {});
53374
+ };
53375
+ return JSON.stringify(canonicalize(left)) === JSON.stringify(canonicalize(right));
53376
+ }
53145
53377
  applySchemaFieldPresentationsToExistingColumns(fields) {
53146
53378
  if (!Array.isArray(fields) || !fields.length)
53147
53379
  return;
@@ -61531,7 +61763,7 @@ const rendererSchema = {
61531
61763
  * Manifesto de authoring canônico para o componente praxis-table.
61532
61764
  * Este arquivo define o contrato executável para que agentes de IA editem tabelas.
61533
61765
  *
61534
- * @version 2.2.2
61766
+ * @version 2.2.3
61535
61767
  * @status COMPLIANT - Alinhado com o contrato v2 e TableConfig canônico.
61536
61768
  */
61537
61769
  const PRAXIS_TABLE_AUTHORING_MANIFEST = {
@@ -61539,7 +61771,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61539
61771
  componentId: 'praxis-table',
61540
61772
  ownerPackage: '@praxisui/table',
61541
61773
  configSchemaId: 'TableConfig',
61542
- manifestVersion: '2.2.2',
61774
+ manifestVersion: '2.2.3',
61543
61775
  runtimeInputs: [
61544
61776
  { name: 'config', type: 'TableConfig', description: 'Configuração completa da tabela' },
61545
61777
  { name: 'data', type: 'any[]', description: 'Dados a serem exibidos (modo client-side)' },
@@ -61552,6 +61784,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61552
61784
  ],
61553
61785
  editableTargets: [
61554
61786
  { kind: 'column', resolver: 'column-by-field', description: 'Colunas base da tabela' },
61787
+ { kind: 'columnProjection', resolver: 'schema-column-projection', description: 'Projecao de colunas derivada do schema com overrides editoriais' },
61555
61788
  { kind: 'computedColumn', resolver: 'column-by-field', description: 'Colunas calculadas' },
61556
61789
  { kind: 'renderer', resolver: 'renderer-in-column', description: 'Renderizador de célula' },
61557
61790
  { kind: 'conditionalRenderer', resolver: 'conditional-renderer-in-column', description: 'Renderizadores condicionais' },
@@ -61586,6 +61819,54 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61586
61819
  ],
61587
61820
  operations: [
61588
61821
  // --- COLUMN OPERATIONS ---
61822
+ {
61823
+ operationId: 'column.projection.configure',
61824
+ title: 'Usar colunas governadas pelo schema',
61825
+ description: 'Mantem /schemas/filtered como fonte estrutural das colunas e registra somente diferencas editoriais por nome canonico de campo. Nao use para inventar campos ou contornar metadata ausente.',
61826
+ scope: 'global',
61827
+ targetKind: 'columnProjection',
61828
+ target: { kind: 'columnProjection', resolver: 'schema-column-projection', ambiguityPolicy: 'fail', required: false },
61829
+ inputSchema: {
61830
+ type: 'object',
61831
+ required: ['source'],
61832
+ additionalProperties: false,
61833
+ properties: {
61834
+ source: { const: 'schema' },
61835
+ include: {
61836
+ type: 'array',
61837
+ uniqueItems: true,
61838
+ items: { type: 'string', minLength: 1 },
61839
+ description: 'Allowlist ordenada de campos canonicos. Recomendada para dados sensiveis ou quando a pagina precisa de uma projecao focada.',
61840
+ },
61841
+ overrides: {
61842
+ type: 'object',
61843
+ description: 'Mapa indexado pelo nome canonico do campo. O objeto de override nao pode conter field.',
61844
+ additionalProperties: {
61845
+ type: 'object',
61846
+ not: { required: ['field'] },
61847
+ },
61848
+ },
61849
+ additions: {
61850
+ type: 'array',
61851
+ description: 'Colunas editoriais sem correspondente no schema, normalmente derivadas pelo round-trip de colunas computadas. Uma adicao nunca substitui um campo canonico.',
61852
+ items: {
61853
+ type: 'object',
61854
+ required: ['field'],
61855
+ properties: {
61856
+ field: { type: 'string', minLength: 1 },
61857
+ header: { type: ['string', 'object'] },
61858
+ type: { enum: COLUMN_TYPES },
61859
+ },
61860
+ },
61861
+ },
61862
+ },
61863
+ },
61864
+ effects: [{ kind: 'set-value', path: 'columnProjection' }],
61865
+ validators: ['schema-column-override-field-immutable', 'editor-round-trip-preserve'],
61866
+ affectedPaths: ['columnProjection'],
61867
+ submissionImpact: 'affects-schema-backed-data',
61868
+ preconditions: ['config-initialized'],
61869
+ },
61589
61870
  {
61590
61871
  operationId: 'column.add',
61591
61872
  title: 'Adicionar coluna',
@@ -63187,6 +63468,12 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
63187
63468
  level: 'error',
63188
63469
  code: 'TB019',
63189
63470
  description: 'Operacoes runtime devem usar operationId e input declarados em tableRuntimeOperations sem alterar a configuracao persistida.'
63471
+ },
63472
+ {
63473
+ validatorId: 'schema-column-override-field-immutable',
63474
+ level: 'error',
63475
+ code: 'TB024',
63476
+ description: 'Overrides de projecao podem alterar apresentacao e comportamento, mas nunca a identidade canonica field.'
63190
63477
  }
63191
63478
  ],
63192
63479
  roundTripRequirements: [
@@ -1,6 +1,6 @@
1
1
  import { Observable, firstValueFrom } from 'rxjs';
2
2
  import { withAuthoringScopePolicy } from '@praxisui/ai';
3
- import { ad as setTableActionGlobalActionRef } from './praxisui-table-praxisui-table-CUH7vNfu.mjs';
3
+ import { ad as setTableActionGlobalActionRef } from './praxisui-table-praxisui-table-Cf63AwZs.mjs';
4
4
 
5
5
  class TableAgenticAuthoringTurnFlow {
6
6
  adapter;
@@ -1,7 +1,7 @@
1
1
  import { firstValueFrom } from 'rxjs';
2
2
  import { BaseAiAdapter, sanitizePraxisAssistantText, createComponentAuthoringContext } from '@praxisui/ai';
3
3
  import { PRAXIS_GLOBAL_ACTION_CATALOG, deepMerge } from '@praxisui/core';
4
- import { I as TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS, l as PRAXIS_TABLE_AUTHORING_MANIFEST, T as TABLE_AI_CAPABILITIES, Z as coerceTableComponentEditPlans, $ as compileTableComponentEditPlans, L as TASK_PRESETS, a4 as getTableComponentEditPlanCapabilities, E as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, y as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, G as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, K as TABLE_COMPONENT_EDIT_PLAN_VERSION, z as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, H as TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table-praxisui-table-CUH7vNfu.mjs';
4
+ import { I as TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS, l as PRAXIS_TABLE_AUTHORING_MANIFEST, T as TABLE_AI_CAPABILITIES, Z as coerceTableComponentEditPlans, $ as compileTableComponentEditPlans, L as TASK_PRESETS, a4 as getTableComponentEditPlanCapabilities, E as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, y as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, G as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, K as TABLE_COMPONENT_EDIT_PLAN_VERSION, z as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, H as TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table-praxisui-table-Cf63AwZs.mjs';
5
5
 
6
6
  const TABLE_ROW_EXPRESSION_CONTEXT_OPTION = {
7
7
  mode: 'expression',
@@ -1 +1 @@
1
- export { A as ANALYTICS_TABLE_ROW_KEY_FIELD, a as AnalyticsTableConfigAdapterService, b as AnalyticsTableContractService, c as AnalyticsTableStatsApiService, B as BOOLEAN_PRESETS, d as BehaviorConfigEditorComponent, C as CURRENCY_PRESETS, e as ColumnsConfigEditorComponent, D as DATE_PRESETS, f as DataFormatterComponent, g as DataFormattingService, F as FORMULA_TEMPLATES, h as FilterConfigService, i as FilterSettingsComponent, j as FormulaGeneratorService, J as JsonConfigEditorComponent, M as MessagesLocalizationEditorComponent, N as NUMBER_PRESETS, P as PERCENTAGE_PRESETS, k as PRAXIS_FILTER_COMPONENT_METADATA, l as PRAXIS_TABLE_AUTHORING_MANIFEST, m as PRAXIS_TABLE_COMPONENT_METADATA, n as PRAXIS_TABLE_TOOLBAR_APPEARANCE_PRESETS, o as PRAXIS_TABLE_TOOLBAR_DEFAULT_APPEARANCE, p as PRAXIS_TABLE_TOOLBAR_TOKEN_PRESETS, q as PraxisFilter, r as PraxisFilterWidgetConfigEditor, s as PraxisTable, t as PraxisTableConfigEditor, u as PraxisTableInlineAuthoringEditorComponent, v as PraxisTableToolbar, w as PraxisTableWidgetConfigEditor, S as STRING_PRESETS, T as TABLE_AI_CAPABILITIES, x as TABLE_COMPONENT_AI_CAPABILITIES, y as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, z as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, E as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, G as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, H as TABLE_COMPONENT_EDIT_PLAN_KIND, K as TABLE_COMPONENT_EDIT_PLAN_VERSION, L as TASK_PRESETS, O as TableDefaultsProvider, Q as TableRulesEditorComponent, R as ToolbarActionsEditorComponent, V as ValueMappingEditorComponent, U as VisualFormulaBuilderComponent, W as analyticsComparisonMetricField, X as buildTableApplyPlan, Y as coerceTableComponentEditPlan, Z as coerceTableComponentEditPlans, _ as compileTableComponentEditPlan, $ as compileTableComponentEditPlans, a0 as createTableAuthoringDocument, a1 as getActionId, a2 as getEnum, a3 as getTableCapabilities, a4 as getTableComponentEditPlanCapabilities, a5 as isTableRendererSupportedByRichContentP0, a6 as mapTableRendererToRichContentP0, a7 as normalizeTableAuthoringDocument, a8 as parseLegacyOrTableDocument, a9 as providePraxisFilterMetadata, aa as providePraxisTableMetadata, ab as providePraxisTableToolbarAppearance, ac as serializeTableAuthoringDocument, ae as toCanonicalTableConfig, af as validateTableAuthoringDocument } from './praxisui-table-praxisui-table-CUH7vNfu.mjs';
1
+ export { A as ANALYTICS_TABLE_ROW_KEY_FIELD, a as AnalyticsTableConfigAdapterService, b as AnalyticsTableContractService, c as AnalyticsTableStatsApiService, B as BOOLEAN_PRESETS, d as BehaviorConfigEditorComponent, C as CURRENCY_PRESETS, e as ColumnsConfigEditorComponent, D as DATE_PRESETS, f as DataFormatterComponent, g as DataFormattingService, F as FORMULA_TEMPLATES, h as FilterConfigService, i as FilterSettingsComponent, j as FormulaGeneratorService, J as JsonConfigEditorComponent, M as MessagesLocalizationEditorComponent, N as NUMBER_PRESETS, P as PERCENTAGE_PRESETS, k as PRAXIS_FILTER_COMPONENT_METADATA, l as PRAXIS_TABLE_AUTHORING_MANIFEST, m as PRAXIS_TABLE_COMPONENT_METADATA, n as PRAXIS_TABLE_TOOLBAR_APPEARANCE_PRESETS, o as PRAXIS_TABLE_TOOLBAR_DEFAULT_APPEARANCE, p as PRAXIS_TABLE_TOOLBAR_TOKEN_PRESETS, q as PraxisFilter, r as PraxisFilterWidgetConfigEditor, s as PraxisTable, t as PraxisTableConfigEditor, u as PraxisTableInlineAuthoringEditorComponent, v as PraxisTableToolbar, w as PraxisTableWidgetConfigEditor, S as STRING_PRESETS, T as TABLE_AI_CAPABILITIES, x as TABLE_COMPONENT_AI_CAPABILITIES, y as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, z as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, E as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, G as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, H as TABLE_COMPONENT_EDIT_PLAN_KIND, K as TABLE_COMPONENT_EDIT_PLAN_VERSION, L as TASK_PRESETS, O as TableDefaultsProvider, Q as TableRulesEditorComponent, R as ToolbarActionsEditorComponent, V as ValueMappingEditorComponent, U as VisualFormulaBuilderComponent, W as analyticsComparisonMetricField, X as buildTableApplyPlan, Y as coerceTableComponentEditPlan, Z as coerceTableComponentEditPlans, _ as compileTableComponentEditPlan, $ as compileTableComponentEditPlans, a0 as createTableAuthoringDocument, a1 as getActionId, a2 as getEnum, a3 as getTableCapabilities, a4 as getTableComponentEditPlanCapabilities, a5 as isTableRendererSupportedByRichContentP0, a6 as mapTableRendererToRichContentP0, a7 as normalizeTableAuthoringDocument, a8 as parseLegacyOrTableDocument, a9 as providePraxisFilterMetadata, aa as providePraxisTableMetadata, ab as providePraxisTableToolbarAppearance, ac as serializeTableAuthoringDocument, ae as toCanonicalTableConfig, af as validateTableAuthoringDocument } from './praxisui-table-praxisui-table-Cf63AwZs.mjs';
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "@praxisui/table",
3
- "version": "9.0.4-rc.47",
3
+ "version": "9.0.4-rc.49",
4
4
  "description": "Advanced data table for Angular (Praxis UI) with editing, filtering, sorting, virtualization, and settings panel integration.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
8
  "@angular/platform-browser": "^21.0.0",
9
- "@praxisui/ai": "^9.0.4-rc.47",
10
- "@praxisui/core": "^9.0.4-rc.47",
11
- "@praxisui/dynamic-fields": "^9.0.4-rc.47",
12
- "@praxisui/dynamic-form": "^9.0.4-rc.47",
13
- "@praxisui/metadata-editor": "^9.0.4-rc.47",
14
- "@praxisui/rich-content": "^9.0.4-rc.47",
15
- "@praxisui/settings-panel": "^9.0.4-rc.47",
16
- "@praxisui/table-rule-builder": "^9.0.4-rc.47",
9
+ "@praxisui/ai": "^9.0.4-rc.49",
10
+ "@praxisui/core": "^9.0.4-rc.49",
11
+ "@praxisui/dynamic-fields": "^9.0.4-rc.49",
12
+ "@praxisui/dynamic-form": "^9.0.4-rc.49",
13
+ "@praxisui/metadata-editor": "^9.0.4-rc.49",
14
+ "@praxisui/rich-content": "^9.0.4-rc.49",
15
+ "@praxisui/settings-panel": "^9.0.4-rc.49",
16
+ "@praxisui/table-rule-builder": "^9.0.4-rc.49",
17
17
  "@angular/cdk": "^21.0.0",
18
18
  "@angular/forms": "^21.0.0",
19
19
  "@angular/material": "^21.0.0",
20
20
  "@angular/router": "^21.0.0",
21
- "@praxisui/dialog": "^9.0.4-rc.47",
21
+ "@praxisui/dialog": "^9.0.4-rc.49",
22
22
  "rxjs": "~7.8.0"
23
23
  },
24
24
  "dependencies": {
@@ -914,10 +914,50 @@ Antes de plugar a tabela em uma aplicação, valide estes pontos:
914
914
  ### Top-level contract
915
915
 
916
916
  O contrato principal e `TableConfig` (alias de `TableConfigV2`) com extensoes de runtime aceitas no JSON:
917
- - Base tipada: `meta`, `columns`, `behavior`, `appearance`, `toolbar`, `actions`, `export`, `messages`, `localization`.
917
+ - Base tipada: `meta`, `columns`, `columnProjection`, `behavior`, `appearance`, `toolbar`, `actions`, `export`, `messages`, `localization`.
918
918
  - Extensoes fora do tipo estrito: `dialogs.confirm.delete`, `rowConditionalRenderers[]`, aliases legados de `behavior.virtualScroll.*` e chaves legadas de header em `actions.row.*`.
919
919
  - Artefatos auxiliares fora do `TableConfig`: `crud-overrides:<componentKeyId>` e o envelope autorado `TableAuthoringDocument`, que carrega `bindings.resourcePath` e `bindings.horizontalScroll`. A chave operacional da linha pertence ao `TableConfig` em `config.meta.idField`.
920
920
 
921
+ #### Projeção governada de colunas
922
+
923
+ Quando `columnProjection.source = "schema"`, a lista estrutural de colunas é
924
+ materializada a partir de `/schemas/filtered`; a página declara apenas diferenças
925
+ em `columnProjection.overrides`, indexadas pelo nome canônico do campo:
926
+
927
+ ```json
928
+ {
929
+ "columns": [],
930
+ "columnProjection": {
931
+ "source": "schema",
932
+ "include": ["competencia", "salarioBruto", "salarioLiquido"],
933
+ "overrides": {
934
+ "salarioLiquido": {
935
+ "sticky": "end",
936
+ "width": "160px"
937
+ }
938
+ }
939
+ }
940
+ }
941
+ ```
942
+
943
+ O runtime reaplica os overrides após bootstrap e atualização do schema. Uma chave
944
+ desconhecida não cria coluna, e `field` não pode ser alterado pelo override. Este
945
+ contrato não cria “defaults da surface” paralelos: tipo, visibilidade, ordem e
946
+ apresentação continuam pertencendo ao schema canônico; a página conserva apenas
947
+ as decisões editoriais específicas da experiência.
948
+
949
+ Durante a renderização, `columns` contém a materialização completa somente em
950
+ memória. Ao salvar, aplicar ou emitir `configChange`, o runtime compacta essa
951
+ materialização novamente: a ordem e os campos canônicos formam `include`, as
952
+ diferenças formam `overrides` e colunas computadas/client-owned sem equivalente
953
+ no schema formam `additions`. Uma `addition` cujo `field` colida com o schema é
954
+ ignorada; ela não pode sombrear a identidade canônica.
955
+
956
+ `include` é uma allowlist ordenada. Em recursos financeiros, pessoais ou
957
+ regulados, ela deve ser preferida para impedir que um novo campo do schema passe
958
+ a integrar a experiência sem decisão editorial explícita. A ausência de
959
+ `include` significa “todos os campos que o backend marcou como visíveis”.
960
+
921
961
  ### Coverage matrix
922
962
 
923
963
  Resumo de cobertura por bloco:
@@ -1368,6 +1368,7 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterCont
1368
1368
  private readonly paginatorIntl;
1369
1369
  private readonly schemaNormalizer;
1370
1370
  private schemaFieldsSnapshot;
1371
+ private schemaColumnFieldsSnapshot;
1371
1372
  private filterSchemaFieldsSnapshot;
1372
1373
  private runtimeSchemaMeta;
1373
1374
  schemaError: boolean;
@@ -2129,6 +2130,23 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterCont
2129
2130
  private loadOrVerifyRemoteSchema;
2130
2131
  private loadFilterSchemaSnapshot;
2131
2132
  private convertFieldToColumn;
2133
+ private usesSchemaColumnProjection;
2134
+ /**
2135
+ * Materializa a projeção efetiva sem promover o JSON da página a fonte de
2136
+ * verdade estrutural. Overrides desconhecidos não criam colunas e `field`
2137
+ * nunca pode ser substituído pelo consumidor.
2138
+ */
2139
+ private projectSchemaColumns;
2140
+ /**
2141
+ * Converte a configuração materializada usada pelo renderer de volta ao
2142
+ * contrato compacto e persistível. O schema continua sendo a fonte
2143
+ * estrutural; somente ordem/allowlist, diferenças editoriais e colunas sem
2144
+ * correspondente canônico são serializadas.
2145
+ */
2146
+ private toPortableTableConfig;
2147
+ private diffPortableColumnDefinition;
2148
+ private toPortableColumnDefinition;
2149
+ private arePortableValuesEqual;
2132
2150
  private applySchemaFieldPresentationsToExistingColumns;
2133
2151
  private applySchemaFieldPresentation;
2134
2152
  private applySchemaSemanticCellPresentation;
@@ -4380,7 +4398,7 @@ declare function serializeTableAuthoringDocument(doc: TableAuthoringDocument): u
4380
4398
  * Manifesto de authoring canônico para o componente praxis-table.
4381
4399
  * Este arquivo define o contrato executável para que agentes de IA editem tabelas.
4382
4400
  *
4383
- * @version 2.2.2
4401
+ * @version 2.2.3
4384
4402
  * @status COMPLIANT - Alinhado com o contrato v2 e TableConfig canônico.
4385
4403
  */
4386
4404
  declare const PRAXIS_TABLE_AUTHORING_MANIFEST: ComponentAuthoringManifest;