@dosgato/dialog 0.0.19 → 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 (95) hide show
  1. package/Button.svelte +77 -0
  2. package/Button.svelte.d.ts +30 -0
  3. package/ButtonGroup.svelte.d.ts +3 -3
  4. package/Checkbox.svelte +2 -1
  5. package/Checkbox.svelte.d.ts +4 -3
  6. package/Container.svelte +18 -19
  7. package/Container.svelte.d.ts +5 -3
  8. package/Dialog.svelte +155 -0
  9. package/Dialog.svelte.d.ts +50 -0
  10. package/FieldAutocomplete.svelte +4 -7
  11. package/FieldAutocomplete.svelte.d.ts +4 -4
  12. package/FieldCheckbox.svelte +3 -2
  13. package/FieldCheckbox.svelte.d.ts +5 -4
  14. package/FieldChoices.svelte +3 -2
  15. package/FieldChoices.svelte.d.ts +4 -3
  16. package/FieldChooserLink.svelte +17 -13
  17. package/FieldChooserLink.svelte.d.ts +4 -5
  18. package/FieldDate.svelte +3 -2
  19. package/FieldDate.svelte.d.ts +4 -3
  20. package/FieldDateTime.svelte +3 -2
  21. package/FieldDateTime.svelte.d.ts +4 -3
  22. package/FieldDualListbox.svelte.d.ts +3 -3
  23. package/FieldHidden.svelte.d.ts +3 -3
  24. package/FieldIdentifier.svelte.d.ts +3 -3
  25. package/FieldMultiple.svelte +14 -7
  26. package/FieldMultiple.svelte.d.ts +6 -3
  27. package/FieldMultiselect.svelte +29 -22
  28. package/FieldMultiselect.svelte.d.ts +3 -3
  29. package/FieldNumber.svelte +3 -2
  30. package/FieldNumber.svelte.d.ts +4 -3
  31. package/FieldRadio.svelte +9 -4
  32. package/FieldRadio.svelte.d.ts +9 -3
  33. package/FieldSelect.svelte +9 -3
  34. package/FieldSelect.svelte.d.ts +9 -3
  35. package/FieldStandard.svelte +8 -3
  36. package/FieldStandard.svelte.d.ts +9 -3
  37. package/FieldText.svelte +3 -2
  38. package/FieldText.svelte.d.ts +4 -3
  39. package/FieldTextArea.svelte +5 -3
  40. package/FieldTextArea.svelte.d.ts +4 -3
  41. package/FileIcon.svelte.d.ts +3 -3
  42. package/Form.svelte +3 -3
  43. package/Form.svelte.d.ts +3 -3
  44. package/FormDialog.svelte +34 -0
  45. package/FormDialog.svelte.d.ts +38 -0
  46. package/Icon.svelte.d.ts +3 -3
  47. package/InlineMessage.svelte.d.ts +3 -3
  48. package/InlineMessages.svelte.d.ts +3 -3
  49. package/Input.svelte +4 -1
  50. package/Input.svelte.d.ts +4 -3
  51. package/Listbox.svelte.d.ts +3 -3
  52. package/Radio.svelte +5 -2
  53. package/Radio.svelte.d.ts +4 -3
  54. package/Tab.svelte +3 -2
  55. package/Tab.svelte.d.ts +3 -3
  56. package/TabStore.d.ts +11 -1
  57. package/TabStore.js +30 -3
  58. package/Tabs.svelte +66 -18
  59. package/Tabs.svelte.d.ts +5 -7
  60. package/chooser/Chooser.svelte +76 -99
  61. package/chooser/Chooser.svelte.d.ts +5 -5
  62. package/chooser/ChooserAPI.d.ts +10 -3
  63. package/chooser/ChooserStore.d.ts +15 -33
  64. package/chooser/ChooserStore.js +32 -149
  65. package/chooser/Details.svelte.d.ts +6 -5
  66. package/chooser/Thumbnail.svelte +9 -2
  67. package/chooser/Thumbnail.svelte.d.ts +6 -5
  68. package/colorpicker/FieldColorPicker.svelte +78 -24
  69. package/colorpicker/FieldColorPicker.svelte.d.ts +5 -6
  70. package/fileIcons.d.ts +2 -1
  71. package/helpers.d.ts +1 -0
  72. package/helpers.js +5 -0
  73. package/iconpicker/FieldIconPicker.svelte +4 -2
  74. package/iconpicker/FieldIconPicker.svelte.d.ts +4 -3
  75. package/index.d.ts +7 -0
  76. package/index.js +7 -0
  77. package/package.json +20 -13
  78. package/tree/LoadIcon.svelte +24 -0
  79. package/tree/LoadIcon.svelte.d.ts +23 -0
  80. package/tree/Tree.svelte +203 -0
  81. package/tree/Tree.svelte.d.ts +28 -0
  82. package/tree/TreeCell.svelte +18 -0
  83. package/tree/TreeCell.svelte.d.ts +18 -0
  84. package/tree/TreeNode.svelte +418 -0
  85. package/tree/TreeNode.svelte.d.ts +30 -0
  86. package/tree/index.d.ts +3 -0
  87. package/tree/index.js +3 -0
  88. package/tree/treestore.d.ts +117 -0
  89. package/tree/treestore.js +336 -0
  90. package/chooser/Asset.svelte +0 -83
  91. package/chooser/Asset.svelte.d.ts +0 -25
  92. package/chooser/AssetFolder.svelte +0 -127
  93. package/chooser/AssetFolder.svelte.d.ts +0 -25
  94. package/chooser/Page.svelte +0 -121
  95. package/chooser/Page.svelte.d.ts +0 -25
@@ -1,17 +1,13 @@
1
- <script>import fileTree from '@iconify-icons/mdi/file-tree.js';
2
- import viewGrid from '@iconify-icons/mdi/view-grid.js';
3
- import { Loading, Modal } from '@txstate-mws/svelte-components';
1
+ <script>import applicationOutline from '@iconify-icons/mdi/application-outline';
2
+ import folderLight from '@iconify-icons/ph/folder-light';
3
+ import folderNotchOpenLight from '@iconify-icons/ph/folder-notch-open-light';
4
4
  import { derivedStore } from '@txstate-mws/svelte-store';
5
5
  import { createEventDispatcher, getContext, onMount, setContext } from 'svelte';
6
- import { hashid, randomid } from 'txstate-utils';
7
- import Asset from './Asset.svelte';
8
- import AssetFolder from './AssetFolder.svelte';
9
- import ButtonGroup from '../ButtonGroup.svelte';
6
+ import { isNotBlank } from 'txstate-utils';
7
+ import { Dialog, iconForMime, Tabs, Tree, TreeStore } from '..';
10
8
  import { CHOOSER_API_CONTEXT } from './ChooserAPI';
11
9
  import { CHOOSER_STORE_CONTEXT, ChooserStore } from './ChooserStore';
12
10
  import Details from './Details.svelte';
13
- import Icon from '../Icon.svelte';
14
- import Page from './Page.svelte';
15
11
  import Thumbnail from './Thumbnail.svelte';
16
12
  const chooserClient = getContext(CHOOSER_API_CONTEXT);
17
13
  export let label = undefined;
@@ -19,7 +15,7 @@ export let images = false;
19
15
  export let pages = false;
20
16
  export let assets = images;
21
17
  export let folders = false;
22
- export let initialType = undefined;
18
+ export let required = false;
23
19
  export let initialSource = undefined;
24
20
  export let initialPath = undefined;
25
21
  export let activeSources = undefined;
@@ -27,99 +23,103 @@ export let passthruFilters = undefined;
27
23
  export let filter = undefined;
28
24
  export let store = new ChooserStore(chooserClient);
29
25
  setContext(CHOOSER_STORE_CONTEXT, store);
30
- $: if (!pages && !assets)
31
- assets = true;
32
- $: activeTypes = [...(assets ? ['asset'] : []), ...(pages ? ['page'] : [])];
33
26
  const dispatch = createEventDispatcher();
34
- const sources = derivedStore(store, v => v.sources?.[v.activetype] ?? []);
35
- const source = derivedStore(store, v => store.getSource(v));
36
- const preview = derivedStore(store, 'preview');
37
- const chooserheadid = randomid();
38
- const listid = randomid();
27
+ let tabStore;
28
+ const { sources, source, preview } = store;
29
+ $: currentName = tabStore?.currentName();
30
+ async function fetchChildren(item) {
31
+ if (item?.type === 'asset' || !$source)
32
+ return [];
33
+ const children = await chooserClient.getChildren($source.name, item?.path ?? '/', filter);
34
+ return children.map(c => ({ ...c, children: undefined }));
35
+ }
36
+ const treeStore = new TreeStore(fetchChildren);
37
+ const selected = derivedStore(treeStore, 'selectedItems.0');
38
+ $: store.setSource($currentName);
39
+ $: selectPreview($preview, $source);
40
+ $: if (['asset', 'page'].includes($selected?.type))
41
+ store.setPreview($selected);
39
42
  function onChoose() {
40
43
  dispatch('change', $store.preview);
41
44
  }
45
+ function onDeselect() {
46
+ store.setPreview(undefined);
47
+ }
48
+ async function openRecursive(pathSplit, depth) {
49
+ console.log($treeStore.rootItems);
50
+ let curr = $treeStore.rootItems?.find(itm => itm.name === pathSplit[0]);
51
+ for (let i = 0; i < depth; i++) {
52
+ curr = curr?.children?.find(c => c.name === pathSplit[i + 1]);
53
+ }
54
+ if (!curr)
55
+ return;
56
+ await treeStore.open(curr, false);
57
+ if (depth + 1 >= pathSplit.length)
58
+ return curr;
59
+ return await openRecursive(pathSplit, depth + 1);
60
+ }
61
+ async function selectPreview(..._) {
62
+ if (!$store.initialized)
63
+ return;
64
+ await treeStore.refresh(undefined);
65
+ const preloadSource = $preview?.source ?? initialSource;
66
+ if ($source?.name !== preloadSource)
67
+ return;
68
+ const preloadPath = $store.preview?.path ?? initialPath;
69
+ initialSource = undefined;
70
+ initialPath = undefined;
71
+ if (preloadPath) {
72
+ const currentSelection = await openRecursive(preloadPath.split('/').filter(isNotBlank), 0);
73
+ treeStore.trigger();
74
+ if (!currentSelection)
75
+ return;
76
+ store.setPreview(currentSelection);
77
+ treeStore.select(currentSelection, {});
78
+ treeStore.trigger();
79
+ }
80
+ }
42
81
  onMount(async () => {
43
- await store.init({ activeTypes, activeSources, initialType, initialSource, initialPath, passthruFilters, filter, onlyImages: images, chooseFolder: folders });
44
- if ($store.focus)
45
- document.getElementById(hashid($store.focus))?.scrollIntoView();
82
+ await store.init({ images, pages, assets, folders, activeSources, initialSource, initialPath, passthruFilters, filter });
83
+ tabStore.activateName($source.name);
84
+ await selectPreview();
46
85
  });
47
86
  </script>
48
87
 
49
- <Modal on:escape>
88
+ <Dialog size="xl" ignoreTabs title={label} on:escape continueText="Choose" disabled={!$store.preview && required} cancelText="Cancel" on:continue={onChoose}>
50
89
  <section class="dialog-chooser-window">
51
- <header>
52
- <div class="dialog-chooser-controls">
53
- {#if activeTypes.length > 1}
54
- <ButtonGroup value={$store.activetype} choices={[{ value: 'asset', label: 'Assets' }, { value: 'page', label: 'Pages' }]} ariaControls={listid} on:change={e => store.setActiveType(e.detail)} />
55
- {/if}
56
- {#if $sources.length > 1}
57
- <div class="dialog-chooser-source">
58
- <select on:change={function () { store.changeSource(Number(this.value)) }}>
59
- {#each $sources as source, i}
60
- <option value={i}>{source.label || source.name}</option>
61
- {/each}
62
- </select>
63
- </div>
64
- {/if}
65
- </div>
66
- <div id={chooserheadid} class="dialog-chooser-label">
67
- {label}
68
- </div>
69
- {#if $source?.type === 'asset'}
70
- <div class="dialog-chooser-view">
71
- <button type="button"><Icon icon={fileTree} /></button>
72
- <button type="button"><Icon icon={viewGrid} /></button>
73
- </div>
90
+ <header class="dialog-chooser-controls">
91
+ {#if $sources.length > 1}
92
+ <Tabs bind:store={tabStore} tabs={$sources.map(s => ({ id: s.name, title: s.label ?? s.name }))} />
74
93
  {/if}
75
94
  </header>
76
95
  <section class="dialog-chooser-chooser">
77
- <Loading loading={!$source || !$source.children}>
78
- <ul id={listid} class="dialog-chooser-list" role="tree" aria-labelledby={chooserheadid}>
79
- {#each $source.children as child, i (child.id)}
80
- {@const setsize = $source.children.length}
81
- {@const posinset = i + 1}
82
- {@const prev = $source.children[i - 1]}
83
- {@const next = $source.children[i + 1]}
84
- {#if child.type === 'folder'}
85
- <AssetFolder folder={child} {setsize} {posinset} level={1} {prev} {next} on:choose={onChoose} />
86
- {:else if child.type === 'page'}
87
- <Page page={child} {setsize} {posinset} level={1} {prev} {next} on:choose={onChoose} />
88
- {:else}
89
- <Asset asset={child} {setsize} {posinset} level={1} {prev} {next} on:choose={onChoose} />
90
- {/if}
91
- {/each}
92
- </ul>
93
- </Loading>
96
+ {#if $store.initialized}
97
+ <Tree headers={[
98
+ { label: 'Path', id: 'name', grow: 4, icon: item => item.type === 'asset' ? iconForMime(item.mime) : (item.type === 'folder' ? (item.open ? folderNotchOpenLight : folderLight) : applicationOutline), get: 'name' }
99
+ ]} singleSelect store={treeStore} on:deselect={onDeselect} on:choose={onChoose} />
100
+ {/if}
94
101
  </section>
95
102
  <section class="dialog-chooser-preview" tabindex="-1">
96
103
  {#if $preview}
97
104
  <Thumbnail item={$preview} />
98
105
  <Details item={$preview}>
99
106
  {#if $preview.type === 'folder'}
100
- <li>{$preview.children?.length || 0} sub-items</li>
107
+ <li>{$selected.children?.length || 0} sub-items</li>
101
108
  {/if}
102
109
  </Details>
103
110
  {/if}
104
111
  </section>
105
- <footer>
106
- <button type="button" on:click={() => dispatch('escape')}>Cancel</button>
107
- <button type="button" disabled={!$store.preview} on:click={onChoose}>Choose</button>
108
- </footer>
109
112
  </section>
110
- </Modal>
113
+ </Dialog>
111
114
 
112
115
  <style>
113
116
  .dialog-chooser-window {
114
117
  position: relative;
115
- width: 80vw;
116
118
  height: 80vh;
117
- background-color: lightgray;
118
119
  display: flex;
119
120
  flex-wrap: wrap;
120
121
  align-items: stretch;
121
122
  justify-content: flex-end;
122
- padding: 1em;
123
123
  overflow: hidden;
124
124
  }
125
125
  .dialog-chooser-window * {
@@ -127,45 +127,22 @@ onMount(async () => {
127
127
  }
128
128
  .dialog-chooser-chooser {
129
129
  position: relative;
130
- width: 70%;
130
+ width: 75%;
131
+ min-width: calc(100% - 21em);
131
132
  height: calc(100% - 4em);
132
133
  background-color: white;
133
134
  padding: 0.5em;
134
135
  overflow: auto;
135
136
  }
136
137
  .dialog-chooser-preview {
137
- width: 30%;
138
+ width: 25%;
139
+ max-width: 21em;
138
140
  height: calc(100% - 4em);
139
141
  padding: 1em;
140
142
  overflow-y: auto;
141
143
  }
142
144
  header {
145
+ position: relative;
143
146
  width: 100%;
144
- height: 2em;
145
- text-align: center;
146
- font-weight: bold;
147
- display: flex;
148
- align-items: center;
149
147
  }
150
- .dialog-chooser-label {
151
- flex-grow: 1;
152
- }
153
- .dialog-chooser-controls {
154
- display: flex;
155
- }
156
- .dialog-chooser-list {
157
- list-style: none;
158
- padding: 0;
159
- margin: 0;
160
- }
161
- .dialog-chooser-list :global(li) {
162
- line-height: 1;
163
- padding: 0.25em 0;
164
- border-bottom: 1px solid var(--asset-chooser-border, #AAAAAA);
165
- }
166
- .dialog-chooser-list :global(.isPreview) {
167
- background-color: var(--asset-chooser-active-bg, #333333);
168
- color: var(--asset-chooser-active, #FFFFFF);
169
- }
170
-
171
148
  </style>
@@ -1,5 +1,5 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
- import { type AnyItem, type ChooserType } from './ChooserAPI';
2
+ import { type AnyItem } from './ChooserAPI';
3
3
  import { ChooserStore } from './ChooserStore';
4
4
  declare class __sveltets_Render<F> {
5
5
  props(): {
@@ -8,7 +8,7 @@ declare class __sveltets_Render<F> {
8
8
  pages?: boolean;
9
9
  assets?: boolean;
10
10
  folders?: boolean;
11
- initialType?: ChooserType;
11
+ required?: boolean;
12
12
  initialSource?: string;
13
13
  initialPath?: string;
14
14
  activeSources?: string[];
@@ -24,9 +24,9 @@ declare class __sveltets_Render<F> {
24
24
  };
25
25
  slots(): {};
26
26
  }
27
- export declare type ChooserProps<F> = ReturnType<__sveltets_Render<F>['props']>;
28
- export declare type ChooserEvents<F> = ReturnType<__sveltets_Render<F>['events']>;
29
- export declare type ChooserSlots<F> = ReturnType<__sveltets_Render<F>['slots']>;
27
+ export type ChooserProps<F> = ReturnType<__sveltets_Render<F>['props']>;
28
+ export type ChooserEvents<F> = ReturnType<__sveltets_Render<F>['events']>;
29
+ export type ChooserSlots<F> = ReturnType<__sveltets_Render<F>['slots']>;
30
30
  export default class Chooser<F> extends SvelteComponentTyped<ChooserProps<F>, ChooserEvents<F>, ChooserSlots<F>> {
31
31
  }
32
32
  export {};
@@ -1,6 +1,6 @@
1
1
  export declare const CHOOSER_API_CONTEXT: {};
2
- export declare type ChooserType = 'asset' | 'page';
3
- export declare type AnyItem = Asset | Folder | Page;
2
+ export type ChooserType = 'asset' | 'page';
3
+ export type AnyItem = Asset | Folder | Page;
4
4
  export interface Client<F = any> {
5
5
  getSources: (type: ChooserType) => Promise<Source[]>;
6
6
  getChildren: (source: string, path: string, filters: F) => Promise<AnyItem[]>;
@@ -24,20 +24,27 @@ interface Item {
24
24
  * PageLink (see dosgato-templating/src/links.ts)
25
25
  */
26
26
  id: string;
27
+ /**
28
+ * path to the item, MUST include the item itself, so ends with /${name}
29
+ */
27
30
  path: string;
28
31
  name: string;
32
+ source: string;
29
33
  }
30
34
  export interface Folder extends Item {
31
35
  type: 'folder';
36
+ hasChildren: boolean;
32
37
  acceptsUpload: boolean;
33
38
  }
34
39
  export interface Page extends Item {
35
40
  type: 'page';
41
+ title?: string;
42
+ hasChildren: boolean;
36
43
  url: string;
37
- title: string;
38
44
  }
39
45
  export interface Asset extends Item {
40
46
  type: 'asset';
47
+ title?: string;
41
48
  mime: string;
42
49
  bytes: number;
43
50
  url: string;
@@ -1,26 +1,15 @@
1
- import { SafeStore } from '@txstate-mws/svelte-store';
1
+ import type { TypedTreeItem } from '../tree/treestore.js';
2
+ import { Store } from '@txstate-mws/svelte-store';
2
3
  import type { AnyItem, Asset, Client, ChooserType, Folder, Page, Source } from './ChooserAPI.js';
3
4
  export interface UISource extends Source {
4
5
  children?: AnyUIItem[];
5
6
  }
6
- export interface UIFolder extends Folder {
7
- children?: (UIFolder | UIAsset)[];
8
- open?: boolean;
9
- loading?: boolean;
10
- }
11
- export interface UIPage extends Page {
12
- children?: UIPage[];
13
- open?: boolean;
14
- loading?: boolean;
15
- }
16
- export interface UIAsset extends Asset {
17
- }
18
7
  export interface RawURL {
19
8
  type: 'raw';
20
9
  id: string;
21
10
  url: string;
22
11
  }
23
- export declare type AnyUIItem = UIPage | UIFolder | UIAsset;
12
+ export type AnyUIItem = TypedTreeItem<Page | Asset | Folder>;
24
13
  export interface IAssetStore {
25
14
  sources?: {
26
15
  page: UISource[];
@@ -28,20 +17,19 @@ export interface IAssetStore {
28
17
  };
29
18
  activetype: ChooserType;
30
19
  activesource: number;
31
- preview?: AnyUIItem;
32
- focus?: string;
33
- focusPath?: string;
20
+ initialized: boolean;
21
+ preview?: AnyItem;
34
22
  }
35
23
  export interface ChooserStoreOptions<F> {
24
+ pages?: boolean;
25
+ assets?: boolean;
26
+ images?: boolean;
27
+ folders?: boolean;
36
28
  filter?: (itm: AnyItem) => boolean | Promise<boolean>;
37
29
  passthruFilters?: F;
38
- activeTypes?: ChooserType[];
39
30
  activeSources?: string[];
40
- initialType?: ChooserType;
41
31
  initialSource?: string;
42
32
  initialPath?: string;
43
- chooseFolder?: boolean;
44
- onlyImages?: boolean;
45
33
  }
46
34
  interface InternalStoreOptions<F> extends Omit<ChooserStoreOptions<F>, 'activeSources'> {
47
35
  activeSources?: Set<string>;
@@ -49,25 +37,19 @@ interface InternalStoreOptions<F> extends Omit<ChooserStoreOptions<F>, 'activeSo
49
37
  export declare const CHOOSER_STORE_CONTEXT: {};
50
38
  export declare function combinePath(path: string, name: string): string;
51
39
  export declare function bytesToHuman(bytes: number): string;
52
- export declare class ChooserStore<F = any> extends SafeStore<IAssetStore> {
40
+ export declare class ChooserStore<F = any> extends Store<IAssetStore> {
53
41
  client: Client;
54
42
  options: InternalStoreOptions<F>;
55
43
  constructor(client: Client);
56
44
  setOptions(options: ChooserStoreOptions<F>): void;
45
+ sources: import("@txstate-mws/svelte-store").DerivedStore<UISource[], IAssetStore>;
46
+ source: import("@txstate-mws/svelte-store").DerivedStore<UISource, IAssetStore>;
47
+ preview: import("@txstate-mws/svelte-store").DerivedStore<AnyItem, IAssetStore>;
57
48
  getSource(state?: IAssetStore): UISource;
58
49
  getSourceIndex(name: string, state?: IAssetStore, type?: ChooserType): number;
59
50
  init(options: ChooserStoreOptions<F>): Promise<void>;
60
- itemByPath(state: IAssetStore, path: string): AnyUIItem;
61
- open(folder: UIFolder | UIPage): Promise<void>;
62
- openPath(path: string): Promise<void>;
63
- openPathRecursive(path: string): Promise<void>;
64
- close(folder: UIFolder | UIPage): Promise<void>;
65
- closePath(path: string): Promise<void>;
66
- toggle(folder: UIFolder | UIPage): Promise<void>;
67
- preview(item?: AnyUIItem): void;
51
+ setPreview(item?: AnyItem): void;
68
52
  clearPreview(): void;
69
- changeSource(idx: number): Promise<void>;
70
- setActiveType(type: ChooserType): Promise<void>;
71
- setFocus(itm: AnyUIItem): void;
53
+ setSource(name: string, init?: boolean): void;
72
54
  }
73
55
  export {};
@@ -1,5 +1,6 @@
1
- import { SafeStore } from '@txstate-mws/svelte-store';
2
- import { filterAsync, findIndex, isNotBlank } from 'txstate-utils';
1
+ import { Store, derivedStore } from '@txstate-mws/svelte-store';
2
+ import { tick } from 'svelte';
3
+ import { findIndex } from 'txstate-utils';
3
4
  export const CHOOSER_STORE_CONTEXT = {};
4
5
  const nofilter = (x) => true;
5
6
  export function combinePath(path, name) {
@@ -12,28 +13,28 @@ export function bytesToHuman(bytes) {
12
13
  const scale = Math.floor(Math.log(bytes) / Math.log(1024));
13
14
  return String(parseFloat((bytes / Math.pow(1024, scale)).toPrecision(3))) + scales[scale];
14
15
  }
15
- export class ChooserStore extends SafeStore {
16
+ export class ChooserStore extends Store {
16
17
  client;
17
18
  options;
18
19
  constructor(client) {
19
- super({ activetype: 'page', activesource: 0 });
20
+ super({ activetype: 'page', activesource: 0, initialized: false });
20
21
  this.client = client;
21
22
  this.setOptions({});
22
23
  }
23
24
  setOptions(options) {
24
- const activeTypes = options.activeTypes?.length ? options.activeTypes : ['asset', 'page'];
25
25
  const userFilter = options.filter ?? nofilter;
26
- const filter = options.onlyImages
26
+ const filter = options.images
27
27
  ? (itm) => ((itm.type === 'asset' && !!itm.image) || itm.type === 'folder') && userFilter(itm)
28
28
  : userFilter;
29
29
  this.options = {
30
30
  ...options,
31
- activeTypes,
32
31
  activeSources: options.activeSources ? new Set(options.activeSources) : undefined,
33
- initialType: options.initialType ?? activeTypes[0],
34
32
  filter
35
33
  };
36
34
  }
35
+ sources = derivedStore(this, v => [...(v.sources?.page ?? []), ...(v.sources?.asset ?? [])].filter(s => this.options.activeSources ? this.options.activeSources.has(s.name) : true));
36
+ source = derivedStore(this, v => this.getSource(v));
37
+ preview = derivedStore(this, 'preview');
37
38
  getSource(state = this.value) {
38
39
  return state.sources?.[state.activetype]?.[state.activesource];
39
40
  }
@@ -44,158 +45,40 @@ export class ChooserStore extends SafeStore {
44
45
  }
45
46
  async init(options) {
46
47
  this.setOptions(options);
47
- const activetype = this.value.preview ? (this.value.preview.type === 'page' ? 'page' : 'asset') : this.options.initialType;
48
- this.update(v => ({ ...v, loading: true, activetype, activesource: this.getSourceIndex(this.options.initialSource, v, this.options.initialType) }));
49
- if (!this.getSource()) {
50
- const [pageSources, assetSources] = await Promise.all([
51
- this.options.activeTypes.includes('page') ? this.client.getSources('page') : [],
52
- this.options.activeTypes.includes('asset') ? this.client.getSources('asset') : []
53
- ]);
54
- this.update(v => {
55
- v.sources = { page: pageSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s)) ?? [], asset: assetSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s)) ?? [] };
56
- v.activesource = this.getSourceIndex(this.options.initialSource, v);
57
- return v;
58
- });
59
- }
60
- if (this.value.preview)
61
- await this.openPathRecursive(this.value.preview.path);
62
- else if (this.options.initialPath)
63
- await this.openPathRecursive(this.options.initialPath);
64
- else
65
- await this.openPathRecursive('/');
66
- this.update(v => ({ ...v, loading: false }));
67
- }
68
- itemByPath(state, path) {
69
- const parts = path.substring(1).split('/');
70
- const source = this.getSource(state);
71
- let item = source.children?.find(c => c.name === parts[0]);
72
- for (const part of parts.slice(1).filter(isNotBlank)) {
73
- if (item.type === 'asset')
74
- return undefined;
75
- item = item?.children?.find(c => c.name === part);
76
- }
77
- return item;
78
- }
79
- async open(folder) {
80
- return await this.openPath(folder.path);
81
- }
82
- async openPath(path) {
83
- const folder = this.itemByPath(this.value, path);
84
- if (!folder || folder.type === 'asset' || folder.open)
85
- return;
86
- this.update(v => {
87
- const folder = this.itemByPath(v, path);
88
- folder.loading = true;
89
- v.focus = folder.id;
90
- return v;
91
- });
92
- try {
93
- const children = await filterAsync(await this.client.getChildren(this.getSource().name, path, this.options.passthruFilters), this.options.filter);
94
- this.update(v => {
95
- const folder = this.itemByPath(v, path);
96
- folder.open = true;
97
- folder.loading = false;
98
- folder.children = children;
99
- return v;
100
- });
101
- }
102
- catch (e) {
103
- console.error(e);
104
- this.update(v => {
105
- const folder = this.itemByPath(v, path);
106
- folder.loading = false;
107
- return v;
108
- });
109
- }
110
- }
111
- async openPathRecursive(path) {
112
- const parts = path.substring(1).split('/');
113
- const source = this.getSource(this.clone(this.value));
114
- if (!source.children)
115
- source.children = await filterAsync(await this.client.getChildren(source.name, '/', this.options.passthruFilters), this.options.filter);
116
- let current = source.children.find(c => c.name === parts[0]) ?? source.children[0];
117
- for (const part of parts.slice(1).filter(isNotBlank)) {
118
- if (!current || current.type === 'asset')
119
- break;
120
- if (!current.open) {
121
- current.children = await filterAsync(await this.client.getChildren(source.name, current.path, this.options.passthruFilters), this.options.filter);
122
- current.loading = false;
123
- current.open = true;
124
- }
125
- current = current.children.find(c => c.name === part);
126
- }
48
+ const [pageSources, assetSources] = await Promise.all([
49
+ this.options.pages ? this.client.getSources('page') : [],
50
+ this.options.assets ? this.client.getSources('asset') : []
51
+ ]);
127
52
  this.update(v => {
128
- const currSource = this.getSource(v);
129
- if (currSource.name !== source.name)
130
- return v;
131
- v.sources[v.activetype][v.activesource] = source;
132
- if (!current)
133
- return v;
134
- v.focus = current.id;
135
- v.focusPath = current.path;
136
- return v;
53
+ const sources = { page: pageSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s)) ?? [], asset: assetSources.filter(s => !this.options.activeSources || this.options.activeSources.has(s)) ?? [] };
54
+ return { ...v, sources };
137
55
  });
56
+ this.setSource(this.value.preview?.source ?? this.options.initialSource, true);
57
+ console.log('before initialized', this.value);
58
+ await tick();
59
+ console.log('just before initialized');
60
+ this.update(v => ({ ...v, initialized: true }));
138
61
  }
139
- async close(folder) {
140
- return await this.closePath(folder.path);
141
- }
142
- async closePath(path) {
143
- this.update(v => {
144
- const folder = this.itemByPath(v, path);
145
- if (folder && folder.type !== 'asset')
146
- folder.open = false;
147
- return v;
148
- });
149
- }
150
- async toggle(folder) {
151
- if (folder.open)
152
- await this.close(folder);
153
- else
154
- await this.open(folder);
155
- }
156
- preview(item) {
62
+ setPreview(item) {
157
63
  if (!item)
158
64
  return this.clearPreview();
159
- if (item.type === 'folder' && !this.options.chooseFolder)
65
+ if (item.type === 'folder' && !this.options.folders)
160
66
  return;
161
- this.update(v => ({ ...v, preview: item, focus: item.id, focusPath: item.path }));
67
+ this.update(v => ({ ...v, preview: item }));
162
68
  }
163
69
  clearPreview() {
164
70
  this.update(v => ({ ...v, preview: undefined }));
165
71
  }
166
- async changeSource(idx) {
167
- if (idx >= this.value.sources[this.value.activetype].length || idx < 0)
168
- return;
169
- this.update(v => {
170
- v.activesource = idx;
171
- const source = this.getSource(v);
172
- if (source.children?.length) {
173
- const firstchild = source.children[0];
174
- v.focus = firstchild.id;
175
- v.focusPath = firstchild.path;
176
- }
177
- return v;
178
- });
179
- const source = this.getSource();
180
- const children = await filterAsync(await this.client.getChildren(source.name, '/', this.options.passthruFilters), this.options.filter);
72
+ setSource(name, init) {
181
73
  this.update(v => {
182
- const source = this.getSource(v);
183
- source.children = children;
184
- v.focus = children[0]?.id;
185
- v.focusPath = children[0] ? children[0]?.path : undefined;
186
- return v;
187
- });
188
- }
189
- async setActiveType(type) {
190
- this.update(v => ({ ...v, activetype: type }));
191
- await this.changeSource(0);
192
- }
193
- setFocus(itm) {
194
- if (!itm)
195
- return;
196
- this.update(v => {
197
- v.focus = itm.id;
198
- v.focusPath = itm.path;
74
+ if (!v.initialized && !init)
75
+ return v;
76
+ const pageSource = v.sources?.page.findIndex(s => s.name === name);
77
+ const assetSource = v.sources?.asset.findIndex(s => s.name === name);
78
+ if (pageSource >= 0)
79
+ return { ...v, activetype: 'page', activesource: pageSource };
80
+ else if (assetSource >= 0)
81
+ return { ...v, activetype: 'asset', activesource: assetSource };
199
82
  return v;
200
83
  });
201
84
  }
@@ -1,8 +1,9 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
- import { type AnyUIItem, type RawURL } from './ChooserStore';
2
+ import type { AnyItem } from './ChooserAPI';
3
+ import { type RawURL } from './ChooserStore';
3
4
  declare const __propDef: {
4
5
  props: {
5
- item: AnyUIItem | RawURL;
6
+ item: AnyItem | RawURL;
6
7
  };
7
8
  events: {
8
9
  [evt: string]: CustomEvent<any>;
@@ -11,9 +12,9 @@ declare const __propDef: {
11
12
  default: {};
12
13
  };
13
14
  };
14
- export declare type DetailsProps = typeof __propDef.props;
15
- export declare type DetailsEvents = typeof __propDef.events;
16
- export declare type DetailsSlots = typeof __propDef.slots;
15
+ export type DetailsProps = typeof __propDef.props;
16
+ export type DetailsEvents = typeof __propDef.events;
17
+ export type DetailsSlots = typeof __propDef.slots;
17
18
  export default class Details extends SvelteComponentTyped<DetailsProps, DetailsEvents, DetailsSlots> {
18
19
  }
19
20
  export {};