New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@praxisui/dynamic-fields

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@praxisui/dynamic-fields

Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.

latest
Source
npmnpm
Version
1.0.0-beta.28
Version published
Weekly downloads
608
-63.74%
Maintainers
1
Weekly downloads
 
Created
Source

@praxisui/dynamic-fields — Dynamic Form Fields

🔰 Exemplos / Quickstart

Para ver esta biblioteca em funcionamento em uma aplicação completa, utilize o projeto de exemplo (Quickstart):

  • Repositório: https://github.com/codexrodrigues/praxis-ui-quickstart
  • O Quickstart demonstra a integração das bibliotecas @praxisui/* em um app Angular, incluindo instalação, configuração e uso em telas reais.

Concept Usage

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.

Instalação

npm install @praxisui/dynamic-fields

Estilos e tokens (opcional)

  • Largura dos campos: quando o host usa providePraxisDynamicFields(), a lib injeta um estilo escopado que garante mat-form-field { width: 100% } dentro dos componentes. Não é necessário repetir no app.
  • Gradiente de inputs/toolbar (se desejar): o host pode definir um gradiente de marca que alguns detalhes visuais consomem (ex.: inputs com gradiente configurado e toolbars de edição):
: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.0
  • rxjs ^7.8.0
  • @praxisui/core, @praxisui/specification-core
  • Opcional conforme uso: @praxisui/dialog, @praxisui/cron-builder

✨ Características

  • Registro Simplificado: Sistema de registro de componentes focado no essencial
  • Lazy Loading: Carregamento sob demanda com cache inteligente
  • Material Design: Componentes baseados no Angular Material
  • Color Picker: Novo componente de seleção de cores com suporte a paleta e canvas
  • Novos Componentes: Toggle, Slider, Time Picker e Rating
  • Material Select Modular: Fragmentado em subcomponentes (SearchInput, OptionsList e Chips)
  • TypeScript: Totalmente tipado com integração do @praxisui/core
  • Corporativo: Adequado para cenários empresariais

🏗️ Arquitetura

Sistema de Registro

import { 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);

Componentes Suportados

O sistema usa as constantes do @praxisui/core para garantir consistência:

  • FieldControlType.INPUT - Campo de texto Material Design
  • FieldControlType.TEXTAREA - Área de texto Material Design
  • FieldControlType.SELECT - Campo de seleção Material Design
  • FieldControlType.CHECKBOX - Caixa de seleção Material Design
  • FieldControlType.RADIO - Botão de rádio Material Design
  • FieldControlType.DATE_PICKER - Seletor de data Material Design
  • FieldControlType.EMAIL_INPUT - Campo de email
  • FieldControlType.PASSWORD - Campo de senha
  • FieldControlType.CURRENCY_INPUT - Campo monetário
  • FieldControlType.NUMERIC_TEXT_BOX - Campo numérico
  • FieldControlType.MULTI_SELECT - Seleção múltipla
  • FieldControlType.AUTO_COMPLETE - Auto completar (busca habilitada por padrão)
  • FieldControlType.DATE_TIME_PICKER - Data e hora
  • FieldControlType.DATE_RANGE - Intervalo de datas
  • FieldControlType.FILE_UPLOAD - Upload de arquivos
  • FieldControlType.TOGGLE - Interruptor Material Design
  • FieldControlType.SLIDER - Slider Material Design
  • FieldControlType.TIME_PICKER - Seletor de horário
  • FieldControlType.RATING - Classificação por estrelas
  • FieldControlType.COLOR_PICKER - Seletor de cores
  • FieldControlType.AVATAR - Avatar visual (imagem/ícone/iniciais)

Campos com FieldControlType.AUTO_COMPLETE utilizam internamente o MaterialSearchableSelectComponent, habilitando busca automaticamente.

🧩 MaterialSelectComponent

O MaterialSelectComponent agora está dividido em subcomponentes menores para facilitar manutenção e testes:

  • SelectSearchInputComponent - Campo de busca opcional exibido dentro do painel.
  • SelectOptionsListComponent - Lista de opções com suporte a grupos e virtualização.
  • SelectChipsComponent - Exibe as opções selecionadas como chips quando multipleDisplay é "chips".

Esses subcomponentes são utilizados internamente pelo select e não exigem alterações na utilização normal do componente.

🧩 MaterialCheckboxGroupComponent

Renderiza uma lista de checkboxes conectada ao @angular/forms, permitindo a seleção de múltiplos valores.

  • Select All: opção para marcar todas as entradas habilitadas.
  • maxSelections: limita o número de escolhas possíveis.
  • Carregamento Remoto: aceita resourcePath, optionLabelKey e optionValueKey para popular opções via API.
  • Layout: suporta labelPosition e color conforme documentação do Angular Material.

🧩 MaterialRadioGroupComponent

Grupo de botões de rádio que consome metadados ou dados remotos para criar seleções exclusivas.

  • Seleção Única: utiliza MatRadioGroup para garantir apenas um valor ativo.
  • Carregamento Dinâmico: mesmas chaves de configuração de MaterialSelectComponent para buscar opções.
  • Layout Flexível: configuração de orientação, labelPosition e color segundo a documentação oficial.

🧩 Avatar Field

Componente visual para exibir representação de usuário/entidade/estado, com prioridade de conteúdo:

  • imageSrc > icon > initials > ng-content

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]

📦 Instalação

npm install @praxisui/dynamic-fields

🚀 Uso Básico (DynamicFieldLoaderDirective)

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);
  }
}

🔧 Registrar Componente Customizado

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);

📊 Estatísticas

const stats = registry.getStats();
console.log(stats);
// {
//   registeredComponents: 7,
//   cachedComponents: 3,
//   registeredTypes: ['input', 'select', ...]
// }

🛠️ API (Pontos de Entrada)

Exportados principais:

  • Diretivas: DynamicFieldLoaderDirective
  • Serviços: ComponentRegistryService
  • Base: SimpleBaseInputComponent, SimpleBaseSelectComponent, SimpleBaseButtonComponent
  • Componentes Material (exemplos): MaterialSelectComponent, MaterialRadioGroupComponent, MaterialCheckboxGroupComponent, MaterialDatepickerComponent, MaterialSliderComponent, MaterialTimepickerComponent, MaterialTextareaComponent, MaterialAutocompleteComponent, MaterialChipsComponent, MaterialButtonComponent, MaterialFileUploadComponent

Referencie src/public-api.ts do pacote para a lista completa de símbolos exportados.

ComponentRegistryService

Métodos Principais

  • register<T>(type, factory) - Registra componente (ultra-simples!)
  • getComponent<T>(type) - Obtém componente (async)
  • isRegistered(type) - Verifica se está registrado
  • getRegisteredTypes() - Lista tipos registrados

Métodos Utilitários

  • getStats() - Estatísticas do registro
  • clearCache(type?) - Limpa cache
  • unregister(type) - Remove componente
  • preload(types[]) - Pré-carrega componentes

Interfaces

interface RegistryStats {
  registeredComponents: number;
  cachedComponents: number;
  registeredTypes: FieldControlType[];
}

interface ComponentRegistration {
  factory: () => Promise<Type<any>>;
  cached?: Type<any>;
}

🎯 Integração com @praxisui/core

Esta biblioteca usa os tipos e metadados do @praxisui/core:

  • FieldControlType - Tipos de controle unificados
  • UnifiedFieldMetadata - Sistema de metadados corporativo
  • MaterialInputMetadata, MaterialSelectMetadata, etc. - Metadados específicos

📋 Desenvolvimento

# Build da biblioteca
ng build praxis-dynamic-fields

# Testes
ng test praxis-dynamic-fields

# Lint
ng lint praxis-dynamic-fields

🏷️ Versão

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.

🔌 Extensão pelo App Host (registrando seu próprio componente)

Aplicações host podem registrar componentes próprios para uso no DynamicFieldLoader e expor metadados para título/ícone amigáveis no editor.

1) Registrar o componente no runtime (DynamicFieldLoader)

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:

  • Metadados: implemente setInputMetadata(metadata) ou exponha um signal metadata (WritableSignal) e use .set(metadata).
  • FormControl: exponha um signal formControl com .set(control) ou implemente setExternalControl(control); alternativamente implemente corretamente ControlValueAccessor e faça [formControl] no template para evitar NG01203.
  • Flags globais (opcional): suporte [readonlyMode], [disabledMode], [visible], [presentationMode] para integração com o shell/canvas.

2) Registrar metadados para título/ícone amigáveis (ComponentMetadataRegistry)

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?

  • O editor “Configurar campo” compõe o título como "<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.

3) Usar no formulário dinâmico

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
};

✅ Checklist de Compatibilidade

  • Implementa ControlValueAccessor ou liga [formControl] a um controle nativo (evita NG01203).
  • Suporta setInputMetadata ou signal metadata com .set(...) para hot updates.
  • Opcional: aceita [readonlyMode], [disabledMode], [visible], [presentationMode].
  • O controlType do campo coincide com o id do ComponentDocMeta (para resolver título/ícone no editor).

Keywords

angular

FAQs

Package last updated on 07 Nov 2025

Did you know?

Socket

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.

Install

Related posts