@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.
Files changed (71) hide show
  1. package/Button.svelte.d.ts +3 -3
  2. package/ButtonGroup.svelte.d.ts +3 -3
  3. package/Checkbox.svelte.d.ts +3 -3
  4. package/Container.svelte.d.ts +3 -3
  5. package/Dialog.svelte +22 -4
  6. package/Dialog.svelte.d.ts +5 -4
  7. package/FieldAutocomplete.svelte.d.ts +3 -3
  8. package/FieldCheckbox.svelte.d.ts +3 -3
  9. package/FieldChoices.svelte.d.ts +3 -3
  10. package/FieldChooserLink.svelte +14 -12
  11. package/FieldChooserLink.svelte.d.ts +3 -5
  12. package/FieldDate.svelte.d.ts +3 -3
  13. package/FieldDateTime.svelte.d.ts +3 -3
  14. package/FieldDualListbox.svelte.d.ts +3 -3
  15. package/FieldHidden.svelte.d.ts +3 -3
  16. package/FieldIdentifier.svelte.d.ts +3 -3
  17. package/FieldMultiple.svelte.d.ts +3 -3
  18. package/FieldMultiselect.svelte.d.ts +3 -3
  19. package/FieldNumber.svelte.d.ts +3 -3
  20. package/FieldRadio.svelte.d.ts +3 -3
  21. package/FieldSelect.svelte.d.ts +3 -3
  22. package/FieldStandard.svelte.d.ts +3 -3
  23. package/FieldText.svelte.d.ts +3 -3
  24. package/FieldTextArea.svelte.d.ts +3 -3
  25. package/FileIcon.svelte.d.ts +3 -3
  26. package/Form.svelte.d.ts +3 -3
  27. package/FormDialog.svelte.d.ts +3 -3
  28. package/Icon.svelte.d.ts +3 -3
  29. package/InlineMessage.svelte.d.ts +3 -3
  30. package/InlineMessages.svelte.d.ts +3 -3
  31. package/Input.svelte.d.ts +3 -3
  32. package/Listbox.svelte.d.ts +3 -3
  33. package/Radio.svelte.d.ts +3 -3
  34. package/Tab.svelte.d.ts +3 -3
  35. package/TabStore.d.ts +3 -0
  36. package/TabStore.js +12 -0
  37. package/Tabs.svelte +5 -4
  38. package/Tabs.svelte.d.ts +3 -3
  39. package/chooser/Chooser.svelte +76 -99
  40. package/chooser/Chooser.svelte.d.ts +5 -5
  41. package/chooser/ChooserAPI.d.ts +10 -3
  42. package/chooser/ChooserStore.d.ts +15 -33
  43. package/chooser/ChooserStore.js +32 -149
  44. package/chooser/Details.svelte.d.ts +6 -5
  45. package/chooser/Thumbnail.svelte +9 -2
  46. package/chooser/Thumbnail.svelte.d.ts +6 -5
  47. package/colorpicker/FieldColorPicker.svelte +78 -24
  48. package/colorpicker/FieldColorPicker.svelte.d.ts +5 -6
  49. package/iconpicker/FieldIconPicker.svelte +4 -2
  50. package/iconpicker/FieldIconPicker.svelte.d.ts +4 -3
  51. package/index.d.ts +3 -0
  52. package/index.js +3 -0
  53. package/package.json +9 -6
  54. package/tree/LoadIcon.svelte +24 -0
  55. package/tree/LoadIcon.svelte.d.ts +23 -0
  56. package/tree/Tree.svelte +203 -0
  57. package/tree/Tree.svelte.d.ts +28 -0
  58. package/tree/TreeCell.svelte +18 -0
  59. package/tree/TreeCell.svelte.d.ts +18 -0
  60. package/tree/TreeNode.svelte +418 -0
  61. package/tree/TreeNode.svelte.d.ts +30 -0
  62. package/tree/index.d.ts +3 -0
  63. package/tree/index.js +3 -0
  64. package/tree/treestore.d.ts +117 -0
  65. package/tree/treestore.js +336 -0
  66. package/chooser/Asset.svelte +0 -83
  67. package/chooser/Asset.svelte.d.ts +0 -25
  68. package/chooser/AssetFolder.svelte +0 -127
  69. package/chooser/AssetFolder.svelte.d.ts +0 -25
  70. package/chooser/Page.svelte +0 -121
  71. 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 {};
@@ -0,0 +1,3 @@
1
+ export * from './treestore.js';
2
+ export { default as Tree } from './Tree.svelte';
3
+ export { default as LoadIcon } from './LoadIcon.svelte';
package/tree/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './treestore.js';
2
+ export { default as Tree } from './Tree.svelte';
3
+ export { default as LoadIcon } from './LoadIcon.svelte';
@@ -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
+ }
@@ -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 {};