Skip to content

Commit a7998d5

Browse files
authored
Merge pull request #63659 from nextcloud/backport/63652/stable35
[stable35] fix(core): let landed search results outgrow the reserved height
2 parents 162bba3 + 12f0eaa commit a7998d5

4 files changed

Lines changed: 43 additions & 11 deletions

File tree

core/src/components/UnifiedSearch/UnifiedSearchModal.vue

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
ref="resultsContainer"
160160
class="unified-search-modal__results"
161161
:class="{ 'unified-search-modal__results--held': heldHeight !== null }"
162-
:style="heldHeight !== null ? { blockSize: `${heldHeight}px`, boxSizing: 'border-box' } : undefined">
162+
:style="heldHeight !== null ? { minBlockSize: `${heldHeight}px`, boxSizing: 'border-box' } : undefined">
163163
<h3 class="hidden-visually">
164164
{{ t('core', 'Results') }}
165165
</h3>
@@ -1807,20 +1807,30 @@ export default defineComponent({
18071807
min-height: 0;
18081808
overflow: hidden auto;
18091809
1810-
// The placeholders deliberately overfill, so the bottom fades out over the cut.
1810+
// The reserved height is a floor, not a size. Column layout so the placeholders can
1811+
// take what the results leave.
18111812
&--held {
1813+
display: flex;
1814+
flex-direction: column;
18121815
flex-grow: 0;
1813-
overflow: clip;
1814-
// Capped, so a short box does not spend a third of itself fading.
1815-
mask-image: linear-gradient(to bottom, #000 calc(100% - min(2lh, 25%)), transparent);
1816+
1817+
> *:not(.search-result-skeleton) {
1818+
flex: none;
1819+
}
18161820
}
18171821
// Adjust padding to match container but keep the scrollbar on the very end
18181822
padding-inline: calc(var(--default-grid-baseline) * 4);
18191823
padding-block: 0 calc(var(--default-grid-baseline) * 4);
18201824
1821-
// Matches the gap a category title keeps above itself.
18221825
.search-result-skeleton {
1826+
// Matches the gap a category title keeps above itself.
18231827
margin-block-start: 14px;
1828+
// The placeholders deliberately overfill, so the bottom fades out over the cut.
1829+
flex: 1 1 0;
1830+
min-block-size: 0;
1831+
overflow: clip;
1832+
// Capped, so a short box does not spend a third of itself fading.
1833+
mask-image: linear-gradient(to bottom, #000 calc(100% - min(2lh, 25%)), transparent);
18241834
}
18251835
18261836
.result {
@@ -1891,7 +1901,7 @@ export default defineComponent({
18911901
18921902
// Ensure modal is accessible on small devices
18931903
@media only screen and (max-height: 400px) {
1894-
.unified-search-modal__results:not(.unified-search-modal__results--held) {
1904+
.unified-search-modal__results {
18951905
overflow: unset;
18961906
}
18971907
}

core/src/tests/components/UnifiedSearchModal.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,13 +1267,35 @@ describe('UnifiedSearchModal loading skeleton', () => {
12671267
expect(wrapper.vm.skeletonRows * 60).toBeGreaterThanOrEqual(300)
12681268
})
12691269

1270+
// isBusy stays true until the last provider answers, so the box carries real results meanwhile.
1271+
it('reserves the height as a floor, so landed results are never cut off', async () => {
1272+
const wrapper = await withResults()
1273+
measureResultsAt(wrapper, 300)
1274+
wrapper.vm.searchQuery = 'querying'
1275+
await wrapper.vm.$nextTick()
1276+
wrapper.vm.find('querying')
1277+
1278+
searchStates.value = {
1279+
files: loaded([{ resourceUrl: '/a' }, { resourceUrl: '/b' }, { resourceUrl: '/c' }]),
1280+
talk: { status: 'loading', entries: [], cursor: null, hasMore: false, loadMoreFailed: false },
1281+
}
1282+
await wrapper.vm.$nextTick()
1283+
1284+
expect(wrapper.vm.isBusy).toBe(true)
1285+
expect(wrapper.vm.hasVisibleResults).toBe(true)
1286+
1287+
const style = wrapper.find('.unified-search-modal__results').attributes('style')
1288+
expect(style).toContain('min-block-size: 300px')
1289+
expect(style).not.toMatch(/(^|[^-])block-size: 300px/)
1290+
})
1291+
12701292
it('holds the same height through repeated keystrokes rather than creeping taller', async () => {
12711293
const wrapper = await withResults()
12721294
const box = wrapper.vm.$refs.resultsContainer as HTMLElement
12731295
// Stand in for the browser: report the padding on top of whatever height is set.
12741296
const padding = 16
12751297
vi.spyOn(box, 'getBoundingClientRect').mockImplementation(() => ({
1276-
height: (parseFloat(box.style.blockSize) || 300) + (box.style.boxSizing === 'border-box' ? 0 : padding),
1298+
height: (parseFloat(box.style.minBlockSize) || 300) + (box.style.boxSizing === 'border-box' ? 0 : padding),
12771299
}) as DOMRect)
12781300

12791301
wrapper.vm.searchQuery = 'q1'

dist/core-unified-search.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/core-unified-search.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)