feat(overlays): create BottomsheetController
This commit is contained in:
parent
1cc92fbd6e
commit
4b858cbea7
9 changed files with 168 additions and 24 deletions
|
|
@ -26,9 +26,17 @@ const myCtrl = overlays.add(
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### BottomsheetController
|
||||||
|
|
||||||
|
A specific extension of GlobalOverlayController configured to create accessible dialogs at the bottom of the screen.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { BottomsheetController } from '@lion/overlays';
|
||||||
|
```
|
||||||
|
|
||||||
### ModalDialogController
|
### ModalDialogController
|
||||||
|
|
||||||
A specific extension of GlobalOverlayController configured to create accessible modal dialogs.
|
A specific extension of GlobalOverlayController configured to create accessible modal dialogs placed in the center of the screen.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { ModalDialogController } from '@lion/overlays';
|
import { ModalDialogController } from '@lion/overlays';
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ export { DynamicOverlayController } from './src/DynamicOverlayController.js';
|
||||||
export { GlobalOverlayController } from './src/GlobalOverlayController.js';
|
export { GlobalOverlayController } from './src/GlobalOverlayController.js';
|
||||||
export { globalOverlaysStyle } from './src/globalOverlaysStyle.js';
|
export { globalOverlaysStyle } from './src/globalOverlaysStyle.js';
|
||||||
export { LocalOverlayController } from './src/LocalOverlayController.js';
|
export { LocalOverlayController } from './src/LocalOverlayController.js';
|
||||||
|
export { BottomsheetController } from './src/BottomsheetController.js';
|
||||||
export { ModalDialogController } from './src/ModalDialogController.js';
|
export { ModalDialogController } from './src/ModalDialogController.js';
|
||||||
export { overlays } from './src/overlays.js';
|
export { overlays } from './src/overlays.js';
|
||||||
export { OverlaysManager } from './src/OverlaysManager.js';
|
export { OverlaysManager } from './src/OverlaysManager.js';
|
||||||
|
|
|
||||||
16
packages/overlays/src/BottomsheetController.js
Normal file
16
packages/overlays/src/BottomsheetController.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { GlobalOverlayController } from './GlobalOverlayController.js';
|
||||||
|
|
||||||
|
export class BottomsheetController extends GlobalOverlayController {
|
||||||
|
constructor(params) {
|
||||||
|
super({
|
||||||
|
hasBackdrop: true,
|
||||||
|
preventsScroll: true,
|
||||||
|
trapsKeyboardFocus: true,
|
||||||
|
hidesOnEsc: true,
|
||||||
|
viewportConfig: {
|
||||||
|
placement: 'bottom',
|
||||||
|
},
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,11 +4,6 @@ export const globalOverlaysStyle = css`
|
||||||
.global-overlays {
|
.global-overlays {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-overlays__overlay,
|
.global-overlays__overlay,
|
||||||
|
|
@ -16,6 +11,60 @@ export const globalOverlaysStyle = css`
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container {
|
||||||
|
display: flex;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--top-left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--top {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--top-right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--bottom-left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--bottom {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--bottom-right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.global-overlays__overlay-container--left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-overlays__overlay-container--center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.global-overlays.global-overlays--blocking-opened .global-overlays__overlay {
|
.global-overlays.global-overlays--blocking-opened .global-overlays__overlay {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -30,9 +79,10 @@ export const globalOverlaysStyle = css`
|
||||||
content: '';
|
content: '';
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
@ -46,19 +96,6 @@ export const globalOverlaysStyle = css`
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-overlays.global-overlays--backdrop-fade-out {
|
|
||||||
content: '';
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: #333333;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
animation: global-overlays-backdrop-fade-out 300ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes global-overlays-backdrop-fade-in {
|
@keyframes global-overlays-backdrop-fade-in {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
|
||||||
47
packages/overlays/stories/bottomsheet.stories.js
Normal file
47
packages/overlays/stories/bottomsheet.stories.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { storiesOf, html } from '@open-wc/demoing-storybook';
|
||||||
|
|
||||||
|
import { css } from '@lion/core';
|
||||||
|
import { overlays, BottomsheetController } from '../index.js';
|
||||||
|
|
||||||
|
const bottomsheetDemoStyle = css`
|
||||||
|
.demo-overlay {
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid lightgrey;
|
||||||
|
text-align: center;
|
||||||
|
height: 800px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
storiesOf('Global Overlay System|Bottomsheet', module).add('Default', () => {
|
||||||
|
const bottomsheetCtrl = overlays.add(
|
||||||
|
new BottomsheetController({
|
||||||
|
contentTemplate: () => html`
|
||||||
|
<div class="demo-overlay">
|
||||||
|
<p>Bottomsheet</p>
|
||||||
|
<button @click="${() => bottomsheetCtrl.hide()}">Close</button>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
${bottomsheetDemoStyle}
|
||||||
|
</style>
|
||||||
|
<a href="#">Anchor 1</a>
|
||||||
|
<button
|
||||||
|
@click="${event => bottomsheetCtrl.show(event.target)}"
|
||||||
|
aria-haspopup="dialog"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
Open dialog
|
||||||
|
</button>
|
||||||
|
<a href="#">Anchor 2</a>
|
||||||
|
${Array(50).fill(
|
||||||
|
html`
|
||||||
|
<p>Lorem ipsum</p>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import './global-overlay.stories.js';
|
import './global-overlay.stories.js';
|
||||||
import './modal-dialog.stories.js';
|
import './modal-dialog.stories.js';
|
||||||
|
import './bottomsheet.stories.js';
|
||||||
import './local-overlay.stories.js';
|
import './local-overlay.stories.js';
|
||||||
import './local-overlay-placement.stories.js';
|
import './local-overlay-placement.stories.js';
|
||||||
import './dynamic-overlay.stories.js';
|
import './dynamic-overlay.stories.js';
|
||||||
|
|
|
||||||
32
packages/overlays/test/BottomsheetController.test.js
Normal file
32
packages/overlays/test/BottomsheetController.test.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { expect, html } from '@open-wc/testing';
|
||||||
|
|
||||||
|
import { GlobalOverlayController } from '../src/GlobalOverlayController.js';
|
||||||
|
import { BottomsheetController } from '../src/BottomsheetController.js';
|
||||||
|
|
||||||
|
describe('BottomsheetController', () => {
|
||||||
|
let defaultOptions;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
defaultOptions = {
|
||||||
|
contentTemplate: () => html`
|
||||||
|
<p>my content</p>
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('extends GlobalOverlayController', () => {
|
||||||
|
expect(new BottomsheetController(defaultOptions)).to.be.instanceof(GlobalOverlayController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has correct defaults', () => {
|
||||||
|
const controller = new BottomsheetController(defaultOptions);
|
||||||
|
expect(controller.hasBackdrop).to.equal(true);
|
||||||
|
expect(controller.isBlocking).to.equal(false);
|
||||||
|
expect(controller.preventsScroll).to.equal(true);
|
||||||
|
expect(controller.trapsKeyboardFocus).to.equal(true);
|
||||||
|
expect(controller.hidesOnEsc).to.equal(true);
|
||||||
|
expect(controller.overlayContainerPlacementClass).to.equal(
|
||||||
|
'global-overlays__overlay-container--bottom',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -349,7 +349,7 @@ describe('GlobalOverlayController', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
controller.show();
|
controller.show();
|
||||||
expect(controller.overlayContainerClass).to.equal(
|
expect(controller.overlayContainerPlacementClass).to.equal(
|
||||||
'global-overlays__overlay-container--center',
|
'global-overlays__overlay-container--center',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -377,7 +377,7 @@ describe('GlobalOverlayController', () => {
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
controller.show();
|
controller.show();
|
||||||
expect(controller.overlayContainerClass).to.equal(
|
expect(controller.overlayContainerPlacementClass).to.equal(
|
||||||
`global-overlays__overlay-container--${viewportPlacement}`,
|
`global-overlays__overlay-container--${viewportPlacement}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ describe('ModalDialogController', () => {
|
||||||
expect(ctrl.preventsScroll).to.be.true;
|
expect(ctrl.preventsScroll).to.be.true;
|
||||||
expect(ctrl.trapsKeyboardFocus).to.be.true;
|
expect(ctrl.trapsKeyboardFocus).to.be.true;
|
||||||
expect(ctrl.hidesOnEsc).to.be.true;
|
expect(ctrl.hidesOnEsc).to.be.true;
|
||||||
expect(ctrl.overlayContainerClass).to.equal('global-overlays__overlay-container--center');
|
expect(ctrl.overlayContainerPlacementClass).to.equal(
|
||||||
|
'global-overlays__overlay-container--center',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue