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

Mobile menus 2.0. #2232

Merged
merged 9 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ decorators, in favor of a simpler inheritance-based approach to defining models
### 🎁 New Features

* New utility method `getOrCreate` for easy caching of properties on objects.
* The `Menu` system on mobile has been reworked to be more consistent with desktop.
A new `MenuButton` component has been added to the mobile framework, which renders a `Menu`
of `MenuItems` next to the `MenuButton`. This change also includes the removal of
`AppMenuModel` (see Breaking Changes)

### 💥 Breaking Changes

Expand All @@ -45,6 +49,8 @@ decorators, in favor of a simpler inheritance-based approach to defining models
wish to select for your component. `Uses` will throw if given any string other than "*", making
the need for any updates clear.
* The `Ref` class, deprecated in v26, has now been removed. Use `createObservableRef` instead.
* `AppMenuModel` has been removed. The `AppMenuButton` is now configured via `AppBar.appMenuButtonProps`.
As with desktop, menu items can be added with `AppBar.appMenuButtonProps.extraItems[]`

### ⚙️ Technical

Expand Down
3 changes: 2 additions & 1 deletion mobile/cmp/button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const [Button, button] = hoistCmp.withFactory({
model: false,
className: 'xh-button',

render(props) {
render(props, ref) {
const [layoutProps, {icon, className, text, modifier, active, onClick, style, ...rest}] = splitLayoutProps(props),
items = [];

Expand All @@ -34,6 +34,7 @@ export const [Button, button] = hoistCmp.withFactory({
}

return onsenButton({
ref,
items,
modifier,
onClick,
Expand Down
28 changes: 0 additions & 28 deletions mobile/cmp/button/MenuButton.js

This file was deleted.

1 change: 0 additions & 1 deletion mobile/cmp/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ export * from './ColChooserButton';
export * from './FeedbackButton';
export * from './ThemeToggleButton';
export * from './LogoutButton';
export * from './MenuButton';
export * from './RefreshButton';
export * from './NavigatorBackButton';
34 changes: 10 additions & 24 deletions mobile/cmp/header/AppBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
*/
import {div} from '@xh/hoist/cmp/layout';
import {hoistCmp, useContextModel, XH} from '@xh/hoist/core';
import {button, menuButton, navigatorBackButton, refreshButton} from '@xh/hoist/mobile/cmp/button';
import {menu} from '@xh/hoist/mobile/cmp/menu';
import {button, navigatorBackButton, refreshButton} from '@xh/hoist/mobile/cmp/button';
import {NavigatorModel} from '@xh/hoist/mobile/cmp/navigator';
import {toolbar} from '@xh/hoist/mobile/cmp/toolbar';
import PT from 'prop-types';

import './AppBar.scss';
import {appMenuButton} from './AppMenuButton';

/**
* A standard application navigation bar which displays the current page title and a standard set of
Expand All @@ -36,11 +37,10 @@ export const [AppBar, appBar] = hoistCmp.withFactory({
hideBackButton,
hideRefreshButton,
appMenuButtonProps = {},
appMenuButtonPosition = 'right',
backButtonProps = {},
refreshButtonProps = {},
appMenuButtonPosition = 'right'
refreshButtonProps = {}
}) {

const navigatorModel = useContextModel(NavigatorModel);

return toolbar({
Expand All @@ -53,8 +53,9 @@ export const [AppBar, appBar] = hoistCmp.withFactory({
omit: hideBackButton,
...backButtonProps
}),
menuButton({
appMenuButton({
omit: hideAppMenuButton || appMenuButtonPosition != 'left',
menuPosition: 'bottom-right',
...appMenuButtonProps
}),
...leftItems || []
Expand Down Expand Up @@ -82,33 +83,18 @@ export const [AppBar, appBar] = hoistCmp.withFactory({
disabled: navigatorModel?.disableAppRefreshButton,
...refreshButtonProps
}),
menuButton({
appMenuButton({
omit: hideAppMenuButton || appMenuButtonPosition != 'right',
menuPosition: 'bottom-left',
...appMenuButtonProps
})
]
}),
appMenu({align: appMenuButtonPosition})
})
]
});
}
});

const appMenu = hoistCmp.factory({
displayName: 'AppMenu',

render({align}) {
const menuModel = XH.appModel.appMenuModel;
if (!menuModel) return null;
return menu({
model: menuModel,
width: 260,
align
});
}
});


AppBar.propTypes = {
/** App icon to display to the left of the title. */
icon: PT.element,
Expand Down
123 changes: 123 additions & 0 deletions mobile/cmp/header/AppMenuButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | [email protected])
*
* Copyright © 2021 Extremely Heavy Industries Inc.
*/
import {hoistCmp, XH} from '@xh/hoist/core';
import {menuButton} from '@xh/hoist/mobile/cmp/menu';
import {Button} from '@xh/hoist/mobile/cmp/button';
import {Icon} from '@xh/hoist/icon';
import {withDefault} from '@xh/hoist/utils/js';
import PT from 'prop-types';

/**
* An top-level application drop down menu, which installs a standard set of menu items for common
* application actions. Application specific items can be displayed before these standard items.
*
* The standard items which are visible will be based on user roles and application configuration,
* or they can each be explicitly hidden.
*/
export const [AppMenuButton, appMenuButton] = hoistCmp.withFactory({
displayName: 'AppMenuButton',
model: false,
className: 'xh-app-menu',

render(props) {
const {className, extraItems, hideImpersonateItem, hideFeedbackItem, hideLogoutItem, hideOptionsItem, hideThemeItem, hideAboutItem, ...rest} = props;

return menuButton({
className,
menuItems: buildMenuItems(props),
...rest
});
}
});

AppMenuButton.propTypes = {
...Button.propTypes,

/** Array of app-specific MenuItems or configs to create them */
extraItems: PT.array,

/**
* True to hide the Impersonate Item.
* Always hidden for users w/o HOIST_ADMIN role or if impersonation is disabled.
*/
hideImpersonateItem: PT.bool,

/** True to hide the Feedback Item. */
hideFeedbackItem: PT.bool,

/** True to hide the Logout button. Defaulted to appSpec.isSSO. */
hideLogoutItem: PT.bool,

/** True to hide the Options button. */
hideOptionsItem: PT.bool,

/** True to hide the Theme Toggle button. */
hideThemeItem: PT.bool,

/** True to hide the About button */
hideAboutItem: PT.bool
};

//---------------------------
// Implementation
//---------------------------
function buildMenuItems({
hideOptionsItem,
hideFeedbackItem,
hideThemeItem,
hideImpersonateItem,
hideLogoutItem,
hideAboutItem,
extraItems = []
}) {
hideOptionsItem = hideOptionsItem || !XH.acm.optionsDialogModel.hasOptions;
hideImpersonateItem = hideImpersonateItem || !XH.identityService.canImpersonate;
hideLogoutItem = withDefault(hideLogoutItem, XH.appSpec.isSSO);

const defaultItems = [
{
omit: hideOptionsItem,
text: 'Options',
icon: Icon.options(),
actionFn: () => XH.showOptionsDialog()
},
{
omit: hideFeedbackItem,
text: 'Feedback',
icon: Icon.comment({className: 'fa-flip-horizontal'}),
actionFn: () => XH.showFeedbackDialog()
},
{
omit: hideThemeItem,
actionFn: () => XH.toggleTheme(),
prepareFn: (item) => {
item.text = XH.darkTheme ? 'Light Theme' : 'Dark Theme';
item.icon = XH.darkTheme ? Icon.sun() : Icon.moon();
}
},
{
omit: hideImpersonateItem,
text: 'Impersonate',
icon: Icon.impersonate(),
actionFn: () => XH.showImpersonationBar()
},
{
omit: hideAboutItem,
icon: Icon.info(),
text: `About ${XH.clientAppName}`,
actionFn: () => XH.showAboutDialog()
},
{
omit: hideLogoutItem,
text: 'Logout',
icon: Icon.logout(),
actionFn: () => XH.identityService.logoutAsync()
}
];

return [...extraItems, ...defaultItems];
}
86 changes: 0 additions & 86 deletions mobile/cmp/header/AppMenuModel.js

This file was deleted.

2 changes: 1 addition & 1 deletion mobile/cmp/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
*/

export * from './AppBar';
export * from './AppMenuModel';
export * from './AppMenuButton';
Loading