diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ff57aa2f..1acc36b75 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+
+# [6.1.0](https://github.com/NativeScript/NativeScript/compare/6.0.7...6.1.0) (2019-09-02)
+
+
+### Bug Fixes
+
+* dots can now be used in module names ([#7655](https://github.com/NativeScript/NativeScript/issues/7655)) ([b6ff4d3](https://github.com/NativeScript/NativeScript/commit/b6ff4d3))
+* **css:** parse css selectors with escape sequences ([#7689](https://github.com/NativeScript/NativeScript/issues/7689)) ([#7732](https://github.com/NativeScript/NativeScript/issues/7732)) ([e3ed028](https://github.com/NativeScript/NativeScript/commit/e3ed028))
+* **ios-tabs:** handle tabs extended layout for ios 10 ([f7f0612](https://github.com/NativeScript/NativeScript/commit/f7f0612))
+* **ios-tabs:** crash when add tabstrip in loaded event ([#7743](https://github.com/NativeScript/NativeScript/issues/7743)) ([a66f2f2](https://github.com/NativeScript/NativeScript/commit/a66f2f2))
+* **ios-tabs:** handle nesting proxy view container ([#7755](https://github.com/NativeScript/NativeScript/issues/7755)) ([92c3338](https://github.com/NativeScript/NativeScript/commit/92c3338))
+* handle empty folders in non-bundle-compat ([#7649](https://github.com/NativeScript/NativeScript/issues/7649)) ([5fd7913](https://github.com/NativeScript/NativeScript/commit/5fd7913))
+
+
+### Features
+
+* implement css-variables and css-calc ([#7553](https://github.com/NativeScript/NativeScript/issues/7553)) ([673c808](https://github.com/NativeScript/NativeScript/commit/673c808))
+* add CSS classes to app/modal root views to target platform/device/orientation/type ([#7606](https://github.com/NativeScript/NativeScript/issues/7606)) ([3adba68](https://github.com/NativeScript/NativeScript/commit/3adba68))
+* **GridLayout:** Add synonym property column[Span] for col[Span] in GridLayout ([#7641](https://github.com/NativeScript/NativeScript/issues/7641)) ([d3c39c1](https://github.com/NativeScript/NativeScript/commit/d3c39c1))
+* apply styles when adding them to the application scope ([#7652](https://github.com/NativeScript/NativeScript/issues/7652)) ([1d12136](https://github.com/NativeScript/NativeScript/commit/1d12136))
+* expose application orientation ([#7602](https://github.com/NativeScript/NativeScript/issues/7602)) ([e2c3c8c](https://github.com/NativeScript/NativeScript/commit/e2c3c8c))
+* **ios-bottom-navigation:** add icon rendering mode ([#7738](https://github.com/NativeScript/NativeScript/issues/7738)) ([ff6d89f](https://github.com/NativeScript/NativeScript/commit/ff6d89f))
+* **android-tabs/bottom-navigation:** fix tab resource icon size based on specification ([#7737](https://github.com/NativeScript/NativeScript/issues/7737)) ([f436b6f](https://github.com/NativeScript/NativeScript/commit/f436b6f))
+* **tabs/bottom-navigation:** introduce TabStrip.isIconSizeFixed property ([#7691](https://github.com/NativeScript/NativeScript/issues/7691)) ([8039c2c](https://github.com/NativeScript/NativeScript/commit/8039c2c))
+* **tabs/bottom-navigation:** add support for custom tabstrip ([#7580](https://github.com/NativeScript/NativeScript/issues/7580)) ([acc3436](https://github.com/NativeScript/NativeScript/commit/acc3436))
+* **tabs/bottom-navigation:** inherit TabContentItem from ContentView ([#7629](https://github.com/NativeScript/NativeScript/issues/7629)) ([72ca461](https://github.com/NativeScript/NativeScript/commit/72ca461))
+* **tabs/bottom-navigation:** flexible font icon usage ([#7672](https://github.com/NativeScript/NativeScript/issues/7672)) ([c0b8db4](https://github.com/NativeScript/NativeScript/commit/c0b8db4))
+* **tabs:** emit tabStripItem tap event ([#7693](https://github.com/NativeScript/NativeScript/issues/7693)) ([b0d1c91](https://github.com/NativeScript/NativeScript/commit/b0d1c91))
+* **tabs/bottom-navigation:** add TabStrip.itemTap event ([#7711](https://github.com/NativeScript/NativeScript/issues/7711)) ([55c9cc9](https://github.com/NativeScript/NativeScript/commit/55c9cc9))
+
+
## [6.0.7](https://github.com/NativeScript/NativeScript/compare/6.0.4...6.0.7) (2019-08-22)
@@ -32,6 +63,25 @@
+
+## [6.0.5](https://github.com/NativeScript/NativeScript/compare/6.0.4...6.0.5) (2019-08-02)
+
+
+### Bug Fixes
+
+* **observable-array:** splice to notify correct amount of added items ([#7426](https://github.com/NativeScript/NativeScript/issues/7426)) ([5e14de6](https://github.com/NativeScript/NativeScript/commit/5e14de6))
+* added missing openFile method in ios utils ([#7431](https://github.com/NativeScript/NativeScript/issues/7431)) ([cb58cab](https://github.com/NativeScript/NativeScript/commit/cb58cab))
+* full Unicode support in xml ([#7428](https://github.com/NativeScript/NativeScript/issues/7428)) ([b8659e6](https://github.com/NativeScript/NativeScript/commit/b8659e6))
+* **timer:** setTimeout/setInterval support for boolean period ([#7569](https://github.com/NativeScript/NativeScript/issues/7569)) ([a569bb2](https://github.com/NativeScript/NativeScript/commit/a569bb2))
+
+
+### Features
+
+* **bottom-navigation-ios:** limit to 5 items ([5815246](https://github.com/NativeScript/NativeScript/commit/5815246))
+* split globals to support smaller worker chunks ([0ee0b67](https://github.com/NativeScript/NativeScript/commit/0ee0b67))
+
+
+
## [6.0.4](https://github.com/NativeScript/NativeScript/compare/6.0.3...6.0.4) (2019-07-30)
diff --git a/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml b/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml
index c13ec26c9..20aa4a2da 100644
--- a/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml
+++ b/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml
@@ -11,7 +11,7 @@
-
+
diff --git a/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml b/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml
index 66266e701..00fe8dae7 100644
--- a/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml
+++ b/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml
@@ -3,23 +3,8 @@
-
-
-
-
-
+
@@ -71,26 +56,4 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml b/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml
index 004de8346..7b1657fb9 100644
--- a/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml
+++ b/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml b/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml
index 1305f2a06..23442767f 100644
--- a/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml
+++ b/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/package.json b/package.json
index 905c56dca..3c57d4ab9 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"shelljs": "^0.7.0",
"source-map-support": "^0.4.17",
"time-grunt": "1.3.0",
- "tslib": "^1.9.3",
+ "tslib": "1.10.0",
"tslint": "^5.4.3",
"typedoc": "^0.13.0",
"typedoc-plugin-external-module-name": "git://github.com/PanayotCankov/typedoc-plugin-external-module-name.git#with-js",
diff --git a/tests/app/ui/styling/root-views-css-classes-tests.ts b/tests/app/ui/styling/root-views-css-classes-tests.ts
index aa636f92b..b259f57b5 100644
--- a/tests/app/ui/styling/root-views-css-classes-tests.ts
+++ b/tests/app/ui/styling/root-views-css-classes-tests.ts
@@ -22,6 +22,7 @@ import {
} from "tns-core-modules/ui/core/view/view-common";
import { DeviceType } from "tns-core-modules/ui/enums/enums";
+const CLASS_NAME = "class-name";
const ROOT_CSS_CLASS = "ns-root";
const MODAL_CSS_CLASS = "ns-modal";
const ANDROID_PLATFORM_CSS_CLASS = "ns-android";
@@ -32,18 +33,41 @@ const PORTRAIT_ORIENTATION_CSS_CLASS = "ns-portrait";
const LANDSCAPE_ORIENTATION_CSS_CLASS = "ns-landscape";
const UNKNOWN_ORIENTATION_CSS_CLASS = "ns-unknown";
-export function test_root_view_root_css_class() {
- const rootViewCssClasses = getRootView().cssClasses;
+function _test_root_view_root_css_class(shouldSetClassName: boolean) {
+ const rootView = getRootView();
+ if (shouldSetClassName) {
+ rootView.className = CLASS_NAME;
+ }
+ const rootViewCssClasses = rootView.cssClasses;
TKUnit.assertTrue(rootViewCssClasses.has(
ROOT_CSS_CLASS),
`${ROOT_CSS_CLASS} CSS class is missing`
);
+
+ if (shouldSetClassName) {
+ TKUnit.assertTrue(rootViewCssClasses.has(
+ CLASS_NAME),
+ `${CLASS_NAME} CSS class is missing`
+ );
+ }
}
-export function test_root_view_platform_css_class() {
- const rootViewCssClasses = getRootView().cssClasses;
+export function test_root_view_root_css_class() {
+ _test_root_view_root_css_class(false);
+}
+export function test_root_view_class_name_preserve_root_css_class() {
+ _test_root_view_root_css_class(true);
+}
+
+function _test_root_view_platform_css_class(shouldSetClassName: boolean) {
+ const rootView = getRootView();
+ if (shouldSetClassName) {
+ rootView.className = CLASS_NAME;
+ }
+
+ const rootViewCssClasses = rootView.cssClasses;
if (isAndroid) {
TKUnit.assertTrue(rootViewCssClasses.has(
ANDROID_PLATFORM_CSS_CLASS),
@@ -63,10 +87,30 @@ export function test_root_view_platform_css_class() {
`${ANDROID_PLATFORM_CSS_CLASS} CSS class is present`
);
}
+
+ if (shouldSetClassName) {
+ TKUnit.assertTrue(rootViewCssClasses.has(
+ CLASS_NAME),
+ `${CLASS_NAME} CSS class is missing`
+ );
+ }
}
-export function test_root_view_device_type_css_class() {
- const rootViewCssClasses = getRootView().cssClasses;
+export function test_root_view_platform_css_class() {
+ _test_root_view_platform_css_class(false);
+}
+
+export function test_root_view_class_name_preserve_platform_css_class() {
+ _test_root_view_platform_css_class(true);
+}
+
+function _test_root_view_device_type_css_class(shouldSetClassName: boolean) {
+ const rootView = getRootView();
+ if (shouldSetClassName) {
+ rootView.className = CLASS_NAME;
+ }
+
+ const rootViewCssClasses = rootView.cssClasses;
const deviceType = device.deviceType;
if (deviceType === DeviceType.Phone) {
@@ -88,10 +132,30 @@ export function test_root_view_device_type_css_class() {
`${PHONE_DEVICE_TYPE_CSS_CLASS} CSS class is present`
);
}
+
+ if (shouldSetClassName) {
+ TKUnit.assertTrue(rootViewCssClasses.has(
+ CLASS_NAME),
+ `${CLASS_NAME} CSS class is missing`
+ );
+ }
}
-export function test_root_view_orientation_css_class() {
- const rootViewCssClasses = getRootView().cssClasses;
+export function test_root_view_device_type_css_class() {
+ _test_root_view_device_type_css_class(false);
+}
+
+export function test_root_view_class_name_preserve_device_type_css_class() {
+ _test_root_view_device_type_css_class(true);
+}
+
+function _test_root_view_orientation_css_class(shouldSetClassName: boolean) {
+ const rootView = getRootView();
+ if (shouldSetClassName) {
+ rootView.className = CLASS_NAME;
+ }
+
+ const rootViewCssClasses = rootView.cssClasses;
let appOrientation;
if (isAndroid) {
@@ -140,9 +204,24 @@ export function test_root_view_orientation_css_class() {
`${PORTRAIT_ORIENTATION_CSS_CLASS} CSS class is present`
);
}
+
+ if (shouldSetClassName) {
+ TKUnit.assertTrue(rootViewCssClasses.has(
+ CLASS_NAME),
+ `${CLASS_NAME} CSS class is missing`
+ );
+ }
}
-export function test_modal_root_view_modal_css_class() {
+export function test_root_view_orientation_css_class() {
+ _test_root_view_orientation_css_class(false);
+}
+
+export function test_root_view_class_name_preserve_orientation_css_class() {
+ _test_root_view_orientation_css_class(true);
+}
+
+function _test_modal_root_view_modal_css_class(shouldSetClassName: boolean) {
let modalClosed = false;
const modalCloseCallback = function () {
@@ -153,7 +232,20 @@ export function test_modal_root_view_modal_css_class() {
const page = args.object;
page.off(View.shownModallyEvent, modalPageShownModallyEventHandler);
- TKUnit.assertTrue(_rootModalViews[0].cssClasses.has(MODAL_CSS_CLASS));
+ const rootModalView = _rootModalViews[0];
+ if (shouldSetClassName) {
+ rootModalView.className = CLASS_NAME;
+ }
+
+ const rootModalViewCssClasses = rootModalView.cssClasses;
+ TKUnit.assertTrue(rootModalViewCssClasses.has(MODAL_CSS_CLASS),
+ `${MODAL_CSS_CLASS} CSS class is missing`);
+
+ if (shouldSetClassName) {
+ TKUnit.assertTrue(rootModalViewCssClasses.has(CLASS_NAME),
+ `${CLASS_NAME} CSS class is missing`);
+ }
+
args.closeCallback();
};
@@ -186,3 +278,11 @@ export function test_modal_root_view_modal_css_class() {
helper.navigate(hostPageFactory);
TKUnit.waitUntilReady(() => modalClosed);
}
+
+export function test_modal_root_view_modal_css_class() {
+ _test_modal_root_view_modal_css_class(false);
+}
+
+export function test_modal_root_view_class_name_preserve_modal_css_class() {
+ _test_modal_root_view_modal_css_class(true);
+}
diff --git a/tests/app/ui/styling/style-tests.ts b/tests/app/ui/styling/style-tests.ts
index d3c5cfa3d..004ddeacd 100644
--- a/tests/app/ui/styling/style-tests.ts
+++ b/tests/app/ui/styling/style-tests.ts
@@ -225,7 +225,7 @@ export function test_multiple_class_selector() {
let page = helper.getClearCurrentPage();
let btnWithClasses: buttonModule.Button;
- page.css = ".style1 { color: red; } .style2 { background-color: blue } ";
+ page.css = ".style1 { color: red; } .style2 { background-color: blue; } ";
//// Will be styled
btnWithClasses = new buttonModule.Button();
@@ -239,6 +239,24 @@ export function test_multiple_class_selector() {
helper.assertViewBackgroundColor(btnWithClasses, "#0000FF");
}
+export function test_class_selector_overwriting() {
+ const page = helper.getClearCurrentPage();
+ page.css = ".first { color: red; } .second { background-color: blue; }";
+
+ const btnWithClass = new buttonModule.Button();
+ const stack = new stackModule.StackLayout();
+ page.content = stack;
+ stack.addChild(btnWithClass);
+
+ btnWithClass.className = "first";
+ helper.assertViewColor(btnWithClass, "#FF0000");
+ TKUnit.assert(btnWithClass.style.backgroundColor === undefined, " Background color should not have a value");
+
+ btnWithClass.className = "second";
+ TKUnit.assert(btnWithClass.style.color === undefined, "Color should not have a value");
+ helper.assertViewBackgroundColor(btnWithClass, "#0000FF");
+}
+
export function test_id_selector() {
let page = helper.getClearCurrentPage();
page.style.color = unsetValue;
@@ -1497,7 +1515,7 @@ export function test_css_calc() {
TKUnit.assertEqual(stack.width as any, 125, "Stack - width === 125");
(stack as any).style = `width: calc(100% / 2)`;
- TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
+ TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
// This should log an error for the invalid css-calc expression, but not cause a crash
stack.className = "invalid-css-calc";
@@ -1568,7 +1586,7 @@ export function test_nested_css_calc() {
(stack as any).style = `width: calc(100% * calc(1 / 2)`;
- TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
+ TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
}
export function test_css_variables() {
@@ -1678,7 +1696,7 @@ export function test_css_calc_and_variables() {
// Test setting the CSS variable via the style-attribute, this should override any value set via css-class
(stack as any).style = `${cssVarName}: 0.5`;
- TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
+ TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
}
export function test_css_variable_fallback() {
@@ -1819,10 +1837,10 @@ export function test_nested_css_calc_and_variables() {
// Test setting the CSS variable via the style-attribute, this should override any value set via css-class
stack.className = "wide";
(stack as any).style = `${cssVarName}: 0.25`;
- TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
+ TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%");
stack.className = "nested";
- TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 1 }, "Stack - width === 100%");
+ TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 1 }, "Stack - width === 100%");
}
export function test_css_variable_is_applied_to_normal_properties() {
diff --git a/tns-core-modules/application/application-common.ts b/tns-core-modules/application/application-common.ts
index 6c6a92de4..c59774ea2 100644
--- a/tns-core-modules/application/application-common.ts
+++ b/tns-core-modules/application/application-common.ts
@@ -40,6 +40,8 @@ import {
LoadAppCSSEventData,
UnhandledErrorEventData
} from "./application";
+
+import { CLASS_PREFIX, pushToRootViewCssClasses, removeFromRootViewCssClasses } from "../css/system-classes";
import { DeviceOrientation } from "../ui/enums/enums";
export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData };
@@ -54,11 +56,10 @@ export const uncaughtErrorEvent = "uncaughtError";
export const discardedErrorEvent = "discardedError";
export const orientationChangedEvent = "orientationChanged";
-export const CSS_CLASS_PREFIX = "ns-";
const ORIENTATION_CSS_CLASSES = [
- `${CSS_CLASS_PREFIX}${DeviceOrientation.portrait}`,
- `${CSS_CLASS_PREFIX}${DeviceOrientation.landscape}`,
- `${CSS_CLASS_PREFIX}${DeviceOrientation.unknown}`
+ `${CLASS_PREFIX}${DeviceOrientation.portrait}`,
+ `${CLASS_PREFIX}${DeviceOrientation.landscape}`,
+ `${CLASS_PREFIX}${DeviceOrientation.unknown}`
];
let cssFile: string = "./app.css";
@@ -126,9 +127,15 @@ export function loadAppCss(): void {
}
export function orientationChanged(rootView: View, newOrientation: "portrait" | "landscape" | "unknown"): void {
- const newOrientationCssClass = `${CSS_CLASS_PREFIX}${newOrientation}`;
+ const newOrientationCssClass = `${CLASS_PREFIX}${newOrientation}`;
if (!rootView.cssClasses.has(newOrientationCssClass)) {
- ORIENTATION_CSS_CLASSES.forEach(c => rootView.cssClasses.delete(c));
+ const removeCssClass = (c: string) => {
+ removeFromRootViewCssClasses(c);
+ rootView.cssClasses.delete(c);
+ };
+
+ ORIENTATION_CSS_CLASSES.forEach(c => removeCssClass(c));
+ pushToRootViewCssClasses(newOrientationCssClass);
rootView.cssClasses.add(newOrientationCssClass);
rootView._onCssStateChange();
}
diff --git a/tns-core-modules/application/application.d.ts b/tns-core-modules/application/application.d.ts
index 8ef338b76..672e55cc5 100644
--- a/tns-core-modules/application/application.d.ts
+++ b/tns-core-modules/application/application.d.ts
@@ -53,11 +53,6 @@ export const lowMemoryEvent: string;
*/
export const orientationChangedEvent: string;
-/**
- * String value "ns-" used for CSS class prefix.
- */
-export const CSS_CLASS_PREFIX: string;
-
/**
* Event data containing information for the application events.
*/
diff --git a/tns-core-modules/application/application.ios.ts b/tns-core-modules/application/application.ios.ts
index 49e9b80cb..37a834096 100644
--- a/tns-core-modules/application/application.ios.ts
+++ b/tns-core-modules/application/application.ios.ts
@@ -1,4 +1,3 @@
-
import {
ApplicationEventData,
CssChangedEventData,
@@ -9,9 +8,8 @@ import {
} from ".";
import {
- CSS_CLASS_PREFIX, displayedEvent, exitEvent, getCssFileName, launchEvent, livesync,
- lowMemoryEvent, notify, on, orientationChanged, orientationChangedEvent, resumeEvent,
- setApplication, suspendEvent
+ displayedEvent, exitEvent, getCssFileName, launchEvent, livesync, lowMemoryEvent, notify, on,
+ orientationChanged, orientationChangedEvent, resumeEvent, setApplication, suspendEvent
} from "./application-common";
// First reexport so that app module is initialized.
@@ -19,18 +17,15 @@ export * from "./application-common";
// TODO: Remove this and get it from global to decouple builder for angular
import { createViewFromEntry } from "../ui/builder";
+import { CLASS_PREFIX, getRootViewCssClasses, pushToRootViewCssClasses } from "../css/system-classes";
import { ios as iosView, View } from "../ui/core/view";
import { Frame, NavigationEntry } from "../ui/frame";
import { device } from "../platform/platform";
import { profile } from "../profiling";
import { ios } from "../utils/utils";
-const ROOT = "root";
const IOS_PLATFORM = "ios";
-const ROOT_VIEW_CSS_CLASSES = [
- `${CSS_CLASS_PREFIX}${ROOT}`,
- `${CSS_CLASS_PREFIX}${IOS_PLATFORM}`
-];
+
const getVisibleViewController = ios.getVisibleViewController;
// NOTE: UIResponder with implementation of window - related to https://github.com/NativeScript/ios-runtime/issues/430
@@ -317,9 +312,12 @@ function createRootView(v?: View) {
}
const deviceType = device.deviceType.toLowerCase();
- ROOT_VIEW_CSS_CLASSES.push(`${CSS_CLASS_PREFIX}${deviceType}`);
- ROOT_VIEW_CSS_CLASSES.push(`${CSS_CLASS_PREFIX}${iosApp.orientation}`);
- ROOT_VIEW_CSS_CLASSES.forEach(c => rootView.cssClasses.add(c));
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${IOS_PLATFORM}`);
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${deviceType}`);
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${iosApp.orientation}`);
+
+ const rootViewCssClasses = getRootViewCssClasses();
+ rootViewCssClasses.forEach(c => rootView.cssClasses.add(c));
return rootView;
}
diff --git a/tns-core-modules/css/system-classes.d.ts b/tns-core-modules/css/system-classes.d.ts
new file mode 100644
index 000000000..98f7ee59e
--- /dev/null
+++ b/tns-core-modules/css/system-classes.d.ts
@@ -0,0 +1,30 @@
+/**
+ * @module "system-classes"
+ */ /** */
+
+/**
+ * String value "ns-" used for CSS system class prefix.
+ */
+export const CLASS_PREFIX: string;
+
+/**
+ * Gets CSS system class for modal root view.
+ */
+export function getModalRootViewCssClass(): string;
+
+/**
+ * Gets CSS system classes for root view.
+ */
+export function getRootViewCssClasses(): string[];
+
+/**
+ * * Appends new CSS class to the system classes and returns the new length of the array.
+ * @param value New CSS system class.
+ */
+export function pushToRootViewCssClasses(value: string): number;
+
+/**
+ * Removes CSS class from the system classes and returns it.
+ * @param value
+ */
+export function removeFromRootViewCssClasses(value: string): string;
diff --git a/tns-core-modules/css/system-classes.ts b/tns-core-modules/css/system-classes.ts
new file mode 100644
index 000000000..6e2f7e80c
--- /dev/null
+++ b/tns-core-modules/css/system-classes.ts
@@ -0,0 +1,32 @@
+const MODAL = "modal";
+const ROOT = "root";
+
+export const CLASS_PREFIX = "ns-";
+
+const modalRootViewCssClass = `${CLASS_PREFIX}${MODAL}`;
+const rootViewCssClasses = [`${CLASS_PREFIX}${ROOT}`];
+
+export function getModalRootViewCssClass(): string {
+ return modalRootViewCssClass;
+}
+
+export function getRootViewCssClasses(): string[] {
+ return rootViewCssClasses;
+}
+
+export function pushToRootViewCssClasses(value: string): number {
+ rootViewCssClasses.push(value);
+
+ return rootViewCssClasses.length;
+}
+
+export function removeFromRootViewCssClasses(value: string): string {
+ const index = rootViewCssClasses.indexOf(value);
+ let removedElement;
+
+ if (index > -1) {
+ removedElement = rootViewCssClasses.splice(index, 1);
+ }
+
+ return removedElement;
+}
diff --git a/tns-core-modules/package.json b/tns-core-modules/package.json
index 9e2061a64..f3070f538 100644
--- a/tns-core-modules/package.json
+++ b/tns-core-modules/package.json
@@ -28,7 +28,7 @@
"dependencies": {
"reduce-css-calc": "^2.1.6",
"tns-core-modules-widgets": "next",
- "tslib": "^1.9.3"
+ "tslib": "1.10.0"
},
"devDependencies": {
"@types/node": "~7.0.5",
diff --git a/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts b/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts
index 4da582b59..0fafaf048 100644
--- a/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts
+++ b/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts
@@ -540,23 +540,15 @@ export class BottomNavigation extends TabNavigationBase {
// ICON
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (iconSource) {
- if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
- tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
- if (tabItemSpec.iconId === 0) {
- // TODO:
- // traceMissingIcon(iconSource);
- }
- } else {
- const icon = this.getIcon(tabStripItem);
+ const icon = this.getIcon(tabStripItem);
- if (icon) {
- // TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
- // tslint:disable-next-line:deprecation
- tabItemSpec.iconDrawable = icon;
- } else {
- // TODO:
- // traceMissingIcon(iconSource);
- }
+ if (icon) {
+ // TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
+ // tslint:disable-next-line:deprecation
+ tabItemSpec.iconDrawable = icon;
+ } else {
+ // TODO:
+ // traceMissingIcon(iconSource);
}
}
}
diff --git a/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts b/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts
index 7ea8e43dd..2d2966105 100644
--- a/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts
+++ b/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts
@@ -531,7 +531,15 @@ export class BottomNavigation extends TabNavigationBase {
}
private getIconRenderingMode(): UIImageRenderingMode {
- return UIImageRenderingMode.AlwaysOriginal;
+ switch (this.tabStrip && this.tabStrip.iosIconRenderingMode) {
+ case "alwaysOriginal":
+ return UIImageRenderingMode.AlwaysOriginal;
+ case "alwaysTemplate":
+ return UIImageRenderingMode.AlwaysTemplate;
+ case "automatic":
+ default:
+ return UIImageRenderingMode.Automatic;
+ }
}
private getIcon(tabStripItem: TabStripItem): UIImage {
@@ -547,10 +555,12 @@ export class BottomNavigation extends TabNavigationBase {
const color = target.style.color;
const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(";");
+ let isFontIcon = false;
let image: UIImage = this._iconsCache[iconTag];
if (!image) {
let is = new ImageSource;
if (isFontIconURI(iconSource)) {
+ isFontIcon = true;
const fontIconCode = iconSource.split("//")[1];
is = fromFontIconCode(fontIconCode, font, color);
} else {
@@ -564,7 +574,11 @@ export class BottomNavigation extends TabNavigationBase {
image = this.getFixedSizeIcon(image);
}
- const originalRenderedImage = image.imageWithRenderingMode(this.getIconRenderingMode());
+ let renderingMode: UIImageRenderingMode = UIImageRenderingMode.AlwaysOriginal;
+ if (!isFontIcon) {
+ renderingMode = this.getIconRenderingMode();
+ }
+ const originalRenderedImage = image.imageWithRenderingMode(renderingMode);
this._iconsCache[iconTag] = originalRenderedImage;
image = originalRenderedImage;
} else {
diff --git a/tns-core-modules/ui/core/view-base/view-base.ts b/tns-core-modules/ui/core/view-base/view-base.ts
index 06ec4c996..89dc23607 100644
--- a/tns-core-modules/ui/core/view-base/view-base.ts
+++ b/tns-core-modules/ui/core/view-base/view-base.ts
@@ -1,10 +1,13 @@
// Definitions.
import { ViewBase as ViewBaseDefinition } from ".";
+import {
+ AlignSelf, FlexGrow, FlexShrink, FlexWrapBefore, Order
+} from "../../layouts/flexbox-layout";
import { Page } from "../../page";
-import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "../../layouts/flexbox-layout";
// Types.
import { Property, CssProperty, CssAnimationProperty, InheritedProperty, Style, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, initNativeView } from "../properties";
+import { getModalRootViewCssClass, getRootViewCssClasses } from "../../../css/system-classes";
import { Source } from "../../../utils/debug";
import { Binding, BindingOptions, Observable, WrappedValue, PropertyChangeData, traceEnabled, traceWrite, traceCategories } from "../bindable";
import { isIOS, isAndroid } from "../../../platform";
@@ -22,10 +25,9 @@ export { isIOS, isAndroid, layout, Color };
export * from "../bindable";
export * from "../properties";
+import * as dnm from "../../../debugger/dom-node";
import * as ssm from "../../styling/style-scope";
-// import { DOMNode } from "../../../debugger/dom-node";
-import * as dnm from "../../../debugger/dom-node";
let domNodeModule: typeof dnm;
function ensuredomNodeModule(): void {
@@ -1036,11 +1038,26 @@ bindingContextProperty.register(ViewBase);
export const classNameProperty = new Property({
name: "className",
valueChanged(view: ViewBase, oldValue: string, newValue: string) {
- let classes = view.cssClasses;
- classes.clear();
- if (typeof newValue === "string" && newValue !== "") {
- newValue.split(" ").forEach(c => classes.add(c));
+ const cssClasses = view.cssClasses;
+
+ const modalViewCssClass = getModalRootViewCssClass();
+ const rootViewCssClasses = getRootViewCssClasses();
+
+ const shouldAddModalRootViewCssClass = cssClasses.has(modalViewCssClass);
+ const shouldAddRootViewCssClasses = cssClasses.has(rootViewCssClasses[0]);
+
+ cssClasses.clear();
+
+ if (shouldAddModalRootViewCssClass) {
+ cssClasses.add(modalViewCssClass);
+ } else if (shouldAddRootViewCssClasses) {
+ rootViewCssClasses.forEach(c => cssClasses.add(c));
}
+
+ if (typeof newValue === "string" && newValue !== "") {
+ newValue.split(" ").forEach(c => cssClasses.add(c));
+ }
+
view._onCssStateChange();
}
});
@@ -1058,4 +1075,4 @@ export function booleanConverter(v: string): boolean {
}
throw new Error(`Invalid boolean: ${v}`);
-}
\ No newline at end of file
+}
diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts
index d09e09929..4e9352358 100644
--- a/tns-core-modules/ui/core/view/view-common.ts
+++ b/tns-core-modules/ui/core/view/view-common.ts
@@ -5,9 +5,8 @@ import {
} from ".";
import {
- ViewBase, Property, booleanConverter, EventData, layout,
- getEventOrGestureName, traceEnabled, traceWrite, traceCategories,
- InheritedProperty, ShowModalOptions
+ booleanConverter, EventData, getEventOrGestureName, InheritedProperty, layout,
+ Property, ShowModalOptions, traceCategories, traceEnabled, traceWrite, ViewBase
} from "../view-base";
import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties";
@@ -20,6 +19,7 @@ import {
fromString as gestureFromString
} from "../../gestures";
+import { getModalRootViewCssClass } from "../../../css/system-classes";
import { createViewFromEntry } from "../../builder";
import { sanitizeModuleName } from "../../builder/module-name-sanitizer";
import { StyleScope } from "../../styling/style-scope";
@@ -31,9 +31,6 @@ export * from "../view-base";
export { LinearGradient };
import * as am from "../../animation";
-import { CSS_CLASS_PREFIX } from "../../../application";
-
-const MODAL = "modal";
let animationModule: typeof am;
function ensureAnimationModule() {
@@ -373,7 +370,9 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
protected _showNativeModalView(parent: ViewCommon, options: ShowModalOptions) {
_rootModalViews.push(this);
- this.cssClasses.add(`${CSS_CLASS_PREFIX}${MODAL}`);
+
+ const modalRootViewCssClass = getModalRootViewCssClass();
+ this.cssClasses.add(modalRootViewCssClass);
parent._modal = this;
this._modalParent = parent;
diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts
index f93d9a874..fc52f37b8 100644
--- a/tns-core-modules/ui/frame/frame.android.ts
+++ b/tns-core-modules/ui/frame/frame.android.ts
@@ -7,9 +7,10 @@ import { Page } from "../page";
// Types.
import * as application from "../../application";
+
import {
- FrameBase, goBack, _stack, NavigationType,
- Observable, View, traceCategories, traceEnabled, traceError, traceWrite
+ _stack, FrameBase, goBack, NavigationType, Observable,
+ traceCategories, traceEnabled, traceError, traceWrite, View
} from "./frame-common";
import {
@@ -19,6 +20,7 @@ import {
// TODO: Remove this and get it from global to decouple builder for angular
import { createViewFromEntry } from "../builder";
+import { CLASS_PREFIX, getRootViewCssClasses, pushToRootViewCssClasses } from "../../css/system-classes";
import { device } from "../../platform/platform";
import { profile } from "../../profiling";
@@ -32,12 +34,7 @@ interface AnimatorState {
transitionName: string;
}
-const ROOT = "root";
const ANDROID_PLATFORM = "android";
-const ROOT_VIEW_CSS_CLASSES = [
- `${application.CSS_CLASS_PREFIX}${ROOT}`,
- `${application.CSS_CLASS_PREFIX}${ANDROID_PLATFORM}`
-];
const INTENT_EXTRA = "com.tns.activity";
const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId";
@@ -1289,9 +1286,12 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
activityRootViewsMap.set(rootView._domId, new WeakRef(rootView));
const deviceType = device.deviceType.toLowerCase();
- ROOT_VIEW_CSS_CLASSES.push(`${application.CSS_CLASS_PREFIX}${deviceType}`);
- ROOT_VIEW_CSS_CLASSES.push(`${application.CSS_CLASS_PREFIX}${application.android.orientation}`);
- ROOT_VIEW_CSS_CLASSES.forEach(c => this._rootView.cssClasses.add(c));
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${ANDROID_PLATFORM}`);
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${deviceType}`);
+ pushToRootViewCssClasses(`${CLASS_PREFIX}${application.android.orientation}`);
+
+ const rootViewCssClasses = getRootViewCssClasses();
+ rootViewCssClasses.forEach(c => this._rootView.cssClasses.add(c));
}
// Initialize native visual tree;
diff --git a/tns-core-modules/ui/list-picker/list-picker.android.ts b/tns-core-modules/ui/list-picker/list-picker.android.ts
index ccc9ea5e1..328af50fd 100644
--- a/tns-core-modules/ui/list-picker/list-picker.android.ts
+++ b/tns-core-modules/ui/list-picker/list-picker.android.ts
@@ -1,8 +1,12 @@
import { ListPickerBase, selectedIndexProperty, itemsProperty, colorProperty, Color } from "./list-picker-common";
import { ItemsSource } from ".";
+import { device } from "../../platform";
+import lazy from "../../utils/lazy";
export * from "./list-picker-common";
+const sdkVersion = lazy(() => parseInt(device.sdkVersion));
+
interface Formatter {
new (owner: ListPicker): android.widget.NumberPicker.Formatter;
}
@@ -90,7 +94,14 @@ export class ListPicker extends ListPickerBase {
super.initNativeView();
initializeNativeClasses();
const nativeView = this.nativeViewProtected;
- this._selectorWheelPaint = getSelectorWheelPaint(nativeView);
+
+ // api28 and lower uses reflection to retrieve and manipulate
+ // android.graphics.Paint object; this is no longer allowed on newer api levels but
+ // equivalent public methods are exposed on api29+ directly on the native widget
+ if (sdkVersion() < 29) {
+ this._selectorWheelPaint = getSelectorWheelPaint(nativeView);
+ }
+
const formatter = new Formatter(this);
nativeView.setFormatter(formatter);
(nativeView).formatter = formatter;
@@ -153,28 +164,33 @@ export class ListPicker extends ListPickerBase {
selectedIndexProperty.coerce(this);
}
- [colorProperty.getDefault](): { wheelColor: number, textColor: number } {
- const editText = (this.nativeViewProtected).editText;
-
- return {
- wheelColor: this._selectorWheelPaint.getColor(),
- textColor: editText ? editText.getTextColors().getDefaultColor() : -1
- };
- }
- [colorProperty.setNative](value: { wheelColor: number, textColor: number } | Color) {
- let color: number;
- let wheelColor: number;
- if (value instanceof Color) {
- color = wheelColor = value.android;
- } else {
- color = value.textColor;
- wheelColor = value.wheelColor;
+ [colorProperty.getDefault](): number {
+ // api28 and lower uses reflection to retrieve and manipulate
+ // android.graphics.Paint object; this is no longer allowed on newer api levels but
+ // equivalent public methods are exposed on api29+ directly on the native widget
+ if (this._selectorWheelPaint) {
+ return this._selectorWheelPaint.getColor();
}
- this._selectorWheelPaint.setColor(wheelColor);
- const editText = (this.nativeViewProtected).editText;
- if (editText) {
- editText.setTextColor(color);
+ return this.nativeView.getTextColor();
+ }
+ [colorProperty.setNative](value: number | Color) {
+ const color = value instanceof Color ? value.android : value;
+
+ // api28 and lower uses reflection to retrieve and manipulate
+ // android.graphics.Paint object; this is no longer allowed on newer api levels but
+ // equivalent public methods are exposed on api29+ directly on the native widget
+ if (this._selectorWheelPaint) {
+ this._selectorWheelPaint.setColor(color);
+
+ const editText = (this.nativeViewProtected).editText;
+ if (editText) {
+ editText.setTextColor(color);
+ }
+ } else {
+ // api29 and higher native implementation sets
+ // both wheel color and input text color with single call
+ this.nativeView.setTextColor(color);
}
}
}
diff --git a/tns-core-modules/ui/tabs/tabs.android.ts b/tns-core-modules/ui/tabs/tabs.android.ts
index c2334f859..d5cfbf212 100644
--- a/tns-core-modules/ui/tabs/tabs.android.ts
+++ b/tns-core-modules/ui/tabs/tabs.android.ts
@@ -615,23 +615,15 @@ export class Tabs extends TabsBase {
// ICON
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (iconSource) {
- if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
- tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
- if (tabItemSpec.iconId === 0) {
- // TODO:
- // traceMissingIcon(iconSource);
- }
- } else {
- const icon = this.getIcon(tabStripItem);
+ const icon = this.getIcon(tabStripItem);
- if (icon) {
- // TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
- // tslint:disable-next-line:deprecation
- tabItemSpec.iconDrawable = icon;
- } else {
- // TODO:
- // traceMissingIcon(iconSource);
- }
+ if (icon) {
+ // TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
+ // tslint:disable-next-line:deprecation
+ tabItemSpec.iconDrawable = icon;
+ } else {
+ // TODO:
+ // traceMissingIcon(iconSource);
}
}
}
diff --git a/tns-core-modules/ui/tabs/tabs.ios.ts b/tns-core-modules/ui/tabs/tabs.ios.ts
index 4a664cb1a..be26ca1b0 100644
--- a/tns-core-modules/ui/tabs/tabs.ios.ts
+++ b/tns-core-modules/ui/tabs/tabs.ios.ts
@@ -82,26 +82,24 @@ class UIPageViewControllerImpl extends UIPageViewController {
public viewDidLoad(): void {
const owner = this._owner.get();
- if (owner.tabStrip) {
- const tabBarItems = owner.tabBarItems;
- const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds);
+ const tabBarItems = owner.tabBarItems;
+ const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds);
- if (tabBarItems && tabBarItems.length) {
- tabBar.items = NSArray.arrayWithArray(tabBarItems);
- }
-
- tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner));
- tabBar.tintColor = UIColor.blueColor;
- tabBar.barTintColor = UIColor.whiteColor;
- tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal);
- tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected);
- tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin;
- tabBar.alignment = MDCTabBarAlignment.Leading;
- tabBar.sizeToFit();
-
- this.tabBar = tabBar;
- this.view.addSubview(tabBar);
+ if (tabBarItems && tabBarItems.length) {
+ tabBar.items = NSArray.arrayWithArray(tabBarItems);
}
+
+ tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner));
+ tabBar.tintColor = UIColor.blueColor;
+ tabBar.barTintColor = UIColor.whiteColor;
+ tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal);
+ tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected);
+ tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin;
+ tabBar.alignment = MDCTabBarAlignment.Leading;
+ tabBar.sizeToFit();
+
+ this.tabBar = tabBar;
+ this.view.addSubview(tabBar);
}
public viewWillAppear(animated: boolean): void {
@@ -152,13 +150,22 @@ class UIPageViewControllerImpl extends UIPageViewController {
scrollViewHeight = this.view.frame.size.height - safeAreaInsetsBottom;
}
- const parent = owner.parent;
+ let parent = owner.parent;
+
+ // Handle Angular scenario where Tabs is in a ProxyViewContainer
+ // It is possible to wrap components in ProxyViewContainers indefinitely
+ while (parent && !parent.nativeViewProtected) {
+ parent = parent.parent;
+ }
+
if (parent && majorVersion > 10) {
// TODO: Figure out a better way to handle ViewController nesting/Safe Area nesting
- tabBarTop = Math.max(tabBarTop, owner.parent.nativeView.safeAreaInsets.top);
+ tabBarTop = Math.max(tabBarTop, parent.nativeView.safeAreaInsets.top);
}
this.tabBar.frame = CGRectMake(0, tabBarTop, this.tabBar.frame.size.width, tabBarHeight);
+ } else {
+ this.tabBar.hidden = true;
}
const subViews: NSArray = this.view.subviews;
@@ -885,6 +892,7 @@ export class Tabs extends TabsBase {
}
private getIconRenderingMode(): UIImageRenderingMode {
+ // MDCTabBar doesn't work with rendering mode AlwaysTemplate
return UIImageRenderingMode.AlwaysOriginal;
}
diff --git a/tns-core-modules/ui/utils.android.ts b/tns-core-modules/ui/utils.android.ts
index b253eba9e..b8e7bc80b 100644
--- a/tns-core-modules/ui/utils.android.ts
+++ b/tns-core-modules/ui/utils.android.ts
@@ -10,4 +10,4 @@
export function _layoutRootView(rootView: any, parentBounds: any) {
throw new Error("Not implemented for Android");
}
-}
\ No newline at end of file
+}
diff --git a/tns-core-modules/ui/utils.d.ts b/tns-core-modules/ui/utils.d.ts
index e54e208bd..a30b9f6f3 100644
--- a/tns-core-modules/ui/utils.d.ts
+++ b/tns-core-modules/ui/utils.d.ts
@@ -3,6 +3,7 @@
*/
import { View } from "./core/view";
+
export module ios {
/**
* Gets actual height of a [UIView](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/) widget in device pixels.
diff --git a/tns-core-modules/ui/utils.ios.ts b/tns-core-modules/ui/utils.ios.ts
index 21ed98575..de61713bb 100644
--- a/tns-core-modules/ui/utils.ios.ts
+++ b/tns-core-modules/ui/utils.ios.ts
@@ -24,4 +24,4 @@ export module ios {
return utils.layout.toDevicePixels(min);
}
-}
\ No newline at end of file
+}