@rdlabo/ionic-theme-ios27 1.2.0-beta.pr231.sha22a35d481cf3 → 1.2.0-beta.pr233.sha647eef34274b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +9 -0
  2. package/dist/native/components/searchable-tabs.d.ts.map +1 -1
  3. package/dist/native/components/searchable-tabs.js +6 -7
  4. package/dist/native/definitions.d.ts +4 -15
  5. package/dist/native/definitions.d.ts.map +1 -1
  6. package/dist/native/definitions.js +1 -6
  7. package/dist/native/index.d.ts +1 -2
  8. package/dist/native/index.d.ts.map +1 -1
  9. package/dist/native/index.js +57 -27
  10. package/dist/native/runtime.d.ts.map +1 -1
  11. package/dist/native/runtime.js +18 -10
  12. package/dist/native/vertical-bars-web.d.ts.map +1 -1
  13. package/dist/native/vertical-bars-web.js +2 -0
  14. package/dist/tab-bar-searchable/index.d.ts.map +1 -1
  15. package/dist/tab-bar-searchable/index.js +39 -11
  16. package/dist/vertical-bars.d.ts +1 -2
  17. package/dist/vertical-bars.d.ts.map +1 -1
  18. package/dist/vertical-bars.js +0 -1
  19. package/docs/iphone-duo-with-original-theme.md +16 -8
  20. package/docs/iphone-duo.md +57 -44
  21. package/docs/native-ui-shell.md +5 -3
  22. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSearchController.swift +1 -1
  23. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +27 -2
  24. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalSearch.swift +118 -0
  25. package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +27 -179
  26. package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +37 -0
  27. package/package.json +1 -1
  28. package/src/native/components/searchable-tabs.ts +8 -11
  29. package/src/native/definitions.ts +6 -19
  30. package/src/native/index.ts +60 -29
  31. package/src/native/runtime.ts +16 -10
  32. package/src/native/vertical-bars-web.ts +2 -0
  33. package/src/tab-bar-searchable/index.ts +40 -9
  34. package/src/vertical-bars.ts +1 -2
@@ -64,6 +64,8 @@ export const attachTabBarSearchable = (
64
64
  // Initialize
65
65
  ionFooter.style.pointerEvents = 'none';
66
66
  ionFooter.style.opacity = '0';
67
+ // Search dismissal belongs beside the Web search field, never in the vertical rail.
68
+ ionFooter.querySelector('ion-buttons[slot=start]')?.classList.add('ios-theme-horizontal-only');
67
69
  const nativeSearch = registerNativeSearch(ionTabBar, ionFabButton, ionFooter);
68
70
 
69
71
  // Saved Params
@@ -72,6 +74,8 @@ export const attachTabBarSearchable = (
72
74
  // Leave is valid both while native Enter awaits its ack and after it completes.
73
75
  let nativeEntry = false;
74
76
  let nativeRequest = 0;
77
+ let verticalSearch = false;
78
+ let tabVisibilityObserver: MutationObserver | undefined;
75
79
 
76
80
  return async (event: Event, type: TabBarSearchableType) => {
77
81
  const selector = type === TabBarSearchableType.Enter ? 'ion-fab-button' : 'ion-buttons[slot=start] ion-button';
@@ -93,19 +97,38 @@ export const attachTabBarSearchable = (
93
97
  return;
94
98
  }
95
99
  if (type === TabBarSearchableType.Enter) {
96
- resumeNative ??= await suspendNativeUIShell([ionTabBar, ionFooter, ionFabButton.closest('ion-fab') ?? ionFabButton]);
100
+ verticalSearch = !!ionTabBar.closest('ion-app.ios-theme-vertical-bars');
101
+ if (verticalSearch) {
102
+ // Ionic hides horizontal tabs when the keyboard opens; keep this rail available.
103
+ const keepTabsVisible = () => {
104
+ if (ionTabBar.classList.contains('tab-bar-hidden') && ionTabBar.closest('ion-app.ios-theme-vertical-bars')) {
105
+ ionTabBar.classList.remove('tab-bar-hidden');
106
+ }
107
+ };
108
+ tabVisibilityObserver?.disconnect();
109
+ tabVisibilityObserver = new MutationObserver(keepTabsVisible);
110
+ tabVisibilityObserver.observe(ionTabBar, { attributes: true, attributeFilter: ['class'] });
111
+ keepTabsVisible();
112
+ }
113
+ resumeNative ??= await suspendNativeUIShell([
114
+ ...(verticalSearch ? [] : [ionTabBar]),
115
+ ionFooter,
116
+ ionFabButton.closest('ion-fab') ?? ionFabButton,
117
+ ]);
97
118
  try {
98
- searchableEventCache = await enterEvent(event, ionTabBar, ionFabButton, ionFooter);
119
+ searchableEventCache = await enterEvent(event, ionTabBar, ionFabButton, ionFooter, verticalSearch);
99
120
  } catch (error) {
121
+ tabVisibilityObserver?.disconnect();
100
122
  resumeNative();
101
123
  resumeNative = undefined;
102
124
  throw error;
103
125
  }
104
126
  } else if (searchableEventCache !== undefined) {
105
127
  try {
106
- await leaveEvent(event, searchableEventCache, ionTabBar, ionFabButton, ionFooter);
128
+ await leaveEvent(event, searchableEventCache, ionTabBar, ionFabButton, ionFooter, verticalSearch);
107
129
  searchableEventCache = undefined;
108
130
  } finally {
131
+ tabVisibilityObserver?.disconnect();
109
132
  resumeNative?.();
110
133
  resumeNative = undefined;
111
134
  }
@@ -120,6 +143,7 @@ const enterEvent = async (
120
143
  ionTabBar: HTMLElement,
121
144
  ionFabButton: HTMLElement,
122
145
  ionFooter: HTMLElement,
146
+ verticalSearch: boolean,
123
147
  ): Promise<SearchableEventCache> => {
124
148
  if (!(event.target as HTMLElement)?.closest('ion-fab-button')) {
125
149
  throw throwErrorByFailedClickElement('ion-fab-button');
@@ -131,10 +155,12 @@ const enterEvent = async (
131
155
  ? getComputedStyle(references.selectedTabButton).getPropertyValue('--color-selected').trim()
132
156
  : '';
133
157
 
134
- const effectAnimation = createEffectAnimation(references, sizes);
158
+ if (verticalSearch) references.closeButtonIcon.setAttribute('name', 'close');
159
+ const tabAnimations = verticalSearch
160
+ ? []
161
+ : [createTabBarAnimation(ionTabBar, references, sizes), createEffectAnimation(references, sizes)];
135
162
  const searchContainerAnimation = createSearchContainerAnimation(references, sizes);
136
163
  const closeButtonsAnimation = createCloseButtonsAnimation(references);
137
- const tabBarAnimation = createTabBarAnimation(ionTabBar, references, sizes);
138
164
  const fabButtonAnimation = createFabButtonAnimation(ionFabButton);
139
165
 
140
166
  await createAnimation()
@@ -144,7 +170,7 @@ const enterEvent = async (
144
170
  .addElement(ionFooter)
145
171
  .afterAddWrite(() => (ionFooter.style.pointerEvents = 'auto'))
146
172
  .fromTo('opacity', '0.8', '1')
147
- .addAnimation([tabBarAnimation, fabButtonAnimation, searchContainerAnimation, effectAnimation, closeButtonsAnimation])
173
+ .addAnimation([...tabAnimations, fabButtonAnimation, searchContainerAnimation, closeButtonsAnimation])
148
174
  .play();
149
175
 
150
176
  return {
@@ -159,6 +185,7 @@ const leaveEvent = async (
159
185
  ionTabBar: HTMLElement,
160
186
  ionFabButton: HTMLElement,
161
187
  ionFooter: HTMLElement,
188
+ verticalSearch: boolean,
162
189
  ): Promise<void> => {
163
190
  if (!(event.target as HTMLElement)?.closest('ion-buttons[slot=start] ion-button')) {
164
191
  throw throwErrorByFailedClickElement('ion-buttons[slot=start] ion-button');
@@ -166,10 +193,14 @@ const leaveEvent = async (
166
193
 
167
194
  const references = getElementReferences(ionTabBar, ionFooter);
168
195
 
169
- const effectAnimation = createReverseEffectAnimation(references, searchableEventCache.elementSizes, searchableEventCache.colorSelected);
196
+ const tabAnimations = verticalSearch
197
+ ? []
198
+ : [
199
+ createReverseTabBarAnimation(ionTabBar, references, searchableEventCache.elementSizes),
200
+ createReverseEffectAnimation(references, searchableEventCache.elementSizes, searchableEventCache.colorSelected),
201
+ ];
170
202
  const searchContainerAnimation = createReverseSearchContainerAnimation(references, searchableEventCache.elementSizes);
171
203
  const closeButtonsAnimation = createReverseCloseButtonsAnimation(references);
172
- const tabBarAnimation = createReverseTabBarAnimation(ionTabBar, references, searchableEventCache.elementSizes);
173
204
  const fabButtonAnimation = createReverseFabButtonAnimation(ionFabButton, searchableEventCache.elementSizes);
174
205
 
175
206
  await createAnimation()
@@ -179,6 +210,6 @@ const leaveEvent = async (
179
210
  .addElement(ionFooter)
180
211
  .afterAddWrite(() => (ionFooter.style.pointerEvents = 'none'))
181
212
  .fromTo('opacity', '1', '0')
182
- .addAnimation([tabBarAnimation, fabButtonAnimation, searchContainerAnimation, effectAnimation, closeButtonsAnimation])
213
+ .addAnimation([...tabAnimations, fabButtonAnimation, searchContainerAnimation, closeButtonsAnimation])
183
214
  .play();
184
215
  };
@@ -1,4 +1,3 @@
1
1
  export { enableVerticalControlArea, setVerticalControlAreaPlacement, IonicNativeUIShell } from './native';
2
- export { HingeStatus } from './native';
3
2
  export { withNativeUIShellTransition } from './native-integration/transition';
4
- export type { DeviceLayout, NativeUIShellStatus, NativeUIShellSuspension, VerticalBarEdge, VerticalControlAreaHandle } from './native';
3
+ export type { NativeUIShellStatus, NativeUIShellSuspension, VerticalBarEdge, VerticalControlAreaHandle } from './native';