chore(overlays): change to API popperConfig to make clear it's Popper.js

This commit is contained in:
Joren Broekema 2019-06-27 15:53:16 +02:00
parent 1e9ec400dd
commit e775554a07
10 changed files with 66 additions and 52 deletions

View file

@ -91,7 +91,7 @@ other overlays, so needed for internals.
- sets focus to overlay content(?) - sets focus to overlay content(?)
- For `isTooltip`: - For `isTooltip`:
- sets role="tooltip" and aria-labelledby/aria-describedby on the content - sets role="tooltip" and aria-labelledby/aria-describedby on the content
- {Object} placementConfig - {Object} popperConfig
- {String} placement - vertical/horizontal position to be supplied to `managePosition`. See https://github.com/ing-bank/lion/pull/61 for current api. Consists of a primary part (where the overlay is located relative from invoker) and secondary alignnment part (how the overlay 'snaps' to the perpendicular boundary of the invoker), separated via '-'. - {String} placement - vertical/horizontal position to be supplied to `managePosition`. See https://github.com/ing-bank/lion/pull/61 for current api. Consists of a primary part (where the overlay is located relative from invoker) and secondary alignnment part (how the overlay 'snaps' to the perpendicular boundary of the invoker), separated via '-'.
- primary : 'bottom' | 'top' | 'left' | 'right' | 'over' (this means the overlay will be positioned on top of the invoker. Think for instance of a select dropdown that opens a selected option on top of the invoker (default behavior of `<select>` on iOS)) - primary : 'bottom' | 'top' | 'left' | 'right' | 'over' (this means the overlay will be positioned on top of the invoker. Think for instance of a select dropdown that opens a selected option on top of the invoker (default behavior of `<select>` on iOS))
- secondary : 'start' | 'end' | 'fill' (occupies width of invoker) | 'middle' (implicit option that will be choosen by default when none of the previous are specified) - secondary : 'start' | 'end' | 'fill' (occupies width of invoker) | 'middle' (implicit option that will be choosen by default when none of the previous are specified)

View file

@ -9,7 +9,7 @@ export class LocalOverlayController {
constructor(params = {}) { constructor(params = {}) {
// TODO: Instead of in constructor, prefetch it or use a preloader-manager to load it during idle time // TODO: Instead of in constructor, prefetch it or use a preloader-manager to load it during idle time
this.constructor.popperModule = __preloadPopper(); this.constructor.popperModule = __preloadPopper();
this.__mergePlacementConfigs(params.placementConfig || {}); this.__mergePopperConfigs(params.popperConfig || {});
this.hidesOnEsc = params.hidesOnEsc; this.hidesOnEsc = params.hidesOnEsc;
this.hidesOnOutsideClick = params.hidesOnOutsideClick; this.hidesOnOutsideClick = params.hidesOnOutsideClick;
@ -125,8 +125,8 @@ export class LocalOverlayController {
// Popper does not export a nice method to update an existing instance with a new config. Therefore we recreate the instance. // Popper does not export a nice method to update an existing instance with a new config. Therefore we recreate the instance.
// TODO: Send a merge request to Popper to abstract their logic in the constructor to an exposed method which takes in the user config. // TODO: Send a merge request to Popper to abstract their logic in the constructor to an exposed method which takes in the user config.
async updatePlacementConfig(config = {}) { async updatePopperConfig(config = {}) {
this.__mergePlacementConfigs(config); this.__mergePopperConfigs(config);
await this.__createPopperInstance(); await this.__createPopperInstance();
} }
@ -233,12 +233,10 @@ export class LocalOverlayController {
* Merges the default config with the current config, and finally with the user supplied config * Merges the default config with the current config, and finally with the user supplied config
* @param {Object} config user supplied configuration * @param {Object} config user supplied configuration
*/ */
__mergePlacementConfigs(config = {}) { __mergePopperConfigs(config = {}) {
this.placementConfig = { const defaultConfig = {
placement: 'top', placement: 'top',
positionFixed: false, positionFixed: false,
...(this.placementConfig || {}),
...(config || {}),
modifiers: { modifiers: {
keepTogether: { keepTogether: {
enabled: false, enabled: false,
@ -259,7 +257,17 @@ export class LocalOverlayController {
arrow: { arrow: {
enabled: false, enabled: false,
}, },
...((this.placementConfig && this.placementConfig.modifiers) || {}), },
};
// Deep merging default config, previously configured user config, new user config
this.popperConfig = {
...defaultConfig,
...(this.popperConfig || {}),
...(config || {}),
modifiers: {
...defaultConfig.modifiers,
...((this.popperConfig && this.popperConfig.modifiers) || {}),
...((config && config.modifiers) || {}), ...((config && config.modifiers) || {}),
}, },
}; };
@ -273,7 +281,7 @@ export class LocalOverlayController {
const mod = await this.constructor.popperModule; const mod = await this.constructor.popperModule;
const Popper = mod.default; const Popper = mod.default;
this._popper = new Popper(this.invokerNode, this.contentNode, { this._popper = new Popper(this.invokerNode, this.contentNode, {
...this.placementConfig, ...this.popperConfig,
}); });
} }
} }

View file

@ -20,7 +20,7 @@ const togglePlacement = popupController => {
'left-end', 'left-end',
]; ];
placement = placements[(placements.indexOf(placement) + 1) % placements.length]; placement = placements[(placements.indexOf(placement) + 1) % placements.length];
popupController.updatePlacementConfig({ placement }); popupController.updatePopperConfig({ placement });
}; };
const popupPlacementDemoStyle = css` const popupPlacementDemoStyle = css`
@ -70,11 +70,11 @@ storiesOf('Local Overlay System|Local Overlay Placement', module)
</div> </div>
`; `;
}) })
.add('Override the placement config', () => { .add('Override the popper config', () => {
const popupController = overlays.add( const popupController = overlays.add(
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
placementConfig: { popperConfig: {
placement: 'bottom-start', placement: 'bottom-start',
positionFixed: true, positionFixed: true,
modifiers: { modifiers: {

View file

@ -54,7 +54,9 @@ storiesOf('Local Overlay System|Local Overlay', module)
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
hidesOnOutsideClick: true, hidesOnOutsideClick: true,
placement: 'top right', popperConfig: {
placement: 'top-end',
},
contentTemplate: () => contentTemplate: () =>
html` html`
<div class="demo-popup">United Kingdom</div> <div class="demo-popup">United Kingdom</div>
@ -79,7 +81,9 @@ storiesOf('Local Overlay System|Local Overlay', module)
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
hidesOnOutsideClick: true, hidesOnOutsideClick: true,
placement: 'bottom', popperConfig: {
placement: 'bottom',
},
contentTemplate: () => html` contentTemplate: () => html`
<div class="demo-popup"> <div class="demo-popup">
Supplying placement with a single parameter will assume 'center' for the other. Supplying placement with a single parameter will assume 'center' for the other.
@ -105,7 +109,9 @@ storiesOf('Local Overlay System|Local Overlay', module)
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
hidesOnOutsideClick: true, hidesOnOutsideClick: true,
placement: 'bottom', popperConfig: {
placement: 'bottom',
},
contentTemplate: () => contentTemplate: () =>
html` html`
<div class="demo-popup">United Kingdom</div> <div class="demo-popup">United Kingdom</div>

View file

@ -269,7 +269,7 @@ describe('LocalOverlayController', () => {
html` html`
<p>Content</p> <p>Content</p>
`, `,
placementConfig: { popperConfig: {
placement: 'left-start', placement: 'left-start',
}, },
}); });
@ -295,7 +295,7 @@ describe('LocalOverlayController', () => {
Invoker Invoker
</button> </button>
`, `,
placementConfig: { popperConfig: {
placement: 'top-start', placement: 'top-start',
}, },
}); });
@ -312,7 +312,7 @@ describe('LocalOverlayController', () => {
it('allows the user to override default Popper modifiers', async () => { it('allows the user to override default Popper modifiers', async () => {
const controller = new LocalOverlayController({ const controller = new LocalOverlayController({
placementConfig: { popperConfig: {
modifiers: { modifiers: {
keepTogether: { keepTogether: {
enabled: false, enabled: false,
@ -345,7 +345,7 @@ describe('LocalOverlayController', () => {
expect(offset.offset).to.equal('0, 16px'); expect(offset.offset).to.equal('0, 16px');
}); });
it('updates placementConfig even when overlay is closed', async () => { it('updates popperConfig even when overlay is closed', async () => {
const controller = new LocalOverlayController({ const controller = new LocalOverlayController({
contentTemplate: () => contentTemplate: () =>
html` html`
@ -356,7 +356,7 @@ describe('LocalOverlayController', () => {
Invoker Invoker
</button> </button>
`, `,
placementConfig: { popperConfig: {
placement: 'top', placement: 'top',
}, },
}); });
@ -370,7 +370,7 @@ describe('LocalOverlayController', () => {
expect(contentChild.getAttribute('x-placement')).to.equal('top'); expect(contentChild.getAttribute('x-placement')).to.equal('top');
controller.hide(); controller.hide();
await controller.updatePlacementConfig({ placement: 'bottom' }); await controller.updatePopperConfig({ placement: 'bottom' });
await controller.show(); await controller.show();
expect(controller._popper.options.placement).to.equal('bottom'); expect(controller._popper.options.placement).to.equal('bottom');
}); });
@ -386,7 +386,7 @@ describe('LocalOverlayController', () => {
Invoker Invoker
</button> </button>
`, `,
placementConfig: { popperConfig: {
placement: 'top', placement: 'top',
}, },
}); });
@ -417,7 +417,7 @@ describe('LocalOverlayController', () => {
Invoker Invoker
</button> </button>
`, `,
placementConfig: { popperConfig: {
placement: 'top', placement: 'top',
}, },
}); });
@ -432,7 +432,7 @@ describe('LocalOverlayController', () => {
expect(contentChild.style.transform).to.equal('translate3d(14px, -58px, 0px)'); expect(contentChild.style.transform).to.equal('translate3d(14px, -58px, 0px)');
controller.hide(); controller.hide();
await controller.updatePlacementConfig({ await controller.updatePopperConfig({
modifiers: { modifiers: {
offset: { offset: {
enabled: true, enabled: true,

View file

@ -4,24 +4,24 @@ import { overlays, LocalOverlayController } from '@lion/overlays';
export class LionPopup extends UpdatingElement { export class LionPopup extends UpdatingElement {
static get properties() { static get properties() {
return { return {
placementConfig: { popperConfig: {
type: Object, type: Object,
}, },
}; };
} }
get placementConfig() { get popperConfig() {
return this._placementConfig; return this._popperConfig;
} }
set placementConfig(config) { set popperConfig(config) {
this._placementConfig = { this._popperConfig = {
...this._placementConfig, ...this._popperConfig,
...config, ...config,
}; };
if (this._controller && this._controller._popper) { if (this._controller && this._controller._popper) {
this._controller.updatePlacementConfig(this._placementConfig); this._controller.updatePopperConfig(this._popperConfig);
} }
} }
@ -34,7 +34,7 @@ export class LionPopup extends UpdatingElement {
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
hidesOnOutsideClick: true, hidesOnOutsideClick: true,
placementConfig: this.placementConfig, popperConfig: this.popperConfig,
contentNode: this.contentNode, contentNode: this.contentNode,
invokerNode: this.invokerNode, invokerNode: this.invokerNode,
}), }),

View file

@ -58,7 +58,7 @@ storiesOf('Local Overlay System|Popup', module)
${popupDemoStyle} ${popupDemoStyle}
</style> </style>
<div class="demo-box"> <div class="demo-box">
<lion-popup .placementConfig="${{ placement: 'top' }}"> <lion-popup .popperConfig="${{ placement: 'top' }}">
<div slot="content" class="popup">Hello there!</div> <div slot="content" class="popup">Hello there!</div>
<lion-button slot="invoker">Popup</lion-button> <lion-button slot="invoker">Popup</lion-button>
</lion-popup> </lion-popup>
@ -72,19 +72,19 @@ storiesOf('Local Overlay System|Popup', module)
${popupDemoStyle} ${popupDemoStyle}
</style> </style>
<div class="demo-box_placements"> <div class="demo-box_placements">
<lion-popup .placementConfig="${{ placement: 'top' }}"> <lion-popup .popperConfig="${{ placement: 'top' }}">
<div slot="content" class="popup">Its top placement</div> <div slot="content" class="popup">Its top placement</div>
<lion-button slot="invoker">Top</lion-button> <lion-button slot="invoker">Top</lion-button>
</lion-popup> </lion-popup>
<lion-popup .placementConfig="${{ placement: 'right' }}"> <lion-popup .popperConfig="${{ placement: 'right' }}">
<div slot="content" class="popup">Its right placement</div> <div slot="content" class="popup">Its right placement</div>
<lion-button slot="invoker">Right</lion-button> <lion-button slot="invoker">Right</lion-button>
</lion-popup> </lion-popup>
<lion-popup .placementConfig="${{ placement: 'bottom' }}"> <lion-popup .popperConfig="${{ placement: 'bottom' }}">
<div slot="content" class="popup">Its bottom placement</div> <div slot="content" class="popup">Its bottom placement</div>
<lion-button slot="invoker">Bottom</lion-button> <lion-button slot="invoker">Bottom</lion-button>
</lion-popup> </lion-popup>
<lion-popup .placementConfig="${{ placement: 'left' }}"> <lion-popup .popperConfig="${{ placement: 'left' }}">
<div slot="content" class="popup">Its left placement</div> <div slot="content" class="popup">Its left placement</div>
<lion-button slot="invoker">Left</lion-button> <lion-button slot="invoker">Left</lion-button>
</lion-popup> </lion-popup>
@ -92,15 +92,15 @@ storiesOf('Local Overlay System|Popup', module)
`, `,
) )
.add( .add(
'Override placement configuration', 'Override popper configuration',
() => html` () => html`
<style> <style>
${popupDemoStyle} ${popupDemoStyle}
</style> </style>
<p>Use the Storybook Knobs to dynamically change the placement configuration!</p> <p>Use the Storybook Knobs to dynamically change the popper configuration!</p>
<div class="demo-box"> <div class="demo-box">
<lion-popup <lion-popup
.placementConfig="${object('Placement Configuration', { .popperConfig="${object('Popper Configuration', {
placement: 'bottom-start', placement: 'bottom-start',
positionFixed: true, positionFixed: true,
modifiers: { modifiers: {

View file

@ -46,7 +46,7 @@ describe('lion-popup', () => {
expect(el.querySelector('strong')).to.not.be.undefined; expect(el.querySelector('strong')).to.not.be.undefined;
}); });
it('should respond to dynamically changing the placementConfig', async () => { it('should respond to dynamically changing the popperConfig', async () => {
const el = await fixture(html` const el = await fixture(html`
<lion-popup> <lion-popup>
<div slot="content" class="popup">Hey there</div> <div slot="content" class="popup">Hey there</div>
@ -56,7 +56,7 @@ describe('lion-popup', () => {
await el._controller.show(); await el._controller.show();
expect(el._controller._popper.options.placement).to.equal('top'); expect(el._controller._popper.options.placement).to.equal('top');
el.placementConfig = { placement: 'left' }; el.popperConfig = { placement: 'left' };
await el._controller.show(); await el._controller.show();
expect(el._controller._popper.options.placement).to.equal('left'); expect(el._controller._popper.options.placement).to.equal('left');
}); });

View file

@ -11,7 +11,7 @@ export class LionTooltip extends LionPopup {
new LocalOverlayController({ new LocalOverlayController({
hidesOnEsc: true, hidesOnEsc: true,
hidesOnOutsideClick: true, hidesOnOutsideClick: true,
placementConfig: this.placementConfig, popperConfig: this.popperConfig,
contentNode: this.contentNode, contentNode: this.contentNode,
invokerNode: this.invokerNode, invokerNode: this.invokerNode,
}), }),

View file

@ -58,7 +58,7 @@ storiesOf('Local Overlay System|Tooltip', module)
${tooltipDemoStyle} ${tooltipDemoStyle}
</style> </style>
<div class="demo-box"> <div class="demo-box">
<lion-tooltip .placementConfig=${{ placement: 'right' }}> <lion-tooltip .popperConfig=${{ placement: 'right' }}>
<div slot="content" class="tooltip">Hello there!</div> <div slot="content" class="tooltip">Hello there!</div>
<lion-button slot="invoker">Tooltip</lion-button> <lion-button slot="invoker">Tooltip</lion-button>
</lion-tooltip> </lion-tooltip>
@ -72,19 +72,19 @@ storiesOf('Local Overlay System|Tooltip', module)
${tooltipDemoStyle} ${tooltipDemoStyle}
</style> </style>
<div class="demo-box_placements"> <div class="demo-box_placements">
<lion-tooltip .placementConfig=${{ placement: 'top' }}> <lion-tooltip .popperConfig=${{ placement: 'top' }}>
<div slot="content" class="tooltip">Its top placement</div> <div slot="content" class="tooltip">Its top placement</div>
<lion-button slot="invoker">Top</lion-button> <lion-button slot="invoker">Top</lion-button>
</lion-tooltip> </lion-tooltip>
<lion-tooltip .placementConfig=${{ placement: 'right' }}> <lion-tooltip .popperConfig=${{ placement: 'right' }}>
<div slot="content" class="tooltip">Its right placement</div> <div slot="content" class="tooltip">Its right placement</div>
<lion-button slot="invoker">Right</lion-button> <lion-button slot="invoker">Right</lion-button>
</lion-tooltip> </lion-tooltip>
<lion-tooltip .placementConfig=${{ placement: 'bottom' }}> <lion-tooltip .popperConfig=${{ placement: 'bottom' }}>
<div slot="content" class="tooltip">Its bottom placement</div> <div slot="content" class="tooltip">Its bottom placement</div>
<lion-button slot="invoker">Bottom</lion-button> <lion-button slot="invoker">Bottom</lion-button>
</lion-tooltip> </lion-tooltip>
<lion-tooltip .placementConfig=${{ placement: 'left' }}> <lion-tooltip .popperConfig=${{ placement: 'left' }}>
<div slot="content" class="tooltip">Its left placement</div> <div slot="content" class="tooltip">Its left placement</div>
<lion-button slot="invoker">Left</lion-button> <lion-button slot="invoker">Left</lion-button>
</lion-tooltip> </lion-tooltip>
@ -92,15 +92,15 @@ storiesOf('Local Overlay System|Tooltip', module)
`, `,
) )
.add( .add(
'Override placement configuration', 'Override popper configuration',
() => html` () => html`
<style> <style>
${tooltipDemoStyle} ${tooltipDemoStyle}
</style> </style>
<p>Use the Storybook Knobs to dynamically change the placement configuration!</p> <p>Use the Storybook Knobs to dynamically change the popper configuration!</p>
<div class="demo-box_placements"> <div class="demo-box_placements">
<lion-tooltip <lion-tooltip
.placementConfig="${object('Placement Configuration', { .popperConfig="${object('Popper Configuration', {
placement: 'bottom-start', placement: 'bottom-start',
positionFixed: true, positionFixed: true,
modifiers: { modifiers: {