import { action } from '@ember/object';
import Component from '@glimmer/component';
import arg from 'ember-bootstrap/utils/decorators/arg';
import { tracked } from '@glimmer/tracking';
import { getOwnConfig, macroCondition } from '@embroider/macros';
import { trackedRef } from 'ember-ref-bucket';
/**
Internal (abstract) component for contextual help markup. Should not be used directly.
@class ContextualHelpElement
@namespace Components
@extends Glimmer.Component
@private
*/
export default class ContextualHelpElement extends Component {
/**
* @property placement
* @type string
* @default 'top'
* @public
*/
@arg
placement = 'top';
@tracked
actualPlacement = this.args.placement;
/**
* @property fade
* @type boolean
* @default true
* @public
*/
@arg
fade = true;
/**
* @property showHelp
* @type boolean
* @default false
* @public
*/
@arg
showHelp = false;
/**
* If true component will render in place, rather than be wormholed.
*
* @property renderInPlace
* @type boolean
* @default true
* @public
*/
/**
* Which element to align to
*
* @property popperTarget
* @type {string|HTMLElement}
* @public
*/
/**
* @property autoPlacement
* @type boolean
* @default true
* @public
*/
/**
* The DOM element of the viewport element.
*
* @property viewportElement
* @type object
* @public
*/
/**
* Take a padding into account for keeping the tooltip/popover within the bounds of the element given by `viewportElement`.
*
* @property viewportPadding
* @type number
* @default 0
* @public
*/
/**
* @property arrowClass
* @private
*/
arrowClass = 'arrow';
placementClassPrefix = '';
offset = [0, 0];
@trackedRef('popperElement') popperElement;
/**
* popper.js modifier config
*
* @property popperModifiers
* @type {object}
* @private
*/
get popperOptions() {
let options = {
placement: this.placement,
onFirstUpdate: this.updatePlacement,
};
// We need popperElement, so we wait for this getter to recompute once it's available
if (!this.popperElement) {
return options;
}
options.modifiers = [
{
name: 'arrow',
options: {
element: this.popperElement.querySelector(`.${this.arrowClass}`),
padding: 4,
},
},
{
name: 'offset',
options: {
offset: this.offset,
},
},
{
name: 'preventOverflow',
enabled: this.args.autoPlacement,
options: {
boundary: this.args.viewportElement,
padding: this.args.viewportPadding,
},
},
{
name: 'flip',
enabled: this.args.autoPlacement,
},
{
name: 'onChange',
enabled: true,
phase: 'afterWrite',
fn: this.updatePlacement,
},
];
return options;
}
get actualPlacementClass() {
let ending = this.actualPlacement;
if (macroCondition(getOwnConfig().isBS5)) {
if (ending === 'right') {
ending = 'end';
}
if (ending === 'left') {
ending = 'start';
}
}
return this.placementClassPrefix + ending;
}
@action
updatePlacement(state) {
// normalize argument
state = state.state ?? state;
if (this.actualPlacement === state.placement) {
return;
}
this.actualPlacement = state.placement;
}
}