refactor: circular deps part 1

This commit is contained in:
Nathan Walker
2025-07-06 10:05:35 -07:00
parent 0fe60552a3
commit 84f5f1920d
14 changed files with 85 additions and 127 deletions

View File

@ -0,0 +1,19 @@
// Types shared between core-types and animation-interfaces
/**
* Defines a custom animation timing curve by using the cubic-bezier function.
* Possible values are numeric values from 0 to 1
*/
export class CubicBezierAnimationCurve {
public x1: number;
public y1: number;
public x2: number;
public y2: number;
constructor(x1: number, y1: number, x2: number, y2: number) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}

View File

@ -4,7 +4,7 @@
// imported for definition purposes only // imported for definition purposes only
import { makeValidator, makeParser } from '../ui/core/properties'; import { makeValidator, makeParser } from '../ui/core/properties';
import { CubicBezierAnimationCurve } from '../ui/animation/animation-interfaces'; import { CubicBezierAnimationCurve } from './animation-types';
export namespace CoreTypes { export namespace CoreTypes {
export type CSSWideKeywords = 'initial' | 'inherit' | 'unset' | 'revert'; export type CSSWideKeywords = 'initial' | 'inherit' | 'unset' | 'revert';

View File

@ -1,5 +1,5 @@
//Types //Types
import { DOMNode } from './dom-node'; import { DOMNode } from './dom-types';
export interface InspectorCommands { export interface InspectorCommands {
// DevTools -> Application communication. Methods that devtools calls when needed. // DevTools -> Application communication. Methods that devtools calls when needed.

View File

@ -2,7 +2,7 @@
import { ViewBase } from '../ui/core/view-base'; import { ViewBase } from '../ui/core/view-base';
//Requires //Requires
import { getNodeById } from './dom-node'; import { getNodeById } from './dom-types';
import { mainThreadify } from '../utils'; import { mainThreadify } from '../utils';
// Use lazy requires for core modules // Use lazy requires for core modules

View File

@ -3,7 +3,8 @@ import { InspectorEvents, InspectorCommands } from './devtools-elements-interfac
// Requires // Requires
import { getDocument, getComputedStylesForNode, removeNode, setAttributeAsText } from './devtools-elements.common'; import { getDocument, getComputedStylesForNode, removeNode, setAttributeAsText } from './devtools-elements.common';
import { registerInspectorEvents, DOMNode } from './dom-node'; import { registerInspectorEvents } from './dom-types';
import { DOMNode } from './dom-types';
export * from './devtools-elements-interfaces'; export * from './devtools-elements-interfaces';

View File

@ -1,27 +0,0 @@
import { ViewBase } from '../ui/core/view-base';
import { CSSComputedStyleProperty } from './css-agent';
export declare function getNodeById(id: number): DOMNode;
declare class WeakRef<T> {
constructor(obj: T);
get(): T;
clear(): void;
}
export declare class DOMNode {
nodeId: any;
nodeType: any;
nodeName: any;
localName: any;
nodeValue: string;
attributes: string[];
viewRef: WeakRef<ViewBase>;
constructor(view: ViewBase);
loadAttributes(): void;
readonly children: DOMNode[];
onChildAdded(childView: ViewBase): void;
onChildRemoved(view: ViewBase): void;
attributeModified(name: string, value: any): void;
attributeRemoved(name: string): void;
getComputedProperties(): CSSComputedStyleProperty[];
dispose(): void;
toJSON(): string;
}

View File

@ -1,28 +1,29 @@
import { CSSComputedStyleProperty } from './css-agent';
import { InspectorEvents } from './devtools-elements-interfaces'; import { InspectorEvents } from './devtools-elements-interfaces';
import { CSSComputedStyleProperty } from './css-agent';
// Needed for typings only
import { ViewBase } from '../ui/core/view-base'; import { ViewBase } from '../ui/core/view-base';
const registeredDomNodes = {};
const ELEMENT_NODE_TYPE = 1; const ELEMENT_NODE_TYPE = 1;
const ROOT_NODE_TYPE = 9; const ROOT_NODE_TYPE = 9;
const propertyBlacklist = ['effectivePaddingLeft', 'effectivePaddingBottom', 'effectivePaddingRight', 'effectivePaddingTop', 'effectiveBorderTopWidth', 'effectiveBorderRightWidth', 'effectiveBorderBottomWidth', 'effectiveBorderLeftWidth', 'effectiveMinWidth', 'effectiveMinHeight', 'effectiveWidth', 'effectiveHeight', 'effectiveMarginLeft', 'effectiveMarginTop', 'effectiveMarginRight', 'effectiveMarginBottom', 'nodeName', 'nodeType', 'decodeWidth', 'decodeHeight', 'ng-reflect-items', 'domNode', 'touchListenerIsSet', 'bindingContext', 'nativeView']; const propertyBlacklist = ['effectivePaddingLeft', 'effectivePaddingBottom', 'effectivePaddingRight', 'effectivePaddingTop', 'effectiveBorderTopWidth', 'effectiveBorderRightWidth', 'effectiveBorderBottomWidth', 'effectiveBorderLeftWidth', 'effectiveMinWidth', 'effectiveMinHeight', 'effectiveWidth', 'effectiveHeight', 'effectiveMarginLeft', 'effectiveMarginTop', 'effectiveMarginRight', 'effectiveMarginBottom', 'nodeName', 'nodeType', 'decodeWidth', 'decodeHeight', 'ng-reflect-items', 'domNode', 'touchListenerIsSet', 'bindingContext', 'nativeView'];
function lazy<T>(action: () => T): () => T { function lazy<T>(action: () => T): () => T {
let _value: T; let _value: T;
return () => _value || (_value = action()); return () => _value || (_value = action());
} }
const percentLengthToStringLazy = lazy<(length) => string>(() => require('../ui/styling/style-properties').PercentLength.convertToString); const percentLengthToStringLazy = lazy<(length) => string>(() => require('../ui/styling/style-properties').PercentLength.convertToString);
const getSetPropertiesLazy = lazy<(view: ViewBase) => [string, any][]>(() => require('../ui/core/properties').getSetProperties); const getSetPropertiesLazy = lazy<(view: ViewBase) => [string, any][]>(() => require('../ui/core/properties').getSetProperties);
const getComputedCssValuesLazy = lazy<(view: ViewBase) => [string, any][]>(() => require('../ui/core/properties').getComputedCssValues); const getComputedCssValuesLazy = lazy<(view: ViewBase) => [string, any][]>(() => require('../ui/core/properties').getComputedCssValues);
const registeredDomNodes = {};
export function getNodeById(id: number): DOMNode {
return registeredDomNodes[id];
}
let inspectorFrontendInstance: any;
export function registerInspectorEvents(inspector: InspectorEvents) { export function registerInspectorEvents(inspector: InspectorEvents) {
inspectorFrontendInstance = inspector; inspectorFrontendInstance = inspector;
} }
let inspectorFrontendInstance: any;
function notifyInspector(callback: (inspector: InspectorEvents) => void) { function notifyInspector(callback: (inspector: InspectorEvents) => void) {
if (inspectorFrontendInstance) { if (inspectorFrontendInstance) {
callback(inspectorFrontendInstance); callback(inspectorFrontendInstance);
@ -63,10 +64,6 @@ function unregisterNode(domNode: DOMNode) {
delete registeredDomNodes[domNode.nodeId]; delete registeredDomNodes[domNode.nodeId];
} }
export function getNodeById(id: number): DOMNode {
return registeredDomNodes[id];
}
export class DOMNode { export class DOMNode {
nodeId; nodeId;
nodeType; nodeType;

View File

@ -77,21 +77,3 @@ export interface IOSView extends View {
_resumePresentationLayerUpdates(); _resumePresentationLayerUpdates();
_isPresentationLayerUpdateSuspended(); _isPresentationLayerUpdateSuspended();
} }
/**
* Defines a custom animation timing curve by using the cubic-bezier function.
* Possible values are numeric values from 0 to 1
*/
export class CubicBezierAnimationCurve {
public x1: number;
public y1: number;
public x2: number;
public y2: number;
constructor(x1: number, y1: number, x2: number, y2: number) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}

View File

@ -1,6 +1,6 @@
import { AnimationDefinitionInternal, AnimationPromise, PropertyAnimation, AnimationBase, Properties } from './animation-common'; import { AnimationDefinitionInternal, AnimationPromise, PropertyAnimation, AnimationBase, Properties } from './animation-common';
import { View } from '../core/view'; import { View } from '../core/view';
import { CubicBezierAnimationCurve } from './animation-interfaces'; import { CubicBezierAnimationCurve } from '../../core-types/animation-types';
import { Color } from '../../color'; import { Color } from '../../color';
import { Trace } from '../../trace'; import { Trace } from '../../trace';
import { opacityProperty, backgroundColorProperty, rotateProperty, rotateXProperty, rotateYProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, heightProperty, widthProperty, PercentLength } from '../styling/style-properties'; import { opacityProperty, backgroundColorProperty, rotateProperty, rotateXProperty, rotateYProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, heightProperty, widthProperty, PercentLength } from '../styling/style-properties';

View File

@ -1,7 +1,7 @@
// Types // Types
import { AnimationDefinitionInternal, AnimationPromise, IOSView, PropertyAnimation, PropertyAnimationInfo, AnimationBase, Properties } from './animation-common'; import { AnimationDefinitionInternal, AnimationPromise, IOSView, PropertyAnimation, PropertyAnimationInfo, AnimationBase, Properties } from './animation-common';
import { View } from '../core/view'; import { View } from '../core/view';
import { CubicBezierAnimationCurve } from './animation-interfaces'; import { CubicBezierAnimationCurve } from '../../core-types/animation-types';
import { Trace } from '../../trace'; import { Trace } from '../../trace';
import { opacityProperty, backgroundColorProperty, rotateProperty, rotateXProperty, rotateYProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, heightProperty, widthProperty, PercentLength } from '../styling/style-properties'; import { opacityProperty, backgroundColorProperty, rotateProperty, rotateXProperty, rotateYProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, heightProperty, widthProperty, PercentLength } from '../styling/style-properties';
import { ios as iosBackground } from '../styling/background'; import { ios as iosBackground } from '../styling/background';

View File

@ -0,0 +1,40 @@
// Shared types/interfaces for bindable and view-base
/**
* The options object used in the Bindable.bind method.
*/
export interface BindingOptions {
/**
* The property name of the source object (typically the ViewModel) to bind to.
*/
sourceProperty: string;
/**
* The property name of the target object (that is the Bindable instance) to bind the source property to.
*/
targetProperty: string;
/**
* True to establish a two-way binding, false otherwise. A two-way binding will synchronize both the source and the target property values regardless of which one initiated the change.
*/
twoWay?: boolean;
/**
* An expression used for calculations (convertions) based on the value of the property.
*/
expression?: string;
}
/**
* An interface which defines methods need to create binding value converter.
*/
export interface ValueConverter {
/**
* A method that will be executed when a value (of the binding property) should be converted to the observable model.
* For example: user types in a text field, but our business logic requires to store data in a different manner (e.g. in lower case).
* @param params - An array of parameters where first element is the value of the property and next elements are parameters send to converter.
*/
toModel: (...params: any[]) => any;
/**
* A method that will be executed when a value should be converted to the UI view. For example we have a date object which should be displayed to the end user in a specific date format.
* @param params - An array of parameters where first element is the value of the property and next elements are parameters send to converter.
*/
toView: (...params: any[]) => any;
}

View File

@ -1,5 +1,6 @@
// Types // Types
import { ViewBase } from '../view-base'; import { ViewBase } from '../view-base';
import { BindingOptions, ValueConverter } from './bindable-types';
// Requires // Requires
import { unsetValue } from '../properties'; import { unsetValue } from '../properties';
@ -49,45 +50,6 @@ function getProperties(property: string): Array<string> {
return result; return result;
} }
/**
* The options object used in the Bindable.bind method.
*/
export interface BindingOptions {
/**
* The property name of the source object (typically the ViewModel) to bind to.
*/
sourceProperty: string;
/**
* The property name of the target object (that is the Bindable instance) to bind the source property to.
*/
targetProperty: string;
/**
* True to establish a two-way binding, false otherwise. A two-way binding will synchronize both the source and the target property values regardless of which one initiated the change.
*/
twoWay?: boolean;
/**
* An expression used for calculations (convertions) based on the value of the property.
*/
expression?: string;
}
/**
* An interface which defines methods need to create binding value converter.
*/
export interface ValueConverter {
/**
* A method that will be executed when a value (of the binding property) should be converted to the observable model.
* For example: user types in a text field, but our business logic requires to store data in a different manner (e.g. in lower case).
* @param params - An array of parameters where first element is the value of the property and next elements are parameters send to converter.
*/
toModel: (...params: any[]) => any;
/**
* A method that will be executed when a value should be converted to the UI view. For example we have a date object which should be displayed to the end user in a specific date format.
* @param params - An array of parameters where first element is the value of the property and next elements are parameters send to converter.
*/
toView: (...params: any[]) => any;
}
/** /**
* Normalizes "ontap" to "tap", and "ondoubletap" to "ondoubletap". * Normalizes "ontap" to "tap", and "ondoubletap" to "ondoubletap".
* *

View File

@ -4,7 +4,8 @@ import { CoreTypes } from '../../../core-types';
import { Property, CssProperty, CssAnimationProperty, InheritedProperty, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, initNativeView } from '../properties'; import { Property, CssProperty, CssAnimationProperty, InheritedProperty, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, initNativeView } from '../properties';
import { CSSUtils } from '../../../css/system-classes'; import { CSSUtils } from '../../../css/system-classes';
import { Source } from '../../../utils/debug'; import { Source } from '../../../utils/debug';
import { Binding, BindingOptions } from '../bindable'; import { Binding } from '../bindable';
import { BindingOptions } from '../bindable/bindable-types';
import { Trace } from '../../../trace'; import { Trace } from '../../../trace';
import { Observable, PropertyChangeData, WrappedValue } from '../../../data/observable'; import { Observable, PropertyChangeData, WrappedValue } from '../../../data/observable';
import { Style } from '../../styling/style'; import { Style } from '../../styling/style';
@ -16,25 +17,10 @@ import { getClass } from '../../../utils/types';
import { profile } from '../../../profiling'; import { profile } from '../../../profiling';
import * as dnm from '../../../debugger/dom-node'; import { DOMNode } from '../../../debugger/dom-types';
import * as ssm from '../../styling/style-scope'; import { applyInlineStyle, CssState, StyleScope } from '../../styling/style-scope';
import { ViewBase as ViewBaseDefinition } from '.'; import { ViewBase as ViewBaseDefinition } from '.';
let domNodeModule: typeof dnm;
function ensuredomNodeModule(): void {
if (!domNodeModule) {
domNodeModule = require('../../../debugger/dom-node');
}
}
let styleScopeModule: typeof ssm;
function ensureStyleScopeModule() {
if (!styleScopeModule) {
styleScopeModule = require('../../styling/style-scope');
}
}
const defaultBindingSource = {}; const defaultBindingSource = {};
export interface ModalTransitionType { export interface ModalTransitionType {
@ -355,7 +341,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
private __nativeView: any; private __nativeView: any;
// private _disableNativeViewRecycling: boolean; // private _disableNativeViewRecycling: boolean;
public domNode: dnm.DOMNode; public domNode: DOMNode;
public recycleNativeView: 'always' | 'never' | 'auto'; public recycleNativeView: 'always' | 'never' | 'auto';
/** /**
@ -422,8 +408,8 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
public _domId: number; public _domId: number;
public _context: any /* android.content.Context */; public _context: any /* android.content.Context */;
public _isAddedToNativeVisualTree: boolean; public _isAddedToNativeVisualTree: boolean;
/* "ui/styling/style-scope" */ public _cssState: ssm.CssState = new ssm.CssState(new WeakRef(this)); /* "ui/styling/style-scope" */ public _cssState: CssState = new CssState(new WeakRef(this));
public _styleScope: ssm.StyleScope; public _styleScope: StyleScope;
/** /**
* A property bag holding suspended native updates. * A property bag holding suspended native updates.
* Native setters that had to execute while there was no native view, * Native setters that had to execute while there was no native view,
@ -675,8 +661,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
*/ */
public ensureDomNode() { public ensureDomNode() {
if (!this.domNode) { if (!this.domNode) {
ensuredomNodeModule(); this.domNode = new DOMNode(this);
this.domNode = new domNodeModule.DOMNode(this);
} }
} }
@ -1406,8 +1391,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
throw new Error('Parameter should be valid CSS string!'); throw new Error('Parameter should be valid CSS string!');
} }
ensureStyleScopeModule(); applyInlineStyle(this, style, undefined);
styleScopeModule.applyInlineStyle(this, style, undefined);
} }
public _parentChanged(oldParent: ViewBase): void { public _parentChanged(oldParent: ViewBase): void {
@ -1459,7 +1443,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
}); });
} }
_inheritStyleScope(styleScope: ssm.StyleScope): void { _inheritStyleScope(styleScope: StyleScope): void {
// If we are styleScope don't inherit parent stylescope. // If we are styleScope don't inherit parent stylescope.
// TODO: Consider adding parent scope and merge selectors. // TODO: Consider adding parent scope and merge selectors.
if (this._isStyleScopeHost) { if (this._isStyleScopeHost) {

View File

@ -9,7 +9,7 @@ export { sanitizeModuleName } from '../utils/common';
export { Button } from './button'; export { Button } from './button';
export { ContentView } from './content-view'; export { ContentView } from './content-view';
export { Binding } from './core/bindable'; export { Binding } from './core/bindable';
export type { BindingOptions } from './core/bindable'; export type { BindingOptions } from './core/bindable/bindable-types';
export { ControlStateChangeListener } from './core/control-state-change'; export { ControlStateChangeListener } from './core/control-state-change';
export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, querySelectorAll } from './core/view-base'; export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, querySelectorAll } from './core/view-base';
export type { ShowModalOptions } from './core/view-base'; export type { ShowModalOptions } from './core/view-base';