refactor: circular deps part 2

This commit is contained in:
Nathan Walker
2025-07-07 19:12:02 -07:00
parent 2fba017113
commit 47c72081dd
52 changed files with 600 additions and 1028 deletions

View File

@@ -1,10 +1,9 @@
import * as definition from '.';
import type { IColor } from './color-types';
import * as types from '../utils/types';
import * as knownColors from './known-colors';
import { Color } from '.';
import { HEX_REGEX, argbFromColorMix, argbFromHslOrHsla, argbFromHsvOrHsva, argbFromRgbOrRgba, hslToRgb, hsvToRgb, isCssColorMixExpression, isHslOrHsla, isHsvOrHsva, isRgbOrRgba, rgbToHsl, rgbToHsv, argbFromString } from './color-utils';
export class ColorBase implements definition.Color {
export class ColorBase implements IColor {
private _argb: number;
private _name: string;
@@ -112,11 +111,11 @@ export class ColorBase implements definition.Color {
return argbFromString(hex);
}
public equals(value: definition.Color): boolean {
public equals(value: IColor): boolean {
return value && this.argb === value.argb;
}
public static equals(value1: definition.Color, value2: definition.Color): boolean {
public static equals(value1: IColor, value2: IColor): boolean {
// both values are falsy
if (!value1 && !value2) {
return true;
@@ -131,7 +130,7 @@ export class ColorBase implements definition.Color {
}
public static isValid(value: any): boolean {
if (value instanceof Color) {
if (value instanceof ColorBase) {
return true;
}
@@ -147,10 +146,10 @@ export class ColorBase implements definition.Color {
return HEX_REGEX.test(value) || isRgbOrRgba(lowered) || isHslOrHsla(lowered);
}
public static fromHSL(a, h, s, l) {
return new Color(a, h, s, l, 'hsl');
return new ColorBase(a, h, s, l, 'hsl');
}
public static fromHSV(a, h, s, l) {
return new Color(a, h, s, l, 'hsv');
return new ColorBase(a, h, s, l, 'hsv');
}
public toString(): string {
@@ -160,7 +159,7 @@ export class ColorBase implements definition.Color {
/**
* @param {UIColor} value
*/
public static fromIosColor(value: any): Color {
public static fromIosColor(value: any): ColorBase {
return undefined;
}
@@ -222,7 +221,7 @@ export class ColorBase implements definition.Color {
* @param alpha (between 0 and 255)
*/
public setAlpha(a: number) {
return new Color(a, this.r, this.g, this.b);
return new ColorBase(a, this.r, this.g, this.b);
}
/**
@@ -234,7 +233,7 @@ export class ColorBase implements definition.Color {
}
/**
* return the [CSS hsv](https://www.w3schools.com/Css/css_colors_hsl.asp) representation of the color
* return the [CSS hsl](https://www.w3schools.com/Css/css_colors_hsl.asp) representation of the color
*
*/
public toHslString() {
@@ -284,7 +283,7 @@ export class ColorBase implements definition.Color {
public desaturate(amount: number) {
amount = amount === 0 ? 0 : amount || 10;
const hsl = rgbToHsl(this.r, this.g, this.b);
return Color.fromHSL(this.a, hsl.h, Math.min(100, Math.max(0, hsl.s - amount)), hsl.l);
return ColorBase.fromHSL(this.a, hsl.h, Math.min(100, Math.max(0, hsl.s - amount)), hsl.l);
}
/**
@@ -295,7 +294,7 @@ export class ColorBase implements definition.Color {
public saturate(amount: number) {
amount = amount === 0 ? 0 : amount || 10;
const hsl = rgbToHsl(this.r, this.g, this.b);
return Color.fromHSL(this.a, hsl.h, Math.min(100, Math.max(0, hsl.s + amount)), hsl.l);
return ColorBase.fromHSL(this.a, hsl.h, Math.min(100, Math.max(0, hsl.s + amount)), hsl.l);
}
/**
@@ -314,7 +313,7 @@ export class ColorBase implements definition.Color {
public lighten(amount: number) {
amount = amount === 0 ? 0 : amount || 10;
const hsl = rgbToHsl(this.r, this.g, this.b);
return Color.fromHSL(this.a, hsl.h, hsl.s, Math.min(100, Math.max(0, hsl.l + amount)));
return ColorBase.fromHSL(this.a, hsl.h, hsl.s, Math.min(100, Math.max(0, hsl.l + amount)));
}
/**
@@ -327,7 +326,7 @@ export class ColorBase implements definition.Color {
const r = Math.max(0, Math.min(255, this.r - Math.round(255 * -(amount / 100))));
const g = Math.max(0, Math.min(255, this.g - Math.round(255 * -(amount / 100))));
const b = Math.max(0, Math.min(255, this.b - Math.round(255 * -(amount / 100))));
return new Color(this.a, r, g, b);
return new ColorBase(this.a, r, g, b);
}
/**
@@ -338,7 +337,7 @@ export class ColorBase implements definition.Color {
public darken(amount: number) {
amount = amount === 0 ? 0 : amount || 10;
const hsl = rgbToHsl(this.r, this.g, this.b);
return Color.fromHSL(this.a, hsl.h, hsl.s, Math.min(100, Math.max(0, hsl.l - amount)));
return ColorBase.fromHSL(this.a, hsl.h, hsl.s, Math.min(100, Math.max(0, hsl.l - amount)));
}
/**
@@ -350,7 +349,7 @@ export class ColorBase implements definition.Color {
const hsl = this.toHsl();
const hue = (hsl.h + amount) % 360;
hsl.h = hue < 0 ? 360 + hue : hue;
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
return ColorBase.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
}
/**
@@ -360,10 +359,10 @@ export class ColorBase implements definition.Color {
public complement() {
const hsl = this.toHsl();
hsl.h = (hsl.h + 180) % 360;
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
return ColorBase.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
}
static mix(color1: Color, color2: Color, amount = 50) {
static mix(color1: ColorBase, color2: ColorBase, amount = 50) {
const p = amount / 100;
const rgba = {
@@ -373,6 +372,6 @@ export class ColorBase implements definition.Color {
a: (color2.a - color1.a) * p + color1.a,
};
return new Color(rgba.a, rgba.r, rgba.g, rgba.b);
return new ColorBase(rgba.a, rgba.r, rgba.g, rgba.b);
}
}

View File

@@ -0,0 +1,44 @@
// Shared Color interface/type for use in color-common.ts and platform files
export interface IColor {
readonly a: number;
readonly r: number;
readonly g: number;
readonly b: number;
readonly hex: string;
readonly argb: number;
readonly name: string;
readonly android: number;
readonly ios: any;
equals(value: IColor): boolean;
isDark(): boolean;
isLight(): boolean;
getBrightness(): number;
getLuminance(): number;
setAlpha(a: number): IColor;
toHsl(): { h: number; s: number; l: number; a: number };
toHslString(): string;
toHsv(): { h: number; s: number; v: number; a: number };
toHsvString(): string;
toRgbString(): string;
desaturate(amount: number): IColor;
saturate(amount: number): IColor;
greyscale(): IColor;
lighten(amount: number): IColor;
brighten(amount: number): IColor;
darken(amount: number): IColor;
spin(amount: number): IColor;
complement(): IColor;
}
// Optionally, export the Color class type for static methods if needed
export type ColorClass = {
new (...args: any[]): IColor;
isValid(value: any): boolean;
fromIosColor(value: any): IColor;
fromHSL(a: number, h: number, s: number, l: number): IColor;
fromHSV(a: number, h: number, s: number, l: number): IColor;
mix(color1: IColor, color2: IColor, amount?: number): IColor;
equals(value1: IColor, value2: IColor): boolean;
};

View File

@@ -1,6 +1,7 @@
import { ColorBase } from './color-common';
import type { IColor } from './color-types';
export class Color extends ColorBase {
export class Color extends ColorBase implements IColor {
private _ios: UIColor;
get ios(): UIColor {

View File

@@ -3,7 +3,7 @@
*/
// imported for definition purposes only
import { makeValidator, makeParser } from '../ui/core/properties';
import { makeValidator, makeParser } from './validators';
import { CubicBezierAnimationCurve } from './animation-types';
export namespace CoreTypes {
@@ -146,7 +146,7 @@ export namespace CoreTypes {
export const sup = 'sup';
export const sub = 'sub';
export const baseline = 'baseline';
export const isValid = makeValidator<VerticalAlignmentTextType>(top, middle, bottom, stretch, texttop, textbottom, sup, sub, baseline);
export const isValid = makeValidator<CoreTypes.VerticalAlignmentTextType>(top, middle, bottom, stretch, texttop, textbottom, sup, sub, baseline);
export const parse = (value: string) => (value.toLowerCase() === 'center' ? middle : parseStrict(value));
const parseStrict = makeParser<CoreTypes.VerticalAlignmentTextType>(isValid);
}

View File

@@ -0,0 +1,19 @@
// Utility functions for validation and parsing, shared between core-types and properties
export function makeValidator<T>(...values: T[]): (value: any) => value is T {
return function (value: any): value is T {
return values.indexOf(value) !== -1;
};
}
export function makeParser<T>(isValid: (value: any) => boolean, allowNumbers = false): (value: any) => T {
return function (value: any): T {
if (allowNumbers && typeof value === 'number') {
return value as T;
}
if (isValid(value)) {
return value as T;
}
throw new Error(`Invalid value: ${value}`);
};
}

View File

@@ -1,5 +1,5 @@
// Types.
import { Animation as AnimationBaseDefinition, Point3D } from '.';
import { Point3D } from './animation-types';
import { AnimationDefinition, AnimationPromise as AnimationPromiseDefinition, Pair, PropertyAnimation } from './animation-interfaces';
// Requires.
@@ -19,7 +19,7 @@ export namespace Properties {
export const width = 'width';
}
export abstract class AnimationBase implements AnimationBaseDefinition {
export abstract class AnimationBase {
public _propertyAnimations: Array<PropertyAnimation>;
public _playSequentially: boolean;
private _isPlaying: boolean;

View File

@@ -0,0 +1,50 @@
// Shared types/interfaces for animation
import { View } from '../core/view';
export interface AnimationDefinition {
target?: View;
opacity?: number;
backgroundColor?: any;
translate?: { x: number; y: number };
scale?: { x: number; y: number };
height?: any;
width?: any;
rotate?: number | { x: number; y: number; z: number };
duration?: number;
delay?: number;
iterations?: number;
curve?: any;
}
// Types from index.d.ts that need to be exported for consumers
export interface Point3D {
x: number;
y: number;
z: number;
}
export interface Pair {
x: number;
y: number;
}
export type TransformationType = 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY';
export type TransformationValue = Point3D | Pair | number;
export type Transformation = {
property: TransformationType;
value: TransformationValue;
};
export type TransformFunctionsInfo = {
translate: Pair;
rotate: Point3D;
scale: Pair;
};
export interface Cancelable {
cancel(): void;
}
export type AnimationPromise = Promise<void> & Cancelable;

View File

@@ -10,7 +10,6 @@ import { Device, Screen } from '../../platform';
import lazy from '../../utils/lazy';
export * from './animation-common';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './keyframe-animation';
let argbEvaluator: android.animation.ArgbEvaluator;
function ensureArgbEvaluator() {

View File

@@ -1,139 +1,3 @@
import { View } from '../core/view';
import { CoreTypes } from '../../core-types';
import { Color } from '../../color';
export type { Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation-types';
export { Animation, _resolveAnimationCurve } from './animation';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './keyframe-animation';
/**
* Defines animation options for the View.animate method.
*/
export interface AnimationDefinition {
/**
* The view whose property is to be animated.
*/
target?: View;
/**
* Animates the opacity of the view. Value should be a number between 0.0 and 1.0
*/
opacity?: number;
/**
* Animates the backgroundColor of the view.
*/
backgroundColor?: Color;
/**
* Animates the translate affine transform of the view.
*/
translate?: Pair;
/**
* Animates the scale affine transform of the view.
*/
scale?: Pair;
/**
* Animates the height of a view.
*/
height?: CoreTypes.PercentLengthType | string;
/**
* Animates the width of a view.
*/
width?: CoreTypes.PercentLengthType | string;
/**
* Animates the rotate affine transform of the view. Value should be a number specifying the rotation amount in degrees.
*/
rotate?: number | Point3D;
/**
* The length of the animation in milliseconds. The default duration is 300 milliseconds.
*/
duration?: number;
/**
* The amount of time, in milliseconds, to delay starting the animation.
*/
delay?: number;
/**
* Specifies how many times the animation should be played. Default is 1.
* iOS animations support fractional iterations, i.e. 1.5.
* To repeat an animation infinitely, use Number.POSITIVE_INFINITY
*/
iterations?: number;
/**
* An optional animation curve. Possible values are contained in the [AnimationCurve enumeration](../modules/_ui_enums_.animationcurve.html).
* Alternatively, you can pass an instance of type UIViewAnimationCurve for iOS or android.animation.TimeInterpolator for Android.
*/
curve?: any;
}
/**
* Defines a key-value pair for css transformation
*/
export type Transformation = {
property: TransformationType;
value: TransformationValue;
};
/**
* Defines possible css transformations
*/
export type TransformationType = 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY';
/**
* Defines possible css transformation values
*/
export type TransformationValue = Point3D | Pair | number;
/**
* Defines a point in 3d space (x, y and z) for rotation in 3d animations.
*/
export interface Point3D {
x: number;
y: number;
z: number;
}
/**
* Defines a pair of values (horizontal and vertical) for translate and scale animations.
*/
export interface Pair {
x: number;
y: number;
}
/**
* Defines full information for css transformation
*/
export type TransformFunctionsInfo = {
translate: Pair;
rotate: Point3D;
scale: Pair;
};
export interface Cancelable {
cancel(): void;
}
/**
* A Promise that can cancel the animation.
*/
export type AnimationPromise = Promise<void> & Cancelable;
/**
* Defines a animation set.
*/
export class Animation {
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
public play: (resetOnFinish?: boolean) => AnimationPromise;
public cancel: () => void;
public isPlaying: boolean;
public _resolveAnimationCurve(curve: any): any;
}
export function _resolveAnimationCurve(curve: any): any;

View File

@@ -12,7 +12,6 @@ import { ios as iosHelper } from '../../utils/native-helper';
import { Screen } from '../../platform';
export * from './animation-common';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './keyframe-animation';
const _transform = '_transform';
const _skip = '_skip';

View File

@@ -1,127 +0,0 @@
import { View } from '../core/view';
import { CoreTypes } from '../../core-types';
import { Color } from '../../color';
export declare const ANIMATION_PROPERTIES;
interface Keyframe {
backgroundColor?: Color;
scale?: { x: number; y: number };
translate?: { x: number; y: number };
rotate?: { x: number; y: number; z: number };
opacity?: number;
width?: CoreTypes.PercentLengthType;
height?: CoreTypes.PercentLengthType;
valueSource?: 'keyframe' | 'animation';
duration?: number;
curve?: any;
forceLayer?: boolean;
}
export interface Keyframes {
name: string;
keyframes: Array<UnparsedKeyframe>;
tag?: string | number;
scopedTag?: string;
mediaQueryString?: string;
}
export interface UnparsedKeyframe {
values: Array<any>;
declarations: Array<KeyframeDeclaration>;
}
export interface KeyframeDeclaration {
property: string;
value: any;
}
export interface KeyframeInfo {
duration: number;
declarations: Array<KeyframeDeclaration>;
curve?: any;
}
/**
* Defines animation options for the View.animate method.
*/
export class KeyframeAnimationInfo {
/**
* Return animation keyframes.
*/
keyframes: Array<KeyframeInfo>;
/**
* The animation name.
*/
name?: string;
/**
* The length of the animation in milliseconds. The default duration is 300 milliseconds.
*/
duration?: number;
/**
* The amount of time, in milliseconds, to delay starting the animation.
*/
delay?: number;
/**
* Specifies how many times the animation should be played. Default is 1.
* iOS animations support fractional iterations, i.e. 1.5.
* To repeat an animation infinitely, use Number.POSITIVE_INFINITY
*/
iterations?: number;
/**
* An optional animation curve. Possible values are contained in the [AnimationCurve enumeration](../modules/_ui_enums_.animationcurve.html).
* Alternatively, you can pass an instance of type UIViewAnimationCurve for iOS or android.animation.TimeInterpolator for Android.
*/
curve?: any;
/**
* Determines whether the animation values will be applied on the animated object after the animation finishes.
*/
isForwards: boolean;
/**
* If true the animation will be played backwards.
*/
isReverse?: boolean;
}
export class KeyframeAnimation {
animations: Array<Keyframe>;
/**
* The amount of time, in milliseconds, to delay starting the animation.
*/
delay: number;
/**
* Specifies how many times the animation should be played. Default is 1.
* iOS animations support fractional iterations, i.e. 1.5.
* To repeat an animation infinitely, use Number.POSITIVE_INFINITY
*/
iterations: number;
/**
* Returns true if the application is currently running.
*/
isPlaying: boolean;
/**
* Plays the animation.
*/
public play: (view: View) => Promise<void>;
/**
* Cancels a playing animation.
*/
public cancel: () => void;
/**
* Creates a keyframe animation from animation definition.
*/
public static keyframeAnimationFromInfo(info: KeyframeAnimationInfo): KeyframeAnimation;
}

View File

@@ -7,7 +7,7 @@ import { Trace } from '../../trace';
// Types.
import { unsetValue } from '../core/properties';
import { Animation } from '.';
import { Animation } from './index';
import { backgroundColorProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, rotateProperty, opacityProperty, rotateXProperty, rotateYProperty, widthProperty, heightProperty } from '../styling/style-properties';
export interface Keyframes {

View File

@@ -80,6 +80,7 @@ export namespace xml2ui {
export function SourceErrorFormat(uri): ErrorFormatter {
return (e: Error, p: xml.Position) => {
console.error(uri);
const source = p ? new Source(uri, p.line, p.column) : new Source(uri, -1, -1);
e = new SourceError(e, source, 'Building UI from XML.');

View File

@@ -6,6 +6,7 @@ import { Style } from '../../styling/style';
import { profile } from '../../../profiling';
import { CoreTypes } from '../../enums';
import { makeValidator, makeParser } from '../../../core-types/validators';
/**
* Value specifying that Property should be set to its initial value.
@@ -1348,6 +1349,8 @@ export class ShorthandProperty<T extends Style, P> implements ShorthandProperty<
}
}
export { makeValidator, makeParser } from '../../../core-types/validators';
function inheritablePropertyValuesOn(view: ViewBase): Array<{ property: InheritedProperty<any, any>; value: any }> {
const array = new Array<{
property: InheritedProperty<any, any>;
@@ -1564,29 +1567,6 @@ export function propagateInheritableCssProperties(parentStyle: Style, childStyle
}
}
export function makeValidator<T>(...values: T[]): (value: any) => value is T {
const set = new Set(values);
return (value: any): value is T => set.has(value);
}
export function makeParser<T>(isValid: (value: any) => boolean, allowNumbers = false): (value: any) => T {
return (value) => {
const lower = value && value.toLowerCase();
if (isValid(lower)) {
return lower;
} else {
if (allowNumbers) {
const convNumber = +value;
if (!isNaN(convNumber)) {
return value;
}
}
throw new Error('Invalid value: ' + value);
}
};
}
export function getSetProperties(view: ViewBase): [string, any][] {
const result = [];

View File

@@ -23,7 +23,8 @@ import { Builder } from '../../builder';
import { StyleScope } from '../../styling/style-scope';
import { LinearGradient } from '../../styling/linear-gradient';
import * as am from '../../animation';
import { Animation } from '../../animation';
import type { AnimationPromise } from '../../animation/animation-types';
import { AccessibilityEventOptions, AccessibilityLiveRegion, AccessibilityRole, AccessibilityState } from '../../../accessibility/accessibility-types';
import { accessibilityHintProperty, accessibilityIdentifierProperty, accessibilityLabelProperty, accessibilityValueProperty, accessibilityIgnoresInvertColorsProperty } from '../../../accessibility/accessibility-properties';
import { accessibilityBlurEvent, accessibilityFocusChangedEvent, accessibilityFocusEvent, accessibilityPerformEscapeEvent, getCurrentFontScale } from '../../../accessibility';
@@ -34,13 +35,6 @@ import { Flex, FlexFlow } from '../../layouts/flexbox-layout';
// helpers (these are okay re-exported here)
export * from './view-helper';
let animationModule: typeof am;
function ensureAnimationModule() {
if (!animationModule) {
animationModule = require('../../animation');
}
}
export function CSSType(type: string): ClassDecorator {
return (cls) => {
cls.prototype.cssType = type;
@@ -122,7 +116,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
protected _isLayoutValid: boolean;
private _cssType: string;
private _localAnimations: Set<am.Animation>;
private _localAnimations: Set<Animation>;
_currentWidthMeasureSpec: number;
_currentHeightMeasureSpec: number;
@@ -1138,23 +1132,25 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
};
}
public animate(animation: any): am.AnimationPromise {
return this.createAnimation(animation).play();
public animate(animation: any): AnimationPromise {
const animationInstance = this.createAnimation(animation);
const promise = animationInstance.play();
(promise as AnimationPromise).cancel = () => animationInstance.cancel();
return promise as AnimationPromise;
}
public createAnimation(animation: any): am.Animation {
ensureAnimationModule();
public createAnimation(animation: any): Animation {
if (!this._localAnimations) {
this._localAnimations = new Set();
}
animation.target = this;
const anim = new animationModule.Animation([animation]);
const anim = new Animation([animation]);
this._localAnimations.add(anim);
return anim;
}
public _removeAnimation(animation: am.Animation): boolean {
public _removeAnimation(animation: Animation): boolean {
const localAnimations = this._localAnimations;
if (localAnimations && localAnimations.has(animation)) {
localAnimations.delete(animation);

View File

@@ -1,304 +1,6 @@
import type { GesturesObserver as GesturesObserverDefinition } from '.';
import type { GesturesObserverDefinition, GestureEvents, GestureStateTypes, SwipeDirection, TouchAction, GestureEventData, TapGestureEventData, TouchGestureEventData, Pointer, GestureEventDataWithState, PinchGestureEventData, SwipeGestureEventData, PanGestureEventData, RotationGestureEventData } from './gestures-types';
import { GestureTypes } from './gestures-types';
import type { View } from '../core/view';
import type { EventData } from '../../data/observable';
export * from './touch-manager';
/**
* Events emitted during gesture lifecycle
*/
export enum GestureEvents {
/**
* When the gesture is attached to the view
* Provides access to the native gesture recognizer for further customization
*
* @nsEvent {GestureEventData} gestureAttached
*/
gestureAttached = 'gestureAttached',
/**
* When a touch down was detected
*
* @nsEvent touchDown
*/
touchDown = 'touchDown',
/**
* When a touch up was detected
*
* @nsEvent touchUp
*/
touchUp = 'touchUp',
}
/**
* Defines an enum with supported gesture types.
*/
export enum GestureTypes {
/**
* Denotes tap (click) gesture.
*
* @nsEvent {TapGestureEventData} tap
*/
tap = 1 << 0,
/**
* Denotes double tap gesture.
*
* @nsEvent {TapGestureEventData} doubleTap
*/
doubleTap = 1 << 1,
/**
* Denotes pinch gesture.
*
* @nsEvent {PinchGestureEventData} pinch
*/
pinch = 1 << 2,
/**
* Denotes pan gesture.
*
* @nsEvent {PanGestureEventData} pan
*/
pan = 1 << 3,
/**
* Denotes swipe gesture.
*
* @nsEvent {SwipeGestureEventData} swipe
*/
swipe = 1 << 4,
/**
* Denotes rotation gesture.
*
* @nsEvent {RotationGestureEventData} rotate
*/
rotation = 1 << 5,
/**
* Denotes long press gesture.
*
* @nsEvent {GestureEventDataWithState} longPress
*/
longPress = 1 << 6,
/**
* Denotes touch action.
*
* @nsEvent {TouchGestureEventData} touch
*/
touch = 1 << 7,
}
/**
* Defines an enum with supported gesture states.
*/
export enum GestureStateTypes {
/**
* Gesture canceled.
*/
cancelled,
/**
* Gesture began.
*/
began,
/**
* Gesture changed.
*/
changed,
/**
* Gesture ended.
*/
ended,
}
/**
* Defines an enum for swipe gesture direction.
*/
export enum SwipeDirection {
/**
* Denotes right direction for swipe gesture.
*/
right = 1 << 0,
/**
* Denotes left direction for swipe gesture.
*/
left = 1 << 1,
/**
* Denotes up direction for swipe gesture.
*/
up = 1 << 2,
/**
* Denotes down direction for swipe gesture.
*/
down = 1 << 3,
}
/**
* Defines a touch action
*/
export enum TouchAction {
/**
* Down action.
*/
down = 'down',
/**
* Up action.
*/
up = 'up',
/**
* Move action.
*/
move = 'move',
/**
* Cancel action.
*/
cancel = 'cancel',
}
/**
* Provides gesture event data.
*/
export interface GestureEventData extends EventData {
/**
* Gets the type of the gesture.
*/
type: GestureTypes;
/**
* Gets the view which originates the gesture.
*/
view: View;
/**
* Gets the underlying native iOS specific [UIGestureRecognizer](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizer_Class/).
*/
ios: any /* UIGestureRecognizer */;
/**
* Gets the underlying native android specific [gesture detector](http://developer.android.com/reference/android/view/GestureDetector.html).
*/
android: any;
}
/**
* Provides gesture event data.
*/
export interface TapGestureEventData extends GestureEventData {
/**
* Gets the number of pointers in the event.
*/
getPointerCount(): number;
/**
* Gets the X coordinate of this event inside the view that triggered the event
*/
getX(): number;
/**
* Gets the Y coordinate of the event inside the view that triggered the event.
*/
getY(): number;
}
/**
* Provides gesture event data.
*/
export interface TouchGestureEventData extends TapGestureEventData {
/**
* Gets action of the touch. Possible values: 'up', 'move', 'down', 'cancel'
*/
action: 'up' | 'move' | 'down' | 'cancel';
/**
* Gets the pointers that triggered the event.
* Note: In Android there is aways only one active pointer.
*/
getActivePointers(): Array<Pointer>;
/**
* Gets all pointers.
*/
getAllPointers(): Array<Pointer>;
}
/**
* Pointer is an object representing a finger (or other object) that is touching the screen.
*/
export interface Pointer {
/**
* The id of the pointer.
*/
android: any;
/**
* The UITouch object associated to the touch
*/
ios: any;
/**
* Gets the X coordinate of the pointer inside the view that triggered the event.
*/
getX(): number;
/**
* Gets the Y coordinate of the pointer inside the view that triggered the event.
*/
getY(): number;
/**
* Gests the X coordinate of the pointer inside the view that triggered the event.
* @returns The X coordinate in _Device Pixels_.
*/
getXPixels(): number;
/**
* Gets the X coordinate of the pointer inside the view that triggered the event.
* @returns The X coordinate in _Device Independent Pixels_.
*/
getXDIP(): number;
/**
* Gests the Y coordinate of the pointer inside the view that triggered the event.
* @returns The Y coordinate in _Device Pixels_.
*/
getYPixels(): number;
/**
* Gets the Y coordinate of the pointer inside the view that triggered the event.
* @returns The Y coordinate in _Device Independent Pixels_.
*/
getYDIP(): number;
}
/**
* Provides gesture event data.
*/
export interface GestureEventDataWithState extends GestureEventData {
state: number;
}
/**
* Provides gesture event data for pinch gesture.
*/
export interface PinchGestureEventData extends GestureEventDataWithState {
scale: number;
getFocusX(): number;
getFocusY(): number;
}
/**
* Provides gesture event data for swipe gesture.
*/
export interface SwipeGestureEventData extends GestureEventData {
direction: SwipeDirection;
}
/**
* Provides gesture event data for pan gesture.
*/
export interface PanGestureEventData extends GestureEventDataWithState {
deltaX: number;
deltaY: number;
}
/**
* Provides gesture event data for rotation gesture.
*/
export interface RotationGestureEventData extends GestureEventDataWithState {
rotation: number;
}
/**
* Returns a string representation of a gesture type.
@@ -399,3 +101,7 @@ export abstract class GesturesObserverBase implements GesturesObserverDefinition
this._context = null;
}
}
export { GesturesObserverBase as GesturesObserver };
export { TouchAction, GestureStateTypes, GestureTypes, SwipeDirection, GestureEvents } from './gestures-types';

View File

@@ -0,0 +1,130 @@
// Shared types/interfaces for gestures
import type { View } from '../core/view';
import type { EventData } from '../../data/observable';
export interface GesturesObserverDefinition {
/**
* Registers a gesture observer to a view and gesture.
* @param type - Type of the gesture.
*/
observe(type: any): void;
/**
* Disconnects the gesture observer.
*/
disconnect(): void;
/**
* Singular gesture type (e.g. GestureTypes.tap) attached to the observer.
* Does not support plural gesture types (e.g.
* GestureTypes.tap & GestureTypes.doubleTap).
*/
type: any;
/**
* A function that will be executed when a gesture is received.
*/
callback: (args: any) => void;
/**
* A context which will be used as `this` in callback execution.
*/
context: any;
/**
* An internal Android specific method used to pass the motion event to the correct gesture observer.
*/
androidOnTouchEvent: (motionEvent: any /* android.view.MotionEvent */) => void;
}
// Shared gesture types, interfaces, and enums for gestures-common.ts and touch-manager.ts
export enum GestureEvents {
gestureAttached = 'gestureAttached',
touchDown = 'touchDown',
touchUp = 'touchUp',
}
export enum GestureTypes {
tap = 1 << 0,
doubleTap = 1 << 1,
pinch = 1 << 2,
pan = 1 << 3,
swipe = 1 << 4,
rotation = 1 << 5,
longPress = 1 << 6,
touch = 1 << 7,
}
export enum GestureStateTypes {
cancelled,
began,
changed,
ended,
}
export enum SwipeDirection {
right = 1 << 0,
left = 1 << 1,
up = 1 << 2,
down = 1 << 3,
}
export enum TouchAction {
down = 'down',
up = 'up',
move = 'move',
cancel = 'cancel',
}
export interface GestureEventData extends EventData {
type: GestureTypes;
view: View;
ios: any;
android: any;
}
export interface TapGestureEventData extends GestureEventData {
getPointerCount(): number;
getX(): number;
getY(): number;
}
export interface TouchGestureEventData extends TapGestureEventData {
action: 'up' | 'move' | 'down' | 'cancel';
getActivePointers(): Array<Pointer>;
getAllPointers(): Array<Pointer>;
}
export interface Pointer {
android: any;
ios: any;
getX(): number;
getY(): number;
getXPixels(): number;
getXDIP(): number;
getYPixels(): number;
getYDIP(): number;
}
export interface GestureEventDataWithState extends GestureEventData {
state: number;
}
export interface PinchGestureEventData extends GestureEventDataWithState {
scale: number;
getFocusX(): number;
getFocusY(): number;
}
export interface SwipeGestureEventData extends GestureEventData {
direction: SwipeDirection;
}
export interface PanGestureEventData extends GestureEventDataWithState {
deltaX: number;
deltaY: number;
}
export interface RotationGestureEventData extends GestureEventDataWithState {
rotation: number;
}

View File

@@ -1,5 +1,5 @@
// Definitions.
import { GestureEventData, TapGestureEventData, SwipeGestureEventData, PanGestureEventData, RotationGestureEventData, GestureEventDataWithState } from '.';
import type { GestureEventData, TapGestureEventData, SwipeGestureEventData, PanGestureEventData, RotationGestureEventData, GestureEventDataWithState } from './gestures-types';
import type { View } from '../core/view';
import { EventData } from '../../data/observable';
@@ -12,6 +12,8 @@ import { layout } from '../../utils';
import * as timer from '../../timer';
export * from './gestures-common';
export * from './gestures-types';
export * from './touch-manager';
interface TapAndDoubleTapGestureListener {
new (observer: GesturesObserver, target: View, type: number): android.view.GestureDetector.SimpleOnGestureListener;

View File

@@ -2,6 +2,7 @@ import type { View } from '../core/view';
export * from './gestures-common';
export * from './touch-manager';
export type { GesturesObserverDefinition } from './gestures-types';
/**
* Provides options for the GesturesObserver.

View File

@@ -11,6 +11,8 @@ import { GesturesObserverBase, toString, TouchAction, GestureStateTypes, Gesture
import { layout } from '../../utils';
export * from './gestures-common';
export * from './gestures-types';
export * from './touch-manager';
export function observe(target: View, type: GestureTypes, callback: (args: GestureEventData) => void, context?: any): GesturesObserver {
const observer = new GesturesObserver(target, callback, context);

View File

@@ -0,0 +1,7 @@
export * from './index.android';
export * from './gestures-common';
export * from './gestures-types';
export * from './touch-manager';
export { GesturesObserver, observe } from './index.android';
export { TouchManager, TouchAnimationOptions, VisionHoverOptions } from './touch-manager';

View File

@@ -2,12 +2,12 @@
* Provides various helpers for adding easy touch handling animations.
* Use when needing to implement more interactivity with your UI regarding touch down/up behavior.
*/
import { GestureEventData, GestureEventDataWithState, TouchGestureEventData } from '.';
import type { GestureEventData, GestureEventDataWithState, TouchGestureEventData } from './gestures-types';
import { GestureEvents, GestureStateTypes, GestureTypes } from './gestures-types';
import { Animation } from '../animation';
import { AnimationDefinition } from '../animation/animation-interfaces';
import type { View } from '../core/view';
import { isObject, isFunction } from '../../utils/types';
import { GestureEvents, GestureStateTypes, GestureTypes } from './gestures-common';
export type TouchAnimationFn = (view: View) => void;
export type TouchAnimationOptions = {

View File

@@ -1,7 +1,8 @@
export { ActionBar, ActionItem, ActionItems, NavigationButton } from './action-bar';
export { ActivityIndicator } from './activity-indicator';
export { Animation, KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './animation';
export type { AnimationDefinition } from './animation';
export { Animation, _resolveAnimationCurve } from './animation';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './animation/keyframe-animation';
export type { AnimationDefinition, Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation/animation-types';
export { Builder } from './builder';
export type { LoadOptions } from './builder';
export type { ComponentModule } from './builder/component-builder';

View File

@@ -4,7 +4,7 @@ import { CSSType, View } from '../../core/view';
import { GridLayout } from '../grid-layout';
import { RootLayout, RootLayoutOptions, ShadeCoverOptions, TransitionAnimation } from '.';
import { Animation } from '../../animation';
import { AnimationDefinition } from '../../animation';
import { AnimationDefinition } from '../../animation/animation-types';
import { isNumber } from '../../../utils/types';
import { _findRootLayoutById, _pushIntoRootLayoutStack, _removeFromRootLayoutStack, _geRootLayoutFromStack } from './root-layout-stack';

View File

@@ -1,4 +1,4 @@
import { Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo } from '../animation';
import { Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo } from '../animation/animation-types';
import { radiansToDegrees } from '../../utils/number-utils';
import { decompose2DTransformMatrix, getTransformMatrix, matrixArrayToCssMatrix, multiplyAffine2d } from '../../matrix';
import { hasDuplicates } from '../../utils';