@dosgato/dialog 0.0.60 → 0.0.62
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/Container.svelte +1 -1
- package/dist/Dialog.svelte +1 -1
- package/dist/Dialog.svelte.d.ts +1 -0
- package/dist/chooser/Chooser.svelte +40 -31
- package/dist/chooser/ChooserAPI.d.ts +14 -1
- package/dist/chooser/ChooserStore.d.ts +5 -1
- package/dist/chooser/ChooserStore.js +12 -1
- package/dist/chooser/UploadUI.svelte +160 -0
- package/dist/chooser/UploadUI.svelte.d.ts +26 -0
- package/dist/chooser/index.d.ts +1 -0
- package/dist/chooser/index.js +1 -0
- package/dist/tree/Tree.svelte +6 -5
- package/dist/tree/TreeCell.svelte +1 -1
- package/dist/tree/treestore.js +0 -2
- package/package.json +1 -1
package/dist/Container.svelte
CHANGED
|
@@ -48,7 +48,7 @@ $: setNeedsShowHelp(helpelement);
|
|
|
48
48
|
{#if helptext}
|
|
49
49
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
50
50
|
<div use:resize={{ debounce: 10 }} on:resize={setNeedsShowHelp} id={helptextid} class="dialog-field-help" class:needsShowHelp class:expanded={showhelp} on:click={() => { if (needsShowHelp) showhelp = !showhelp }}>
|
|
51
|
-
<span bind:this={helpelement}>{helptext}</span>
|
|
51
|
+
<span bind:this={helpelement}>{@html helptext}</span>
|
|
52
52
|
{#if needsShowHelp}
|
|
53
53
|
<button type="button" class="dialog-field-help-expand">Show {#if showhelp}Less{:else}More{/if}<ScreenReaderOnly>, ignore this, the help text it controls will be read to you as input description</ScreenReaderOnly></button>
|
|
54
54
|
{/if}
|
package/dist/Dialog.svelte
CHANGED
|
@@ -48,7 +48,7 @@ $: describedby = [title ? labelid : undefined, descid].filter(isNotBlank).join('
|
|
|
48
48
|
<slot></slot>
|
|
49
49
|
</div>
|
|
50
50
|
<footer class="actions">
|
|
51
|
-
<slot name="buttons" {nextTitle} {prevTitle} hasRequired={hasRequired && !ignoreTabs} onPrev={onPrev} onNext={onNext}>
|
|
51
|
+
<slot name="buttons" {nextTitle} {prevTitle} hasRequired={hasRequired && !ignoreTabs} onPrev={onPrev} onNext={onNext} {describedby}>
|
|
52
52
|
{#if prevTitle && !ignoreTabs}
|
|
53
53
|
<Button class="prev" disabled={!prevTitle} on:click={onPrev}><Icon icon={arrowLeftLight} inline /> Previous<ScreenReaderOnly> Tab ({prevTitle})</ScreenReaderOnly></Button>
|
|
54
54
|
{/if}
|
package/dist/Dialog.svelte.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script>import applicationOutline from '@iconify-icons/mdi/application-outline';
|
|
2
2
|
import folderIcon from '@iconify-icons/ph/folder';
|
|
3
3
|
import folderNotchOpen from '@iconify-icons/ph/folder-notch-open';
|
|
4
|
-
import { derivedStore } from '@txstate-mws/svelte-store';
|
|
5
4
|
import { createEventDispatcher, getContext, onMount, setContext } from 'svelte';
|
|
6
|
-
import { isNotBlank } from 'txstate-utils';
|
|
7
|
-
import { Dialog, iconForMime, Tabs, Tree,
|
|
5
|
+
import { isNotBlank, randomid, sleep } from 'txstate-utils';
|
|
6
|
+
import { Button, Dialog, iconForMime, Tabs, Tree, UploadUI } from '..';
|
|
8
7
|
import { CHOOSER_API_CONTEXT } from './ChooserAPI';
|
|
9
8
|
import { CHOOSER_STORE_CONTEXT, ChooserStore } from './ChooserStore';
|
|
10
9
|
import Details from './Details.svelte';
|
|
@@ -22,21 +21,17 @@ export let activeSources = undefined;
|
|
|
22
21
|
export let passthruFilters = undefined;
|
|
23
22
|
export let filter = undefined;
|
|
24
23
|
export let store = new ChooserStore(chooserClient);
|
|
24
|
+
store.filter = filter;
|
|
25
25
|
setContext(CHOOSER_STORE_CONTEXT, store);
|
|
26
26
|
const dispatch = createEventDispatcher();
|
|
27
|
+
let showuploader = false;
|
|
27
28
|
let tabStore;
|
|
28
|
-
const { sources, source, preview } = store;
|
|
29
|
+
const { sources, source, preview, treeStore, selected } = store;
|
|
29
30
|
$: currentName = tabStore?.currentName();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const children = await chooserClient.getChildren($source.name, item?.path ?? '/', filter);
|
|
34
|
-
return children.map(c => ({ ...c, children: undefined }));
|
|
31
|
+
$: if ($currentName) {
|
|
32
|
+
store.setSource($currentName);
|
|
33
|
+
treeStore.refresh().catch(console.error);
|
|
35
34
|
}
|
|
36
|
-
const treeStore = new TreeStore(fetchChildren);
|
|
37
|
-
const selected = derivedStore(treeStore, 'selectedItems.0');
|
|
38
|
-
$: store.setSource($currentName);
|
|
39
|
-
$: selectPreview($preview, $source);
|
|
40
35
|
$: store.setPreview($selected);
|
|
41
36
|
function onChoose() {
|
|
42
37
|
dispatch('change', $store.preview);
|
|
@@ -44,28 +39,27 @@ function onChoose() {
|
|
|
44
39
|
function onDeselect() {
|
|
45
40
|
store.setPreview(undefined);
|
|
46
41
|
}
|
|
42
|
+
function onUploadComplete() {
|
|
43
|
+
treeStore.openAndRefresh($selected).catch(console.error);
|
|
44
|
+
showuploader = false;
|
|
45
|
+
}
|
|
47
46
|
async function openRecursive(pathSplit, depth) {
|
|
48
47
|
let curr = $treeStore.rootItems?.find(itm => itm.name === pathSplit[0]);
|
|
49
48
|
for (let i = 0; i < depth; i++) {
|
|
50
49
|
curr = curr?.children?.find(c => c.name === pathSplit[i + 1]);
|
|
51
50
|
}
|
|
52
|
-
if (!curr)
|
|
53
|
-
|
|
51
|
+
if (!curr) {
|
|
52
|
+
console.warn('tried to preload a path', '/' + pathSplit.join('/'), 'that does not exist ');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
54
55
|
await treeStore.open(curr, false);
|
|
55
56
|
if (depth + 1 >= pathSplit.length)
|
|
56
57
|
return curr;
|
|
57
58
|
return await openRecursive(pathSplit, depth + 1);
|
|
58
59
|
}
|
|
59
|
-
async function selectPreview(
|
|
60
|
+
async function selectPreview(preloadPath) {
|
|
60
61
|
if (!$store.initialized)
|
|
61
62
|
return;
|
|
62
|
-
await treeStore.refresh(undefined);
|
|
63
|
-
const preloadSource = $preview?.source ?? initialSource;
|
|
64
|
-
if ($source?.name !== preloadSource)
|
|
65
|
-
return;
|
|
66
|
-
const preloadPath = $store.preview?.path ?? initialPath;
|
|
67
|
-
initialSource = undefined;
|
|
68
|
-
initialPath = undefined;
|
|
69
63
|
if (preloadPath) {
|
|
70
64
|
const currentSelection = await openRecursive(preloadPath.split('/').filter(isNotBlank), 0);
|
|
71
65
|
treeStore.trigger();
|
|
@@ -77,18 +71,20 @@ async function selectPreview(..._) {
|
|
|
77
71
|
}
|
|
78
72
|
}
|
|
79
73
|
onMount(async () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
await
|
|
74
|
+
const preloadSource = $preview?.source ?? $selected?.source ?? $source?.name ?? initialSource;
|
|
75
|
+
const preloadPath = $preview?.path ?? $selected?.path ?? initialPath;
|
|
76
|
+
await store.init({ images, pages, assets, folders, activeSources, initialSource: preloadSource, initialPath: preloadPath, passthruFilters, filter });
|
|
77
|
+
await treeStore.refresh();
|
|
78
|
+
await selectPreview(preloadPath);
|
|
84
79
|
});
|
|
80
|
+
const previewId = randomid();
|
|
85
81
|
</script>
|
|
86
82
|
|
|
87
|
-
<Dialog size="xl" ignoreTabs title={label} on:escape continueText="Choose" disabled={!$
|
|
83
|
+
<Dialog size="xl" ignoreTabs title={label} on:escape continueText="Choose" disabled={!$preview && required} cancelText="Cancel">
|
|
88
84
|
<section class="dialog-chooser-window">
|
|
89
85
|
<header class="dialog-chooser-controls">
|
|
90
86
|
{#if $sources.length > 1}
|
|
91
|
-
<Tabs bind:store={tabStore} tabs={$sources.map(s => ({ name: s.name, title: s.label ?? s.name }))} />
|
|
87
|
+
<Tabs bind:store={tabStore} tabs={$sources.map(s => ({ name: s.name, title: s.label ?? s.name }))} active={$preview?.source ?? $selected?.source ?? $source?.name ?? initialSource} />
|
|
92
88
|
{/if}
|
|
93
89
|
</header>
|
|
94
90
|
<section class="dialog-chooser-chooser">
|
|
@@ -98,13 +94,23 @@ onMount(async () => {
|
|
|
98
94
|
]} singleSelect store={treeStore} on:deselect={onDeselect} on:choose={onChoose} />
|
|
99
95
|
{/if}
|
|
100
96
|
</section>
|
|
101
|
-
<section class="dialog-chooser-preview" tabindex="-1">
|
|
97
|
+
<section id={previewId} class="dialog-chooser-preview" tabindex="-1">
|
|
102
98
|
{#if $preview}
|
|
103
99
|
<Thumbnail item={$preview} larger />
|
|
104
100
|
<Details item={$preview} />
|
|
105
101
|
{/if}
|
|
106
102
|
</section>
|
|
107
103
|
</section>
|
|
104
|
+
<svelte:fragment slot="buttons" let:describedby>
|
|
105
|
+
{#if chooserClient.upload && $source?.type === 'asset'}
|
|
106
|
+
<Button class="upload" disabled={$selected?.type !== 'folder' || !(chooserClient.mayUpload?.($selected) ?? true)} on:click={() => { showuploader = true }}>Upload</Button>
|
|
107
|
+
{/if}
|
|
108
|
+
<Button cancel {describedby} on:click={() => dispatch('escape')}>Cancel</Button>
|
|
109
|
+
<Button class="primary" disabled={!$preview && required} describedby={previewId} on:click={onChoose}>Choose</Button>
|
|
110
|
+
</svelte:fragment>
|
|
111
|
+
{#if showuploader && $selected?.type === 'folder' && chooserClient.upload}
|
|
112
|
+
<UploadUI title="Upload to {$selected.path}" folder={$selected} uploader={chooserClient.upload.bind(chooserClient)} on:escape={() => { showuploader = false }} on:saved={onUploadComplete}/>
|
|
113
|
+
{/if}
|
|
108
114
|
</Dialog>
|
|
109
115
|
|
|
110
116
|
<style>
|
|
@@ -136,9 +142,12 @@ onMount(async () => {
|
|
|
136
142
|
padding: 1em;
|
|
137
143
|
overflow-y: auto;
|
|
138
144
|
}
|
|
139
|
-
|
|
145
|
+
.dialog-chooser-controls {
|
|
140
146
|
position: relative;
|
|
141
147
|
width: 100%;
|
|
142
148
|
}
|
|
149
|
+
:global(footer.actions .upload) {
|
|
150
|
+
margin-right: auto;
|
|
151
|
+
}
|
|
143
152
|
|
|
144
153
|
</style>
|
|
@@ -25,7 +25,20 @@ export interface Client<F = any> {
|
|
|
25
25
|
* undo values it generates.
|
|
26
26
|
*/
|
|
27
27
|
valueToUrl?: (value: string) => string | undefined;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* must accept a standard FileList object and upload the files to the service
|
|
30
|
+
* should throw an error if the source/path does not accept uploads the UI is
|
|
31
|
+
* responsible for refreshing the folder list after success
|
|
32
|
+
* should call the provided progress function as often as possible so that
|
|
33
|
+
* dosgato-dialog can keep the user informed
|
|
34
|
+
*/
|
|
35
|
+
upload?: (folder: Folder, files: File[], progress: (ratio: number) => void) => Promise<(Asset | Folder)[] | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* return whether the user is allowed to upload to the currently selected folder
|
|
38
|
+
* if this function is not provided it is assumed the answer is always yes
|
|
39
|
+
* may optionally return an array of accepted mime types for the folder
|
|
40
|
+
*/
|
|
41
|
+
mayUpload?: (folder: Folder) => boolean | string[];
|
|
29
42
|
}
|
|
30
43
|
export interface Source {
|
|
31
44
|
type: ChooserType;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { TreeStore, type TypedTreeItem } from '../tree/treestore.js';
|
|
2
2
|
import { Store } from '@txstate-mws/svelte-store';
|
|
3
3
|
import type { AnyItem, Asset, Client, ChooserType, Folder, Page, Source } from './ChooserAPI.js';
|
|
4
4
|
export interface UISource extends Source {
|
|
@@ -47,9 +47,13 @@ export declare class ChooserStore<F = any> extends Store<IAssetStore> {
|
|
|
47
47
|
options: InternalStoreOptions<F>;
|
|
48
48
|
constructor(client: Client);
|
|
49
49
|
setOptions(options: ChooserStoreOptions<F>): void;
|
|
50
|
+
filter: undefined | ((item: AnyItem) => boolean | Promise<boolean>);
|
|
51
|
+
fetchChildren(item?: TypedTreeItem<Page | Folder | Asset>): Promise<AnyItem[]>;
|
|
52
|
+
treeStore: TreeStore<Asset | Folder | Page>;
|
|
50
53
|
sources: import("@txstate-mws/svelte-store").DerivedStore<UISource[], IAssetStore>;
|
|
51
54
|
source: import("@txstate-mws/svelte-store").DerivedStore<UISource | undefined, IAssetStore>;
|
|
52
55
|
preview: import("@txstate-mws/svelte-store").DerivedStore<AnyItem | AnyUIItem | undefined, IAssetStore>;
|
|
56
|
+
selected: import("@txstate-mws/svelte-store").DerivedStore<TypedTreeItem<Asset | Folder | Page> | undefined, any>;
|
|
53
57
|
getSource(state?: IAssetStore): UISource | undefined;
|
|
54
58
|
getSourceIndex(name: string, state?: IAssetStore, type?: ChooserType): number;
|
|
55
59
|
init(options: ChooserStoreOptions<F>): Promise<void>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { TreeStore } from '../tree/treestore.js';
|
|
1
2
|
import { Store, derivedStore } from '@txstate-mws/svelte-store';
|
|
2
3
|
import { tick } from 'svelte';
|
|
3
4
|
import { findIndex } from 'txstate-utils';
|
|
5
|
+
import { TabStore } from '../TabStore.js';
|
|
4
6
|
export const CHOOSER_STORE_CONTEXT = {};
|
|
5
7
|
const nofilter = (x) => true;
|
|
6
8
|
export function combinePath(path, name) {
|
|
@@ -32,9 +34,18 @@ export class ChooserStore extends Store {
|
|
|
32
34
|
filter
|
|
33
35
|
};
|
|
34
36
|
}
|
|
37
|
+
filter = undefined;
|
|
38
|
+
async fetchChildren(item) {
|
|
39
|
+
const $source = this.getSource();
|
|
40
|
+
if (item?.type === 'asset' || !$source)
|
|
41
|
+
return [];
|
|
42
|
+
return await this.client.getChildren($source.name, item?.path ?? '/', this.filter);
|
|
43
|
+
}
|
|
44
|
+
treeStore = new TreeStore(this.fetchChildren.bind(this));
|
|
35
45
|
sources = derivedStore(this, v => [...(v.sources?.page ?? []), ...(v.sources?.asset ?? [])].filter(s => this.options.activeSources ? this.options.activeSources.has(s.name) : true));
|
|
36
46
|
source = derivedStore(this, v => this.getSource(v));
|
|
37
47
|
preview = derivedStore(this, 'preview');
|
|
48
|
+
selected = derivedStore(this.treeStore, 'selectedItems.0');
|
|
38
49
|
getSource(state = this.value) {
|
|
39
50
|
return state.sources?.[state.activetype]?.[state.activesource];
|
|
40
51
|
}
|
|
@@ -53,7 +64,7 @@ export class ChooserStore extends Store {
|
|
|
53
64
|
const sources = { page: pageSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s.name)) ?? [], asset: assetSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s.name)) ?? [] };
|
|
54
65
|
return { ...v, sources };
|
|
55
66
|
});
|
|
56
|
-
this.setSource(this.
|
|
67
|
+
this.setSource(this.options.initialSource, true);
|
|
57
68
|
await tick();
|
|
58
69
|
this.update(v => ({ ...v, initialized: true }));
|
|
59
70
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<script>import trashLight from '@iconify-icons/ph/trash-light';
|
|
2
|
+
import { roundTo, unique } from 'txstate-utils';
|
|
3
|
+
import { createEventDispatcher } from 'svelte';
|
|
4
|
+
import { Dialog, FileIcon, Icon } from '..';
|
|
5
|
+
export let title;
|
|
6
|
+
export let folder;
|
|
7
|
+
export let maxFiles = 200;
|
|
8
|
+
export let escapable = true;
|
|
9
|
+
export let mimeWhitelist = [];
|
|
10
|
+
export let mimeBlacklist = [];
|
|
11
|
+
export let uploader;
|
|
12
|
+
$: whitelist = new Set(mimeWhitelist);
|
|
13
|
+
$: blacklist = new Set(mimeBlacklist);
|
|
14
|
+
const dispatch = createEventDispatcher();
|
|
15
|
+
let dragover = 0;
|
|
16
|
+
let uploadList = [];
|
|
17
|
+
let uploadLocked = false;
|
|
18
|
+
let uploadProgress = 0;
|
|
19
|
+
let uploadError;
|
|
20
|
+
function onUploadEnter(e) {
|
|
21
|
+
if (e.dataTransfer?.items.length)
|
|
22
|
+
dragover++;
|
|
23
|
+
}
|
|
24
|
+
function onUploadLeave(e) {
|
|
25
|
+
if (e.dataTransfer?.items.length)
|
|
26
|
+
dragover--;
|
|
27
|
+
}
|
|
28
|
+
function onUploadDrop(e) {
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
dragover = 0;
|
|
31
|
+
if (!uploadLocked && e.dataTransfer?.items?.length) {
|
|
32
|
+
uploadList = unique(uploadList.concat(Array.from(e.dataTransfer.files)), 'name').slice(-1 * maxFiles);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function onUploadChange(e) {
|
|
36
|
+
const files = e.currentTarget.files;
|
|
37
|
+
if (files?.length)
|
|
38
|
+
uploadList = unique(uploadList.concat(Array.from(files)), 'name').slice(-1 * maxFiles);
|
|
39
|
+
e.currentTarget.value = '';
|
|
40
|
+
}
|
|
41
|
+
async function onUploadSubmit() {
|
|
42
|
+
if (uploadLocked)
|
|
43
|
+
return;
|
|
44
|
+
uploadLocked = true;
|
|
45
|
+
try {
|
|
46
|
+
const data = new FormData();
|
|
47
|
+
for (let i = 0; i < uploadList.length; i++) {
|
|
48
|
+
data.append('file' + i, uploadList[i]);
|
|
49
|
+
}
|
|
50
|
+
// TODO: accept new list of children from uploader function and feed it
|
|
51
|
+
// to the tree instead of refreshing the tree
|
|
52
|
+
await uploader(folder, uploadList, ratio => { uploadProgress = ratio; });
|
|
53
|
+
uploadList = [];
|
|
54
|
+
uploadError = undefined;
|
|
55
|
+
dispatch('saved');
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
uploadError = e.message;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
uploadLocked = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function onUploadEscape() {
|
|
65
|
+
if (!uploadLocked && escapable) {
|
|
66
|
+
uploadList = [];
|
|
67
|
+
uploadError = undefined;
|
|
68
|
+
dispatch('escape');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function onDeleteFile(file) {
|
|
72
|
+
return () => {
|
|
73
|
+
uploadList = uploadList.filter(f => f !== file);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<Dialog {title} disabled={!uploadList.length} cancelText="Cancel" continueText="Upload" on:escape={onUploadEscape} on:continue={onUploadSubmit}>
|
|
79
|
+
{#if uploadLocked}
|
|
80
|
+
<progress value={uploadProgress} aria-label="Assets Uploading">{roundTo(100 * uploadProgress)}%</progress>
|
|
81
|
+
{:else}
|
|
82
|
+
{#if uploadError}<div class="error">{uploadError}</div>{/if}
|
|
83
|
+
<form method="POST" enctype="multipart/form-data"
|
|
84
|
+
on:submit|preventDefault|stopPropagation={onUploadSubmit}
|
|
85
|
+
class="uploader" class:dragover={dragover > 0}
|
|
86
|
+
on:dragenter={onUploadEnter} on:dragleave={onUploadLeave}
|
|
87
|
+
on:dragover|preventDefault={() => {}} on:drop={onUploadDrop}
|
|
88
|
+
>
|
|
89
|
+
<input type="file" id="uploader_input" multiple on:change={onUploadChange}>
|
|
90
|
+
<label for="uploader_input">Choose or drag files</label>
|
|
91
|
+
<ul>
|
|
92
|
+
{#each uploadList as file}
|
|
93
|
+
<li>
|
|
94
|
+
<FileIcon width="1.5em" mime={file.type} inline />{file.name}<button type="button" on:click={onDeleteFile(file)}><Icon icon={trashLight} width="1.5em" hiddenLabel="Remove File" inline /></button>
|
|
95
|
+
{#if (whitelist.size && !whitelist.has(file.type)) || (blacklist.size && blacklist.has(file.type))}
|
|
96
|
+
<div class="error">File type not allowed</div>
|
|
97
|
+
{/if}
|
|
98
|
+
</li>
|
|
99
|
+
{/each}
|
|
100
|
+
</ul>
|
|
101
|
+
</form>
|
|
102
|
+
{/if}
|
|
103
|
+
</Dialog>
|
|
104
|
+
|
|
105
|
+
<style>
|
|
106
|
+
.uploader {
|
|
107
|
+
border: 2px dashed #666666;
|
|
108
|
+
border-radius: 0.5em;
|
|
109
|
+
text-align: center;
|
|
110
|
+
padding: 1em;
|
|
111
|
+
min-height: 10em;
|
|
112
|
+
}
|
|
113
|
+
.uploader.dragover {
|
|
114
|
+
border-color: #333333;
|
|
115
|
+
}
|
|
116
|
+
.uploader ul {
|
|
117
|
+
padding: 0;
|
|
118
|
+
margin: 0;
|
|
119
|
+
list-style: none;
|
|
120
|
+
text-align: left;
|
|
121
|
+
}
|
|
122
|
+
progress {
|
|
123
|
+
width: 80%;
|
|
124
|
+
margin-left: 10%;
|
|
125
|
+
}
|
|
126
|
+
input[type="file"] {
|
|
127
|
+
opacity: 0;
|
|
128
|
+
}
|
|
129
|
+
label {
|
|
130
|
+
display: inline-block;
|
|
131
|
+
width: 50%;
|
|
132
|
+
padding: 1em;
|
|
133
|
+
background: #ccc;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
border-radius: 5px;
|
|
136
|
+
border: 1px solid #ccc;
|
|
137
|
+
margin-bottom: 1em;
|
|
138
|
+
}
|
|
139
|
+
input:focus + label {
|
|
140
|
+
outline: 2px solid blue;
|
|
141
|
+
}
|
|
142
|
+
.error {
|
|
143
|
+
color: red;
|
|
144
|
+
}
|
|
145
|
+
button {
|
|
146
|
+
border: 0;
|
|
147
|
+
background: none;
|
|
148
|
+
padding: 0.5em;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
}
|
|
151
|
+
li {
|
|
152
|
+
display: flex;
|
|
153
|
+
flex-wrap: wrap;
|
|
154
|
+
align-items: center;
|
|
155
|
+
}
|
|
156
|
+
li div {
|
|
157
|
+
width: 100%;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type Client, type Folder } from '..';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
title: string;
|
|
6
|
+
folder: Folder;
|
|
7
|
+
maxFiles?: number | undefined;
|
|
8
|
+
escapable?: boolean | undefined;
|
|
9
|
+
mimeWhitelist?: string[] | undefined;
|
|
10
|
+
mimeBlacklist?: string[] | undefined;
|
|
11
|
+
uploader: NonNullable<Client['upload']>;
|
|
12
|
+
};
|
|
13
|
+
events: {
|
|
14
|
+
saved: CustomEvent<any>;
|
|
15
|
+
escape: CustomEvent<any>;
|
|
16
|
+
} & {
|
|
17
|
+
[evt: string]: CustomEvent<any>;
|
|
18
|
+
};
|
|
19
|
+
slots: {};
|
|
20
|
+
};
|
|
21
|
+
export type UploadUiProps = typeof __propDef.props;
|
|
22
|
+
export type UploadUiEvents = typeof __propDef.events;
|
|
23
|
+
export type UploadUiSlots = typeof __propDef.slots;
|
|
24
|
+
export default class UploadUi extends SvelteComponentTyped<UploadUiProps, UploadUiEvents, UploadUiSlots> {
|
|
25
|
+
}
|
|
26
|
+
export {};
|
package/dist/chooser/index.d.ts
CHANGED
package/dist/chooser/index.js
CHANGED
package/dist/tree/Tree.svelte
CHANGED
|
@@ -146,6 +146,7 @@ afterUpdate(() => {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
});
|
|
149
|
+
$: myRootItems = $store && $filteredRootItems;
|
|
149
150
|
</script>
|
|
150
151
|
|
|
151
152
|
<svelte:window on:mouseup={headerDragEnd} />
|
|
@@ -157,20 +158,20 @@ afterUpdate(() => {
|
|
|
157
158
|
{#if enableResize && i !== headers.length - 1}<div class="tree-separator" on:mousedown={headerDragStart(header, i)} on:touchstart={headerDragStart(header, i)} on:dblclick={headerDragReset}> </div>{/if}
|
|
158
159
|
{/each}
|
|
159
160
|
</div>
|
|
160
|
-
{#if mounted &&
|
|
161
|
+
{#if mounted && myRootItems?.length}
|
|
161
162
|
<!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
|
|
162
163
|
<ul bind:this={store.treeElement} role="tree" class:resizing={!!dragheaderid} on:mousemove={dragheaderid ? headerDrag : undefined} on:touchmove={dragheaderid ? headerDrag : undefined} on:mouseup={headerDragEnd} on:touchend={headerDragEnd} on:keyup={onKeyUp}>
|
|
163
|
-
{#each
|
|
164
|
+
{#each myRootItems as item, i (item.id)}
|
|
164
165
|
<TreeNode
|
|
165
166
|
{item}
|
|
166
167
|
{headers}
|
|
167
168
|
{headerSizes}
|
|
168
169
|
{nodeClass}
|
|
169
170
|
posinset={i + 1}
|
|
170
|
-
setsize={
|
|
171
|
+
setsize={myRootItems.length}
|
|
171
172
|
level={item.level}
|
|
172
|
-
prev={
|
|
173
|
-
next={
|
|
173
|
+
prev={myRootItems[i - 1]}
|
|
174
|
+
next={myRootItems[i + 1]}
|
|
174
175
|
on:choose
|
|
175
176
|
on:deselect
|
|
176
177
|
/>
|
|
@@ -7,7 +7,7 @@ $: headerComponent = header.component;
|
|
|
7
7
|
</script>
|
|
8
8
|
|
|
9
9
|
{#if header.icon}
|
|
10
|
-
<span class="icon"><Icon {icon} inline width="1.
|
|
10
|
+
<span class="icon"><Icon {icon} inline width="1.5em" /></span>
|
|
11
11
|
{/if}
|
|
12
12
|
{#if header.component}
|
|
13
13
|
<svelte:component this={headerComponent} {item} {header} />
|
package/dist/tree/treestore.js
CHANGED
package/package.json
CHANGED