@praxisui/table 9.0.0-beta.88 → 9.0.0-beta.90

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.
@@ -36,7 +36,7 @@ import * as i13 from '@angular/cdk/drag-drop';
36
36
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
37
37
  import { Subject, debounceTime, takeUntil, firstValueFrom, of, BehaviorSubject, Subscription, take as take$1 } from 'rxjs';
38
38
  import * as i1 from '@praxisui/core';
39
- import { LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisJsonLogicService, PraxisIconDirective, PraxisIconButtonComponent, PraxisI18nService, isTableConfigV2, providePraxisI18nConfig, PRAXIS_GLOBAL_ACTION_CATALOG, SURFACE_OPEN_I18N_NAMESPACE, isRequiredGlobalActionPayloadMissing, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, ASYNC_CONFIG_STORAGE, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_VALUES, FieldControlType, normalizeControlTypeToken, resolveControlTypeAlias, mapFieldDefinitionsToMetadata, PraxisJsonLogicError, GLOBAL_ACTION_CATALOG, GenericCrudService, validateGlobalActionRefs, getGlobalActionCatalog, TableConfigService, createDefaultTableConfig, fillUndefined, deepMerge, INLINE_FILTER_ALIAS_TOKENS, GlobalConfigService, buildSchemaId, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, resolveInlineFilterControlType, fetchWithETag, serializeEntityLookupValueForPayload, ComponentMetadataRegistry, AnalyticsStatsRequestBuilderService, buildApiUrl, normalizePraxisDataQueryContext, API_URL, PraxisRuntimeComponentObservationRegistryService, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PraxisCollectionExportService, SchemaNormalizerService, translateResourceAvailabilityReason, ResourceDiscoveryService, ResourceSurfaceOpenAdapterService, CrudOperationResolutionService, ResourceQuickConnectComponent, assertPraxisCollectionExportArtifact, PRAXIS_LOADING_CTX, resolveColumnTypeFromFieldDefinition, isPraxisPresentationVisualizationTableSafe, resolveTextMaskFormatFromFieldDefinition, translateResourceDiscoveryText, supportsImplicitValuePresentation, resolveValuePresentation, renderPraxisPresentationVisualizationHtml, materializeResourceIdentity, translateUnavailableWorkflowMessage, CONNECTION_STORAGE, PRAXIS_LOADING_RENDERER, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG } from '@praxisui/core';
39
+ import { LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisJsonLogicService, PraxisIconDirective, PraxisIconButtonComponent, PraxisI18nService, isTableConfigV2, providePraxisI18nConfig, PRAXIS_GLOBAL_ACTION_CATALOG, SURFACE_OPEN_I18N_NAMESPACE, isRequiredGlobalActionPayloadMissing, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, ASYNC_CONFIG_STORAGE, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_VALUES, FieldControlType, normalizeControlTypeToken, resolveControlTypeAlias, mapFieldDefinitionsToMetadata, PraxisJsonLogicError, GLOBAL_ACTION_CATALOG, GenericCrudService, validateGlobalActionRefs, getGlobalActionCatalog, TableConfigService, createDefaultTableConfig, fillUndefined, deepMerge, INLINE_FILTER_ALIAS_TOKENS, GlobalConfigService, buildSchemaId, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, resolveInlineFilterControlType, fetchWithETag, serializeEntityLookupValueForPayload, ComponentMetadataRegistry, AnalyticsStatsRequestBuilderService, buildApiUrl, normalizePraxisDataQueryContext, API_URL, PraxisRuntimeComponentObservationRegistryService, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PraxisCollectionExportService, SchemaNormalizerService, translateResourceAvailabilityReason, ResourceDiscoveryService, ResourceSurfaceOpenAdapterService, CrudOperationResolutionService, ResourceQuickConnectComponent, assertPraxisCollectionExportArtifact, PRAXIS_LOADING_CTX, resolveColumnTypeFromFieldDefinition, isPraxisPresentationVisualizationTableSafe, resolveTextMaskFormatFromFieldDefinition, translateResourceDiscoveryText, supportsImplicitValuePresentation, resolveValuePresentation, renderPraxisPresentationVisualizationHtml, resolveResourceIdentityContract, materializeResourceIdentity, translateUnavailableWorkflowMessage, CONNECTION_STORAGE, PRAXIS_LOADING_RENDERER, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG } from '@praxisui/core';
40
40
  import { PraxisRichContent } from '@praxisui/rich-content';
41
41
  import * as i2 from '@angular/material/toolbar';
42
42
  import { MatToolbarModule } from '@angular/material/toolbar';
@@ -41646,6 +41646,9 @@ class PraxisTable {
41646
41646
  warnLog(message, data, meta) {
41647
41647
  this.getLogger().warn(message, this.buildLogOptions(data, meta));
41648
41648
  }
41649
+ infoLog(message, data, meta) {
41650
+ this.getLogger().info(message, this.buildLogOptions(data, meta));
41651
+ }
41649
41652
  warnOnceLog(message, data, meta) {
41650
41653
  this.getLogger().warnOnce(message, this.buildLogOptions(data, meta));
41651
41654
  }
@@ -42549,7 +42552,7 @@ class PraxisTable {
42549
42552
  if (this.aiAdapter || this.aiAdapterLoadStarted)
42550
42553
  return;
42551
42554
  this.aiAdapterLoadStarted = true;
42552
- import('./praxisui-table-table-ai.adapter-DjfE591p.mjs')
42555
+ import('./praxisui-table-table-ai.adapter-CeH1iTVt.mjs')
42553
42556
  .then(({ TableAiAdapter }) => {
42554
42557
  if (!this.isAiAssistantEnabled()) {
42555
42558
  this.aiAssistantOpenAfterAdapterLoad = false;
@@ -43295,7 +43298,7 @@ class PraxisTable {
43295
43298
  initializeAiAssistantController() {
43296
43299
  if (!this.aiAdapter || this.aiAssistantController)
43297
43300
  return;
43298
- import('./praxisui-table-table-agentic-authoring-turn-flow-Dk7mU6l2.mjs')
43301
+ import('./praxisui-table-table-agentic-authoring-turn-flow-BLNUMwu5.mjs')
43299
43302
  .then(({ TableAgenticAuthoringTurnFlow }) => {
43300
43303
  if (this.aiAssistantController || !this.aiAdapter)
43301
43304
  return;
@@ -56462,7 +56465,64 @@ class PraxisTable {
56462
56465
  materializeRecordIdentity(row) {
56463
56466
  if (!row || typeof row !== 'object' || Array.isArray(row))
56464
56467
  return null;
56465
- return materializeResourceIdentity(this.crudService.getResourceIdentity?.(), row, this.schemaFieldsSnapshot);
56468
+ const record = row;
56469
+ const canonicalContract = this.crudService.getResourceIdentity?.() ?? null;
56470
+ const canonicalDiagnostics = this.crudService.getResourceIdentityDiagnostics?.() ?? [];
56471
+ this.reportResourceIdentityDiagnostics(canonicalDiagnostics);
56472
+ const hostResolution = canonicalContract
56473
+ ? null
56474
+ : resolveResourceIdentityContract({
56475
+ effectiveIdField: this.resolveHostIdentityIdField(),
56476
+ availableFields: this.schemaFieldsSnapshot,
56477
+ });
56478
+ if (hostResolution) {
56479
+ this.reportResourceIdentityDiagnostics(hostResolution.diagnostics);
56480
+ }
56481
+ const contract = canonicalContract ?? hostResolution?.contract ?? null;
56482
+ const identity = materializeResourceIdentity(contract, record, this.schemaFieldsSnapshot);
56483
+ if (!identity && contract) {
56484
+ const field = contract.keyField
56485
+ ?? contract.titleField
56486
+ ?? contract.displayLabelField
56487
+ ?? contract.metadataFields?.[0];
56488
+ this.reportResourceIdentityDiagnostics([{
56489
+ code: 'resource-identity.value-missing',
56490
+ severity: 'warning',
56491
+ message: 'The configured record identity has no displayable value in this row.',
56492
+ source: contract.source,
56493
+ ...(field ? { field } : {}),
56494
+ }]);
56495
+ }
56496
+ return identity;
56497
+ }
56498
+ resolveHostIdentityIdField() {
56499
+ return this.resolveConfigMetaIdField()
56500
+ || this.normalizeIdField(this.crudContext?.idField)
56501
+ || undefined;
56502
+ }
56503
+ reportResourceIdentityDiagnostics(diagnostics) {
56504
+ for (const diagnostic of diagnostics) {
56505
+ const logMeta = {
56506
+ dedupeKey: [
56507
+ 'praxis-table:resource-identity',
56508
+ diagnostic.code,
56509
+ diagnostic.source || 'none',
56510
+ diagnostic.field || 'none',
56511
+ ].join(':'),
56512
+ throttleKey: [
56513
+ 'praxis-table:resource-identity',
56514
+ diagnostic.code,
56515
+ diagnostic.source || 'none',
56516
+ diagnostic.field || 'none',
56517
+ ].join(':'),
56518
+ context: { feature: 'resource-identity' },
56519
+ };
56520
+ if (diagnostic.severity === 'info') {
56521
+ this.infoLog('[PraxisTable] Resource identity diagnostic', { ...diagnostic }, logMeta);
56522
+ continue;
56523
+ }
56524
+ this.warnOnceLog('[PraxisTable] Resource identity diagnostic', { ...diagnostic }, logMeta);
56525
+ }
56466
56526
  }
56467
56527
  emitResourceEvent(kind, sourceOutput, payload, surface, resourceId, phase) {
56468
56528
  this.resourceEvent.emit(this.buildResourceEvent(kind, sourceOutput, payload, surface, resourceId, phase));
@@ -59111,213 +59171,270 @@ const tablePerformanceSchema = {
59111
59171
  }
59112
59172
  }
59113
59173
  };
59114
- const rendererSchema = {
59174
+ const rendererButtonSchema = {
59115
59175
  type: 'object',
59116
- description: 'Renderizador visual. Quando a intencao pedir chip, use type "chip" e configure chip; efeitos iconBadge materializam badge, nao chip.',
59117
- required: ['type'],
59176
+ required: ['action'],
59118
59177
  properties: {
59119
- type: { enum: RENDERER_TYPES },
59120
- typeExpr: { type: 'string' },
59121
- button: {
59122
- type: 'object',
59123
- required: ['action'],
59124
- properties: {
59125
- label: { type: 'string' },
59126
- labelField: { type: 'string' },
59127
- icon: { type: 'string' },
59128
- color: { enum: ['primary', 'accent', 'warn'] },
59129
- variant: { enum: ['filled', 'outlined', 'text'] },
59130
- size: { enum: ['sm', 'md', 'lg'] },
59131
- ariaLabel: { type: 'string' },
59132
- disabledCondition: { type: 'object', description: 'AST Json Logic' },
59133
- action: {
59134
- type: 'object',
59135
- required: ['id'],
59136
- properties: {
59137
- id: { type: 'string' },
59138
- payloadExpr: { type: 'string' }
59139
- }
59140
- }
59141
- }
59142
- },
59143
- menu: {
59144
- type: 'object',
59145
- required: ['itemsExpr'],
59146
- properties: {
59147
- itemsExpr: { type: 'string' },
59148
- ariaLabel: { type: 'string' }
59149
- }
59150
- },
59151
- link: {
59152
- type: 'object',
59153
- anyOf: [{ required: ['href'] }, { required: ['hrefField'] }],
59154
- properties: {
59155
- text: { type: 'string' },
59156
- textField: { type: 'string' },
59157
- href: { type: 'string' },
59158
- hrefField: { type: 'string' },
59159
- target: { enum: ['_blank', '_self', '_parent', '_top'] },
59160
- rel: { type: 'string' }
59161
- }
59162
- },
59163
- progress: {
59164
- type: 'object',
59165
- required: ['valueExpr'],
59166
- properties: {
59167
- valueExpr: { type: 'string' },
59168
- color: { type: 'string' },
59169
- showLabel: { type: 'boolean' }
59170
- }
59171
- },
59172
- badge: {
59178
+ label: { type: 'string' },
59179
+ labelField: { type: 'string' },
59180
+ icon: { type: 'string' },
59181
+ color: { enum: ['primary', 'accent', 'warn'] },
59182
+ variant: { enum: ['filled', 'outlined', 'text'] },
59183
+ size: { enum: ['sm', 'md', 'lg'] },
59184
+ ariaLabel: { type: 'string' },
59185
+ disabledCondition: { type: 'object', description: 'AST Json Logic' },
59186
+ action: {
59173
59187
  type: 'object',
59174
- anyOf: [{ required: ['text'] }, { required: ['textField'] }],
59188
+ required: ['id'],
59175
59189
  properties: {
59176
- text: { type: 'string' },
59177
- textField: { type: 'string' },
59178
- color: { enum: RENDERER_COLOR_TOKENS },
59179
- variant: { enum: ['filled', 'outlined', 'soft', 'plain'] },
59180
- icon: { type: 'string' },
59181
- tooltip: {
59182
- type: 'object',
59183
- properties: {
59184
- text: { type: 'string' },
59185
- position: { enum: ['top', 'right', 'bottom', 'left'] },
59186
- bgColor: { type: 'string' },
59187
- delayMs: { type: 'number' }
59188
- }
59189
- }
59190
+ id: { type: 'string' },
59191
+ payloadExpr: { type: 'string' }
59190
59192
  }
59191
- },
59192
- chip: {
59193
+ }
59194
+ }
59195
+ };
59196
+ const rendererMenuSchema = {
59197
+ type: 'object',
59198
+ required: ['itemsExpr'],
59199
+ properties: {
59200
+ itemsExpr: { type: 'string' },
59201
+ ariaLabel: { type: 'string' }
59202
+ }
59203
+ };
59204
+ const rendererLinkSchema = {
59205
+ type: 'object',
59206
+ anyOf: [{ required: ['href'] }, { required: ['hrefField'] }],
59207
+ properties: {
59208
+ text: { type: 'string' },
59209
+ textField: { type: 'string' },
59210
+ href: { type: 'string' },
59211
+ hrefField: { type: 'string' },
59212
+ target: { enum: ['_blank', '_self', '_parent', '_top'] },
59213
+ rel: { type: 'string' }
59214
+ }
59215
+ };
59216
+ const rendererProgressSchema = {
59217
+ type: 'object',
59218
+ required: ['valueExpr'],
59219
+ properties: {
59220
+ valueExpr: { type: 'string' },
59221
+ color: { type: 'string' },
59222
+ showLabel: { type: 'boolean' }
59223
+ }
59224
+ };
59225
+ const rendererBadgeSchema = {
59226
+ type: 'object',
59227
+ anyOf: [{ required: ['text'] }, { required: ['textField'] }],
59228
+ properties: {
59229
+ text: { type: 'string' },
59230
+ textField: { type: 'string' },
59231
+ color: { enum: RENDERER_COLOR_TOKENS },
59232
+ variant: { enum: ['filled', 'outlined', 'soft', 'plain'] },
59233
+ icon: { type: 'string' },
59234
+ tooltip: {
59193
59235
  type: 'object',
59194
- anyOf: [{ required: ['text'] }, { required: ['textField'] }],
59195
59236
  properties: {
59196
59237
  text: { type: 'string' },
59197
- textField: { type: 'string' },
59198
- color: { enum: RENDERER_COLOR_TOKENS },
59199
- variant: { enum: ['filled', 'outlined'] },
59200
- icon: { type: 'string' },
59201
- tooltip: {
59202
- type: 'object',
59203
- properties: {
59204
- text: { type: 'string' },
59205
- position: { enum: ['top', 'right', 'bottom', 'left'] },
59206
- bgColor: { type: 'string' },
59207
- delayMs: { type: 'number' }
59208
- }
59209
- }
59238
+ position: { enum: ['top', 'right', 'bottom', 'left'] },
59239
+ bgColor: { type: 'string' },
59240
+ delayMs: { type: 'number' }
59210
59241
  }
59211
- },
59212
- icon: {
59242
+ }
59243
+ }
59244
+ };
59245
+ const rendererChipSchema = {
59246
+ type: 'object',
59247
+ anyOf: [{ required: ['text'] }, { required: ['textField'] }],
59248
+ properties: {
59249
+ text: { type: 'string' },
59250
+ textField: { type: 'string' },
59251
+ color: { enum: RENDERER_COLOR_TOKENS },
59252
+ variant: { enum: ['filled', 'outlined'] },
59253
+ icon: { type: 'string' },
59254
+ tooltip: {
59213
59255
  type: 'object',
59214
- anyOf: [{ required: ['name'] }, { required: ['nameField'] }],
59215
59256
  properties: {
59216
- name: { type: 'string' },
59217
- nameField: { type: 'string' },
59218
59257
  text: { type: 'string' },
59219
- textField: { type: 'string' },
59220
- prefix: { type: 'string' },
59221
- suffix: { type: 'string' },
59222
- color: { type: 'string' },
59223
- size: { type: 'number' },
59224
- ariaLabel: { type: 'string' }
59225
- }
59226
- },
59227
- image: {
59228
- type: 'object',
59229
- anyOf: [{ required: ['src'] }, { required: ['srcField'] }],
59230
- properties: {
59231
- src: { type: 'string' },
59232
- srcField: { type: 'string' },
59233
- alt: { type: 'string' },
59234
- altField: { type: 'string' },
59235
- width: { type: 'number' },
59236
- height: { type: 'number' },
59237
- shape: { enum: ['square', 'rounded', 'circle'] },
59238
- fit: { enum: ['cover', 'contain'] },
59239
- lazy: { type: 'boolean' }
59240
- }
59241
- },
59242
- avatar: {
59243
- type: 'object',
59244
- anyOf: [{ required: ['src'] }, { required: ['srcField'] }, { required: ['initialsField'] }, { required: ['initialsExpr'] }],
59245
- properties: {
59246
- src: { type: 'string' },
59247
- srcField: { type: 'string' },
59248
- alt: { type: 'string' },
59249
- altField: { type: 'string' },
59250
- initialsField: { type: 'string' },
59251
- initialsExpr: { type: 'string' },
59252
- shape: { enum: ['circle', 'square', 'rounded'] },
59253
- size: { type: 'number' },
59254
- backgroundColor: { type: 'string' },
59255
- textColor: { type: 'string' }
59258
+ position: { enum: ['top', 'right', 'bottom', 'left'] },
59259
+ bgColor: { type: 'string' },
59260
+ delayMs: { type: 'number' }
59256
59261
  }
59257
- },
59258
- toggle: {
59262
+ }
59263
+ }
59264
+ };
59265
+ const rendererIconSchema = {
59266
+ type: 'object',
59267
+ anyOf: [{ required: ['name'] }, { required: ['nameField'] }],
59268
+ properties: {
59269
+ name: { type: 'string' },
59270
+ nameField: { type: 'string' },
59271
+ text: { type: 'string' },
59272
+ textField: { type: 'string' },
59273
+ prefix: { type: 'string' },
59274
+ suffix: { type: 'string' },
59275
+ color: { type: 'string' },
59276
+ size: { type: 'number' },
59277
+ ariaLabel: { type: 'string' }
59278
+ }
59279
+ };
59280
+ const rendererImageSchema = {
59281
+ type: 'object',
59282
+ anyOf: [{ required: ['src'] }, { required: ['srcField'] }],
59283
+ properties: {
59284
+ src: { type: 'string' },
59285
+ srcField: { type: 'string' },
59286
+ alt: { type: 'string' },
59287
+ altField: { type: 'string' },
59288
+ width: { type: 'number', description: 'Largura visual em pixels; altere apenas quando o pedido mudar o tamanho da imagem.' },
59289
+ height: { type: 'number', description: 'Altura visual em pixels; para imagem quadrada, mantenha igual a width.' },
59290
+ shape: { enum: ['square', 'rounded', 'circle'], description: 'square não arredonda, rounded usa cantos arredondados e circle materializa um círculo.' },
59291
+ fit: { enum: ['cover', 'contain'] },
59292
+ lazy: { type: 'boolean' }
59293
+ }
59294
+ };
59295
+ const rendererAvatarSchema = {
59296
+ type: 'object',
59297
+ anyOf: [{ required: ['src'] }, { required: ['srcField'] }, { required: ['initialsField'] }, { required: ['initialsExpr'] }],
59298
+ properties: {
59299
+ src: { type: 'string' },
59300
+ srcField: { type: 'string' },
59301
+ alt: { type: 'string' },
59302
+ altField: { type: 'string' },
59303
+ initialsField: { type: 'string' },
59304
+ initialsExpr: { type: 'string' },
59305
+ shape: { enum: ['circle', 'square', 'rounded'], description: 'circle é circular, square é quadrado e rounded é quadrado com cantos arredondados.' },
59306
+ size: { type: 'number', description: 'Tamanho visual do avatar em pixels; preserve os demais campos e itens do compose ao mudar apenas o tamanho.' },
59307
+ backgroundColor: { type: 'string' },
59308
+ textColor: { type: 'string' }
59309
+ }
59310
+ };
59311
+ const rendererToggleSchema = {
59312
+ type: 'object',
59313
+ required: ['stateExpr', 'action'],
59314
+ properties: {
59315
+ stateExpr: { type: 'string' },
59316
+ disabledCondition: { type: 'object', description: 'AST Json Logic' },
59317
+ ariaLabel: { type: 'string' },
59318
+ action: {
59259
59319
  type: 'object',
59260
- required: ['stateExpr', 'action'],
59320
+ required: ['id'],
59261
59321
  properties: {
59262
- stateExpr: { type: 'string' },
59263
- disabledCondition: { type: 'object', description: 'AST Json Logic' },
59264
- ariaLabel: { type: 'string' },
59265
- action: {
59266
- type: 'object',
59267
- required: ['id'],
59268
- properties: {
59269
- id: { type: 'string' },
59270
- payloadExpr: { type: 'string' }
59271
- }
59272
- }
59322
+ id: { type: 'string' },
59323
+ payloadExpr: { type: 'string' }
59273
59324
  }
59325
+ }
59326
+ }
59327
+ };
59328
+ const rendererRatingSchema = {
59329
+ type: 'object',
59330
+ required: ['valueExpr'],
59331
+ properties: {
59332
+ valueExpr: { type: 'string' },
59333
+ max: { type: 'number' },
59334
+ color: { type: 'string' },
59335
+ outlineColor: { type: 'string' },
59336
+ size: { enum: ['small', 'medium', 'large'] },
59337
+ ariaLabel: { type: 'string' }
59338
+ }
59339
+ };
59340
+ const rendererHtmlSchema = {
59341
+ type: 'object',
59342
+ required: ['template'],
59343
+ properties: {
59344
+ template: { type: 'string' },
59345
+ sanitize: { enum: ['strict', 'basic'] },
59346
+ emptyFallback: { type: 'string' }
59347
+ }
59348
+ };
59349
+ const rendererVariantRequirements = [
59350
+ { if: { properties: { type: { const: 'button' } } }, then: { required: ['button'] } },
59351
+ { if: { properties: { type: { const: 'menu' } } }, then: { required: ['menu'] } },
59352
+ { if: { properties: { type: { const: 'link' } } }, then: { required: ['link'] } },
59353
+ { if: { properties: { type: { const: 'progress' } } }, then: { required: ['progress'] } },
59354
+ { if: { properties: { type: { const: 'badge' } } }, then: { required: ['badge'] } },
59355
+ { if: { properties: { type: { const: 'chip' } } }, then: { required: ['chip'] } },
59356
+ { if: { properties: { type: { const: 'icon' } } }, then: { required: ['icon'] } },
59357
+ { if: { properties: { type: { const: 'image' } } }, then: { required: ['image'] } },
59358
+ { if: { properties: { type: { const: 'avatar' } } }, then: { required: ['avatar'] } },
59359
+ { if: { properties: { type: { const: 'toggle' } } }, then: { required: ['toggle'] } },
59360
+ { if: { properties: { type: { const: 'rating' } } }, then: { required: ['rating'] } },
59361
+ { if: { properties: { type: { const: 'html' } } }, then: { required: ['html'] } }
59362
+ ];
59363
+ const rendererComposeItemSchema = {
59364
+ type: 'object',
59365
+ description: 'Item de uma célula composta. value mostra um campo da linha; os demais tipos exigem seu bloco de configuração homônimo.',
59366
+ required: ['type'],
59367
+ properties: {
59368
+ type: {
59369
+ enum: ['value', 'icon', 'image', 'badge', 'link', 'button', 'chip', 'progress', 'avatar', 'toggle', 'menu', 'rating', 'html']
59274
59370
  },
59275
- rating: {
59276
- type: 'object',
59277
- required: ['valueExpr'],
59278
- properties: {
59279
- valueExpr: { type: 'string' },
59280
- max: { type: 'number' },
59281
- color: { type: 'string' },
59282
- outlineColor: { type: 'string' },
59283
- size: { enum: ['small', 'medium', 'large'] },
59284
- ariaLabel: { type: 'string' }
59285
- }
59371
+ field: { type: 'string' },
59372
+ textField: { type: 'string' },
59373
+ valueField: { type: 'string' },
59374
+ text: { type: 'string' },
59375
+ style: { type: 'string' },
59376
+ button: rendererButtonSchema,
59377
+ menu: rendererMenuSchema,
59378
+ link: rendererLinkSchema,
59379
+ progress: rendererProgressSchema,
59380
+ badge: rendererBadgeSchema,
59381
+ chip: rendererChipSchema,
59382
+ icon: rendererIconSchema,
59383
+ image: rendererImageSchema,
59384
+ avatar: rendererAvatarSchema,
59385
+ toggle: rendererToggleSchema,
59386
+ rating: rendererRatingSchema,
59387
+ html: rendererHtmlSchema
59388
+ },
59389
+ allOf: rendererVariantRequirements
59390
+ };
59391
+ const rendererComposeLayoutSchema = {
59392
+ type: 'object',
59393
+ minProperties: 1,
59394
+ properties: {
59395
+ gap: { type: 'number' },
59396
+ direction: {
59397
+ enum: ['row', 'column'],
59398
+ description: 'row coloca os itens lado a lado na mesma linha; column empilha verticalmente, por exemplo foto em cima e código embaixo.'
59286
59399
  },
59287
- html: {
59288
- type: 'object',
59289
- required: ['template'],
59290
- properties: {
59291
- template: { type: 'string' },
59292
- sanitize: { enum: ['strict', 'basic'] },
59293
- emptyFallback: { type: 'string' }
59294
- }
59400
+ align: { enum: ['start', 'center', 'end'] },
59401
+ wrap: { type: 'boolean' },
59402
+ ellipsis: { type: 'boolean' }
59403
+ }
59404
+ };
59405
+ const rendererComposeSchema = {
59406
+ type: 'object',
59407
+ description: 'Composição de vários itens dentro da mesma célula. Em refinamentos, preserve os itens atuais e altere somente o atributo solicitado.',
59408
+ required: ['items'],
59409
+ properties: {
59410
+ items: {
59411
+ type: 'array',
59412
+ minItems: 1,
59413
+ items: rendererComposeItemSchema
59295
59414
  },
59296
- compose: {
59297
- type: 'object',
59298
- required: ['items'],
59299
- properties: {
59300
- items: {
59301
- type: 'array',
59302
- minItems: 1,
59303
- items: {
59304
- type: 'object',
59305
- required: ['type'],
59306
- properties: { type: { enum: RENDERER_TYPES.filter(type => type !== 'compose') } }
59307
- }
59308
- },
59309
- layout: {
59310
- type: 'object',
59311
- properties: {
59312
- gap: { type: 'number' },
59313
- direction: { enum: ['row', 'column'] },
59314
- align: { enum: ['start', 'center', 'end'] },
59315
- wrap: { type: 'boolean' },
59316
- ellipsis: { type: 'boolean' }
59317
- }
59318
- }
59319
- }
59320
- }
59415
+ layout: rendererComposeLayoutSchema
59416
+ }
59417
+ };
59418
+ const rendererSchema = {
59419
+ type: 'object',
59420
+ description: 'Renderizador visual. Quando a intencao pedir chip, use type "chip" e configure chip; efeitos iconBadge materializam badge, nao chip. Ao refinar um compose existente, copie seus itens atuais e altere somente tamanho, forma, direção ou outra propriedade explicitamente solicitada.',
59421
+ required: ['type'],
59422
+ properties: {
59423
+ type: { enum: RENDERER_TYPES },
59424
+ typeExpr: { type: 'string' },
59425
+ button: rendererButtonSchema,
59426
+ menu: rendererMenuSchema,
59427
+ link: rendererLinkSchema,
59428
+ progress: rendererProgressSchema,
59429
+ badge: rendererBadgeSchema,
59430
+ chip: rendererChipSchema,
59431
+ icon: rendererIconSchema,
59432
+ image: rendererImageSchema,
59433
+ avatar: rendererAvatarSchema,
59434
+ toggle: rendererToggleSchema,
59435
+ rating: rendererRatingSchema,
59436
+ html: rendererHtmlSchema,
59437
+ compose: rendererComposeSchema
59321
59438
  },
59322
59439
  allOf: [
59323
59440
  { if: { properties: { type: { const: 'button' } } }, then: { required: ['button'] } },
@@ -59339,7 +59456,7 @@ const rendererSchema = {
59339
59456
  * Manifesto de authoring canônico para o componente praxis-table.
59340
59457
  * Este arquivo define o contrato executável para que agentes de IA editem tabelas.
59341
59458
  *
59342
- * @version 2.0.0
59459
+ * @version 2.2.1
59343
59460
  * @status COMPLIANT - Alinhado com o contrato v2 e TableConfig canônico.
59344
59461
  */
59345
59462
  const PRAXIS_TABLE_AUTHORING_MANIFEST = {
@@ -59347,7 +59464,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59347
59464
  componentId: 'praxis-table',
59348
59465
  ownerPackage: '@praxisui/table',
59349
59466
  configSchemaId: 'TableConfig',
59350
- manifestVersion: '2.0.0',
59467
+ manifestVersion: '2.2.1',
59351
59468
  runtimeInputs: [
59352
59469
  { name: 'config', type: 'TableConfig', description: 'Configuração completa da tabela' },
59353
59470
  { name: 'data', type: 'any[]', description: 'Dados a serem exibidos (modo client-side)' },
@@ -59432,7 +59549,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59432
59549
  },
59433
59550
  {
59434
59551
  operationId: 'column.header.set',
59435
- title: 'Definir cabeçalho',
59552
+ title: 'Renomear o título da coluna sem alterar valores das células',
59436
59553
  scope: 'column',
59437
59554
  targetKind: 'column',
59438
59555
  target: { kind: 'column', resolver: 'column-by-field', ambiguityPolicy: 'fail', required: true },
@@ -59610,7 +59727,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59610
59727
  },
59611
59728
  {
59612
59729
  operationId: 'column.valueMapping.set',
59613
- title: 'Definir mapeamento de valores',
59730
+ title: 'Mapear valores exibidos nas células sem renomear a coluna',
59614
59731
  scope: 'column',
59615
59732
  targetKind: 'column',
59616
59733
  target: { kind: 'column', resolver: 'column-by-field', ambiguityPolicy: 'fail', required: true },
@@ -59627,7 +59744,7 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59627
59744
  },
59628
59745
  {
59629
59746
  operationId: 'column.order.set',
59630
- title: 'Definir ordem visual',
59747
+ title: 'Mover coluna inteira sem alterar o conteúdo da célula',
59631
59748
  scope: 'column',
59632
59749
  targetKind: 'column',
59633
59750
  target: { kind: 'column', resolver: 'column-by-field', ambiguityPolicy: 'fail', required: true },
@@ -59644,7 +59761,8 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59644
59761
  },
59645
59762
  {
59646
59763
  operationId: 'column.visibility.set',
59647
- title: 'Definir visibilidade',
59764
+ title: 'Mostrar ou ocultar coluna independente sem excluí-la',
59765
+ description: 'Altera somente a visibilidade da coluna-alvo. Quando um pedido incorpora o conteúdo de uma coluna em outra célula e também diz que a coluna de origem não deve continuar separada, esta operação complementa a composição do renderer.',
59648
59766
  scope: 'column',
59649
59767
  targetKind: 'column',
59650
59768
  target: { kind: 'column', resolver: 'column-by-field', ambiguityPolicy: 'fail', required: true },
@@ -59686,7 +59804,8 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59686
59804
  },
59687
59805
  {
59688
59806
  operationId: 'column.renderer.set',
59689
- title: 'Definir renderizador',
59807
+ title: 'Compor ou definir o conteúdo visual dentro da célula',
59808
+ description: 'Define ou substitui o renderer raiz da célula. Para mudar somente direção, alinhamento, espaçamento ou quebra de um compose existente, use column.renderer.composeLayout.set. Para mudar somente tamanho, forma ou outra propriedade de um item existente, use column.renderer.composeItem.set. Esta operação não oculta uma coluna de origem; quando o mesmo pedido exige que essa origem deixe de aparecer separadamente, combine-a com column.visibility.set.',
59690
59809
  scope: 'column',
59691
59810
  targetKind: 'renderer',
59692
59811
  target: { kind: 'renderer', resolver: 'renderer-in-column', ambiguityPolicy: 'fail', required: true },
@@ -59697,6 +59816,66 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
59697
59816
  submissionImpact: 'visual-only',
59698
59817
  preconditions: ['config-initialized', 'target-exists']
59699
59818
  },
59819
+ {
59820
+ operationId: 'column.renderer.composeLayout.set',
59821
+ title: 'Refinar somente o layout de uma célula composta',
59822
+ description: 'Altera direção, alinhamento, espaçamento, quebra ou ellipsis do layout de renderer.type compose já existente. Preserva o discriminator compose, a ordem, a configuração e todos os itens atuais; não reconstrua os itens para uma mudança somente de layout.',
59823
+ scope: 'column',
59824
+ targetKind: 'renderer',
59825
+ target: { kind: 'renderer', resolver: 'renderer-in-column', ambiguityPolicy: 'fail', required: true },
59826
+ inputSchema: rendererComposeLayoutSchema,
59827
+ effects: [{
59828
+ kind: 'compile-domain-patch',
59829
+ handler: 'table-renderer-compose-layout-merge',
59830
+ path: 'columns[].renderer.compose.layout'
59831
+ }],
59832
+ validators: [
59833
+ 'target-column-exists',
59834
+ 'renderer-compose-exists',
59835
+ 'editor-round-trip-preserve'
59836
+ ],
59837
+ affectedPaths: ['columns[].renderer.compose.layout'],
59838
+ submissionImpact: 'visual-only',
59839
+ preconditions: ['config-initialized', 'target-exists']
59840
+ },
59841
+ {
59842
+ operationId: 'column.renderer.composeItem.set',
59843
+ title: 'Refinar somente um item existente da célula composta',
59844
+ description: 'Altera um único item já materializado em renderer.type compose, preservando o discriminator compose, o layout, a ordem e todos os itens irmãos. Use itemType para resolver o item; quando houver mais de um item do mesmo tipo, informe itemField para desambiguar.',
59845
+ scope: 'column',
59846
+ targetKind: 'renderer',
59847
+ target: { kind: 'renderer', resolver: 'renderer-in-column', ambiguityPolicy: 'fail', required: true },
59848
+ inputSchema: {
59849
+ type: 'object',
59850
+ required: ['itemType', 'item'],
59851
+ properties: {
59852
+ itemType: {
59853
+ enum: ['value', 'icon', 'image', 'badge', 'link', 'button', 'chip', 'progress', 'avatar', 'toggle', 'menu', 'rating', 'html'],
59854
+ description: 'Discriminator canônico do item existente que será refinado.'
59855
+ },
59856
+ itemField: {
59857
+ type: 'string',
59858
+ description: 'Campo estável do item quando itemType sozinho não o identifica de forma única.'
59859
+ },
59860
+ item: rendererComposeItemSchema
59861
+ }
59862
+ },
59863
+ effects: [{
59864
+ kind: 'compile-domain-patch',
59865
+ handler: 'table-renderer-compose-item-merge',
59866
+ path: 'columns[].renderer.compose.items[]'
59867
+ }],
59868
+ validators: [
59869
+ 'target-column-exists',
59870
+ 'renderer-compose-item-exists',
59871
+ 'renderer-type-supported',
59872
+ 'renderer-config-match',
59873
+ 'editor-round-trip-preserve'
59874
+ ],
59875
+ affectedPaths: ['columns[].renderer.compose.items[]'],
59876
+ submissionImpact: 'visual-only',
59877
+ preconditions: ['config-initialized', 'target-exists']
59878
+ },
59700
59879
  {
59701
59880
  operationId: 'column.conditionalRenderer.add',
59702
59881
  title: 'Adicionar renderizador condicional',
@@ -60796,6 +60975,18 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
60796
60975
  code: 'TB004',
60797
60976
  description: 'A configuração do renderizador deve corresponder ao tipo selecionado.'
60798
60977
  },
60978
+ {
60979
+ validatorId: 'renderer-compose-exists',
60980
+ level: 'error',
60981
+ code: 'TB022',
60982
+ description: 'O renderer alvo deve ser uma composição existente e conter ao menos um item antes de refinar seu layout.'
60983
+ },
60984
+ {
60985
+ validatorId: 'renderer-compose-item-exists',
60986
+ level: 'error',
60987
+ code: 'TB021',
60988
+ description: 'O renderer alvo deve ser compose e conter exatamente um item compatível com itemType e itemField.'
60989
+ },
60799
60990
  {
60800
60991
  validatorId: 'grouping-fields-exist',
60801
60992
  level: 'error',
@@ -61022,6 +61213,36 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61022
61213
  params: { field: 'email', header: 'Contato', type: 'string' },
61023
61214
  isPositive: true
61024
61215
  },
61216
+ {
61217
+ id: 'rename-active-column-to-status',
61218
+ request: 'Ativo vira Status.',
61219
+ operationId: 'column.header.set',
61220
+ target: 'ativo',
61221
+ params: { header: 'Status' },
61222
+ isPositive: true
61223
+ },
61224
+ {
61225
+ id: 'rename-column-title-without-changing-cell-values',
61226
+ request: 'Troque somente o título da coluna Ativo para Status, sem alterar os valores das células',
61227
+ operationId: 'column.header.set',
61228
+ target: 'ativo',
61229
+ params: { header: 'Status' },
61230
+ isPositive: true
61231
+ },
61232
+ {
61233
+ id: 'cell-value-mapping-is-not-header-renaming',
61234
+ request: 'Sem mudar o título da coluna Ativo, mostre Sim e Não no lugar dos valores das células',
61235
+ operationId: 'column.header.set',
61236
+ target: 'ativo',
61237
+ isPositive: false
61238
+ },
61239
+ {
61240
+ id: 'current-column-label-is-not-a-rename-request',
61241
+ request: 'Na coluna chamada Status, mostre um chip vermelho quando o valor estiver inativo',
61242
+ operationId: 'column.header.set',
61243
+ target: 'ativo',
61244
+ isPositive: false
61245
+ },
61025
61246
  {
61026
61247
  id: 'add-computed-column',
61027
61248
  request: 'Criar coluna de idade baseada na data de nascimento',
@@ -61046,6 +61267,29 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61046
61267
  },
61047
61268
  isPositive: true
61048
61269
  },
61270
+ {
61271
+ id: 'set-active-base-chip-for-status-pair',
61272
+ request: 'Na coluna Status, use chip verde quando ativo e chip vermelho quando inativo sem alterar as outras colunas',
61273
+ operationId: 'column.renderer.set',
61274
+ target: 'ativo',
61275
+ params: {
61276
+ type: 'chip',
61277
+ chip: { textField: 'ativo', color: 'success', variant: 'filled' }
61278
+ },
61279
+ isPositive: true
61280
+ },
61281
+ {
61282
+ id: 'add-inactive-conditional-chip',
61283
+ request: 'Na coluna Status, use chip verde quando ativo e chip vermelho quando inativo sem alterar as outras colunas',
61284
+ operationId: 'column.conditionalRenderer.add',
61285
+ target: 'ativo',
61286
+ params: {
61287
+ id: 'chip-inativo',
61288
+ condition: { "==": [{ "var": "ativo" }, false] },
61289
+ renderer: { type: 'chip', chip: { text: 'Inativo', color: 'warn', variant: 'filled' } }
61290
+ },
61291
+ isPositive: true
61292
+ },
61049
61293
  {
61050
61294
  id: 'enable-export',
61051
61295
  request: 'Habilitar exportação para Excel e PDF',
@@ -61094,6 +61338,84 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61094
61338
  params: { type: 'icon', image: { src: '...' } },
61095
61339
  isPositive: false
61096
61340
  },
61341
+ {
61342
+ id: 'compose-photo-and-code-in-code-cell',
61343
+ request: 'Na coluna Código, mostrar primeiro a foto e depois o código na mesma célula, sem manter Foto como coluna separada',
61344
+ operationId: 'column.renderer.set',
61345
+ target: 'codigo',
61346
+ params: {
61347
+ type: 'compose',
61348
+ compose: {
61349
+ items: [
61350
+ {
61351
+ type: 'avatar',
61352
+ avatar: {
61353
+ srcField: 'foto',
61354
+ altField: 'nome',
61355
+ initialsField: 'nome',
61356
+ shape: 'rounded',
61357
+ size: 32
61358
+ }
61359
+ },
61360
+ { type: 'value', field: 'codigo' }
61361
+ ],
61362
+ layout: { direction: 'row', align: 'center', gap: 8 }
61363
+ }
61364
+ },
61365
+ isPositive: true
61366
+ },
61367
+ {
61368
+ id: 'stack-existing-photo-and-code-vertically',
61369
+ request: 'No composto anterior, deixe em duas linhas: foto em cima e código embaixo',
61370
+ operationId: 'column.renderer.composeLayout.set',
61371
+ target: 'codigo',
61372
+ params: { direction: 'column' },
61373
+ isPositive: true
61374
+ },
61375
+ {
61376
+ id: 'grow-photo-inside-existing-compose',
61377
+ request: 'Aumente um pouco somente a foto dessa célula composta, sem mudar os outros itens',
61378
+ operationId: 'column.renderer.composeItem.set',
61379
+ target: 'codigo',
61380
+ params: {
61381
+ itemType: 'avatar',
61382
+ item: { type: 'avatar', avatar: { srcField: 'foto', initialsField: 'nome', shape: 'rounded', size: 40 } }
61383
+ },
61384
+ isPositive: true
61385
+ },
61386
+ {
61387
+ id: 'shrink-photo-inside-existing-compose',
61388
+ request: 'Diminua só essa foto; ela está grande demais, e preserve o restante',
61389
+ operationId: 'column.renderer.composeItem.set',
61390
+ target: 'codigo',
61391
+ params: {
61392
+ itemType: 'avatar',
61393
+ item: { type: 'avatar', avatar: { srcField: 'foto', initialsField: 'nome', shape: 'rounded', size: 24 } }
61394
+ },
61395
+ isPositive: true
61396
+ },
61397
+ {
61398
+ id: 'make-photo-circular-inside-existing-compose',
61399
+ request: 'Deixe somente a foto dessa célula composta circular, sem alterar tamanho, layout ou os outros itens',
61400
+ operationId: 'column.renderer.composeItem.set',
61401
+ target: 'codigo',
61402
+ params: {
61403
+ itemType: 'avatar',
61404
+ item: { type: 'avatar', avatar: { srcField: 'foto', initialsField: 'nome', shape: 'circle', size: 24 } }
61405
+ },
61406
+ isPositive: true
61407
+ },
61408
+ {
61409
+ id: 'set-composed-photo-rounded-square-after-correction',
61410
+ request: 'Deixe a foto circular... não, cancela essa parte: quero quadrada com cantos arredondados',
61411
+ operationId: 'column.renderer.composeItem.set',
61412
+ target: 'codigo',
61413
+ params: {
61414
+ itemType: 'avatar',
61415
+ item: { type: 'avatar', avatar: { srcField: 'foto', initialsField: 'nome', shape: 'rounded', size: 24 } }
61416
+ },
61417
+ isPositive: true
61418
+ },
61097
61419
  {
61098
61420
  id: 'set-button-renderer',
61099
61421
  request: 'Transformar a coluna acoes em botao que executa abrir-detalhe',
@@ -61186,14 +61508,37 @@ const PRAXIS_TABLE_AUTHORING_MANIFEST = {
61186
61508
  params: { visible: false },
61187
61509
  isPositive: true
61188
61510
  },
61511
+ {
61512
+ id: 'hide-source-column-after-cell-composition',
61513
+ request: 'Na coluna Código, mostrar primeiro a foto e depois o código na mesma célula, sem manter Foto como coluna separada',
61514
+ operationId: 'column.visibility.set',
61515
+ target: 'foto',
61516
+ params: { visible: false },
61517
+ isPositive: true
61518
+ },
61519
+ {
61520
+ id: 'move-whole-photo-column-before-code',
61521
+ request: 'Mover a coluna Foto inteira para antes da coluna Código, mantendo as duas colunas separadas e sem alterar suas células',
61522
+ operationId: 'column.order.set',
61523
+ target: 'foto',
61524
+ params: { order: 0 },
61525
+ isPositive: true
61526
+ },
61189
61527
  {
61190
61528
  id: 'map-active-status-labels',
61191
- request: 'Mostre Sim e Não na coluna ativo',
61529
+ request: 'Sem mudar o título da coluna Ativo, mostre Sim e Não no lugar dos valores das células',
61192
61530
  operationId: 'column.valueMapping.set',
61193
61531
  target: 'ativo',
61194
61532
  params: { valueMapping: { true: 'Sim', false: 'Não' } },
61195
61533
  isPositive: true
61196
61534
  },
61535
+ {
61536
+ id: 'column-header-renaming-is-not-value-mapping',
61537
+ request: 'Ativo vira Status.',
61538
+ operationId: 'column.valueMapping.set',
61539
+ target: 'ativo',
61540
+ isPositive: false
61541
+ },
61197
61542
  {
61198
61543
  id: 'set-avatar-chip-renderer',
61199
61544
  request: 'Corrija o avatar do funcionário e mantenha o nome como chip',