aurelia-dialog-lite
A very lite Aurelia dialog plugin.
This project is a cut-off version of original aurelia-dialog, with added focus-trap from Micromodal.
What's changed from original aurelia-dialog?
- removed most of the features, simplified APIs (incompatible).
- give users total control on CSS and layout.
- properly trap focus, prevent users from using Tab and Enter to hit button/anchor on the background DOM behind the active dialog.
Should I migrate to aurelia-dialog-lite?
There are breaking changes, if aurelia-dialog did not trouble you, don't migrate.
For users who absolutely need proper focus trap, or have strong need for the CSS customization, aurelia-dialog-lite is a good fit.
Guide
Install and config
npm i aurelia-dialog-lite
Or
yarn add aurelia-dialog-lite
In Aurelia app's src/main.js
(or src/main.ts
).
aureliause;
Note
PLATFORM.moduleName()
wrapper is only needed for app built with webpack.
Optionally, you can modify the default dialog settings.
aureliause;
- host is the element where aurelia-dialog-lite appends all dialogs to. Default to HTML body.
- overlayClassName is the CSS class name for the overlay element. Default to
"dialog-lite-overlay"
. See simplifed layout for more details. - escDismiss allows for closing the dialog via the keyboard ESC key.
- overlayDismiss allows for closing the dialog via clicking the overlay element.
They are the only settings available in aurelia-dialog-lite.
Simplified layout
Before getting into the code, it's better to understand how aurelia-dialog-lite renders the dialogs.
For a dialog with following HTML template:
...
aurelia-dialog-lite inserts following to the host
element (default to HTML body) .
... <!-- following is appended by aurelia-dialog-lite --> ... <!-- additional dialog has its own overlay element --> ...
Imaging aurelia-dialog-lite only changes the <template>
in your dialog HTML template to <div class="dialog-lite-overlay">
, then appends the whole thing to HTML body.
Original aurelia-dialog creates lots of DOM layers above your actual dialog, making CSS customization quite difficult.
Simplified CSS
The default CSS for the overlay element is quite simple. It covers the full screen, uses flex layout to centre the user dialog. The following is all of aurelia-dialog-lite's CSS (injected to HTML head automatically).
Note not all browsers support flex layout. To support old browsers like IE11, override
.dialog-lite-overlay
in your local CSS.
aurelia-dialog-lite injects the above CSS piece onto the very beginning of the HTML head, so your local CSS will always override/patch the original.
This is all that aurelia-dialog-lite does on the DOM. Knowing your dialog DOM is simply wrapped by a <div class="dialog-lite-overlay">
, you are responsible to position and style your dialog through local CSS.
Original aurelia-dialog supports few custom elements:
<ux-dialog>
,<ux-dialog-header>
,<ux-dialog-body>
,<ux-dialog-footer>
, and one custom attributeattach-focus
. They are all removed from aurelia-dialog-lite.
Basic usage
Inject DialogService
to your view model.
Following guide shows all code examples in ESNext. It's very similar in TypeScript. At the end of each section, all the runnable code demos have both ESNext and TypeScript versions.
;; @ { thisdialogService = dialogService; }
Then use dialogService.open()
to show a dialog.
; //... { thisdialogService }
Or use async/await
async { try const output = await thisdialogService; // ... catch err // cancelled )
Note different from original aurelia-dialog, we simply return dialog closePromise. It either resolves to an output, or rejects to an cancellation error which you can ignore most of the time.
- viewModel is the dialog implementation.
- view is the optional HTML template for the dialog. Only for non-default HTML template file, or view only dialog implementation. See advanced usage for more details.
- model is an optional model object which will be passed to
activate(model?: any)
lifecycle callback of the dialog.
Implement a dialog
In dialog, inject DialogController
so that you can call controller.cancel()
or controller.ok()
later.
;; @
${title} Cancel OK
controller.cancel(reason: string = 'cancelled')
supports an optional reason for the cancellation. Default to"cancelled"
. You can get it out from the rejectederr.message
followingdialogService.open()
.controller.ok(output?: any)
supports an optional output for the resolution. The output is the resolved result of the promise returned bydialogService.open()
.
Note different from original aurelia-dialog,
controller.cancel()
andcontroller.ok()
are now synchronous, doesn't return a promise any more.
Demo | ||
---|---|---|
Baisc usage | ESNext | TypeScript |
Customise settings
On top of the global settings through aurelia.use.plugin()
, there are two more places you can customise the settings per dialog.
dialogService.open()
and dialogService.create()
(showing in next section: advanced usage).
1. in thisdialogService
You can customise host
, overlayClassName
, escDismiss
, and overlayDismiss
. All the options are customisable per dialog.
2. in dialog implementation constructor
{ thiscontroller = controller; thiscontrolleroverlayDismiss = true; }
The injected dialog controller instance is unique per dialog. Customise the settings in constructor so that the later rendering will honour the changed settings.
Note the API is simplified from the original aurelia-dialig:
aurelia-dialog
thiscontrollersettingsoverlayDismiss = true;
aurelia-dialog-lite
thiscontrolleroverlayDismiss = true;
Demo | dialogService.open | dialog constructor |
---|---|---|
Customise settings | ESNext | TypeScript |
Advanced usage
Programmatically close a dialog
API dialogService.create()
is similar to dialogService.open()
, but it returns a promise that resolves to new dialog controller, so you can control the dialog from outside.
In fact, dialogService.open()
is simply implemented through dialogService.create()
.
public opencontextSettings: DialogContextSettings = : Promise<any>
After you got the dialog controller from dialogService.create()
, you can use controller.ok(...)
or controller.cancel()
to close the dialog based on what happened outside of the dialog (e.g. a remote update).
thisdialogService
Or async/await
const controller = await thisdialogService;// ...
Following demo shows how to use dialog controller to close the dialog from outside. It also demonstrate native bootstrap modal layout inside aurelia-dialog-lite.
Note technically the delayed closure can be implemented in the dialog class itself. We only use delayed closure as a simple example of controlling dialog from outside.
Demo | ||
---|---|---|
Programmatically close dialog | ESNext | TypeScript |
View only dialog
Demo | ||
---|---|---|
View-only dialog | ESNext | TypeScript |
Dialog with multiple view templates
Demo | ||
---|---|---|
Multiple view templates | ESNext | TypeScript |
dialogSerivce.hasActiveDialog, dialogSerivce.controllers, dialogSerivce.cancelAll()
DialogService exposes the controllers of the active dialogs through dialogSerivce.controllers
, you can manually call ok()
or cancel()
on one or more of the controllers. It also exposes a simple boolean flag dialogSerivce.hasActiveDialog
which is only true
when there is at least one active dialog.
dialogSerivce.cancelAll()
is a convenient method to cancel all active dialogs. It returns a promise to be resolved after all dialogs were cancelled.
dialogSerivce.cancelAll()
replaced aurelia-dialog's originaldialogSerivce.closeAll()
.
Recipes
z-index
aurelia-dialog-lite does not provide an option to set starting z-index. Just put an z-index in your CSS directly. For example set to 1040 as same as boostrap's modal backdrop.
Enter key
We removed "Enter" key support from original aurelia-dialog because of an edge case. When user uses "Tab" to shift focus to a cancel button, then hit "Enter" key, he/she wants to "click" the cancel button, not to trigger the default action of "Enter" key.
Likely aurelia-combo fixed the edge case. User can use aurelia-combo and aurelia-dialog-lite together to handle default "Enter" action without worrying about misfired "Enter" key on focused button.
Demo | ||
---|---|---|
Use aurelia-combo to handle "Enter" key | ESNext | TypeScript |
Position through CSS
To customise the position of dialogs, you can directly overwrite the default css class .dialog-lite-overlay
or provide your own css class together with overlayClassName
option (can be either global or local setting).
Here is an example of customised .dialog-lite-overlay
without using flex layout (some old browsers do not support it well).
Demo | ||
---|---|---|
Customise position | ESNext | TypeScript |
Transition and animation
TBD: due to manual rendering, aurelia-dialog-lite doesn't work with aurelia-animator-css right now.
License
MIT.