
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@praxisui/dynamic-fields
Advanced tools
Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.
Para ver esta biblioteca em funcionamento em uma aplicação completa, utilize o projeto de exemplo (Quickstart):
@praxisui/* em um app Angular, incluindo instalação, configuração e uso em telas reais.Biblioteca de campos dinâmicos para aplicações Angular (v20+) com Material Design. Renderiza campos a partir de metadados, com carregamento lazy e integração com Reactive Forms.
npm install @praxisui/dynamic-fields
providePraxisDynamicFields(), a lib injeta um estilo escopado que garante mat-form-field { width: 100% } dentro dos componentes. Não é necessário repetir no app.:root {
--p-primary-gradient: linear-gradient(90deg, #1f8a8a, #6c63ff);
--p-input-gradient: var(--p-primary-gradient);
}
Sem essas variáveis, a aparência deriva do tema M3 (tokens --mat-sys-* / --md-sys-*).
Peers (instale no app host):
@angular/core ^20.1.0, @angular/common ^20.1.0, @angular/forms ^20.1.0@angular/material ^20.1.0, @angular/cdk ^20.1.0, @angular/router ^20.1.0rxjs ^7.8.0@praxisui/core, @praxisui/specification-core@praxisui/dialog, @praxisui/cron-builder@praxisui/coreimport { ComponentRegistryService } from "@praxisui/dynamic-fields";
import { FieldControlType } from "@praxisui/core";
// Obter componente usando constantes
const component = await registry.getComponent(FieldControlType.INPUT);
// Verificar registro
const isRegistered = registry.isRegistered(FieldControlType.INPUT);
O sistema usa as constantes do @praxisui/core para garantir consistência:
FieldControlType.INPUT - Campo de texto Material DesignFieldControlType.TEXTAREA - Área de texto Material DesignFieldControlType.SELECT - Campo de seleção Material DesignFieldControlType.CHECKBOX - Caixa de seleção Material DesignFieldControlType.RADIO - Botão de rádio Material DesignFieldControlType.DATE_PICKER - Seletor de data Material DesignFieldControlType.EMAIL_INPUT - Campo de emailFieldControlType.PASSWORD - Campo de senhaFieldControlType.CURRENCY_INPUT - Campo monetárioFieldControlType.NUMERIC_TEXT_BOX - Campo numéricoFieldControlType.MULTI_SELECT - Seleção múltiplaFieldControlType.AUTO_COMPLETE - Auto completar (busca habilitada por padrão)FieldControlType.DATE_TIME_PICKER - Data e horaFieldControlType.DATE_RANGE - Intervalo de datasFieldControlType.FILE_UPLOAD - Upload de arquivosFieldControlType.TOGGLE - Interruptor Material DesignFieldControlType.SLIDER - Slider Material DesignFieldControlType.TIME_PICKER - Seletor de horárioFieldControlType.RATING - Classificação por estrelasFieldControlType.COLOR_PICKER - Seletor de coresFieldControlType.AVATAR - Avatar visual (imagem/ícone/iniciais)Campos com FieldControlType.AUTO_COMPLETE utilizam internamente o MaterialSearchableSelectComponent, habilitando busca automaticamente.
O MaterialSelectComponent agora está dividido em subcomponentes menores para facilitar manutenção e testes:
multipleDisplay é "chips".Esses subcomponentes são utilizados internamente pelo select e não exigem alterações na utilização normal do componente.
Renderiza uma lista de checkboxes conectada ao @angular/forms, permitindo a seleção de múltiplos valores.
resourcePath, optionLabelKey e optionValueKey para popular opções via API.labelPosition e color conforme documentação do Angular Material.Grupo de botões de rádio que consome metadados ou dados remotos para criar seleções exclusivas.
MatRadioGroup para garantir apenas um valor ativo.MaterialSelectComponent para buscar opções.labelPosition e color segundo a documentação oficial.Componente visual para exibir representação de usuário/entidade/estado, com prioridade de conteúdo:
Propriedades principais: themeColor, rounded, size, fillMode, border, tooltip, ariaLabel.
Exemplos:
<pdx-material-avatar [imageSrc]="user.img" size="large" themeColor="tertiary"></pdx-material-avatar>
<pdx-material-avatar initials="MB" themeColor="secondary"></pdx-material-avatar>
<pdx-material-avatar icon="person" fillMode="outline"></pdx-material-avatar>
<pdx-material-avatar><app-status-badge></app-status-badge></pdx-material-avatar>
Uso em formulários dinâmicos (via metadata):
import { FieldControlType, type FieldMetadata } from '@praxisui/core';
const fields: FieldMetadata[] = [
{
name: 'avatar',
label: 'Avatar',
controlType: FieldControlType.AVATAR,
// opções específicas via `extra` (quando aplicável)
extra: { imageSrc: 'https://example.com/u/42.png', size: 'large' }
}
];
Tokens M3 aplicados:
--pfx-avatar-bg, --pfx-avatar-fg, --pfx-avatar-border-color, --pfx-avatar-border-w--pfx-avatar-size, --pfx-avatar-radius-[full|lg|md|sm]npm install @praxisui/dynamic-fields
Exemplo mínimo usando a diretiva dynamicFieldLoader para criar campos Material a partir de metadados.
import { Component, signal, inject } from '@angular/core';
import { ReactiveFormsModule, NonNullableFormBuilder, Validators } from '@angular/forms';
import { DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
import { FieldMetadata, FieldControlType } from '@praxisui/core';
@Component({
selector: 'app-dynamic-form',
standalone: true,
imports: [ReactiveFormsModule, DynamicFieldLoaderDirective],
template: `
<form [formGroup]="form">
<ng-container
dynamicFieldLoader
[fields]="fields"
[formGroup]="form"
(componentsCreated)="onReady($event)">
</ng-container>
</form>
`,
})
export class DynamicFormComponent {
private readonly fb = inject(NonNullableFormBuilder);
form = this.fb.group({
fullName: this.fb.control('', { validators: [Validators.required] }),
category: this.fb.control(null),
});
fields: FieldMetadata[] = [
{
name: 'fullName',
label: 'Nome',
controlType: FieldControlType.INPUT,
placeholder: 'Seu nome completo',
required: true,
},
{
name: 'category',
label: 'Categoria',
controlType: FieldControlType.SELECT,
options: [
{ label: 'A', value: 'A' },
{ label: 'B', value: 'B' },
],
multiple: false,
searchable: true,
},
];
onReady(map: Map<string, any>) {
// Recebe referências dos componentes criados (opcional)
console.log('components', Array.from(map.keys()));
}
}
Template-only:
<ng-container dynamicFieldLoader [fields]="fields" [formGroup]="form"></ng-container>
import { ComponentRegistryService } from "@praxisui/dynamic-fields";
import { FieldControlType } from "@praxisui/core";
@Component({
selector: "app-dynamic-form",
template: `<ng-container #dynamicContainer></ng-container>`,
})
export class DynamicFormComponent {
@ViewChild("dynamicContainer", { read: ViewContainerRef })
container!: ViewContainerRef;
constructor(private registry: ComponentRegistryService) {}
async loadField(type: FieldControlType) {
const component = await this.registry.getComponent(type);
if (component) {
this.container.createComponent(component);
}
}
// Exemplo prático
async loadInputField() {
await this.loadField(FieldControlType.INPUT);
}
async loadDatePicker() {
await this.loadField(FieldControlType.DATE_PICKER);
}
async loadColorPicker() {
await this.loadField(FieldControlType.COLOR_PICKER);
}
}
import { FieldControlType } from "@praxisui/core";
// Registrar componente customizado - SUPER SIMPLES!
registry.register("customField" as FieldControlType, () => import("./custom-field.component").then((m) => m.CustomFieldComponent));
// Uso posterior
const customComponent = await registry.getComponent("customField" as FieldControlType);
const stats = registry.getStats();
console.log(stats);
// {
// registeredComponents: 7,
// cachedComponents: 3,
// registeredTypes: ['input', 'select', ...]
// }
Exportados principais:
DynamicFieldLoaderDirectiveComponentRegistryServiceSimpleBaseInputComponent, SimpleBaseSelectComponent, SimpleBaseButtonComponentMaterialSelectComponent, MaterialRadioGroupComponent, MaterialCheckboxGroupComponent, MaterialDatepickerComponent, MaterialSliderComponent, MaterialTimepickerComponent, MaterialTextareaComponent, MaterialAutocompleteComponent, MaterialChipsComponent, MaterialButtonComponent, MaterialFileUploadComponentReferencie src/public-api.ts do pacote para a lista completa de símbolos exportados.
register<T>(type, factory) - Registra componente (ultra-simples!)getComponent<T>(type) - Obtém componente (async)isRegistered(type) - Verifica se está registradogetRegisteredTypes() - Lista tipos registradosgetStats() - Estatísticas do registroclearCache(type?) - Limpa cacheunregister(type) - Remove componentepreload(types[]) - Pré-carrega componentesinterface RegistryStats {
registeredComponents: number;
cachedComponents: number;
registeredTypes: FieldControlType[];
}
interface ComponentRegistration {
factory: () => Promise<Type<any>>;
cached?: Type<any>;
}
Esta biblioteca usa os tipos e metadados do @praxisui/core:
FieldControlType - Tipos de controle unificadosUnifiedFieldMetadata - Sistema de metadados corporativoMaterialInputMetadata, MaterialSelectMetadata, etc. - Metadados específicos# Build da biblioteca
ng build praxis-dynamic-fields
# Testes
ng test praxis-dynamic-fields
# Lint
ng lint praxis-dynamic-fields
Versão atual: Sistema simplificado pós-refatoração
Dependências: @praxisui/core, @angular/material
Angular: 20+
TypeScript: 5.8+
Sistema desenvolvido seguindo diretrizes de simplicidade e foco no essencial.
Aplicações host podem registrar componentes próprios para uso no DynamicFieldLoader e expor metadados para título/ícone amigáveis no editor.
Use ENVIRONMENT_INITIALIZER para registrar o componente no ComponentRegistryService durante o bootstrap do app:
import { ApplicationConfig, ENVIRONMENT_INITIALIZER } from '@angular/core';
import { ComponentRegistryService } from '@praxisui/dynamic-fields';
import { FieldControlType } from '@praxisui/core';
export const appConfig: ApplicationConfig = {
providers: [
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory: (registry: ComponentRegistryService) => () => {
// "my-custom" será usado como controlType no metadata do formulário
registry.register('my-custom' as FieldControlType, () =>
import('./components/my-custom.component').then((m) => m.MyCustomComponent),
);
},
deps: [ComponentRegistryService],
},
],
};
Observações de integração com o DynamicFieldLoader:
setInputMetadata(metadata) ou exponha um signal metadata (WritableSignal) e use .set(metadata).formControl com .set(control) ou implemente setExternalControl(control); alternativamente implemente corretamente ControlValueAccessor e faça [formControl] no template para evitar NG01203.[readonlyMode], [disabledMode], [visible], [presentationMode] para integração com o shell/canvas.Registre ComponentDocMeta para que o editor de campos use nome/ícone do seu componente:
import { ApplicationConfig, ENVIRONMENT_INITIALIZER } from '@angular/core';
import { ComponentDocMeta, ComponentMetadataRegistry } from '@praxisui/core';
import { MyCustomComponent } from './components/my-custom.component';
const MY_CUSTOM_METADATA: ComponentDocMeta = {
id: 'my-custom',
selector: 'my-custom',
component: MyCustomComponent,
friendlyName: 'Meu Componente',
description: 'Componente custom do app host',
icon: 'bolt',
lib: 'app-host',
};
export const appConfig: ApplicationConfig = {
providers: [
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory: (registry: ComponentMetadataRegistry) => () => {
registry.register(MY_CUSTOM_METADATA);
},
deps: [ComponentMetadataRegistry],
},
],
};
Por que isso importa?
"<Friendly Type> — <Label>" e resolve o ícone via ComponentMetadataRegistry. Se controlType do seu campo for igual ao id do metadata (ex.: 'my-custom'), o Dynamic Form usará diretamente os valores do registry.Defina o controlType do campo como o id registrado:
const field: FieldMetadata = {
name: 'customField',
label: 'Meu Campo',
controlType: 'my-custom', // corresponde ao id do metadata e ao registro do runtime
};
ControlValueAccessor ou liga [formControl] a um controle nativo (evita NG01203).setInputMetadata ou signal metadata com .set(...) para hot updates.[readonlyMode], [disabledMode], [visible], [presentationMode].controlType do campo coincide com o id do ComponentDocMeta (para resolver título/ícone no editor).FAQs
Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.
The npm package @praxisui/dynamic-fields receives a total of 557 weekly downloads. As such, @praxisui/dynamic-fields popularity was classified as not popular.
We found that @praxisui/dynamic-fields demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.