import { IDirtyClean } from '../dirty-clean'; import addDirtyProps, { DirtyProp, IDirtyProp } from '../dirty-props'; export type IDirtyPropOpts = Pick; const WATCHED_PROP_NAMES = ['top', 'left', 'height', 'width', 'units', 'space']; export type PositionUnit = 'cell' | 'px'; export type PositionSpace = 'data' | 'virtual' | 'real'; export const toStandardSpace = (space: PositionSpace) => { if (space === 'real') { return 'view'; } return space; }; export interface IRawPositionRange { top: number; left: number; height: number; width: number; } export type RawPositionRange = IRawPositionRange; export type PartialRawPositionRange = Partial; export type RawPositionRangeUnion = RawPositionRange | PartialRawPositionRange; export interface IPartialPositionRange extends PartialRawPositionRange { units: PositionUnit; space: PositionSpace; isDirty(): boolean; } // not the sexiest but we get the position type assuming top / left width / height are the same type export type PositionType = T['top']; export type SizeType = T['height']; export type PositionGet = (r: T) => PositionType; export type PositionSet = (r: T, p: PositionType) => T; export type SizeGet = (r: T) => SizeType; export type SizeSet = (r: T, p: SizeType) => T; export interface IPositionRangeDimension { getPosition: PositionGet; setPosition: PositionSet; getSize: SizeGet; setSize: SizeSet; } const getTop = (range: T) => { return range.top; }; const setTop = (range: T, p: number) => { range.top = p; return range; }; const getHeight = (range: T) => { return range.height; }; const setHeight = (range: T, s: number) => { range.height = s; return range; }; const getLeft = (range: T) => { return range.left; }; const setLeft = (range: T, p: number) => { range.left = p; return range; }; const getWidth = (range: T) => { return range.width; }; const setWidth = (range: T, s: number) => { range.width = s; return range; }; export const rowPositionRangeDimension: IPositionRangeDimension = { getPosition: getTop, getSize: getHeight, setPosition: setTop, setSize: setHeight, }; export const colPositionRangeDimension: IPositionRangeDimension = { getPosition: getLeft, getSize: getWidth, setPosition: setLeft, setSize: setWidth, }; export function mixin( range: T, dirtyClean: IDirtyClean, parentDirtyClean?: IDirtyClean, propOpts?: IDirtyPropOpts ) { range = range || {}; // allow mixin functionality // tslint:disable-next-line:prefer-object-spread const rangeResult: IPartialPositionRange & T = Object.assign(range, { isDirty: dirtyClean.isDirty, // defaults units: 'cell' as 'cell', space: 'data' as 'data', }); (rangeResult as any)._positionRangeDirtyClean = dirtyClean; let watchedProperties: DirtyProp[] = WATCHED_PROP_NAMES; if (propOpts) { watchedProperties = WATCHED_PROP_NAMES.map((propName) => { return { name: propName, onDirty: propOpts.onDirty, preDirty: propOpts.preDirty }; }); } const dirtyCleans = [dirtyClean]; if (parentDirtyClean) { dirtyCleans.push(parentDirtyClean); } addDirtyProps(rangeResult, watchedProperties, dirtyCleans); return rangeResult; } export default mixin;