@dosgato/dialog 0.0.20 → 0.0.21
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/Button.svelte.d.ts +3 -3
- package/ButtonGroup.svelte.d.ts +3 -3
- package/Checkbox.svelte.d.ts +3 -3
- package/Container.svelte.d.ts +3 -3
- package/Dialog.svelte +22 -4
- package/Dialog.svelte.d.ts +5 -4
- package/FieldAutocomplete.svelte.d.ts +3 -3
- package/FieldCheckbox.svelte.d.ts +3 -3
- package/FieldChoices.svelte.d.ts +3 -3
- package/FieldChooserLink.svelte +14 -12
- package/FieldChooserLink.svelte.d.ts +3 -5
- package/FieldDate.svelte.d.ts +3 -3
- package/FieldDateTime.svelte.d.ts +3 -3
- package/FieldDualListbox.svelte.d.ts +3 -3
- package/FieldHidden.svelte.d.ts +3 -3
- package/FieldIdentifier.svelte.d.ts +3 -3
- package/FieldMultiple.svelte.d.ts +3 -3
- package/FieldMultiselect.svelte.d.ts +3 -3
- package/FieldNumber.svelte.d.ts +3 -3
- package/FieldRadio.svelte.d.ts +3 -3
- package/FieldSelect.svelte.d.ts +3 -3
- package/FieldStandard.svelte.d.ts +3 -3
- package/FieldText.svelte.d.ts +3 -3
- package/FieldTextArea.svelte.d.ts +3 -3
- package/FileIcon.svelte.d.ts +3 -3
- package/Form.svelte.d.ts +3 -3
- package/FormDialog.svelte.d.ts +3 -3
- package/Icon.svelte.d.ts +3 -3
- package/InlineMessage.svelte.d.ts +3 -3
- package/InlineMessages.svelte.d.ts +3 -3
- package/Input.svelte.d.ts +3 -3
- package/Listbox.svelte.d.ts +3 -3
- package/Radio.svelte.d.ts +3 -3
- package/Tab.svelte.d.ts +3 -3
- package/TabStore.d.ts +3 -0
- package/TabStore.js +12 -0
- package/Tabs.svelte +5 -4
- package/Tabs.svelte.d.ts +3 -3
- package/chooser/Chooser.svelte +76 -99
- package/chooser/Chooser.svelte.d.ts +5 -5
- package/chooser/ChooserAPI.d.ts +10 -3
- package/chooser/ChooserStore.d.ts +15 -33
- package/chooser/ChooserStore.js +32 -149
- package/chooser/Details.svelte.d.ts +6 -5
- package/chooser/Thumbnail.svelte +9 -2
- package/chooser/Thumbnail.svelte.d.ts +6 -5
- package/colorpicker/FieldColorPicker.svelte +78 -24
- package/colorpicker/FieldColorPicker.svelte.d.ts +5 -6
- package/iconpicker/FieldIconPicker.svelte +4 -2
- package/iconpicker/FieldIconPicker.svelte.d.ts +4 -3
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/package.json +9 -6
- package/tree/LoadIcon.svelte +24 -0
- package/tree/LoadIcon.svelte.d.ts +23 -0
- package/tree/Tree.svelte +203 -0
- package/tree/Tree.svelte.d.ts +28 -0
- package/tree/TreeCell.svelte +18 -0
- package/tree/TreeCell.svelte.d.ts +18 -0
- package/tree/TreeNode.svelte +418 -0
- package/tree/TreeNode.svelte.d.ts +30 -0
- package/tree/index.d.ts +3 -0
- package/tree/index.js +3 -0
- package/tree/treestore.d.ts +117 -0
- package/tree/treestore.js +336 -0
- package/chooser/Asset.svelte +0 -83
- package/chooser/Asset.svelte.d.ts +0 -25
- package/chooser/AssetFolder.svelte +0 -127
- package/chooser/AssetFolder.svelte.d.ts +0 -25
- package/chooser/Page.svelte +0 -121
- package/chooser/Page.svelte.d.ts +0 -25
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { Store } from '@txstate-mws/svelte-store';
|
|
3
|
+
import { type TypedTreeItem, type TreeItemFromDB, type TreeHeader } from './treestore';
|
|
4
|
+
declare class __sveltets_Render<T extends TreeItemFromDB> {
|
|
5
|
+
props(): {
|
|
6
|
+
headers: TreeHeader<T>[];
|
|
7
|
+
headerSizes: Store<string[]>;
|
|
8
|
+
nodeClass?: (itm: T) => string;
|
|
9
|
+
item: TypedTreeItem<T>;
|
|
10
|
+
posinset: number;
|
|
11
|
+
setsize: number;
|
|
12
|
+
level: number;
|
|
13
|
+
next: TypedTreeItem<T>;
|
|
14
|
+
prev: TypedTreeItem<T>;
|
|
15
|
+
parent?: TypedTreeItem<T>;
|
|
16
|
+
};
|
|
17
|
+
events(): {
|
|
18
|
+
choose: CustomEvent<any>;
|
|
19
|
+
deselect: CustomEvent<any>;
|
|
20
|
+
} & {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots(): {};
|
|
24
|
+
}
|
|
25
|
+
export type TreeNodeProps<T extends TreeItemFromDB> = ReturnType<__sveltets_Render<T>['props']>;
|
|
26
|
+
export type TreeNodeEvents<T extends TreeItemFromDB> = ReturnType<__sveltets_Render<T>['events']>;
|
|
27
|
+
export type TreeNodeSlots<T extends TreeItemFromDB> = ReturnType<__sveltets_Render<T>['slots']>;
|
|
28
|
+
export default class TreeNode<T extends TreeItemFromDB> extends SvelteComponentTyped<TreeNodeProps<T>, TreeNodeEvents<T>, TreeNodeSlots<T>> {
|
|
29
|
+
}
|
|
30
|
+
export {};
|
package/tree/index.d.ts
ADDED
package/tree/index.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { ActiveStore } from '@txstate-mws/svelte-store';
|
|
2
|
+
import type { IconifyIcon } from '@iconify/svelte';
|
|
3
|
+
import type { SvelteComponent } from 'svelte';
|
|
4
|
+
export declare const TREE_STORE_CONTEXT: {};
|
|
5
|
+
export interface TreeItemFromDB {
|
|
6
|
+
id: string;
|
|
7
|
+
hasChildren?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface TreeItem<T extends TreeItemFromDB> extends TreeItemFromDB {
|
|
10
|
+
level: number;
|
|
11
|
+
parent?: TypedTreeItem<T>;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
open?: boolean;
|
|
14
|
+
children?: TypedTreeItem<T>[];
|
|
15
|
+
}
|
|
16
|
+
export type TypedTreeItem<T extends TreeItemFromDB> = TreeItem<T> & T;
|
|
17
|
+
export interface ITreeStore<T extends TreeItemFromDB> {
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
rootItems?: TypedTreeItem<T>[];
|
|
20
|
+
itemsById: Record<string, TypedTreeItem<T> | undefined>;
|
|
21
|
+
focused?: TypedTreeItem<T>;
|
|
22
|
+
selected: Map<string, TypedTreeItem<T>>;
|
|
23
|
+
selectedItems: TypedTreeItem<T>[];
|
|
24
|
+
copied: Map<string, TypedTreeItem<T>>;
|
|
25
|
+
cut?: boolean;
|
|
26
|
+
draggable: boolean;
|
|
27
|
+
selectedUndraggable?: boolean;
|
|
28
|
+
dragging: boolean;
|
|
29
|
+
headerWidthOverrides: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
export type FetchChildrenFn<T extends TreeItemFromDB> = (item?: TypedTreeItem<T>) => Promise<T[]>;
|
|
32
|
+
export type DragEligibleFn<T extends TreeItemFromDB> = (selectedItems: TypedTreeItem<T>[], userWantsCopy: boolean) => boolean;
|
|
33
|
+
export type DropEffectFn<T extends TreeItemFromDB> = (selectedItems: TypedTreeItem<T>[], dropTarget: TypedTreeItem<T>, above: boolean, userWantsCopy: boolean) => 'move' | 'copy' | 'none';
|
|
34
|
+
export type MoveHandlerFn<T extends TreeItemFromDB> = (selectedItems: TypedTreeItem<T>[], dropTarget: TypedTreeItem<T>, above: boolean) => boolean | Promise<boolean>;
|
|
35
|
+
export type CopyHandlerFn<T extends TreeItemFromDB> = (selectedItems: TypedTreeItem<T>[], dropTarget: TypedTreeItem<T>, above: boolean, userWantsRecursive: boolean | undefined) => boolean | Promise<boolean>;
|
|
36
|
+
export interface TreeHeader<T extends TreeItemFromDB> {
|
|
37
|
+
id: string;
|
|
38
|
+
label: string;
|
|
39
|
+
fixed?: string;
|
|
40
|
+
grow?: number;
|
|
41
|
+
icon?: IconifyIcon | ((item: TypedTreeItem<T>) => IconifyIcon | undefined);
|
|
42
|
+
get?: string;
|
|
43
|
+
render?: (item: TypedTreeItem<T>) => string;
|
|
44
|
+
component?: SvelteComponent;
|
|
45
|
+
class?: (item: TypedTreeItem<T>) => string | string[];
|
|
46
|
+
}
|
|
47
|
+
export declare class TreeStore<T extends TreeItemFromDB> extends ActiveStore<ITreeStore<T>> {
|
|
48
|
+
#private;
|
|
49
|
+
fetchChildren: FetchChildrenFn<T>;
|
|
50
|
+
treeElement?: HTMLElement;
|
|
51
|
+
rootItems: import("@txstate-mws/svelte-store").DerivedStore<TypedTreeItem<T>[], ITreeStore<T>>;
|
|
52
|
+
draggable: import("@txstate-mws/svelte-store").DerivedStore<boolean, ITreeStore<T>>;
|
|
53
|
+
dragging: import("@txstate-mws/svelte-store").DerivedStore<boolean, ITreeStore<T>>;
|
|
54
|
+
selectedUndraggable: import("@txstate-mws/svelte-store").DerivedStore<boolean, ITreeStore<T>>;
|
|
55
|
+
selected: import("@txstate-mws/svelte-store").DerivedStore<Map<string, TypedTreeItem<T>>, ITreeStore<T>>;
|
|
56
|
+
focused: import("@txstate-mws/svelte-store").DerivedStore<TypedTreeItem<T>, ITreeStore<T>>;
|
|
57
|
+
copied: import("@txstate-mws/svelte-store").DerivedStore<Map<string, TypedTreeItem<T>>, ITreeStore<T>>;
|
|
58
|
+
headerOverride: import("@txstate-mws/svelte-store").DerivedStore<Record<string, string>, ITreeStore<T>>;
|
|
59
|
+
moveHandler?: MoveHandlerFn<T>;
|
|
60
|
+
copyHandler?: CopyHandlerFn<T>;
|
|
61
|
+
dragEligibleHandler?: DragEligibleFn<T>;
|
|
62
|
+
dropEffectHandler?: DropEffectFn<T>;
|
|
63
|
+
singleSelect?: boolean;
|
|
64
|
+
private refreshPromise?;
|
|
65
|
+
constructor(fetchChildren: FetchChildrenFn<T>, { moveHandler, copyHandler, dragEligible, dropEffect, singleSelect }?: {
|
|
66
|
+
moveHandler?: MoveHandlerFn<T>;
|
|
67
|
+
copyHandler?: CopyHandlerFn<T>;
|
|
68
|
+
dragEligible?: DragEligibleFn<T>;
|
|
69
|
+
dropEffect?: DropEffectFn<T>;
|
|
70
|
+
singleSelect?: boolean;
|
|
71
|
+
});
|
|
72
|
+
visit(item: TypedTreeItem<T>, cb: (item: TypedTreeItem<T>) => Promise<void>): Promise<void>;
|
|
73
|
+
visitSync(item: TypedTreeItem<T>, cb: (item: TypedTreeItem<T>) => void): void;
|
|
74
|
+
addLookup(items: TypedTreeItem<T>[]): void;
|
|
75
|
+
cleanSelected(): void;
|
|
76
|
+
determineDraggable(): void;
|
|
77
|
+
trigger(): void;
|
|
78
|
+
fetch(item?: TypedTreeItem<T>): Promise<TypedTreeItem<T>[]>;
|
|
79
|
+
refresh(item?: TypedTreeItem<T>, skipNotify?: boolean): Promise<void>;
|
|
80
|
+
focus(item: TypedTreeItem<T> | undefined, notify?: boolean): void;
|
|
81
|
+
select(item: TypedTreeItem<T>, { clear, notify, toggle }: {
|
|
82
|
+
clear?: boolean;
|
|
83
|
+
notify?: boolean;
|
|
84
|
+
toggle?: boolean;
|
|
85
|
+
}): void;
|
|
86
|
+
selectById(id: string, { clear, notify, toggle }: {
|
|
87
|
+
clear?: boolean;
|
|
88
|
+
notify?: boolean;
|
|
89
|
+
toggle?: boolean;
|
|
90
|
+
}): void;
|
|
91
|
+
deselect(notify?: boolean): void;
|
|
92
|
+
isSelected(item: TypedTreeItem<T>): boolean;
|
|
93
|
+
open(item: TypedTreeItem<T>, notify?: boolean): Promise<void>;
|
|
94
|
+
openAndRefresh(item: TypedTreeItem<T>, notify?: boolean): Promise<void>;
|
|
95
|
+
close(item: TypedTreeItem<T>): void;
|
|
96
|
+
toggle(item: TypedTreeItem<T>): Promise<void>;
|
|
97
|
+
viewUnder(item?: TypedTreeItem<T>): Promise<void>;
|
|
98
|
+
dragStart(item: TypedTreeItem<T>): void;
|
|
99
|
+
protected _drop(item: TypedTreeItem<T>, droppedItems: Map<string, TypedTreeItem<T>>, above: boolean, userWantsCopy: boolean, userWantsRecursive: boolean | undefined): Promise<boolean>;
|
|
100
|
+
drop(item: TypedTreeItem<T>, above: boolean, userWantsCopy: any): Promise<boolean>;
|
|
101
|
+
collectAncestors(item: TypedTreeItem<T>): TypedTreeItem<T>[];
|
|
102
|
+
root(item: TypedTreeItem<T>): TypedTreeItem<T>;
|
|
103
|
+
findCommonParent(items: TypedTreeItem<T>[]): TypedTreeItem<T>;
|
|
104
|
+
dragEligible(selectedItems: TypedTreeItem<T>[], userWantsCopy: boolean): boolean;
|
|
105
|
+
protected _dropEffect(item: TypedTreeItem<T>, droppedItems: Map<string, TypedTreeItem<T>>, above: boolean, userWantsCopy: boolean): "none" | "copy" | "move";
|
|
106
|
+
dropEffect(item: TypedTreeItem<T>, above: boolean, userWantsCopy: boolean): "none" | "copy" | "move";
|
|
107
|
+
cut(): void;
|
|
108
|
+
copy(): void;
|
|
109
|
+
cutEligible(): boolean;
|
|
110
|
+
copyEligible(): boolean;
|
|
111
|
+
cancelCopy(): void;
|
|
112
|
+
pasteEligible(above?: boolean): boolean;
|
|
113
|
+
pasteEffect(above?: boolean): "none" | "copy" | "move";
|
|
114
|
+
paste(above?: boolean, userWantsRecursive?: boolean): Promise<boolean>;
|
|
115
|
+
setHeaderOverride(id: string, width: string): void;
|
|
116
|
+
resetHeaderOverride(): void;
|
|
117
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { ActiveStore, derivedStore } from '@txstate-mws/svelte-store';
|
|
2
|
+
import { keyby } from 'txstate-utils';
|
|
3
|
+
export const TREE_STORE_CONTEXT = {};
|
|
4
|
+
export class TreeStore extends ActiveStore {
|
|
5
|
+
fetchChildren;
|
|
6
|
+
treeElement;
|
|
7
|
+
rootItems = derivedStore(this, 'rootItems');
|
|
8
|
+
draggable = derivedStore(this, v => v.draggable && !v.loading);
|
|
9
|
+
dragging = derivedStore(this, 'dragging');
|
|
10
|
+
selectedUndraggable = derivedStore(this, 'selectedUndraggable');
|
|
11
|
+
selected = derivedStore(this, 'selected');
|
|
12
|
+
focused = derivedStore(this, 'focused');
|
|
13
|
+
copied = derivedStore(this, 'copied');
|
|
14
|
+
headerOverride = derivedStore(this, 'headerWidthOverrides');
|
|
15
|
+
moveHandler;
|
|
16
|
+
copyHandler;
|
|
17
|
+
dragEligibleHandler;
|
|
18
|
+
dropEffectHandler;
|
|
19
|
+
singleSelect;
|
|
20
|
+
refreshPromise;
|
|
21
|
+
constructor(fetchChildren, { moveHandler, copyHandler, dragEligible, dropEffect, singleSelect } = {}) {
|
|
22
|
+
super({ itemsById: {}, selected: new Map(), selectedItems: [], copied: new Map(), dragging: false, draggable: !!moveHandler, headerWidthOverrides: {} });
|
|
23
|
+
this.fetchChildren = fetchChildren;
|
|
24
|
+
this.moveHandler = moveHandler;
|
|
25
|
+
this.copyHandler = copyHandler;
|
|
26
|
+
this.dragEligibleHandler = dragEligible;
|
|
27
|
+
this.dropEffectHandler = dropEffect;
|
|
28
|
+
this.singleSelect = singleSelect;
|
|
29
|
+
}
|
|
30
|
+
async visit(item, cb) {
|
|
31
|
+
await cb(item);
|
|
32
|
+
await Promise.all((item.children ?? []).map(async (child) => await this.visit(child, cb)));
|
|
33
|
+
}
|
|
34
|
+
visitSync(item, cb) {
|
|
35
|
+
cb(item);
|
|
36
|
+
for (const child of item.children ?? [])
|
|
37
|
+
this.visitSync(child, cb);
|
|
38
|
+
}
|
|
39
|
+
addLookup(items) {
|
|
40
|
+
for (const item of items) {
|
|
41
|
+
this.visitSync(item, itm => {
|
|
42
|
+
this.value.itemsById[itm.id] = itm;
|
|
43
|
+
if (this.value.selected.has(itm.id))
|
|
44
|
+
this.value.selected.set(itm.id, itm);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
this.cleanSelected();
|
|
48
|
+
}
|
|
49
|
+
cleanSelected() {
|
|
50
|
+
for (const selected of this.value.selected.values()) {
|
|
51
|
+
if (!this.value.itemsById[selected.id])
|
|
52
|
+
this.value.selected.delete(selected.id);
|
|
53
|
+
}
|
|
54
|
+
this.determineDraggable();
|
|
55
|
+
}
|
|
56
|
+
determineDraggable() {
|
|
57
|
+
this.value.selectedItems = Array.from(this.value.selected.values());
|
|
58
|
+
this.value.selectedUndraggable = !this.dragEligible(this.value.selectedItems, true) && !this.dragEligible(this.value.selectedItems, false);
|
|
59
|
+
}
|
|
60
|
+
trigger() {
|
|
61
|
+
this.set(this.value);
|
|
62
|
+
}
|
|
63
|
+
async fetch(item) {
|
|
64
|
+
const children = await this.fetchChildren(item);
|
|
65
|
+
for (const child of children) {
|
|
66
|
+
child.level = (item?.level ?? 0) + 1;
|
|
67
|
+
child.parent = item;
|
|
68
|
+
}
|
|
69
|
+
return children;
|
|
70
|
+
}
|
|
71
|
+
async #refresh(item, skipNotify = false) {
|
|
72
|
+
if (item)
|
|
73
|
+
item.loading = true;
|
|
74
|
+
else
|
|
75
|
+
this.value.loading = true;
|
|
76
|
+
this.trigger();
|
|
77
|
+
try {
|
|
78
|
+
const children = await this.fetch(item);
|
|
79
|
+
// re-open any open children
|
|
80
|
+
await Promise.all(children.map(async (child) => await this.visit(child, async (child) => {
|
|
81
|
+
child.open = this.value.itemsById[child.id]?.open;
|
|
82
|
+
if (child.open) {
|
|
83
|
+
child.children = await this.fetch(child);
|
|
84
|
+
child.hasChildren = child.children.length > 0;
|
|
85
|
+
if (!child.hasChildren)
|
|
86
|
+
child.open = false;
|
|
87
|
+
}
|
|
88
|
+
})));
|
|
89
|
+
if (item) {
|
|
90
|
+
this.visitSync(item, itm => { if (itm.id !== item.id)
|
|
91
|
+
this.value.itemsById[itm.id] = undefined; });
|
|
92
|
+
item.children = children;
|
|
93
|
+
item.hasChildren = children.length > 0;
|
|
94
|
+
if (!item.hasChildren)
|
|
95
|
+
item.open = false;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.value.itemsById = {};
|
|
99
|
+
for (const child of children)
|
|
100
|
+
child.level = 1;
|
|
101
|
+
this.value.rootItems = children;
|
|
102
|
+
}
|
|
103
|
+
this.addLookup(children);
|
|
104
|
+
// if the focused item disappeared in the refresh, we need to replace it,
|
|
105
|
+
// as without a focus the tree becomes invisible to keyboard nav
|
|
106
|
+
if (!this.value.itemsById[this.value.focused?.id])
|
|
107
|
+
this.focus(this.value.selectedItems.slice(-1)[0] ?? this.value.rootItems?.[0], true);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
if (item)
|
|
111
|
+
item.loading = false;
|
|
112
|
+
this.value.loading = false;
|
|
113
|
+
if (!skipNotify)
|
|
114
|
+
this.trigger();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async refresh(item, skipNotify = false) {
|
|
118
|
+
this.refreshPromise ??= this.#refresh(item, skipNotify);
|
|
119
|
+
await this.refreshPromise;
|
|
120
|
+
this.refreshPromise = undefined;
|
|
121
|
+
}
|
|
122
|
+
focus(item, notify = true) {
|
|
123
|
+
this.value.focused = item;
|
|
124
|
+
if (notify)
|
|
125
|
+
this.trigger();
|
|
126
|
+
}
|
|
127
|
+
select(item, { clear = false, notify = true, toggle = false }) {
|
|
128
|
+
const selected = this.isSelected(item);
|
|
129
|
+
const numSelected = this.value.selected.size;
|
|
130
|
+
if (this.singleSelect)
|
|
131
|
+
clear = true;
|
|
132
|
+
if (clear) {
|
|
133
|
+
this.value.selected.clear();
|
|
134
|
+
this.focus(item, false);
|
|
135
|
+
}
|
|
136
|
+
if (toggle && selected && (!clear || numSelected === 1))
|
|
137
|
+
this.value.selected.delete(item.id);
|
|
138
|
+
else
|
|
139
|
+
this.value.selected.set(item.id, item);
|
|
140
|
+
this.determineDraggable();
|
|
141
|
+
if (notify)
|
|
142
|
+
this.trigger();
|
|
143
|
+
}
|
|
144
|
+
selectById(id, { clear = false, notify = true, toggle = false }) {
|
|
145
|
+
const item = this.value.itemsById[id];
|
|
146
|
+
if (item)
|
|
147
|
+
this.select(item, { clear, notify, toggle });
|
|
148
|
+
}
|
|
149
|
+
deselect(notify = true) {
|
|
150
|
+
this.value.selected.clear();
|
|
151
|
+
this.determineDraggable();
|
|
152
|
+
if (notify)
|
|
153
|
+
this.trigger();
|
|
154
|
+
}
|
|
155
|
+
isSelected(item) {
|
|
156
|
+
return this.value.selected.has(item.id);
|
|
157
|
+
}
|
|
158
|
+
async open(item, notify = true) {
|
|
159
|
+
if (item.open || item.hasChildren === false)
|
|
160
|
+
return;
|
|
161
|
+
await this.openAndRefresh(item, notify);
|
|
162
|
+
}
|
|
163
|
+
async openAndRefresh(item, notify = true) {
|
|
164
|
+
await this.refresh(item, true);
|
|
165
|
+
item.open = !!item.children?.length;
|
|
166
|
+
if (notify)
|
|
167
|
+
this.trigger();
|
|
168
|
+
}
|
|
169
|
+
close(item) {
|
|
170
|
+
for (const child of item.children ?? [])
|
|
171
|
+
this.value.itemsById[child.id] = undefined;
|
|
172
|
+
this.cleanSelected();
|
|
173
|
+
item.children = undefined;
|
|
174
|
+
item.open = false;
|
|
175
|
+
this.trigger();
|
|
176
|
+
}
|
|
177
|
+
async toggle(item) {
|
|
178
|
+
if (item.open)
|
|
179
|
+
this.close(item);
|
|
180
|
+
else
|
|
181
|
+
await this.open(item);
|
|
182
|
+
}
|
|
183
|
+
async viewUnder(item) {
|
|
184
|
+
if (item)
|
|
185
|
+
await this.open(item);
|
|
186
|
+
this.trigger();
|
|
187
|
+
}
|
|
188
|
+
dragStart(item) {
|
|
189
|
+
if (this.value.dragging || !this.value.draggable)
|
|
190
|
+
return;
|
|
191
|
+
if (!this.value.selected.has(item.id)) {
|
|
192
|
+
this.select(item, { clear: true, notify: false });
|
|
193
|
+
}
|
|
194
|
+
this.value.dragging = true;
|
|
195
|
+
this.trigger();
|
|
196
|
+
}
|
|
197
|
+
async _drop(item, droppedItems, above, userWantsCopy, userWantsRecursive) {
|
|
198
|
+
const dropEffect = this._dropEffect(item, droppedItems, above, userWantsCopy);
|
|
199
|
+
if (dropEffect === 'none')
|
|
200
|
+
return false;
|
|
201
|
+
this.value.dragging = false;
|
|
202
|
+
this.value.loading = true;
|
|
203
|
+
this.trigger();
|
|
204
|
+
const selectedItems = Array.from(droppedItems.values());
|
|
205
|
+
const commonparent = this.findCommonParent([...selectedItems, item]);
|
|
206
|
+
try {
|
|
207
|
+
const result = dropEffect === 'move'
|
|
208
|
+
? await this.moveHandler(selectedItems, item, above)
|
|
209
|
+
: await this.copyHandler(selectedItems, item, above, userWantsRecursive);
|
|
210
|
+
await this.openAndRefresh(item);
|
|
211
|
+
await this.refresh(commonparent);
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
console.error(e);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
this.update(v => ({ ...v, loading: false }));
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
async drop(item, above, userWantsCopy) {
|
|
223
|
+
const ret = await this._drop(item, this.value.selected, above, userWantsCopy, undefined);
|
|
224
|
+
return ret;
|
|
225
|
+
}
|
|
226
|
+
collectAncestors(item) {
|
|
227
|
+
const ret = [];
|
|
228
|
+
let itm = item;
|
|
229
|
+
while (itm.parent) {
|
|
230
|
+
ret.push(itm.parent);
|
|
231
|
+
itm = itm.parent;
|
|
232
|
+
}
|
|
233
|
+
return ret;
|
|
234
|
+
}
|
|
235
|
+
root(item) {
|
|
236
|
+
let root = item;
|
|
237
|
+
while (root.parent)
|
|
238
|
+
root = root.parent;
|
|
239
|
+
return root;
|
|
240
|
+
}
|
|
241
|
+
findCommonParent(items) {
|
|
242
|
+
if (items.length <= 1)
|
|
243
|
+
return;
|
|
244
|
+
const [first, ...rest] = items;
|
|
245
|
+
const ancestors = [first, ...this.collectAncestors(first)];
|
|
246
|
+
const lookup = keyby(ancestors, 'id');
|
|
247
|
+
const depthById = ancestors.reduce((depthById, a, i) => { depthById[a.id] = i; return depthById; }, {});
|
|
248
|
+
let idx = -1;
|
|
249
|
+
for (const item of rest) {
|
|
250
|
+
const itemAncestors = this.collectAncestors(item);
|
|
251
|
+
const firstcommon = itemAncestors.find(a => lookup[a.id]);
|
|
252
|
+
if (!firstcommon)
|
|
253
|
+
return;
|
|
254
|
+
const found = depthById[firstcommon.id];
|
|
255
|
+
if (found > idx)
|
|
256
|
+
idx = found;
|
|
257
|
+
}
|
|
258
|
+
return ancestors[idx];
|
|
259
|
+
}
|
|
260
|
+
dragEligible(selectedItems, userWantsCopy) {
|
|
261
|
+
return !this.dragEligibleHandler || this.dragEligibleHandler(selectedItems, userWantsCopy);
|
|
262
|
+
}
|
|
263
|
+
_dropEffect(item, droppedItems, above, userWantsCopy) {
|
|
264
|
+
const handlerAnswer = this.dropEffectHandler?.(Array.from(droppedItems.values()), item, above, userWantsCopy) ?? 'move';
|
|
265
|
+
if (handlerAnswer === 'none')
|
|
266
|
+
return 'none';
|
|
267
|
+
if (handlerAnswer === 'move') {
|
|
268
|
+
// I could make the user's dropEffectHandler check this, but it's pretty universal that you
|
|
269
|
+
// can't move a thing into itself or one of its own descendants
|
|
270
|
+
// and it would be super weird to just automagically turn it into a copy, not to mention it would
|
|
271
|
+
// mean placing it back on itself would feel like canceling the move but make a copy instead
|
|
272
|
+
if (droppedItems.has(item.id))
|
|
273
|
+
return 'none';
|
|
274
|
+
for (const ancestor of this.collectAncestors(item)) {
|
|
275
|
+
if (droppedItems.has(ancestor.id))
|
|
276
|
+
return 'none';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (handlerAnswer === 'move' && !this.moveHandler)
|
|
280
|
+
return 'none';
|
|
281
|
+
if (handlerAnswer === 'copy' && !this.copyHandler)
|
|
282
|
+
return 'none';
|
|
283
|
+
return handlerAnswer;
|
|
284
|
+
}
|
|
285
|
+
dropEffect(item, above, userWantsCopy) {
|
|
286
|
+
return this._dropEffect(item, this.value.selected, above, userWantsCopy);
|
|
287
|
+
}
|
|
288
|
+
cut() {
|
|
289
|
+
if (!this.cutEligible())
|
|
290
|
+
return;
|
|
291
|
+
this.value.copied = new Map(this.value.selected);
|
|
292
|
+
this.value.cut = true;
|
|
293
|
+
this.trigger();
|
|
294
|
+
}
|
|
295
|
+
copy() {
|
|
296
|
+
if (!this.copyEligible())
|
|
297
|
+
return;
|
|
298
|
+
this.value.copied = new Map(this.value.selected);
|
|
299
|
+
this.value.cut = false;
|
|
300
|
+
this.trigger();
|
|
301
|
+
}
|
|
302
|
+
cutEligible() {
|
|
303
|
+
return this.moveHandler && this.dragEligible(this.value.selectedItems, false);
|
|
304
|
+
}
|
|
305
|
+
copyEligible() {
|
|
306
|
+
return this.copyHandler && this.dragEligible(this.value.selectedItems, true);
|
|
307
|
+
}
|
|
308
|
+
cancelCopy() {
|
|
309
|
+
this.value.copied = new Map();
|
|
310
|
+
this.value.cut = undefined;
|
|
311
|
+
this.trigger();
|
|
312
|
+
}
|
|
313
|
+
pasteEligible(above = false) {
|
|
314
|
+
return this.value.copied.size && this.pasteEffect(above) !== 'none';
|
|
315
|
+
}
|
|
316
|
+
pasteEffect(above = false) {
|
|
317
|
+
return this._dropEffect(this.value.selectedItems[0], this.value.copied, above, !this.value.cut);
|
|
318
|
+
}
|
|
319
|
+
async paste(above = false, userWantsRecursive = false) {
|
|
320
|
+
if (this.pasteEffect(above) === 'none')
|
|
321
|
+
return;
|
|
322
|
+
const copied = this.value.copied;
|
|
323
|
+
const cut = this.value.cut;
|
|
324
|
+
this.value.copied = new Map();
|
|
325
|
+
this.value.cut = undefined;
|
|
326
|
+
return await this._drop(this.value.selectedItems[0], copied, above, !cut, userWantsRecursive);
|
|
327
|
+
}
|
|
328
|
+
setHeaderOverride(id, width) {
|
|
329
|
+
this.value.headerWidthOverrides[id] = `max(20px, ${width})`;
|
|
330
|
+
this.trigger();
|
|
331
|
+
}
|
|
332
|
+
resetHeaderOverride() {
|
|
333
|
+
this.value.headerWidthOverrides = {};
|
|
334
|
+
this.trigger();
|
|
335
|
+
}
|
|
336
|
+
}
|
package/chooser/Asset.svelte
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
<script>import { modifierKey } from '@txstate-mws/svelte-components';
|
|
2
|
-
import { createEventDispatcher, getContext } from 'svelte';
|
|
3
|
-
import { hashid } from 'txstate-utils';
|
|
4
|
-
import { CHOOSER_STORE_CONTEXT } from './ChooserStore';
|
|
5
|
-
import FileIcon from '../FileIcon.svelte';
|
|
6
|
-
export let asset;
|
|
7
|
-
export let level;
|
|
8
|
-
export let posinset;
|
|
9
|
-
export let setsize;
|
|
10
|
-
export let next;
|
|
11
|
-
export let prev;
|
|
12
|
-
export let parent = undefined;
|
|
13
|
-
const store = getContext(CHOOSER_STORE_CONTEXT);
|
|
14
|
-
$: id = hashid(asset.id);
|
|
15
|
-
$: haveFocus = $store?.focus === asset.id;
|
|
16
|
-
$: isPreview = $store.preview?.id === asset.id;
|
|
17
|
-
const dispatch = createEventDispatcher();
|
|
18
|
-
function onKeyDown(e) {
|
|
19
|
-
if (modifierKey(e))
|
|
20
|
-
return;
|
|
21
|
-
if (['Enter', ' '].includes(e.key)) {
|
|
22
|
-
onClick(e);
|
|
23
|
-
}
|
|
24
|
-
else if (e.key === 'ArrowDown') {
|
|
25
|
-
e.preventDefault();
|
|
26
|
-
e.stopPropagation();
|
|
27
|
-
if (next) {
|
|
28
|
-
store.setFocus(next);
|
|
29
|
-
document.getElementById(hashid(next.id)).focus();
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
else if (e.key === 'ArrowUp') {
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
e.stopPropagation();
|
|
35
|
-
const anyprev = prev;
|
|
36
|
-
const myprev = anyprev?.open && anyprev.children?.length && anyprev.path === asset.path ? anyprev.children[anyprev.children.length - 1] : prev;
|
|
37
|
-
if (myprev) {
|
|
38
|
-
store.setFocus(myprev);
|
|
39
|
-
document.getElementById(hashid(myprev.id)).focus();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
else if (e.key === 'ArrowLeft') {
|
|
43
|
-
e.preventDefault();
|
|
44
|
-
e.stopPropagation();
|
|
45
|
-
if (parent) {
|
|
46
|
-
store.setFocus(parent);
|
|
47
|
-
document.getElementById(hashid(parent.id)).focus();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function onClick(e) {
|
|
52
|
-
e.preventDefault();
|
|
53
|
-
e.stopPropagation();
|
|
54
|
-
// if the id was already the same as the one that was clicked, the user
|
|
55
|
-
// has clicked it twice, so we should choose the item and end the modal
|
|
56
|
-
if ($store.preview?.id === asset.id)
|
|
57
|
-
dispatch('choose', asset);
|
|
58
|
-
else
|
|
59
|
-
store.preview(asset);
|
|
60
|
-
}
|
|
61
|
-
</script>
|
|
62
|
-
|
|
63
|
-
<li
|
|
64
|
-
{id}
|
|
65
|
-
role="treeitem"
|
|
66
|
-
tabindex={haveFocus ? 0 : -1}
|
|
67
|
-
aria-setsize={setsize}
|
|
68
|
-
aria-posinset={posinset}
|
|
69
|
-
aria-level={level}
|
|
70
|
-
aria-selected={isPreview}
|
|
71
|
-
class="dialog-asset-file"
|
|
72
|
-
class:isPreview
|
|
73
|
-
on:keydown={onKeyDown}
|
|
74
|
-
on:click={onClick}
|
|
75
|
-
>
|
|
76
|
-
<FileIcon mime={asset.mime} inline /> {asset.name}
|
|
77
|
-
</li>
|
|
78
|
-
|
|
79
|
-
<style>
|
|
80
|
-
li {
|
|
81
|
-
cursor: pointer;
|
|
82
|
-
}
|
|
83
|
-
</style>
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { SvelteComponentTyped } from "svelte";
|
|
2
|
-
import type { UIAsset, UIFolder, AnyUIItem } from './ChooserStore';
|
|
3
|
-
declare const __propDef: {
|
|
4
|
-
props: {
|
|
5
|
-
asset: UIAsset;
|
|
6
|
-
level: number;
|
|
7
|
-
posinset: number;
|
|
8
|
-
setsize: number;
|
|
9
|
-
next: AnyUIItem | undefined;
|
|
10
|
-
prev: AnyUIItem | undefined;
|
|
11
|
-
parent?: UIFolder | undefined;
|
|
12
|
-
};
|
|
13
|
-
events: {
|
|
14
|
-
choose: CustomEvent<any>;
|
|
15
|
-
} & {
|
|
16
|
-
[evt: string]: CustomEvent<any>;
|
|
17
|
-
};
|
|
18
|
-
slots: {};
|
|
19
|
-
};
|
|
20
|
-
export declare type AssetProps = typeof __propDef.props;
|
|
21
|
-
export declare type AssetEvents = typeof __propDef.events;
|
|
22
|
-
export declare type AssetSlots = typeof __propDef.slots;
|
|
23
|
-
export default class Asset extends SvelteComponentTyped<AssetProps, AssetEvents, AssetSlots> {
|
|
24
|
-
}
|
|
25
|
-
export {};
|