react-core-ts 2.0.20 → 2.0.22
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/dist/AutoCompleteWithSelectedList.js +48 -22
- package/dist/AutoCompleteWithSelectedList.js.map +1 -1
- package/dist/AutoCompleteWithTabFilter.js +77 -50
- package/dist/AutoCompleteWithTabFilter.js.map +1 -1
- package/dist/ExpandableAutoComplete.js +1 -1
- package/dist/ExpandableAutoComplete.js.map +1 -1
- package/dist/commontypes.d.ts +1 -0
- package/dist/dropdownFilterTabs.js +52 -23
- package/dist/dropdownFilterTabs.js.map +1 -1
- package/dist/styles/components/selectedautocomplete.css +39 -0
- package/dist/utilities/measureTabListNaturalWidth.d.ts +30 -0
- package/dist/utilities/measureTabListNaturalWidth.js +92 -0
- package/dist/utilities/measureTabListNaturalWidth.js.map +1 -0
- package/package.json +1 -1
- package/src/AutoCompleteWithSelectedList.tsx +49 -13
- package/src/AutoCompleteWithTabFilter.tsx +55 -18
- package/src/ExpandableAutoComplete.tsx +1 -0
- package/src/commontypes.ts +1 -0
- package/src/dropdownFilterTabs.tsx +52 -14
- package/src/styles/components/selectedautocomplete.css +39 -0
- package/src/utilities/measureTabListNaturalWidth.ts +117 -0
- package/dist/styles/styles/components/autocomplete.css +0 -744
- package/dist/styles/styles/components/selectedautocomplete.css +0 -179
- package/dist/styles/styles/components/tooltip.css +0 -497
- package/dist/styles/styles/components/treedropdown.css +0 -97
- package/dist/styles/styles/global.css +0 -8
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const DROPDOWN_HORIZONTAL_PADDING_PX = 16; // .qbs-autocomplete-suggestions has padding: 8px
|
|
2
|
+
const VIEWPORT_RIGHT_GUTTER_PX = 8;
|
|
3
|
+
const VIEWPORT_LEFT_GUTTER_PX = 8;
|
|
4
|
+
export const MIN_DROPDOWN_WIDTH_PX = 300;
|
|
5
|
+
// When tabs exist, cap dropdown width and let the tab strip scroll horizontally if needed.
|
|
6
|
+
export const MAX_DROPDOWN_WIDTH_WITH_TABS_PX = 600;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Measures the "natural" (nowrap) width of a rendered tabs <ul>, including the dropdown's horizontal padding.
|
|
10
|
+
* This avoids tabs wrapping/squishing when the trigger/input is narrower than the tab labels.
|
|
11
|
+
*/
|
|
12
|
+
export function measureTabListNaturalWidth(tabListEl: HTMLUListElement): number | null {
|
|
13
|
+
if (!tabListEl || typeof document === 'undefined') return null;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const container = document.createElement('div');
|
|
17
|
+
container.style.position = 'absolute';
|
|
18
|
+
container.style.top = '-99999px';
|
|
19
|
+
container.style.left = '-99999px';
|
|
20
|
+
container.style.visibility = 'hidden';
|
|
21
|
+
container.style.pointerEvents = 'none';
|
|
22
|
+
container.style.whiteSpace = 'nowrap';
|
|
23
|
+
|
|
24
|
+
const clone = tabListEl.cloneNode(true) as HTMLUListElement;
|
|
25
|
+
|
|
26
|
+
// Force a single row with natural width.
|
|
27
|
+
clone.style.display = 'inline-flex';
|
|
28
|
+
clone.style.flexWrap = 'nowrap';
|
|
29
|
+
clone.style.width = 'max-content';
|
|
30
|
+
clone.style.whiteSpace = 'nowrap';
|
|
31
|
+
|
|
32
|
+
// Remove width constraints from items so content can dictate width.
|
|
33
|
+
clone.querySelectorAll('li').forEach((li) => {
|
|
34
|
+
(li as HTMLElement).style.flex = '0 0 auto';
|
|
35
|
+
(li as HTMLElement).style.width = 'auto';
|
|
36
|
+
});
|
|
37
|
+
clone.querySelectorAll('span').forEach((span) => {
|
|
38
|
+
(span as HTMLElement).style.width = 'max-content';
|
|
39
|
+
(span as HTMLElement).style.whiteSpace = 'nowrap';
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
container.appendChild(clone);
|
|
43
|
+
document.body.appendChild(container);
|
|
44
|
+
|
|
45
|
+
const tabRowWidth = Math.ceil(clone.getBoundingClientRect().width);
|
|
46
|
+
|
|
47
|
+
document.body.removeChild(container);
|
|
48
|
+
|
|
49
|
+
// Include dropdown padding so the tabs still fit within the content box.
|
|
50
|
+
return tabRowWidth + DROPDOWN_HORIZONTAL_PADDING_PX;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Keeps a dropdown fully visible within the viewport by clamping width and shifting left/right as needed.
|
|
58
|
+
* All coordinates are page coordinates (i.e., include window.scrollX).
|
|
59
|
+
*/
|
|
60
|
+
export function clampDropdownToViewport(opts: { desiredWidth: number; desiredLeft: number }): {
|
|
61
|
+
width: number;
|
|
62
|
+
left: number;
|
|
63
|
+
} {
|
|
64
|
+
if (typeof window === 'undefined') return { width: opts.desiredWidth, left: opts.desiredLeft };
|
|
65
|
+
|
|
66
|
+
const viewportLeft = window.scrollX;
|
|
67
|
+
const viewportRight = window.scrollX + window.innerWidth;
|
|
68
|
+
const maxWidth = Math.max(
|
|
69
|
+
0,
|
|
70
|
+
Math.floor(viewportRight - viewportLeft - VIEWPORT_LEFT_GUTTER_PX - VIEWPORT_RIGHT_GUTTER_PX)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const width = maxWidth > 0 ? Math.min(opts.desiredWidth, maxWidth) : opts.desiredWidth;
|
|
74
|
+
|
|
75
|
+
const minLeft = viewportLeft + VIEWPORT_LEFT_GUTTER_PX;
|
|
76
|
+
const maxLeft = viewportRight - VIEWPORT_RIGHT_GUTTER_PX - width;
|
|
77
|
+
|
|
78
|
+
const left = Math.min(Math.max(opts.desiredLeft, minLeft), maxLeft);
|
|
79
|
+
|
|
80
|
+
return { width, left };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Same as clampDropdownToViewport, but if the dropdown would overflow the right edge, it will prefer
|
|
85
|
+
* right-aligning the dropdown to the provided anchor (typically the input's right edge).
|
|
86
|
+
*/
|
|
87
|
+
export function clampDropdownToViewportPreferRightAlign(opts: {
|
|
88
|
+
desiredWidth: number;
|
|
89
|
+
desiredLeft: number;
|
|
90
|
+
anchorRight: number;
|
|
91
|
+
}): { width: number; left: number } {
|
|
92
|
+
if (typeof window === 'undefined') return { width: opts.desiredWidth, left: opts.desiredLeft };
|
|
93
|
+
|
|
94
|
+
const viewportLeft = window.scrollX;
|
|
95
|
+
const viewportRight = window.scrollX + window.innerWidth;
|
|
96
|
+
const maxWidth = Math.max(
|
|
97
|
+
0,
|
|
98
|
+
Math.floor(viewportRight - viewportLeft - VIEWPORT_LEFT_GUTTER_PX - VIEWPORT_RIGHT_GUTTER_PX)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const width = maxWidth > 0 ? Math.min(opts.desiredWidth, maxWidth) : opts.desiredWidth;
|
|
102
|
+
|
|
103
|
+
const minLeft = viewportLeft + VIEWPORT_LEFT_GUTTER_PX;
|
|
104
|
+
const maxLeft = viewportRight - VIEWPORT_RIGHT_GUTTER_PX - width;
|
|
105
|
+
|
|
106
|
+
// Default: left-align to the trigger.
|
|
107
|
+
let left = opts.desiredLeft;
|
|
108
|
+
|
|
109
|
+
// If it would overflow right, prefer right-align to the trigger's right edge.
|
|
110
|
+
if (left + width > viewportRight - VIEWPORT_RIGHT_GUTTER_PX) {
|
|
111
|
+
left = opts.anchorRight - width;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
left = Math.min(Math.max(left, minLeft), maxLeft);
|
|
115
|
+
|
|
116
|
+
return { width, left };
|
|
117
|
+
}
|