From 19ce9fc2bfb824203714842724643e59b09dda8b Mon Sep 17 00:00:00 2001 From: William Tjondrosuharto Date: Sat, 20 Feb 2021 13:39:06 +0700 Subject: [PATCH] chore: box shadow updates (#9220) --- apps/toolbox/src/box-shadow.ts | 5 - .../core/__tests__/ui/styling/css-shadow.ts | 145 ++++++++++++++++++ .../accessibility-service.android.ts | 1 + packages/core/ui/styling/background-common.ts | 18 +++ .../core/ui/styling/background.android.ts | 15 +- packages/core/ui/styling/background.d.ts | 3 + packages/core/ui/styling/background.ios.ts | 36 +++-- packages/core/ui/styling/style-properties.ts | 3 +- packages/core/ui/text-base/index.android.ts | 5 +- 9 files changed, 208 insertions(+), 23 deletions(-) create mode 100644 packages/core/__tests__/ui/styling/css-shadow.ts diff --git a/apps/toolbox/src/box-shadow.ts b/apps/toolbox/src/box-shadow.ts index c45824314..379db6b91 100644 --- a/apps/toolbox/src/box-shadow.ts +++ b/apps/toolbox/src/box-shadow.ts @@ -105,11 +105,6 @@ export class BoxShadowModel extends Observable { } this.appliedBoxShadow = this._boxShadow; this.notifyPropertyChange('appliedBoxShadow', this.appliedBoxShadow); - - // TODO: this is a workaround to apply shadow immediately, - // since the box-shadow logic is currently inside background.ts - this.notifyPropertyChange('background', ''); - this.notifyPropertyChange('background', this.background); } textChange(args): void { diff --git a/packages/core/__tests__/ui/styling/css-shadow.ts b/packages/core/__tests__/ui/styling/css-shadow.ts new file mode 100644 index 000000000..705080522 --- /dev/null +++ b/packages/core/__tests__/ui/styling/css-shadow.ts @@ -0,0 +1,145 @@ +// This has been disabled/unfinished becase with the current testing setup +// the imports don't work. We need to fully switch to jest & set up ts support +// todo: fix tests. + +// import { parseCSSShadow } from "@nativescript/core/ui/styling/css-shadow"; +// import { zeroLength } from "@nativescript/core"; + +// describe('ui', () => { +// describe('styling', () => { +// describe('css-shadow', () => { +// +// it("empty", () => { +// const shadow = parseCSSShadow("") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(zeroLength) +// expect(shadow.offsetY).toBe(zeroLength) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('black') +// }); +// +// it("1px 1px 2px black", () => { +// const shadow = parseCSSShadow("1px 1px 2px black") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(1) +// expect(shadow.offsetY).toBe(1) +// expect(shadow.blurRadius).toBe(2) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('black') +// }); +// +// it("#fc0 1px 0 10px", () => { +// const shadow = parseCSSShadow("#fc0 1px 0 10px") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(1) +// expect(shadow.offsetY).toBe(zeroLength) +// expect(shadow.blurRadius).toBe(10) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('#fc0') +// }); +// +// it("5px 5px #558abb", () => { +// const shadow = parseCSSShadow("5px 5px #558abb") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(5) +// expect(shadow.offsetY).toBe(5) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('#558abb') +// }); +// +// it("white 2px 5px", () => { +// const shadow = parseCSSShadow("white 2px 5px") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(2) +// expect(shadow.offsetY).toBe(5) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('white') +// }); +// +// it("5px 10px", () => { +// const shadow = parseCSSShadow("5px 10px") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(5) +// expect(shadow.offsetY).toBe(10) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('black') +// }); +// +// // box +// it("60px -16px teal", () => { +// const shadow = parseCSSShadow("60px -16px teal") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(60) +// expect(shadow.offsetY).toBe(-16) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('teal') +// }); +// +// it("10px 5px 5px black", () => { +// const shadow = parseCSSShadow("10px 5px 5px black") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(10) +// expect(shadow.offsetY).toBe(5) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('black') +// }); +// +// it("2px 2px 2px 1px rgba(0, 0, 0, 0.2)", () => { +// const shadow = parseCSSShadow("2px 2px 2px 1px rgba(0, 0, 0, 0.2)") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(2) +// expect(shadow.offsetY).toBe(2) +// expect(shadow.blurRadius).toBe(2) +// expect(shadow.spreadRadius).toBe(1) +// expect(shadow.color).toBe('rgba(0, 0, 0, 0.2)') +// }); +// +// it("inset 5em 1em gold", () => { +// const shadow = parseCSSShadow("inset 5em 1em gold") +// expect(shadow.inset).toBe(true) +// expect(shadow.offsetX).toBe(5) +// expect(shadow.offsetY).toBe(1) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('gold') +// }); +// +// it("5 10", () => { +// const shadow = parseCSSShadow("5 10") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(5) +// expect(shadow.offsetY).toBe(10) +// expect(shadow.blurRadius).toBe(zeroLength) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('black') +// }); +// +// it("2 2 2 #333", () => { +// const shadow = parseCSSShadow("2 2 2 #333") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(2) +// expect(shadow.offsetY).toBe(2) +// expect(shadow.blurRadius).toBe(2) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('#333') +// }); +// +// it("-1 -1 1 #333", () => { +// const shadow = parseCSSShadow("-1 -1 1 #333") +// expect(shadow.inset).toBe(false) +// expect(shadow.offsetX).toBe(-1) +// expect(shadow.offsetY).toBe(-1) +// expect(shadow.blurRadius).toBe(1) +// expect(shadow.spreadRadius).toBe(zeroLength) +// expect(shadow.color).toBe('#333') +// }); +// }); +// }); +// }); +// diff --git a/packages/core/accessibility/accessibility-service.android.ts b/packages/core/accessibility/accessibility-service.android.ts index 90a8bd275..2f5af8c03 100644 --- a/packages/core/accessibility/accessibility-service.android.ts +++ b/packages/core/accessibility/accessibility-service.android.ts @@ -20,6 +20,7 @@ class AndroidSharedA11YObservable extends SharedA11YObservable { [accessibilityStateEnabledPropName]: boolean; [touchExplorationStateEnabledPropName]: boolean; + // @ts-ignore todo: fix get accessibilityServiceEnabled(): boolean { return !!this[accessibilityStateEnabledPropName] && !!this[touchExplorationStateEnabledPropName]; } diff --git a/packages/core/ui/styling/background-common.ts b/packages/core/ui/styling/background-common.ts index cd49d0c8c..a6d86886b 100644 --- a/packages/core/ui/styling/background-common.ts +++ b/packages/core/ui/styling/background-common.ts @@ -4,6 +4,7 @@ import { BackgroundRepeat } from '../styling/style-properties'; import { LinearGradient } from './linear-gradient'; // Types. import { Color } from '../../color'; +import { CSSShadow } from './css-shadow'; export class Background implements BackgroundDefinition { public static default = new Background(); @@ -26,6 +27,7 @@ export class Background implements BackgroundDefinition { public borderBottomLeftRadius = 0; public borderBottomRightRadius = 0; public clipPath: string; + public boxShadow: CSSShadow; private clone(): Background { const clone = new Background(); @@ -48,6 +50,7 @@ export class Background implements BackgroundDefinition { clone.borderBottomRightRadius = this.borderBottomRightRadius; clone.borderBottomLeftRadius = this.borderBottomLeftRadius; clone.clipPath = this.clipPath; + clone.boxShadow = this.boxShadow; return clone; } @@ -178,6 +181,13 @@ export class Background implements BackgroundDefinition { return clone; } + public withBoxShadow(value: CSSShadow): Background { + const clone = this.clone(); + clone.boxShadow = value; + + return clone; + } + public isEmpty(): boolean { return !this.color && !this.image && !this.hasBorderWidth() && !this.hasBorderRadius() && !this.clipPath; } @@ -274,6 +284,14 @@ export class Background implements BackgroundDefinition { return 0; } + public hasBoxShadow(): boolean { + return !!this.boxShadow; + } + + public getBoxShadow(): CSSShadow { + return this.boxShadow; + } + public toString(): string { return `isEmpty: ${this.isEmpty()}; color: ${this.color}; image: ${this.image}; repeat: ${this.repeat}; position: ${this.position}; size: ${this.size}; borderTopColor: ${this.borderTopColor}; borderRightColor: ${this.borderRightColor}; borderBottomColor: ${this.borderBottomColor}; borderLeftColor: ${this.borderLeftColor}; borderTopWidth: ${this.borderTopWidth}; borderRightWidth: ${this.borderRightWidth}; borderBottomWidth: ${this.borderBottomWidth}; borderLeftWidth: ${this.borderLeftWidth}; borderTopLeftRadius: ${this.borderTopLeftRadius}; borderTopRightRadius: ${ this.borderTopRightRadius diff --git a/packages/core/ui/styling/background.android.ts b/packages/core/ui/styling/background.android.ts index 1dcda93bd..9c38117e7 100644 --- a/packages/core/ui/styling/background.android.ts +++ b/packages/core/ui/styling/background.android.ts @@ -6,9 +6,9 @@ import { parse } from '../../css-value'; import { path, knownFolders } from '../../file-system'; import * as application from '../../application'; import { profile } from '../../profiling'; -import { BoxShadow } from './box-shadow'; import { Color } from '../../color'; import { Screen } from '../../platform'; +import { CSSShadow } from './css-shadow'; export * from './background-common'; interface AndroidView { @@ -93,9 +93,10 @@ export namespace ad { nativeView.setBackground(defaultDrawable); } - const boxShadow = view.style.boxShadow; - if (boxShadow) { - drawBoxShadow(nativeView, view, boxShadow); + if (background.hasBoxShadow()) { + drawBoxShadow(nativeView, view, background.getBoxShadow()); + } else { + clearBoxShadow(nativeView); } // TODO: Can we move BorderWidths as separate native setter? @@ -226,7 +227,7 @@ function createNativeCSSValueArray(css: string): androidNative.Array({ name: 'boxShadow', cssName: 'box-shadow', valueChanged: (target, oldValue, newValue) => { - target.boxShadow = newValue; + const background = target.backgroundInternal.withBoxShadow(newValue); + target.backgroundInternal = background; }, valueConverter: (value) => { return parseCSSShadow(value); diff --git a/packages/core/ui/text-base/index.android.ts b/packages/core/ui/text-base/index.android.ts index 1ad31a7ac..0f45f29f8 100644 --- a/packages/core/ui/text-base/index.android.ts +++ b/packages/core/ui/text-base/index.android.ts @@ -1,5 +1,6 @@ // Types -import { TextDecoration, TextAlignment, TextTransform, TextShadow, WhiteSpace, getClosestPropertyValue } from './text-base-common'; +import { TextDecoration, TextAlignment, TextTransform, WhiteSpace, getClosestPropertyValue } from './text-base-common'; +import { CSSShadow } from '../styling/css-shadow'; // Requires import { Font } from '../styling/font'; @@ -387,7 +388,7 @@ export class TextBase extends TextBaseCommon { }; } - [textShadowProperty.setNative](value: TextShadow) { + [textShadowProperty.setNative](value: CSSShadow) { this.nativeViewProtected.setShadowLayer(Length.toDevicePixels(value.blurRadius, 0), Length.toDevicePixels(value.offsetX, 0), Length.toDevicePixels(value.offsetY, 0), value.color.android); }