@hyvor/design 2.1.12 → 2.1.14
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/components/FileUploader/Excalidraw/Excalidraw.svelte +78 -0
- package/dist/components/FileUploader/Excalidraw/Excalidraw.svelte.d.ts +18 -0
- package/dist/components/FileUploader/Excalidraw/ExcalidrawComponent.svelte +70 -0
- package/dist/components/FileUploader/Excalidraw/ExcalidrawComponent.svelte.d.ts +7 -0
- package/dist/components/FileUploader/Excalidraw/ExcalidrawIcon.svelte +21 -0
- package/dist/components/FileUploader/Excalidraw/ExcalidrawIcon.svelte.d.ts +26 -0
- package/dist/components/FileUploader/Excalidraw/excalidraw-loader.d.ts +13 -0
- package/dist/components/FileUploader/Excalidraw/excalidraw-loader.js +36 -0
- package/dist/components/FileUploader/FileUploader.svelte +41 -27
- package/dist/components/FileUploader/Media/Media.svelte +118 -0
- package/dist/components/FileUploader/Media/Media.svelte.d.ts +3 -0
- package/dist/components/FileUploader/Preview/Preview.svelte +14 -3
- package/dist/components/FileUploader/Unsplash/Unsplash.svelte +156 -0
- package/dist/components/FileUploader/Unsplash/Unsplash.svelte.d.ts +3 -0
- package/dist/components/FileUploader/file-uploader.d.ts +20 -10
- package/dist/components/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconArrowRightCircle from '@hyvor/icons/IconArrowRightCircle';
|
|
3
|
+
import Button from '../../Button/Button.svelte';
|
|
4
|
+
import toast from '../../Toast/toast.js';
|
|
5
|
+
import ExcalidrawComponent from './ExcalidrawComponent.svelte';
|
|
6
|
+
import type { LoadedExcalidraw } from './excalidraw-loader.js';
|
|
7
|
+
import { setSelectedFile } from '../file-uploader.js';
|
|
8
|
+
|
|
9
|
+
let loaded: LoadedExcalidraw | undefined;
|
|
10
|
+
let excalidrawAPI: any;
|
|
11
|
+
|
|
12
|
+
function handleReady(loadedLib: LoadedExcalidraw, api: any) {
|
|
13
|
+
loaded = loadedLib;
|
|
14
|
+
excalidrawAPI = api;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function handleFinish() {
|
|
18
|
+
if (!loaded || !excalidrawAPI) {
|
|
19
|
+
toast.error('Excalidraw is not ready yet');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const elements = excalidrawAPI.getSceneElements();
|
|
24
|
+
if (!elements || !elements.length) {
|
|
25
|
+
toast.error('Draw something first');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const svg = await loaded.ExcalidrawLib.exportToSvg({
|
|
30
|
+
elements,
|
|
31
|
+
appState: excalidrawAPI.getAppState(),
|
|
32
|
+
files: excalidrawAPI.getFiles()
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const data = new XMLSerializer().serializeToString(svg);
|
|
36
|
+
const blob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
|
|
37
|
+
|
|
38
|
+
setSelectedFile({
|
|
39
|
+
type: 'image',
|
|
40
|
+
from: 'excalidraw',
|
|
41
|
+
upload: {
|
|
42
|
+
type: 'excalidraw',
|
|
43
|
+
blob
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<div class="excalidraw-tab">
|
|
50
|
+
<div class="canvas">
|
|
51
|
+
<ExcalidrawComponent onReady={handleReady} />
|
|
52
|
+
</div>
|
|
53
|
+
<div class="footer">
|
|
54
|
+
<Button size="large" onclick={handleFinish}>
|
|
55
|
+
Finalize
|
|
56
|
+
{#snippet end()}
|
|
57
|
+
<IconArrowRightCircle />
|
|
58
|
+
{/snippet}
|
|
59
|
+
</Button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<style>
|
|
64
|
+
.excalidraw-tab {
|
|
65
|
+
height: 100%;
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
}
|
|
69
|
+
.canvas {
|
|
70
|
+
flex: 1;
|
|
71
|
+
min-height: 0;
|
|
72
|
+
}
|
|
73
|
+
.footer {
|
|
74
|
+
padding-top: 15px;
|
|
75
|
+
margin-bottom: 10px;
|
|
76
|
+
text-align: center;
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const Excalidraw: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type Excalidraw = InstanceType<typeof Excalidraw>;
|
|
18
|
+
export default Excalidraw;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onDestroy, onMount } from 'svelte';
|
|
3
|
+
import Loader from '../../Loader/Loader.svelte';
|
|
4
|
+
import { loadExcalidraw, type LoadedExcalidraw } from './excalidraw-loader.js';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
onReady: (loaded: LoadedExcalidraw, api: any) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { onReady }: Props = $props();
|
|
11
|
+
|
|
12
|
+
let mountEl: HTMLDivElement | undefined = $state();
|
|
13
|
+
let ready = $state(false);
|
|
14
|
+
let error = $state('');
|
|
15
|
+
|
|
16
|
+
let root: ReturnType<LoadedExcalidraw['createRoot']> | undefined;
|
|
17
|
+
|
|
18
|
+
onMount(async () => {
|
|
19
|
+
try {
|
|
20
|
+
const loaded = await loadExcalidraw();
|
|
21
|
+
if (!mountEl) return;
|
|
22
|
+
|
|
23
|
+
root = loaded.createRoot(mountEl);
|
|
24
|
+
root.render(
|
|
25
|
+
loaded.React.createElement(loaded.ExcalidrawLib.Excalidraw, {
|
|
26
|
+
excalidrawAPI: (api: any) => onReady(loaded, api)
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
ready = true;
|
|
30
|
+
} catch (e: any) {
|
|
31
|
+
error = e?.message || 'Failed to load Excalidraw';
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
onDestroy(() => {
|
|
36
|
+
root?.unmount();
|
|
37
|
+
});
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div class="excalidraw-wrap">
|
|
41
|
+
{#if !ready}
|
|
42
|
+
<div class="loading">
|
|
43
|
+
{#if error}
|
|
44
|
+
{error}
|
|
45
|
+
{:else}
|
|
46
|
+
<Loader full />
|
|
47
|
+
{/if}
|
|
48
|
+
</div>
|
|
49
|
+
{/if}
|
|
50
|
+
<div class="mount" bind:this={mountEl}></div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<style>
|
|
54
|
+
.excalidraw-wrap {
|
|
55
|
+
position: relative;
|
|
56
|
+
height: 100%;
|
|
57
|
+
width: 100%;
|
|
58
|
+
}
|
|
59
|
+
.loading {
|
|
60
|
+
position: absolute;
|
|
61
|
+
inset: 0;
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
}
|
|
66
|
+
.mount {
|
|
67
|
+
height: 100%;
|
|
68
|
+
width: 100%;
|
|
69
|
+
}
|
|
70
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type LoadedExcalidraw } from './excalidraw-loader.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
onReady: (loaded: LoadedExcalidraw, api: any) => void;
|
|
4
|
+
}
|
|
5
|
+
declare const ExcalidrawComponent: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type ExcalidrawComponent = ReturnType<typeof ExcalidrawComponent>;
|
|
7
|
+
export default ExcalidrawComponent;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
|
2
|
+
<rect width="1000" height="1000" rx="200" ry="200" fill="#fff" />
|
|
3
|
+
<svg
|
|
4
|
+
viewBox="0 0 107 101"
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
7
|
+
xml:space="preserve"
|
|
8
|
+
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
style="fill:none"
|
|
12
|
+
d="M24 17h121v121H24z"
|
|
13
|
+
transform="matrix(.8843 0 0 .83471 -21.223 -14.19)"
|
|
14
|
+
/>
|
|
15
|
+
<path
|
|
16
|
+
d="M119.81 105.98a.549.549 0 0 0-.53-.12c-4.19-6.19-9.52-12.06-14.68-17.73l-.85-.93c0-.11-.05-.21-.12-.3a.548.548 0 0 0-.34-.2l-.17-.18-.12-.09c-.15-.32-.53-.56-.95-.35-1.58.81-3 1.97-4.4 3.04-1.87 1.43-3.7 2.92-5.42 4.52-.7.65-1.39 1.33-1.97 2.09-.28.37-.07.72.27.87-1.22 1.2-2.45 2.45-3.68 3.74-.11.12-.17.28-.16.44.01.16.09.31.22.41l2.16 1.65s.01.03.03.04c3.09 3.05 8.51 7.28 14.25 11.76.85.67 1.71 1.34 2.57 2.01.39.47.76.94 1.12 1.4.19.25.55.3.8.11.13.1.26.21.39.31a.57.57 0 0 0 .8-.1c.07-.09.1-.2.11-.31.04 0 .07.03.1.03.15 0 .31-.06.42-.18l10.18-11.12a.56.56 0 0 0-.04-.8l.01-.01Zm-29.23-3.85c.07.09.14.17.21.25 1.16.98 2.4 2.04 3.66 3.12l-5.12-3.91s-.32-.22-.52-.36c-.11-.08-.21-.16-.31-.24l-.38-.32s.07-.07.1-.11l.35-.35c1.72-1.74 4.67-4.64 6.19-6.06-1.61 1.62-4.87 6.37-4.17 7.98h-.01Zm17.53 13.81-4.22-3.22c-1.65-1.71-3.43-3.4-5.24-5.03 2.28 1.76 4.23 3.25 4.52 3.51 2.21 1.97 2.11 1.61 3.63 2.91l1.83 1.33c-.18.16-.36.33-.53.49l.01.01Zm1.06.81-.08-.06c.16-.13.33-.25.49-.38l-.4.44h-.01ZM42.24 51.45c.14.72.27 1.43.4 2.11.69 3.7 1.33 7.03 2.55 9.56l.48 1.92c.19.73.46 1.64.71 1.83 2.85 2.52 7.22 6.28 11.89 9.82.21.16.5.15.7-.01.01.02.03.03.04.04.11.1.24.15.38.15.16 0 .31-.06.42-.19 5.98-6.65 10.43-12.12 13.6-16.7.2-.25.3-.54.29-.84.2-.24.41-.48.6-.68a.558.558 0 0 0-.1-.86.578.578 0 0 0-.17-.36c-1.39-1.34-2.42-2.31-3.46-3.28-1.84-1.72-3.74-3.5-7.77-7.51-.02-.02-.05-.04-.07-.06a.555.555 0 0 0-.22-.14c-1.11-.39-3.39-.78-6.26-1.28-4.22-.72-10-1.72-15.2-3.27h-.04v-.01s-.02 0-.03.02h-.01l.04-.02s-.31.01-.37.04c-.08.04-.14.09-.19.15-.05.06-.09.12-.47.2-.38.08.08 0 .11 0h-.11v.03c.07.34.05.58.16.97-.02.1.21 1.02.24 1.11l1.83 7.26h.03Zm30.95 6.54s-.03.04-.04.05l-.64-.71c.22.21.44.42.68.66Zm-7.09 9.39s-.07.08-.1.12l-.02-.02c.04-.03.08-.07.13-.1h-.01Zm-7.07 8.47Zm3.02-28.57c.35.35 1.74 1.65 2.06 1.97-1.45-.66-5.06-2.34-6.74-2.88 1.65.29 3.93.66 4.68.91Zm-19.18-2.77c.84 1.44 1.5 6.49 2.16 11.4-.37-1.58-.69-3.12-.99-4.6-.52-2.56-1-4.85-1.67-6.88.14.01.31.03.49.05 0 .01 0 .02.02.03h-.01Zm-.29-1.21c-.23-.02-.44-.04-.62-.05-.02-.04-.03-.08-.04-.12l.66.18v-.01Zm-2.22.45v-.02.02ZM118.9 42.57c.04-.23-1.1-1.24-.74-1.26.85-.04.86-1.35 0-1.31-1.13.06-2.27.32-3.37.53-1.98.37-3.95.78-5.92 1.21-4.39.94-8.77 1.93-13.1 3.11-1.36.37-2.86.7-4.11 1.36-.42.22-.4.67-.17.95-.09.05-.18.08-.28.09-.37.07-.74.13-1.11.19a.566.566 0 0 0-.39.86c-2.32 3.1-4.96 6.44-7.82 9.95-2.81 3.21-5.73 6.63-8.72 10.14-9.41 11.06-20.08 23.6-31.9 34.64-.23.21-.24.57-.03.8.05.06.12.1.19.13-.16.15-.32.3-.48.44-.1.09-.14.2-.16.32-.08.08-.16.17-.23.25-.21.23-.2.59.03.8.23.21.59.2.8-.03.04-.04.08-.09.12-.13a.84.84 0 0 1 1.22 0c.69.74 1.34 1.44 1.95 2.09l-1.38-1.15a.57.57 0 0 0-.8.07c-.2.24-.17.6.07.8l14.82 12.43c.11.09.24.13.37.13.15 0 .29-.06.4-.17l.36-.36a.56.56 0 0 0 .63-.12c20.09-20.18 36.27-35.43 54.8-49.06.17-.12.25-.32.23-.51a.57.57 0 0 0 .48-.39c3.42-10.46 4.08-19.72 4.28-24.27 0-.03.01-.05.02-.07.02-.05.03-.1.04-.14.03-.11.05-.19.05-.19.26-.78.17-1.53-.15-2.15v.02ZM82.98 58.94c.9-1.03 1.79-2.04 2.67-3.02-5.76 7.58-15.3 19.26-28.81 33.14 9.2-10.18 18.47-20.73 26.14-30.12Zm-32.55 52.81-.03-.03c.11.02.19.04.2.04a.47.47 0 0 0-.17 0v-.01Zm6.9 6.42-.05-.04.03-.03c.02 0 .03.02.04.02 0 .02-.02.03-.03.05h.01Zm8.36-7.21 1.38-1.44c.01.01.02.03.03.05-.47.46-.94.93-1.42 1.39h.01Zm2.24-2.21c.26-.3.56-.65.87-1.02.01-.01.02-.03.04-.04 3.29-3.39 6.68-6.82 10.18-10.25.02-.02.05-.04.07-.06.86-.66 1.82-1.39 2.72-2.08-4.52 4.32-9.11 8.78-13.88 13.46v-.01Zm21.65-55.88c-1.86 2.42-3.9 5.56-5.63 8.07-5.46 7.91-23.04 27.28-23.43 27.65-2.71 2.62-10.88 10.46-16.09 15.37-.14.13-.25.24-.34.35a.794.794 0 0 1 .03-1.13c24.82-23.4 39.88-42.89 46-51.38-.13.33-.24.69-.55 1.09l.01-.02Zm16.51 7.1-.01.02c0-.02-.02-.07.01-.02Zm-.91-5.13Zm-5.89 9.45c-2.26-1.31-3.32-3.27-2.71-5.25l.19-.66c.08-.19.17-.38.28-.57.59-.98 1.49-1.85 2.52-2.36.05-.02.1-.03.15-.04a.795.795 0 0 1-.04-.43c.05-.31.25-.58.66-.58.67 0 2.75.62 3.54 1.3.24.19.47.4.68.63.3.35.74.92.96 1.33.13.06.23.62.38.91.14.46.2.93.18 1.4 0 .02 0 .02.01.03-.03.07 0 .37-.04.4-.1.72-.36 1.43-.75 2.05-.04.05-.07.11-.11.16 0 .01-.02.02-.03.04-.3.43-.65.83-1.08 1.13-1.26.89-2.73 1.16-4.2.79a6.33 6.33 0 0 1-.57-.25l-.02-.03Zm16.27-1.63c-.49 2.05-1.09 4.19-1.8 6.38-.03.08-.03.16-.03.23-.1.01-.19.05-.27.11-4.44 3.26-8.73 6.62-12.98 10.11 3.67-3.32 7.39-6.62 11.23-9.95a6.409 6.409 0 0 0 2.11-3.74l.56-3.37.03-.1c.25-.71 1.34-.4 1.17.33h-.02Z"
|
|
17
|
+
style="fill:currentColor;fill-rule:nonzero"
|
|
18
|
+
transform="matrix(1 0 0 1 -26.41 -29.49)"
|
|
19
|
+
/>
|
|
20
|
+
</svg>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default ExcalidrawIcon;
|
|
2
|
+
type ExcalidrawIcon = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const ExcalidrawIcon: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
15
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
16
|
+
$$bindings?: Bindings;
|
|
17
|
+
} & Exports;
|
|
18
|
+
(internal: unknown, props: {
|
|
19
|
+
$$events?: Events;
|
|
20
|
+
$$slots?: Slots;
|
|
21
|
+
}): Exports & {
|
|
22
|
+
$set?: any;
|
|
23
|
+
$on?: any;
|
|
24
|
+
};
|
|
25
|
+
z_$$bindings?: Bindings;
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface LoadedExcalidraw {
|
|
2
|
+
React: any;
|
|
3
|
+
createRoot: (container: Element) => {
|
|
4
|
+
render: (node: any) => void;
|
|
5
|
+
unmount: () => void;
|
|
6
|
+
};
|
|
7
|
+
ExcalidrawLib: any;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Loads Excalidraw directly in the browser, on demand, with no installed dependency.
|
|
11
|
+
* See https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration#browser
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadExcalidraw(): Promise<LoadedExcalidraw>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const EXCALIDRAW_VERSION = '0.18.0';
|
|
2
|
+
const REACT_VERSION = '19.0.0';
|
|
3
|
+
const REACT_URL = `https://esm.sh/react@${REACT_VERSION}`;
|
|
4
|
+
const REACT_DOM_CLIENT_URL = `https://esm.sh/react-dom@${REACT_VERSION}/client`;
|
|
5
|
+
const EXCALIDRAW_ASSET_PATH = `https://esm.sh/@excalidraw/excalidraw@${EXCALIDRAW_VERSION}/dist/prod/`;
|
|
6
|
+
const EXCALIDRAW_JS_URL = `${EXCALIDRAW_ASSET_PATH}index.js?deps=react@${REACT_VERSION},react-dom@${REACT_VERSION}`;
|
|
7
|
+
const EXCALIDRAW_CSS_URL = `${EXCALIDRAW_ASSET_PATH}index.css`;
|
|
8
|
+
let loadPromise = null;
|
|
9
|
+
function ensureStylesheet() {
|
|
10
|
+
if (document.querySelector(`link[href="${EXCALIDRAW_CSS_URL}"]`))
|
|
11
|
+
return;
|
|
12
|
+
const link = document.createElement('link');
|
|
13
|
+
link.rel = 'stylesheet';
|
|
14
|
+
link.href = EXCALIDRAW_CSS_URL;
|
|
15
|
+
document.head.appendChild(link);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Loads Excalidraw directly in the browser, on demand, with no installed dependency.
|
|
19
|
+
* See https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration#browser
|
|
20
|
+
*/
|
|
21
|
+
export function loadExcalidraw() {
|
|
22
|
+
if (loadPromise)
|
|
23
|
+
return loadPromise;
|
|
24
|
+
window.EXCALIDRAW_ASSET_PATH = EXCALIDRAW_ASSET_PATH;
|
|
25
|
+
ensureStylesheet();
|
|
26
|
+
loadPromise = Promise.all([
|
|
27
|
+
import(/* @vite-ignore */ REACT_URL),
|
|
28
|
+
import(/* @vite-ignore */ REACT_DOM_CLIENT_URL),
|
|
29
|
+
import(/* @vite-ignore */ EXCALIDRAW_JS_URL)
|
|
30
|
+
]).then(([ReactModule, ReactDOMClientModule, ExcalidrawLib]) => ({
|
|
31
|
+
React: ReactModule.default ?? ReactModule,
|
|
32
|
+
createRoot: ReactDOMClientModule.createRoot,
|
|
33
|
+
ExcalidrawLib
|
|
34
|
+
}));
|
|
35
|
+
return loadPromise;
|
|
36
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import IconCaretLeft from '@hyvor/icons/IconCaretLeft';
|
|
3
3
|
import IconCloudUpload from '@hyvor/icons/IconCloudUpload';
|
|
4
|
+
import IconCardImage from '@hyvor/icons/IconCardImage';
|
|
4
5
|
import Button from '../Button/Button.svelte';
|
|
5
6
|
import Modal from '../Modal/Modal.svelte';
|
|
6
7
|
import TabNav from '../TabNav/TabNav.svelte';
|
|
@@ -13,9 +14,17 @@
|
|
|
13
14
|
} from './file-uploader.js';
|
|
14
15
|
import TabUpload from './TabUpload/TabUpload.svelte';
|
|
15
16
|
import Preview from './Preview/Preview.svelte';
|
|
17
|
+
import Media from './Media/Media.svelte';
|
|
18
|
+
import Unsplash from './Unsplash/Unsplash.svelte';
|
|
19
|
+
import Excalidraw from './Excalidraw/Excalidraw.svelte';
|
|
20
|
+
import ExcalidrawIcon from './Excalidraw/ExcalidrawIcon.svelte';
|
|
16
21
|
|
|
17
22
|
const config = getFileUploaderConfig();
|
|
18
23
|
|
|
24
|
+
const showMedia = config.type !== 'file' && !!config.mediaLoad;
|
|
25
|
+
const showUnsplash = config.type === 'image' && !!config.unsplashSearch;
|
|
26
|
+
const showExcalidraw = config.type === 'image' && !!config.excalidraw;
|
|
27
|
+
|
|
19
28
|
let tab = $state('upload');
|
|
20
29
|
|
|
21
30
|
function onClose() {
|
|
@@ -46,22 +55,28 @@
|
|
|
46
55
|
</Button>
|
|
47
56
|
{:else}
|
|
48
57
|
<TabNav>
|
|
49
|
-
<TabNavItem name="upload" active>
|
|
58
|
+
<TabNavItem name="upload" active={tab === 'upload'} onclick={() => (tab = 'upload')}>
|
|
50
59
|
{#snippet start()}
|
|
51
60
|
<IconCloudUpload />
|
|
52
61
|
{/snippet}
|
|
53
62
|
Upload
|
|
54
63
|
</TabNavItem>
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
{#if showMedia}
|
|
66
|
+
<TabNavItem name="media" active={tab === 'media'} onclick={() => (tab = 'media')}>
|
|
67
|
+
{#snippet start()}
|
|
68
|
+
<IconCardImage />
|
|
69
|
+
{/snippet}
|
|
70
|
+
Media Library
|
|
71
|
+
</TabNavItem>
|
|
72
|
+
{/if}
|
|
62
73
|
|
|
63
|
-
{#if
|
|
64
|
-
|
|
74
|
+
{#if showUnsplash}
|
|
75
|
+
<TabNavItem
|
|
76
|
+
name="unsplash"
|
|
77
|
+
active={tab === 'unsplash'}
|
|
78
|
+
onclick={() => (tab = 'unsplash')}
|
|
79
|
+
>
|
|
65
80
|
{#snippet start()}
|
|
66
81
|
<svg
|
|
67
82
|
role="img"
|
|
@@ -70,44 +85,43 @@
|
|
|
70
85
|
fill="currentColor"
|
|
71
86
|
viewBox="0 0 24 24"
|
|
72
87
|
xmlns="http://www.w3.org/2000/svg"
|
|
73
|
-
><path
|
|
74
|
-
d="M7.5 6.75V0h9v6.75h-9zm9 3.75H24V24H0V10.5h7.5v6.75h9V10.5z"
|
|
75
|
-
/></svg
|
|
88
|
+
><path d="M7.5 6.75V0h9v6.75h-9zm9 3.75H24V24H0V10.5h7.5v6.75h9V10.5z" /></svg
|
|
76
89
|
>
|
|
77
90
|
{/snippet}
|
|
78
91
|
Unsplash
|
|
79
92
|
</TabNavItem>
|
|
80
|
-
|
|
93
|
+
{/if}
|
|
94
|
+
|
|
95
|
+
{#if showExcalidraw}
|
|
96
|
+
<TabNavItem
|
|
97
|
+
name="excalidraw"
|
|
98
|
+
active={tab === 'excalidraw'}
|
|
99
|
+
onclick={() => (tab = 'excalidraw')}
|
|
100
|
+
>
|
|
81
101
|
{#snippet start()}
|
|
82
102
|
<ExcalidrawIcon />
|
|
83
103
|
{/snippet}
|
|
84
104
|
Excalidraw
|
|
85
|
-
</TabNavItem>
|
|
105
|
+
</TabNavItem>
|
|
86
106
|
{/if}
|
|
87
107
|
</TabNav>
|
|
88
108
|
{/if}
|
|
89
109
|
</div>
|
|
90
110
|
{/snippet}
|
|
91
|
-
<div class="body" style:position={selectedFile ? 'relative' : undefined}>
|
|
111
|
+
<div class="body" style:position={$selectedFile ? 'relative' : undefined}>
|
|
92
112
|
{#if tab === 'upload'}
|
|
93
113
|
<TabUpload />
|
|
114
|
+
{:else if tab === 'media'}
|
|
115
|
+
<Media />
|
|
116
|
+
{:else if tab === 'unsplash'}
|
|
117
|
+
<Unsplash />
|
|
118
|
+
{:else if tab === 'excalidraw'}
|
|
119
|
+
<Excalidraw />
|
|
94
120
|
{/if}
|
|
95
121
|
|
|
96
122
|
{#if $selectedFile}
|
|
97
123
|
<Preview />
|
|
98
124
|
{/if}
|
|
99
|
-
|
|
100
|
-
<!-- {#if tab === 'upload'}
|
|
101
|
-
<TabUpload {type} on:select={handleSelect} />
|
|
102
|
-
{:else if tab === 'media' && type !== 'any'}
|
|
103
|
-
<Media {type} on:select={handleSelect} />
|
|
104
|
-
{:else if tab === 'unsplash'}
|
|
105
|
-
<Unsplash on:select={handleSelect} />
|
|
106
|
-
{:else if tab === 'excalidraw'}
|
|
107
|
-
<Excalidraw on:select={handleSelect} />
|
|
108
|
-
{/if}
|
|
109
|
-
|
|
110
|
-
-->
|
|
111
125
|
</div>
|
|
112
126
|
</Modal>
|
|
113
127
|
</div>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import Loader from '../../Loader/Loader.svelte';
|
|
4
|
+
import LoadButton from '../../Loader/LoadButton.svelte';
|
|
5
|
+
import IconMessage from '../../IconMessage/IconMessage.svelte';
|
|
6
|
+
import toast from '../../Toast/toast.js';
|
|
7
|
+
import { getFileUploaderConfig, setSelectedFile, type MediaItem } from '../file-uploader.js';
|
|
8
|
+
|
|
9
|
+
const config = getFileUploaderConfig();
|
|
10
|
+
|
|
11
|
+
let items: MediaItem[] = $state([]);
|
|
12
|
+
let page = $state(1);
|
|
13
|
+
let isLoading = $state(true);
|
|
14
|
+
let isLoadingMore = $state(false);
|
|
15
|
+
let hasMore = $state(false);
|
|
16
|
+
|
|
17
|
+
function load(nextPage = 1) {
|
|
18
|
+
if (!config.mediaLoad) return;
|
|
19
|
+
|
|
20
|
+
nextPage === 1 ? (isLoading = true) : (isLoadingMore = true);
|
|
21
|
+
|
|
22
|
+
config
|
|
23
|
+
.mediaLoad(nextPage, config.type)
|
|
24
|
+
.then((results) => {
|
|
25
|
+
items = nextPage === 1 ? results : [...items, ...results];
|
|
26
|
+
hasMore = results.length > 0;
|
|
27
|
+
page = nextPage;
|
|
28
|
+
})
|
|
29
|
+
.catch((err) => {
|
|
30
|
+
toast.error(err.message || 'Failed to load media');
|
|
31
|
+
})
|
|
32
|
+
.finally(() => {
|
|
33
|
+
isLoading = false;
|
|
34
|
+
isLoadingMore = false;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function handleSelect(item: MediaItem) {
|
|
39
|
+
setSelectedFile({
|
|
40
|
+
type: config.type === 'audio' ? 'audio' : 'image',
|
|
41
|
+
from: 'media',
|
|
42
|
+
media: item
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function handleLoadMore() {
|
|
47
|
+
load(page + 1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onMount(() => load());
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<div class="media">
|
|
54
|
+
{#if isLoading}
|
|
55
|
+
<Loader full />
|
|
56
|
+
{:else if items.length === 0}
|
|
57
|
+
<IconMessage empty message="No media found" />
|
|
58
|
+
{:else}
|
|
59
|
+
<div class="grid">
|
|
60
|
+
{#each items as item (item.id)}
|
|
61
|
+
<button type="button" class="item" onclick={() => handleSelect(item)}>
|
|
62
|
+
{#if config.type === 'audio'}
|
|
63
|
+
<div class="audio-name">{item.name}</div>
|
|
64
|
+
{:else}
|
|
65
|
+
<img src={item.url} alt={item.name} />
|
|
66
|
+
{/if}
|
|
67
|
+
</button>
|
|
68
|
+
{/each}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<LoadButton text="Load More" show={hasMore} loading={isLoadingMore} on:click={handleLoadMore} />
|
|
72
|
+
{/if}
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<style>.media {
|
|
76
|
+
height: 100%;
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
overflow-y: auto;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.grid {
|
|
83
|
+
display: grid;
|
|
84
|
+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
85
|
+
gap: 10px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.item {
|
|
89
|
+
display: block;
|
|
90
|
+
width: 100%;
|
|
91
|
+
aspect-ratio: 1;
|
|
92
|
+
padding: 0;
|
|
93
|
+
border: 1px solid var(--border);
|
|
94
|
+
border-radius: 5px;
|
|
95
|
+
background: var(--input);
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
transition: 0.2s box-shadow;
|
|
99
|
+
}
|
|
100
|
+
.item:hover {
|
|
101
|
+
box-shadow: 0 0 0 2px var(--accent-light);
|
|
102
|
+
}
|
|
103
|
+
.item img {
|
|
104
|
+
display: block;
|
|
105
|
+
width: 100%;
|
|
106
|
+
height: 100%;
|
|
107
|
+
object-fit: cover;
|
|
108
|
+
}
|
|
109
|
+
.item .audio-name {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
height: 100%;
|
|
114
|
+
padding: 10px;
|
|
115
|
+
font-size: 13px;
|
|
116
|
+
text-align: center;
|
|
117
|
+
word-break: break-word;
|
|
118
|
+
}</style>
|
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
if (file.upload) {
|
|
22
22
|
return URL.createObjectURL(file.upload.blob);
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
if (file.unsplash) {
|
|
25
|
+
return file.unsplash.url;
|
|
26
|
+
}
|
|
27
|
+
if (file.media) {
|
|
28
|
+
return file.media.url;
|
|
29
|
+
}
|
|
30
|
+
return '';
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
let imageSize = $state(getInitialImageSize());
|
|
@@ -39,7 +45,12 @@
|
|
|
39
45
|
if (file.upload && file.upload.blob instanceof File) {
|
|
40
46
|
return file.upload.blob.name;
|
|
41
47
|
}
|
|
42
|
-
|
|
48
|
+
if (file.unsplash) {
|
|
49
|
+
return file.unsplash.title || file.unsplash.alt;
|
|
50
|
+
}
|
|
51
|
+
if (file.media) {
|
|
52
|
+
return file.media.name;
|
|
53
|
+
}
|
|
43
54
|
return null;
|
|
44
55
|
}
|
|
45
56
|
|
|
@@ -129,7 +140,7 @@
|
|
|
129
140
|
});
|
|
130
141
|
} else {
|
|
131
142
|
completeFileUpload({
|
|
132
|
-
url: file.upload
|
|
143
|
+
url: file.upload?.fetchedUrl || file.unsplash?.url || file.media?.url || '',
|
|
133
144
|
selectedFile: file
|
|
134
145
|
});
|
|
135
146
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconArrowReturnLeft from '@hyvor/icons/IconArrowReturnLeft';
|
|
3
|
+
import Button from '../../Button/Button.svelte';
|
|
4
|
+
import TextInput from '../../TextInput/TextInput.svelte';
|
|
5
|
+
import Loader from '../../Loader/Loader.svelte';
|
|
6
|
+
import LoadButton from '../../Loader/LoadButton.svelte';
|
|
7
|
+
import IconMessage from '../../IconMessage/IconMessage.svelte';
|
|
8
|
+
import toast from '../../Toast/toast.js';
|
|
9
|
+
import { getFileUploaderConfig, setSelectedFile, type UnsplashImage } from '../file-uploader.js';
|
|
10
|
+
|
|
11
|
+
const config = getFileUploaderConfig();
|
|
12
|
+
|
|
13
|
+
let search = $state('');
|
|
14
|
+
let images: UnsplashImage[] = $state([]);
|
|
15
|
+
let page = $state(1);
|
|
16
|
+
let isLoading = $state(false);
|
|
17
|
+
let isLoadingMore = $state(false);
|
|
18
|
+
let hasMore = $state(false);
|
|
19
|
+
let hasSearched = $state(false);
|
|
20
|
+
let inputError = $state(false);
|
|
21
|
+
|
|
22
|
+
function performSearch(nextPage = 1) {
|
|
23
|
+
inputError = false;
|
|
24
|
+
|
|
25
|
+
if (search.trim() === '') {
|
|
26
|
+
inputError = true;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!config.unsplashSearch) return;
|
|
31
|
+
|
|
32
|
+
nextPage === 1 ? (isLoading = true) : (isLoadingMore = true);
|
|
33
|
+
|
|
34
|
+
config
|
|
35
|
+
.unsplashSearch(search, nextPage)
|
|
36
|
+
.then((results) => {
|
|
37
|
+
images = nextPage === 1 ? results : [...images, ...results];
|
|
38
|
+
hasMore = results.length > 0;
|
|
39
|
+
page = nextPage;
|
|
40
|
+
hasSearched = true;
|
|
41
|
+
})
|
|
42
|
+
.catch((err) => {
|
|
43
|
+
toast.error(err.message || 'Failed to search Unsplash');
|
|
44
|
+
})
|
|
45
|
+
.finally(() => {
|
|
46
|
+
isLoading = false;
|
|
47
|
+
isLoadingMore = false;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function handleKeyup(e: KeyboardEvent) {
|
|
52
|
+
if (e.key === 'Enter') {
|
|
53
|
+
performSearch();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function handleSelect(image: UnsplashImage) {
|
|
58
|
+
setSelectedFile({
|
|
59
|
+
type: 'image',
|
|
60
|
+
from: 'unsplash',
|
|
61
|
+
unsplash: image
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function handleLoadMore() {
|
|
66
|
+
performSearch(page + 1);
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<div class="unsplash">
|
|
71
|
+
<div class="search-wrap">
|
|
72
|
+
<TextInput
|
|
73
|
+
bind:value={search}
|
|
74
|
+
placeholder="Search Unsplash"
|
|
75
|
+
autofocus
|
|
76
|
+
autocomplete="off"
|
|
77
|
+
onkeyup={handleKeyup}
|
|
78
|
+
block
|
|
79
|
+
state={inputError ? 'error' : 'default'}
|
|
80
|
+
/>
|
|
81
|
+
<Button onclick={() => performSearch()}>
|
|
82
|
+
Search
|
|
83
|
+
{#snippet end()}
|
|
84
|
+
<IconArrowReturnLeft size={14} />
|
|
85
|
+
{/snippet}
|
|
86
|
+
</Button>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="results">
|
|
90
|
+
{#if isLoading}
|
|
91
|
+
<Loader full />
|
|
92
|
+
{:else if images.length === 0 && hasSearched}
|
|
93
|
+
<IconMessage empty message="No images found" />
|
|
94
|
+
{:else}
|
|
95
|
+
<div class="cols">
|
|
96
|
+
{#each [0, 1, 2] as col (col)}
|
|
97
|
+
<div class="col">
|
|
98
|
+
{#each images as image, i (image.url)}
|
|
99
|
+
{#if i % 3 === col}
|
|
100
|
+
<button type="button" class="img-wrap" onclick={() => handleSelect(image)}>
|
|
101
|
+
<img src={image.url} alt={image.alt || image.title || ''} />
|
|
102
|
+
</button>
|
|
103
|
+
{/if}
|
|
104
|
+
{/each}
|
|
105
|
+
</div>
|
|
106
|
+
{/each}
|
|
107
|
+
</div>
|
|
108
|
+
{/if}
|
|
109
|
+
|
|
110
|
+
<LoadButton
|
|
111
|
+
text="Load More"
|
|
112
|
+
show={hasMore && !isLoading}
|
|
113
|
+
loading={isLoadingMore}
|
|
114
|
+
on:click={handleLoadMore}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<style>.unsplash {
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
height: 100%;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.search-wrap {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
margin-bottom: 15px;
|
|
129
|
+
gap: 10px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.results {
|
|
133
|
+
flex: 1;
|
|
134
|
+
overflow-y: auto;
|
|
135
|
+
}
|
|
136
|
+
.results .cols {
|
|
137
|
+
display: flex;
|
|
138
|
+
gap: 10px;
|
|
139
|
+
}
|
|
140
|
+
.results .col {
|
|
141
|
+
flex: 1;
|
|
142
|
+
}
|
|
143
|
+
.results .img-wrap {
|
|
144
|
+
display: block;
|
|
145
|
+
width: 100%;
|
|
146
|
+
margin-bottom: 10px;
|
|
147
|
+
padding: 0;
|
|
148
|
+
border: none;
|
|
149
|
+
background: none;
|
|
150
|
+
cursor: pointer;
|
|
151
|
+
}
|
|
152
|
+
.results .img-wrap img {
|
|
153
|
+
display: block;
|
|
154
|
+
width: 100%;
|
|
155
|
+
border-radius: 5px;
|
|
156
|
+
}</style>
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
export declare let fileUploaderConfig: import("svelte/store").Writable<FileUploaderConfigInternal | null>;
|
|
2
2
|
export declare let selectedFile: import("svelte/store").Writable<SelectedFile | null>;
|
|
3
3
|
export type UploadType = 'image' | 'audio' | 'file';
|
|
4
|
+
export interface UnsplashImage {
|
|
5
|
+
url: string;
|
|
6
|
+
author: string;
|
|
7
|
+
author_url: string;
|
|
8
|
+
title: string | null;
|
|
9
|
+
alt: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface MediaItem {
|
|
12
|
+
id: string | number;
|
|
13
|
+
url: string;
|
|
14
|
+
name: string;
|
|
15
|
+
}
|
|
4
16
|
export interface FileUploaderConfig {
|
|
5
17
|
/**
|
|
6
18
|
* image:
|
|
7
|
-
* - shows unsplash and excalidraw tabs
|
|
19
|
+
* - shows unsplash and excalidraw tabs (if configured)
|
|
8
20
|
* audio:
|
|
9
21
|
* - shows audio preview
|
|
10
22
|
* file
|
|
11
23
|
* - allows any file type
|
|
12
24
|
* - preview tries to detect file type (image/audio/other)
|
|
25
|
+
* - hides the media library tab
|
|
13
26
|
*/
|
|
14
27
|
type: UploadType;
|
|
15
28
|
uploader: (file: Blob, name: string | null) => Promise<{
|
|
@@ -17,16 +30,12 @@ export interface FileUploaderConfig {
|
|
|
17
30
|
}>;
|
|
18
31
|
allowedMimeTypes?: string[];
|
|
19
32
|
maxFileSizeInMB?: number;
|
|
33
|
+
mediaLoad?: (page: number, type: UploadType) => Promise<MediaItem[]>;
|
|
34
|
+
unsplashSearch?: (search: string, page: number) => Promise<UnsplashImage[]>;
|
|
35
|
+
excalidraw?: boolean;
|
|
20
36
|
}
|
|
21
37
|
export type SelectedFileFrom = 'upload' | 'media' | 'unsplash' | 'excalidraw';
|
|
22
|
-
export type SelectedFileUploadType = 'paste' | 'dnd' | 'browse' | 'url';
|
|
23
|
-
export interface UnsplashImage {
|
|
24
|
-
url: string;
|
|
25
|
-
author: string;
|
|
26
|
-
author_url: string;
|
|
27
|
-
title: string | null;
|
|
28
|
-
alt: string | null;
|
|
29
|
-
}
|
|
38
|
+
export type SelectedFileUploadType = 'paste' | 'dnd' | 'browse' | 'url' | 'excalidraw';
|
|
30
39
|
export interface SelectedFile {
|
|
31
40
|
type: UploadType;
|
|
32
41
|
from: SelectedFileFrom;
|
|
@@ -36,12 +45,13 @@ export interface SelectedFile {
|
|
|
36
45
|
fetchedUrl?: string;
|
|
37
46
|
};
|
|
38
47
|
unsplash?: UnsplashImage;
|
|
48
|
+
media?: MediaItem;
|
|
39
49
|
}
|
|
40
50
|
export interface UploadedFile {
|
|
41
51
|
url: string;
|
|
42
52
|
selectedFile: SelectedFile;
|
|
43
53
|
}
|
|
44
|
-
export type FileUploaderConfigInternal = Required<FileUploaderConfig> & {
|
|
54
|
+
export type FileUploaderConfigInternal = Required<Omit<FileUploaderConfig, 'mediaLoad' | 'unsplashSearch' | 'excalidraw'>> & Pick<FileUploaderConfig, 'mediaLoad' | 'unsplashSearch' | 'excalidraw'> & {
|
|
45
55
|
onCancel: () => void;
|
|
46
56
|
onUpload: (file: UploadedFile) => void;
|
|
47
57
|
};
|
|
@@ -30,7 +30,7 @@ export { default as FormControl } from './FormControl/FormControl.svelte';
|
|
|
30
30
|
export { default as InputGroup } from './FormControl/InputGroup.svelte';
|
|
31
31
|
export { default as Label } from './FormControl/Label.svelte';
|
|
32
32
|
export { default as Validation } from './FormControl/Validation.svelte';
|
|
33
|
-
export { uploadFile, type FileUploaderConfig, type UploadedFile as FileUploaderUploadedFile, type SelectedFile as FileUploaderSelectedFile } from './FileUploader/file-uploader.js';
|
|
33
|
+
export { uploadFile, type FileUploaderConfig, type UploadedFile as FileUploaderUploadedFile, type SelectedFile as FileUploaderSelectedFile, type UnsplashImage as FileUploaderUnsplashImage, type MediaItem as FileUploaderMediaItem } from './FileUploader/file-uploader.js';
|
|
34
34
|
export { default as IconButton } from './IconButton/IconButton.svelte';
|
|
35
35
|
export { default as Kbd } from './Kbd/Kbd.svelte';
|
|
36
36
|
export { default as Link } from './Link/Link.svelte';
|