Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebuild mobile navigator without Onsen, and add smooth swipe behaviour #3898

Merged
merged 14 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## v72.0.0-SNAPSHOT - unreleased

### 💥 Breaking Changes

* Mobile `Navigator` no longer supports `animation` prop, and `NavigatorModel` no longer supports
`swipeToGoBack`. Both of these properties are now managed internally by the `Navigator` component.

### 🎁 New Features

* Mobile `Navigator` has been rebuilt to support smooth swipe-based navigation. The API remains
largely the same, notwithstanding the minor breaking changes detailed above.

### 🐞 Bug Fixes

* Fixed `ViewManagerModel` unique name validation.
Expand All @@ -10,7 +20,6 @@

* Added support for providing custom `PersistenceProvider` implementations to `PersistOptions`.


### ⚙️ Typescript API Adjustments

* Improved signature of `HoistBase.markPersist`.
Expand Down
6 changes: 6 additions & 0 deletions cmp/ag-grid/AgGrid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
.ag-floating-bottom {
overflow-y: hidden !important;
}

// Prevent the "bounce" overscroll effect for horizontal scrolling on mobile devices, as it
// conflicts with the drag management in the Navigator.
.ag-center-cols-viewport {
overscroll-behavior-x: none;
}
}

// Ag-Grid themes referenced here to help ensure a high enough level of specificity for our rules.
Expand Down
1 change: 0 additions & 1 deletion kit/onsen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const [button, Button] = wrappedCmp(ons.Button),
[checkbox, Checkbox] = wrappedCmp(ons.Checkbox),
[gestureDetector, GestureDetector] = wrappedCmp(ons.GestureDetector),
[input, Input] = wrappedCmp(ons.Input),
[navigator, Navigator] = wrappedCmp(ons.Navigator),
[searchInput, SearchInput] = wrappedCmp(ons.SearchInput),
[select, Select] = wrappedCmp(ons.Select),
[switchControl, SwitchControl] = wrappedCmp(ons.Switch);
Expand Down
5 changes: 0 additions & 5 deletions kit/onsen/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,10 @@
// Override styles provided in onsenui.css and onsen-css-components.css to use variable declarations
body.xh-app.xh-mobile {
// Background
.page,
.page__content,
.page__background,
.textarea {
background-color: var(--xh-bg);
}

.page--material,
.page--material__background,
.bottom-bar,
.tabbar {
background-color: var(--xh-bg-alt);
Expand Down
14 changes: 14 additions & 0 deletions kit/swiper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | [email protected])
*
* Copyright © 2025 Extremely Heavy Industries Inc.
*/
import {elementFactory} from '@xh/hoist/core';
import {Swiper, SwiperSlide} from 'swiper/react';
import {EffectCreative} from 'swiper/modules';
import './styles.scss';

export {Swiper, SwiperSlide, EffectCreative};
export const swiper = elementFactory(Swiper),
swiperSlide = elementFactory(SwiperSlide);
2 changes: 2 additions & 0 deletions kit/swiper/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import 'swiper/scss';
@import 'swiper/scss/effect-creative';
20 changes: 20 additions & 0 deletions mobile/cmp/navigator/Navigator.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | [email protected])
*
* Copyright © 2025 Extremely Heavy Industries Inc.
*/
.xh-navigator {
width: 100%;
height: 100%;

.swiper-slide {
box-shadow:
0 0 0 1px var(--xh-border-color),
0 0 20px rgba(0, 0, 0, 0.3);
}

.div.swiper-container {
touch-action: pan-x;
}
}
55 changes: 36 additions & 19 deletions mobile/cmp/navigator/Navigator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,53 @@
*
* Copyright © 2025 Extremely Heavy Industries Inc.
*/
import {hoistCmp, HoistProps, uses} from '@xh/hoist/core';
import {navigator as onsenNavigator} from '@xh/hoist/kit/onsen';
import {hoistCmp, uses} from '@xh/hoist/core';
import {swiper, swiperSlide, EffectCreative} from '@xh/hoist/kit/swiper';
import '@xh/hoist/mobile/register';
import {swiper} from './impl/swipe/Swiper';
import './Navigator.scss';
import {NavigatorModel} from './NavigatorModel';

export interface NavigatorProps extends HoistProps<NavigatorModel> {
/** Set animation style or turn off, default 'slide'. */
animation?: 'slide' | 'lift' | 'fade' | 'none';
}
import {PageModel} from './PageModel';
import {gestureRefresh} from './impl/GestureRefresh';
import {page} from './impl/Page';

/**
* Top-level Component within an application, responsible for rendering a stack of
* pages and managing transitions between pages.
*/
export const [Navigator, navigator] = hoistCmp.withFactory<NavigatorProps>({
export const [Navigator, navigator] = hoistCmp.withFactory<NavigatorModel>({
displayName: 'Navigator',
model: uses(NavigatorModel),
className: 'xh-navigator',

render({model, className, animation = 'slide'}) {
return swiper(
onsenNavigator({
render({model, className}) {
const {stack, allowSlideNext, allowSlidePrev} = model;
return gestureRefresh(
swiper({
className,
initialRoute: {init: true},
animation,
animationOptions: {duration: 0.2, delay: 0, timing: 'ease-in'},
renderPage: model.renderPage,
onPostPush: model.onPageChange,
onPostPop: model.onPageChange
allowSlideNext,
allowSlidePrev,
slidesPerView: 1,
modules: [EffectCreative],
effect: 'creative',
creativeEffect: {
prev: {
shadow: true,
translate: ['-15%', 0, -1]
},
next: {
translate: ['100%', 0, 0]
}
},
onSwiper: swiper => model.setSwiper(swiper),
items: stack.map(it => {
const {key} = it as PageModel;
return swiperSlide({
key: `slide-${key}`,
item: page({
key: `page-${key}`,
model: it
})
});
})
})
);
}
Expand Down
Loading
Loading