
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/manual-form
Advanced tools
Manual form toolkit for Praxis UI: container, instance factory and editor bridge for @praxisui/* fields.
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.npm install @praxisui/manual-form
Peers necessários (instale no app host):
@angular/core ^20.1.0, @angular/common ^20.1.0@praxisui/core (ConfigStorage, GenericCrudService, ícones)@praxisui/dynamic-fields (componentes de campo pdx-*)@praxisui/settings-panel (integração com painel de configurações)@praxisui/metadata-editor (edição visual de campos, opcional)Montar formulários Praxis manualmente (usando <pdx-*>) exigia montar FormConfig, FormGroup, persistência e metadados manualmente. Isso gerava atrito para hosts e dificultava a evolução.
Criamos a biblioteca @praxisui/manual-form com:
FieldMetadata, cria o FormGroup, mantém hot update e persiste via ManualFormInstance. Aceita inputs formId, formTitle, actions, enableAutoSave etc.createManualFormSeed, saveDraft, resetToSeed).submit/cancel/reset/custom).@praxisui/metadata-editor, aplica patches e garante persistência via ManualFormInstance.O exemplo /cargos/manual-form demonstra uso declarativo:
<praxis-manual-form formId="cargo">
<pdx-text-input formControlName="nome" label="Nome" required></pdx-text-input>
<pdx-material-currency formControlName="salario" label="Salário"></pdx-material-currency>
</praxis-manual-form>
Use o ManualFieldMetadataBridgeService para abrir o editor visual a partir de qualquer campo detectado pelo container. O serviço carrega o módulo sob demanda, aplica o patch retornado e chama saveDraft() para persistir as alterações no runtime.
@Component({
/* ... */
})
export class CargoManualFormComponent {
@ViewChild(ManualFormComponent) manualForm?: ManualFormComponent;
constructor(private readonly metadataBridge: ManualFieldMetadataBridgeService) {}
openFieldEditor(fieldName: string): void {
const instance = this.manualForm?.instance;
if (!instance) {
return;
}
void this.metadataBridge.openEditor(instance, fieldName);
}
}
selector/constructor → FieldControlType), infere label, validators.required.ManualFormInstance/ConfigStorage).FormActionsLayout (normalizado por DEFAULT_ACTIONS).ensureIds.enableAutoSave + autoSaveDebounceMs).@Input() sections ou layoutConfig.projects/praxis-manual-form e atualize demos (ex. /src/app/features/cargo-manual-form).ng-packagr, confirme que libs referenciadas (@praxisui/core, @praxisui/dynamic-fields) estão construídas ou apontam para dist/.FieldMetadata e use helpers (ensureIds, deepClone).metadata, readonlyMode, etc.).Essa base permite que hosts manualmente criem formulários com componentes Praxis, mantendo compatibilidade com o restante do ecossistema (persistência, metadados e editor).
FormGroup tipado e passá‑lo via [formGroup]. O container adota esse grupo, aplica metadados/validators e evita interceptações internas. Isso habilita o Angular Language Service a validar formControlName e melhora a DX.[formGroup] for informado, o container cria e gerencia um FormGroup interno (útil para PoCs), sem garantia de validação estática de nomes.@Input() usePathNames: boolean (padrão: false)
FormControlName.path (segmentos unidos por .) como FieldMetadata.name. Requer suporte a grupos aninhados — já implementado em DynamicFormService.MANUAL_FORM_SELECTOR_TO_CONTROL_TYPE e MANUAL_FORM_CONSTRUCTOR_TO_CONTROL_TYPE permitem sobrescrever o mapa padrão de seletores/constructors → FieldControlType.@Input() enableAutoSave: boolean (padrão: true) e @Input() autoSaveDebounceMs: number (padrão: 800).Em SSR, localStorage não existe. Como praxis-manual-form apenas depende do token CONFIG_STORAGE, você pode prover uma implementação segura no servidor (ex.: in‑memory) e manter LocalStorageConfigService no browser.
Exemplo (Angular com app.config.server.ts):
// app.config.server.ts
import { ApplicationConfig, PLATFORM_ID, inject, isPlatformServer } from '@angular/core';
import { CONFIG_STORAGE, LocalStorageConfigService, type ConfigStorage } from '@praxisui/core';
class MemoryConfigStorage implements ConfigStorage {
private readonly map = new Map<string, any>();
loadConfig<T>(key: string): T | null { return (this.map.get(key) as T) ?? null; }
saveConfig<T>(key: string, config: T): void { this.map.set(key, config); }
clearConfig(key: string): void { this.map.delete(key); }
}
export const appConfig: ApplicationConfig = {
providers: [
{
provide: CONFIG_STORAGE,
useFactory: () => isPlatformServer(inject(PLATFORM_ID))
? new MemoryConfigStorage()
: inject(LocalStorageConfigService),
},
],
};
Alternativas no servidor: usar cookies, cache distribuído (ex.: Redis) ou persistir por sessão do usuário. Basta implementar a interface ConfigStorage.
<form [formGroup]="form">
<praxis-manual-form formId="nested" [usePathNames]="true">
<div formGroupName="endereco">
<pdx-text-input formControlName="logradouro" label="Logradouro"></pdx-text-input>
<pdx-text-input formControlName="numero" label="Número"></pdx-text-input>
</div>
</praxis-manual-form>
</form>
Com usePathNames=true, os metadados serão gerados com nomes endereco.logradouro e endereco.numero, mantendo o FormGroup aninhado do host.
Use esta biblioteca quando:
Prefira o formulário totalmente dinâmico (JSON com @praxisui/dynamic-form) quando:
// component.ts
@Component({ /* … */ })
export class MinhaPagina {
private readonly fb = inject(FormBuilder);
readonly form = this.fb.group({
nome: this.fb.control('', { nonNullable: true, validators: [Validators.required] }),
endereco: this.fb.group({ logradouro: this.fb.control('', { nonNullable: true }) }),
});
}
<praxis-manual-form
[formGroup]="form"
formId="meu-form"
[usePathNames]="true"
formTitle="Cadastro"
(submitted)="onSubmit($event)"
>
<pdx-text-input formControlName="nome" label="Nome"></pdx-text-input>
<div formGroupName="endereco">
<pdx-text-input formControlName="logradouro" label="Logradouro"></pdx-text-input>
</div>
</praxis-manual-form>
Observações importantes:
[formGroup] diretamente no seletor <praxis-manual-form> (no host).<form [formGroup]> externo; não há necessidade e pode causar forms aninhados.Modo dinâmico (sem host tipado):
[formGroup] é informado no host, o container renderiza internamente um <form [formGroup]="formGroup"> para atender o Angular Forms e evitar o erro NG01050.Inputs (sinais):
formId: string (obrigatório)formTitle?: string, formDescription?: stringactions?: FormActionsLayout | nullshowHeader = true, showActions = trueenableAutoSave = true, autoSaveDebounceMs = 800editModeEnabled = false (habilita ações de customização — ex.: abrir editor por duplo clique)persistenceOptions?: { namespace?, tenantId?, profileId?, locale? }usePathNames = false (usa FormControlName.path como nome do campo)Outputs (sinais):
submitted({ value, instance }), saved(instance), reset(instance)metadataChange(FormConfig)Métodos públicos:
tryOpenFieldEditor(fieldName: string): tenta abrir o editor do campo, respeitando editModeEnabled (no‑op quando false).<praxis-manual-form-header>: recebe instance, title, description, saveLabel, resetLabel e emite save/reset.editModeEnabled está ativo no container, o header exibe um botão “Editar formulário” que emite editForm; o container trata esse evento chamando openFormEditor().<praxis-manual-form-actions>: recebe actions: FormActionsLayout, emite actionClick e aceita trackByFn opcional para listas grandes.@ViewChild(ManualFormComponent) manual?: ManualFormComponent;
constructor(private readonly bridge: ManualFieldMetadataBridgeService) {}
openEditor(fieldName: string) {
const inst = this.manual?.instance; if (!inst) return;
this.bridge.openEditor(inst, fieldName).catch(console.error);
}
Integração com Settings Panel: o ManualFormComponent utiliza SettingsPanelService para abrir o editor do formulário (lista de campos e flags) quando editModeEnabled está ativo. É possível abrir programaticamente via manualForm.openFormEditor().
Para espelhar o comportamento das demais libs (permitir edição apenas quando o modo de edição está ativo), use o input editModeEnabled no container e a diretiva pdxManualEdit nos campos:
<praxis-manual-form formId="cargo" [editModeEnabled]="custom.enabled()">
<pdx-text-input formControlName="nome" label="Nome" pdxManualEdit="nome"></pdx-text-input>
<pdx-material-currency formControlName="salario" label="Salário" pdxManualEdit="salario"></pdx-material-currency>
</praxis-manual-form>
A diretiva chama manualForm.tryOpenFieldEditor(fieldName) e respeita editModeEnabled, de modo que o duplo clique só abre o editor quando a edição está ligada.
O ManualFormComponent expõe openFormEditor() para abrir um editor simples do formulário que lista todos os campos e permite alternar: visibilidade (mostrar/ocultar), obrigatório, somente leitura e desabilitado — facilitando encontrar campos ocultos e reexibi‑los, além de ajustes rápidos. O editor respeita editModeEnabled e usa o SettingsPanelService.
Exemplo de uso no host:
<button *ngIf="custom.enabled()" type="button" (click)="manualForm?.openFormEditor()">Editar formulário</button>
<praxis-manual-form #manualForm [formGroup]="form" formId="'cargo'" [editModeEnabled]="custom.enabled()">
<!-- campos -->
</praxis-manual-form>
FieldControlType via tokens:
MANUAL_FORM_SELECTOR_TO_CONTROL_TYPEMANUAL_FORM_CONSTRUCTOR_TO_CONTROL_TYPE<ng-container *praxisManualField="'nome'; praxisManualFieldInstance: manual.instance as ctx">
Label atual: {{ ctx?.label }}
</ng-container>
pdxManualEdit)editModeEnabled do ManualFormComponent.<praxis-manual-form>.<praxis-manual-form formId="cargo" [editModeEnabled]="custom.enabled()">
<pdx-text-input formControlName="nome" label="Nome" pdxManualEdit="nome"></pdx-text-input>
</praxis-manual-form>
usePathNames=true para nested forms.CONFIG_STORAGE compatível (sem localStorage).Apache-2.0 — consulte LICENSE neste pacote ou no repositório raiz.
[formGroup] não habilita validação estática de formControlName no IDE.FAQs
Manual form toolkit for Praxis UI: container, instance factory and editor bridge for @praxisui/* fields.
We found that @praxisui/manual-form 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.