diff --git a/.github/workflows/apps_automated_android.yml b/.github/workflows/apps_automated_android.yml
index d8483b4448..ff4a3eb088 100644
--- a/.github/workflows/apps_automated_android.yml
+++ b/.github/workflows/apps_automated_android.yml
@@ -31,7 +31,7 @@ jobs:
node-version: 23.5.0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
- uses: nrwl/nx-set-shas@826660b82addbef3abff5fa871492ebad618c9e1 # v4.3.3
+ uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1
with:
main-branch-name: 'main'
@@ -65,7 +65,7 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: Run tests on Android Emulator
- uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # v2.35.0
+ uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2.37.0
with:
api-level: 35
arch: x86_64
diff --git a/.github/workflows/apps_automated_ios.yml b/.github/workflows/apps_automated_ios.yml
index 7fcce34749..7dfb51f331 100644
--- a/.github/workflows/apps_automated_ios.yml
+++ b/.github/workflows/apps_automated_ios.yml
@@ -34,7 +34,7 @@ jobs:
node-version: 23.5.0
- name: Derive appropriate SHAs for base and head for `nx affected` commands
- uses: nrwl/nx-set-shas@826660b82addbef3abff5fa871492ebad618c9e1 # v4.3.3
+ uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1
with:
main-branch-name: 'main'
@@ -52,7 +52,7 @@ jobs:
run: npx nx run-many --target=test --configuration=ci --projects=core
- name: Start iOS Simulator
- uses: futureware-tech/simulator-action@dab10d813144ef59b48d401cd95da151222ef8cd # v4
+ uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # v5
with:
model: 'iPhone 16 Pro'
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index d69dfb2474..6b3ebd28cc 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -19,4 +19,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: 'Dependency Review'
- uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3
\ No newline at end of file
+ uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
\ No newline at end of file
diff --git a/.github/workflows/npm_release_tns_core.yml b/.github/workflows/npm_release_tns_core.yml
index b0c6ab3bbe..c4f405ee63 100644
--- a/.github/workflows/npm_release_tns_core.yml
+++ b/.github/workflows/npm_release_tns_core.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Harden the runner (Audit all outbound calls)
- uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
+ uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1
with:
egress-policy: audit
diff --git a/.github/workflows/npm_release_types.yml b/.github/workflows/npm_release_types.yml
index d99b1ad1cf..4aa5c151e5 100644
--- a/.github/workflows/npm_release_types.yml
+++ b/.github/workflows/npm_release_types.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Harden the runner (Audit all outbound calls)
- uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
+ uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1
with:
egress-policy: audit
diff --git a/.github/workflows/npm_release_webpack.yml b/.github/workflows/npm_release_webpack.yml
index 3df7b98875..8d78e4e624 100644
--- a/.github/workflows/npm_release_webpack.yml
+++ b/.github/workflows/npm_release_webpack.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Harden the runner (Audit all outbound calls)
- uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
+ uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1
with:
egress-policy: audit
diff --git a/.github/workflows/secure_nx_release.yml b/.github/workflows/secure_nx_release.yml
index 643e3ff14b..63bf00c3e9 100644
--- a/.github/workflows/secure_nx_release.yml
+++ b/.github/workflows/secure_nx_release.yml
@@ -45,10 +45,11 @@ jobs:
env:
# Optional: provide Nx Cloud token if used in this repo
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
+ NEXT_PRERELEASE_PROJECT_ALLOWLIST: core,webpack5
steps:
- name: Harden the runner (Audit all outbound calls)
- uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
+ uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1
with:
egress-policy: audit
@@ -124,8 +125,8 @@ jobs:
fi
fi
- # Only consider libs under packages/* and exclude items configured as non-releaseable.
- affected_json=$(npx nx show projects --affected --base "$base" --head "$head" --type lib --projects "packages/*" --exclude "ui-mobile-base,types-minimal,winter-tc,types,types-ios,types-android" --json)
+ # Only consider main-branch prerelease libraries allowed for automatic next publishes.
+ affected_json=$(npx nx show projects --affected --base "$base" --head "$head" --type lib --projects "$NEXT_PRERELEASE_PROJECT_ALLOWLIST" --json)
affected_list=$(printf '%s' "$affected_json" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const a=JSON.parse(s||"[]");process.stdout.write(a.join(","));});')
affected_count=$(printf '%s' "$affected_json" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const a=JSON.parse(s||"[]");process.stdout.write(String(a.length));});')
@@ -337,7 +338,6 @@ jobs:
- name: nx release publish (token, dispatch)
if: ${{ steps.ctx.outputs.mode == 'dispatch' && steps.ctx.outputs.dry_run != 'true' && vars.USE_NPM_TOKEN == 'true' }}
- shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
@@ -353,7 +353,6 @@ jobs:
- name: nx release publish (token, dispatch dry-run)
if: ${{ steps.ctx.outputs.mode == 'dispatch' && inputs.dry-run && vars.USE_NPM_TOKEN == 'true' }}
- shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
@@ -403,9 +402,23 @@ jobs:
- name: Summary
if: always()
run: |
+ mode="${{ steps.ctx.outputs.mode }}"
+
echo "Nx Release completed."
- echo "- mode: ${{ steps.ctx.outputs.mode }}"
+ echo "- mode: ${mode}"
echo "- dist-tag: ${{ steps.ctx.outputs.mode == 'tag' && steps.taginfo.outputs.dist_tag || steps.ctx.outputs.dist_tag }}"
echo "- scope: '${{ steps.ctx.outputs.scope }}'"
+ echo "- next-prerelease-allowlist: ${NEXT_PRERELEASE_PROJECT_ALLOWLIST}"
+ if [[ "$mode" == "main" ]]; then
+ echo "- projects: ${{ steps.affected.outputs.projects }}"
+ elif [[ "$mode" == "dispatch" ]]; then
+ if [[ -n "${{ steps.ctx.outputs.scope }}" ]]; then
+ echo "- projects: ${{ steps.ctx.outputs.scope }}"
+ else
+ echo "- projects: all configured release projects"
+ fi
+ else
+ echo "- project: ${{ steps.taginfo.outputs.project }}"
+ fi
echo "- dry-run: ${{ steps.ctx.outputs.dry_run }}"
echo "- use-token: ${{ vars.USE_NPM_TOKEN == 'true' }}"
diff --git a/apps/automated/src/ui/layouts/flexbox-layout-tests.ts b/apps/automated/src/ui/layouts/flexbox-layout-tests.ts
index 3bbe457cdc..5233cfd147 100644
--- a/apps/automated/src/ui/layouts/flexbox-layout-tests.ts
+++ b/apps/automated/src/ui/layouts/flexbox-layout-tests.ts
@@ -1,4 +1,4 @@
-import { FlexboxLayout, Button, View, unsetValue, Length, PercentLength, Label, Builder } from '@nativescript/core';
+import { FlexboxLayout, Button, View, unsetValue, Length, PercentLength, Label, Builder, isIOS } from '@nativescript/core';
export namespace FlexDirection {
export const ROW: 'row' = 'row';
@@ -1746,3 +1746,45 @@ export const testFlexboxLayout_does_not_crash_with_proxy_view_container = test(a
// Omit testDivider_directionRow_verticalBeginning
// Omit divider test family, we don't draw dividers
+
+let activity_liquidglass_flexbox_layout = () =>
+ getViews(
+ `
+
+
+
+ `,
+ );
+
+export const testLiquidGlassFlexboxLayout = isIOS
+ ? test(activity_liquidglass_flexbox_layout, noop, ({ flexbox, text1, text2, text3 }) => {
+ isTopAlignedWith(text1, flexbox);
+ isLeftAlignedWith(text1, flexbox);
+ isRightOf(text2, text1);
+ isTopAlignedWith(text2, flexbox);
+ isRightOf(text3, text2);
+ isTopAlignedWith(text3, flexbox);
+
+ equal(width(flexbox), width(text1) + width(text2) + width(text3));
+ // Layout helpers report device pixels, so fixed XML DIP sizes must be converted too.
+ closeEnough(height(flexbox), dipToDp(300));
+ })
+ : undefined;
+
+export const testLiquidGlassViews_do_not_crash_when_updating_iosGlassEffect = isIOS
+ ? test(activity_liquidglass_flexbox_layout, noop, ({ root, text1, text2 }) => {
+ const liquidGlass = text1 as unknown as View;
+ const liquidGlassContainer = text2 as unknown as View;
+
+ TKUnit.assertTrue(liquidGlass.nativeViewProtected instanceof UIVisualEffectView, 'LiquidGlass should create a UIVisualEffectView host.');
+ TKUnit.assertTrue(liquidGlassContainer.nativeViewProtected instanceof UIVisualEffectView, 'LiquidGlassContainer should create a UIVisualEffectView host.');
+
+ liquidGlass.iosGlassEffect = 'regular';
+ liquidGlassContainer.iosGlassEffect = { variant: 'clear', spacing: 12 };
+ liquidGlass.iosGlassEffect = 'none';
+ liquidGlassContainer.iosGlassEffect = 'none';
+
+ waitUntilTestElementLayoutIsValid(root);
+ TKUnit.assertTrue(root.isLoaded, 'Liquid glass view tree should remain loaded after glass effect updates.');
+ })
+ : undefined;
diff --git a/apps/toolbox/src/pages/glass-effects.xml b/apps/toolbox/src/pages/glass-effects.xml
index 58601674af..c457ccf70b 100644
--- a/apps/toolbox/src/pages/glass-effects.xml
+++ b/apps/toolbox/src/pages/glass-effects.xml
@@ -15,13 +15,13 @@
-
+
-
+
@@ -32,6 +32,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md
index 426ed0f8b7..fcb54025d0 100644
--- a/packages/core/CHANGELOG.md
+++ b/packages/core/CHANGELOG.md
@@ -1,3 +1,29 @@
+## 9.0.18 (2026-03-30)
+
+### 🩹 Fixes
+
+- **ios:** liquid glass flexbox ([#11134](https://github.com/NativeScript/NativeScript/pull/11134))
+- **ios:** guard against non-string imageURI in createUIImageFromURI ([#11144](https://github.com/NativeScript/NativeScript/pull/11144))
+- **ios:** scene notify first launch ([#11149](https://github.com/NativeScript/NativeScript/pull/11149))
+- **android:** setTextColor is non-nullable, prevent null exception ([#11147](https://github.com/NativeScript/NativeScript/pull/11147))
+- **TextField:** allow toggling of secure when secureWithoutAutofill is present ([65503ba3f](https://github.com/NativeScript/NativeScript/commit/65503ba3f))
+- **core:** split http module to solve circular refs ([#11141](https://github.com/NativeScript/NativeScript/pull/11141))
+- **android:** enable edge-to-edge only for fullscreen modals ([#11140](https://github.com/NativeScript/NativeScript/pull/11140))
+- **core:** size export in View object ([#11132](https://github.com/NativeScript/NativeScript/pull/11132))
+
+### 🔥 Performance
+
+- **TextField:** optimize secureWithoutAutofill ([#11131](https://github.com/NativeScript/NativeScript/pull/11131))
+
+### ❤️ Thank You
+
+- Abdelkarim Ait Bourich @VeinDevTtv
+- Dimitris-Rafail Katsampas @CatchABus
+- felixkrautschuk
+- Juan de Dios Martínez Vallejo
+- Nathan Walker
+- xieweilyg
+
## 9.0.17 (2026-03-04)
### 🩹 Fixes
diff --git a/packages/core/application/application.d.ts b/packages/core/application/application.d.ts
index e5c2eec0c7..a305a88838 100644
--- a/packages/core/application/application.d.ts
+++ b/packages/core/application/application.d.ts
@@ -265,6 +265,12 @@ export class iOSApplication extends ApplicationCommon {
* Get the current one or set a custom one.
*/
sceneDelegate: UIWindowSceneDelegate;
+
+ /**
+ * Flag to be set when the launch event should be delayed until the application has become active.
+ * This is useful when you want to process notifications or data in the background without creating the UI.
+ */
+ shouldDelayLaunchEvent: boolean;
}
export const VALID_FONT_SCALES: number[];
diff --git a/packages/core/application/application.ios.ts b/packages/core/application/application.ios.ts
index fca05bf8bf..df76b1f827 100644
--- a/packages/core/application/application.ios.ts
+++ b/packages/core/application/application.ios.ts
@@ -9,6 +9,7 @@ import { ios as iosUtils, dataSerialize } from '../utils/native-helper';
import { ApplicationCommon, initializeSdkVersionClass, SceneEvents } from './application-common';
import { ApplicationEventData, SceneEventData } from './application-interfaces';
import { Observable } from '../data/observable';
+import type { iOSApplication as IiOSApplication } from './application';
import { Trace } from '../trace';
import {
AccessibilityServiceEnabledPropName,
@@ -186,6 +187,8 @@ class SceneDelegate extends UIResponder implements UIWindowSceneDelegate {
return;
}
+ const isFirstScene = !Application.ios.getPrimaryScene() && !Application.hasLaunched();
+
this._scene = scene;
// Create window for this scene
@@ -221,7 +224,7 @@ class SceneDelegate extends UIResponder implements UIWindowSceneDelegate {
}
// If this is the first scene, trigger app startup
- if (!Application.ios.getPrimaryScene()) {
+ if (isFirstScene) {
Application.ios._notifySceneAppStarted();
}
}
@@ -254,10 +257,11 @@ class SceneDelegate extends UIResponder implements UIWindowSceneDelegate {
// ensure available globally
global.SceneDelegate = SceneDelegate;
-export class iOSApplication extends ApplicationCommon {
+export class iOSApplication extends ApplicationCommon implements IiOSApplication {
private _delegate: UIApplicationDelegate;
private _delegateHandlers = new Map>();
private _rootView: View;
+ private launchEventCalled = false;
private _sceneDelegate: UIWindowSceneDelegate;
private _windowSceneMap = new Map();
private _primaryScene: UIWindowScene | null = null;
@@ -269,6 +273,8 @@ export class iOSApplication extends ApplicationCommon {
displayedLinkTarget: CADisplayLinkTarget;
displayedLink: CADisplayLink;
+ shouldDelayLaunchEvent = false;
+
/**
* @internal - should not be constructed by the user.
*/
@@ -583,6 +589,7 @@ export class iOSApplication extends ApplicationCommon {
}
private notifyAppStarted(notification?: NSNotification) {
+ this.launchEventCalled = true;
const root = this.notifyLaunch({
ios: notification?.userInfo?.objectForKey('UIApplicationLaunchOptionsLocalNotificationKey') ?? null,
});
@@ -691,7 +698,10 @@ export class iOSApplication extends ApplicationCommon {
this.window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
}
- this.notifyAppStarted(notification);
+ this.launchEventCalled = false;
+ if (!this.shouldDelayLaunchEvent) {
+ this.notifyAppStarted();
+ }
} else {
// Scene-based app - window creation will happen in scene delegate
}
@@ -699,6 +709,9 @@ export class iOSApplication extends ApplicationCommon {
@profile
private didBecomeActive(notification: NSNotification) {
+ if (!this.launchEventCalled) {
+ this.notifyAppStarted(notification);
+ }
const additionalData = {
ios: UIApplication.sharedApplication,
};
@@ -905,8 +918,11 @@ export class iOSApplication extends ApplicationCommon {
setiOSWindow(window);
}
- // Set up the window content for the primary scene
- this.setWindowContent();
+ // During initial scene startup we must wait for launch to be notified first.
+ // Some frameworks provide root content from launch handlers.
+ if (this.hasLaunched()) {
+ this.setWindowContent();
+ }
}
}
diff --git a/packages/core/package.json b/packages/core/package.json
index b7d10c2766..193c7322dd 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@nativescript/core",
- "version": "9.0.18-next.6",
+ "version": "9.0.19-next.1",
"description": "A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.",
"type": "module",
"main": "index",
diff --git a/packages/core/ui/core/view/index.ios.ts b/packages/core/ui/core/view/index.ios.ts
index a88ccaf8dc..85b4c8baaf 100644
--- a/packages/core/ui/core/view/index.ios.ts
+++ b/packages/core/ui/core/view/index.ios.ts
@@ -927,13 +927,11 @@ export class View extends ViewCommon {
const variant = config ? config.variant : (value as GlassEffectVariant);
const defaultDuration = 0.3;
const duration = config ? (config.animateChangeDuration ?? defaultDuration) : defaultDuration;
-
- let effect: UIGlassEffect | UIGlassContainerEffect | UIVisualEffect;
+ const glassSupported = supportsGlass();
+ let effect: UIVisualEffect = UIVisualEffect.new();
// Create the appropriate effect based on type and variant
- if (!value || ['identity', 'none'].includes(variant)) {
- effect = UIVisualEffect.new();
- } else {
+ if (value && !['identity', 'none'].includes(variant) && glassSupported) {
if (options.effectType === 'glass') {
const styleFn = options.toGlassStyleFn || this.toUIGlassStyle.bind(this);
effect = UIGlassEffect.effectWithStyle(styleFn(variant));
@@ -1086,9 +1084,9 @@ export class View extends ViewCommon {
if (supportsGlass()) {
switch (value) {
case 'regular':
- return UIGlassEffectStyle?.Regular ?? 0;
+ return UIGlassEffectStyle.Regular;
case 'clear':
- return UIGlassEffectStyle?.Clear ?? 1;
+ return UIGlassEffectStyle.Clear;
}
}
return 1;
diff --git a/packages/core/ui/layouts/liquid-glass-container/index.ios.ts b/packages/core/ui/layouts/liquid-glass-container/index.ios.ts
index a9bc485687..323edf9fe0 100644
--- a/packages/core/ui/layouts/liquid-glass-container/index.ios.ts
+++ b/packages/core/ui/layouts/liquid-glass-container/index.ios.ts
@@ -1,4 +1,5 @@
import type { NativeScriptUIView } from '../../utils';
+import { supportsGlass } from '../../../utils/constants';
import { GlassEffectType, iosGlassEffectProperty, View } from '../../core/view';
import { LiquidGlassContainerCommon } from './liquid-glass-container-common';
import { toUIGlassStyle } from '../liquid-glass';
@@ -9,11 +10,16 @@ export class LiquidGlassContainer extends LiquidGlassContainerCommon {
private _normalizing = false;
createNativeView() {
+ const glassSupported = supportsGlass();
// Keep UIVisualEffectView as the root to preserve interactive container effect
- const effect = UIGlassContainerEffect.alloc().init();
- effect.spacing = 8;
+ const effect = glassSupported ? UIGlassContainerEffect.alloc().init() : UIVisualEffect.new();
+ if (glassSupported) {
+ (effect as UIGlassContainerEffect).spacing = 8;
+ }
const effectView = UIVisualEffectView.alloc().initWithEffect(effect);
- effectView.overrideUserInterfaceStyle = UIUserInterfaceStyle.Dark;
+ if (glassSupported) {
+ effectView.overrideUserInterfaceStyle = UIUserInterfaceStyle.Dark;
+ }
effectView.clipsToBounds = true;
effectView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
@@ -53,12 +59,54 @@ export class LiquidGlassContainer extends LiquidGlassContainerCommon {
return false;
}
+ // When LiquidGlassContainer is a child of FlexboxLayout (or any layout that passes
+ // a measure spec already reduced by the child's padding), AbsoluteLayout.onMeasure
+ // would subtract our padding a second time. To prevent this double-deduction we
+ // temporarily zero the effective padding/border values before delegating to the
+ // AbsoluteLayout measurement, then restore them immediately after.
+ public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
+ const pl = this.effectivePaddingLeft;
+ const pr = this.effectivePaddingRight;
+ const pt = this.effectivePaddingTop;
+ const pb = this.effectivePaddingBottom;
+ const bl = this.effectiveBorderLeftWidth;
+ const br = this.effectiveBorderRightWidth;
+ const bt = this.effectiveBorderTopWidth;
+ const bb = this.effectiveBorderBottomWidth;
+
+ this.effectivePaddingLeft = 0;
+ this.effectivePaddingRight = 0;
+ this.effectivePaddingTop = 0;
+ this.effectivePaddingBottom = 0;
+ this.effectiveBorderLeftWidth = 0;
+ this.effectiveBorderRightWidth = 0;
+ this.effectiveBorderTopWidth = 0;
+ this.effectiveBorderBottomWidth = 0;
+
+ try {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ } finally {
+ this.effectivePaddingLeft = pl;
+ this.effectivePaddingRight = pr;
+ this.effectivePaddingTop = pt;
+ this.effectivePaddingBottom = pb;
+ this.effectiveBorderLeftWidth = bl;
+ this.effectiveBorderRightWidth = br;
+ this.effectiveBorderTopWidth = bt;
+ this.effectiveBorderBottomWidth = bb;
+ }
+ }
+
// When children animate with translate (layer transform), UIVisualEffectView-based
// container effects may recompute based on the underlying frames (not transforms),
// which can cause jumps. Normalize any residual translation into the
// child's frame so the effect uses the final visual positions.
public onLayout(left: number, top: number, right: number, bottom: number): void {
- super.onLayout(left, top, right, bottom);
+ // AbsoluteLayout.onLayout positions children using our padding as an offset.
+ // Since the FlexboxLayout (or parent) already placed our UIVisualEffectView at
+ // (left, top), we normalise to local coordinates so that AbsoluteLayout places
+ // children in (0, 0, width, height) space — the coordinate space of _contentHost.
+ super.onLayout(0, 0, right - left, bottom - top);
// Try to fold any pending translates into frames on each layout pass
this._normalizeChildrenTransforms();
diff --git a/packages/core/ui/layouts/liquid-glass/index.ios.ts b/packages/core/ui/layouts/liquid-glass/index.ios.ts
index 2bf63e39d7..e545dd29bb 100644
--- a/packages/core/ui/layouts/liquid-glass/index.ios.ts
+++ b/packages/core/ui/layouts/liquid-glass/index.ios.ts
@@ -8,9 +8,12 @@ export class LiquidGlass extends LiquidGlassCommon {
private _contentHost: UIView;
createNativeView() {
+ const glassSupported = supportsGlass();
// Use UIVisualEffectView as the root so interactive effects can track touches
- const effect = UIGlassEffect.effectWithStyle(UIGlassEffectStyle.Clear);
- effect.interactive = true;
+ const effect = glassSupported ? UIGlassEffect.effectWithStyle(toUIGlassStyle('clear')) : UIVisualEffect.new();
+ if (glassSupported) {
+ (effect as UIGlassEffect).interactive = true;
+ }
const effectView = UIVisualEffectView.alloc().initWithEffect(effect);
effectView.frame = CGRectMake(0, 0, 0, 0);
effectView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
@@ -49,6 +52,53 @@ export class LiquidGlass extends LiquidGlassCommon {
return false;
}
+ public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
+ // When LiquidGlass is a child of FlexboxLayout (or any layout that passes a child
+ // measure spec already reduced by the child's padding), GridLayout.onMeasure would
+ // subtract our padding a second time. To prevent this double-deduction we temporarily
+ // zero the effective padding/border values before delegating to the GridLayout
+ // measurement, then restore them immediately after.
+ const pl = this.effectivePaddingLeft;
+ const pr = this.effectivePaddingRight;
+ const pt = this.effectivePaddingTop;
+ const pb = this.effectivePaddingBottom;
+ const bl = this.effectiveBorderLeftWidth;
+ const br = this.effectiveBorderRightWidth;
+ const bt = this.effectiveBorderTopWidth;
+ const bb = this.effectiveBorderBottomWidth;
+
+ this.effectivePaddingLeft = 0;
+ this.effectivePaddingRight = 0;
+ this.effectivePaddingTop = 0;
+ this.effectivePaddingBottom = 0;
+ this.effectiveBorderLeftWidth = 0;
+ this.effectiveBorderRightWidth = 0;
+ this.effectiveBorderTopWidth = 0;
+ this.effectiveBorderBottomWidth = 0;
+
+ try {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ } finally {
+ this.effectivePaddingLeft = pl;
+ this.effectivePaddingRight = pr;
+ this.effectivePaddingTop = pt;
+ this.effectivePaddingBottom = pb;
+ this.effectiveBorderLeftWidth = bl;
+ this.effectiveBorderRightWidth = br;
+ this.effectiveBorderTopWidth = bt;
+ this.effectiveBorderBottomWidth = bb;
+ }
+ }
+
+ public onLayout(left: number, top: number, right: number, bottom: number): void {
+ // GridLayout.onLayout computes column/row offsets relative to (left, top), then
+ // adds its own padding on top. Since the FlexboxLayout (or parent) already placed
+ // our UIVisualEffectView at (left, top), we normalise to local coordinates so that
+ // GridLayout lays children out in (0, 0, width, height) space — which is exactly
+ // the coordinate space of our _contentHost UIView that hosts the children.
+ super.onLayout(0, 0, right - left, bottom - top);
+ }
+
[iosGlassEffectProperty.setNative](value: GlassEffectType) {
this._applyGlassEffect(value, {
effectType: 'glass',
@@ -62,9 +112,9 @@ export function toUIGlassStyle(value?: GlassEffectVariant) {
if (supportsGlass()) {
switch (value) {
case 'regular':
- return UIGlassEffectStyle?.Regular ?? 0;
+ return UIGlassEffectStyle.Regular;
case 'clear':
- return UIGlassEffectStyle?.Clear ?? 1;
+ return UIGlassEffectStyle.Clear;
}
}
return 1;
diff --git a/packages/core/ui/styling/background.ios.ts b/packages/core/ui/styling/background.ios.ts
index 613971e528..315a1b5988 100644
--- a/packages/core/ui/styling/background.ios.ts
+++ b/packages/core/ui/styling/background.ios.ts
@@ -184,6 +184,10 @@ export namespace ios {
const style = view.style;
if (imageURI) {
+ if (typeof imageURI !== 'string') {
+ callback(null);
+ return;
+ }
const match = imageURI.match(uriPattern);
if (match && match[2]) {
imageURI = match[2];
diff --git a/packages/core/utils/constants.ios.ts b/packages/core/utils/constants.ios.ts
index 735e204362..2b9a98b6e0 100644
--- a/packages/core/utils/constants.ios.ts
+++ b/packages/core/utils/constants.ios.ts
@@ -1,4 +1,5 @@
export const SDK_VERSION = parseFloat(UIDevice.currentDevice.systemVersion);
+
export function supportsGlass(): boolean {
return __APPLE__ && SDK_VERSION >= 26;
}
diff --git a/packages/devtools/package.json b/packages/devtools/package.json
index 0b095dc152..18b4f7f1b2 100644
--- a/packages/devtools/package.json
+++ b/packages/devtools/package.json
@@ -1,6 +1,6 @@
{
"name": "@nativescript/devtools",
- "version": "0.0.2-next.32",
+ "version": "0.0.5",
"private": true,
"files": [
"./dist/"
@@ -10,6 +10,6 @@
"prepack": "tsc || echo ok"
},
"devDependencies": {
- "@nativescript/core": "9.0.18-next.6"
+ "@nativescript/core": "9.0.19-next.1"
}
}
diff --git a/packages/vite/package.json b/packages/vite/package.json
index bd049e471a..4d7391d300 100644
--- a/packages/vite/package.json
+++ b/packages/vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@nativescript/vite",
- "version": "1.0.6-next.32",
+ "version": "1.0.9",
"description": "Vite for NativeScript",
"main": "./index.js",
"module": "./index.js",
diff --git a/packages/webpack5/CHANGELOG.md b/packages/webpack5/CHANGELOG.md
index 7f1e56f115..1367e39762 100644
--- a/packages/webpack5/CHANGELOG.md
+++ b/packages/webpack5/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 5.0.33 (2026-03-30)
+
+### 🩹 Fixes
+
+- **webpack:** disable __dirname & __filename webpack polyfills for esm builds ([#11146](https://github.com/NativeScript/NativeScript/pull/11146))
+
+### ❤️ Thank You
+
+- Daniel Grima @dangrima90
+
## 5.0.32 (2026-03-18)
### 🩹 Fixes
diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json
index ccd9ca2372..a11f889d3e 100644
--- a/packages/webpack5/package.json
+++ b/packages/webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@nativescript/webpack",
- "version": "5.0.33-next.3",
+ "version": "5.0.34-next.1",
"private": false,
"main": "dist/index.js",
"files": [
diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts
index 774ae8c2dd..516347c240 100644
--- a/packages/webpack5/src/configuration/base.ts
+++ b/packages/webpack5/src/configuration/base.ts
@@ -267,6 +267,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
if (env === null || env === void 0 ? void 0 : env.uniqueBundle) {
config.output.filename(`[name].${env.uniqueBundle}.mjs`);
}
+ // Prevent webpack from generating Node-style ESM shims for __dirname/__filename.
+ // For output modules, webpack defaults these to a fileURLToPath(import.meta.url) helper
+ // imported from bare "url", which does not match the NativeScript iOS runtime contract.
+ // The runtime already provides import.meta.dirname and initializes global.__dirname,
+ // so webpack's helper is redundant and can misresolve in bundle/worker contexts.
+ // ESM app or dependency code should use import.meta.dirname/import.meta.url instead
+ // of expecting webpack to synthesize __dirname/__filename.
+ config.node.set('__dirname', false);
+ config.node.set('__filename', false);
}
config.watchOptions({