@praxisui/dynamic-form 4.0.0-beta.0 → 5.0.0-beta.0
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 +1 -3
- package/fesm2022/praxisui-dynamic-form.mjs +703 -429
- package/index.d.ts +12 -5
- package/package.json +5 -7
|
@@ -23,14 +23,13 @@ import { MatBadgeModule } from '@angular/material/badge';
|
|
|
23
23
|
import { firstValueFrom, BehaviorSubject, Subject, throwError, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs';
|
|
24
24
|
import { map, take, takeUntil, debounceTime, finalize } from 'rxjs/operators';
|
|
25
25
|
import * as i1$2 from '@praxisui/core';
|
|
26
|
-
import { PraxisIconDirective, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, deepMerge, createDefaultFormConfig, normalizeFormConfig as normalizeFormConfig$1, ensureIds, ASYNC_CONFIG_STORAGE, migrateFormLayoutRule, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisI18nService, ResourceQuickConnectComponent, composeHeadersWithVersion, buildApiUrl, mapFieldDefinitionsToMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, normalizeControlTypeKey, resolveSpan, resolveOffset, resolveOrder, resolveHidden, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, CONNECTION_STORAGE, API_URL, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, DynamicWidgetLoaderDirective, EmptyStateCardComponent, providePraxisI18nConfig, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_SPEC_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG } from '@praxisui/core';
|
|
26
|
+
import { PraxisIconDirective, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, deepMerge, createDefaultFormConfig, normalizeFormConfig as normalizeFormConfig$1, ensureIds, ASYNC_CONFIG_STORAGE, migrateFormLayoutRule, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisI18nService, ResourceQuickConnectComponent, composeHeadersWithVersion, buildApiUrl, mapFieldDefinitionsToMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, normalizeControlTypeKey, resolveSpan, resolveOffset, resolveOrder, resolveHidden, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, CONNECTION_STORAGE, API_URL, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, DynamicWidgetLoaderDirective, EmptyStateCardComponent, providePraxisI18nConfig, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_SPEC_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, PraxisJsonLogicService } from '@praxisui/core';
|
|
27
27
|
import * as i1 from '@praxisui/dynamic-fields';
|
|
28
28
|
import { getControlTypeCatalog, ConfirmDialogComponent, DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
|
|
29
29
|
import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
|
|
30
30
|
import * as i6 from '@angular/material/menu';
|
|
31
31
|
import { MatMenuModule } from '@angular/material/menu';
|
|
32
32
|
import { produce } from 'immer';
|
|
33
|
-
import { DslParser } from '@praxisui/specification';
|
|
34
33
|
import * as i7 from '@praxisui/settings-panel';
|
|
35
34
|
import { SETTINGS_PANEL_DATA, GLOBAL_CONFIG_DYNAMIC_FORM_COMPONENT } from '@praxisui/settings-panel';
|
|
36
35
|
import * as i12 from '@angular/router';
|
|
@@ -668,7 +667,7 @@ function withRatingMetadata(base, patch) {
|
|
|
668
667
|
}
|
|
669
668
|
|
|
670
669
|
/**
|
|
671
|
-
*
|
|
670
|
+
* Catálogo de capacidades do PraxisDynamicForm para uso da IA.
|
|
672
671
|
* Paths seguem o schema do FormConfig (layout + metadados de campos).
|
|
673
672
|
*/
|
|
674
673
|
var ColumnAlign;
|
|
@@ -835,7 +834,7 @@ function generateRulePropertyWhenFalseCapabilities(targetType, properties) {
|
|
|
835
834
|
path: `formRules[].effect.propertiesWhenFalse.${prop.name}`,
|
|
836
835
|
category: 'rules',
|
|
837
836
|
valueKind: prop.type === 'object' ? 'object' : prop.type === 'enum' ? 'enum' : prop.type === 'boolean' ? 'boolean' : prop.type === 'number' ? 'number' : 'string',
|
|
838
|
-
description: `Propriedade '${prop.label}' aplicada ao ${targetType} quando a
|
|
837
|
+
description: `Propriedade '${prop.label}' aplicada ao ${targetType} quando a condição é falsa.`,
|
|
839
838
|
example: prop.type === 'boolean' ? 'false' : prop.type === 'number' ? '0' : prop.type === 'enum' ? (prop.enumValues?.[0]?.value || 'valor') : 'valor',
|
|
840
839
|
safetyNotes: prop.type === 'object' ? 'O objeto deve seguir o schema esperado pelo componente alvo.' : undefined,
|
|
841
840
|
};
|
|
@@ -864,16 +863,17 @@ const FORM_AI_CAPABILITIES = {
|
|
|
864
863
|
'praxis-section-preset-picker'
|
|
865
864
|
],
|
|
866
865
|
notes: [
|
|
867
|
-
'Este
|
|
868
|
-
'Detalhes de propriedades internas de campos individuais devem ser tratados em
|
|
866
|
+
'Este catálogo foca em configurações de alto nÃvel (macro) do formulário e regras.',
|
|
867
|
+
'Detalhes de propriedades internas de campos individuais devem ser tratados em catálogos de microcomponentes.',
|
|
869
868
|
'Referencie campos pelo name em fieldMetadata[].name.',
|
|
870
869
|
'Para hierarquia do layout use sections[].rows[].columns[].fields (campos por coluna).',
|
|
871
|
-
'POLICY: Ao alterar arrays de layout (sections, rows, columns), o patch deve ser tratado como merge/append,
|
|
872
|
-
'
|
|
873
|
-
'
|
|
874
|
-
'
|
|
875
|
-
'
|
|
876
|
-
'
|
|
870
|
+
'POLICY: Ao alterar arrays de layout (sections, rows, columns), o patch deve ser tratado como merge/append, não replace total.',
|
|
871
|
+
'Condições booleanas declarativas devem usar Json Logic canônico. Funções, handlers e hooks continuam exigindo revisão de segurança ou wiring pelo host.',
|
|
872
|
+
'Regras condicionais devem usar JSON Logic canônico em rules.condition. Não utilize JS puro nem string ad hoc.',
|
|
873
|
+
'Taxonomia editorial: regras condicionais usam Json Logic; hooks/callbacks do host nao sao a mesma categoria de expressao; blocos editoriais tambem nao usam transform-pipeline.',
|
|
874
|
+
'Paths marcados como "critical" exigem confirmação explÃcita antes de alteração.',
|
|
875
|
+
'A surface editorial do FormConfig usa formBlocksBefore, formBlocksBeforeActions e formBlocksAfter com WidgetDefinition e não participa do formData.',
|
|
876
|
+
'formBlocksBeforeActions representa um slot semântico após as seções e antes da área principal de ações, preservando compatibilidade de formBlocksAfter.',
|
|
877
877
|
],
|
|
878
878
|
capabilities: [
|
|
879
879
|
// =============================================================================
|
|
@@ -883,21 +883,21 @@ const FORM_AI_CAPABILITIES = {
|
|
|
883
883
|
path: 'metadata.version',
|
|
884
884
|
category: 'metadata',
|
|
885
885
|
valueKind: 'string',
|
|
886
|
-
description: '
|
|
887
|
-
intentExamples: ['atualizar
|
|
886
|
+
description: 'Versão da configuração do formulário para controle de migração.',
|
|
887
|
+
intentExamples: ['atualizar versão do form'],
|
|
888
888
|
},
|
|
889
889
|
{
|
|
890
890
|
path: 'metadata.source',
|
|
891
891
|
category: 'metadata',
|
|
892
892
|
valueKind: 'enum',
|
|
893
893
|
allowedValues: ['local', 'server', 'default'],
|
|
894
|
-
description: 'Origem da
|
|
894
|
+
description: 'Origem da configuração do formulário.',
|
|
895
895
|
},
|
|
896
896
|
{
|
|
897
897
|
path: 'metadata.lastUpdated',
|
|
898
898
|
category: 'metadata',
|
|
899
899
|
valueKind: 'string',
|
|
900
|
-
description: 'Timestamp da
|
|
900
|
+
description: 'Timestamp da última atualização da configuração (ISO-8601).',
|
|
901
901
|
example: '2024-01-31T10:15:00Z',
|
|
902
902
|
safetyNotes: 'Valor gerado pelo host/servidor. Evite alterar manualmente.',
|
|
903
903
|
},
|
|
@@ -905,15 +905,15 @@ const FORM_AI_CAPABILITIES = {
|
|
|
905
905
|
path: 'metadata.schemaId',
|
|
906
906
|
category: 'metadata',
|
|
907
907
|
valueKind: 'string',
|
|
908
|
-
description: 'ID do schema de origem para
|
|
909
|
-
safetyNotes: '
|
|
908
|
+
description: 'ID do schema de origem para reconciliação no servidor.',
|
|
909
|
+
safetyNotes: 'Não deve ser manipulado diretamente pela IA sem contexto do backend.',
|
|
910
910
|
},
|
|
911
911
|
{
|
|
912
912
|
path: 'metadata.schemaContext',
|
|
913
913
|
category: 'metadata',
|
|
914
914
|
valueKind: 'object',
|
|
915
|
-
description: 'Contexto do schema usado para compor o
|
|
916
|
-
safetyNotes: 'Preenchido pelo backend.
|
|
915
|
+
description: 'Contexto do schema usado para compor o formulário.',
|
|
916
|
+
safetyNotes: 'Preenchido pelo backend. Não alterar sem coordenação com o servidor.',
|
|
917
917
|
},
|
|
918
918
|
{
|
|
919
919
|
path: 'metadata.schemaContext.path',
|
|
@@ -925,7 +925,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
925
925
|
path: 'metadata.schemaContext.operation',
|
|
926
926
|
category: 'metadata',
|
|
927
927
|
valueKind: 'string',
|
|
928
|
-
description: '
|
|
928
|
+
description: 'Operação do schema (ex.: "get", "post").',
|
|
929
929
|
},
|
|
930
930
|
{
|
|
931
931
|
path: 'metadata.schemaContext.schemaType',
|
|
@@ -938,45 +938,45 @@ const FORM_AI_CAPABILITIES = {
|
|
|
938
938
|
path: 'metadata.schemaContext.internal',
|
|
939
939
|
category: 'metadata',
|
|
940
940
|
valueKind: 'boolean',
|
|
941
|
-
description: 'Indica se o schema
|
|
941
|
+
description: 'Indica se o schema é interno.',
|
|
942
942
|
},
|
|
943
943
|
{
|
|
944
944
|
path: 'metadata.schemaContext.tenant',
|
|
945
945
|
category: 'metadata',
|
|
946
946
|
valueKind: 'string',
|
|
947
|
-
description: 'Tenant do schema (se
|
|
947
|
+
description: 'Tenant do schema (se aplicável).',
|
|
948
948
|
},
|
|
949
949
|
{
|
|
950
950
|
path: 'metadata.schemaContext.locale',
|
|
951
951
|
category: 'metadata',
|
|
952
952
|
valueKind: 'string',
|
|
953
|
-
description: 'Locale do schema (se
|
|
953
|
+
description: 'Locale do schema (se aplicável).',
|
|
954
954
|
},
|
|
955
955
|
{
|
|
956
956
|
path: 'metadata.serverHash',
|
|
957
957
|
category: 'metadata',
|
|
958
958
|
valueKind: 'string',
|
|
959
|
-
description: 'Hash dos dados do servidor para
|
|
960
|
-
safetyNotes: 'Valor gerado internamente,
|
|
959
|
+
description: 'Hash dos dados do servidor para detecção de mudanças.',
|
|
960
|
+
safetyNotes: 'Valor gerado internamente, não deve ser alterado manualmente.',
|
|
961
961
|
},
|
|
962
962
|
{
|
|
963
963
|
path: 'metadata.customizations',
|
|
964
964
|
category: 'metadata',
|
|
965
965
|
valueKind: 'array',
|
|
966
|
-
description: 'Log de
|
|
967
|
-
safetyNotes: 'Usado para auditoria,
|
|
966
|
+
description: 'Log de customizações manuais aplicadas ao formulário.',
|
|
967
|
+
safetyNotes: 'Usado para auditoria, não deve ser gerado pela IA.',
|
|
968
968
|
},
|
|
969
969
|
// =============================================================================
|
|
970
|
-
// FORM CONFIG - FIELD METADATA (
|
|
970
|
+
// FORM CONFIG - FIELD METADATA (Referência)
|
|
971
971
|
// =============================================================================
|
|
972
972
|
{
|
|
973
973
|
path: 'fieldMetadata',
|
|
974
974
|
category: 'fields',
|
|
975
975
|
valueKind: 'array',
|
|
976
|
-
description: 'Array de metadados dos campos. Usado para referenciar a
|
|
976
|
+
description: 'Array de metadados dos campos. Usado para referenciar a configuração de campos.',
|
|
977
977
|
critical: true,
|
|
978
|
-
safetyNotes: 'Consuma FieldMetadata via
|
|
979
|
-
intentExamples: ['adicionar novo campo ao
|
|
978
|
+
safetyNotes: 'Consuma FieldMetadata via catálogo base (field-metadata-ai-capabilities); use controlType para escolher overlay de microcomponente. Não altere props internas aqui sem consultar o catálogo base.',
|
|
979
|
+
intentExamples: ['adicionar novo campo ao formulário', 'remover campo de endereço'],
|
|
980
980
|
},
|
|
981
981
|
{
|
|
982
982
|
path: 'fieldMetadata[]',
|
|
@@ -984,7 +984,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
984
984
|
valueKind: 'object',
|
|
985
985
|
description: 'Item de metadados do campo (FieldMetadata).',
|
|
986
986
|
critical: true,
|
|
987
|
-
safetyNotes: 'Consuma FieldMetadata via
|
|
987
|
+
safetyNotes: 'Consuma FieldMetadata via catálogo base (field-metadata-ai-capabilities); use controlType para escolher overlay de microcomponente. Não altere props internas aqui sem consultar o catálogo base.',
|
|
988
988
|
},
|
|
989
989
|
// =============================================================================
|
|
990
990
|
// FORM CONFIG - EDITORIAL HOSTING
|
|
@@ -1046,14 +1046,14 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1046
1046
|
path: 'formBlocksBeforeActions',
|
|
1047
1047
|
category: 'editorial',
|
|
1048
1048
|
valueKind: 'array',
|
|
1049
|
-
description: 'Lista de WidgetDefinition renderizados depois das
|
|
1050
|
-
safetyNotes: 'Ideal para blocos contextuais
|
|
1049
|
+
description: 'Lista de WidgetDefinition renderizados depois das seções e antes da área principal de ações.',
|
|
1050
|
+
safetyNotes: 'Ideal para blocos contextuais próximos ao preenchimento, sem contaminar formData.',
|
|
1051
1051
|
},
|
|
1052
1052
|
{
|
|
1053
1053
|
path: 'formBlocksBeforeActions[]',
|
|
1054
1054
|
category: 'editorial',
|
|
1055
1055
|
valueKind: 'object',
|
|
1056
|
-
description: 'WidgetDefinition editorial hospedado antes da
|
|
1056
|
+
description: 'WidgetDefinition editorial hospedado antes da área principal de ações.',
|
|
1057
1057
|
},
|
|
1058
1058
|
{
|
|
1059
1059
|
path: 'formBlocksBeforeActions[].id',
|
|
@@ -1084,8 +1084,8 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1084
1084
|
path: 'formBlocksAfter',
|
|
1085
1085
|
category: 'editorial',
|
|
1086
1086
|
valueKind: 'array',
|
|
1087
|
-
description: 'Lista de WidgetDefinition renderizados depois do formulario inteiro, incluindo a
|
|
1088
|
-
safetyNotes: 'Blocos editoriais nao entram em formData e este slot
|
|
1087
|
+
description: 'Lista de WidgetDefinition renderizados depois do formulario inteiro, incluindo a área principal de ações.',
|
|
1088
|
+
safetyNotes: 'Blocos editoriais nao entram em formData e este slot é mais adequado para conteúdo de fechamento.',
|
|
1089
1089
|
},
|
|
1090
1090
|
{
|
|
1091
1091
|
path: 'formBlocksAfter[]',
|
|
@@ -1126,36 +1126,36 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1126
1126
|
path: 'sections[].id',
|
|
1127
1127
|
category: 'layout',
|
|
1128
1128
|
valueKind: 'string',
|
|
1129
|
-
description: 'ID
|
|
1129
|
+
description: 'ID único da seção.',
|
|
1130
1130
|
critical: true,
|
|
1131
|
-
safetyNotes: 'Alterar o ID pode quebrar
|
|
1131
|
+
safetyNotes: 'Alterar o ID pode quebrar referências de regras ou layout.',
|
|
1132
1132
|
},
|
|
1133
1133
|
{
|
|
1134
1134
|
path: 'sections[].title',
|
|
1135
1135
|
category: 'layout',
|
|
1136
1136
|
valueKind: 'string',
|
|
1137
|
-
description: '
|
|
1138
|
-
intentExamples: ['renomear
|
|
1137
|
+
description: 'TÃtulo exibido para cada seção do formulário.',
|
|
1138
|
+
intentExamples: ['renomear seção de endereços', 'colocar tÃtulo em maiúsculas'],
|
|
1139
1139
|
},
|
|
1140
1140
|
{
|
|
1141
1141
|
path: 'sections[].description',
|
|
1142
1142
|
category: 'layout',
|
|
1143
1143
|
valueKind: 'string',
|
|
1144
|
-
description: '
|
|
1145
|
-
intentExamples: ['adicionar
|
|
1144
|
+
description: 'Descrição auxiliar exibida abaixo do tÃtulo da seção.',
|
|
1145
|
+
intentExamples: ['adicionar descrição da seção', 'explicar uso da seção'],
|
|
1146
1146
|
},
|
|
1147
1147
|
{
|
|
1148
1148
|
path: 'sections[].icon',
|
|
1149
1149
|
category: 'layout',
|
|
1150
1150
|
valueKind: 'string',
|
|
1151
|
-
description: 'Nome do
|
|
1152
|
-
intentExamples: ['colocar
|
|
1151
|
+
description: 'Nome do Ãcone (Material Icons) para o cabeçalho da seção.',
|
|
1152
|
+
intentExamples: ['colocar Ãcone de casa na seção de endereço'],
|
|
1153
1153
|
},
|
|
1154
1154
|
{
|
|
1155
1155
|
path: 'sections[].sectionHeader',
|
|
1156
1156
|
category: 'layout',
|
|
1157
1157
|
valueKind: 'object',
|
|
1158
|
-
description: '
|
|
1158
|
+
description: 'Configuração rica do header visual da seção, com suporte a avatar por imagem, iniciais ou modo automático.',
|
|
1159
1159
|
safetyNotes: 'Prefira definir `sourceField` para imagem, `initialsSourceField` para iniciais e `emptyState` neutro em fluxos create.',
|
|
1160
1160
|
},
|
|
1161
1161
|
{
|
|
@@ -1163,13 +1163,13 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1163
1163
|
category: 'layout',
|
|
1164
1164
|
valueKind: 'enum',
|
|
1165
1165
|
allowedValues: ['icon', 'avatar-image', 'avatar-initials', 'auto'],
|
|
1166
|
-
description: '
|
|
1166
|
+
description: 'Estratégia visual do header da seção.',
|
|
1167
1167
|
},
|
|
1168
1168
|
{
|
|
1169
1169
|
path: 'sections[].sectionHeader.sourceField',
|
|
1170
1170
|
category: 'layout',
|
|
1171
1171
|
valueKind: 'string',
|
|
1172
|
-
description: 'Campo do
|
|
1172
|
+
description: 'Campo do formulário usado como origem da imagem do avatar.',
|
|
1173
1173
|
},
|
|
1174
1174
|
{
|
|
1175
1175
|
path: 'sections[].sectionHeader.initialsSourceField',
|
|
@@ -1187,227 +1187,227 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1187
1187
|
path: 'sections[].sectionHeader.fallbackIcon',
|
|
1188
1188
|
category: 'layout',
|
|
1189
1189
|
valueKind: 'string',
|
|
1190
|
-
description: '
|
|
1190
|
+
description: 'Ãcone opcional usado quando o avatar dinâmico estiver vazio ou inválido.',
|
|
1191
1191
|
},
|
|
1192
1192
|
{
|
|
1193
1193
|
path: 'sections[].sectionHeader.emptyState',
|
|
1194
1194
|
category: 'layout',
|
|
1195
1195
|
valueKind: 'enum',
|
|
1196
1196
|
allowedValues: ['fallback-icon', 'placeholder-avatar', 'none'],
|
|
1197
|
-
description: 'Comportamento do header quando os campos de origem ainda
|
|
1197
|
+
description: 'Comportamento do header quando os campos de origem ainda não possuem valor.',
|
|
1198
1198
|
},
|
|
1199
1199
|
{
|
|
1200
1200
|
path: 'sections[].sectionHeader.size',
|
|
1201
1201
|
category: 'layout',
|
|
1202
1202
|
valueKind: 'enum',
|
|
1203
1203
|
allowedValues: ['sm', 'md', 'lg'],
|
|
1204
|
-
description: 'Tamanho
|
|
1204
|
+
description: 'Tamanho semântico do avatar da seção, materializado pelo runtime via tokens.',
|
|
1205
1205
|
},
|
|
1206
1206
|
{
|
|
1207
1207
|
path: 'sections[].sectionHeader.initialsMaxLength',
|
|
1208
1208
|
category: 'layout',
|
|
1209
1209
|
valueKind: 'number',
|
|
1210
|
-
description: '
|
|
1210
|
+
description: 'Máximo de letras exibidas no avatar textual.',
|
|
1211
1211
|
},
|
|
1212
1212
|
{
|
|
1213
1213
|
path: 'sections[].collapsible',
|
|
1214
1214
|
category: 'layout',
|
|
1215
1215
|
valueKind: 'boolean',
|
|
1216
|
-
description: 'Define se a
|
|
1217
|
-
intentExamples: ['permitir fechar a
|
|
1216
|
+
description: 'Define se a seção pode ser colapsada/expandida pelo usuário.',
|
|
1217
|
+
intentExamples: ['permitir fechar a seção de anexos', 'tornar seção fixa'],
|
|
1218
1218
|
},
|
|
1219
1219
|
{
|
|
1220
1220
|
path: 'sections[].collapsed',
|
|
1221
1221
|
category: 'layout',
|
|
1222
1222
|
valueKind: 'boolean',
|
|
1223
|
-
description: 'Estado inicial da
|
|
1223
|
+
description: 'Estado inicial da seção (colapsada/expandida) quando `collapsible` é true.',
|
|
1224
1224
|
dependsOn: 'sections[].collapsible',
|
|
1225
|
-
intentExamples: ['recolher
|
|
1225
|
+
intentExamples: ['recolher seção de endereços por padrão', 'expandir dados básicos ao carregar'],
|
|
1226
1226
|
},
|
|
1227
1227
|
{
|
|
1228
1228
|
path: 'sections[].gapBottom',
|
|
1229
1229
|
category: 'layout',
|
|
1230
1230
|
valueKind: 'number',
|
|
1231
|
-
description: '
|
|
1232
|
-
intentExamples: ['aumentar
|
|
1231
|
+
description: 'Espaçamento vertical (em px) após a seção.',
|
|
1232
|
+
intentExamples: ['aumentar espaço depois da seção'],
|
|
1233
1233
|
},
|
|
1234
1234
|
{
|
|
1235
1235
|
path: 'sections[].titleGapBottom',
|
|
1236
1236
|
category: 'layout',
|
|
1237
1237
|
valueKind: 'number',
|
|
1238
|
-
description: '
|
|
1238
|
+
description: 'Espaçamento vertical (em px) abaixo do tÃtulo da seção.',
|
|
1239
1239
|
},
|
|
1240
1240
|
{
|
|
1241
1241
|
path: 'sections[].descriptionGapBottom',
|
|
1242
1242
|
category: 'layout',
|
|
1243
1243
|
valueKind: 'number',
|
|
1244
|
-
description: '
|
|
1244
|
+
description: 'Espaçamento vertical (em px) abaixo da descrição da seção.',
|
|
1245
1245
|
},
|
|
1246
1246
|
{
|
|
1247
1247
|
path: 'sections[].appearance',
|
|
1248
1248
|
category: 'appearance',
|
|
1249
1249
|
valueKind: 'enum',
|
|
1250
1250
|
allowedValues: ['card', 'plain', 'step'],
|
|
1251
|
-
description: 'Preset visual do container/
|
|
1252
|
-
intentExamples: ['deixar a
|
|
1251
|
+
description: 'Preset visual do container/cabeçalho da seção.',
|
|
1252
|
+
intentExamples: ['deixar a seção como step', 'remover card da seção'],
|
|
1253
1253
|
},
|
|
1254
1254
|
{
|
|
1255
1255
|
path: 'sections[].stepLabel',
|
|
1256
1256
|
category: 'content',
|
|
1257
1257
|
valueKind: 'string',
|
|
1258
|
-
description: '
|
|
1259
|
-
intentExamples: ['mostrar etapa 2', 'exibir badge
|
|
1258
|
+
description: 'Rótulo curto do passo exibido antes do tÃtulo da seção.',
|
|
1259
|
+
intentExamples: ['mostrar etapa 2', 'exibir badge numérico na seção'],
|
|
1260
1260
|
},
|
|
1261
1261
|
{
|
|
1262
1262
|
path: 'sections[].titleStyle',
|
|
1263
1263
|
category: 'appearance',
|
|
1264
1264
|
valueKind: 'enum',
|
|
1265
1265
|
allowedValues: ENUMS$1.sectionTitleStyle,
|
|
1266
|
-
description: 'Preset de tipografia para o
|
|
1267
|
-
intentExamples: ['
|
|
1266
|
+
description: 'Preset de tipografia para o tÃtulo da seção.',
|
|
1267
|
+
intentExamples: ['tÃtulo da seção maior'],
|
|
1268
1268
|
},
|
|
1269
1269
|
{
|
|
1270
1270
|
path: 'sections[].descriptionStyle',
|
|
1271
1271
|
category: 'appearance',
|
|
1272
1272
|
valueKind: 'enum',
|
|
1273
1273
|
allowedValues: ENUMS$1.sectionDescriptionStyle,
|
|
1274
|
-
description: 'Preset de tipografia para a
|
|
1275
|
-
intentExamples: ['
|
|
1274
|
+
description: 'Preset de tipografia para a descrição da seção.',
|
|
1275
|
+
intentExamples: ['descrição da seção em texto menor'],
|
|
1276
1276
|
},
|
|
1277
1277
|
{
|
|
1278
1278
|
path: 'sections[].titleColor',
|
|
1279
1279
|
category: 'appearance',
|
|
1280
1280
|
valueKind: 'string',
|
|
1281
|
-
description: 'Cor do
|
|
1281
|
+
description: 'Cor do tÃtulo da seção (CSS color ou token).',
|
|
1282
1282
|
},
|
|
1283
1283
|
{
|
|
1284
1284
|
path: 'sections[].descriptionColor',
|
|
1285
1285
|
category: 'appearance',
|
|
1286
1286
|
valueKind: 'string',
|
|
1287
|
-
description: 'Cor da
|
|
1287
|
+
description: 'Cor da descrição da seção (CSS color ou token).',
|
|
1288
1288
|
},
|
|
1289
1289
|
{
|
|
1290
1290
|
path: 'sections[].headerAlign',
|
|
1291
1291
|
category: 'appearance',
|
|
1292
1292
|
valueKind: 'enum',
|
|
1293
1293
|
allowedValues: ['start', 'center'],
|
|
1294
|
-
description: 'Alinhamento horizontal do
|
|
1294
|
+
description: 'Alinhamento horizontal do conteúdo do cabeçalho da seção.',
|
|
1295
1295
|
},
|
|
1296
1296
|
{
|
|
1297
1297
|
path: 'sections[].headerTooltip',
|
|
1298
1298
|
category: 'layout',
|
|
1299
1299
|
valueKind: 'string',
|
|
1300
|
-
description: 'Texto de tooltip para o
|
|
1300
|
+
description: 'Texto de tooltip para o cabeçalho da seção.',
|
|
1301
1301
|
},
|
|
1302
1302
|
{
|
|
1303
1303
|
path: 'sections[].headerActions',
|
|
1304
1304
|
category: 'layout',
|
|
1305
1305
|
valueKind: 'array',
|
|
1306
|
-
description: 'Lista de
|
|
1307
|
-
safetyNotes: 'Prefira IDs
|
|
1306
|
+
description: 'Lista de ações iconográficas renderizadas no canto direito do cabeçalho da seção.',
|
|
1307
|
+
safetyNotes: 'Prefira IDs estáveis porque essas ações podem ser alvo de regras e integrações do host.',
|
|
1308
1308
|
},
|
|
1309
1309
|
{
|
|
1310
1310
|
path: 'sections[].headerActions[].id',
|
|
1311
1311
|
category: 'layout',
|
|
1312
1312
|
valueKind: 'string',
|
|
1313
|
-
description: 'ID
|
|
1313
|
+
description: 'ID estável da ação de cabeçalho da seção.',
|
|
1314
1314
|
},
|
|
1315
1315
|
{
|
|
1316
1316
|
path: 'sections[].headerActions[].label',
|
|
1317
1317
|
category: 'layout',
|
|
1318
1318
|
valueKind: 'string',
|
|
1319
|
-
description: 'Label
|
|
1319
|
+
description: 'Label acessÃvel usada em tooltip e aria-label da ação.',
|
|
1320
1320
|
},
|
|
1321
1321
|
{
|
|
1322
1322
|
path: 'sections[].headerActions[].icon',
|
|
1323
1323
|
category: 'layout',
|
|
1324
1324
|
valueKind: 'string',
|
|
1325
|
-
description: '
|
|
1325
|
+
description: 'Ãcone renderizado na ação do cabeçalho da seção.',
|
|
1326
1326
|
},
|
|
1327
1327
|
{
|
|
1328
1328
|
path: 'sections[].headerActions[].action',
|
|
1329
1329
|
category: 'layout',
|
|
1330
1330
|
valueKind: 'string',
|
|
1331
|
-
description: 'Nome opcional da
|
|
1331
|
+
description: 'Nome opcional da ação emitida no customAction; se ausente, o runtime usa o ID.',
|
|
1332
1332
|
},
|
|
1333
1333
|
{
|
|
1334
1334
|
path: 'sections[].headerActions[].tooltip',
|
|
1335
1335
|
category: 'layout',
|
|
1336
1336
|
valueKind: 'string',
|
|
1337
|
-
description: 'Tooltip opcional da
|
|
1337
|
+
description: 'Tooltip opcional da ação; se ausente, o runtime usa a label.',
|
|
1338
1338
|
},
|
|
1339
1339
|
{
|
|
1340
1340
|
path: 'sections[].headerActions[].color',
|
|
1341
1341
|
category: 'appearance',
|
|
1342
1342
|
valueKind: 'enum',
|
|
1343
1343
|
allowedValues: ['primary', 'accent', 'warn', 'basic'],
|
|
1344
|
-
description: 'Tom visual da
|
|
1344
|
+
description: 'Tom visual da ação do cabeçalho da seção.',
|
|
1345
1345
|
},
|
|
1346
1346
|
{
|
|
1347
1347
|
path: 'sections[].headerActions[].visible',
|
|
1348
1348
|
category: 'layout',
|
|
1349
1349
|
valueKind: 'boolean',
|
|
1350
|
-
description: 'Controla a visibilidade da
|
|
1350
|
+
description: 'Controla a visibilidade da ação do cabeçalho da seção.',
|
|
1351
1351
|
},
|
|
1352
1352
|
{
|
|
1353
1353
|
path: 'sections[].headerActions[].disabled',
|
|
1354
1354
|
category: 'layout',
|
|
1355
1355
|
valueKind: 'boolean',
|
|
1356
|
-
description: 'Controla o estado desabilitado da
|
|
1356
|
+
description: 'Controla o estado desabilitado da ação do cabeçalho da seção.',
|
|
1357
1357
|
},
|
|
1358
1358
|
{
|
|
1359
1359
|
path: 'sections[].className',
|
|
1360
1360
|
category: 'appearance',
|
|
1361
1361
|
valueKind: 'string',
|
|
1362
|
-
description: 'Classe CSS aplicada ao container da
|
|
1362
|
+
description: 'Classe CSS aplicada ao container da seção.',
|
|
1363
1363
|
},
|
|
1364
1364
|
{
|
|
1365
1365
|
path: 'sections[].styles',
|
|
1366
1366
|
category: 'appearance',
|
|
1367
1367
|
valueKind: 'object',
|
|
1368
|
-
description: 'Estilos inline aplicados ao container da
|
|
1368
|
+
description: 'Estilos inline aplicados ao container da seção.',
|
|
1369
1369
|
},
|
|
1370
1370
|
{
|
|
1371
1371
|
path: 'sections[].rows[].id',
|
|
1372
1372
|
category: 'layout',
|
|
1373
1373
|
valueKind: 'string',
|
|
1374
|
-
description: 'ID
|
|
1374
|
+
description: 'ID único da linha dentro de uma seção.',
|
|
1375
1375
|
critical: true,
|
|
1376
|
-
safetyNotes: 'Alterar o ID pode quebrar
|
|
1376
|
+
safetyNotes: 'Alterar o ID pode quebrar referências de regras ou layout.',
|
|
1377
1377
|
},
|
|
1378
1378
|
{
|
|
1379
1379
|
path: 'sections[].rows[].title',
|
|
1380
1380
|
category: 'layout',
|
|
1381
1381
|
valueKind: 'string',
|
|
1382
|
-
description: '
|
|
1382
|
+
description: 'TÃtulo interno da linha (usado em editores e labels).',
|
|
1383
1383
|
},
|
|
1384
1384
|
{
|
|
1385
1385
|
path: 'sections[].rows[].gap',
|
|
1386
1386
|
category: 'layout',
|
|
1387
1387
|
valueKind: 'number',
|
|
1388
|
-
description: '
|
|
1389
|
-
intentExamples: ['aumentar
|
|
1388
|
+
description: 'Espaçamento horizontal (em px) entre colunas nesta linha.',
|
|
1389
|
+
intentExamples: ['aumentar espaço entre campos da linha'],
|
|
1390
1390
|
},
|
|
1391
1391
|
{
|
|
1392
1392
|
path: 'sections[].rows[].rowGap',
|
|
1393
1393
|
category: 'layout',
|
|
1394
1394
|
valueKind: 'number',
|
|
1395
|
-
description: '
|
|
1396
|
-
intentExamples: ['adicionar mais
|
|
1395
|
+
description: 'Espaçamento vertical (em px) após esta linha.',
|
|
1396
|
+
intentExamples: ['adicionar mais espaço depois desta linha de campos'],
|
|
1397
1397
|
},
|
|
1398
1398
|
{
|
|
1399
1399
|
path: 'sections[].rows[].columns[].id',
|
|
1400
1400
|
category: 'layout',
|
|
1401
1401
|
valueKind: 'string',
|
|
1402
|
-
description: 'ID
|
|
1402
|
+
description: 'ID único da coluna dentro de uma linha.',
|
|
1403
1403
|
critical: true,
|
|
1404
|
-
safetyNotes: 'Alterar o ID pode quebrar
|
|
1404
|
+
safetyNotes: 'Alterar o ID pode quebrar referências de regras ou layout.',
|
|
1405
1405
|
},
|
|
1406
1406
|
{
|
|
1407
1407
|
path: 'sections[].rows[].columns[].title',
|
|
1408
1408
|
category: 'layout',
|
|
1409
1409
|
valueKind: 'string',
|
|
1410
|
-
description: '
|
|
1410
|
+
description: 'TÃtulo interno da coluna (usado em editores e labels).',
|
|
1411
1411
|
},
|
|
1412
1412
|
{
|
|
1413
1413
|
path: 'sections[].rows[].columns[].testId',
|
|
@@ -1449,7 +1449,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1449
1449
|
path: 'sections[].rows[].columns[].span.md',
|
|
1450
1450
|
category: 'layout',
|
|
1451
1451
|
valueKind: 'number',
|
|
1452
|
-
description: 'Largura da coluna para telas
|
|
1452
|
+
description: 'Largura da coluna para telas médias (md) no grid system (1-12).',
|
|
1453
1453
|
},
|
|
1454
1454
|
{
|
|
1455
1455
|
path: 'sections[].rows[].columns[].span.lg',
|
|
@@ -1479,7 +1479,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1479
1479
|
path: 'sections[].rows[].columns[].offset.md',
|
|
1480
1480
|
category: 'layout',
|
|
1481
1481
|
valueKind: 'number',
|
|
1482
|
-
description: 'Offset da coluna para telas
|
|
1482
|
+
description: 'Offset da coluna para telas médias (md) no grid system (1-12).',
|
|
1483
1483
|
},
|
|
1484
1484
|
{
|
|
1485
1485
|
path: 'sections[].rows[].columns[].offset.lg',
|
|
@@ -1509,7 +1509,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1509
1509
|
path: 'sections[].rows[].columns[].order.md',
|
|
1510
1510
|
category: 'layout',
|
|
1511
1511
|
valueKind: 'number',
|
|
1512
|
-
description: 'Ordem visual da coluna para telas
|
|
1512
|
+
description: 'Ordem visual da coluna para telas médias (md).',
|
|
1513
1513
|
},
|
|
1514
1514
|
{
|
|
1515
1515
|
path: 'sections[].rows[].columns[].order.lg',
|
|
@@ -1539,7 +1539,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1539
1539
|
path: 'sections[].rows[].columns[].hidden.md',
|
|
1540
1540
|
category: 'layout',
|
|
1541
1541
|
valueKind: 'boolean',
|
|
1542
|
-
description: 'Oculta a coluna para telas
|
|
1542
|
+
description: 'Oculta a coluna para telas médias (md).',
|
|
1543
1543
|
},
|
|
1544
1544
|
{
|
|
1545
1545
|
path: 'sections[].rows[].columns[].hidden.lg',
|
|
@@ -1558,7 +1558,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1558
1558
|
category: 'layout',
|
|
1559
1559
|
valueKind: 'enum',
|
|
1560
1560
|
allowedValues: ENUMS$1.columnAlign,
|
|
1561
|
-
description: 'Alinhamento vertical do
|
|
1561
|
+
description: 'Alinhamento vertical do conteúdo da coluna.',
|
|
1562
1562
|
},
|
|
1563
1563
|
{
|
|
1564
1564
|
path: 'sections[].rows[].columns[].padding',
|
|
@@ -1570,7 +1570,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1570
1570
|
path: 'sections[].rows[].columns[].className',
|
|
1571
1571
|
category: 'appearance',
|
|
1572
1572
|
valueKind: 'string',
|
|
1573
|
-
description: 'Classe CSS aplicada
|
|
1573
|
+
description: 'Classe CSS aplicada à coluna.',
|
|
1574
1574
|
},
|
|
1575
1575
|
// =============================================================================
|
|
1576
1576
|
// FORM CONFIG - ACTIONS
|
|
@@ -1579,74 +1579,74 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1579
1579
|
path: 'actions.submit.id',
|
|
1580
1580
|
category: 'actions',
|
|
1581
1581
|
valueKind: 'string',
|
|
1582
|
-
description: 'ID do
|
|
1583
|
-
safetyNotes: 'Alterar o ID impacta regras e overrides por
|
|
1582
|
+
description: 'ID do botão de submissão.',
|
|
1583
|
+
safetyNotes: 'Alterar o ID impacta regras e overrides por ação.',
|
|
1584
1584
|
},
|
|
1585
1585
|
{
|
|
1586
1586
|
path: 'actions.submit.visible',
|
|
1587
1587
|
category: 'actions',
|
|
1588
1588
|
valueKind: 'boolean',
|
|
1589
|
-
description: 'Visibilidade do
|
|
1590
|
-
intentExamples: ['esconder
|
|
1589
|
+
description: 'Visibilidade do botão de submissão.',
|
|
1590
|
+
intentExamples: ['esconder botão de salvar', 'mostrar botão de enviar'],
|
|
1591
1591
|
},
|
|
1592
1592
|
{
|
|
1593
1593
|
path: 'actions.submit.label',
|
|
1594
1594
|
category: 'actions',
|
|
1595
1595
|
valueKind: 'string',
|
|
1596
|
-
description: '
|
|
1597
|
-
intentExamples: ['mudar texto do
|
|
1596
|
+
description: 'Rótulo do botão de submissão.',
|
|
1597
|
+
intentExamples: ['mudar texto do botão de salvar para "Finalizar"'],
|
|
1598
1598
|
},
|
|
1599
1599
|
{
|
|
1600
1600
|
path: 'actions.submit.icon',
|
|
1601
1601
|
category: 'actions',
|
|
1602
1602
|
valueKind: 'string',
|
|
1603
|
-
description: '
|
|
1603
|
+
description: 'Ãcone (Material Icons) para o botão de submissão.',
|
|
1604
1604
|
},
|
|
1605
1605
|
{
|
|
1606
1606
|
path: 'actions.submit.color',
|
|
1607
1607
|
category: 'actions',
|
|
1608
1608
|
valueKind: 'enum',
|
|
1609
1609
|
allowedValues: ENUMS$1.formActionButtonColor,
|
|
1610
|
-
description: 'Cor do
|
|
1610
|
+
description: 'Cor do botão de submissão.',
|
|
1611
1611
|
},
|
|
1612
1612
|
{
|
|
1613
1613
|
path: 'actions.submit.variant',
|
|
1614
1614
|
category: 'actions',
|
|
1615
1615
|
valueKind: 'enum',
|
|
1616
1616
|
allowedValues: ENUMS$1.formActionButtonVariant,
|
|
1617
|
-
description: 'Variante visual do
|
|
1617
|
+
description: 'Variante visual do botão de submissão.',
|
|
1618
1618
|
},
|
|
1619
1619
|
{
|
|
1620
1620
|
path: 'actions.submit.size',
|
|
1621
1621
|
category: 'actions',
|
|
1622
1622
|
valueKind: 'enum',
|
|
1623
1623
|
allowedValues: ENUMS$1.formActionButtonSize,
|
|
1624
|
-
description: 'Tamanho do
|
|
1624
|
+
description: 'Tamanho do botão de submissão.',
|
|
1625
1625
|
},
|
|
1626
1626
|
{
|
|
1627
1627
|
path: 'actions.submit.className',
|
|
1628
1628
|
category: 'actions',
|
|
1629
1629
|
valueKind: 'string',
|
|
1630
|
-
description: 'Classe CSS aplicada ao
|
|
1630
|
+
description: 'Classe CSS aplicada ao botão de submissão.',
|
|
1631
1631
|
},
|
|
1632
1632
|
{
|
|
1633
1633
|
path: 'actions.submit.style',
|
|
1634
1634
|
category: 'actions',
|
|
1635
1635
|
valueKind: 'object',
|
|
1636
|
-
description: 'Estilos inline aplicados ao
|
|
1636
|
+
description: 'Estilos inline aplicados ao botão de submissão.',
|
|
1637
1637
|
},
|
|
1638
1638
|
{
|
|
1639
1639
|
path: 'actions.submit.disabled',
|
|
1640
1640
|
category: 'actions',
|
|
1641
1641
|
valueKind: 'boolean',
|
|
1642
|
-
description: 'Desabilita o
|
|
1642
|
+
description: 'Desabilita o botão de submissão.',
|
|
1643
1643
|
},
|
|
1644
1644
|
{
|
|
1645
1645
|
path: 'actions.submit.type',
|
|
1646
1646
|
category: 'actions',
|
|
1647
1647
|
valueKind: 'enum',
|
|
1648
1648
|
allowedValues: ENUMS$1.formActionButtonType,
|
|
1649
|
-
description: 'Tipo do
|
|
1649
|
+
description: 'Tipo do botão de submissão.',
|
|
1650
1650
|
},
|
|
1651
1651
|
{
|
|
1652
1652
|
path: 'actions.submit.action',
|
|
@@ -1659,91 +1659,91 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1659
1659
|
path: 'actions.submit.tooltip',
|
|
1660
1660
|
category: 'actions',
|
|
1661
1661
|
valueKind: 'string',
|
|
1662
|
-
description: 'Tooltip exibido no
|
|
1662
|
+
description: 'Tooltip exibido no botão de submissão.',
|
|
1663
1663
|
},
|
|
1664
1664
|
{
|
|
1665
1665
|
path: 'actions.submit.loading',
|
|
1666
1666
|
category: 'actions',
|
|
1667
1667
|
valueKind: 'boolean',
|
|
1668
|
-
description: 'Exibe estado de carregamento no
|
|
1668
|
+
description: 'Exibe estado de carregamento no botão de submissão.',
|
|
1669
1669
|
},
|
|
1670
1670
|
{
|
|
1671
1671
|
path: 'actions.submit.shortcut',
|
|
1672
1672
|
category: 'actions',
|
|
1673
1673
|
valueKind: 'string',
|
|
1674
|
-
description: 'Atalho de teclado (ex.: "ctrl+s") para o
|
|
1674
|
+
description: 'Atalho de teclado (ex.: "ctrl+s") para o botão de submissão.',
|
|
1675
1675
|
},
|
|
1676
1676
|
{
|
|
1677
1677
|
path: 'actions.cancel.id',
|
|
1678
1678
|
category: 'actions',
|
|
1679
1679
|
valueKind: 'string',
|
|
1680
|
-
description: 'ID do
|
|
1681
|
-
safetyNotes: 'Alterar o ID impacta regras e overrides por
|
|
1680
|
+
description: 'ID do botão de cancelar.',
|
|
1681
|
+
safetyNotes: 'Alterar o ID impacta regras e overrides por ação.',
|
|
1682
1682
|
},
|
|
1683
1683
|
{
|
|
1684
1684
|
path: 'actions.cancel.visible',
|
|
1685
1685
|
category: 'actions',
|
|
1686
1686
|
valueKind: 'boolean',
|
|
1687
|
-
description: 'Visibilidade do
|
|
1688
|
-
intentExamples: ['esconder
|
|
1687
|
+
description: 'Visibilidade do botão de cancelar.',
|
|
1688
|
+
intentExamples: ['esconder botão de cancelar'],
|
|
1689
1689
|
},
|
|
1690
1690
|
{
|
|
1691
1691
|
path: 'actions.cancel.label',
|
|
1692
1692
|
category: 'actions',
|
|
1693
1693
|
valueKind: 'string',
|
|
1694
|
-
description: '
|
|
1694
|
+
description: 'Rótulo do botão de cancelar.',
|
|
1695
1695
|
},
|
|
1696
1696
|
{
|
|
1697
1697
|
path: 'actions.cancel.icon',
|
|
1698
1698
|
category: 'actions',
|
|
1699
1699
|
valueKind: 'string',
|
|
1700
|
-
description: '
|
|
1700
|
+
description: 'Ãcone (Material Icons) para o botão de cancelar.',
|
|
1701
1701
|
},
|
|
1702
1702
|
{
|
|
1703
1703
|
path: 'actions.cancel.color',
|
|
1704
1704
|
category: 'actions',
|
|
1705
1705
|
valueKind: 'enum',
|
|
1706
1706
|
allowedValues: ENUMS$1.formActionButtonColor,
|
|
1707
|
-
description: 'Cor do
|
|
1707
|
+
description: 'Cor do botão de cancelar.',
|
|
1708
1708
|
},
|
|
1709
1709
|
{
|
|
1710
1710
|
path: 'actions.cancel.variant',
|
|
1711
1711
|
category: 'actions',
|
|
1712
1712
|
valueKind: 'enum',
|
|
1713
1713
|
allowedValues: ENUMS$1.formActionButtonVariant,
|
|
1714
|
-
description: 'Variante visual do
|
|
1714
|
+
description: 'Variante visual do botão de cancelar.',
|
|
1715
1715
|
},
|
|
1716
1716
|
{
|
|
1717
1717
|
path: 'actions.cancel.size',
|
|
1718
1718
|
category: 'actions',
|
|
1719
1719
|
valueKind: 'enum',
|
|
1720
1720
|
allowedValues: ENUMS$1.formActionButtonSize,
|
|
1721
|
-
description: 'Tamanho do
|
|
1721
|
+
description: 'Tamanho do botão de cancelar.',
|
|
1722
1722
|
},
|
|
1723
1723
|
{
|
|
1724
1724
|
path: 'actions.cancel.className',
|
|
1725
1725
|
category: 'actions',
|
|
1726
1726
|
valueKind: 'string',
|
|
1727
|
-
description: 'Classe CSS aplicada ao
|
|
1727
|
+
description: 'Classe CSS aplicada ao botão de cancelar.',
|
|
1728
1728
|
},
|
|
1729
1729
|
{
|
|
1730
1730
|
path: 'actions.cancel.style',
|
|
1731
1731
|
category: 'actions',
|
|
1732
1732
|
valueKind: 'object',
|
|
1733
|
-
description: 'Estilos inline aplicados ao
|
|
1733
|
+
description: 'Estilos inline aplicados ao botão de cancelar.',
|
|
1734
1734
|
},
|
|
1735
1735
|
{
|
|
1736
1736
|
path: 'actions.cancel.disabled',
|
|
1737
1737
|
category: 'actions',
|
|
1738
1738
|
valueKind: 'boolean',
|
|
1739
|
-
description: 'Desabilita o
|
|
1739
|
+
description: 'Desabilita o botão de cancelar.',
|
|
1740
1740
|
},
|
|
1741
1741
|
{
|
|
1742
1742
|
path: 'actions.cancel.type',
|
|
1743
1743
|
category: 'actions',
|
|
1744
1744
|
valueKind: 'enum',
|
|
1745
1745
|
allowedValues: ENUMS$1.formActionButtonType,
|
|
1746
|
-
description: 'Tipo do
|
|
1746
|
+
description: 'Tipo do botão de cancelar.',
|
|
1747
1747
|
},
|
|
1748
1748
|
{
|
|
1749
1749
|
path: 'actions.cancel.action',
|
|
@@ -1756,90 +1756,90 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1756
1756
|
path: 'actions.cancel.tooltip',
|
|
1757
1757
|
category: 'actions',
|
|
1758
1758
|
valueKind: 'string',
|
|
1759
|
-
description: 'Tooltip exibido no
|
|
1759
|
+
description: 'Tooltip exibido no botão de cancelar.',
|
|
1760
1760
|
},
|
|
1761
1761
|
{
|
|
1762
1762
|
path: 'actions.cancel.loading',
|
|
1763
1763
|
category: 'actions',
|
|
1764
1764
|
valueKind: 'boolean',
|
|
1765
|
-
description: 'Exibe estado de carregamento no
|
|
1765
|
+
description: 'Exibe estado de carregamento no botão de cancelar.',
|
|
1766
1766
|
},
|
|
1767
1767
|
{
|
|
1768
1768
|
path: 'actions.cancel.shortcut',
|
|
1769
1769
|
category: 'actions',
|
|
1770
1770
|
valueKind: 'string',
|
|
1771
|
-
description: 'Atalho de teclado (ex.: "esc") para o
|
|
1771
|
+
description: 'Atalho de teclado (ex.: "esc") para o botão de cancelar.',
|
|
1772
1772
|
},
|
|
1773
1773
|
{
|
|
1774
1774
|
path: 'actions.reset.id',
|
|
1775
1775
|
category: 'actions',
|
|
1776
1776
|
valueKind: 'string',
|
|
1777
|
-
description: 'ID do
|
|
1778
|
-
safetyNotes: 'Alterar o ID impacta regras e overrides por
|
|
1777
|
+
description: 'ID do botão de reset.',
|
|
1778
|
+
safetyNotes: 'Alterar o ID impacta regras e overrides por ação.',
|
|
1779
1779
|
},
|
|
1780
1780
|
{
|
|
1781
1781
|
path: 'actions.reset.visible',
|
|
1782
1782
|
category: 'actions',
|
|
1783
1783
|
valueKind: 'boolean',
|
|
1784
|
-
description: 'Visibilidade do
|
|
1784
|
+
description: 'Visibilidade do botão de reset.',
|
|
1785
1785
|
},
|
|
1786
1786
|
{
|
|
1787
1787
|
path: 'actions.reset.label',
|
|
1788
1788
|
category: 'actions',
|
|
1789
1789
|
valueKind: 'string',
|
|
1790
|
-
description: '
|
|
1790
|
+
description: 'Rótulo do botão de reset.',
|
|
1791
1791
|
},
|
|
1792
1792
|
{
|
|
1793
1793
|
path: 'actions.reset.icon',
|
|
1794
1794
|
category: 'actions',
|
|
1795
1795
|
valueKind: 'string',
|
|
1796
|
-
description: '
|
|
1796
|
+
description: 'Ãcone (Material Icons) para o botão de reset.',
|
|
1797
1797
|
},
|
|
1798
1798
|
{
|
|
1799
1799
|
path: 'actions.reset.color',
|
|
1800
1800
|
category: 'actions',
|
|
1801
1801
|
valueKind: 'enum',
|
|
1802
1802
|
allowedValues: ENUMS$1.formActionButtonColor,
|
|
1803
|
-
description: 'Cor do
|
|
1803
|
+
description: 'Cor do botão de reset.',
|
|
1804
1804
|
},
|
|
1805
1805
|
{
|
|
1806
1806
|
path: 'actions.reset.variant',
|
|
1807
1807
|
category: 'actions',
|
|
1808
1808
|
valueKind: 'enum',
|
|
1809
1809
|
allowedValues: ENUMS$1.formActionButtonVariant,
|
|
1810
|
-
description: 'Variante visual do
|
|
1810
|
+
description: 'Variante visual do botão de reset.',
|
|
1811
1811
|
},
|
|
1812
1812
|
{
|
|
1813
1813
|
path: 'actions.reset.size',
|
|
1814
1814
|
category: 'actions',
|
|
1815
1815
|
valueKind: 'enum',
|
|
1816
1816
|
allowedValues: ENUMS$1.formActionButtonSize,
|
|
1817
|
-
description: 'Tamanho do
|
|
1817
|
+
description: 'Tamanho do botão de reset.',
|
|
1818
1818
|
},
|
|
1819
1819
|
{
|
|
1820
1820
|
path: 'actions.reset.className',
|
|
1821
1821
|
category: 'actions',
|
|
1822
1822
|
valueKind: 'string',
|
|
1823
|
-
description: 'Classe CSS aplicada ao
|
|
1823
|
+
description: 'Classe CSS aplicada ao botão de reset.',
|
|
1824
1824
|
},
|
|
1825
1825
|
{
|
|
1826
1826
|
path: 'actions.reset.style',
|
|
1827
1827
|
category: 'actions',
|
|
1828
1828
|
valueKind: 'object',
|
|
1829
|
-
description: 'Estilos inline aplicados ao
|
|
1829
|
+
description: 'Estilos inline aplicados ao botão de reset.',
|
|
1830
1830
|
},
|
|
1831
1831
|
{
|
|
1832
1832
|
path: 'actions.reset.disabled',
|
|
1833
1833
|
category: 'actions',
|
|
1834
1834
|
valueKind: 'boolean',
|
|
1835
|
-
description: 'Desabilita o
|
|
1835
|
+
description: 'Desabilita o botão de reset.',
|
|
1836
1836
|
},
|
|
1837
1837
|
{
|
|
1838
1838
|
path: 'actions.reset.type',
|
|
1839
1839
|
category: 'actions',
|
|
1840
1840
|
valueKind: 'enum',
|
|
1841
1841
|
allowedValues: ENUMS$1.formActionButtonType,
|
|
1842
|
-
description: 'Tipo do
|
|
1842
|
+
description: 'Tipo do botão de reset.',
|
|
1843
1843
|
},
|
|
1844
1844
|
{
|
|
1845
1845
|
path: 'actions.reset.action',
|
|
@@ -1852,105 +1852,105 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1852
1852
|
path: 'actions.reset.tooltip',
|
|
1853
1853
|
category: 'actions',
|
|
1854
1854
|
valueKind: 'string',
|
|
1855
|
-
description: 'Tooltip exibido no
|
|
1855
|
+
description: 'Tooltip exibido no botão de reset.',
|
|
1856
1856
|
},
|
|
1857
1857
|
{
|
|
1858
1858
|
path: 'actions.reset.loading',
|
|
1859
1859
|
category: 'actions',
|
|
1860
1860
|
valueKind: 'boolean',
|
|
1861
|
-
description: 'Exibe estado de carregamento no
|
|
1861
|
+
description: 'Exibe estado de carregamento no botão de reset.',
|
|
1862
1862
|
},
|
|
1863
1863
|
{
|
|
1864
1864
|
path: 'actions.reset.shortcut',
|
|
1865
1865
|
category: 'actions',
|
|
1866
1866
|
valueKind: 'string',
|
|
1867
|
-
description: 'Atalho de teclado (ex.: "ctrl+shift+r") para o
|
|
1867
|
+
description: 'Atalho de teclado (ex.: "ctrl+shift+r") para o botão de reset.',
|
|
1868
1868
|
},
|
|
1869
1869
|
{
|
|
1870
1870
|
path: 'actions.custom',
|
|
1871
1871
|
category: 'actions',
|
|
1872
1872
|
valueKind: 'array',
|
|
1873
|
-
description: 'Lista de
|
|
1874
|
-
safetyNotes: 'Cada
|
|
1873
|
+
description: 'Lista de botões de ação customizados.',
|
|
1874
|
+
safetyNotes: 'Cada ação customizada deve ter `id` ou `action` válidos.',
|
|
1875
1875
|
},
|
|
1876
1876
|
{
|
|
1877
1877
|
path: 'actions.custom[]',
|
|
1878
1878
|
category: 'actions',
|
|
1879
1879
|
valueKind: 'object',
|
|
1880
|
-
description: '
|
|
1881
|
-
safetyNotes: '
|
|
1882
|
-
example: '{ id: "myAction", label: "
|
|
1880
|
+
description: 'Configuração de um botão de ação customizado.',
|
|
1881
|
+
safetyNotes: 'Ações customizadas requerem `id` ou `action` e um handler registrado para funcionar.',
|
|
1882
|
+
example: '{ id: "myAction", label: "Ação Customizada", icon: "star", action: "myCustomEvent" }',
|
|
1883
1883
|
},
|
|
1884
1884
|
{
|
|
1885
1885
|
path: 'actions.custom[].id',
|
|
1886
1886
|
category: 'actions',
|
|
1887
1887
|
valueKind: 'string',
|
|
1888
|
-
description: 'ID da
|
|
1889
|
-
safetyNotes: 'Usado para overrides e mensagens por
|
|
1888
|
+
description: 'ID da ação customizada.',
|
|
1889
|
+
safetyNotes: 'Usado para overrides e mensagens por ação.',
|
|
1890
1890
|
},
|
|
1891
1891
|
{
|
|
1892
1892
|
path: 'actions.custom[].visible',
|
|
1893
1893
|
category: 'actions',
|
|
1894
1894
|
valueKind: 'boolean',
|
|
1895
|
-
description: 'Visibilidade da
|
|
1895
|
+
description: 'Visibilidade da ação customizada.',
|
|
1896
1896
|
},
|
|
1897
1897
|
{
|
|
1898
1898
|
path: 'actions.custom[].label',
|
|
1899
1899
|
category: 'actions',
|
|
1900
1900
|
valueKind: 'string',
|
|
1901
|
-
description: '
|
|
1901
|
+
description: 'Rótulo da ação customizada.',
|
|
1902
1902
|
},
|
|
1903
1903
|
{
|
|
1904
1904
|
path: 'actions.custom[].icon',
|
|
1905
1905
|
category: 'actions',
|
|
1906
1906
|
valueKind: 'string',
|
|
1907
|
-
description: '
|
|
1907
|
+
description: 'Ãcone (Material Icons) para a ação customizada.',
|
|
1908
1908
|
},
|
|
1909
1909
|
{
|
|
1910
1910
|
path: 'actions.custom[].color',
|
|
1911
1911
|
category: 'actions',
|
|
1912
1912
|
valueKind: 'enum',
|
|
1913
1913
|
allowedValues: ENUMS$1.formActionButtonColor,
|
|
1914
|
-
description: 'Cor da
|
|
1914
|
+
description: 'Cor da ação customizada.',
|
|
1915
1915
|
},
|
|
1916
1916
|
{
|
|
1917
1917
|
path: 'actions.custom[].variant',
|
|
1918
1918
|
category: 'actions',
|
|
1919
1919
|
valueKind: 'enum',
|
|
1920
1920
|
allowedValues: ENUMS$1.formActionButtonVariant,
|
|
1921
|
-
description: 'Variante visual da
|
|
1921
|
+
description: 'Variante visual da ação customizada.',
|
|
1922
1922
|
},
|
|
1923
1923
|
{
|
|
1924
1924
|
path: 'actions.custom[].size',
|
|
1925
1925
|
category: 'actions',
|
|
1926
1926
|
valueKind: 'enum',
|
|
1927
1927
|
allowedValues: ENUMS$1.formActionButtonSize,
|
|
1928
|
-
description: 'Tamanho da
|
|
1928
|
+
description: 'Tamanho da ação customizada.',
|
|
1929
1929
|
},
|
|
1930
1930
|
{
|
|
1931
1931
|
path: 'actions.custom[].className',
|
|
1932
1932
|
category: 'actions',
|
|
1933
1933
|
valueKind: 'string',
|
|
1934
|
-
description: 'Classe CSS aplicada
|
|
1934
|
+
description: 'Classe CSS aplicada à ação customizada.',
|
|
1935
1935
|
},
|
|
1936
1936
|
{
|
|
1937
1937
|
path: 'actions.custom[].style',
|
|
1938
1938
|
category: 'actions',
|
|
1939
1939
|
valueKind: 'object',
|
|
1940
|
-
description: 'Estilos inline aplicados
|
|
1940
|
+
description: 'Estilos inline aplicados à ação customizada.',
|
|
1941
1941
|
},
|
|
1942
1942
|
{
|
|
1943
1943
|
path: 'actions.custom[].disabled',
|
|
1944
1944
|
category: 'actions',
|
|
1945
1945
|
valueKind: 'boolean',
|
|
1946
|
-
description: 'Desabilita a
|
|
1946
|
+
description: 'Desabilita a ação customizada.',
|
|
1947
1947
|
},
|
|
1948
1948
|
{
|
|
1949
1949
|
path: 'actions.custom[].type',
|
|
1950
1950
|
category: 'actions',
|
|
1951
1951
|
valueKind: 'enum',
|
|
1952
1952
|
allowedValues: ENUMS$1.formActionButtonType,
|
|
1953
|
-
description: 'Tipo do
|
|
1953
|
+
description: 'Tipo do botão da ação customizada.',
|
|
1954
1954
|
},
|
|
1955
1955
|
{
|
|
1956
1956
|
path: 'actions.custom[].action',
|
|
@@ -1963,132 +1963,132 @@ const FORM_AI_CAPABILITIES = {
|
|
|
1963
1963
|
path: 'actions.custom[].tooltip',
|
|
1964
1964
|
category: 'actions',
|
|
1965
1965
|
valueKind: 'string',
|
|
1966
|
-
description: 'Tooltip exibido na
|
|
1966
|
+
description: 'Tooltip exibido na ação customizada.',
|
|
1967
1967
|
},
|
|
1968
1968
|
{
|
|
1969
1969
|
path: 'actions.custom[].loading',
|
|
1970
1970
|
category: 'actions',
|
|
1971
1971
|
valueKind: 'boolean',
|
|
1972
|
-
description: 'Exibe estado de carregamento na
|
|
1972
|
+
description: 'Exibe estado de carregamento na ação customizada.',
|
|
1973
1973
|
},
|
|
1974
1974
|
{
|
|
1975
1975
|
path: 'actions.custom[].shortcut',
|
|
1976
1976
|
category: 'actions',
|
|
1977
1977
|
valueKind: 'string',
|
|
1978
|
-
description: 'Atalho de teclado para a
|
|
1978
|
+
description: 'Atalho de teclado para a ação customizada.',
|
|
1979
1979
|
},
|
|
1980
1980
|
{
|
|
1981
1981
|
path: 'actions.position',
|
|
1982
1982
|
category: 'layout',
|
|
1983
1983
|
valueKind: 'enum',
|
|
1984
1984
|
allowedValues: ENUMS$1.formActionsLayoutPosition,
|
|
1985
|
-
description: 'Posicionamento horizontal da barra de
|
|
1985
|
+
description: 'Posicionamento horizontal da barra de ações.',
|
|
1986
1986
|
},
|
|
1987
1987
|
{
|
|
1988
1988
|
path: 'actions.orientation',
|
|
1989
1989
|
category: 'layout',
|
|
1990
1990
|
valueKind: 'enum',
|
|
1991
1991
|
allowedValues: ENUMS$1.formActionsLayoutOrientation,
|
|
1992
|
-
description: '
|
|
1992
|
+
description: 'Orientação dos botões dentro da barra de ações (horizontal/vertical).',
|
|
1993
1993
|
},
|
|
1994
1994
|
{
|
|
1995
1995
|
path: 'actions.spacing',
|
|
1996
1996
|
category: 'layout',
|
|
1997
1997
|
valueKind: 'enum',
|
|
1998
1998
|
allowedValues: ENUMS$1.formActionsLayoutSpacing,
|
|
1999
|
-
description: '
|
|
1999
|
+
description: 'Espaçamento entre os botões na barra de ações.',
|
|
2000
2000
|
},
|
|
2001
2001
|
{
|
|
2002
2002
|
path: 'actions.sticky',
|
|
2003
2003
|
category: 'layout',
|
|
2004
2004
|
valueKind: 'boolean',
|
|
2005
|
-
description: 'Define se a barra de
|
|
2005
|
+
description: 'Define se a barra de ações deve permanecer visÃvel ao rolar a página.',
|
|
2006
2006
|
},
|
|
2007
2007
|
{
|
|
2008
2008
|
path: 'actions.divider',
|
|
2009
2009
|
category: 'layout',
|
|
2010
2010
|
valueKind: 'boolean',
|
|
2011
|
-
description: 'Exibe um divisor superior acima da barra de
|
|
2011
|
+
description: 'Exibe um divisor superior acima da barra de ações.',
|
|
2012
2012
|
},
|
|
2013
2013
|
{
|
|
2014
2014
|
path: 'actions.placement',
|
|
2015
2015
|
category: 'layout',
|
|
2016
2016
|
valueKind: 'enum',
|
|
2017
2017
|
allowedValues: ENUMS$1.formActionsLayoutPlacement,
|
|
2018
|
-
description: '
|
|
2018
|
+
description: 'Localização estrutural da barra de ações no layout.',
|
|
2019
2019
|
},
|
|
2020
2020
|
{
|
|
2021
2021
|
path: 'actions.mobile.position',
|
|
2022
2022
|
category: 'layout',
|
|
2023
2023
|
valueKind: 'enum',
|
|
2024
2024
|
allowedValues: ENUMS$1.formActionsLayoutMobilePosition,
|
|
2025
|
-
description: 'Posicionamento da barra de
|
|
2025
|
+
description: 'Posicionamento da barra de ações em dispositivos móveis.',
|
|
2026
2026
|
},
|
|
2027
2027
|
{
|
|
2028
2028
|
path: 'actions.mobile.orientation',
|
|
2029
2029
|
category: 'layout',
|
|
2030
2030
|
valueKind: 'enum',
|
|
2031
2031
|
allowedValues: ENUMS$1.formActionsLayoutOrientation,
|
|
2032
|
-
description: '
|
|
2032
|
+
description: 'Orientação dos botões em dispositivos móveis.',
|
|
2033
2033
|
},
|
|
2034
2034
|
{
|
|
2035
2035
|
path: 'actions.mobile.collapseToMenu',
|
|
2036
2036
|
category: 'behavior',
|
|
2037
2037
|
valueKind: 'boolean',
|
|
2038
|
-
description: 'Em mobile, agrupa
|
|
2038
|
+
description: 'Em mobile, agrupa ações em um menu (se houver muitas).',
|
|
2039
2039
|
},
|
|
2040
2040
|
{
|
|
2041
2041
|
path: 'actions.containerClassName',
|
|
2042
2042
|
category: 'appearance',
|
|
2043
2043
|
valueKind: 'string',
|
|
2044
|
-
description: 'Classe CSS aplicada ao container da barra de
|
|
2044
|
+
description: 'Classe CSS aplicada ao container da barra de ações.',
|
|
2045
2045
|
},
|
|
2046
2046
|
{
|
|
2047
2047
|
path: 'actions.containerStyles',
|
|
2048
2048
|
category: 'appearance',
|
|
2049
2049
|
valueKind: 'object',
|
|
2050
|
-
description: 'Estilos inline aplicados ao container da barra de
|
|
2050
|
+
description: 'Estilos inline aplicados ao container da barra de ações.',
|
|
2051
2051
|
},
|
|
2052
2052
|
{
|
|
2053
2053
|
path: 'actions.showSaveButton',
|
|
2054
2054
|
category: 'actions',
|
|
2055
2055
|
valueKind: 'boolean',
|
|
2056
|
-
description: 'Legacy: controla visibilidade do
|
|
2056
|
+
description: 'Legacy: controla visibilidade do botão de submit.',
|
|
2057
2057
|
safetyNotes: 'Preferir actions.submit.visible.',
|
|
2058
2058
|
},
|
|
2059
2059
|
{
|
|
2060
2060
|
path: 'actions.submitButtonLabel',
|
|
2061
2061
|
category: 'actions',
|
|
2062
2062
|
valueKind: 'string',
|
|
2063
|
-
description: 'Legacy:
|
|
2063
|
+
description: 'Legacy: rótulo do botão de submit.',
|
|
2064
2064
|
safetyNotes: 'Preferir actions.submit.label.',
|
|
2065
2065
|
},
|
|
2066
2066
|
{
|
|
2067
2067
|
path: 'actions.showCancelButton',
|
|
2068
2068
|
category: 'actions',
|
|
2069
2069
|
valueKind: 'boolean',
|
|
2070
|
-
description: 'Legacy: controla visibilidade do
|
|
2070
|
+
description: 'Legacy: controla visibilidade do botão de cancel.',
|
|
2071
2071
|
safetyNotes: 'Preferir actions.cancel.visible.',
|
|
2072
2072
|
},
|
|
2073
2073
|
{
|
|
2074
2074
|
path: 'actions.cancelButtonLabel',
|
|
2075
2075
|
category: 'actions',
|
|
2076
2076
|
valueKind: 'string',
|
|
2077
|
-
description: 'Legacy:
|
|
2077
|
+
description: 'Legacy: rótulo do botão de cancel.',
|
|
2078
2078
|
safetyNotes: 'Preferir actions.cancel.label.',
|
|
2079
2079
|
},
|
|
2080
2080
|
{
|
|
2081
2081
|
path: 'actions.showResetButton',
|
|
2082
2082
|
category: 'actions',
|
|
2083
2083
|
valueKind: 'boolean',
|
|
2084
|
-
description: 'Legacy: controla visibilidade do
|
|
2084
|
+
description: 'Legacy: controla visibilidade do botão de reset.',
|
|
2085
2085
|
safetyNotes: 'Preferir actions.reset.visible.',
|
|
2086
2086
|
},
|
|
2087
2087
|
{
|
|
2088
2088
|
path: 'actions.resetButtonLabel',
|
|
2089
2089
|
category: 'actions',
|
|
2090
2090
|
valueKind: 'string',
|
|
2091
|
-
description: 'Legacy:
|
|
2091
|
+
description: 'Legacy: rótulo do botão de reset.',
|
|
2092
2092
|
safetyNotes: 'Preferir actions.reset.label.',
|
|
2093
2093
|
},
|
|
2094
2094
|
// =============================================================================
|
|
@@ -2098,14 +2098,14 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2098
2098
|
path: 'behavior.confirmOnUnsavedChanges',
|
|
2099
2099
|
category: 'behavior',
|
|
2100
2100
|
valueKind: 'boolean',
|
|
2101
|
-
description: 'Exibe um alerta se o
|
|
2102
|
-
intentExamples: ['ativar aviso de
|
|
2101
|
+
description: 'Exibe um alerta se o usuário tentar sair com mudanças não salvas.',
|
|
2102
|
+
intentExamples: ['ativar aviso de saÃda sem salvar'],
|
|
2103
2103
|
},
|
|
2104
2104
|
{
|
|
2105
2105
|
path: 'behavior.trackHistory',
|
|
2106
2106
|
category: 'behavior',
|
|
2107
2107
|
valueKind: 'boolean',
|
|
2108
|
-
description: 'Habilita rastreamento de
|
|
2108
|
+
description: 'Habilita rastreamento de histórico para desfazer/refazer (se suportado).',
|
|
2109
2109
|
},
|
|
2110
2110
|
{
|
|
2111
2111
|
path: 'behavior.focusFirstError',
|
|
@@ -2117,33 +2117,33 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2117
2117
|
path: 'behavior.scrollToErrors',
|
|
2118
2118
|
category: 'behavior',
|
|
2119
2119
|
valueKind: 'boolean',
|
|
2120
|
-
description: 'Ao submeter, rola a
|
|
2120
|
+
description: 'Ao submeter, rola a página para exibir o primeiro erro.',
|
|
2121
2121
|
},
|
|
2122
2122
|
{
|
|
2123
2123
|
path: 'behavior.clearAfterSave',
|
|
2124
2124
|
category: 'behavior',
|
|
2125
2125
|
valueKind: 'boolean',
|
|
2126
|
-
description: 'Limpa o
|
|
2126
|
+
description: 'Limpa o formulário após uma submissão bem-sucedida.',
|
|
2127
2127
|
intentExamples: ['limpar form depois de salvar'],
|
|
2128
2128
|
},
|
|
2129
2129
|
{
|
|
2130
2130
|
path: 'behavior.redirectAfterSave',
|
|
2131
2131
|
category: 'behavior',
|
|
2132
2132
|
valueKind: 'string',
|
|
2133
|
-
description: 'URL para redirecionar
|
|
2134
|
-
intentExamples: ['redirecionar para lista
|
|
2133
|
+
description: 'URL para redirecionar após uma submissão bem-sucedida.',
|
|
2134
|
+
intentExamples: ['redirecionar para lista após salvar'],
|
|
2135
2135
|
},
|
|
2136
2136
|
{
|
|
2137
2137
|
path: 'behavior.reactiveValidation',
|
|
2138
2138
|
category: 'validation',
|
|
2139
2139
|
valueKind: 'boolean',
|
|
2140
|
-
description: 'Ativa
|
|
2140
|
+
description: 'Ativa validação reativa (em tempo real) em `valueChanges`.',
|
|
2141
2141
|
},
|
|
2142
2142
|
{
|
|
2143
2143
|
path: 'behavior.reactiveValidationDebounceMs',
|
|
2144
2144
|
category: 'validation',
|
|
2145
2145
|
valueKind: 'number',
|
|
2146
|
-
description: 'Debounce (em ms) para a
|
|
2146
|
+
description: 'Debounce (em ms) para a validação reativa.',
|
|
2147
2147
|
dependsOn: 'behavior.reactiveValidation',
|
|
2148
2148
|
example: '300',
|
|
2149
2149
|
},
|
|
@@ -2154,14 +2154,14 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2154
2154
|
path: 'api.saveEndpoint',
|
|
2155
2155
|
category: 'api',
|
|
2156
2156
|
valueKind: 'string',
|
|
2157
|
-
description: 'URL para onde os dados do
|
|
2157
|
+
description: 'URL para onde os dados do formulário serão enviados (POST/PUT/PATCH).',
|
|
2158
2158
|
intentExamples: ['configurar endpoint de salvar'],
|
|
2159
2159
|
},
|
|
2160
2160
|
{
|
|
2161
2161
|
path: 'api.loadEndpoint',
|
|
2162
2162
|
category: 'api',
|
|
2163
2163
|
valueKind: 'string',
|
|
2164
|
-
description: 'URL para buscar dados para popular o
|
|
2164
|
+
description: 'URL para buscar dados para popular o formulário (GET).',
|
|
2165
2165
|
intentExamples: ['configurar endpoint de carregar'],
|
|
2166
2166
|
},
|
|
2167
2167
|
{
|
|
@@ -2169,20 +2169,20 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2169
2169
|
category: 'api',
|
|
2170
2170
|
valueKind: 'enum',
|
|
2171
2171
|
allowedValues: ['POST', 'PUT', 'PATCH'],
|
|
2172
|
-
description: '
|
|
2172
|
+
description: 'Método HTTP para a requisição de salvar.',
|
|
2173
2173
|
},
|
|
2174
2174
|
{
|
|
2175
2175
|
path: 'api.timeout',
|
|
2176
2176
|
category: 'api',
|
|
2177
2177
|
valueKind: 'number',
|
|
2178
|
-
description: 'Tempo limite (em ms) para as
|
|
2178
|
+
description: 'Tempo limite (em ms) para as requisições API.',
|
|
2179
2179
|
example: '5000',
|
|
2180
2180
|
},
|
|
2181
2181
|
{
|
|
2182
2182
|
path: 'api.headers',
|
|
2183
2183
|
category: 'api',
|
|
2184
2184
|
valueKind: 'object',
|
|
2185
|
-
description: '
|
|
2185
|
+
description: 'Cabeçalhos HTTP personalizados para as requisições API.',
|
|
2186
2186
|
example: '{ "Authorization": "Bearer token" }',
|
|
2187
2187
|
},
|
|
2188
2188
|
{
|
|
@@ -2195,15 +2195,15 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2195
2195
|
path: 'api.beforeSave',
|
|
2196
2196
|
category: 'hooks',
|
|
2197
2197
|
valueKind: 'expression',
|
|
2198
|
-
description: 'Hook para pr
|
|
2199
|
-
safetyNotes: '
|
|
2198
|
+
description: 'Hook para pré-processamento de dados antes de enviar para a API.',
|
|
2199
|
+
safetyNotes: 'Não serializável. Deve ser uma função JS fornecida pelo host.',
|
|
2200
2200
|
},
|
|
2201
2201
|
{
|
|
2202
2202
|
path: 'api.afterLoad',
|
|
2203
2203
|
category: 'hooks',
|
|
2204
2204
|
valueKind: 'expression',
|
|
2205
|
-
description: 'Hook para
|
|
2206
|
-
safetyNotes: '
|
|
2205
|
+
description: 'Hook para pós-processamento de dados após carregar da API.',
|
|
2206
|
+
safetyNotes: 'Não serializável. Deve ser uma função JS fornecida pelo host.',
|
|
2207
2207
|
},
|
|
2208
2208
|
// =============================================================================
|
|
2209
2209
|
// FORM CONFIG - MESSAGES
|
|
@@ -2212,81 +2212,81 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2212
2212
|
path: 'messages.updateRegistrySuccess',
|
|
2213
2213
|
category: 'messages',
|
|
2214
2214
|
valueKind: 'string',
|
|
2215
|
-
description: 'Mensagem de sucesso
|
|
2215
|
+
description: 'Mensagem de sucesso após atualização de registro.',
|
|
2216
2216
|
},
|
|
2217
2217
|
{
|
|
2218
2218
|
path: 'messages.createRegistrySuccess',
|
|
2219
2219
|
category: 'messages',
|
|
2220
2220
|
valueKind: 'string',
|
|
2221
|
-
description: 'Mensagem de sucesso
|
|
2221
|
+
description: 'Mensagem de sucesso após criação de registro.',
|
|
2222
2222
|
},
|
|
2223
2223
|
{
|
|
2224
2224
|
path: 'messages.updateRegistryError',
|
|
2225
2225
|
category: 'messages',
|
|
2226
2226
|
valueKind: 'string',
|
|
2227
|
-
description: 'Mensagem de erro
|
|
2227
|
+
description: 'Mensagem de erro após atualização de registro.',
|
|
2228
2228
|
},
|
|
2229
2229
|
{
|
|
2230
2230
|
path: 'messages.createRegistryError',
|
|
2231
2231
|
category: 'messages',
|
|
2232
2232
|
valueKind: 'string',
|
|
2233
|
-
description: 'Mensagem de erro
|
|
2233
|
+
description: 'Mensagem de erro após criação de registro.',
|
|
2234
2234
|
},
|
|
2235
2235
|
{
|
|
2236
2236
|
path: 'messages.confirmations.submit',
|
|
2237
2237
|
category: 'messages',
|
|
2238
2238
|
valueKind: 'string',
|
|
2239
|
-
description: 'Mensagem de
|
|
2239
|
+
description: 'Mensagem de confirmação antes de submeter o formulário.',
|
|
2240
2240
|
},
|
|
2241
2241
|
{
|
|
2242
2242
|
path: 'messages.confirmations.cancel',
|
|
2243
2243
|
category: 'messages',
|
|
2244
2244
|
valueKind: 'string',
|
|
2245
|
-
description: 'Mensagem de
|
|
2245
|
+
description: 'Mensagem de confirmação antes de cancelar.',
|
|
2246
2246
|
},
|
|
2247
2247
|
{
|
|
2248
2248
|
path: 'messages.confirmations.reset',
|
|
2249
2249
|
category: 'messages',
|
|
2250
2250
|
valueKind: 'string',
|
|
2251
|
-
description: 'Mensagem de
|
|
2251
|
+
description: 'Mensagem de confirmação antes de resetar o formulário.',
|
|
2252
2252
|
},
|
|
2253
2253
|
{
|
|
2254
2254
|
path: 'messages.confirmations.[actionId]',
|
|
2255
2255
|
category: 'messages',
|
|
2256
2256
|
valueKind: 'string',
|
|
2257
|
-
description: 'Mensagem de
|
|
2258
|
-
safetyNotes: 'Use IDs de
|
|
2257
|
+
description: 'Mensagem de confirmação para ações customizadas. Substitua `[actionId]` pelo ID da ação.',
|
|
2258
|
+
safetyNotes: 'Use IDs de ações existentes em `actions.custom[]`.',
|
|
2259
2259
|
},
|
|
2260
2260
|
{
|
|
2261
2261
|
path: 'messages.customActions.[actionId]',
|
|
2262
2262
|
category: 'messages',
|
|
2263
2263
|
valueKind: 'object',
|
|
2264
|
-
description: 'Mensagens da
|
|
2265
|
-
safetyNotes: 'Use IDs de
|
|
2264
|
+
description: 'Mensagens da ação customizada (success/error/confirmation). Substitua `[actionId]` pelo ID da ação.',
|
|
2265
|
+
safetyNotes: 'Use IDs de ações existentes em `actions.custom[]`.',
|
|
2266
2266
|
},
|
|
2267
2267
|
{
|
|
2268
2268
|
path: 'messages.customActions.[actionId].success',
|
|
2269
2269
|
category: 'messages',
|
|
2270
2270
|
valueKind: 'string',
|
|
2271
|
-
description: 'Mensagem de sucesso para a
|
|
2271
|
+
description: 'Mensagem de sucesso para a ação customizada.',
|
|
2272
2272
|
},
|
|
2273
2273
|
{
|
|
2274
2274
|
path: 'messages.customActions.[actionId].error',
|
|
2275
2275
|
category: 'messages',
|
|
2276
2276
|
valueKind: 'string',
|
|
2277
|
-
description: 'Mensagem de erro para a
|
|
2277
|
+
description: 'Mensagem de erro para a ação customizada.',
|
|
2278
2278
|
},
|
|
2279
2279
|
{
|
|
2280
2280
|
path: 'messages.customActions.[actionId].confirmation',
|
|
2281
2281
|
category: 'messages',
|
|
2282
2282
|
valueKind: 'string',
|
|
2283
|
-
description: 'Mensagem de
|
|
2283
|
+
description: 'Mensagem de confirmação para a ação customizada.',
|
|
2284
2284
|
},
|
|
2285
2285
|
{
|
|
2286
2286
|
path: 'messages.loading.submit',
|
|
2287
2287
|
category: 'messages',
|
|
2288
2288
|
valueKind: 'string',
|
|
2289
|
-
description: 'Mensagem exibida durante o envio do
|
|
2289
|
+
description: 'Mensagem exibida durante o envio do formulário.',
|
|
2290
2290
|
},
|
|
2291
2291
|
{
|
|
2292
2292
|
path: 'messages.loading.cancel',
|
|
@@ -2298,13 +2298,13 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2298
2298
|
path: 'messages.loading.reset',
|
|
2299
2299
|
category: 'messages',
|
|
2300
2300
|
valueKind: 'string',
|
|
2301
|
-
description: 'Mensagem exibida durante o reset do
|
|
2301
|
+
description: 'Mensagem exibida durante o reset do formulário.',
|
|
2302
2302
|
},
|
|
2303
2303
|
{
|
|
2304
2304
|
path: 'messages.loading.[actionId]',
|
|
2305
2305
|
category: 'messages',
|
|
2306
2306
|
valueKind: 'string',
|
|
2307
|
-
description: 'Mensagem exibida durante a
|
|
2307
|
+
description: 'Mensagem exibida durante a execução de uma ação customizada. Substitua `[actionId]` pelo ID da ação.',
|
|
2308
2308
|
},
|
|
2309
2309
|
// =============================================================================
|
|
2310
2310
|
// FORM CONFIG - FORM RULES
|
|
@@ -2313,41 +2313,41 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2313
2313
|
path: 'formRules[].id',
|
|
2314
2314
|
category: 'rules',
|
|
2315
2315
|
valueKind: 'string',
|
|
2316
|
-
description: 'ID
|
|
2316
|
+
description: 'ID único da regra de layout.',
|
|
2317
2317
|
critical: true,
|
|
2318
2318
|
safetyNotes: 'Alterar o ID pode quebrar a regra.',
|
|
2319
|
-
intentExamples: ['id da regra', 'identificador
|
|
2319
|
+
intentExamples: ['id da regra', 'identificador único da regra'],
|
|
2320
2320
|
},
|
|
2321
2321
|
{
|
|
2322
2322
|
path: 'formRules[].name',
|
|
2323
2323
|
category: 'rules',
|
|
2324
2324
|
valueKind: 'string',
|
|
2325
|
-
description: 'Nome
|
|
2326
|
-
intentExamples: ['nomear regra', 'dar nome
|
|
2325
|
+
description: 'Nome amigável da regra de layout.',
|
|
2326
|
+
intentExamples: ['nomear regra', 'dar nome à condição', 'tÃtulo da regra'],
|
|
2327
2327
|
},
|
|
2328
2328
|
{
|
|
2329
2329
|
path: 'formRules[].description',
|
|
2330
2330
|
category: 'rules',
|
|
2331
2331
|
valueKind: 'string',
|
|
2332
|
-
description: '
|
|
2333
|
-
intentExamples: ['descrever o que a regra faz', 'documentar
|
|
2332
|
+
description: 'Descrição da regra de layout para documentação.',
|
|
2333
|
+
intentExamples: ['descrever o que a regra faz', 'documentar lógica da regra'],
|
|
2334
2334
|
},
|
|
2335
2335
|
{
|
|
2336
2336
|
path: 'formRules[].targetType',
|
|
2337
2337
|
category: 'rules',
|
|
2338
2338
|
valueKind: 'enum',
|
|
2339
2339
|
allowedValues: ENUMS$1.formRuleTargetType,
|
|
2340
|
-
description: 'Tipo do elemento alvo da regra (campo,
|
|
2340
|
+
description: 'Tipo do elemento alvo da regra (campo, seção, ação, linha, coluna).',
|
|
2341
2341
|
critical: true,
|
|
2342
|
-
intentExamples: ['aplicar regra a um campo', 'regra para uma
|
|
2342
|
+
intentExamples: ['aplicar regra a um campo', 'regra para uma seção', 'condição em uma linha'],
|
|
2343
2343
|
},
|
|
2344
2344
|
{
|
|
2345
2345
|
path: 'formRules[].context',
|
|
2346
2346
|
category: 'rules',
|
|
2347
2347
|
valueKind: 'enum',
|
|
2348
2348
|
allowedValues: ENUMS$1.formRuleContext,
|
|
2349
|
-
description: 'Contexto legado da regra (quando properties
|
|
2350
|
-
safetyNotes: 'Preferir effect.properties/propertiesWhenFalse quando
|
|
2349
|
+
description: 'Contexto legado da regra (quando properties não forem informadas).',
|
|
2350
|
+
safetyNotes: 'Preferir effect.properties/propertiesWhenFalse quando possÃvel.',
|
|
2351
2351
|
},
|
|
2352
2352
|
{
|
|
2353
2353
|
path: 'formRules[].targets',
|
|
@@ -2355,8 +2355,8 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2355
2355
|
valueKind: 'array',
|
|
2356
2356
|
description: 'Lista de IDs dos elementos alvo da regra. O tipo do ID depende de `targetType`.',
|
|
2357
2357
|
critical: true,
|
|
2358
|
-
safetyNotes: 'Verifique se os IDs dos alvos existem no
|
|
2359
|
-
intentExamples: ['tornar campo "email"
|
|
2358
|
+
safetyNotes: 'Verifique se os IDs dos alvos existem no formulário.',
|
|
2359
|
+
intentExamples: ['tornar campo "email" visÃvel', 'esconder seção "dados-pessoais"', 'aplicar no campo X'],
|
|
2360
2360
|
},
|
|
2361
2361
|
{
|
|
2362
2362
|
path: 'formRules[].targets[]',
|
|
@@ -2364,7 +2364,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2364
2364
|
valueKind: 'string',
|
|
2365
2365
|
description: 'ID do alvo da regra.',
|
|
2366
2366
|
critical: true,
|
|
2367
|
-
safetyNotes: 'Verifique se o ID existe no
|
|
2367
|
+
safetyNotes: 'Verifique se o ID existe no formulário.',
|
|
2368
2368
|
},
|
|
2369
2369
|
{
|
|
2370
2370
|
path: 'formRules[].targetFields',
|
|
@@ -2383,11 +2383,11 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2383
2383
|
path: 'formRules[].effect.condition',
|
|
2384
2384
|
category: 'rules',
|
|
2385
2385
|
valueKind: 'expression',
|
|
2386
|
-
description: '
|
|
2386
|
+
description: 'Condicao canonica da regra, expressa em Json Logic.',
|
|
2387
2387
|
critical: true,
|
|
2388
|
-
safetyNotes: '
|
|
2389
|
-
example: '
|
|
2390
|
-
intentExamples: ['se valor for maior que 10', 'quando status for ativo', '
|
|
2388
|
+
safetyNotes: 'NÃO utilize código JS puro nem strings arbitrárias. Utilize JSON Logic validado.',
|
|
2389
|
+
example: '{ "and": [{ "==": [{ "var": "status" }, "active"] }, { ">": [{ "var": "amount" }, 100] }] }',
|
|
2390
|
+
intentExamples: ['se valor for maior que 10', 'quando status for ativo', 'condição da regra'],
|
|
2391
2391
|
},
|
|
2392
2392
|
...generateRulePropertyCapabilities(FormRuleTargetType.Field, RULE_PROPERTY_SCHEMA.field),
|
|
2393
2393
|
...generateRulePropertyCapabilities(FormRuleTargetType.Section, RULE_PROPERTY_SCHEMA.section),
|
|
@@ -2404,7 +2404,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2404
2404
|
category: 'rules',
|
|
2405
2405
|
valueKind: 'object',
|
|
2406
2406
|
description: 'Estado interno do builder de regras (metadados visuais).',
|
|
2407
|
-
safetyNotes: 'Gerado por round-trip do builder.
|
|
2407
|
+
safetyNotes: 'Gerado por round-trip do builder. Não deve ser editado manualmente ou pela IA.',
|
|
2408
2408
|
},
|
|
2409
2409
|
// =============================================================================
|
|
2410
2410
|
// FORM CONFIG - HOOKS
|
|
@@ -2413,16 +2413,16 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2413
2413
|
path: 'hooks',
|
|
2414
2414
|
category: 'hooks',
|
|
2415
2415
|
valueKind: 'object',
|
|
2416
|
-
description: '
|
|
2417
|
-
safetyNotes: 'Hooks
|
|
2416
|
+
description: 'Declarações de hooks por estágio do ciclo de vida do formulário.',
|
|
2417
|
+
safetyNotes: 'Hooks são resolvidos por ID no host. Não são funções serializáveis.',
|
|
2418
2418
|
example: '{ beforeInit: [{ id: "load-options", priority: 100 }] }',
|
|
2419
|
-
intentExamples: ['adicionar hook de
|
|
2419
|
+
intentExamples: ['adicionar hook de inicialização', 'executar ação antes do submit'],
|
|
2420
2420
|
},
|
|
2421
2421
|
{
|
|
2422
2422
|
path: 'hooks.beforeInit[]',
|
|
2423
2423
|
category: 'hooks',
|
|
2424
2424
|
valueKind: 'array',
|
|
2425
|
-
description: '
|
|
2425
|
+
description: 'Declarações de hooks para beforeInit.',
|
|
2426
2426
|
},
|
|
2427
2427
|
{
|
|
2428
2428
|
path: 'hooks.beforeInit[].id',
|
|
@@ -2452,7 +2452,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2452
2452
|
path: 'hooks.afterInit[]',
|
|
2453
2453
|
category: 'hooks',
|
|
2454
2454
|
valueKind: 'array',
|
|
2455
|
-
description: '
|
|
2455
|
+
description: 'Declarações de hooks para afterInit.',
|
|
2456
2456
|
},
|
|
2457
2457
|
{
|
|
2458
2458
|
path: 'hooks.afterInit[].id',
|
|
@@ -2482,7 +2482,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2482
2482
|
path: 'hooks.beforeValidate[]',
|
|
2483
2483
|
category: 'hooks',
|
|
2484
2484
|
valueKind: 'array',
|
|
2485
|
-
description: '
|
|
2485
|
+
description: 'Declarações de hooks para beforeValidate.',
|
|
2486
2486
|
},
|
|
2487
2487
|
{
|
|
2488
2488
|
path: 'hooks.beforeValidate[].id',
|
|
@@ -2512,7 +2512,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2512
2512
|
path: 'hooks.afterValidate[]',
|
|
2513
2513
|
category: 'hooks',
|
|
2514
2514
|
valueKind: 'array',
|
|
2515
|
-
description: '
|
|
2515
|
+
description: 'Declarações de hooks para afterValidate.',
|
|
2516
2516
|
},
|
|
2517
2517
|
{
|
|
2518
2518
|
path: 'hooks.afterValidate[].id',
|
|
@@ -2542,7 +2542,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2542
2542
|
path: 'hooks.beforeSubmit[]',
|
|
2543
2543
|
category: 'hooks',
|
|
2544
2544
|
valueKind: 'array',
|
|
2545
|
-
description: '
|
|
2545
|
+
description: 'Declarações de hooks para beforeSubmit.',
|
|
2546
2546
|
},
|
|
2547
2547
|
{
|
|
2548
2548
|
path: 'hooks.beforeSubmit[].id',
|
|
@@ -2572,7 +2572,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2572
2572
|
path: 'hooks.afterSubmit[]',
|
|
2573
2573
|
category: 'hooks',
|
|
2574
2574
|
valueKind: 'array',
|
|
2575
|
-
description: '
|
|
2575
|
+
description: 'Declarações de hooks para afterSubmit.',
|
|
2576
2576
|
},
|
|
2577
2577
|
{
|
|
2578
2578
|
path: 'hooks.afterSubmit[].id',
|
|
@@ -2602,7 +2602,7 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2602
2602
|
path: 'hooks.onError[]',
|
|
2603
2603
|
category: 'hooks',
|
|
2604
2604
|
valueKind: 'array',
|
|
2605
|
-
description: '
|
|
2605
|
+
description: 'Declarações de hooks para onError.',
|
|
2606
2606
|
},
|
|
2607
2607
|
{
|
|
2608
2608
|
path: 'hooks.onError[].id',
|
|
@@ -2635,25 +2635,25 @@ const FORM_AI_CAPABILITIES = {
|
|
|
2635
2635
|
path: 'hints.dataModes.create',
|
|
2636
2636
|
category: 'form_config',
|
|
2637
2637
|
valueKind: 'string',
|
|
2638
|
-
description: 'Dica para o modo de
|
|
2638
|
+
description: 'Dica para o modo de criação de dados.',
|
|
2639
2639
|
},
|
|
2640
2640
|
{
|
|
2641
2641
|
path: 'hints.dataModes.edit',
|
|
2642
2642
|
category: 'form_config',
|
|
2643
2643
|
valueKind: 'string',
|
|
2644
|
-
description: 'Dica para o modo de
|
|
2644
|
+
description: 'Dica para o modo de edição de dados.',
|
|
2645
2645
|
},
|
|
2646
2646
|
{
|
|
2647
2647
|
path: 'hints.dataModes.view',
|
|
2648
2648
|
category: 'form_config',
|
|
2649
2649
|
valueKind: 'string',
|
|
2650
|
-
description: 'Dica para o modo de
|
|
2650
|
+
description: 'Dica para o modo de visualização de dados.',
|
|
2651
2651
|
},
|
|
2652
2652
|
{
|
|
2653
2653
|
path: 'hints.uiModes.presentation',
|
|
2654
2654
|
category: 'form_config',
|
|
2655
2655
|
valueKind: 'string',
|
|
2656
|
-
description: 'Dica para o modo de
|
|
2656
|
+
description: 'Dica para o modo de apresentação da UI.',
|
|
2657
2657
|
},
|
|
2658
2658
|
{
|
|
2659
2659
|
path: 'hints.uiModes.readonly',
|
|
@@ -3803,6 +3803,12 @@ function coerceValue(def, value) {
|
|
|
3803
3803
|
case 'string':
|
|
3804
3804
|
return typeof value === 'string' ? { ok: true, value } : { ok: false };
|
|
3805
3805
|
case 'object':
|
|
3806
|
+
if (def.name === 'defaultValue') {
|
|
3807
|
+
if (typeof value === 'function' || value === undefined) {
|
|
3808
|
+
return { ok: false };
|
|
3809
|
+
}
|
|
3810
|
+
return { ok: true, value: sanitizeStructured(def.name, value) };
|
|
3811
|
+
}
|
|
3806
3812
|
if (def.name === 'options' && Array.isArray(value)) {
|
|
3807
3813
|
return { ok: true, value: sanitizeStructured(def.name, value) };
|
|
3808
3814
|
}
|
|
@@ -3859,6 +3865,9 @@ function sanitizeStructured(name, value) {
|
|
|
3859
3865
|
});
|
|
3860
3866
|
return allowed;
|
|
3861
3867
|
}
|
|
3868
|
+
if (name === 'defaultValue') {
|
|
3869
|
+
return value;
|
|
3870
|
+
}
|
|
3862
3871
|
if (name === 'sectionHeader') {
|
|
3863
3872
|
return sanitizeSectionHeaderConfig(value);
|
|
3864
3873
|
}
|
|
@@ -3866,12 +3875,9 @@ function sanitizeStructured(name, value) {
|
|
|
3866
3875
|
}
|
|
3867
3876
|
|
|
3868
3877
|
class FormRulesService {
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
.replace(/!=/g, ' ne ')
|
|
3873
|
-
.replace(/===/g, ' eq ')
|
|
3874
|
-
.replace(/==/g, ' eq ');
|
|
3878
|
+
jsonLogic;
|
|
3879
|
+
constructor(jsonLogic) {
|
|
3880
|
+
this.jsonLogic = jsonLogic;
|
|
3875
3881
|
}
|
|
3876
3882
|
/**
|
|
3877
3883
|
* Evaluates a set of form rules against the current value of a FormGroup.
|
|
@@ -3892,7 +3898,6 @@ class FormRulesService {
|
|
|
3892
3898
|
return result;
|
|
3893
3899
|
}
|
|
3894
3900
|
const formData = formGroup.value;
|
|
3895
|
-
const parser = new DslParser();
|
|
3896
3901
|
for (const originalRule of formRules) {
|
|
3897
3902
|
const rule = sanitizeRuleEffect(originalRule);
|
|
3898
3903
|
if (!rule || !rule.targets?.length || !rule.targetType) {
|
|
@@ -3904,21 +3909,7 @@ class FormRulesService {
|
|
|
3904
3909
|
}
|
|
3905
3910
|
try {
|
|
3906
3911
|
const condition = effect.condition;
|
|
3907
|
-
|
|
3908
|
-
if (condition === null || condition === undefined) {
|
|
3909
|
-
isSatisfied = true;
|
|
3910
|
-
}
|
|
3911
|
-
else if (typeof condition === 'string') {
|
|
3912
|
-
const normalizedCondition = this.normalizeLegacyConditionSyntax(condition);
|
|
3913
|
-
const spec = parser.parse(normalizedCondition);
|
|
3914
|
-
isSatisfied = spec.isSatisfiedBy(formData);
|
|
3915
|
-
}
|
|
3916
|
-
else if (typeof condition === 'object' && typeof condition.isSatisfiedBy === 'function') {
|
|
3917
|
-
isSatisfied = condition.isSatisfiedBy(formData);
|
|
3918
|
-
}
|
|
3919
|
-
else {
|
|
3920
|
-
continue;
|
|
3921
|
-
}
|
|
3912
|
+
const isSatisfied = this.evaluateCondition(condition, formData);
|
|
3922
3913
|
const targetMap = rule.targetType === 'field'
|
|
3923
3914
|
? result.fieldProps
|
|
3924
3915
|
: rule.targetType === 'section'
|
|
@@ -3959,6 +3950,23 @@ class FormRulesService {
|
|
|
3959
3950
|
}
|
|
3960
3951
|
return result;
|
|
3961
3952
|
}
|
|
3953
|
+
evaluateCondition(condition, formData) {
|
|
3954
|
+
if (condition === null || condition === undefined) {
|
|
3955
|
+
return true;
|
|
3956
|
+
}
|
|
3957
|
+
if (typeof condition === 'string') {
|
|
3958
|
+
return false;
|
|
3959
|
+
}
|
|
3960
|
+
try {
|
|
3961
|
+
return this.jsonLogic.matches({
|
|
3962
|
+
condition: condition,
|
|
3963
|
+
data: formData,
|
|
3964
|
+
});
|
|
3965
|
+
}
|
|
3966
|
+
catch {
|
|
3967
|
+
return false;
|
|
3968
|
+
}
|
|
3969
|
+
}
|
|
3962
3970
|
setPath(target, path, value) {
|
|
3963
3971
|
if (!path.includes('.')) {
|
|
3964
3972
|
target[path] = value;
|
|
@@ -4001,7 +4009,7 @@ class FormRulesService {
|
|
|
4001
4009
|
return;
|
|
4002
4010
|
delete cursor[segments[segments.length - 1]];
|
|
4003
4011
|
}
|
|
4004
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FormRulesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4012
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FormRulesService, deps: [{ token: i1$2.PraxisJsonLogicService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4005
4013
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FormRulesService, providedIn: 'root' });
|
|
4006
4014
|
}
|
|
4007
4015
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FormRulesService, decorators: [{
|
|
@@ -4009,7 +4017,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
4009
4017
|
args: [{
|
|
4010
4018
|
providedIn: 'root',
|
|
4011
4019
|
}]
|
|
4012
|
-
}] });
|
|
4020
|
+
}], ctorParameters: () => [{ type: i1$2.PraxisJsonLogicService }] });
|
|
4013
4021
|
|
|
4014
4022
|
class CanvasStateService {
|
|
4015
4023
|
_hoveredElement$ = new BehaviorSubject(null);
|
|
@@ -6640,9 +6648,7 @@ class PraxisDynamicForm {
|
|
|
6640
6648
|
const readonlyOverride = overrides.readonly !== undefined ? overrides.readonly : overrides.readOnly;
|
|
6641
6649
|
const disabledOverride = overrides.disabled;
|
|
6642
6650
|
const meta = fieldByName.get(field.name);
|
|
6643
|
-
const isVisible = overrides
|
|
6644
|
-
? !!overrides.visible
|
|
6645
|
-
: true;
|
|
6651
|
+
const isVisible = this.resolveRuleVisibility(overrides);
|
|
6646
6652
|
this.fieldVisibility[field.name] = isVisible;
|
|
6647
6653
|
const baseDisabled = meta?.disabled === true || meta?.readOnly === true;
|
|
6648
6654
|
const shouldDisable = (disabledOverride !== undefined
|
|
@@ -6660,17 +6666,20 @@ class PraxisDynamicForm {
|
|
|
6660
6666
|
}
|
|
6661
6667
|
if (!meta)
|
|
6662
6668
|
continue;
|
|
6669
|
+
const metadataOverrides = this.buildFieldRuleMetadataOverrides(meta, overrides);
|
|
6663
6670
|
const mergedValidators = { ...(meta.validators || {}) };
|
|
6664
|
-
if (
|
|
6665
|
-
|
|
6671
|
+
if (metadataOverrides.validators &&
|
|
6672
|
+
typeof metadataOverrides.validators === 'object') {
|
|
6673
|
+
Object.assign(mergedValidators, metadataOverrides.validators);
|
|
6666
6674
|
}
|
|
6667
|
-
if (
|
|
6668
|
-
mergedValidators.required =
|
|
6675
|
+
if (metadataOverrides.required !== undefined) {
|
|
6676
|
+
mergedValidators.required = metadataOverrides.required;
|
|
6669
6677
|
}
|
|
6670
6678
|
if (control) {
|
|
6671
6679
|
const overrideStyle = overrides.style;
|
|
6672
6680
|
const nextMeta = {
|
|
6673
6681
|
...meta,
|
|
6682
|
+
...metadataOverrides,
|
|
6674
6683
|
validators: mergedValidators,
|
|
6675
6684
|
disabled: shouldDisable,
|
|
6676
6685
|
readOnly: readonlyOverride !== undefined
|
|
@@ -6689,6 +6698,11 @@ class PraxisDynamicForm {
|
|
|
6689
6698
|
this.dynamicForm.updateControlFromMetadata(this.form, nextMeta, {
|
|
6690
6699
|
emitEvent: false,
|
|
6691
6700
|
});
|
|
6701
|
+
if (metadataOverrides.defaultValue !== undefined &&
|
|
6702
|
+
(control.pristine || control.value == null || control.value === '')) {
|
|
6703
|
+
control.setValue(metadataOverrides.defaultValue, { emitEvent: false });
|
|
6704
|
+
}
|
|
6705
|
+
this.applyLiveFieldMetadata(field.name, nextMeta, isVisible);
|
|
6692
6706
|
}
|
|
6693
6707
|
}
|
|
6694
6708
|
this.cdr.detectChanges();
|
|
@@ -6717,10 +6731,7 @@ class PraxisDynamicForm {
|
|
|
6717
6731
|
if (!section)
|
|
6718
6732
|
return true;
|
|
6719
6733
|
const props = this.getSectionRuleProps(section);
|
|
6720
|
-
|
|
6721
|
-
return !!props.visible;
|
|
6722
|
-
}
|
|
6723
|
-
return true;
|
|
6734
|
+
return this.resolveRuleVisibility(props, true);
|
|
6724
6735
|
}
|
|
6725
6736
|
getSectionTitle(section) {
|
|
6726
6737
|
const props = this.getSectionRuleProps(section);
|
|
@@ -6892,9 +6903,7 @@ class PraxisDynamicForm {
|
|
|
6892
6903
|
if (!row)
|
|
6893
6904
|
return true;
|
|
6894
6905
|
const props = this.getRowRuleProps(row);
|
|
6895
|
-
|
|
6896
|
-
return !!props.visible;
|
|
6897
|
-
return true;
|
|
6906
|
+
return this.resolveRuleVisibility(props, true);
|
|
6898
6907
|
}
|
|
6899
6908
|
getRowGap(row) {
|
|
6900
6909
|
const props = this.getRowRuleProps(row);
|
|
@@ -7192,6 +7201,18 @@ class PraxisDynamicForm {
|
|
|
7192
7201
|
}
|
|
7193
7202
|
}
|
|
7194
7203
|
}
|
|
7204
|
+
resolveRuleVisibility(props, fallback = true) {
|
|
7205
|
+
if (!props || typeof props !== 'object') {
|
|
7206
|
+
return fallback;
|
|
7207
|
+
}
|
|
7208
|
+
if (props.visible !== undefined) {
|
|
7209
|
+
return !!props.visible;
|
|
7210
|
+
}
|
|
7211
|
+
if (props.hidden !== undefined) {
|
|
7212
|
+
return !props.hidden;
|
|
7213
|
+
}
|
|
7214
|
+
return fallback;
|
|
7215
|
+
}
|
|
7195
7216
|
toggleSectionCollapse(event, section) {
|
|
7196
7217
|
event.stopPropagation();
|
|
7197
7218
|
if (!this.isSectionCollapsible(section))
|
|
@@ -7225,10 +7246,18 @@ class PraxisDynamicForm {
|
|
|
7225
7246
|
const visibleNames = column.fields
|
|
7226
7247
|
.filter((name) => this.fieldVisibility[name] !== false)
|
|
7227
7248
|
.map((name) => {
|
|
7249
|
+
const meta = (this.config.fieldMetadata || []).find((field) => field.name === name);
|
|
7228
7250
|
const overrides = this.fieldRuleProps[name] || {};
|
|
7229
7251
|
return `${name}:${JSON.stringify({
|
|
7230
|
-
|
|
7231
|
-
|
|
7252
|
+
overrides,
|
|
7253
|
+
meta: meta ? {
|
|
7254
|
+
disabled: meta.disabled,
|
|
7255
|
+
readonly: meta.readonly,
|
|
7256
|
+
readOnly: meta.readOnly,
|
|
7257
|
+
required: meta.required,
|
|
7258
|
+
cssClass: meta.cssClass,
|
|
7259
|
+
style: meta.style,
|
|
7260
|
+
} : null,
|
|
7232
7261
|
})}`;
|
|
7233
7262
|
})
|
|
7234
7263
|
.join('|');
|
|
@@ -7245,13 +7274,15 @@ class PraxisDynamicForm {
|
|
|
7245
7274
|
const meta = byName.get(name);
|
|
7246
7275
|
if (meta) {
|
|
7247
7276
|
const overrides = this.fieldRuleProps[name] || {};
|
|
7248
|
-
if (overrides.
|
|
7277
|
+
if (Object.keys(overrides).length > 0) {
|
|
7278
|
+
const { visible: _visible, hidden: _hidden, className, style, ...metadataOverrides } = overrides;
|
|
7249
7279
|
ordered.push({
|
|
7250
7280
|
...meta,
|
|
7251
|
-
|
|
7281
|
+
...metadataOverrides,
|
|
7282
|
+
cssClass: className ?? meta.cssClass,
|
|
7252
7283
|
style: {
|
|
7253
7284
|
...meta.style,
|
|
7254
|
-
...(
|
|
7285
|
+
...(style || {}),
|
|
7255
7286
|
},
|
|
7256
7287
|
});
|
|
7257
7288
|
}
|
|
@@ -7268,6 +7299,92 @@ class PraxisDynamicForm {
|
|
|
7268
7299
|
return {};
|
|
7269
7300
|
return this.columnRuleProps[column.id] || {};
|
|
7270
7301
|
}
|
|
7302
|
+
buildFieldRuleMetadataOverrides(meta, overrides) {
|
|
7303
|
+
const next = {};
|
|
7304
|
+
for (const [key, value] of Object.entries(overrides || {})) {
|
|
7305
|
+
if (key === 'visible' ||
|
|
7306
|
+
key === 'hidden' ||
|
|
7307
|
+
key === 'className' ||
|
|
7308
|
+
key === 'style' ||
|
|
7309
|
+
key === 'validators' ||
|
|
7310
|
+
key === 'required' ||
|
|
7311
|
+
key === 'disabled' ||
|
|
7312
|
+
key === 'readonly' ||
|
|
7313
|
+
key === 'readOnly' ||
|
|
7314
|
+
key === 'options') {
|
|
7315
|
+
continue;
|
|
7316
|
+
}
|
|
7317
|
+
next[key] = value;
|
|
7318
|
+
}
|
|
7319
|
+
if (overrides.options !== undefined) {
|
|
7320
|
+
const normalized = this.normalizeRuleFieldOptions(overrides.options) ?? [];
|
|
7321
|
+
next.options = normalized;
|
|
7322
|
+
const controlType = normalizeControlTypeKey(meta.controlType);
|
|
7323
|
+
if (controlType === 'SELECT' || controlType === 'AUTO_COMPLETE') {
|
|
7324
|
+
next.selectOptions = normalized;
|
|
7325
|
+
}
|
|
7326
|
+
else if (controlType === 'MULTI_SELECT' || controlType === 'SELECTION_LIST') {
|
|
7327
|
+
next.listOptions = normalized;
|
|
7328
|
+
}
|
|
7329
|
+
else if (controlType === 'TRANSFER_LIST') {
|
|
7330
|
+
next.transferOptions = normalized;
|
|
7331
|
+
}
|
|
7332
|
+
else if (controlType === 'RADIO') {
|
|
7333
|
+
next.radioOptions = normalized;
|
|
7334
|
+
}
|
|
7335
|
+
else if (controlType === 'BUTTON_TOGGLE') {
|
|
7336
|
+
next.toggleOptions = normalized;
|
|
7337
|
+
}
|
|
7338
|
+
else if (controlType === 'TREE_SELECT' || controlType === 'MULTI_SELECT_TREE') {
|
|
7339
|
+
next.nodes = normalized;
|
|
7340
|
+
}
|
|
7341
|
+
}
|
|
7342
|
+
const validatorOverrides = overrides.validators && typeof overrides.validators === 'object'
|
|
7343
|
+
? overrides.validators
|
|
7344
|
+
: null;
|
|
7345
|
+
if (validatorOverrides) {
|
|
7346
|
+
next.validators = { ...(meta.validators || {}), ...validatorOverrides };
|
|
7347
|
+
if (validatorOverrides.required !== undefined) {
|
|
7348
|
+
next.required = !!validatorOverrides.required;
|
|
7349
|
+
}
|
|
7350
|
+
if (validatorOverrides.minLength !== undefined) {
|
|
7351
|
+
next.minLength = validatorOverrides.minLength;
|
|
7352
|
+
}
|
|
7353
|
+
if (validatorOverrides.maxLength !== undefined) {
|
|
7354
|
+
next.maxLength = validatorOverrides.maxLength;
|
|
7355
|
+
}
|
|
7356
|
+
if (validatorOverrides.pattern !== undefined) {
|
|
7357
|
+
next.pattern = validatorOverrides.pattern;
|
|
7358
|
+
}
|
|
7359
|
+
if (validatorOverrides.min !== undefined) {
|
|
7360
|
+
next.min = validatorOverrides.min;
|
|
7361
|
+
}
|
|
7362
|
+
if (validatorOverrides.max !== undefined) {
|
|
7363
|
+
next.max = validatorOverrides.max;
|
|
7364
|
+
}
|
|
7365
|
+
if (validatorOverrides.requiredTrue !== undefined) {
|
|
7366
|
+
next.requiredTrue = validatorOverrides.requiredTrue;
|
|
7367
|
+
}
|
|
7368
|
+
}
|
|
7369
|
+
return next;
|
|
7370
|
+
}
|
|
7371
|
+
normalizeRuleFieldOptions(raw) {
|
|
7372
|
+
if (raw == null)
|
|
7373
|
+
return undefined;
|
|
7374
|
+
const array = Array.isArray(raw) ? raw : raw?.items;
|
|
7375
|
+
if (!Array.isArray(array))
|
|
7376
|
+
return undefined;
|
|
7377
|
+
return array.map((option) => typeof option === 'object' && option !== null
|
|
7378
|
+
? {
|
|
7379
|
+
value: option.value,
|
|
7380
|
+
text: option.text ?? option.label,
|
|
7381
|
+
label: option.label ?? option.text,
|
|
7382
|
+
disabled: option.disabled,
|
|
7383
|
+
group: option.group,
|
|
7384
|
+
children: option.children,
|
|
7385
|
+
}
|
|
7386
|
+
: { value: option, text: String(option), label: String(option) });
|
|
7387
|
+
}
|
|
7271
7388
|
getEffectiveColumn(column) {
|
|
7272
7389
|
const props = this.getColumnRuleProps(column);
|
|
7273
7390
|
const merged = { ...column };
|
|
@@ -7345,11 +7462,41 @@ class PraxisDynamicForm {
|
|
|
7345
7462
|
isColumnVisible(column) {
|
|
7346
7463
|
const props = this.getColumnRuleProps(column);
|
|
7347
7464
|
if (props.visible !== undefined) {
|
|
7348
|
-
return
|
|
7465
|
+
return this.resolveRuleVisibility(props, true);
|
|
7466
|
+
}
|
|
7467
|
+
if (props.hidden !== undefined) {
|
|
7468
|
+
if (typeof props.hidden === 'boolean') {
|
|
7469
|
+
return !props.hidden;
|
|
7470
|
+
}
|
|
7471
|
+
if (props.hidden && typeof props.hidden === 'object') {
|
|
7472
|
+
return !this.isResponsiveHiddenActive(props.hidden);
|
|
7473
|
+
}
|
|
7349
7474
|
}
|
|
7350
7475
|
// A column is visible if at least one of its fields is visible.
|
|
7351
7476
|
return column.fields.some((fieldName) => this.fieldVisibility[fieldName]);
|
|
7352
7477
|
}
|
|
7478
|
+
isResponsiveHiddenActive(hidden) {
|
|
7479
|
+
if (!hidden || typeof hidden !== 'object' || Array.isArray(hidden)) {
|
|
7480
|
+
return false;
|
|
7481
|
+
}
|
|
7482
|
+
const resolved = resolveHidden(hidden);
|
|
7483
|
+
const width = typeof window !== 'undefined' && typeof window.innerWidth === 'number'
|
|
7484
|
+
? window.innerWidth
|
|
7485
|
+
: Number.POSITIVE_INFINITY;
|
|
7486
|
+
if (width >= 1536) {
|
|
7487
|
+
return !!(resolved.xs || resolved.sm || resolved.md || resolved.lg || resolved.xl);
|
|
7488
|
+
}
|
|
7489
|
+
if (width >= 1200) {
|
|
7490
|
+
return !!(resolved.xs || resolved.sm || resolved.md || resolved.lg);
|
|
7491
|
+
}
|
|
7492
|
+
if (width >= 900) {
|
|
7493
|
+
return !!(resolved.xs || resolved.sm || resolved.md);
|
|
7494
|
+
}
|
|
7495
|
+
if (width >= 600) {
|
|
7496
|
+
return !!(resolved.xs || resolved.sm);
|
|
7497
|
+
}
|
|
7498
|
+
return !!resolved.xs;
|
|
7499
|
+
}
|
|
7353
7500
|
getColumnPadding(column) {
|
|
7354
7501
|
const effective = this.getEffectiveColumn(column);
|
|
7355
7502
|
return effective.padding;
|
|
@@ -10081,75 +10228,7 @@ class PraxisDynamicForm {
|
|
|
10081
10228
|
fallbackToLoadedEntity: true,
|
|
10082
10229
|
});
|
|
10083
10230
|
}
|
|
10084
|
-
|
|
10085
|
-
const loader = this.findLoaderForField(fieldName);
|
|
10086
|
-
try {
|
|
10087
|
-
this.debugLog('[PDF] hot-update: loader lookup', { fieldName, found: !!loader });
|
|
10088
|
-
}
|
|
10089
|
-
catch { }
|
|
10090
|
-
if (loader) {
|
|
10091
|
-
try {
|
|
10092
|
-
const comp = loader.getComponent?.(fieldName);
|
|
10093
|
-
try {
|
|
10094
|
-
this.debugLog('[PDF] hot-update: component lookup', { fieldName, found: !!comp });
|
|
10095
|
-
}
|
|
10096
|
-
catch { }
|
|
10097
|
-
if (comp) {
|
|
10098
|
-
const inst = comp.instance;
|
|
10099
|
-
if (typeof inst.setInputMetadata === 'function') {
|
|
10100
|
-
try {
|
|
10101
|
-
this.debugLog('[PDF] Applying setInputMetadata on live instance', { fieldName, hasFn: true });
|
|
10102
|
-
try {
|
|
10103
|
-
this.debugLog('[PDF] hot-update: setInputMetadata payload preview', { fieldName, allowHalf: fm?.allowHalf, precision: fm?.precision, ratingColor: fm?.ratingColor, outlineColor: fm?.outlineColor });
|
|
10104
|
-
}
|
|
10105
|
-
catch { }
|
|
10106
|
-
inst.setInputMetadata(fm);
|
|
10107
|
-
}
|
|
10108
|
-
catch (e) {
|
|
10109
|
-
this.warnLog('[PDF] setInputMetadata failed; refreshing loader', e);
|
|
10110
|
-
loader.refresh();
|
|
10111
|
-
}
|
|
10112
|
-
}
|
|
10113
|
-
else if (inst?.metadata && typeof inst.metadata === 'function' && 'set' in inst.metadata) {
|
|
10114
|
-
try {
|
|
10115
|
-
this.debugLog('[PDF] Using metadata.set on live instance', { fieldName });
|
|
10116
|
-
inst.metadata.set(fm);
|
|
10117
|
-
}
|
|
10118
|
-
catch (e) {
|
|
10119
|
-
this.warnLog('[PDF] metadata.set failed; refreshing loader', e);
|
|
10120
|
-
loader.refresh();
|
|
10121
|
-
}
|
|
10122
|
-
}
|
|
10123
|
-
else {
|
|
10124
|
-
// No hot path available; refresh the column's loader
|
|
10125
|
-
this.warnLog('[PDF] No hot-update path; refreshing loader', { fieldName });
|
|
10126
|
-
loader.refresh();
|
|
10127
|
-
}
|
|
10128
|
-
}
|
|
10129
|
-
else {
|
|
10130
|
-
// Component not found (field may be hidden); refresh loader to pick changes
|
|
10131
|
-
this.warnLog('[PDF] Component not found; refreshing loader', { fieldName });
|
|
10132
|
-
loader.refresh();
|
|
10133
|
-
}
|
|
10134
|
-
}
|
|
10135
|
-
catch (e) {
|
|
10136
|
-
this.warnLog('[PDF] hot-update error; refreshing loader', { fieldName, error: e?.message || e });
|
|
10137
|
-
try {
|
|
10138
|
-
loader.refresh();
|
|
10139
|
-
}
|
|
10140
|
-
catch { }
|
|
10141
|
-
}
|
|
10142
|
-
}
|
|
10143
|
-
else {
|
|
10144
|
-
// Could not locate loader (edge case); rebuild safely
|
|
10145
|
-
this.debugLog('[PDF] Loader not found; rebuilding form');
|
|
10146
|
-
this.buildFormFromConfig({
|
|
10147
|
-
reason: 'loader-refresh',
|
|
10148
|
-
preserveRuntimeState: true,
|
|
10149
|
-
preserveInteractionState: true,
|
|
10150
|
-
fallbackToLoadedEntity: true,
|
|
10151
|
-
});
|
|
10152
|
-
}
|
|
10231
|
+
this.applyLiveFieldMetadata(fieldName, fm);
|
|
10153
10232
|
}
|
|
10154
10233
|
this.cdr.detectChanges();
|
|
10155
10234
|
// Persist updated config locally so editor changes survive reloads
|
|
@@ -10202,6 +10281,77 @@ class PraxisDynamicForm {
|
|
|
10202
10281
|
}
|
|
10203
10282
|
return undefined;
|
|
10204
10283
|
}
|
|
10284
|
+
applyLiveFieldMetadata(fieldName, metadata, isVisible) {
|
|
10285
|
+
const loader = this.findLoaderForField(fieldName);
|
|
10286
|
+
try {
|
|
10287
|
+
this.debugLog('[PDF] hot-update: loader lookup', { fieldName, found: !!loader });
|
|
10288
|
+
}
|
|
10289
|
+
catch { }
|
|
10290
|
+
if (loader) {
|
|
10291
|
+
try {
|
|
10292
|
+
const comp = loader.getComponent?.(fieldName);
|
|
10293
|
+
const shell = loader.shellRefs?.get?.(fieldName);
|
|
10294
|
+
if (shell) {
|
|
10295
|
+
shell.instance.field = {
|
|
10296
|
+
...(shell.instance.field || {}),
|
|
10297
|
+
...metadata,
|
|
10298
|
+
};
|
|
10299
|
+
if (typeof isVisible === 'boolean') {
|
|
10300
|
+
shell.instance.visible = isVisible;
|
|
10301
|
+
}
|
|
10302
|
+
try {
|
|
10303
|
+
shell.changeDetectorRef.detectChanges();
|
|
10304
|
+
}
|
|
10305
|
+
catch { }
|
|
10306
|
+
}
|
|
10307
|
+
try {
|
|
10308
|
+
this.debugLog('[PDF] hot-update: component lookup', { fieldName, found: !!comp });
|
|
10309
|
+
}
|
|
10310
|
+
catch { }
|
|
10311
|
+
if (comp) {
|
|
10312
|
+
const inst = comp.instance;
|
|
10313
|
+
if (typeof inst.setInputMetadata === 'function') {
|
|
10314
|
+
try {
|
|
10315
|
+
this.debugLog('[PDF] Applying setInputMetadata on live instance', { fieldName, hasFn: true });
|
|
10316
|
+
inst.setInputMetadata(metadata);
|
|
10317
|
+
}
|
|
10318
|
+
catch (e) {
|
|
10319
|
+
this.warnLog('[PDF] setInputMetadata failed; refreshing loader', e);
|
|
10320
|
+
loader.refresh();
|
|
10321
|
+
}
|
|
10322
|
+
}
|
|
10323
|
+
else if (inst?.metadata && typeof inst.metadata === 'function' && 'set' in inst.metadata) {
|
|
10324
|
+
try {
|
|
10325
|
+
this.debugLog('[PDF] Using metadata.set on live instance', { fieldName });
|
|
10326
|
+
inst.metadata.set(metadata);
|
|
10327
|
+
}
|
|
10328
|
+
catch (e) {
|
|
10329
|
+
this.warnLog('[PDF] metadata.set failed; refreshing loader', e);
|
|
10330
|
+
loader.refresh();
|
|
10331
|
+
}
|
|
10332
|
+
}
|
|
10333
|
+
else {
|
|
10334
|
+
this.warnLog('[PDF] No hot-update path; refreshing loader', { fieldName });
|
|
10335
|
+
loader.refresh();
|
|
10336
|
+
}
|
|
10337
|
+
}
|
|
10338
|
+
else {
|
|
10339
|
+
this.warnLog('[PDF] Component not found; refreshing loader', { fieldName });
|
|
10340
|
+
loader.refresh();
|
|
10341
|
+
}
|
|
10342
|
+
}
|
|
10343
|
+
catch (e) {
|
|
10344
|
+
this.warnLog('[PDF] hot-update error; refreshing loader', { fieldName, error: e?.message || e });
|
|
10345
|
+
try {
|
|
10346
|
+
loader.refresh();
|
|
10347
|
+
}
|
|
10348
|
+
catch { }
|
|
10349
|
+
}
|
|
10350
|
+
}
|
|
10351
|
+
else {
|
|
10352
|
+
this.debugLog('[PDF] Loader not found; skipping live patch', { fieldName });
|
|
10353
|
+
}
|
|
10354
|
+
}
|
|
10205
10355
|
// --- New methods for field canvas interaction ---
|
|
10206
10356
|
onToolbarMove(direction) {
|
|
10207
10357
|
if (!this.selectedElement)
|
|
@@ -10843,11 +10993,22 @@ class PraxisDynamicForm {
|
|
|
10843
10993
|
};
|
|
10844
10994
|
}
|
|
10845
10995
|
readLegacySchemaUrlForEditor() {
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10996
|
+
// Detached hosts such as the public playground can mount PraxisDynamicForm
|
|
10997
|
+
// without a configured GenericCrudService. The editor contract should
|
|
10998
|
+
// degrade gracefully in that case instead of crashing while probing the
|
|
10999
|
+
// legacy CRUD schema URL.
|
|
11000
|
+
let schemaUrlSource = '';
|
|
11001
|
+
try {
|
|
11002
|
+
schemaUrlSource =
|
|
11003
|
+
typeof this.crud.schemaUrl === 'function'
|
|
11004
|
+
? this.crud.schemaUrl()
|
|
11005
|
+
: typeof this.crud.schemaUrl === 'string'
|
|
11006
|
+
? this.crud.schemaUrl
|
|
11007
|
+
: '';
|
|
11008
|
+
}
|
|
11009
|
+
catch {
|
|
11010
|
+
schemaUrlSource = '';
|
|
11011
|
+
}
|
|
10851
11012
|
const normalized = String(schemaUrlSource || '').trim();
|
|
10852
11013
|
return normalized || null;
|
|
10853
11014
|
}
|
|
@@ -11399,7 +11560,7 @@ class PraxisDynamicForm {
|
|
|
11399
11560
|
}
|
|
11400
11561
|
}
|
|
11401
11562
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisDynamicForm, deps: [{ token: i1$2.GenericCrudService }, { token: i2.HttpClient }, { token: i1$3.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: FormLayoutService }, { token: FormContextService }, { token: FormRulesService }, { token: i7.SettingsPanelService }, { token: i2$1.MatDialog }, { token: ASYNC_CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: i1$2.DynamicFormService }, { token: i9$1.MatSnackBar }, { token: CanvasStateService }, { token: DynamicFormLayoutService }, { token: i1$2.ErrorMessageService }, { token: i1$2.SchemaNormalizerService }, { token: i1$2.ComponentMetadataRegistry }, { token: i1$2.GlobalConfigService }, { token: i1$2.ComponentKeyService }, { token: i1$2.LoadingOrchestrator }, { token: i0.NgZone }, { token: API_URL }, { token: PRAXIS_LOADING_RENDERER, optional: true }, { token: i12.Router, optional: true }, { token: i12.ActivatedRoute, optional: true }, { token: i1$2.FormHooksRegistry, optional: true }, { token: FORM_HOOKS_PRESETS, optional: true }, { token: i1$2.LoggerService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
11402
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", editorialContext: "editorialContext", mode: "mode", config: "config", schemaSource: "schemaSource", schemaUrl: "schemaUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", formId: "formId", componentInstanceId: "componentInstanceId", layout: "layout", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", visibleGlobal: "visibleGlobal", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", formReady: "formReady", valueChange: "valueChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", widgetEvent: "widgetEvent" }, providers: [providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true }, { propertyName: "fieldLoaders", predicate: DynamicFieldLoaderDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<!-- Loading State -->\n<div class=\"form-loading\">\n <mat-progress-spinner diameter=\"40\"></mat-progress-spinner>\n <p>Carregando formul\u00E1rio...</p>\n</div>\n} @else if (initializationStatus === 'error') {\n<!-- Error State -->\n<div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n</div>\n} @else if (initializationStatus === 'success') {\n<!-- Inline banner for schema change (only when customization is enabled) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n</div>\n}\n\n<!-- Configuration Controls -->\n@if (shouldShowConfigControls && enableCustomization) {\n<div class=\"form-config-controls\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n <button type=\"button\" mat-icon-button (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configurar formul\u00E1rio'\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n <button type=\"button\" mat-icon-button (click)=\"disconnect()\" matTooltip=\"Desconectar da fonte de dados\"\n [disabled]=\"isLoading\">\n <mat-icon [praxisIcon]=\"'link_off'\"></mat-icon>\n </button>\n</div>\n}\n\n<!-- Form Content -->\n@if (!resourcePath && (!config.sections || config.sections.length === 0)) {\n<praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n}\n<form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n *ngIf=\"enableCustomization && selectedElement\" [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n\n @if (formBlocksBefore.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n @for (block of formBlocksBefore; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('before', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of config.sections; track (section.id ?? $index); let sectionIndex = $index;\n let last = $last) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!last ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getSectionTitleGapBottom(section) ?? 20\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n mat-icon-button\n [color]=\"getSectionHeaderActionColor(action)\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <mat-progress-spinner diameter=\"16\" mode=\"indeterminate\"></mat-progress-spinner>\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n } @else {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" mat-icon-button\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n <mat-icon [praxisIcon]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\"></mat-icon>\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n <ng-container dynamicFieldLoader [fields]=\"getColumnFields(column)\" [formGroup]=\"form\"\n [readonlyMode]=\"readonlyModeGlobal === null ? null : readonlyModeGlobal\"\n [disabledMode]=\"disabledModeGlobal === null ? null : disabledModeGlobal\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (last && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && last && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"config.actions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner diameter=\"40\" color=\"primary\"></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n @for (block of formBlocksAfter; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('after', $event)\">\n </ng-container>\n }\n </section>\n }\n</form>\n@if (!enableCustomization && mode === 'view') {\n<div class=\"ai-floating-assistant\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n</div>\n}\n}\n", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@media(min-width:600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@media(min-width:900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@media(min-width:1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@media(min-width:1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative}.form-config-controls{position:sticky;top:10px;margin-left:auto;margin-bottom:10px;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--md-sys-color-surface) 92%,transparent);padding:6px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:999px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 10px 22px #0f172a14;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.88;transition:opacity .16s ease,box-shadow .16s ease,border-color .16s ease,transform .16s ease}.form-config-controls>*{pointer-events:auto}.praxis-dynamic-form:hover .form-config-controls,.praxis-dynamic-form:focus-within .form-config-controls{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%);box-shadow:0 14px 28px #0f172a1f;transform:translateY(-1px)}.form-config-controls .mat-icon-button{--mdc-icon-button-state-layer-size: 34px;width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);border:1px solid transparent}.form-config-controls .mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant praxis-ai-assistant{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-on-surface);gap:1rem}.form-loading p{margin:0;font-size:.875rem;opacity:.7}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var(--md-sys-color-surface-container-low);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--md-sys-color-outline-variant) );--pfx-editorial-form-text: var(--md-sys-color-on-surface);--pfx-editorial-form-text-muted: var(--md-sys-color-on-surface-variant);--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var(--md-sys-color-primary);--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.editorial-visual-context{font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--editorial-text-primary, var(--md-sys-color-on-surface));--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--md-sys-color-primary)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--md-sys-color-on-primary)) );--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --pfx-editorial-form-text, var(--md-sys-color-on-surface) );--md-sys-color-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant) );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, var(--md-sys-color-on-surface-rgb) );--mat-sys-on-surface: var( --pfx-editorial-form-text, var(--mat-sys-on-surface) );--mat-sys-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--mat-sys-on-surface-variant) );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, var(--mat-sys-on-surface-rgb, var(--md-sys-color-on-surface-rgb)) );color:var(--pfx-editorial-form-text);color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:.5rem;margin-bottom:.5rem}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:.75rem .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:.35rem;margin-bottom:.35rem}.praxis-dynamic-form.pres-compact .form-section{padding:.5rem .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:var(--pfx-presentation-label-w, 220px) 1fr;align-items:baseline;column-gap:10px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:18px;border-bottom:1px solid var(--pfx-form-section-divider)}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:18px;padding-top:0}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle;--mdc-icon-button-size: 28px;--mdc-icon-button-icon-size: 16px}.inline-edit-btn mat-icon{font-size:16px;width:16px;height:16px}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-row.grid-12{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.form-row{flex-direction:column;gap:.5rem}.form-section{padding:1rem}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:14px}}.section-title{display:flex;align-items:center;gap:8px}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i16.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i18.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: CanvasToolbarComponent, selector: "praxis-canvas-toolbar", inputs: ["selectedElement"], outputs: ["editMetadata", "delete", "moveUp", "moveDown", "selectPath", "requestClose", "toggleReadonly", "toggleRequired", "toggleHidden", "toggleDisabled"] }, { kind: "component", type: PraxisFormActionsComponent, selector: "praxis-form-actions", inputs: ["actions", "editorialVisualContext", "isSubmitting", "formIsValid", "submitError", "formId", "actionOverrides"], outputs: ["action"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }] });
|
|
11563
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", editorialContext: "editorialContext", mode: "mode", config: "config", schemaSource: "schemaSource", schemaUrl: "schemaUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", formId: "formId", componentInstanceId: "componentInstanceId", layout: "layout", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", visibleGlobal: "visibleGlobal", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", formReady: "formReady", valueChange: "valueChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", widgetEvent: "widgetEvent" }, providers: [providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true }, { propertyName: "fieldLoaders", predicate: DynamicFieldLoaderDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<!-- Loading State -->\n<div class=\"form-loading\">\n <mat-progress-spinner diameter=\"40\"></mat-progress-spinner>\n <p>Carregando formul\u00E1rio...</p>\n</div>\n} @else if (initializationStatus === 'error') {\n<!-- Error State -->\n<div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n</div>\n} @else if (initializationStatus === 'success') {\n<!-- Inline banner for schema change (only when customization is enabled) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n</div>\n}\n\n<!-- Configuration Controls -->\n@if (shouldShowConfigControls && enableCustomization) {\n<div class=\"form-config-controls\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n <button type=\"button\" mat-icon-button (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configurar formul\u00E1rio'\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n <button type=\"button\" mat-icon-button (click)=\"disconnect()\" matTooltip=\"Desconectar da fonte de dados\"\n [disabled]=\"isLoading\">\n <mat-icon [praxisIcon]=\"'link_off'\"></mat-icon>\n </button>\n</div>\n}\n\n<!-- Form Content -->\n@if (!resourcePath && (!config.sections || config.sections.length === 0)) {\n<praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n}\n<form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n *ngIf=\"enableCustomization && selectedElement\" [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n\n @if (formBlocksBefore.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n @for (block of formBlocksBefore; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('before', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of config.sections; track (section.id ?? $index); let sectionIndex = $index;\n let last = $last) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!last ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getSectionTitleGapBottom(section) ?? 20\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n mat-icon-button\n [color]=\"getSectionHeaderActionColor(action)\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <mat-progress-spinner diameter=\"16\" mode=\"indeterminate\"></mat-progress-spinner>\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n } @else {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" mat-icon-button\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n <mat-icon [praxisIcon]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\"></mat-icon>\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n <ng-container dynamicFieldLoader [fields]=\"getColumnFields(column)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"readonlyModeGlobal === null ? null : readonlyModeGlobal\"\n [disabledMode]=\"disabledModeGlobal === null ? null : disabledModeGlobal\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (last && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && last && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"config.actions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner diameter=\"40\" color=\"primary\"></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n @for (block of formBlocksAfter; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('after', $event)\">\n </ng-container>\n }\n </section>\n }\n</form>\n@if (!enableCustomization && mode === 'view') {\n<div class=\"ai-floating-assistant\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n</div>\n}\n}\n", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@media(min-width:600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@media(min-width:900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@media(min-width:1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@media(min-width:1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative}.form-config-controls{position:sticky;top:10px;margin-left:auto;margin-bottom:10px;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--md-sys-color-surface) 92%,transparent);padding:6px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:999px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 10px 22px #0f172a14;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.88;transition:opacity .16s ease,box-shadow .16s ease,border-color .16s ease,transform .16s ease}.form-config-controls>*{pointer-events:auto}.praxis-dynamic-form:hover .form-config-controls,.praxis-dynamic-form:focus-within .form-config-controls{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%);box-shadow:0 14px 28px #0f172a1f;transform:translateY(-1px)}.form-config-controls .mat-icon-button{--mdc-icon-button-state-layer-size: 34px;width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);border:1px solid transparent}.form-config-controls .mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant praxis-ai-assistant{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-on-surface);gap:1rem}.form-loading p{margin:0;font-size:.875rem;opacity:.7}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var(--md-sys-color-surface-container-low);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--md-sys-color-outline-variant) );--pfx-editorial-form-text: var(--md-sys-color-on-surface);--pfx-editorial-form-text-muted: var(--md-sys-color-on-surface-variant);--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var(--md-sys-color-primary);--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.editorial-visual-context{font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--editorial-text-primary, var(--md-sys-color-on-surface));--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--md-sys-color-primary)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--md-sys-color-on-primary)) );--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --pfx-editorial-form-text, var(--md-sys-color-on-surface) );--md-sys-color-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant) );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, var(--md-sys-color-on-surface-rgb) );--mat-sys-on-surface: var( --pfx-editorial-form-text, var(--mat-sys-on-surface) );--mat-sys-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--mat-sys-on-surface-variant) );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, var(--mat-sys-on-surface-rgb, var(--md-sys-color-on-surface-rgb)) );color:var(--pfx-editorial-form-text);color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:.5rem;margin-bottom:.5rem}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:.75rem .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:.35rem;margin-bottom:.35rem}.praxis-dynamic-form.pres-compact .form-section{padding:.5rem .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:var(--pfx-presentation-label-w, 220px) 1fr;align-items:baseline;column-gap:10px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:18px;border-bottom:1px solid var(--pfx-form-section-divider)}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:18px;padding-top:0}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle;--mdc-icon-button-size: 28px;--mdc-icon-button-icon-size: 16px}.inline-edit-btn mat-icon{font-size:16px;width:16px;height:16px}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-row.grid-12{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.form-row{flex-direction:column;gap:.5rem}.form-section{padding:1rem}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:14px}}.section-title{display:flex;align-items:center;gap:8px}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i16.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i18.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: CanvasToolbarComponent, selector: "praxis-canvas-toolbar", inputs: ["selectedElement"], outputs: ["editMetadata", "delete", "moveUp", "moveDown", "selectPath", "requestClose", "toggleReadonly", "toggleRequired", "toggleHidden", "toggleDisabled"] }, { kind: "component", type: PraxisFormActionsComponent, selector: "praxis-form-actions", inputs: ["actions", "editorialVisualContext", "isSubmitting", "formIsValid", "submitError", "formId", "actionOverrides"], outputs: ["action"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }] });
|
|
11403
11564
|
}
|
|
11404
11565
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisDynamicForm, decorators: [{
|
|
11405
11566
|
type: Component,
|
|
@@ -11420,7 +11581,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
11420
11581
|
PraxisFormActionsComponent,
|
|
11421
11582
|
EmptyStateCardComponent,
|
|
11422
11583
|
PraxisAiAssistantComponent,
|
|
11423
|
-
], template: "@if (isLoading) {\n<!-- Loading State -->\n<div class=\"form-loading\">\n <mat-progress-spinner diameter=\"40\"></mat-progress-spinner>\n <p>Carregando formul\u00E1rio...</p>\n</div>\n} @else if (initializationStatus === 'error') {\n<!-- Error State -->\n<div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n</div>\n} @else if (initializationStatus === 'success') {\n<!-- Inline banner for schema change (only when customization is enabled) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n</div>\n}\n\n<!-- Configuration Controls -->\n@if (shouldShowConfigControls && enableCustomization) {\n<div class=\"form-config-controls\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n <button type=\"button\" mat-icon-button (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configurar formul\u00E1rio'\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n <button type=\"button\" mat-icon-button (click)=\"disconnect()\" matTooltip=\"Desconectar da fonte de dados\"\n [disabled]=\"isLoading\">\n <mat-icon [praxisIcon]=\"'link_off'\"></mat-icon>\n </button>\n</div>\n}\n\n<!-- Form Content -->\n@if (!resourcePath && (!config.sections || config.sections.length === 0)) {\n<praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n}\n<form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n *ngIf=\"enableCustomization && selectedElement\" [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n\n @if (formBlocksBefore.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n @for (block of formBlocksBefore; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('before', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of config.sections; track (section.id ?? $index); let sectionIndex = $index;\n let last = $last) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!last ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getSectionTitleGapBottom(section) ?? 20\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n mat-icon-button\n [color]=\"getSectionHeaderActionColor(action)\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <mat-progress-spinner diameter=\"16\" mode=\"indeterminate\"></mat-progress-spinner>\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n } @else {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" mat-icon-button\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n <mat-icon [praxisIcon]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\"></mat-icon>\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n <ng-container dynamicFieldLoader [fields]=\"getColumnFields(column)\" [formGroup]=\"form\"\n [readonlyMode]=\"readonlyModeGlobal === null ? null : readonlyModeGlobal\"\n [disabledMode]=\"disabledModeGlobal === null ? null : disabledModeGlobal\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (last && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && last && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"config.actions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner diameter=\"40\" color=\"primary\"></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n @for (block of formBlocksAfter; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('after', $event)\">\n </ng-container>\n }\n </section>\n }\n</form>\n@if (!enableCustomization && mode === 'view') {\n<div class=\"ai-floating-assistant\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n</div>\n}\n}\n", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@media(min-width:600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@media(min-width:900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@media(min-width:1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@media(min-width:1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative}.form-config-controls{position:sticky;top:10px;margin-left:auto;margin-bottom:10px;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--md-sys-color-surface) 92%,transparent);padding:6px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:999px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 10px 22px #0f172a14;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.88;transition:opacity .16s ease,box-shadow .16s ease,border-color .16s ease,transform .16s ease}.form-config-controls>*{pointer-events:auto}.praxis-dynamic-form:hover .form-config-controls,.praxis-dynamic-form:focus-within .form-config-controls{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%);box-shadow:0 14px 28px #0f172a1f;transform:translateY(-1px)}.form-config-controls .mat-icon-button{--mdc-icon-button-state-layer-size: 34px;width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);border:1px solid transparent}.form-config-controls .mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant praxis-ai-assistant{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-on-surface);gap:1rem}.form-loading p{margin:0;font-size:.875rem;opacity:.7}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var(--md-sys-color-surface-container-low);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--md-sys-color-outline-variant) );--pfx-editorial-form-text: var(--md-sys-color-on-surface);--pfx-editorial-form-text-muted: var(--md-sys-color-on-surface-variant);--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var(--md-sys-color-primary);--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.editorial-visual-context{font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--editorial-text-primary, var(--md-sys-color-on-surface));--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--md-sys-color-primary)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--md-sys-color-on-primary)) );--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --pfx-editorial-form-text, var(--md-sys-color-on-surface) );--md-sys-color-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant) );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, var(--md-sys-color-on-surface-rgb) );--mat-sys-on-surface: var( --pfx-editorial-form-text, var(--mat-sys-on-surface) );--mat-sys-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--mat-sys-on-surface-variant) );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, var(--mat-sys-on-surface-rgb, var(--md-sys-color-on-surface-rgb)) );color:var(--pfx-editorial-form-text);color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:.5rem;margin-bottom:.5rem}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:.75rem .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:.35rem;margin-bottom:.35rem}.praxis-dynamic-form.pres-compact .form-section{padding:.5rem .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:var(--pfx-presentation-label-w, 220px) 1fr;align-items:baseline;column-gap:10px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:18px;border-bottom:1px solid var(--pfx-form-section-divider)}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:18px;padding-top:0}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle;--mdc-icon-button-size: 28px;--mdc-icon-button-icon-size: 16px}.inline-edit-btn mat-icon{font-size:16px;width:16px;height:16px}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-row.grid-12{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.form-row{flex-direction:column;gap:.5rem}.form-section{padding:1rem}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:14px}}.section-title{display:flex;align-items:center;gap:8px}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
11584
|
+
], template: "@if (isLoading) {\n<!-- Loading State -->\n<div class=\"form-loading\">\n <mat-progress-spinner diameter=\"40\"></mat-progress-spinner>\n <p>Carregando formul\u00E1rio...</p>\n</div>\n} @else if (initializationStatus === 'error') {\n<!-- Error State -->\n<div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n</div>\n} @else if (initializationStatus === 'success') {\n<!-- Inline banner for schema change (only when customization is enabled) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n</div>\n}\n\n<!-- Configuration Controls -->\n@if (shouldShowConfigControls && enableCustomization) {\n<div class=\"form-config-controls\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n <button type=\"button\" mat-icon-button (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configurar formul\u00E1rio'\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n <button type=\"button\" mat-icon-button (click)=\"disconnect()\" matTooltip=\"Desconectar da fonte de dados\"\n [disabled]=\"isLoading\">\n <mat-icon [praxisIcon]=\"'link_off'\"></mat-icon>\n </button>\n</div>\n}\n\n<!-- Form Content -->\n@if (!resourcePath && (!config.sections || config.sections.length === 0)) {\n<praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n}\n<form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n *ngIf=\"enableCustomization && selectedElement\" [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n\n @if (formBlocksBefore.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n @for (block of formBlocksBefore; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('before', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of config.sections; track (section.id ?? $index); let sectionIndex = $index;\n let last = $last) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!last ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getSectionTitleGapBottom(section) ?? 20\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" mat-icon-button\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n <mat-icon>edit</mat-icon>\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n mat-icon-button\n [color]=\"getSectionHeaderActionColor(action)\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <mat-progress-spinner diameter=\"16\" mode=\"indeterminate\"></mat-progress-spinner>\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n } @else {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" mat-icon-button\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n <mat-icon [praxisIcon]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\"></mat-icon>\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n <ng-container dynamicFieldLoader [fields]=\"getColumnFields(column)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"readonlyModeGlobal === null ? null : readonlyModeGlobal\"\n [disabledMode]=\"disabledModeGlobal === null ? null : disabledModeGlobal\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (last && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && last && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"config.actions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner diameter=\"40\" color=\"primary\"></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n @for (block of formBlocksBeforeActions; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('beforeActions', $event)\">\n </ng-container>\n }\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"config.actions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"form.valid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n @for (block of formBlocksAfter; track (block.id ?? $index)) {\n <ng-container\n [dynamicWidgetLoader]=\"block\"\n [context]=\"getEditorialWidgetContext()\"\n [strictValidation]=\"true\"\n [autoWireOutputs]=\"true\"\n (widgetEvent)=\"onEditorialWidgetEvent('after', $event)\">\n </ng-container>\n }\n </section>\n }\n</form>\n@if (!enableCustomization && mode === 'view') {\n<div class=\"ai-floating-assistant\">\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n</div>\n}\n}\n", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@media(min-width:600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@media(min-width:900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@media(min-width:1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@media(min-width:1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative}.form-config-controls{position:sticky;top:10px;margin-left:auto;margin-bottom:10px;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--md-sys-color-surface) 92%,transparent);padding:6px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:999px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 10px 22px #0f172a14;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.88;transition:opacity .16s ease,box-shadow .16s ease,border-color .16s ease,transform .16s ease}.form-config-controls>*{pointer-events:auto}.praxis-dynamic-form:hover .form-config-controls,.praxis-dynamic-form:focus-within .form-config-controls{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%);box-shadow:0 14px 28px #0f172a1f;transform:translateY(-1px)}.form-config-controls .mat-icon-button{--mdc-icon-button-state-layer-size: 34px;width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);border:1px solid transparent}.form-config-controls .mat-icon-button:hover{color:var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant praxis-ai-assistant{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-on-surface);gap:1rem}.form-loading p{margin:0;font-size:.875rem;opacity:.7}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var(--md-sys-color-surface-container-low);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--md-sys-color-outline-variant) );--pfx-editorial-form-text: var(--md-sys-color-on-surface);--pfx-editorial-form-text-muted: var(--md-sys-color-on-surface-variant);--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var(--md-sys-color-primary);--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.editorial-visual-context{font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--editorial-text-primary, var(--md-sys-color-on-surface));--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--md-sys-color-primary)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--md-sys-color-on-primary)) );--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --pfx-editorial-form-text, var(--md-sys-color-on-surface) );--md-sys-color-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant) );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, var(--md-sys-color-on-surface-rgb) );--mat-sys-on-surface: var( --pfx-editorial-form-text, var(--mat-sys-on-surface) );--mat-sys-on-surface-variant: var( --pfx-editorial-form-text-muted, var(--mat-sys-on-surface-variant) );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, var(--mat-sys-on-surface-rgb, var(--md-sys-color-on-surface-rgb)) );color:var(--pfx-editorial-form-text);color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:.5rem;margin-bottom:.5rem}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:.75rem .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:.35rem;margin-bottom:.35rem}.praxis-dynamic-form.pres-compact .form-section{padding:.5rem .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:var(--pfx-presentation-label-w, 220px) 1fr;align-items:baseline;column-gap:10px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:18px;border-bottom:1px solid var(--pfx-form-section-divider)}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections] .form-actions{margin-top:18px;padding-top:0}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle;--mdc-icon-button-size: 28px;--mdc-icon-button-icon-size: 16px}.inline-edit-btn mat-icon{font-size:16px;width:16px;height:16px}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-row.grid-12{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.form-row{flex-direction:column;gap:.5rem}.form-section{padding:1rem}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:14px}}.section-title{display:flex;align-items:center;gap:8px}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
11424
11585
|
}], ctorParameters: () => [{ type: i1$2.GenericCrudService }, { type: i2.HttpClient }, { type: i1$3.FormBuilder }, { type: i0.ChangeDetectorRef }, { type: FormLayoutService }, { type: FormContextService }, { type: FormRulesService }, { type: i7.SettingsPanelService }, { type: i2$1.MatDialog }, { type: undefined, decorators: [{
|
|
11425
11586
|
type: Inject,
|
|
11426
11587
|
args: [ASYNC_CONFIG_STORAGE]
|
|
@@ -17693,11 +17854,13 @@ function formLayoutRulesToBuilderState(rules) {
|
|
|
17693
17854
|
}
|
|
17694
17855
|
for (const rule of rules) {
|
|
17695
17856
|
const nodePairs = formLayoutRuleToNodes(rule);
|
|
17696
|
-
nodePairs.forEach(({ rootNode, conditionNode }) => {
|
|
17857
|
+
nodePairs.forEach(({ rootNode, conditionNode, conditionNodes }) => {
|
|
17697
17858
|
state.nodes[rootNode.id] = rootNode;
|
|
17698
17859
|
state.rootNodes.push(rootNode.id);
|
|
17699
17860
|
if (conditionNode) {
|
|
17700
|
-
|
|
17861
|
+
for (const nestedNode of conditionNodes) {
|
|
17862
|
+
state.nodes[nestedNode.id] = nestedNode;
|
|
17863
|
+
}
|
|
17701
17864
|
}
|
|
17702
17865
|
});
|
|
17703
17866
|
}
|
|
@@ -17722,12 +17885,12 @@ function ruleNodeToFormLayoutRule(node, allNodes) {
|
|
|
17722
17885
|
const normalizedTargetType = targetType;
|
|
17723
17886
|
const ruleId = config.ruleId || node.id;
|
|
17724
17887
|
const nodeType = config.type || node.type;
|
|
17725
|
-
let
|
|
17888
|
+
let conditionExpression = null;
|
|
17726
17889
|
if (config.conditionNodeId) {
|
|
17727
|
-
|
|
17890
|
+
conditionExpression = buildJsonLogicFromCondition(allNodes[config.conditionNodeId], allNodes);
|
|
17728
17891
|
}
|
|
17729
17892
|
else if (config.condition) {
|
|
17730
|
-
|
|
17893
|
+
conditionExpression = buildJsonLogicFromCondition(config.condition, allNodes);
|
|
17731
17894
|
}
|
|
17732
17895
|
const inferredProperties = nodeType === 'propertyRule' ? null : inferPropertiesFromNode(nodeType);
|
|
17733
17896
|
const properties = config.properties || (inferredProperties?.properties ?? undefined);
|
|
@@ -17740,38 +17903,37 @@ function ruleNodeToFormLayoutRule(node, allNodes) {
|
|
|
17740
17903
|
targets,
|
|
17741
17904
|
description: node.metadata?.description,
|
|
17742
17905
|
effect: {
|
|
17743
|
-
condition:
|
|
17906
|
+
condition: conditionExpression ?? null,
|
|
17744
17907
|
properties,
|
|
17745
17908
|
propertiesWhenFalse,
|
|
17746
17909
|
},
|
|
17747
17910
|
});
|
|
17748
17911
|
return sanitizeRuleEffect(migrated);
|
|
17749
17912
|
}
|
|
17750
|
-
function
|
|
17913
|
+
function buildJsonLogicFromCondition(node, allNodes) {
|
|
17751
17914
|
if (!node) {
|
|
17752
17915
|
return null;
|
|
17753
17916
|
}
|
|
17754
17917
|
if (typeof node === 'string') {
|
|
17755
|
-
return
|
|
17918
|
+
return null;
|
|
17756
17919
|
}
|
|
17757
17920
|
if (node.type === 'fieldCondition') {
|
|
17758
17921
|
const cfg = node.config;
|
|
17759
|
-
const
|
|
17760
|
-
if (!
|
|
17922
|
+
const expression = buildFieldConditionExpression(cfg);
|
|
17923
|
+
if (!expression) {
|
|
17761
17924
|
return null;
|
|
17762
17925
|
}
|
|
17763
|
-
|
|
17764
|
-
return `${cfg.fieldName} ${operator} ${value}`;
|
|
17926
|
+
return expression;
|
|
17765
17927
|
}
|
|
17766
17928
|
if (node.type === 'andGroup' || node.type === 'orGroup') {
|
|
17767
17929
|
const op = node.type === 'andGroup' ? 'and' : 'or';
|
|
17768
17930
|
const parts = (node.children || [])
|
|
17769
|
-
.map((id) =>
|
|
17770
|
-
.filter((
|
|
17931
|
+
.map((id) => buildJsonLogicFromCondition(allNodes[id], allNodes))
|
|
17932
|
+
.filter((part) => !!part);
|
|
17771
17933
|
if (parts.length === 0) {
|
|
17772
17934
|
return null;
|
|
17773
17935
|
}
|
|
17774
|
-
return parts.length > 1 ?
|
|
17936
|
+
return parts.length > 1 ? { [op]: parts } : parts[0];
|
|
17775
17937
|
}
|
|
17776
17938
|
return null;
|
|
17777
17939
|
}
|
|
@@ -17810,8 +17972,10 @@ function formLayoutRuleToNodes(rule) {
|
|
|
17810
17972
|
: [normalizedRule.id || generateId()];
|
|
17811
17973
|
targets.forEach((target, index) => {
|
|
17812
17974
|
let conditionNode;
|
|
17813
|
-
|
|
17814
|
-
|
|
17975
|
+
let conditionNodes = [];
|
|
17976
|
+
if (condition) {
|
|
17977
|
+
conditionNode = parseConditionExpression(condition);
|
|
17978
|
+
conditionNodes = conditionNode ? flattenConditionNodes(conditionNode) : [];
|
|
17815
17979
|
}
|
|
17816
17980
|
const inferredType = inferRuleType(normalizedRule);
|
|
17817
17981
|
const rootType = inferredType === 'propertyRule'
|
|
@@ -17829,7 +17993,7 @@ function formLayoutRuleToNodes(rule) {
|
|
|
17829
17993
|
properties: filterRuleProperties(normalizedRule.targetType, normalizedRule.effect?.properties),
|
|
17830
17994
|
propertiesWhenFalse: filterRuleProperties(normalizedRule.targetType, normalizedRule.effect?.propertiesWhenFalse),
|
|
17831
17995
|
ruleId: normalizedRule.id,
|
|
17832
|
-
condition:
|
|
17996
|
+
condition: conditionNode ? normalizedRule.effect?.condition : undefined,
|
|
17833
17997
|
};
|
|
17834
17998
|
if (normalizedRule.targetType && normalizedRule.targetType !== 'field') {
|
|
17835
17999
|
config.targetType = normalizedRule.targetType;
|
|
@@ -17846,7 +18010,7 @@ function formLayoutRuleToNodes(rule) {
|
|
|
17846
18010
|
label: normalizedRule.name,
|
|
17847
18011
|
config,
|
|
17848
18012
|
};
|
|
17849
|
-
nodes.push({ rootNode, conditionNode });
|
|
18013
|
+
nodes.push({ rootNode, conditionNode, conditionNodes });
|
|
17850
18014
|
});
|
|
17851
18015
|
return nodes;
|
|
17852
18016
|
}
|
|
@@ -17953,43 +18117,156 @@ function isScopedSectionHeaderActionTarget(value) {
|
|
|
17953
18117
|
function isUnscopedSectionHeaderActionTarget(value) {
|
|
17954
18118
|
return !!value && value.startsWith('header-action:');
|
|
17955
18119
|
}
|
|
17956
|
-
function
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
return
|
|
18120
|
+
function parseConditionExpression(condition) {
|
|
18121
|
+
if (condition &&
|
|
18122
|
+
typeof condition === 'object' &&
|
|
18123
|
+
!Array.isArray(condition)) {
|
|
18124
|
+
return parseJsonLogicCondition(condition);
|
|
17961
18125
|
}
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
18126
|
+
return undefined;
|
|
18127
|
+
}
|
|
18128
|
+
function parseJsonLogicCondition(condition) {
|
|
18129
|
+
if ('and' in condition || 'or' in condition) {
|
|
18130
|
+
const groupOperator = 'and' in condition ? 'and' : 'or';
|
|
18131
|
+
const rawChildren = condition[groupOperator];
|
|
18132
|
+
const children = Array.isArray(rawChildren) ? rawChildren : [rawChildren];
|
|
18133
|
+
const childNodes = children
|
|
18134
|
+
.map((child) => child &&
|
|
18135
|
+
typeof child === 'object' &&
|
|
18136
|
+
!Array.isArray(child)
|
|
18137
|
+
? parseJsonLogicCondition(child)
|
|
18138
|
+
: undefined)
|
|
18139
|
+
.filter((child) => !!child);
|
|
18140
|
+
if (!childNodes.length) {
|
|
18141
|
+
return undefined;
|
|
18142
|
+
}
|
|
18143
|
+
const nodeId = generateId();
|
|
18144
|
+
return {
|
|
18145
|
+
id: nodeId,
|
|
18146
|
+
type: groupOperator === 'and' ? 'andGroup' : 'orGroup',
|
|
18147
|
+
children: childNodes.map((child) => child.id),
|
|
18148
|
+
config: {
|
|
18149
|
+
type: groupOperator === 'and' ? 'andGroup' : 'orGroup',
|
|
18150
|
+
operator: groupOperator,
|
|
18151
|
+
},
|
|
18152
|
+
__children: childNodes,
|
|
18153
|
+
};
|
|
18154
|
+
}
|
|
18155
|
+
const operationKeys = Object.keys(condition);
|
|
18156
|
+
if (operationKeys.length !== 1) {
|
|
17965
18157
|
return undefined;
|
|
17966
18158
|
}
|
|
17967
|
-
const
|
|
17968
|
-
|
|
18159
|
+
const operatorKey = operationKeys[0];
|
|
18160
|
+
const args = condition[operatorKey];
|
|
18161
|
+
const normalizedOperator = jsonLogicOperatorToBuilderOperator(operatorKey);
|
|
18162
|
+
if (!normalizedOperator) {
|
|
17969
18163
|
return undefined;
|
|
17970
18164
|
}
|
|
17971
|
-
const
|
|
17972
|
-
|
|
17973
|
-
|
|
17974
|
-
value = JSON.parse(normalizedValueRaw);
|
|
18165
|
+
const normalizedArgs = Array.isArray(args) ? args : [args];
|
|
18166
|
+
if (normalizedArgs.length < 2) {
|
|
18167
|
+
return undefined;
|
|
17975
18168
|
}
|
|
17976
|
-
|
|
17977
|
-
|
|
17978
|
-
|
|
18169
|
+
const [left, right] = normalizedArgs;
|
|
18170
|
+
if (!isVarExpression(left)) {
|
|
18171
|
+
return undefined;
|
|
17979
18172
|
}
|
|
17980
|
-
|
|
17981
|
-
|
|
18173
|
+
return {
|
|
18174
|
+
id: generateId(),
|
|
17982
18175
|
type: 'fieldCondition',
|
|
17983
|
-
|
|
17984
|
-
|
|
17985
|
-
|
|
18176
|
+
config: {
|
|
18177
|
+
type: 'fieldCondition',
|
|
18178
|
+
fieldName: extractVarPath(left.var),
|
|
18179
|
+
operator: normalizedOperator,
|
|
18180
|
+
value: right,
|
|
18181
|
+
},
|
|
17986
18182
|
};
|
|
18183
|
+
}
|
|
18184
|
+
function buildFieldConditionExpression(config) {
|
|
18185
|
+
const operator = builderOperatorToJsonLogicOperator(config.operator);
|
|
18186
|
+
if (!config.fieldName || !operator) {
|
|
18187
|
+
return null;
|
|
18188
|
+
}
|
|
18189
|
+
const fieldReference = { var: config.fieldName };
|
|
17987
18190
|
return {
|
|
17988
|
-
|
|
17989
|
-
type: 'fieldCondition',
|
|
17990
|
-
config,
|
|
18191
|
+
[operator]: [fieldReference, normalizeConditionValue(config.value)],
|
|
17991
18192
|
};
|
|
17992
18193
|
}
|
|
18194
|
+
function builderOperatorToJsonLogicOperator(operator) {
|
|
18195
|
+
const normalized = normalizeOperator(operator);
|
|
18196
|
+
switch (normalized) {
|
|
18197
|
+
case 'eq':
|
|
18198
|
+
return '===';
|
|
18199
|
+
case 'neq':
|
|
18200
|
+
return '!==';
|
|
18201
|
+
case 'lt':
|
|
18202
|
+
return '<';
|
|
18203
|
+
case 'lte':
|
|
18204
|
+
return '<=';
|
|
18205
|
+
case 'gt':
|
|
18206
|
+
return '>';
|
|
18207
|
+
case 'gte':
|
|
18208
|
+
return '>=';
|
|
18209
|
+
case 'contains':
|
|
18210
|
+
return 'contains';
|
|
18211
|
+
case 'startsWith':
|
|
18212
|
+
return 'startsWith';
|
|
18213
|
+
case 'endsWith':
|
|
18214
|
+
return 'endsWith';
|
|
18215
|
+
case 'in':
|
|
18216
|
+
return 'in';
|
|
18217
|
+
default:
|
|
18218
|
+
return undefined;
|
|
18219
|
+
}
|
|
18220
|
+
}
|
|
18221
|
+
function jsonLogicOperatorToBuilderOperator(operator) {
|
|
18222
|
+
switch (operator) {
|
|
18223
|
+
case '===':
|
|
18224
|
+
case '==':
|
|
18225
|
+
return 'eq';
|
|
18226
|
+
case '!==':
|
|
18227
|
+
case '!=':
|
|
18228
|
+
return 'neq';
|
|
18229
|
+
case '<':
|
|
18230
|
+
return 'lt';
|
|
18231
|
+
case '<=':
|
|
18232
|
+
return 'lte';
|
|
18233
|
+
case '>':
|
|
18234
|
+
return 'gt';
|
|
18235
|
+
case '>=':
|
|
18236
|
+
return 'gte';
|
|
18237
|
+
case 'contains':
|
|
18238
|
+
return 'contains';
|
|
18239
|
+
case 'startsWith':
|
|
18240
|
+
return 'startsWith';
|
|
18241
|
+
case 'endsWith':
|
|
18242
|
+
return 'endsWith';
|
|
18243
|
+
case 'in':
|
|
18244
|
+
return 'in';
|
|
18245
|
+
default:
|
|
18246
|
+
return undefined;
|
|
18247
|
+
}
|
|
18248
|
+
}
|
|
18249
|
+
function normalizeConditionValue(value) {
|
|
18250
|
+
if (value === undefined) {
|
|
18251
|
+
return null;
|
|
18252
|
+
}
|
|
18253
|
+
return value;
|
|
18254
|
+
}
|
|
18255
|
+
function isVarExpression(value) {
|
|
18256
|
+
return !!value && typeof value === 'object' && !Array.isArray(value) && 'var' in value;
|
|
18257
|
+
}
|
|
18258
|
+
function extractVarPath(reference) {
|
|
18259
|
+
return Array.isArray(reference) ? reference[0] : reference;
|
|
18260
|
+
}
|
|
18261
|
+
function flattenConditionNodes(rootNode) {
|
|
18262
|
+
const nodes = [rootNode];
|
|
18263
|
+
const nestedChildren = rootNode.__children || [];
|
|
18264
|
+
for (const child of nestedChildren) {
|
|
18265
|
+
nodes.push(...flattenConditionNodes(child));
|
|
18266
|
+
}
|
|
18267
|
+
delete rootNode.__children;
|
|
18268
|
+
return nodes;
|
|
18269
|
+
}
|
|
17993
18270
|
function generateId() {
|
|
17994
18271
|
return Math.random().toString(36).substring(2, 9);
|
|
17995
18272
|
}
|
|
@@ -18613,7 +18890,6 @@ class PraxisDynamicFormConfigEditor {
|
|
|
18613
18890
|
nodes: state.nodes,
|
|
18614
18891
|
rootNodes: state.rootNodes,
|
|
18615
18892
|
currentJSON: state.currentJSON,
|
|
18616
|
-
currentDSL: state.currentDSL,
|
|
18617
18893
|
validationErrors: state.validationErrors,
|
|
18618
18894
|
mode: state.mode,
|
|
18619
18895
|
});
|
|
@@ -19322,25 +19598,23 @@ function providePraxisDynamicFormMetadata() {
|
|
|
19322
19598
|
* Evaluates whether a rule's condition is satisfied for the given data.
|
|
19323
19599
|
* If no condition is defined, defaults to true.
|
|
19324
19600
|
*/
|
|
19325
|
-
const
|
|
19601
|
+
const jsonLogic = new PraxisJsonLogicService(null);
|
|
19326
19602
|
function isRuleSatisfied(rule, data) {
|
|
19327
19603
|
const { condition } = rule.effect;
|
|
19328
19604
|
if (condition === null || condition === undefined) {
|
|
19329
19605
|
return true;
|
|
19330
19606
|
}
|
|
19607
|
+
if (typeof condition === 'string') {
|
|
19608
|
+
return false;
|
|
19609
|
+
}
|
|
19331
19610
|
try {
|
|
19332
|
-
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
}
|
|
19336
|
-
else {
|
|
19337
|
-
specification = condition;
|
|
19338
|
-
}
|
|
19339
|
-
return specification.isSatisfiedBy(data);
|
|
19611
|
+
return jsonLogic.matches({
|
|
19612
|
+
condition: condition,
|
|
19613
|
+
data: (data ?? {}),
|
|
19614
|
+
});
|
|
19340
19615
|
}
|
|
19341
19616
|
catch {
|
|
19342
|
-
|
|
19343
|
-
return true;
|
|
19617
|
+
return false;
|
|
19344
19618
|
}
|
|
19345
19619
|
}
|
|
19346
19620
|
/**
|