feat: unified preview eye icon component, enhanced search & preview

- Unify filter group and filter value preview icons into shared
  .filter-chip-wrapper + .chip-preview-btn component pattern
- Remove old .toggle-count.clickable inline eye icon approach
- Add dropdown-level event handler for preview buttons (dropdown
  appended to body, needs separate delegation)
- Enhanced EntitySearchEngine with improved product condition
  resolution and preview data
- Add EntityPreviewHandler for richer preview popovers
- Various SCSS improvements for chips, groups, and list-preview

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 21:33:14 +00:00
parent a7fbfa372c
commit 55e3135903
23 changed files with 2683 additions and 266 deletions

View File

@@ -422,16 +422,20 @@
console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest));
// Single bulk AJAX call for all entity types
var bulkAjaxData = {
ajax: 1,
action: 'getTargetEntitiesByIdsBulk',
trait: 'EntitySelector',
entities: JSON.stringify(bulkRequest)
};
if (self.config.productSelectionLevel && self.config.productSelectionLevel !== 'product') {
bulkAjaxData.product_selection_level = self.config.productSelectionLevel;
}
$.ajax({
url: self.config.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
ajax: 1,
action: 'getTargetEntitiesByIdsBulk',
trait: 'EntitySelector',
entities: JSON.stringify(bulkRequest)
},
data: bulkAjaxData,
success: function(response) {
console.log('[EntitySelector] AJAX response:', response);
if (!response.success || !response.entities) {
@@ -750,18 +754,22 @@
// Handle entity_search type - load via AJAX
var searchEntity = $picker.attr('data-search-entity') || blockType;
var pickerAjaxData = {
ajax: 1,
action: 'getTargetEntitiesByIds',
trait: 'EntitySelector',
entity_type: searchEntity,
ids: JSON.stringify(values)
};
if (this.config.productSelectionLevel && this.config.productSelectionLevel !== 'product') {
pickerAjaxData.product_selection_level = this.config.productSelectionLevel;
}
$.ajax({
url: this.config.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
ajax: 1,
action: 'getTargetEntitiesByIds',
trait: 'EntitySelector',
entity_type: searchEntity,
ids: JSON.stringify(values)
},
data: pickerAjaxData,
success: function(response) {
if (response.success && response.entities) {
// Track which IDs were actually found (entities may have been deleted)

View File

@@ -107,9 +107,9 @@
!$(e.target).closest('.group-count-badge').length &&
!$(e.target).closest('.group-modifiers').length &&
!$(e.target).closest('.group-preview-badge').length &&
!$(e.target).closest('.toggle-count.clickable').length &&
!$(e.target).closest('.trait-total-count').length &&
!$(e.target).closest('.chip-preview-holidays').length) {
!$(e.target).closest('.chip-preview-holidays').length &&
!$(e.target).closest('.chip-preview-btn').length) {
self.hidePreviewPopover();
// Also close holiday popover
$('.holiday-preview-popover').remove();
@@ -152,6 +152,31 @@
}
});
// Filter chip/group preview eye button (unified handler)
this.$wrapper.on('click', '.chip-preview-btn', function(e) {
e.preventDefault();
e.stopPropagation();
var $btn = $(this);
if ($btn.hasClass('popover-open')) {
self.hidePreviewPopover();
} else {
var valueId = $btn.data('id');
var valueType = $btn.data('type');
var valueName = $btn.data('name');
var groupId = $btn.data('groupId');
if (valueId) {
// Value-level preview (specific attribute/feature value)
self.showFilterValuePreviewPopover($btn, valueId, valueType, valueName, groupId);
} else if (groupId) {
// Group-level preview (entire attribute/feature group)
self.showFilterGroupPreviewPopover($btn, groupId, valueType, valueName);
}
}
});
// Group-level collapse toggle (click on group header or toggle icon)
this.$wrapper.on('click', '.group-header', function(e) {
if ($(e.target).closest('.btn-remove-group, .group-name-input').length) {
@@ -1031,7 +1056,7 @@
if (isSelected) {
// Remove from pending selections
self.pendingSelections = self.pendingSelections.filter(function(s) {
return parseInt(s.id, 10) !== parseInt(id, 10);
return String(s.id) !== String(id);
});
self.removeSelection($picker, id);
$item.toggleClass('selected');
@@ -1058,7 +1083,7 @@
} else {
// Add to pending selections
var exists = self.pendingSelections.some(function(s) {
return parseInt(s.id, 10) === parseInt(id, 10);
return String(s.id) === String(id);
});
if (!exists) {
self.pendingSelections.push({ id: id, name: name, data: $item.data() });
@@ -1083,7 +1108,7 @@
// Also remove from pending selections if dropdown is open
if (self.pendingSelections) {
self.pendingSelections = self.pendingSelections.filter(function(s) {
return parseInt(s.id, 10) !== parseInt(id, 10);
return String(s.id) !== String(id);
});
}
@@ -1210,7 +1235,7 @@
// Add to pending selections for Save button
var exists = self.pendingSelections.some(function(s) {
return parseInt(s.id, 10) === parseInt(id, 10);
return String(s.id) === String(id);
});
if (!exists) {
self.pendingSelections.push({
@@ -1825,10 +1850,6 @@
// Toggle filter group - show values
this.$dropdown.on('click', '.filter-group-toggle', function(e) {
// Ignore clicks on the preview badge
if ($(e.target).closest('.toggle-count.clickable').length) {
return;
}
e.preventDefault();
var $btn = $(this);
var groupId = $btn.data('group-id');
@@ -1845,20 +1866,26 @@
}
});
// Filter group toggle count badge click for preview popover
this.$dropdown.on('click', '.filter-group-toggle .toggle-count.clickable', function(e) {
e.stopPropagation();
// Filter preview eye button (dropdown-level, since dropdown is appended to body)
this.$dropdown.on('click', '.chip-preview-btn', function(e) {
e.preventDefault();
e.stopPropagation();
var $badge = $(this);
var groupId = $badge.data('groupId');
var groupType = $badge.data('type');
var groupName = $badge.data('groupName');
var $btn = $(this);
if ($badge.hasClass('popover-open')) {
if ($btn.hasClass('popover-open')) {
self.hidePreviewPopover();
} else {
self.showFilterGroupPreviewPopover($badge, groupId, groupType, groupName);
var valueId = $btn.data('id');
var valueType = $btn.data('type');
var valueName = $btn.data('name');
var groupId = $btn.data('groupId');
if (valueId) {
self.showFilterValuePreviewPopover($btn, valueId, valueType, valueName, groupId);
} else if (groupId) {
self.showFilterGroupPreviewPopover($btn, groupId, valueType, valueName);
}
}
});
@@ -2017,13 +2044,13 @@
// If already pinned, unpin and close
if ($wrapper.hasClass('pinned')) {
$wrapper.removeClass('pinned');
$wrapper.find('.material-icons').text('info_outline');
$wrapper.find('.material-icons').text('info');
$('.mpr-tooltip-fixed.pinned').remove();
return;
}
// Close any other pinned tooltips
$('.mpr-info-wrapper.pinned').removeClass('pinned').find('.material-icons').text('info_outline');
$('.mpr-info-wrapper.pinned').removeClass('pinned').find('.material-icons').text('info');
$('.mpr-tooltip-fixed').remove();
var content = $wrapper.attr('data-tooltip');
@@ -2043,7 +2070,7 @@
// Close button click
$closeBtn.on('click', function() {
$wrapper.removeClass('pinned');
$wrapper.find('.material-icons').text('info_outline');
$wrapper.find('.material-icons').text('info');
$tooltip.remove();
});

View File

@@ -228,6 +228,7 @@
if (!this.$dropdown || !this.filterableData) return;
var self = this;
var previewLabel = self.config.trans && self.config.trans.preview || 'Preview';
// Render attribute group toggle buttons
var $attrContainer = this.$dropdown.find('.filter-attributes-container');
@@ -235,12 +236,17 @@
if (this.filterableData.attributes && this.filterableData.attributes.length > 0) {
this.filterableData.attributes.forEach(function(group) {
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="attribute" data-group-name="' + self.escapeAttr(group.name) + '">';
var html = '<span class="filter-chip-wrapper">';
html += '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="attribute" data-group-name="' + self.escapeAttr(group.name) + '">';
html += '<span class="toggle-name">' + group.name + '</span>';
if (group.count !== undefined) {
html += '<span class="toggle-count clickable" data-group-id="' + group.id + '" data-type="attribute" data-group-name="' + self.escapeAttr(group.name) + '"><i class="icon-eye"></i> ' + group.count + '</span>';
html += '<span class="toggle-count">(' + group.count + ')</span>';
}
html += '</button>';
html += '<button type="button" class="chip-preview-btn" data-group-id="' + group.id + '" data-type="attribute" data-name="' + self.escapeAttr(group.name) + '" title="' + previewLabel + '">';
html += '<i class="icon-eye"></i>';
html += '</button>';
html += '</span>';
$attrContainer.append(html);
});
this.$dropdown.find('.filter-row-attributes').show();
@@ -252,12 +258,17 @@
if (this.filterableData.features && this.filterableData.features.length > 0) {
this.filterableData.features.forEach(function(group) {
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="feature" data-group-name="' + self.escapeAttr(group.name) + '">';
var html = '<span class="filter-chip-wrapper">';
html += '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="feature" data-group-name="' + self.escapeAttr(group.name) + '">';
html += '<span class="toggle-name">' + group.name + '</span>';
if (group.count !== undefined) {
html += '<span class="toggle-count clickable" data-group-id="' + group.id + '" data-type="feature" data-group-name="' + self.escapeAttr(group.name) + '"><i class="icon-eye"></i> ' + group.count + '</span>';
html += '<span class="toggle-count">(' + group.count + ')</span>';
}
html += '</button>';
html += '<button type="button" class="chip-preview-btn" data-group-id="' + group.id + '" data-type="feature" data-name="' + self.escapeAttr(group.name) + '" title="' + previewLabel + '">';
html += '<i class="icon-eye"></i>';
html += '</button>';
html += '</span>';
$featContainer.append(html);
});
this.$dropdown.find('.filter-row-features').show();
@@ -295,6 +306,7 @@
var colorStyle = val.color ? ' style="--chip-color: ' + val.color + '"' : '';
var colorClass = val.color ? ' has-color' : '';
html += '<span class="filter-chip-wrapper">';
html += '<button type="button" class="filter-chip ' + chipClass + activeClass + colorClass + '" data-id="' + val.id + '" data-group-id="' + groupId + '"' + colorStyle + '>';
if (val.color) {
html += '<span class="chip-color-dot"></span>';
@@ -304,6 +316,10 @@
html += '<span class="chip-count">(' + val.count + ')</span>';
}
html += '</button>';
html += '<button type="button" class="chip-preview-btn" data-id="' + val.id + '" data-group-id="' + groupId + '" data-type="' + type + '" data-name="' + self.escapeAttr(val.name) + '" title="' + (self.config.trans && self.config.trans.preview || 'Preview') + '">';
html += '<i class="icon-eye"></i>';
html += '</button>';
html += '</span>';
});
$valuesContainer.html(html);

View File

@@ -1852,7 +1852,8 @@
clearValidationError: function() {
this.$wrapper.removeClass('has-validation-error');
this.$wrapper.find('.trait-validation-error').remove();
}
},
};
})(jQuery);

View File

@@ -586,7 +586,7 @@
class: 'mpr-info-wrapper',
'data-tooltip': helpContent
});
$infoWrapper.append($('<i>', { class: 'material-icons', text: 'info_outline' }));
$infoWrapper.append($('<i>', { class: 'material-icons', text: 'info' }));
$placeholder.append($infoWrapper);
}
},

View File

@@ -192,23 +192,8 @@
});
}
// Position popover below badge
var badgeOffset = $badge.offset();
var badgeHeight = $badge.outerHeight();
var badgeWidth = $badge.outerWidth();
var popoverWidth = $popover.outerWidth();
var leftPos = badgeOffset.left + (badgeWidth / 2) - (popoverWidth / 2);
var minLeft = 10;
var maxLeft = $(window).width() - popoverWidth - 10;
leftPos = Math.max(minLeft, Math.min(leftPos, maxLeft));
$popover.css({
position: 'absolute',
top: badgeOffset.top + badgeHeight + 8,
left: leftPos,
zIndex: 10000
});
// Position popover relative to badge (handles viewport overflow)
this.positionPopover($popover, $badge);
// Show with transition
$popover.addClass('show');
@@ -216,6 +201,61 @@
return $popover;
},
/**
* Position a popover relative to a trigger element.
* Handles horizontal and vertical viewport overflow.
* @param {jQuery} $popover - The popover element
* @param {jQuery} $trigger - The trigger element to position against
* @param {number} [zIndex=10000] - Optional z-index
*/
positionPopover: function($popover, $trigger, zIndex) {
var triggerRect = $trigger[0].getBoundingClientRect();
var scrollTop = $(window).scrollTop();
var scrollLeft = $(window).scrollLeft();
var popoverWidth = $popover.outerWidth();
var popoverHeight = $popover.outerHeight();
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var gap = 8;
// Horizontal: center on trigger, then clamp to viewport
var left = triggerRect.left + scrollLeft + (triggerRect.width / 2) - (popoverWidth / 2);
left = Math.max(10, Math.min(left, windowWidth - popoverWidth - 10));
// Vertical: prefer below, flip above if it would overflow
var top;
var positionAbove = false;
if (triggerRect.bottom + popoverHeight + gap > windowHeight - 10) {
// Position above the trigger
top = triggerRect.top + scrollTop - popoverHeight - gap;
positionAbove = true;
} else {
// Position below the trigger
top = triggerRect.bottom + scrollTop + gap;
}
$popover.css({
position: 'absolute',
top: top,
left: left,
zIndex: zIndex || 10000
});
// Toggle arrow direction class
$popover.toggleClass('position-above', positionAbove);
// Determine horizontal arrow position class
var triggerCenter = triggerRect.left + (triggerRect.width / 2);
var popoverLeft = left;
var popoverCenter = popoverLeft + (popoverWidth / 2);
$popover.removeClass('position-left position-right');
if (triggerCenter - popoverLeft < popoverWidth * 0.3) {
$popover.addClass('position-right');
} else if (triggerCenter - popoverLeft > popoverWidth * 0.7) {
$popover.addClass('position-left');
}
},
/**
* Update popover after loading more items
*/
@@ -1180,6 +1220,144 @@
});
},
// =========================================================================
// FILTER VALUE PREVIEW (individual attribute/feature value chip)
// =========================================================================
/**
* Show preview popover for a specific filter value (attribute or feature value)
* @param {jQuery} $badge - The preview button on the chip
* @param {number} valueId - The attribute/feature value ID
* @param {string} valueType - 'attribute' or 'feature'
* @param {string} valueName - Display name of the value
* @param {number} groupId - The parent group ID
*/
showFilterValuePreviewPopover: function($badge, valueId, valueType, valueName, groupId) {
var self = this;
this.hidePreviewPopover();
$badge.addClass('popover-open loading');
this.$activeBadge = $badge;
$.ajax({
url: this.config.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
ajax: 1,
action: 'previewFilterValueProducts',
trait: 'EntitySelector',
value_id: valueId,
value_type: valueType,
group_id: groupId,
limit: 10
},
success: function(response) {
$badge.removeClass('loading');
if (response.success) {
self.createPreviewPopover({
$badge: $badge,
items: response.items || [],
totalCount: response.count || 0,
hasMore: response.hasMore || false,
entityLabel: 'products',
previewType: 'filter-value',
context: { valueId: valueId, valueType: valueType, groupId: groupId, valueName: valueName },
onLoadMore: function($btn) {
self.loadMoreFilterValueItems($btn);
},
onFilter: function(query) {
self.filterFilterValueItems(query);
}
});
} else {
$badge.removeClass('popover-open');
self.$activeBadge = null;
}
},
error: function() {
$badge.removeClass('loading popover-open');
self.$activeBadge = null;
}
});
},
/**
* AJAX filter handler for filter value preview
*/
filterFilterValueItems: function(query) {
var self = this;
var ctx = this.previewContext;
if (!ctx || !ctx.valueId) {
self.showFilterLoading(false);
return;
}
$.ajax({
url: this.config.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
ajax: 1,
action: 'previewFilterValueProducts',
trait: 'EntitySelector',
value_id: ctx.valueId,
value_type: ctx.valueType,
group_id: ctx.groupId,
filter: query,
limit: 20
},
success: function(response) {
self.updatePreviewPopoverFiltered(response);
},
error: function() {
self.showFilterLoading(false);
}
});
},
loadMoreFilterValueItems: function($btn) {
var self = this;
var ctx = this.previewContext;
if (!ctx || !ctx.valueId) return;
var loadCount = this.previewLoadCount || 20;
var ajaxData = {
ajax: 1,
action: 'previewFilterValueProducts',
trait: 'EntitySelector',
value_id: ctx.valueId,
value_type: ctx.valueType,
group_id: ctx.groupId,
limit: self.previewLoadedCount + loadCount
};
if (self.previewCurrentFilter) {
ajaxData.filter = self.previewCurrentFilter;
}
$.ajax({
url: this.config.ajaxUrl,
type: 'POST',
dataType: 'json',
data: ajaxData,
success: function(response) {
if (response.success) {
self.previewTotalCount = response.count;
self.updatePreviewPopover(response.items || [], response.hasMore);
}
},
error: function() {
$btn.removeClass('loading');
$btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus');
}
});
},
// =========================================================================
// CATEGORY ITEMS PREVIEW (products/pages in a category)
// =========================================================================
@@ -1517,28 +1695,9 @@
self.switchToBlock(blockType);
});
// Position popover
// Position popover relative to badge (handles viewport overflow)
$('body').append($popover);
var badgeOffset = $badge.offset();
var badgeHeight = $badge.outerHeight();
var popoverWidth = $popover.outerWidth();
$popover.css({
position: 'absolute',
top: badgeOffset.top + badgeHeight + 5,
left: badgeOffset.left - (popoverWidth / 2) + ($badge.outerWidth() / 2),
zIndex: 10000
});
// Adjust if off screen
var windowWidth = $(window).width();
var popoverRight = $popover.offset().left + popoverWidth;
if (popoverRight > windowWidth - 10) {
$popover.css('left', windowWidth - popoverWidth - 10);
}
if ($popover.offset().left < 10) {
$popover.css('left', 10);
}
this.positionPopover($popover, $badge);
$popover.hide().fadeIn(150);
},

View File

@@ -40,6 +40,11 @@
sort_dir: this.currentSort ? this.currentSort.dir : 'ASC'
};
// Add product_selection_level if set
if (this.config.productSelectionLevel && this.config.productSelectionLevel !== 'product') {
requestData.product_selection_level = this.config.productSelectionLevel;
}
// Add refine query if present
if (this.refineQuery) {
requestData.refine = this.refineQuery;
@@ -367,6 +372,8 @@
var isSelected = selectedIds.indexOf(String(item.id)) !== -1;
var itemClass = 'dropdown-item' + (isSelected ? ' selected' : '');
if (item.type === 'product') itemClass += ' result-item-product';
if (item.is_combination) itemClass += ' is-combination';
if (item.is_parent) itemClass += ' is-parent-product';
html += '<div class="' + itemClass + '" ';
html += 'data-id="' + self.escapeAttr(item.id) + '" ';
@@ -374,6 +381,7 @@
if (item.image) html += ' data-image="' + self.escapeAttr(item.image) + '"';
if (item.subtitle) html += ' data-subtitle="' + self.escapeAttr(item.subtitle) + '"';
if (item.iso_code) html += ' data-iso="' + self.escapeAttr(item.iso_code) + '"';
if (item.attributes) html += ' data-attributes="' + self.escapeAttr(item.attributes) + '"';
html += '>';
html += '<span class="result-checkbox"><i class="icon-check"></i></span>';

View File

@@ -343,6 +343,16 @@
word-break: break-word;
}
.chip-attrs {
font-size: 0.85em;
opacity: 0.7;
margin-left: 2px;
&::before {
content: '';
}
}
.chip-remove {
@include button-reset;
display: flex;

View File

@@ -359,6 +359,20 @@
gap: $es-spacing-sm;
}
// Combination-level search results ('both' mode)
.dropdown-item.is-combination {
padding-left: 28px;
.result-name {
font-size: 0.9em;
}
}
.dropdown-item.is-parent-product {
background: $es-slate-50;
font-weight: $es-font-weight-medium;
}
// No results state
.no-results {
display: flex;
@@ -1290,50 +1304,9 @@ body > .target-search-dropdown,
font-weight: $es-font-weight-medium;
}
// Count with eye icon (like group-count-badge)
.toggle-count {
display: inline-flex;
align-items: center;
gap: 0.125rem;
color: $es-text-muted;
font-size: 0.65rem;
i {
font-size: 10px;
color: $es-primary;
}
// Clickable preview badge
&.clickable {
cursor: pointer;
padding: 0.125rem 0.25rem;
border-radius: $es-radius-sm;
transition: all $es-transition-fast;
&:hover {
background: rgba($es-primary, 0.1);
color: $es-primary;
i {
color: $es-primary;
}
}
&.popover-open {
background: $es-primary;
color: $es-white;
i {
color: $es-white;
}
}
&.loading {
i {
animation: spin 0.6s linear infinite;
}
}
}
}
}
@@ -1426,6 +1399,67 @@ body > .target-search-dropdown,
color: rgba(255, 255, 255, 0.8);
}
// Filter chip wrapper (chip/toggle + preview button)
.filter-chip-wrapper {
display: inline-flex;
align-items: stretch;
border-radius: $es-radius-sm;
overflow: hidden;
// Left element gets left-only border-radius
.filter-chip,
.filter-group-toggle {
border-radius: $es-radius-sm 0 0 $es-radius-sm;
}
// Preview eye button — unified for both value chips and group toggles
.chip-preview-btn {
@include button-reset;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 0.375rem;
font-size: 10px;
color: $es-text-muted;
background: $es-slate-100;
border-left: 1px solid $es-border-color;
border-radius: 0 $es-radius-sm $es-radius-sm 0;
cursor: pointer;
transition: all $es-transition-fast;
&:hover {
background: rgba($es-primary, 0.1);
color: $es-primary;
}
&.popover-open {
background: $es-primary;
color: $es-white;
}
&.loading i {
animation: spin 0.6s linear infinite;
}
}
// When no preview button, restore full border-radius
.filter-chip:last-child,
.filter-group-toggle:last-child {
border-radius: $es-radius-sm;
}
// Group toggle active/has-selection states propagate to wrapper border
.filter-group-toggle.active + .chip-preview-btn {
border-left-color: $es-primary;
background: rgba($es-primary, 0.05);
}
.filter-group-toggle.has-selection + .chip-preview-btn {
border-left-color: $es-success;
background: rgba($es-success, 0.03);
}
}
// Dropdown content
.dropdown-content {
max-height: 400px;

View File

@@ -368,6 +368,7 @@
// Single mode specific styles
.target-conditions-trait.single-mode,
.entity-selector-trait.single-mode {
// Hide tabs in standalone layout (has separate header, 1 tab is redundant)
.target-block-tabs {
display: none;
}
@@ -375,6 +376,11 @@
.target-block-container {
display: block;
}
// In form-content layout, always show tabs — they serve as the block title
.entity-selector-tabs-row .target-block-tabs {
display: flex;
}
}
// Header action buttons

View File

@@ -931,6 +931,36 @@
background-size: 1.25em 1.25em;
}
// Single mode — strip padding, borders, backgrounds for clean single-selection UI
&[data-mode=single],
.mode-single {
.groups-container {
padding: 0;
}
.group-body {
padding: 0;
}
.group-include {
padding: 0.5rem;
margin-bottom: 0;
background: transparent;
border: none;
border-radius: 0;
}
.selection-group {
background: transparent;
border: none;
margin-bottom: 0;
}
.group-header {
display: none;
}
}
// Condition match count badge
.condition-match-count {
display: inline-flex;

View File

@@ -66,6 +66,23 @@
transform: none;
}
}
// Positioned above trigger - arrow pointing down
&.position-above {
&::before {
top: auto;
bottom: -8px;
border-top: 8px solid $es-border-color;
border-bottom: 0;
}
&::after {
top: auto;
bottom: -6px;
border-top: 6px solid $es-white;
border-bottom: 0;
}
}
}
// =============================================================================