mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
8.9 KiB
319 lines
8.9 KiB
/**
|
|
* @license Angular v21.1.1
|
|
* (c) 2010-2026 Google LLC. https://angular.dev/
|
|
* License: MIT
|
|
*/
|
|
|
|
import { FieldNode, getInjectorFromOptions, FieldNodeState, FieldNodeStructure, calculateValidationSelfStatus, BasicFieldAdapter, form, normalizeFormArgs } from './_structure-chunk.mjs';
|
|
import { linkedSignal, untracked, runInInjectionContext, computed, signal, ɵRuntimeError as _RuntimeError } from '@angular/core';
|
|
import { FormGroup, FormArray, AbstractControl } from '@angular/forms';
|
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
import { ReplaySubject } from 'rxjs';
|
|
import { map, takeUntil } from 'rxjs/operators';
|
|
import '@angular/core/primitives/signals';
|
|
|
|
class CompatFieldNode extends FieldNode {
|
|
options;
|
|
control;
|
|
constructor(options) {
|
|
super(options);
|
|
this.options = options;
|
|
this.control = this.options.control;
|
|
}
|
|
}
|
|
function makeCreateDestroySubject() {
|
|
let destroy$ = new ReplaySubject(1);
|
|
return () => {
|
|
if (destroy$) {
|
|
destroy$.next();
|
|
destroy$.complete();
|
|
}
|
|
return destroy$ = new ReplaySubject(1);
|
|
};
|
|
}
|
|
function extractControlPropToSignal(options, makeSignal) {
|
|
const injector = getInjectorFromOptions(options);
|
|
const createDestroySubject = makeCreateDestroySubject();
|
|
const signalOfControlSignal = linkedSignal({
|
|
...(ngDevMode ? {
|
|
debugName: "signalOfControlSignal"
|
|
} : {}),
|
|
source: options.control,
|
|
computation: control => {
|
|
return untracked(() => {
|
|
return runInInjectionContext(injector, () => makeSignal(control, createDestroySubject()));
|
|
});
|
|
}
|
|
});
|
|
return computed(() => signalOfControlSignal()());
|
|
}
|
|
const getControlStatusSignal = (options, getValue) => {
|
|
return extractControlPropToSignal(options, (c, destroy$) => toSignal(c.statusChanges.pipe(map(() => getValue(c)), takeUntil(destroy$)), {
|
|
initialValue: getValue(c)
|
|
}));
|
|
};
|
|
const getControlEventsSignal = (options, getValue) => {
|
|
return extractControlPropToSignal(options, (c, destroy$) => toSignal(c.events.pipe(map(() => {
|
|
return getValue(c);
|
|
}), takeUntil(destroy$)), {
|
|
initialValue: getValue(c)
|
|
}));
|
|
};
|
|
|
|
class CompatNodeState extends FieldNodeState {
|
|
compatNode;
|
|
touched;
|
|
dirty;
|
|
disabled;
|
|
control;
|
|
constructor(compatNode, options) {
|
|
super(compatNode);
|
|
this.compatNode = compatNode;
|
|
this.control = options.control;
|
|
this.touched = getControlEventsSignal(options, c => c.touched);
|
|
this.dirty = getControlEventsSignal(options, c => c.dirty);
|
|
const controlDisabled = getControlStatusSignal(options, c => c.disabled);
|
|
this.disabled = computed(() => {
|
|
return controlDisabled() || this.disabledReasons().length > 0;
|
|
}, ...(ngDevMode ? [{
|
|
debugName: "disabled"
|
|
}] : []));
|
|
}
|
|
markAsDirty() {
|
|
this.control().markAsDirty();
|
|
}
|
|
markAsTouched() {
|
|
this.control().markAsTouched();
|
|
}
|
|
markAsPristine() {
|
|
this.control().markAsPristine();
|
|
}
|
|
markAsUntouched() {
|
|
this.control().markAsUntouched();
|
|
}
|
|
}
|
|
|
|
function getParentFromOptions(options) {
|
|
if (options.kind === 'root') {
|
|
return undefined;
|
|
}
|
|
return options.parent;
|
|
}
|
|
function getFieldManagerFromOptions(options) {
|
|
if (options.kind === 'root') {
|
|
return options.fieldManager;
|
|
}
|
|
return options.parent.structure.root.structure.fieldManager;
|
|
}
|
|
function getControlValueSignal(options) {
|
|
const value = extractControlPropToSignal(options, (control, destroy$) => {
|
|
return toSignal(control.valueChanges.pipe(map(() => control.getRawValue()), takeUntil(destroy$)), {
|
|
initialValue: control.getRawValue()
|
|
});
|
|
});
|
|
value.set = value => {
|
|
options.control().setValue(value);
|
|
};
|
|
value.update = fn => {
|
|
value.set(fn(value()));
|
|
};
|
|
return value;
|
|
}
|
|
class CompatStructure extends FieldNodeStructure {
|
|
value;
|
|
keyInParent;
|
|
root;
|
|
pathKeys;
|
|
children = signal([], ...(ngDevMode ? [{
|
|
debugName: "children"
|
|
}] : []));
|
|
childrenMap = computed(() => undefined, ...(ngDevMode ? [{
|
|
debugName: "childrenMap"
|
|
}] : []));
|
|
parent;
|
|
fieldManager;
|
|
constructor(node, options) {
|
|
super(options.logic, node, () => {
|
|
throw new _RuntimeError(1911, ngDevMode && `Compat nodes don't have children.`);
|
|
});
|
|
this.value = getControlValueSignal(options);
|
|
this.parent = getParentFromOptions(options);
|
|
this.root = this.parent?.structure.root ?? node;
|
|
this.fieldManager = getFieldManagerFromOptions(options);
|
|
const identityInParent = options.kind === 'child' ? options.identityInParent : undefined;
|
|
const initialKeyInParent = options.kind === 'child' ? options.initialKeyInParent : undefined;
|
|
this.keyInParent = this.createKeyInParent(options, identityInParent, initialKeyInParent);
|
|
this.pathKeys = computed(() => this.parent ? [...this.parent.structure.pathKeys(), this.keyInParent()] : [], ...(ngDevMode ? [{
|
|
debugName: "pathKeys"
|
|
}] : []));
|
|
}
|
|
getChild() {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
class CompatValidationError {
|
|
kind = 'compat';
|
|
control;
|
|
fieldTree;
|
|
context;
|
|
message;
|
|
constructor({
|
|
context,
|
|
kind,
|
|
control
|
|
}) {
|
|
this.context = context;
|
|
this.kind = kind;
|
|
this.control = control;
|
|
}
|
|
}
|
|
|
|
function reactiveErrorsToSignalErrors(errors, control) {
|
|
if (errors === null) {
|
|
return [];
|
|
}
|
|
return Object.entries(errors).map(([kind, context]) => {
|
|
return new CompatValidationError({
|
|
context,
|
|
kind,
|
|
control
|
|
});
|
|
});
|
|
}
|
|
function extractNestedReactiveErrors(control) {
|
|
const errors = [];
|
|
if (control.errors) {
|
|
errors.push(...reactiveErrorsToSignalErrors(control.errors, control));
|
|
}
|
|
if (control instanceof FormGroup || control instanceof FormArray) {
|
|
for (const c of Object.values(control.controls)) {
|
|
errors.push(...extractNestedReactiveErrors(c));
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
const EMPTY_ARRAY_SIGNAL = computed(() => [], ...(ngDevMode ? [{
|
|
debugName: "EMPTY_ARRAY_SIGNAL"
|
|
}] : []));
|
|
const TRUE_SIGNAL = computed(() => true, ...(ngDevMode ? [{
|
|
debugName: "TRUE_SIGNAL"
|
|
}] : []));
|
|
class CompatValidationState {
|
|
syncValid;
|
|
errors;
|
|
pending;
|
|
invalid;
|
|
valid;
|
|
constructor(options) {
|
|
this.syncValid = getControlStatusSignal(options, c => c.status === 'VALID');
|
|
this.errors = getControlStatusSignal(options, extractNestedReactiveErrors);
|
|
this.pending = getControlStatusSignal(options, c => c.pending);
|
|
this.valid = getControlStatusSignal(options, c => {
|
|
return c.valid;
|
|
});
|
|
this.invalid = getControlStatusSignal(options, c => {
|
|
return c.invalid;
|
|
});
|
|
}
|
|
asyncErrors = EMPTY_ARRAY_SIGNAL;
|
|
errorSummary = EMPTY_ARRAY_SIGNAL;
|
|
rawSyncTreeErrors = EMPTY_ARRAY_SIGNAL;
|
|
syncErrors = EMPTY_ARRAY_SIGNAL;
|
|
rawAsyncErrors = EMPTY_ARRAY_SIGNAL;
|
|
shouldSkipValidation = TRUE_SIGNAL;
|
|
status = computed(() => {
|
|
return calculateValidationSelfStatus(this);
|
|
}, ...(ngDevMode ? [{
|
|
debugName: "status"
|
|
}] : []));
|
|
}
|
|
|
|
class CompatFieldAdapter {
|
|
basicAdapter = new BasicFieldAdapter();
|
|
newRoot(fieldManager, value, pathNode, adapter) {
|
|
if (value() instanceof AbstractControl) {
|
|
return createCompatNode({
|
|
kind: 'root',
|
|
fieldManager,
|
|
value,
|
|
pathNode,
|
|
logic: pathNode.builder.build(),
|
|
fieldAdapter: adapter
|
|
});
|
|
}
|
|
return this.basicAdapter.newRoot(fieldManager, value, pathNode, adapter);
|
|
}
|
|
createNodeState(node, options) {
|
|
if (!options.control) {
|
|
return this.basicAdapter.createNodeState(node);
|
|
}
|
|
return new CompatNodeState(node, options);
|
|
}
|
|
createStructure(node, options) {
|
|
if (!options.control) {
|
|
return this.basicAdapter.createStructure(node, options);
|
|
}
|
|
return new CompatStructure(node, options);
|
|
}
|
|
createValidationState(node, options) {
|
|
if (!options.control) {
|
|
return this.basicAdapter.createValidationState(node);
|
|
}
|
|
return new CompatValidationState(options);
|
|
}
|
|
newChild(options) {
|
|
const value = options.parent.value()[options.initialKeyInParent];
|
|
if (value instanceof AbstractControl) {
|
|
return createCompatNode(options);
|
|
}
|
|
return new FieldNode(options);
|
|
}
|
|
}
|
|
function createCompatNode(options) {
|
|
const control = options.kind === 'root' ? options.value : computed(() => {
|
|
return options.parent.value()[options.initialKeyInParent];
|
|
});
|
|
return new CompatFieldNode({
|
|
...options,
|
|
control
|
|
});
|
|
}
|
|
|
|
function compatForm(...args) {
|
|
const [model, maybeSchema, maybeOptions] = normalizeFormArgs(args);
|
|
const options = {
|
|
...maybeOptions,
|
|
adapter: new CompatFieldAdapter()
|
|
};
|
|
const schema = maybeSchema || (() => {});
|
|
return form(model, schema, options);
|
|
}
|
|
|
|
const NG_STATUS_CLASSES = {
|
|
'ng-touched': ({
|
|
state
|
|
}) => state().touched(),
|
|
'ng-untouched': ({
|
|
state
|
|
}) => !state().touched(),
|
|
'ng-dirty': ({
|
|
state
|
|
}) => state().dirty(),
|
|
'ng-pristine': ({
|
|
state
|
|
}) => !state().dirty(),
|
|
'ng-valid': ({
|
|
state
|
|
}) => state().valid(),
|
|
'ng-invalid': ({
|
|
state
|
|
}) => state().invalid(),
|
|
'ng-pending': ({
|
|
state
|
|
}) => state().pending()
|
|
};
|
|
|
|
export { CompatValidationError, NG_STATUS_CLASSES, compatForm };
|
|
//# sourceMappingURL=signals-compat.mjs.map
|
|
|