@twick/studio 0.15.18 → 0.15.19
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/container/element-panel-container.d.ts +3 -1
- package/dist/components/shared/cloud-media-upload.d.ts +15 -0
- package/dist/components/shared/index.d.ts +1 -0
- package/dist/hooks/use-cloud-media-upload.d.ts +27 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +294 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +295 -43
- package/dist/index.mjs.map +1 -1
- package/dist/studio.css +6 -1
- package/dist/types/index.d.ts +11 -0
- package/package.json +12 -12
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { Size, TrackElement } from '@twick/timeline';
|
|
3
|
+
import { UploadConfig } from '../../types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Props interface for the ElementPanelContainer component.
|
|
@@ -12,6 +13,7 @@ interface ElementPanelContainerProps {
|
|
|
12
13
|
setSelectedTool: (tool: string) => void;
|
|
13
14
|
addElement: (element: TrackElement) => void;
|
|
14
15
|
updateElement: (element: TrackElement) => void;
|
|
16
|
+
uploadConfig?: UploadConfig;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* ElementPanelContainer component that renders the appropriate element panel
|
|
@@ -34,5 +36,5 @@ interface ElementPanelContainerProps {
|
|
|
34
36
|
* />
|
|
35
37
|
* ```
|
|
36
38
|
*/
|
|
37
|
-
declare const ElementPanelContainer: ({ selectedTool, videoResolution, selectedElement, addElement, updateElement, }: ElementPanelContainerProps) => React.ReactElement;
|
|
39
|
+
declare const ElementPanelContainer: ({ selectedTool, videoResolution, selectedElement, addElement, updateElement, uploadConfig, }: ElementPanelContainerProps) => React.ReactElement;
|
|
38
40
|
export default ElementPanelContainer;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CloudUploadProvider } from '../../hooks/use-cloud-media-upload';
|
|
2
|
+
|
|
3
|
+
export interface CloudMediaUploadProps {
|
|
4
|
+
onSuccess: (url: string, file: File) => void;
|
|
5
|
+
onError?: (error: string) => void;
|
|
6
|
+
accept?: string;
|
|
7
|
+
uploadApiUrl: string;
|
|
8
|
+
provider: CloudUploadProvider;
|
|
9
|
+
buttonText?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
id?: string;
|
|
13
|
+
icon?: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare const CloudMediaUpload: ({ onSuccess, onError, accept, uploadApiUrl, provider, buttonText, className, disabled, id: providedId, icon, }: CloudMediaUploadProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type CloudUploadProvider = "s3" | "gcs";
|
|
2
|
+
export interface UseCloudMediaUploadConfig {
|
|
3
|
+
uploadApiUrl: string;
|
|
4
|
+
provider: CloudUploadProvider;
|
|
5
|
+
}
|
|
6
|
+
/** Response from S3 presign API (e.g. file-uploader Lambda). */
|
|
7
|
+
export interface S3PresignResponse {
|
|
8
|
+
uploadUrl: string;
|
|
9
|
+
key?: string;
|
|
10
|
+
bucket?: string;
|
|
11
|
+
contentType?: string;
|
|
12
|
+
expiresIn?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Response from GCS upload API (server-side upload). */
|
|
15
|
+
export interface GCSUploadResponse {
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
export interface UseCloudMediaUploadReturn {
|
|
19
|
+
uploadFile: (file: File) => Promise<{
|
|
20
|
+
url: string;
|
|
21
|
+
}>;
|
|
22
|
+
isUploading: boolean;
|
|
23
|
+
progress: number;
|
|
24
|
+
error: string | null;
|
|
25
|
+
resetError: () => void;
|
|
26
|
+
}
|
|
27
|
+
export declare const useCloudMediaUpload: (config: UseCloudMediaUploadConfig) => UseCloudMediaUploadReturn;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { TextPanel } from './components/panel/text-panel';
|
|
|
10
10
|
import { CirclePanel } from './components/panel/circle-panel';
|
|
11
11
|
import { RectPanel } from './components/panel/rect-panel';
|
|
12
12
|
import { CaptionsPanel } from './components/panel/captions-panel';
|
|
13
|
+
import { CloudMediaUpload } from './components/shared/cloud-media-upload';
|
|
14
|
+
import { useCloudMediaUpload } from './hooks/use-cloud-media-upload';
|
|
13
15
|
|
|
14
16
|
export {
|
|
15
17
|
/** Main studio editing environment */
|
|
@@ -37,10 +39,17 @@ export {
|
|
|
37
39
|
/** Hook for managing studio state and selections */
|
|
38
40
|
useStudioManager,
|
|
39
41
|
/** Hook for polling-based caption generation */
|
|
40
|
-
useGenerateCaptions,
|
|
42
|
+
useGenerateCaptions,
|
|
43
|
+
/** Hook for S3/GCS cloud media upload */
|
|
44
|
+
useCloudMediaUpload, };
|
|
45
|
+
export {
|
|
46
|
+
/** Cloud media upload (S3 or GCS) for use in media panels */
|
|
47
|
+
CloudMediaUpload, };
|
|
41
48
|
export * from './helpers/generate-captions.service';
|
|
42
49
|
export * from './helpers/constant';
|
|
43
50
|
export * from './types';
|
|
51
|
+
export type { CloudUploadProvider, UseCloudMediaUploadConfig, UseCloudMediaUploadReturn, S3PresignResponse, GCSUploadResponse, } from './hooks/use-cloud-media-upload';
|
|
52
|
+
export type { CloudMediaUploadProps } from './components/shared/cloud-media-upload';
|
|
44
53
|
/**
|
|
45
54
|
* ============================================================================
|
|
46
55
|
* RE-EXPORTS FROM DEPENDENCY PACKAGES
|
package/dist/index.js
CHANGED
|
@@ -751,6 +751,182 @@ const useStudioManager = () => {
|
|
|
751
751
|
updateElement
|
|
752
752
|
};
|
|
753
753
|
};
|
|
754
|
+
const putFileWithProgress = (uploadUrl, file, onProgress) => {
|
|
755
|
+
return new Promise((resolve, reject) => {
|
|
756
|
+
const xhr = new XMLHttpRequest();
|
|
757
|
+
xhr.upload.addEventListener("progress", (e) => {
|
|
758
|
+
if (e.lengthComputable) {
|
|
759
|
+
onProgress(e.loaded / e.total * 100);
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
xhr.addEventListener("load", () => {
|
|
763
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
764
|
+
onProgress(100);
|
|
765
|
+
resolve();
|
|
766
|
+
} else {
|
|
767
|
+
reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`));
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
xhr.addEventListener("error", () => reject(new Error("Upload failed")));
|
|
771
|
+
xhr.addEventListener("abort", () => reject(new Error("Upload aborted")));
|
|
772
|
+
xhr.open("PUT", uploadUrl);
|
|
773
|
+
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
774
|
+
xhr.send(file);
|
|
775
|
+
});
|
|
776
|
+
};
|
|
777
|
+
const useCloudMediaUpload = (config) => {
|
|
778
|
+
const { uploadApiUrl, provider } = config;
|
|
779
|
+
const [isUploading, setIsUploading] = react.useState(false);
|
|
780
|
+
const [progress, setProgress] = react.useState(0);
|
|
781
|
+
const [error, setError] = react.useState(null);
|
|
782
|
+
const resetError = react.useCallback(() => {
|
|
783
|
+
setError(null);
|
|
784
|
+
}, []);
|
|
785
|
+
const uploadFile = react.useCallback(
|
|
786
|
+
async (file) => {
|
|
787
|
+
setIsUploading(true);
|
|
788
|
+
setProgress(0);
|
|
789
|
+
setError(null);
|
|
790
|
+
try {
|
|
791
|
+
if (provider === "s3") {
|
|
792
|
+
const presignRes = await fetch(uploadApiUrl, {
|
|
793
|
+
method: "POST",
|
|
794
|
+
headers: { "Content-Type": "application/json" },
|
|
795
|
+
body: JSON.stringify({
|
|
796
|
+
filename: file.name,
|
|
797
|
+
contentType: file.type || "application/octet-stream"
|
|
798
|
+
})
|
|
799
|
+
});
|
|
800
|
+
if (!presignRes.ok) {
|
|
801
|
+
const errBody = await presignRes.json().catch(() => ({}));
|
|
802
|
+
throw new Error(
|
|
803
|
+
errBody.error ?? `Failed to get upload URL: ${presignRes.statusText}`
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
const presignData = await presignRes.json();
|
|
807
|
+
const uploadUrl = presignData.uploadUrl;
|
|
808
|
+
await putFileWithProgress(uploadUrl, file, setProgress);
|
|
809
|
+
const publicUrl = uploadUrl.split("?")[0];
|
|
810
|
+
return { url: publicUrl };
|
|
811
|
+
}
|
|
812
|
+
if (provider === "gcs") {
|
|
813
|
+
setProgress(10);
|
|
814
|
+
const formData = new FormData();
|
|
815
|
+
formData.append("file", file);
|
|
816
|
+
const uploadRes = await fetch(uploadApiUrl, {
|
|
817
|
+
method: "POST",
|
|
818
|
+
body: formData
|
|
819
|
+
});
|
|
820
|
+
if (!uploadRes.ok) {
|
|
821
|
+
const errBody = await uploadRes.json().catch(() => ({}));
|
|
822
|
+
throw new Error(
|
|
823
|
+
errBody.error ?? `Upload failed: ${uploadRes.statusText}`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
setProgress(100);
|
|
827
|
+
const data = await uploadRes.json();
|
|
828
|
+
if (!data.url) {
|
|
829
|
+
throw new Error("Upload response missing url");
|
|
830
|
+
}
|
|
831
|
+
return { url: data.url };
|
|
832
|
+
}
|
|
833
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
834
|
+
} catch (err) {
|
|
835
|
+
const message = err instanceof Error ? err.message : "Upload failed";
|
|
836
|
+
setError(message);
|
|
837
|
+
throw err;
|
|
838
|
+
} finally {
|
|
839
|
+
setIsUploading(false);
|
|
840
|
+
setProgress(0);
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
[uploadApiUrl, provider]
|
|
844
|
+
);
|
|
845
|
+
return {
|
|
846
|
+
uploadFile,
|
|
847
|
+
isUploading,
|
|
848
|
+
progress,
|
|
849
|
+
error,
|
|
850
|
+
resetError
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
const CloudMediaUpload = ({
|
|
854
|
+
onSuccess,
|
|
855
|
+
onError,
|
|
856
|
+
accept,
|
|
857
|
+
uploadApiUrl,
|
|
858
|
+
provider,
|
|
859
|
+
buttonText = "Upload to cloud",
|
|
860
|
+
className,
|
|
861
|
+
disabled = false,
|
|
862
|
+
id: providedId,
|
|
863
|
+
icon
|
|
864
|
+
}) => {
|
|
865
|
+
const id = providedId ?? `cloud-media-upload-${Math.random().toString(36).slice(2, 9)}`;
|
|
866
|
+
const inputRef = react.useRef(null);
|
|
867
|
+
const {
|
|
868
|
+
uploadFile,
|
|
869
|
+
isUploading,
|
|
870
|
+
progress,
|
|
871
|
+
error,
|
|
872
|
+
resetError
|
|
873
|
+
} = useCloudMediaUpload({ uploadApiUrl, provider });
|
|
874
|
+
const handleFileChange = async (e) => {
|
|
875
|
+
var _a;
|
|
876
|
+
const file = (_a = e.target.files) == null ? void 0 : _a[0];
|
|
877
|
+
if (!file) return;
|
|
878
|
+
try {
|
|
879
|
+
const { url } = await uploadFile(file);
|
|
880
|
+
onSuccess(url, file);
|
|
881
|
+
if (inputRef.current) {
|
|
882
|
+
inputRef.current.value = "";
|
|
883
|
+
}
|
|
884
|
+
} catch (err) {
|
|
885
|
+
const message = err instanceof Error ? err.message : "Upload failed";
|
|
886
|
+
onError == null ? void 0 : onError(message);
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
const handleLabelClick = () => {
|
|
890
|
+
if (disabled || isUploading) return;
|
|
891
|
+
resetError();
|
|
892
|
+
};
|
|
893
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "file-input-container cloud-media-upload-container", children: [
|
|
894
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
895
|
+
"input",
|
|
896
|
+
{
|
|
897
|
+
ref: inputRef,
|
|
898
|
+
type: "file",
|
|
899
|
+
accept,
|
|
900
|
+
className: "file-input-hidden",
|
|
901
|
+
id,
|
|
902
|
+
onChange: handleFileChange,
|
|
903
|
+
disabled: disabled || isUploading,
|
|
904
|
+
"aria-label": buttonText
|
|
905
|
+
}
|
|
906
|
+
),
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
908
|
+
"label",
|
|
909
|
+
{
|
|
910
|
+
htmlFor: id,
|
|
911
|
+
className: className ?? "btn-primary file-input-label",
|
|
912
|
+
onClick: handleLabelClick,
|
|
913
|
+
style: { pointerEvents: disabled || isUploading ? "none" : void 0 },
|
|
914
|
+
children: [
|
|
915
|
+
icon ?? /* @__PURE__ */ jsxRuntime.jsx(Upload, { className: "icon-sm" }),
|
|
916
|
+
isUploading ? `${Math.round(progress)}%` : buttonText
|
|
917
|
+
]
|
|
918
|
+
}
|
|
919
|
+
),
|
|
920
|
+
isUploading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cloud-media-upload-progress", role: "progressbar", "aria-valuenow": progress, "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
921
|
+
"div",
|
|
922
|
+
{
|
|
923
|
+
className: "cloud-media-upload-progress-fill",
|
|
924
|
+
style: { width: `${progress}%` }
|
|
925
|
+
}
|
|
926
|
+
) }),
|
|
927
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cloud-media-upload-error", role: "alert", children: error })
|
|
928
|
+
] });
|
|
929
|
+
};
|
|
754
930
|
const _MediaManagerSingleton = class _MediaManagerSingleton {
|
|
755
931
|
constructor() {
|
|
756
932
|
}
|
|
@@ -1308,19 +1484,42 @@ const AudioPanelContainer = (props) => {
|
|
|
1308
1484
|
});
|
|
1309
1485
|
addItem(newItem);
|
|
1310
1486
|
};
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
{
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1487
|
+
const onCloudUploadSuccess = async (url, file) => {
|
|
1488
|
+
var _a;
|
|
1489
|
+
const newItem = await mediaManager.addItem({
|
|
1490
|
+
name: file.name,
|
|
1491
|
+
url,
|
|
1492
|
+
type: "audio",
|
|
1493
|
+
metadata: { source: ((_a = props.uploadConfig) == null ? void 0 : _a.provider) ?? "s3" }
|
|
1494
|
+
});
|
|
1495
|
+
addItem(newItem);
|
|
1496
|
+
};
|
|
1497
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1498
|
+
props.uploadConfig && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex panel-section", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1499
|
+
CloudMediaUpload,
|
|
1500
|
+
{
|
|
1501
|
+
uploadApiUrl: props.uploadConfig.uploadApiUrl,
|
|
1502
|
+
provider: props.uploadConfig.provider,
|
|
1503
|
+
accept: "audio/*",
|
|
1504
|
+
onSuccess: onCloudUploadSuccess,
|
|
1505
|
+
buttonText: "Upload audio",
|
|
1506
|
+
className: "btn-ghost w-full"
|
|
1507
|
+
}
|
|
1508
|
+
) }),
|
|
1509
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1510
|
+
AudioPanel,
|
|
1511
|
+
{
|
|
1512
|
+
items,
|
|
1513
|
+
searchQuery,
|
|
1514
|
+
onSearchChange: setSearchQuery,
|
|
1515
|
+
onItemSelect: handleSelection,
|
|
1516
|
+
onFileUpload: handleFileUpload,
|
|
1517
|
+
isLoading,
|
|
1518
|
+
acceptFileTypes,
|
|
1519
|
+
onUrlAdd
|
|
1520
|
+
}
|
|
1521
|
+
)
|
|
1522
|
+
] });
|
|
1324
1523
|
};
|
|
1325
1524
|
function ImagePanel({
|
|
1326
1525
|
items,
|
|
@@ -1406,19 +1605,42 @@ function ImagePanelContainer(props) {
|
|
|
1406
1605
|
});
|
|
1407
1606
|
addItem(newItem);
|
|
1408
1607
|
};
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
{
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1608
|
+
const onCloudUploadSuccess = async (url, file) => {
|
|
1609
|
+
var _a;
|
|
1610
|
+
const newItem = await mediaManager.addItem({
|
|
1611
|
+
name: file.name,
|
|
1612
|
+
url,
|
|
1613
|
+
type: "image",
|
|
1614
|
+
metadata: { source: ((_a = props.uploadConfig) == null ? void 0 : _a.provider) ?? "s3" }
|
|
1615
|
+
});
|
|
1616
|
+
addItem(newItem);
|
|
1617
|
+
};
|
|
1618
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1619
|
+
props.uploadConfig && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex panel-section", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1620
|
+
CloudMediaUpload,
|
|
1621
|
+
{
|
|
1622
|
+
uploadApiUrl: props.uploadConfig.uploadApiUrl,
|
|
1623
|
+
provider: props.uploadConfig.provider,
|
|
1624
|
+
accept: "image/*",
|
|
1625
|
+
onSuccess: onCloudUploadSuccess,
|
|
1626
|
+
buttonText: "Upload image",
|
|
1627
|
+
className: "btn-ghost w-full"
|
|
1628
|
+
}
|
|
1629
|
+
) }),
|
|
1630
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1631
|
+
ImagePanel,
|
|
1632
|
+
{
|
|
1633
|
+
items,
|
|
1634
|
+
searchQuery,
|
|
1635
|
+
onSearchChange: setSearchQuery,
|
|
1636
|
+
onItemSelect: handleSelection,
|
|
1637
|
+
onFileUpload: handleFileUpload,
|
|
1638
|
+
isLoading,
|
|
1639
|
+
acceptFileTypes,
|
|
1640
|
+
onUrlAdd
|
|
1641
|
+
}
|
|
1642
|
+
)
|
|
1643
|
+
] });
|
|
1422
1644
|
}
|
|
1423
1645
|
const useVideoPreview = () => {
|
|
1424
1646
|
const [playingVideo, setPlayingVideo] = react.useState(null);
|
|
@@ -1572,17 +1794,40 @@ function VideoPanelContainer(props) {
|
|
|
1572
1794
|
});
|
|
1573
1795
|
addItem(newItem);
|
|
1574
1796
|
};
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
{
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1797
|
+
const onCloudUploadSuccess = async (url, file) => {
|
|
1798
|
+
var _a;
|
|
1799
|
+
const newItem = await mediaManager.addItem({
|
|
1800
|
+
name: file.name,
|
|
1801
|
+
url,
|
|
1802
|
+
type: "video",
|
|
1803
|
+
metadata: { source: ((_a = props.uploadConfig) == null ? void 0 : _a.provider) ?? "s3" }
|
|
1804
|
+
});
|
|
1805
|
+
addItem(newItem);
|
|
1806
|
+
};
|
|
1807
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1808
|
+
props.uploadConfig && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex panel-section", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1809
|
+
CloudMediaUpload,
|
|
1810
|
+
{
|
|
1811
|
+
uploadApiUrl: props.uploadConfig.uploadApiUrl,
|
|
1812
|
+
provider: props.uploadConfig.provider,
|
|
1813
|
+
accept: "video/*",
|
|
1814
|
+
onSuccess: onCloudUploadSuccess,
|
|
1815
|
+
buttonText: "Upload video",
|
|
1816
|
+
className: "btn-ghost w-full"
|
|
1817
|
+
}
|
|
1818
|
+
) }),
|
|
1819
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1820
|
+
VideoPanel,
|
|
1821
|
+
{
|
|
1822
|
+
items,
|
|
1823
|
+
onItemSelect: handleSelection,
|
|
1824
|
+
onFileUpload: handleFileUpload,
|
|
1825
|
+
isLoading,
|
|
1826
|
+
acceptFileTypes,
|
|
1827
|
+
onUrlAdd
|
|
1828
|
+
}
|
|
1829
|
+
)
|
|
1830
|
+
] });
|
|
1586
1831
|
}
|
|
1587
1832
|
function TextPanel({
|
|
1588
1833
|
textContent,
|
|
@@ -2677,7 +2922,8 @@ const ElementPanelContainer = ({
|
|
|
2677
2922
|
videoResolution,
|
|
2678
2923
|
selectedElement,
|
|
2679
2924
|
addElement,
|
|
2680
|
-
updateElement
|
|
2925
|
+
updateElement,
|
|
2926
|
+
uploadConfig
|
|
2681
2927
|
}) => {
|
|
2682
2928
|
const addNewElement = async (element) => {
|
|
2683
2929
|
await addElement(element);
|
|
@@ -2691,7 +2937,8 @@ const ElementPanelContainer = ({
|
|
|
2691
2937
|
videoResolution,
|
|
2692
2938
|
selectedElement,
|
|
2693
2939
|
addElement: addNewElement,
|
|
2694
|
-
updateElement
|
|
2940
|
+
updateElement,
|
|
2941
|
+
uploadConfig
|
|
2695
2942
|
}
|
|
2696
2943
|
);
|
|
2697
2944
|
case "audio":
|
|
@@ -2701,7 +2948,8 @@ const ElementPanelContainer = ({
|
|
|
2701
2948
|
videoResolution,
|
|
2702
2949
|
selectedElement,
|
|
2703
2950
|
addElement: addNewElement,
|
|
2704
|
-
updateElement
|
|
2951
|
+
updateElement,
|
|
2952
|
+
uploadConfig
|
|
2705
2953
|
}
|
|
2706
2954
|
);
|
|
2707
2955
|
case "video":
|
|
@@ -2711,7 +2959,8 @@ const ElementPanelContainer = ({
|
|
|
2711
2959
|
videoResolution,
|
|
2712
2960
|
selectedElement,
|
|
2713
2961
|
addElement: addNewElement,
|
|
2714
|
-
updateElement
|
|
2962
|
+
updateElement,
|
|
2963
|
+
uploadConfig
|
|
2715
2964
|
}
|
|
2716
2965
|
);
|
|
2717
2966
|
case "text":
|
|
@@ -3908,7 +4157,8 @@ function TwickStudio({ studioConfig }) {
|
|
|
3908
4157
|
setSelectedTool,
|
|
3909
4158
|
selectedElement,
|
|
3910
4159
|
addElement,
|
|
3911
|
-
updateElement
|
|
4160
|
+
updateElement,
|
|
4161
|
+
uploadConfig: twickStudiConfig.uploadConfig
|
|
3912
4162
|
}
|
|
3913
4163
|
) }),
|
|
3914
4164
|
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "main-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-wrapper", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4207,6 +4457,7 @@ exports.AudioPanel = AudioPanel;
|
|
|
4207
4457
|
exports.CAPTION_PROPS = CAPTION_PROPS;
|
|
4208
4458
|
exports.CaptionsPanel = CaptionsPanel;
|
|
4209
4459
|
exports.CirclePanel = CirclePanel;
|
|
4460
|
+
exports.CloudMediaUpload = CloudMediaUpload;
|
|
4210
4461
|
exports.ImagePanel = ImagePanel;
|
|
4211
4462
|
exports.RectPanel = RectPanel;
|
|
4212
4463
|
exports.StudioHeader = StudioHeader;
|
|
@@ -4215,6 +4466,7 @@ exports.Toolbar = Toolbar;
|
|
|
4215
4466
|
exports.TwickStudio = TwickStudio;
|
|
4216
4467
|
exports.VideoPanel = VideoPanel;
|
|
4217
4468
|
exports.default = TwickStudio;
|
|
4469
|
+
exports.useCloudMediaUpload = useCloudMediaUpload;
|
|
4218
4470
|
exports.useGenerateCaptions = useGenerateCaptions;
|
|
4219
4471
|
exports.useStudioManager = useStudioManager;
|
|
4220
4472
|
//# sourceMappingURL=index.js.map
|