} superclass
*/
export const ArrowMixinImplementation = superclass =>
// @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
class ArrowMixin extends OverlayMixin(superclass) {
static get properties() {
return {
hasArrow: {
type: Boolean,
reflect: true,
attribute: 'has-arrow',
},
};
}
static get styles() {
return [
.../** @type {CSSResultArray} */ (super.styles || []),
css`
:host {
--tooltip-arrow-width: 12px;
--tooltip-arrow-height: 8px;
}
.arrow svg {
display: block;
}
.arrow {
position: absolute;
width: var(--tooltip-arrow-width);
height: var(--tooltip-arrow-height);
}
.arrow__graphic {
display: block;
}
[data-popper-placement^='top'] .arrow {
bottom: calc(-1 * var(--tooltip-arrow-height));
}
[data-popper-placement^='bottom'] .arrow {
top: calc(-1 * var(--tooltip-arrow-height));
}
[data-popper-placement^='bottom'] .arrow__graphic {
transform: rotate(180deg);
}
[data-popper-placement^='left'] .arrow {
right: calc(
-1 * (var(--tooltip-arrow-height) +
(var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
);
}
[data-popper-placement^='left'] .arrow__graphic {
transform: rotate(270deg);
}
[data-popper-placement^='right'] .arrow {
left: calc(
-1 * (var(--tooltip-arrow-height) +
(var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
);
}
[data-popper-placement^='right'] .arrow__graphic {
transform: rotate(90deg);
}
:host(:not([has-arrow])) .arrow {
display: none;
}
`,
];
}
constructor() {
super();
this.hasArrow = true;
/** @private */
this.__setupRepositionCompletePromise();
}
render() {
return html`
${this._arrowNodeTemplate()}
`;
}
/** @protected */
_arrowNodeTemplate() {
return html` ${this._arrowTemplate()}
`;
}
/** @protected */
// eslint-disable-next-line class-methods-use-this
_arrowTemplate() {
return html`
`;
}
/**
* Overrides arrow and keepTogether modifier to be enabled,
* and adds onCreate and onUpdate hooks to sync from popper state
* @configure OverlayMixin
* @returns {OverlayConfig}
* @protected
*/
// eslint-disable-next-line
_defineOverlayConfig() {
const superConfig = super._defineOverlayConfig() || {};
if (!this.hasArrow) {
return superConfig;
}
return {
...superConfig,
popperConfig: {
...this._getPopperArrowConfig(
/** @type {Partial} */ (superConfig.popperConfig),
),
},
};
}
/**
* @param {Partial} popperConfigToExtendFrom
* @returns {Partial}
* @protected
*/
_getPopperArrowConfig(popperConfigToExtendFrom) {
/** @type {Partial & { afterWrite: (arg0: Partial) => void }} */
const popperCfg = {
...(popperConfigToExtendFrom || {}),
placement: /** @type {Placement} */ ('top'),
modifiers: [
{
name: 'arrow',
enabled: true,
options: {
padding: 8, // 8px from the edges of the popper
},
},
{
name: 'offset',
enabled: true,
options: { offset: [0, 8] },
},
...((popperConfigToExtendFrom && popperConfigToExtendFrom.modifiers) || []),
],
/** @param {Partial} data */
onFirstUpdate: data => {
this.__syncFromPopperState(data);
},
/** @param {Partial} data */
afterWrite: data => {
this.__syncFromPopperState(data);
},
};
return popperCfg;
}
/** @private */
__setupRepositionCompletePromise() {
this.repositionComplete = new Promise(resolve => {
this.__repositionCompleteResolver = resolve;
});
}
get _arrowNode() {
return /** @type {ShadowRoot} */ (this.shadowRoot).querySelector('[data-popper-arrow]');
}
/**
* @param {Partial} data
* @private
*/
__syncFromPopperState(data) {
if (!data) {
return;
}
if (
this._arrowNode &&
data.placement !== /** @type {Element & {placement:string}} */ (this._arrowNode).placement
) {
/** @type {function} */ (this.__repositionCompleteResolver)(data.placement);
this.__setupRepositionCompletePromise();
}
}
};
export const ArrowMixin = dedupeMixin(ArrowMixinImplementation);