Skip to content

Commit d1e8a18

Browse files
duncanmccleanclaudejasonvarga
authored
[6.x] Fix asset selector drag-to-upload covering footer but not handling drops (#14551)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Jason Varga <jason@pixelfear.com>
1 parent 25ccef8 commit d1e8a18

3 files changed

Lines changed: 107 additions & 68 deletions

File tree

resources/js/components/assets/Browser/Browser.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<template>
22
<div ref="browser" class="h-full" @keydown.shift="shiftDown" @keyup="clearShift">
33
<Uploader
4-
ref="uploader"
4+
ref="internalUploader"
55
:container="container.id"
66
:path="path"
7-
:enabled="!preventDragging && canUpload"
7+
:enabled="!uploader && !preventDragging && canUpload"
88
@updated="uploadsUpdated"
99
@upload-complete="uploadCompleted"
1010
@error="uploadError"
@@ -272,6 +272,10 @@ export default {
272272
type: Array,
273273
default: () => [],
274274
},
275+
uploader: {
276+
type: Object,
277+
default: null,
278+
},
275279
},
276280
277281
setup() {
@@ -476,8 +480,9 @@ export default {
476480
this.loadAssets();
477481
},
478482
479-
path() {
483+
path(path) {
480484
this.loadAssets();
485+
this.$emit('path-changed', path);
481486
},
482487
483488
searchQuery() {
@@ -676,7 +681,7 @@ export default {
676681
},
677682
678683
openFileBrowser() {
679-
this.$refs.uploader.browse();
684+
(this.uploader || this.$refs.internalUploader).browse();
680685
},
681686
682687
selectFolder(path) {

resources/js/components/assets/Selector.vue

Lines changed: 87 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,96 @@
11
<template>
2-
<div class="h-full">
3-
<div class="flex h-full min-h-0 flex-col">
4-
<div class="flex flex-1 flex-col gap-4 overflow-auto p-4">
5-
<AssetBrowser
6-
:container="container"
7-
:initial-per-page="$config.get('paginationSize')"
8-
:initial-columns="columns"
9-
:selected-path="folder"
10-
:selected-assets="browserSelections"
11-
:restrict-folder-navigation="restrictFolderNavigation"
12-
:max-files="maxFiles"
13-
:query-scopes="queryScopes"
14-
:autoselect-uploads="true"
15-
allow-selecting-existing-upload
16-
:allow-bulk-actions="false"
17-
@selections-updated="selectionsUpdated"
18-
@edit-asset="toggleAssetSelection"
19-
@initialized="focusSearchInput"
20-
>
21-
<template #initializing>
22-
<div class="flex flex-1">
23-
<div class="absolute inset-0 z-200 flex items-center justify-center text-center">
24-
<Icon name="loading" />
25-
</div>
26-
</div>
27-
</template>
2+
<Uploader
3+
ref="uploader"
4+
:container="container.id"
5+
:path="currentPath"
6+
:enabled="container.can_upload"
7+
@updated="(uploads) => $refs.browser?.uploadsUpdated(uploads)"
8+
@upload-complete="(asset) => $refs.browser?.uploadCompleted(asset)"
9+
@error="(upload, uploads) => $refs.browser?.uploadError(upload, uploads)"
10+
v-slot="{ dragging }"
11+
>
12+
<div class="relative h-full">
13+
<div class="drag-notification" v-show="dragging">
14+
<Icon name="upload-cloud-large" class="m-4 size-13" />
15+
<span>{{ __('Drop File to Upload') }}</span>
16+
</div>
2817

29-
<template #header="{ canUpload, openFileBrowser, canCreateFolders, startCreatingFolder, mode, modeChanged }">
30-
<div class="flex items-center gap-2 sm:gap-3 mb-4">
31-
<div class="flex flex-1 items-center gap-2 sm:gap-3">
32-
<Search ref="search" />
18+
<div class="flex h-full min-h-0 flex-col">
19+
<div class="flex flex-1 flex-col gap-4 overflow-auto p-4">
20+
<AssetBrowser
21+
ref="browser"
22+
:container="container"
23+
:initial-per-page="$config.get('paginationSize')"
24+
:initial-columns="columns"
25+
:selected-path="folder"
26+
:selected-assets="browserSelections"
27+
:restrict-folder-navigation="restrictFolderNavigation"
28+
:max-files="maxFiles"
29+
:query-scopes="queryScopes"
30+
:autoselect-uploads="true"
31+
:uploader="uploaderInstance"
32+
allow-selecting-existing-upload
33+
:allow-bulk-actions="false"
34+
@selections-updated="selectionsUpdated"
35+
@edit-asset="toggleAssetSelection"
36+
@initialized="focusSearchInput"
37+
@path-changed="currentPath = $event"
38+
>
39+
<template #initializing>
40+
<div class="flex flex-1">
41+
<div class="absolute inset-0 z-200 flex items-center justify-center text-center">
42+
<Icon name="loading" />
43+
</div>
3344
</div>
45+
</template>
3446

35-
<Button v-if="canUpload" :text="__('Upload')" icon="upload" @click="openFileBrowser" />
36-
<Button v-if="canCreateFolders" :text="__('Create Folder')" icon="folder-add" @click="startCreatingFolder" />
47+
<template #header="{ canUpload, openFileBrowser, canCreateFolders, startCreatingFolder, mode, modeChanged }">
48+
<div class="flex items-center gap-2 sm:gap-3 mb-4">
49+
<div class="flex flex-1 items-center gap-2 sm:gap-3">
50+
<Search ref="search" />
51+
</div>
3752

38-
<ToggleGroup :model-value="mode" @update:model-value="modeChanged">
39-
<ToggleItem icon="layout-grid" value="grid" />
40-
<ToggleItem icon="layout-list" value="table" />
41-
</ToggleGroup>
42-
</div>
43-
</template>
44-
</AssetBrowser>
45-
</div>
53+
<Button v-if="canUpload" :text="__('Upload')" icon="upload" @click="openFileBrowser" />
54+
<Button v-if="canCreateFolders" :text="__('Create Folder')" icon="folder-add" @click="startCreatingFolder" />
55+
56+
<ToggleGroup :model-value="mode" @update:model-value="modeChanged">
57+
<ToggleItem icon="layout-grid" value="grid" />
58+
<ToggleItem icon="layout-list" value="table" />
59+
</ToggleGroup>
60+
</div>
61+
</template>
62+
</AssetBrowser>
63+
</div>
4664

47-
<div class="flex items-center justify-between border-t bg-gray-100 dark:bg-gray-850 dark:border-gray-700 px-4 py-2 sm:p-4">
48-
<div
49-
class="dark:text-gray-200 text-sm text-gray-700"
50-
v-text="
51-
hasMaxFiles
52-
? __n(':count/:max selected', browserSelections, { max: maxFiles })
53-
: __n(':count asset selected|:count assets selected', browserSelections)
54-
"
55-
/>
56-
57-
<div class="flex items-center space-x-3">
58-
<Button variant="ghost" @click="close">
59-
{{ __('Cancel') }}
60-
</Button>
61-
62-
<Button variant="primary" @click="select">
63-
{{ __('Select') }}
64-
</Button>
65+
<div class="flex items-center justify-between border-t bg-gray-100 dark:bg-gray-850 dark:border-gray-700 px-4 py-2 sm:p-4">
66+
<div
67+
class="dark:text-gray-200 text-sm text-gray-700"
68+
v-text="
69+
hasMaxFiles
70+
? __n(':count/:max selected', browserSelections, { max: maxFiles })
71+
: __n(':count asset selected|:count assets selected', browserSelections)
72+
"
73+
/>
74+
75+
<div class="flex items-center space-x-3">
76+
<Button variant="ghost" @click="close">
77+
{{ __('Cancel') }}
78+
</Button>
79+
80+
<Button variant="primary" @click="select">
81+
{{ __('Select') }}
82+
</Button>
83+
</div>
6584
</div>
6685
</div>
6786
</div>
68-
</div>
87+
</Uploader>
6988
</template>
7089

7190
<script>
91+
import { markRaw } from 'vue';
7292
import AssetBrowser from './Browser/Browser.vue'
93+
import Uploader from './Uploader.vue'
7394
import {
7495
Button,
7596
ToggleGroup,
@@ -92,6 +113,7 @@ export default {
92113
93114
components: {
94115
Uploads,
116+
Uploader,
95117
PanelHeader, Grid,
96118
Slider,
97119
ListingPagination, Breadcrumbs,
@@ -128,9 +150,15 @@ export default {
128150
// We only want selection changes to be reflected in the fieldtype once the user is ready to commit
129151
// them. They should be able to cancel at any time and have their updated selections discarded.
130152
browserSelections: this.selected,
153+
currentPath: this.folder,
154+
uploaderInstance: null,
131155
};
132156
},
133157
158+
mounted() {
159+
this.uploaderInstance = markRaw(this.$refs.uploader);
160+
},
161+
134162
computed: {
135163
hasMaxFiles() {
136164
return this.maxFiles === Infinity ? false : Boolean(this.maxFiles);

resources/js/components/assets/Uploader.vue

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,23 @@ export default {
1414
ref: 'nativeFileField',
1515
});
1616
17+
const events = this.enabled
18+
? {
19+
onDragenter: this.dragenter,
20+
onDragover: this.dragover,
21+
onDragleave: this.dragleave,
22+
onDrop: this.drop,
23+
}
24+
: {};
25+
1726
return h(
1827
'div',
1928
{
2029
class: 'h-full',
21-
onDragenter: this.dragenter,
22-
onDragover: this.dragover,
23-
onDragleave: this.dragleave,
24-
onDrop: this.drop,
30+
...events,
2531
},
2632
[
27-
h('div', { class: { 'pointer-events-none': this.dragging } }, [
33+
h('div', { class: ['h-full', { 'pointer-events-none': this.dragging }] }, [
2834
fileField,
2935
...this.$slots.default({ dragging: this.enabled ? this.dragging : false }),
3036
]),

0 commit comments

Comments
 (0)