@aquera/nile-elements 0.1.34 → 0.1.35-beta-1.2
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/README.md +29 -8
- package/demo/index.css +7 -4
- package/demo/index.html +20 -36
- package/demo/variables.css +13 -0
- package/demo/variables_v2.css +13 -0
- package/dist/{fixture-161dee0b.cjs.js → fixture-d5b55278.cjs.js} +3 -3
- package/dist/fixture-d5b55278.cjs.js.map +1 -0
- package/dist/{fixture-372df3b0.esm.js → fixture-df8b52d7.esm.js} +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/internal/animate.cjs.js +1 -1
- package/dist/internal/animate.cjs.js.map +1 -1
- package/dist/internal/animate.esm.js +1 -1
- package/dist/nile-accordion/nile-accordian.test.cjs.js +1 -1
- package/dist/nile-accordion/nile-accordian.test.esm.js +1 -1
- package/dist/nile-auto-complete/nile-auto-complete.test.cjs.js +1 -1
- package/dist/nile-auto-complete/nile-auto-complete.test.esm.js +1 -1
- package/dist/nile-avatar/nile-avatar.test.cjs.js +1 -1
- package/dist/nile-avatar/nile-avatar.test.esm.js +1 -1
- package/dist/nile-badge/nile-badge.test.cjs.js +1 -1
- package/dist/nile-badge/nile-badge.test.esm.js +1 -1
- package/dist/nile-button/nile-button.test.cjs.js +1 -1
- package/dist/nile-button/nile-button.test.esm.js +1 -1
- package/dist/nile-button-toggle-group/nile-button-toggle-group.test.cjs.js +1 -1
- package/dist/nile-button-toggle-group/nile-button-toggle-group.test.esm.js +1 -1
- package/dist/nile-calendar/nile-calendar.test.cjs.js +1 -1
- package/dist/nile-calendar/nile-calendar.test.esm.js +1 -1
- package/dist/nile-card/nile-card.test.cjs.js +1 -1
- package/dist/nile-card/nile-card.test.esm.js +1 -1
- package/dist/nile-checkbox/nile-checkbox.test.cjs.js +1 -1
- package/dist/nile-checkbox/nile-checkbox.test.esm.js +1 -1
- package/dist/nile-chip/nile-chip.test.cjs.js +1 -1
- package/dist/nile-chip/nile-chip.test.esm.js +1 -1
- package/dist/nile-code-editor/extensionSetup.cjs.js +1 -1
- package/dist/nile-code-editor/extensionSetup.cjs.js.map +1 -1
- package/dist/nile-code-editor/extensionSetup.esm.js +1 -1
- package/dist/nile-code-editor/nile-code-editor.cjs.js +1 -1
- package/dist/nile-code-editor/nile-code-editor.cjs.js.map +1 -1
- package/dist/nile-code-editor/nile-code-editor.esm.js +2 -2
- package/dist/nile-dialog/nile-dialog.test.cjs.js +1 -1
- package/dist/nile-dialog/nile-dialog.test.esm.js +1 -1
- package/dist/nile-drawer/nile-drawer.test.cjs.js +1 -1
- package/dist/nile-drawer/nile-drawer.test.esm.js +1 -1
- package/dist/nile-dropdown/nile-dropdown.test.cjs.js +1 -1
- package/dist/nile-dropdown/nile-dropdown.test.esm.js +1 -1
- package/dist/nile-empty-state/nile-empty-state.test.cjs.js +1 -1
- package/dist/nile-empty-state/nile-empty-state.test.esm.js +1 -1
- package/dist/nile-error-message/nile-error-message.cjs.js +1 -1
- package/dist/nile-error-message/nile-error-message.cjs.js.map +1 -1
- package/dist/nile-error-message/nile-error-message.css.cjs.js +1 -1
- package/dist/nile-error-message/nile-error-message.css.cjs.js.map +1 -1
- package/dist/nile-error-message/nile-error-message.css.esm.js +6 -4
- package/dist/nile-error-message/nile-error-message.esm.js +4 -4
- package/dist/nile-error-message/nile-error-message.test.cjs.js +1 -1
- package/dist/nile-error-message/nile-error-message.test.esm.js +1 -1
- package/dist/nile-error-notification/nile-error-notification.css.cjs.js +1 -1
- package/dist/nile-error-notification/nile-error-notification.css.cjs.js.map +1 -1
- package/dist/nile-error-notification/nile-error-notification.css.esm.js +1 -1
- package/dist/nile-filter-chip/index.cjs.js +2 -0
- package/dist/nile-filter-chip/index.cjs.js.map +1 -0
- package/dist/nile-filter-chip/index.esm.js +1 -0
- package/dist/nile-filter-chip/nile-filter-chip.cjs.js +2 -0
- package/dist/nile-filter-chip/nile-filter-chip.cjs.js.map +1 -0
- package/dist/nile-filter-chip/nile-filter-chip.css.cjs.js +2 -0
- package/dist/nile-filter-chip/nile-filter-chip.css.cjs.js.map +1 -0
- package/dist/nile-filter-chip/nile-filter-chip.css.esm.js +98 -0
- package/dist/nile-filter-chip/nile-filter-chip.esm.js +34 -0
- package/dist/nile-filter-chip/nile-filter-chip.test.cjs.js +2 -0
- package/dist/nile-filter-chip/nile-filter-chip.test.cjs.js.map +1 -0
- package/dist/nile-filter-chip/nile-filter-chip.test.esm.js +20 -0
- package/dist/nile-form-group/nile-form-group.test.cjs.js +1 -1
- package/dist/nile-form-group/nile-form-group.test.esm.js +1 -1
- package/dist/nile-form-help-text/nile-form-help-text.test.cjs.js +1 -1
- package/dist/nile-form-help-text/nile-form-help-text.test.esm.js +1 -1
- package/dist/nile-hero/nile-hero.test.cjs.js +1 -1
- package/dist/nile-hero/nile-hero.test.esm.js +1 -1
- package/dist/nile-icon/nile-icon.test.cjs.js +1 -1
- package/dist/nile-icon/nile-icon.test.esm.js +1 -1
- package/dist/nile-input/nile-input.test.cjs.js +1 -1
- package/dist/nile-input/nile-input.test.esm.js +1 -1
- package/dist/nile-link/nile-link.test.cjs.js +1 -1
- package/dist/nile-link/nile-link.test.esm.js +1 -1
- package/dist/nile-loader/nile-loader.test.cjs.js +1 -1
- package/dist/nile-loader/nile-loader.test.esm.js +1 -1
- package/dist/nile-popover/nile-popover.test.cjs.js +1 -1
- package/dist/nile-popover/nile-popover.test.esm.js +1 -1
- package/dist/nile-popup/nile-popup.test.cjs.js +1 -1
- package/dist/nile-popup/nile-popup.test.esm.js +1 -1
- package/dist/nile-progress-bar/nile-progress-bar.css.cjs.js +1 -1
- package/dist/nile-progress-bar/nile-progress-bar.css.cjs.js.map +1 -1
- package/dist/nile-progress-bar/nile-progress-bar.css.esm.js +1 -0
- package/dist/nile-progress-bar/nile-progress-bar.test.cjs.js +1 -1
- package/dist/nile-progress-bar/nile-progress-bar.test.esm.js +1 -1
- package/dist/nile-radio/nile-radio.test.cjs.js +1 -1
- package/dist/nile-radio/nile-radio.test.esm.js +1 -1
- package/dist/nile-radio-group/nile-radio-group.test.cjs.js +1 -1
- package/dist/nile-radio-group/nile-radio-group.test.esm.js +1 -1
- package/dist/nile-select/nile-select.cjs.js +1 -1
- package/dist/nile-select/nile-select.cjs.js.map +1 -1
- package/dist/nile-select/nile-select.esm.js +1 -1
- package/dist/nile-select/nile-select.test.cjs.js +1 -1
- package/dist/nile-select/nile-select.test.esm.js +1 -1
- package/dist/nile-slide-toggle/nile-slide-toggle.test.cjs.js +1 -1
- package/dist/nile-slide-toggle/nile-slide-toggle.test.esm.js +1 -1
- package/dist/nile-tab-group/nile-tab-group.test.cjs.js +1 -1
- package/dist/nile-tab-group/nile-tab-group.test.esm.js +1 -1
- package/dist/nile-table/nile-table.cjs.js.map +1 -1
- package/dist/nile-textarea/nile-textarea.test.cjs.js +1 -1
- package/dist/nile-textarea/nile-textarea.test.esm.js +1 -1
- package/dist/nile-tooltip/index.cjs.js +1 -1
- package/dist/nile-tooltip/index.esm.js +1 -1
- package/dist/nile-tooltip/nile-tooltip-utils.cjs.js +2 -0
- package/dist/nile-tooltip/nile-tooltip-utils.cjs.js.map +1 -0
- package/dist/nile-tooltip/nile-tooltip-utils.esm.js +1 -0
- package/dist/nile-tooltip/nile-tooltip.cjs.js +1 -1
- package/dist/nile-tooltip/nile-tooltip.cjs.js.map +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.cjs.js +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.cjs.js.map +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.esm.js +78 -45
- package/dist/nile-tooltip/nile-tooltip.esm.js +23 -28
- package/dist/nile-tooltip/nile-tooltip.test.cjs.js +2 -0
- package/dist/nile-tooltip/nile-tooltip.test.cjs.js.map +1 -0
- package/dist/nile-tooltip/nile-tooltip.test.esm.js +47 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/nile-code-editor/extensionSetup.d.ts +2 -1
- package/dist/src/nile-code-editor/extensionSetup.js +8 -0
- package/dist/src/nile-code-editor/extensionSetup.js.map +1 -1
- package/dist/src/nile-code-editor/nile-code-editor.d.ts +2 -0
- package/dist/src/nile-code-editor/nile-code-editor.js +12 -3
- package/dist/src/nile-code-editor/nile-code-editor.js.map +1 -1
- package/dist/src/nile-error-message/nile-error-message.css.js +6 -4
- package/dist/src/nile-error-message/nile-error-message.css.js.map +1 -1
- package/dist/src/nile-error-message/nile-error-message.d.ts +4 -0
- package/dist/src/nile-error-message/nile-error-message.js +20 -0
- package/dist/src/nile-error-message/nile-error-message.js.map +1 -1
- package/dist/src/nile-error-notification/nile-error-notification.css.js +1 -1
- package/dist/src/nile-error-notification/nile-error-notification.css.js.map +1 -1
- package/dist/src/nile-filter-chip/index.d.ts +1 -0
- package/dist/src/nile-filter-chip/index.js +2 -0
- package/dist/src/nile-filter-chip/index.js.map +1 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.css.d.ts +12 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.css.js +110 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.css.js.map +1 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.d.ts +35 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.js +128 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.js.map +1 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.test.d.ts +1 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.test.js +80 -0
- package/dist/src/nile-filter-chip/nile-filter-chip.test.js.map +1 -0
- package/dist/src/nile-progress-bar/nile-progress-bar.css.js +1 -0
- package/dist/src/nile-progress-bar/nile-progress-bar.css.js.map +1 -1
- package/dist/src/nile-select/nile-select.js +1 -1
- package/dist/src/nile-select/nile-select.js.map +1 -1
- package/dist/src/nile-table/nile-table.js.map +1 -1
- package/dist/src/nile-tooltip/nile-tooltip-utils.d.ts +18 -0
- package/dist/src/nile-tooltip/nile-tooltip-utils.js +216 -0
- package/dist/src/nile-tooltip/nile-tooltip-utils.js.map +1 -0
- package/dist/src/nile-tooltip/nile-tooltip.css.js +76 -43
- package/dist/src/nile-tooltip/nile-tooltip.css.js.map +1 -1
- package/dist/src/nile-tooltip/nile-tooltip.d.ts +24 -46
- package/dist/src/nile-tooltip/nile-tooltip.js +235 -232
- package/dist/src/nile-tooltip/nile-tooltip.js.map +1 -1
- package/dist/src/nile-tooltip/nile-tooltip.test.d.ts +1 -0
- package/dist/src/nile-tooltip/nile-tooltip.test.js +148 -0
- package/dist/src/nile-tooltip/nile-tooltip.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +2 -1
- package/src/nile-code-editor/extensionSetup.ts +13 -1
- package/src/nile-code-editor/nile-code-editor.ts +9 -4
- package/src/nile-error-message/nile-error-message.css.ts +6 -4
- package/src/nile-error-message/nile-error-message.ts +18 -0
- package/src/nile-error-notification/nile-error-notification.css.ts +1 -1
- package/src/nile-filter-chip/index.ts +1 -0
- package/src/nile-filter-chip/nile-filter-chip.css.ts +115 -0
- package/src/nile-filter-chip/nile-filter-chip.test.ts +92 -0
- package/src/nile-filter-chip/nile-filter-chip.ts +125 -0
- package/src/nile-progress-bar/nile-progress-bar.css.ts +1 -0
- package/src/nile-select/nile-select.ts +1 -1
- package/src/nile-table/nile-table.ts +2 -2
- package/src/nile-tooltip/nile-tooltip-utils.ts +271 -0
- package/src/nile-tooltip/nile-tooltip.css.ts +77 -44
- package/src/nile-tooltip/nile-tooltip.test.ts +168 -0
- package/src/nile-tooltip/nile-tooltip.ts +268 -230
- package/vscode-html-custom-data.json +150 -96
- package/dist/fixture-161dee0b.cjs.js.map +0 -1
@@ -0,0 +1,271 @@
|
|
1
|
+
export function isInViewport(element: HTMLElement): boolean {
|
2
|
+
const rect = element.getBoundingClientRect();
|
3
|
+
return (
|
4
|
+
rect.top >= 0 &&
|
5
|
+
rect.left >= 0 &&
|
6
|
+
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
7
|
+
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
8
|
+
);
|
9
|
+
}
|
10
|
+
|
11
|
+
|
12
|
+
export function getValidTooltipPosition(
|
13
|
+
triggerRect: DOMRect,
|
14
|
+
tooltipRect: DOMRect,
|
15
|
+
originalPlacement: string,
|
16
|
+
distance: number,
|
17
|
+
skidding: number,
|
18
|
+
caretSize: number,
|
19
|
+
viewportWidth: number,
|
20
|
+
viewportHeight: number
|
21
|
+
): { top: number; left: number; placement: string } {
|
22
|
+
const triggerCenterX = triggerRect.left + triggerRect.width / 2;
|
23
|
+
|
24
|
+
const getCandidatePosition = (placement: string) => {
|
25
|
+
let top = 0;
|
26
|
+
let left = 0;
|
27
|
+
|
28
|
+
switch (placement) {
|
29
|
+
case 'top':
|
30
|
+
top = triggerRect.top - tooltipRect.height - distance;
|
31
|
+
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2 + skidding;
|
32
|
+
break;
|
33
|
+
case 'top-start': {
|
34
|
+
top = triggerRect.top - tooltipRect.height - distance;
|
35
|
+
const centeredLeft = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2) + skidding;
|
36
|
+
left = Math.max(triggerRect.left + skidding, centeredLeft);
|
37
|
+
break;
|
38
|
+
}
|
39
|
+
case 'top-end': {
|
40
|
+
top = triggerRect.top - tooltipRect.height - distance;
|
41
|
+
const centeredLeft = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2) + skidding;
|
42
|
+
const maxLeft = triggerRect.right - tooltipRect.width + skidding;
|
43
|
+
left = Math.min(centeredLeft, maxLeft);
|
44
|
+
break;
|
45
|
+
}
|
46
|
+
|
47
|
+
case 'bottom':
|
48
|
+
top = triggerRect.bottom + distance;
|
49
|
+
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2 + skidding;
|
50
|
+
break;
|
51
|
+
case 'bottom-start': {
|
52
|
+
top = triggerRect.bottom + distance;
|
53
|
+
const centeredLeft = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2) + skidding;
|
54
|
+
left = Math.max(triggerRect.left + skidding, centeredLeft);
|
55
|
+
|
56
|
+
break;
|
57
|
+
}
|
58
|
+
|
59
|
+
case 'bottom-end': {
|
60
|
+
top = triggerRect.bottom + distance;
|
61
|
+
const centeredLeft = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2) + skidding;
|
62
|
+
const maxLeft = triggerRect.right - tooltipRect.width + skidding;
|
63
|
+
left = Math.min(centeredLeft, maxLeft);
|
64
|
+
break;
|
65
|
+
}
|
66
|
+
|
67
|
+
case 'left':
|
68
|
+
top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2 + skidding;
|
69
|
+
left = triggerRect.left - tooltipRect.width - distance;
|
70
|
+
break;
|
71
|
+
case 'left-start': {
|
72
|
+
const triggerCenterY = triggerRect.top + triggerRect.height / 2;
|
73
|
+
top = triggerCenterY - tooltipRect.height / 2;
|
74
|
+
left = triggerRect.left - tooltipRect.width - distance;
|
75
|
+
if (top < triggerRect.top) {
|
76
|
+
top = triggerRect.top;
|
77
|
+
}
|
78
|
+
break;
|
79
|
+
}
|
80
|
+
|
81
|
+
case 'left-end': {
|
82
|
+
const triggerCenterY = triggerRect.top + triggerRect.height / 2;
|
83
|
+
top = triggerCenterY - tooltipRect.height / 2;
|
84
|
+
left = triggerRect.left - tooltipRect.width - distance;
|
85
|
+
if (top + tooltipRect.height > triggerRect.bottom) {
|
86
|
+
top = triggerRect.bottom - tooltipRect.height;
|
87
|
+
}
|
88
|
+
|
89
|
+
break;
|
90
|
+
}
|
91
|
+
|
92
|
+
case 'right':
|
93
|
+
top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2 + skidding;
|
94
|
+
left = triggerRect.right + distance;
|
95
|
+
break;
|
96
|
+
case 'right-start': {
|
97
|
+
const triggerCenterY = triggerRect.top + triggerRect.height / 2;
|
98
|
+
top = triggerCenterY - tooltipRect.height / 2;
|
99
|
+
left = triggerRect.right + distance;
|
100
|
+
if (top < triggerRect.top) {
|
101
|
+
top = triggerRect.top;
|
102
|
+
}
|
103
|
+
|
104
|
+
break;
|
105
|
+
}
|
106
|
+
|
107
|
+
case 'right-end': {
|
108
|
+
const triggerCenterY = triggerRect.top + triggerRect.height / 2;
|
109
|
+
top = triggerCenterY - tooltipRect.height / 2;
|
110
|
+
left = triggerRect.right + distance;
|
111
|
+
if (top + tooltipRect.height > triggerRect.bottom) {
|
112
|
+
top = triggerRect.bottom - tooltipRect.height;
|
113
|
+
}
|
114
|
+
|
115
|
+
break;
|
116
|
+
}
|
117
|
+
|
118
|
+
default:
|
119
|
+
top = triggerRect.top - tooltipRect.height - distance;
|
120
|
+
left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2 + skidding;
|
121
|
+
}
|
122
|
+
|
123
|
+
return { top, left };
|
124
|
+
};
|
125
|
+
|
126
|
+
const candidateFits = (top: number, left: number) =>
|
127
|
+
top >= 0 &&
|
128
|
+
left >= 0 &&
|
129
|
+
top + tooltipRect.height <= viewportHeight &&
|
130
|
+
left + tooltipRect.width <= viewportWidth;
|
131
|
+
|
132
|
+
let placement = originalPlacement;
|
133
|
+
let candidate = getCandidatePosition(placement);
|
134
|
+
|
135
|
+
if (!candidateFits(candidate.top, candidate.left)) {
|
136
|
+
if (['top', 'top-start', 'top-end'].includes(originalPlacement)) {
|
137
|
+
placement = 'bottom';
|
138
|
+
} else if (['bottom', 'bottom-start', 'bottom-end'].includes(originalPlacement)) {
|
139
|
+
placement = 'top';
|
140
|
+
} else if (['right', 'right-start', 'right-end'].includes(originalPlacement)) {
|
141
|
+
placement = 'left';
|
142
|
+
} else if (['left', 'left-start', 'left-end'].includes(originalPlacement)) {
|
143
|
+
placement = 'right';
|
144
|
+
}
|
145
|
+
candidate = getCandidatePosition(placement);
|
146
|
+
const leftCandidate = getCandidatePosition('left');
|
147
|
+
const bottomCandidate = getCandidatePosition('bottom');
|
148
|
+
const topCandidate = getCandidatePosition('top');
|
149
|
+
if (
|
150
|
+
!candidateFits(leftCandidate.top, leftCandidate.left) &&
|
151
|
+
!candidateFits(bottomCandidate.top, bottomCandidate.left) &&
|
152
|
+
!candidateFits(topCandidate.top, topCandidate.left)
|
153
|
+
) {
|
154
|
+
placement = 'right';
|
155
|
+
candidate = getCandidatePosition(placement);
|
156
|
+
}
|
157
|
+
else {
|
158
|
+
const rightCandidate = getCandidatePosition('right');
|
159
|
+
if (
|
160
|
+
!candidateFits(rightCandidate.top, rightCandidate.left) &&
|
161
|
+
!candidateFits(bottomCandidate.top, bottomCandidate.left) &&
|
162
|
+
!candidateFits(topCandidate.top, topCandidate.left)
|
163
|
+
) {
|
164
|
+
placement = 'left';
|
165
|
+
candidate = getCandidatePosition(placement);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
if (candidate.left < 0) {
|
171
|
+
candidate.left = 5;
|
172
|
+
} else if (candidate.left + tooltipRect.width > viewportWidth) {
|
173
|
+
candidate.left = viewportWidth - tooltipRect.width - 5;
|
174
|
+
}
|
175
|
+
|
176
|
+
if (candidate.top < 0) {
|
177
|
+
candidate.top = 5;
|
178
|
+
} else if (candidate.top + tooltipRect.height > viewportHeight) {
|
179
|
+
candidate.top = viewportHeight - tooltipRect.height - 5;
|
180
|
+
}
|
181
|
+
|
182
|
+
return { ...candidate, placement };
|
183
|
+
}
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
export interface CaretPositionInput {
|
188
|
+
placement: string;
|
189
|
+
tooltipRect: DOMRect;
|
190
|
+
triggerRect: DOMRect;
|
191
|
+
caretSize: number;
|
192
|
+
left: number;
|
193
|
+
top: number;
|
194
|
+
}
|
195
|
+
|
196
|
+
export function getCaretPosition({
|
197
|
+
placement,
|
198
|
+
tooltipRect,
|
199
|
+
triggerRect,
|
200
|
+
caretSize,
|
201
|
+
left,
|
202
|
+
top
|
203
|
+
}: CaretPositionInput): { caretLeft: number; caretTop: number } {
|
204
|
+
const triggerCenterX = triggerRect.left + triggerRect.width / 2;
|
205
|
+
const triggerCenterY = triggerRect.top + triggerRect.height / 2;
|
206
|
+
|
207
|
+
const [primaryPlacement, secondaryPlacement] = placement.split('-');
|
208
|
+
|
209
|
+
let caretLeft = 0;
|
210
|
+
let caretTop = 0;
|
211
|
+
|
212
|
+
switch (primaryPlacement) {
|
213
|
+
case 'top':
|
214
|
+
caretTop = tooltipRect.height - caretSize;
|
215
|
+
caretLeft = triggerCenterX - left - caretSize;
|
216
|
+
if (placement === 'top-end') {
|
217
|
+
caretLeft = triggerCenterX - left - caretSize;
|
218
|
+
} else if (secondaryPlacement === 'start') {
|
219
|
+
caretLeft = triggerCenterX - left - caretSize;
|
220
|
+
} else if (secondaryPlacement === 'end') {
|
221
|
+
caretLeft = tooltipRect.width - 2 * caretSize + 8;
|
222
|
+
}
|
223
|
+
caretLeft = Math.max(caretSize, Math.min(caretLeft, tooltipRect.width - 2 * caretSize));
|
224
|
+
break;
|
225
|
+
|
226
|
+
case 'bottom':
|
227
|
+
caretTop = -caretSize;
|
228
|
+
caretLeft = triggerCenterX - left - caretSize;
|
229
|
+
break;
|
230
|
+
|
231
|
+
case 'left':
|
232
|
+
caretLeft = tooltipRect.width - caretSize;
|
233
|
+
if (secondaryPlacement === 'start') {
|
234
|
+
const computedCaretTop = triggerCenterY - top - caretSize;
|
235
|
+
const minCaretTop = triggerRect.top - top;
|
236
|
+
caretTop = Math.max(computedCaretTop, minCaretTop);
|
237
|
+
} else if (secondaryPlacement === 'end') {
|
238
|
+
const computedCaretTop = triggerCenterY - top - caretSize;
|
239
|
+
const maxCaretTop = triggerRect.bottom - top - 2 * caretSize;
|
240
|
+
caretTop = Math.min(computedCaretTop, maxCaretTop);
|
241
|
+
} else {
|
242
|
+
caretTop = triggerCenterY - top - caretSize;
|
243
|
+
}
|
244
|
+
caretTop = Math.max(caretSize, Math.min(caretTop, tooltipRect.height - 2 * caretSize));
|
245
|
+
break;
|
246
|
+
|
247
|
+
|
248
|
+
case 'right':
|
249
|
+
caretLeft = -caretSize;
|
250
|
+
if (secondaryPlacement === 'start') {
|
251
|
+
const computedCaretTop = triggerCenterY - top - caretSize;
|
252
|
+
const minCaretTop = triggerRect.top - top;
|
253
|
+
caretTop = Math.max(computedCaretTop, minCaretTop);
|
254
|
+
} else if (secondaryPlacement === 'end') {
|
255
|
+
const computedCaretTop = triggerCenterY - top - caretSize;
|
256
|
+
const maxCaretTop = triggerRect.bottom - top - 2 * caretSize;
|
257
|
+
caretTop = Math.min(computedCaretTop, maxCaretTop);
|
258
|
+
} else {
|
259
|
+
caretTop = triggerCenterY - top - caretSize;
|
260
|
+
}
|
261
|
+
caretTop = Math.max(caretSize, Math.min(caretTop, tooltipRect.height - 2 * caretSize));
|
262
|
+
break;
|
263
|
+
|
264
|
+
|
265
|
+
default:
|
266
|
+
caretLeft = tooltipRect.width / 2 - caretSize;
|
267
|
+
caretTop = tooltipRect.height / 2 - caretSize;
|
268
|
+
}
|
269
|
+
|
270
|
+
return { caretLeft, caretTop };
|
271
|
+
}
|
@@ -11,60 +11,93 @@ import { css } from 'lit';
|
|
11
11
|
* Tooltip CSS
|
12
12
|
*/
|
13
13
|
export const styles = css`
|
14
|
-
:host {
|
15
|
-
--max-width: 20rem;
|
16
|
-
--hide-delay: 0ms;
|
17
|
-
--show-delay: 150ms;
|
18
14
|
|
19
|
-
display: contents;
|
20
|
-
}
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
:host {
|
17
|
+
position: relative;
|
18
|
+
display: inline-block;
|
19
|
+
}
|
20
|
+
.tooltip {
|
21
|
+
position: fixed;
|
22
|
+
z-index: 1000;
|
23
|
+
background-color: var(--nile-tooltip-color-background, #333);
|
24
|
+
color: var(--nile-colors-white-base, #fff);
|
25
|
+
padding: 6px 10px;
|
26
|
+
border-radius: 4px;
|
27
|
+
font-size: var(--nile-tooltip-font-size-sm, 14px);
|
28
|
+
line-height: var(--nile-tooltip-line-height-sm, 1.5);
|
29
|
+
opacity: 0;
|
30
|
+
transition: opacity 0.2s, transform 0.2s;
|
31
|
+
pointer-events: none;
|
32
|
+
white-space: normal;
|
33
|
+
visibility: hidden;
|
34
|
+
overflow: visible;
|
35
|
+
|
36
|
+
}
|
37
|
+
:host([open]) .tooltip {
|
38
|
+
opacity: 1;
|
39
|
+
visibility: visible;
|
40
|
+
pointer-events: auto;
|
41
|
+
}
|
42
|
+
.tooltip-content {
|
43
|
+
overflow: auto;
|
44
|
+
max-width: 250px;
|
45
|
+
max-height: 116px;
|
46
|
+
}
|
47
|
+
.tooltip-caret {
|
48
|
+
position: absolute;
|
49
|
+
width: calc(2 * var(--caret-size, 6px));
|
50
|
+
height: calc(2 * var(--caret-size, 6px));
|
51
|
+
background-color: inherit;
|
52
|
+
transform: rotate(45deg);
|
53
|
+
z-index: -1;
|
54
|
+
}
|
55
|
+
.trigger-container {
|
56
|
+
display: inline-block;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
:host([open]) .tooltip {
|
61
|
+
visibility: visible;
|
62
|
+
pointer-events: auto;
|
63
|
+
animation: fadeIn 150ms forwards;
|
64
|
+
}
|
26
65
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
66
|
+
|
67
|
+
.tooltip.hide {
|
68
|
+
animation: fadeOut 100ms forwards;
|
69
|
+
}
|
31
70
|
|
32
|
-
|
33
|
-
|
71
|
+
|
72
|
+
@keyframes fadeIn {
|
73
|
+
from {
|
74
|
+
opacity: 0;
|
75
|
+
transform: translateY(5px);
|
34
76
|
}
|
35
|
-
|
36
|
-
|
37
|
-
transform
|
77
|
+
to {
|
78
|
+
opacity: 1;
|
79
|
+
transform: translateY(0);
|
38
80
|
}
|
81
|
+
}
|
39
82
|
|
40
|
-
|
41
|
-
|
83
|
+
|
84
|
+
@keyframes fadeOut {
|
85
|
+
from {
|
86
|
+
opacity: 1;
|
87
|
+
transform: translateY(0);
|
42
88
|
}
|
43
|
-
|
44
|
-
|
45
|
-
transform
|
89
|
+
to {
|
90
|
+
opacity: 0;
|
91
|
+
transform: translateY(5px);
|
46
92
|
}
|
93
|
+
}
|
47
94
|
|
48
|
-
.tooltip__body {
|
49
|
-
display: block;
|
50
|
-
width: max-content;
|
51
|
-
max-width: var(--max-width);
|
52
|
-
border-radius: 4px;
|
53
|
-
background-color: var(--nile-tooltip-color-background);
|
54
|
-
font-size: var(--nile-tooltip-font-size-sm);
|
55
|
-
font-weight: var(--nile-tooltip-font-weight-sm);
|
56
|
-
line-height: var(--nile-tooltip-line-height-sm);
|
57
|
-
padding: var(--nile-tooltip-padding-y) var(--nile-tooltip-padding-x);
|
58
|
-
color: var(--nile-colors-white-base);
|
59
|
-
pointer-events: none;
|
60
|
-
word-break: break-word;
|
61
|
-
}
|
62
95
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
68
101
|
`;
|
69
102
|
|
70
|
-
export default [styles];
|
103
|
+
export default [styles];
|
@@ -0,0 +1,168 @@
|
|
1
|
+
import { fixture, html, assert, oneEvent, waitUntil } from '@open-wc/testing';
|
2
|
+
import './nile-tooltip';
|
3
|
+
import { NileTooltip } from './nile-tooltip';
|
4
|
+
|
5
|
+
describe('NileTooltip', () => {
|
6
|
+
|
7
|
+
it('renders with default properties', async () => {
|
8
|
+
const el = await fixture<NileTooltip>(html`<nile-tooltip content="Hello"><button>Hover me</button></nile-tooltip>`);
|
9
|
+
assert.equal(el.content, 'Hello');
|
10
|
+
assert.equal(el.placement, 'top');
|
11
|
+
assert.equal(el.disabled, false);
|
12
|
+
assert.equal(el.open, false);
|
13
|
+
});
|
14
|
+
|
15
|
+
it('renders text content when no slot is used', async () => {
|
16
|
+
const el = await fixture<NileTooltip>(html`<nile-tooltip content="Fallback"><button>Trigger</button></nile-tooltip>`);
|
17
|
+
const content = el.shadowRoot!.querySelector('.tooltip-content')!;
|
18
|
+
assert.include(content.textContent!, 'Fallback');
|
19
|
+
});
|
20
|
+
|
21
|
+
it('uses slotted content when provided', async () => {
|
22
|
+
const el = await fixture<NileTooltip>(html`
|
23
|
+
<nile-tooltip>
|
24
|
+
<div slot="content">Slot Content</div>
|
25
|
+
<button>Trigger</button>
|
26
|
+
</nile-tooltip>
|
27
|
+
`);
|
28
|
+
|
29
|
+
const slot = el.shadowRoot!.querySelector('slot[name="content"]') as HTMLSlotElement;
|
30
|
+
const assigned = slot.assignedNodes({ flatten: true });
|
31
|
+
assert.isAbove(assigned.length, 0);
|
32
|
+
assert.include(assigned[0].textContent ?? '', 'Slot Content');
|
33
|
+
});
|
34
|
+
|
35
|
+
it('shows tooltip on hover when trigger includes "hover"', async () => {
|
36
|
+
const el = await fixture<NileTooltip>(html`
|
37
|
+
<nile-tooltip content="Tooltip" trigger="hover">
|
38
|
+
<button>Hover me</button>
|
39
|
+
</nile-tooltip>
|
40
|
+
`);
|
41
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container')!;
|
42
|
+
trigger.dispatchEvent(new Event('mouseover', { bubbles: true }));
|
43
|
+
await waitUntil(() => el.open === true);
|
44
|
+
assert.isTrue(el.open);
|
45
|
+
});
|
46
|
+
|
47
|
+
it('hides tooltip on mouseout when trigger includes "hover"', async () => {
|
48
|
+
const el = await fixture<NileTooltip>(html`
|
49
|
+
<nile-tooltip content="Tooltip" trigger="hover">
|
50
|
+
<button>Hover me</button>
|
51
|
+
</nile-tooltip>
|
52
|
+
`);
|
53
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container')!;
|
54
|
+
trigger.dispatchEvent(new Event('mouseover', { bubbles: true }));
|
55
|
+
await waitUntil(() => el.open === true);
|
56
|
+
trigger.dispatchEvent(new Event('mouseout', { bubbles: true }));
|
57
|
+
await waitUntil(() => el.open === false);
|
58
|
+
});
|
59
|
+
|
60
|
+
it('toggles tooltip on click when trigger includes "click"', async () => {
|
61
|
+
const el = await fixture<NileTooltip>(html`
|
62
|
+
<nile-tooltip content="Click me" trigger="click">
|
63
|
+
<button>Click</button>
|
64
|
+
</nile-tooltip>
|
65
|
+
`);
|
66
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container') as HTMLElement;
|
67
|
+
trigger.click();
|
68
|
+
await waitUntil(() => el.open === true);
|
69
|
+
trigger.click();
|
70
|
+
await waitUntil(() => el.open === false);
|
71
|
+
});
|
72
|
+
|
73
|
+
it('shows and hides tooltip on focus/blur when trigger includes "focus"', async () => {
|
74
|
+
const el = await fixture<NileTooltip>(html`
|
75
|
+
<nile-tooltip content="Focus" trigger="focus">
|
76
|
+
<button>Focus</button>
|
77
|
+
</nile-tooltip>
|
78
|
+
`);
|
79
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container')!;
|
80
|
+
trigger.dispatchEvent(new Event('focusin'));
|
81
|
+
await waitUntil(() => el.open === true);
|
82
|
+
trigger.dispatchEvent(new Event('focusout'));
|
83
|
+
await waitUntil(() => el.open === false);
|
84
|
+
});
|
85
|
+
|
86
|
+
it('does not show tooltip when disabled', async () => {
|
87
|
+
const el = await fixture<NileTooltip>(html`
|
88
|
+
<nile-tooltip content="Disabled" disabled trigger="hover">
|
89
|
+
<button>Hover me</button>
|
90
|
+
</nile-tooltip>
|
91
|
+
`);
|
92
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container')!;
|
93
|
+
trigger.dispatchEvent(new Event('mouseover'));
|
94
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
95
|
+
assert.isFalse(el.open);
|
96
|
+
});
|
97
|
+
|
98
|
+
|
99
|
+
it('emits nile-show and nile-after-show events', async () => {
|
100
|
+
const el = await fixture<NileTooltip>(html`
|
101
|
+
<nile-tooltip content="Event test" trigger="click">
|
102
|
+
<button>Click</button>
|
103
|
+
</nile-tooltip>
|
104
|
+
`);
|
105
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container') as HTMLElement;
|
106
|
+
setTimeout(() => trigger.click());
|
107
|
+
const showEvent = await oneEvent(el, 'nile-show');
|
108
|
+
assert.ok(showEvent);
|
109
|
+
const afterShow = await oneEvent(el, 'nile-after-show');
|
110
|
+
assert.ok(afterShow);
|
111
|
+
});
|
112
|
+
|
113
|
+
it('emits nile-hide and nile-after-hide events', async () => {
|
114
|
+
const el = await fixture<NileTooltip>(html`
|
115
|
+
<nile-tooltip content="Event test" trigger="click">
|
116
|
+
<button>Click</button>
|
117
|
+
</nile-tooltip>
|
118
|
+
`);
|
119
|
+
const trigger = el.shadowRoot!.querySelector('.trigger-container') as HTMLElement;
|
120
|
+
trigger.click();
|
121
|
+
await waitUntil(() => el.open === true);
|
122
|
+
setTimeout(() => trigger.click());
|
123
|
+
const hideEvent = await oneEvent(el, 'nile-hide');
|
124
|
+
assert.ok(hideEvent);
|
125
|
+
const afterHide = await oneEvent(el, 'nile-after-hide');
|
126
|
+
assert.ok(afterHide);
|
127
|
+
});
|
128
|
+
|
129
|
+
it('defaults to "bottom" placement when given invalid value', async () => {
|
130
|
+
const el = await fixture<NileTooltip>(html`
|
131
|
+
<nile-tooltip content="Fallback" placement=${'invalid' as unknown as NileTooltip['placement']} >
|
132
|
+
<button>Trigger</button>
|
133
|
+
</nile-tooltip>
|
134
|
+
`);
|
135
|
+
await el.updateComplete;
|
136
|
+
assert.equal(el.placement, 'top');
|
137
|
+
});
|
138
|
+
|
139
|
+
|
140
|
+
it('updates hasTooltipSlot on slot change', async () => {
|
141
|
+
const el = await fixture<NileTooltip>(html`
|
142
|
+
<nile-tooltip>
|
143
|
+
<div slot="content">Initial slot</div>
|
144
|
+
<button>Trigger</button>
|
145
|
+
</nile-tooltip>
|
146
|
+
`);
|
147
|
+
|
148
|
+
const slot = el.shadowRoot!.querySelector('slot[name="content"]') as HTMLSlotElement;
|
149
|
+
const newSlotNode = document.createElement('div');
|
150
|
+
newSlotNode.slot = 'content';
|
151
|
+
newSlotNode.textContent = 'Updated slot';
|
152
|
+
el.appendChild(newSlotNode);
|
153
|
+
|
154
|
+
slot.dispatchEvent(new Event('slotchange'));
|
155
|
+
await el.updateComplete;
|
156
|
+
|
157
|
+
assert.isTrue((el as any).hasTooltipSlot);
|
158
|
+
});
|
159
|
+
|
160
|
+
it('respects hoist attribute', async () => {
|
161
|
+
const el = await fixture<NileTooltip>(html`
|
162
|
+
<nile-tooltip hoist content="Hoisted">
|
163
|
+
<button>Hoist</button>
|
164
|
+
</nile-tooltip>
|
165
|
+
`);
|
166
|
+
assert.isTrue(el.hoist);
|
167
|
+
});
|
168
|
+
});
|