@ship-ui/core 0.17.16 → 0.17.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/mcp/components.json +2261 -2255
- package/fesm2022/ship-ui-core.mjs +98 -64
- package/fesm2022/ship-ui-core.mjs.map +1 -1
- package/package.json +1 -1
- package/snippets/ship-ui.code-snippets +275 -275
- package/types/ship-ui-core.d.ts +0 -3
|
@@ -7014,31 +7014,56 @@ class ShipTooltipWrapper {
|
|
|
7014
7014
|
close: () => this.close()(),
|
|
7015
7015
|
};
|
|
7016
7016
|
this.isTemplate = computed(() => this.content() instanceof TemplateRef, ...(ngDevMode ? [{ debugName: "isTemplate" }] : []));
|
|
7017
|
+
this.#document = inject(DOCUMENT);
|
|
7017
7018
|
this.#selfRef = inject((ElementRef));
|
|
7018
7019
|
this.#renderer = inject(Renderer2);
|
|
7019
7020
|
this.#positionAbort = null;
|
|
7020
|
-
this.SUPPORTS_ANCHOR = typeof CSS !== 'undefined' && CSS.supports('position-anchor', '--abc');
|
|
7021
|
+
this.SUPPORTS_ANCHOR = typeof CSS !== 'undefined' && CSS.supports('position-anchor', '--abc') && CSS.supports('anchor-name', '--abc');
|
|
7021
7022
|
this.isBelow = signal(false, ...(ngDevMode ? [{ debugName: "isBelow" }] : []));
|
|
7022
7023
|
this.openEffect = effect(() => {
|
|
7023
7024
|
if (this.isOpen()) {
|
|
7024
|
-
|
|
7025
|
-
this.#selfRef.nativeElement
|
|
7026
|
-
|
|
7025
|
+
queueMicrotask(() => {
|
|
7026
|
+
const tooltipEl = this.#selfRef.nativeElement;
|
|
7027
|
+
if (!tooltipEl || !tooltipEl.isConnected)
|
|
7028
|
+
return;
|
|
7029
|
+
if (this.#positionAbort) {
|
|
7030
|
+
this.#positionAbort.abort();
|
|
7031
|
+
}
|
|
7032
|
+
this.#positionAbort = new AbortController();
|
|
7033
|
+
tooltipEl.showPopover();
|
|
7034
|
+
if (!this.SUPPORTS_ANCHOR) {
|
|
7035
|
+
setTimeout(() => {
|
|
7036
|
+
const scrollableParent = this.#findScrollableParent(tooltipEl);
|
|
7037
|
+
scrollableParent.addEventListener('scroll', () => this.calculateTooltipPosition(), {
|
|
7038
|
+
signal: this.#positionAbort?.signal,
|
|
7039
|
+
passive: true,
|
|
7040
|
+
});
|
|
7041
|
+
window?.addEventListener('resize', () => this.calculateTooltipPosition(), {
|
|
7042
|
+
signal: this.#positionAbort?.signal,
|
|
7043
|
+
passive: true,
|
|
7044
|
+
});
|
|
7045
|
+
this.calculateTooltipPosition();
|
|
7046
|
+
});
|
|
7047
|
+
}
|
|
7027
7048
|
});
|
|
7028
7049
|
}
|
|
7029
7050
|
else {
|
|
7030
|
-
this.#selfRef.nativeElement
|
|
7051
|
+
const tooltipEl = this.#selfRef.nativeElement;
|
|
7052
|
+
if (tooltipEl) {
|
|
7053
|
+
try {
|
|
7054
|
+
if (tooltipEl.matches(':popover-open')) {
|
|
7055
|
+
tooltipEl.hidePopover();
|
|
7056
|
+
}
|
|
7057
|
+
}
|
|
7058
|
+
catch (e) {
|
|
7059
|
+
// Ignore if already hidden or other errors
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
7062
|
+
this.#positionAbort?.abort();
|
|
7063
|
+
this.#positionAbort = null;
|
|
7031
7064
|
}
|
|
7032
7065
|
}, ...(ngDevMode ? [{ debugName: "openEffect" }] : []));
|
|
7033
|
-
this.rafId = null;
|
|
7034
|
-
this.schedulePositionUpdate = () => {
|
|
7035
|
-
if (this.rafId !== null) {
|
|
7036
|
-
cancelAnimationFrame(this.rafId);
|
|
7037
|
-
}
|
|
7038
|
-
this.rafId = requestAnimationFrame(this.calculateTooltipPosition);
|
|
7039
|
-
};
|
|
7040
7066
|
this.calculateTooltipPosition = () => {
|
|
7041
|
-
this.rafId = null;
|
|
7042
7067
|
if (!this.anchorEl())
|
|
7043
7068
|
return;
|
|
7044
7069
|
const hostRect = this.anchorEl().nativeElement.getBoundingClientRect();
|
|
@@ -7046,61 +7071,71 @@ class ShipTooltipWrapper {
|
|
|
7046
7071
|
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
7047
7072
|
if (tooltipRect.width === 0 && tooltipRect.height === 0)
|
|
7048
7073
|
return;
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7074
|
+
const BASE_SPACE = 8;
|
|
7075
|
+
// Position generators
|
|
7076
|
+
const topCenter = (t, m) => ({
|
|
7077
|
+
left: t.left + t.width / 2 - m.width / 2,
|
|
7078
|
+
top: t.top - m.height - BASE_SPACE,
|
|
7079
|
+
});
|
|
7080
|
+
const bottomCenter = (t, m) => ({
|
|
7081
|
+
left: t.left + t.width / 2 - m.width / 2,
|
|
7082
|
+
top: t.bottom + BASE_SPACE,
|
|
7083
|
+
});
|
|
7084
|
+
const topSpanLeft = (t, m) => ({ left: t.right - m.width, top: t.top - m.height - BASE_SPACE });
|
|
7085
|
+
const topSpanRight = (t, m) => ({ left: t.left, top: t.top - m.height - BASE_SPACE });
|
|
7086
|
+
const bottomSpanLeft = (t, m) => ({ left: t.right - m.width, top: t.bottom + BASE_SPACE });
|
|
7087
|
+
const bottomSpanRight = (t, m) => ({ left: t.left, top: t.bottom + BASE_SPACE });
|
|
7088
|
+
const tryOrder = [topCenter, topSpanLeft, topSpanRight, bottomCenter, bottomSpanLeft, bottomSpanRight];
|
|
7089
|
+
for (const positionFn of tryOrder) {
|
|
7090
|
+
const pos = positionFn(hostRect, tooltipRect);
|
|
7091
|
+
if (this.#fitsInViewport(pos, tooltipRect)) {
|
|
7092
|
+
this.#applyPosition(pos, tooltipEl);
|
|
7093
|
+
this.isBelow.set(pos.top > hostRect.top);
|
|
7094
|
+
return;
|
|
7053
7095
|
}
|
|
7054
|
-
return;
|
|
7055
|
-
}
|
|
7056
|
-
const gap = 12;
|
|
7057
|
-
const outOfBoundsTop = hostRect.top - tooltipRect.height - gap < 0;
|
|
7058
|
-
if (this.isBelow() !== outOfBoundsTop) {
|
|
7059
|
-
this.isBelow.set(outOfBoundsTop);
|
|
7060
|
-
}
|
|
7061
|
-
let newTop = hostRect.top - tooltipRect.height - gap;
|
|
7062
|
-
let newLeft = hostRect.left + hostRect.width / 2 - tooltipRect.width / 2;
|
|
7063
|
-
if (outOfBoundsTop) {
|
|
7064
|
-
newTop = hostRect.top + hostRect.height;
|
|
7065
|
-
}
|
|
7066
|
-
if (newLeft + tooltipRect.width > window?.innerWidth) {
|
|
7067
|
-
newLeft = hostRect.right - tooltipRect.width / 2;
|
|
7068
|
-
}
|
|
7069
|
-
if (newLeft < 0) {
|
|
7070
|
-
newLeft = -(tooltipRect.width / 2);
|
|
7071
|
-
}
|
|
7072
|
-
const leftStyle = `${newLeft}px`;
|
|
7073
|
-
const topStyle = `${newTop}px`;
|
|
7074
|
-
if (tooltipEl.style.left !== leftStyle) {
|
|
7075
|
-
this.#renderer.setStyle(tooltipEl, 'left', leftStyle);
|
|
7076
|
-
}
|
|
7077
|
-
if (tooltipEl.style.top !== topStyle) {
|
|
7078
|
-
this.#renderer.setStyle(tooltipEl, 'top', topStyle);
|
|
7079
|
-
}
|
|
7080
|
-
if (tooltipEl.style.position !== 'fixed') {
|
|
7081
|
-
this.#renderer.setStyle(tooltipEl, 'position', 'fixed');
|
|
7082
7096
|
}
|
|
7097
|
+
const fallback = this.#clampToViewport(topCenter(hostRect, tooltipRect), tooltipRect);
|
|
7098
|
+
this.#applyPosition(fallback, tooltipEl);
|
|
7099
|
+
this.isBelow.set(fallback.top > hostRect.top);
|
|
7083
7100
|
};
|
|
7084
7101
|
}
|
|
7102
|
+
#document;
|
|
7085
7103
|
#selfRef;
|
|
7086
7104
|
#renderer;
|
|
7087
7105
|
#positionAbort;
|
|
7088
|
-
ngAfterViewInit() {
|
|
7089
|
-
this.#positionAbort = new AbortController();
|
|
7090
|
-
const options = { signal: this.#positionAbort.signal, capture: true, passive: true };
|
|
7091
|
-
window?.addEventListener('scroll', this.schedulePositionUpdate, options);
|
|
7092
|
-
window?.addEventListener('resize', this.schedulePositionUpdate, {
|
|
7093
|
-
signal: this.#positionAbort.signal,
|
|
7094
|
-
passive: true,
|
|
7095
|
-
});
|
|
7096
|
-
this.schedulePositionUpdate();
|
|
7097
|
-
}
|
|
7098
7106
|
ngOnDestroy() {
|
|
7099
7107
|
this.#positionAbort?.abort();
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7108
|
+
this.#positionAbort = null;
|
|
7109
|
+
}
|
|
7110
|
+
#findScrollableParent(element) {
|
|
7111
|
+
const SCROLLABLE_STYLES = ['scroll', 'auto'];
|
|
7112
|
+
let parent = element.parentElement;
|
|
7113
|
+
while (parent) {
|
|
7114
|
+
if (SCROLLABLE_STYLES.indexOf(window?.getComputedStyle(parent).overflowY) > -1 &&
|
|
7115
|
+
parent.scrollHeight > parent.clientHeight) {
|
|
7116
|
+
return parent;
|
|
7117
|
+
}
|
|
7118
|
+
parent = parent.parentElement;
|
|
7103
7119
|
}
|
|
7120
|
+
return this.#document.documentElement;
|
|
7121
|
+
}
|
|
7122
|
+
#applyPosition(pos, element) {
|
|
7123
|
+
this.#renderer.setStyle(element, 'left', `${pos.left}px`);
|
|
7124
|
+
this.#renderer.setStyle(element, 'top', `${pos.top}px`);
|
|
7125
|
+
this.#renderer.setStyle(element, 'position', 'fixed');
|
|
7126
|
+
this.#renderer.setStyle(element, 'margin', '0');
|
|
7127
|
+
}
|
|
7128
|
+
#fitsInViewport(pos, m) {
|
|
7129
|
+
return (pos.left >= 0 &&
|
|
7130
|
+
pos.top >= 0 &&
|
|
7131
|
+
pos.left + m.width <= window.innerWidth &&
|
|
7132
|
+
pos.top + m.height <= window.innerHeight);
|
|
7133
|
+
}
|
|
7134
|
+
#clampToViewport(pos, m) {
|
|
7135
|
+
return {
|
|
7136
|
+
left: Math.max(0, Math.min(pos.left, window.innerWidth - m.width)),
|
|
7137
|
+
top: Math.max(0, Math.min(pos.top, window.innerHeight - m.height)),
|
|
7138
|
+
};
|
|
7104
7139
|
}
|
|
7105
7140
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: ShipTooltipWrapper, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7106
7141
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: ShipTooltipWrapper, isStandalone: true, selector: "ship-tooltip-wrapper", inputs: { positionAnchorName: { classPropertyName: "positionAnchorName", publicName: "positionAnchorName", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, close: { classPropertyName: "close", publicName: "close", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tooltip" }, properties: { "attr.popover": "\"manual\"", "style.position-anchor": "positionAnchorName()", "class.below": "isBelow()" } }, ngImport: i0, template: `
|
|
@@ -7219,13 +7254,12 @@ class ShipTooltip {
|
|
|
7219
7254
|
cleanupTooltip() {
|
|
7220
7255
|
if (openRef?.wrapperComponentRef) {
|
|
7221
7256
|
openRef.component.cancelCleanupTimer();
|
|
7222
|
-
const nativeEl = openRef.wrapperComponentRef.location.nativeElement;
|
|
7223
|
-
if (nativeEl && typeof nativeEl.matches === 'function' && nativeEl.matches(':popover-open')) {
|
|
7224
|
-
nativeEl.hidePopover();
|
|
7225
|
-
}
|
|
7226
|
-
openRef.wrapperComponentRef.destroy();
|
|
7227
7257
|
openRef.component.isOpen.set(false);
|
|
7228
|
-
openRef
|
|
7258
|
+
openRef.wrapperComponentRef.location.nativeElement.hidePopover();
|
|
7259
|
+
setTimeout(() => {
|
|
7260
|
+
openRef.wrapperComponentRef.destroy();
|
|
7261
|
+
openRef = null;
|
|
7262
|
+
});
|
|
7229
7263
|
}
|
|
7230
7264
|
}
|
|
7231
7265
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: ShipTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|