1+ diff --git a/lib/module/views/NativeStackView.native.js b/lib/module/views/NativeStackView.native.js
2+ index c342e90bffde9ad5044b6167bdde2e19be219270..5d3e4407aa1bb68b873cf164adf5a9f0b487bb0b 100644
3+ --- a/lib/module/views/NativeStackView.native.js
4+ +++ b/lib/module/views/NativeStackView.native.js
5+ @@ -370,6 +370,17 @@ export function NativeStackView({
6+ return /*#__PURE__*/_jsx(SafeAreaProviderCompat, {
7+ children: /*#__PURE__*/_jsx(ScreenStack, {
8+ style: styles.container,
9+ + onFinishTransitioning: () => {
10+ + // Surface UIKit's transition-completion callback to every route of
11+ + // this navigator. Unlike transitionEnd, this also fires when a modal
12+ + // finishes dismissing — where the presenting screen below receives no
13+ + // appearance callbacks — and for a gesture-driven dismissal it fires
14+ + // before the state pop, while the modal route is still the focused
15+ + // one, so the event must not be targeted at a single route.
16+ + navigation.emit({
17+ + type: 'finishTransitioning'
18+ + });
19+ + },
20+ children: state.routes.concat(state.preloadedRoutes).map((route, index) => {
21+ const descriptor = descriptors[route.key] ?? preloadedDescriptors[route.key];
22+ const isFocused = state.index === index;
123diff --git a/lib/module/views/useHeaderConfigProps.js b/lib/module/views/useHeaderConfigProps.js
2- index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b01175ec19220 100644
24+ index 9c21aa48cb580704aa17e59d9cdadcc612a1e4ff..a1b3a38368c5ef2257570f382e87df5d6f55b11e 100644
325--- a/lib/module/views/useHeaderConfigProps.js
426+++ b/lib/module/views/useHeaderConfigProps.js
5- @@ -19,6 +19,12 @@
27+ @@ -19,6 +19,12 @@ const processBarButtonItems = (items, colors, fonts) => {
628 }
729 return item;
830 }
@@ -15,7 +37,7 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
1537 if (item.type === 'button' || item.type === 'menu') {
1638 if (item.type === 'menu' && item.menu == null) {
1739 throw new Error(`Menu item must have a 'menu' property defined: ${JSON.stringify(item)}`);
18- @@ -79,7 +85,7 @@
40+ @@ -79,7 +85,7 @@ const processBarButtonItems = (items, colors, fonts) => {
1941 }
2042 return processedItem;
2143 }
@@ -24,7 +46,7 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
2446 }).filter(item => item != null);
2547 };
2648 const transformIcon = icon => {
27- @@ -158,8 +164,12 @@
49+ @@ -158,8 +164,12 @@ export function useHeaderConfigProps({
2850 headerBack,
2951 route,
3052 title,
@@ -38,7 +60,7 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
3860 }) {
3961 const {
4062 direction
41- @@ -255,6 +265,10 @@
63+ @@ -255,6 +265,10 @@ export function useHeaderConfigProps({
4264 tintColor,
4365 canGoBack
4466 });
@@ -49,7 +71,7 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
4971 let rightItems = headerRightItems?.({
5072 tintColor,
5173 canGoBack
52- @@ -264,6 +278,10 @@
74+ @@ -264,6 +278,10 @@ export function useHeaderConfigProps({
5375 // So we need to reverse them here to match the order
5476 rightItems = [...rightItems].reverse();
5577 }
@@ -60,7 +82,14 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
6082 const children = /*#__PURE__*/_jsxs(_Fragment, {
6183 children: [Platform.OS === 'ios' ? /*#__PURE__*/_jsxs(_Fragment, {
6284 children: [leftItems ? leftItems.map((item, index) => {
63- @@ -278,7 +296,15 @@
85+ @@ -272,13 +290,23 @@ export function useHeaderConfigProps({
86+ // eslint-disable-next-line @eslint-react/no-array-index-key
87+ , {
88+ hidesSharedBackground: item.hidesSharedBackground,
89+ + identifier: item.identifier,
90+ children: item.element
91+ }, index);
92+ }
6493 return null;
6594 }) : headerLeftElement != null ? /*#__PURE__*/_jsx(ScreenStackHeaderLeftView, {
6695 children: headerLeftElement
@@ -69,6 +98,7 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
6998+ if (item.type === 'custom') {
7099+ return /*#__PURE__*/_jsx(ScreenStackHeaderCenterView, {
71100+ hidesSharedBackground: item.hidesSharedBackground,
101+ + identifier: item.identifier,
72102+ children: item.element
73103+ }, index);
74104+ }
@@ -77,15 +107,23 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
77107 children: headerTitleElement
78108 }) : null]
79109 }) : /*#__PURE__*/_jsxs(_Fragment, {
80- @@ -356,6 +382,7 @@
110+ @@ -321,6 +349,7 @@ export function useHeaderConfigProps({
111+ // eslint-disable-next-line @eslint-react/no-array-index-key
112+ , {
113+ hidesSharedBackground: item.hidesSharedBackground,
114+ + identifier: item.identifier,
115+ children: item.element
116+ }, index);
117+ }
118+ @@ -356,6 +385,7 @@ export function useHeaderConfigProps({
81119 largeTitleFontWeight,
82120 largeTitleHideShadow: headerLargeTitleShadowVisible === false,
83121 title: titleText,
84122+ subtitle: headerSubtitle,
85123 titleColor,
86124 titleFontFamily,
87125 titleFontSize,
88- @@ -364,9 +391,12 @@
126+ @@ -364,6 +394,9 @@ export function useHeaderConfigProps({
89127 disableTopInsetApplication: !headerTopInsetEnabled,
90128 translucent: translucent === true,
91129 children,
@@ -95,30 +133,59 @@ index 0b75c70b4e0d233ee3b5faaf9cfbc40d4f8ed494..eb174e3fde91a7783f132b3fb16b0117
95133 headerLeftBarButtonItems: processBarButtonItems(leftItems, colors, fonts),
96134 headerRightBarButtonItems: processBarButtonItems(rightItems, colors, fonts),
97135 experimental_userInterfaceStyle: dark ? 'dark' : 'light'
98- };
99- }
100- - //# sourceMappingURL=useHeaderConfigProps.js.map
101- \ No newline at end of file
102- + //# sourceMappingURL=useHeaderConfigProps.js.map
103- diff --git a/lib/module/views/NativeStackView.native.js b/lib/module/views/NativeStackView.native.js
104- index c342e90..5d3e440 100644
105- --- a/lib/module/views/NativeStackView.native.js
106- +++ b/lib/module/views/NativeStackView.native.js
107- @@ -370,6 +370,17 @@ export function NativeStackView({
108- return /*#__PURE__*/_jsx(SafeAreaProviderCompat, {
109- children: /*#__PURE__*/_jsx(ScreenStack, {
110- style: styles.container,
111- + onFinishTransitioning: () => {
112- + // Surface UIKit's transition-completion callback to every route of
113- + // this navigator. Unlike transitionEnd, this also fires when a modal
114- + // finishes dismissing — where the presenting screen below receives no
115- + // appearance callbacks — and for a gesture-driven dismissal it fires
116- + // before the state pop, while the modal route is still the focused
117- + // one, so the event must not be targeted at a single route.
118- + navigation.emit({
119- + type: 'finishTransitioning'
120- + });
121- + },
122- children: state.routes.concat(state.preloadedRoutes).map((route, index) => {
123- const descriptor = descriptors[route.key] ?? preloadedDescriptors[route.key];
124- const isFocused = state.index === index;
136+ diff --git a/lib/typescript/src/types.d.ts b/lib/typescript/src/types.d.ts
137+ index 2f1351a89f0f2e67e854dc81e392198326b71834..ccf8556911fa1fa17588f06b56edb2151a712bf0 100644
138+ --- a/lib/typescript/src/types.d.ts
139+ +++ b/lib/typescript/src/types.d.ts
140+ @@ -1091,6 +1091,13 @@ export type NativeStackHeaderItemSpacing = {
141+ */
142+ export type NativeStackHeaderItemCustom = {
143+ type: 'custom';
144+ + /**
145+ + * An identifier used to match items across transitions.
146+ + * Only available from iOS 26.0 and later.
147+ + *
148+ + * Read more: https://developer.apple.com/documentation/uikit/uibarbuttonitem/identifier
149+ + */
150+ + identifier?: string;
151+ /**
152+ * A React Element to display as the item.
153+ */
154+ diff --git a/src/types.tsx b/src/types.tsx
155+ index 7488b1cf20afe36b5c585fbfcd369471fdb6ab8d..f4bd78e48c687024ba84e998fac79e9eb16f1a80 100644
156+ --- a/src/types.tsx
157+ +++ b/src/types.tsx
158+ @@ -1156,6 +1156,13 @@ export type NativeStackHeaderItemSpacing = {
159+ */
160+ export type NativeStackHeaderItemCustom = {
161+ type: 'custom';
162+ + /**
163+ + * An identifier used to match items across transitions.
164+ + * Only available from iOS 26.0 and later.
165+ + *
166+ + * Read more: https://developer.apple.com/documentation/uikit/uibarbuttonitem/identifier
167+ + */
168+ + identifier?: string;
169+ /**
170+ * A React Element to display as the item.
171+ */
172+ diff --git a/src/views/useHeaderConfigProps.tsx b/src/views/useHeaderConfigProps.tsx
173+ index 3f3fff405048b3c2250afbe99dd7f35cecb9a6d5..bb062b898cfa77f8c02f951dc9d81b51672d7d0e 100644
174+ --- a/src/views/useHeaderConfigProps.tsx
175+ +++ b/src/views/useHeaderConfigProps.tsx
176+ @@ -397,6 +397,7 @@ export function useHeaderConfigProps({
177+ // eslint-disable-next-line @eslint-react/no-array-index-key
178+ key={index}
179+ hidesSharedBackground={item.hidesSharedBackground}
180+ + identifier={item.identifier}
181+ >
182+ {item.element}
183+ </ScreenStackHeaderLeftView>
184+ @@ -471,6 +472,7 @@ export function useHeaderConfigProps({
185+ // eslint-disable-next-line @eslint-react/no-array-index-key
186+ key={index}
187+ hidesSharedBackground={item.hidesSharedBackground}
188+ + identifier={item.identifier}
189+ >
190+ {item.element}
191+ </ScreenStackHeaderRightView>
0 commit comments