@edifice.io/react 2.3.1-develop-b2school.20250916133741 → 2.3.1-develop-b2school-actualites.20250916153920
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/Divider/Divider.d.ts +5 -0
- package/dist/components/Divider/Divider.js +21 -0
- package/dist/components/Divider/index.d.ts +1 -0
- package/dist/components/SeparatedInfo/SeparatedInfo.d.ts +6 -0
- package/dist/components/SeparatedInfo/SeparatedInfo.js +13 -0
- package/dist/components/SeparatedInfo/index.d.ts +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/editor.js +38 -34
- package/dist/icons.js +288 -286
- package/dist/index.js +4 -0
- package/dist/modules/editor/components/Editor/EditorPreview.d.ts +14 -0
- package/dist/modules/editor/components/Editor/EditorPreview.js +56 -0
- package/dist/modules/editor/components/Editor/EditorPreviewSkeleton.d.ts +8 -0
- package/dist/modules/editor/components/Editor/EditorPreviewSkeleton.js +24 -0
- package/dist/modules/editor/components/Editor/index.d.ts +2 -0
- package/dist/modules/icons/components/IconClockAlert.d.ts +7 -0
- package/dist/modules/icons/components/IconClockAlert.js +17 -0
- package/dist/modules/icons/components/index.d.ts +1 -0
- package/dist/modules/multimedia/VideoRecorder/VideoRecorder.js +145 -36
- package/package.json +6 -6
- package/dist/modules/multimedia/VideoRecorder/VideoRecorderToolbar.d.ts +0 -18
- package/dist/modules/multimedia/VideoRecorder/VideoRecorderToolbar.js +0 -96
- package/dist/modules/multimedia/VideoRecorder/useCameras.d.ts +0 -10
- package/dist/modules/multimedia/VideoRecorder/useCameras.js +0 -86
package/dist/index.js
CHANGED
|
@@ -98,12 +98,14 @@ import { default as default97 } from "./modules/multimedia/VideoRecorder/VideoRe
|
|
|
98
98
|
import { default as default98 } from "./modules/multimedia/Workspace/Workspace.js";
|
|
99
99
|
import { default as default99 } from "./modules/multimedia/WorkspaceFolders/WorkspaceFolders.js";
|
|
100
100
|
import { AccessiblePalette, DefaultPalette } from "./components/ColorPicker/ColorPalette.js";
|
|
101
|
+
import { Divider } from "./components/Divider/Divider.js";
|
|
101
102
|
import { DropzoneContext, useDropzoneContext } from "./components/Dropzone/DropzoneContext.js";
|
|
102
103
|
import { Column, Grid } from "./components/Grid/Grid.js";
|
|
103
104
|
import { Layout } from "./components/Layout/Layout.js";
|
|
104
105
|
import { List } from "./components/List/List.js";
|
|
105
106
|
import { Menu } from "./components/Menu/components/Menu.js";
|
|
106
107
|
import { Popover, PopoverBody, PopoverFooter, PopoverHeader } from "./components/Popover/Popover.js";
|
|
108
|
+
import { SeparatedInfo } from "./components/SeparatedInfo/SeparatedInfo.js";
|
|
107
109
|
import { Tabs } from "./components/Tabs/components/Tabs.js";
|
|
108
110
|
import { Toolbar } from "./components/Toolbar/Toolbar.js";
|
|
109
111
|
import { useTreeSortable } from "./components/Tree/hooks/useTreeSortable.js";
|
|
@@ -148,6 +150,7 @@ export {
|
|
|
148
150
|
default18 as Combobox,
|
|
149
151
|
default83 as ConfirmModal,
|
|
150
152
|
DefaultPalette,
|
|
153
|
+
Divider,
|
|
151
154
|
DndTree,
|
|
152
155
|
default19 as Dropdown,
|
|
153
156
|
default20 as Dropzone,
|
|
@@ -192,6 +195,7 @@ export {
|
|
|
192
195
|
default35 as SearchBar,
|
|
193
196
|
default13 as SearchButton,
|
|
194
197
|
default36 as Select,
|
|
198
|
+
SeparatedInfo,
|
|
195
199
|
default89 as ShareBlog,
|
|
196
200
|
default88 as ShareModal,
|
|
197
201
|
default44 as SortableTree,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor component properties
|
|
3
|
+
*/
|
|
4
|
+
export interface EditorPreviewProps {
|
|
5
|
+
/** Rich content to render. */
|
|
6
|
+
content: string;
|
|
7
|
+
/** Display with or without a border */
|
|
8
|
+
variant?: 'outline' | 'ghost';
|
|
9
|
+
onDetailClick?: () => void;
|
|
10
|
+
onMediaClick?: () => void;
|
|
11
|
+
maxMediaDisplayed?: number;
|
|
12
|
+
}
|
|
13
|
+
declare const EditorPreview: ({ content, variant, onDetailClick, onMediaClick, maxMediaDisplayed, }: EditorPreviewProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default EditorPreview;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { getThumbnail } from "@edifice.io/utilities";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import Image from "../../../../components/Image/Image.js";
|
|
7
|
+
const EditorPreview = ({
|
|
8
|
+
content,
|
|
9
|
+
variant = "outline",
|
|
10
|
+
onDetailClick,
|
|
11
|
+
onMediaClick,
|
|
12
|
+
maxMediaDisplayed = 3
|
|
13
|
+
}) => {
|
|
14
|
+
const {
|
|
15
|
+
t
|
|
16
|
+
} = useTranslation(), [summaryContent, setSummaryContent] = useState(""), [medias, setMedias] = useState([]), borderClass = clsx(variant === "outline" && "border rounded-3 py-12 px-16"), hasMediaCallback = onDetailClick || onMediaClick, handleMediaClick = (e) => {
|
|
17
|
+
onMediaClick && (e.stopPropagation(), onMediaClick());
|
|
18
|
+
};
|
|
19
|
+
return useEffect(() => {
|
|
20
|
+
const contentHTML = content;
|
|
21
|
+
if (contentHTML) {
|
|
22
|
+
const doc = new DOMParser().parseFromString(contentHTML, "text/html"), mediaElements = Array.from(doc.querySelectorAll("img, video, iframe, audio, embed"));
|
|
23
|
+
setMedias(mediaElements.filter((el) => el.tagName.toLowerCase() === "img").map((el) => {
|
|
24
|
+
const image = el;
|
|
25
|
+
return image.src ? {
|
|
26
|
+
url: getThumbnail(image.src, 0, 300),
|
|
27
|
+
alt: image.alt
|
|
28
|
+
} : {
|
|
29
|
+
url: "",
|
|
30
|
+
alt: ""
|
|
31
|
+
};
|
|
32
|
+
})), mediaElements.forEach((el) => {
|
|
33
|
+
var _a;
|
|
34
|
+
return (_a = el.parentNode) == null ? void 0 : _a.removeChild(el);
|
|
35
|
+
}), setSummaryContent(doc.body.textContent || "");
|
|
36
|
+
}
|
|
37
|
+
}, [content]), /* @__PURE__ */ jsxs("div", { className: borderClass, "data-testid": "editor-preview", onClick: onDetailClick, tabIndex: onDetailClick ? -1 : void 0, role: onDetailClick ? "button" : void 0, children: [
|
|
38
|
+
/* @__PURE__ */ jsx("div", { className: "flex-fill text-truncate text-truncate-2 post-preview-content overflow-hidden", children: summaryContent }),
|
|
39
|
+
/* @__PURE__ */ jsx("div", { onClick: handleMediaClick, tabIndex: hasMediaCallback ? -1 : void 0, role: hasMediaCallback ? "button" : void 0, className: "d-flex align-items-center justify-content-center gap-24 px-32 pt-16", children: medias.slice(0, maxMediaDisplayed).map((media, index) => /* @__PURE__ */ jsxs("div", { className: clsx("position-relative col-12 col-md-4 ", {
|
|
40
|
+
"d-none d-md-block": index >= 1
|
|
41
|
+
}), style: {
|
|
42
|
+
maxWidth: "150px"
|
|
43
|
+
}, children: [
|
|
44
|
+
/* @__PURE__ */ jsx(Image, { alt: media.alt, objectFit: "cover", ratio: "16", className: "rounded", src: media.url, sizes: "" }),
|
|
45
|
+
(index === 0 || index === 2) && medias.length - (index + 1) > 0 && /* @__PURE__ */ jsx("div", { className: clsx("position-absolute top-0 bottom-0 start-0 end-0 d-flex justify-content-center align-items-center rounded text-light bg-dark bg-opacity-50", {
|
|
46
|
+
"d-flex d-md-none": index === 0,
|
|
47
|
+
"d-none d-md-flex": index === 2
|
|
48
|
+
}), children: t("editor.preview.moreMedia", {
|
|
49
|
+
mediaCount: medias.length - (index + 1)
|
|
50
|
+
}) })
|
|
51
|
+
] }, media.url)) })
|
|
52
|
+
] });
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
EditorPreview as default
|
|
56
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor component properties
|
|
3
|
+
*/
|
|
4
|
+
export interface EditorPreviewSkeletonProps {
|
|
5
|
+
variant?: 'outline' | 'ghost';
|
|
6
|
+
}
|
|
7
|
+
declare const EditorPreview: ({ variant }: EditorPreviewSkeletonProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default EditorPreview;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import TextSkeleton from "../../../../components/Skeleton/TextSkeleton.js";
|
|
4
|
+
import Image from "../../../../components/Image/Image.js";
|
|
5
|
+
const EditorPreview = ({
|
|
6
|
+
variant = "outline"
|
|
7
|
+
}) => {
|
|
8
|
+
const borderClass = clsx(variant === "outline" && "border rounded-3"), contentClass = clsx("mt-16", variant === "outline" && "my-12 mx-16");
|
|
9
|
+
return /* @__PURE__ */ jsx("div", { className: borderClass, "data-testid": "editor-preview", children: /* @__PURE__ */ jsxs("div", { className: contentClass, children: [
|
|
10
|
+
/* @__PURE__ */ jsx(TextSkeleton, { className: "col-12" }),
|
|
11
|
+
/* @__PURE__ */ jsx(TextSkeleton, { className: "col-12" }),
|
|
12
|
+
/* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-center gap-24 px-32 pt-16", children: [
|
|
13
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
14
|
+
maxWidth: "150px"
|
|
15
|
+
}, className: "col-12 col-md-4", children: /* @__PURE__ */ jsx(Image, { alt: "", objectFit: "cover", ratio: "16", className: "rounded placeholder", src: "", sizes: "" }) }),
|
|
16
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
17
|
+
maxWidth: "150px"
|
|
18
|
+
}, className: "col-12 col-md-4", children: /* @__PURE__ */ jsx(Image, { alt: "", objectFit: "cover", ratio: "16", className: "rounded placeholder", src: "", sizes: "" }) })
|
|
19
|
+
] })
|
|
20
|
+
] }) });
|
|
21
|
+
};
|
|
22
|
+
export {
|
|
23
|
+
EditorPreview as default
|
|
24
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export * from './Editor';
|
|
2
2
|
export { default as Editor } from './Editor';
|
|
3
|
+
export { default as EditorPreview } from './EditorPreview';
|
|
4
|
+
export { default as EditorPreviewSkeleton } from './EditorPreviewSkeleton';
|
|
3
5
|
export { default as EditorSkeleton } from './EditorSkeleton';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SVGProps } from 'react';
|
|
2
|
+
interface SVGRProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
titleId?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const SvgIconClockAlert: ({ title, titleId, ...props }: SVGProps<SVGSVGElement> & SVGRProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default SvgIconClockAlert;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
const SvgIconClockAlert = ({
|
|
3
|
+
title,
|
|
4
|
+
titleId,
|
|
5
|
+
...props
|
|
6
|
+
}) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", fill: "none", viewBox: "0 0 24 24", "aria-hidden": "true", "aria-labelledby": titleId, ...props, children: [
|
|
7
|
+
title ? /* @__PURE__ */ jsx("title", { id: titleId, children: title }) : null,
|
|
8
|
+
/* @__PURE__ */ jsxs("g", { fill: "currentColor", clipPath: "url(#icon-clock-alert_svg__a)", children: [
|
|
9
|
+
/* @__PURE__ */ jsx("path", { d: "M0 10.075C0 4.51 4.51 0 10.075 0c4.573 0 8.431 3.046 9.663 7.217a1 1 0 0 1-1.918.566A8.075 8.075 0 1 0 7.783 17.82a1 1 0 0 1-.566 1.918C3.046 18.506 0 14.648 0 10.075" }),
|
|
10
|
+
/* @__PURE__ */ jsx("path", { d: "M10.075 4.108a1 1 0 0 1 1 1v5.43a1 1 0 0 1-.357.767L7.83 13.728a1 1 0 1 1-1.286-1.532l2.53-2.123V5.108a1 1 0 0 1 1-1M17 13.3a1 1 0 0 1 1 1v2.2a1 1 0 1 1-2 0v-2.2a1 1 0 0 1 1-1M17 18.4a1 1 0 1 0 0 2h.006a1 1 0 1 0 0-2z" }),
|
|
11
|
+
/* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M17 10a7 7 0 1 0 0 14 7 7 0 0 0 0-14m-5 7a5 5 0 1 1 10 0 5 5 0 0 1-10 0", clipRule: "evenodd" })
|
|
12
|
+
] }),
|
|
13
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: "icon-clock-alert_svg__a", children: /* @__PURE__ */ jsx("path", { fill: "#fff", d: "M0 0h24v24H0z" }) }) })
|
|
14
|
+
] });
|
|
15
|
+
export {
|
|
16
|
+
SvgIconClockAlert as default
|
|
17
|
+
};
|
|
@@ -24,6 +24,7 @@ export { default as IconCantoo } from './IconCantoo';
|
|
|
24
24
|
export { default as IconCenter } from './IconCenter';
|
|
25
25
|
export { default as IconCheck } from './IconCheck';
|
|
26
26
|
export { default as IconChecklist } from './IconChecklist';
|
|
27
|
+
export { default as IconClockAlert } from './IconClockAlert';
|
|
27
28
|
export { default as IconClock } from './IconClock';
|
|
28
29
|
export { default as IconCloseFullScreen } from './IconCloseFullScreen';
|
|
29
30
|
export { default as IconClose } from './IconClose';
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useState, useRef, useImperativeHandle, useEffect, useCallback } from "react";
|
|
3
3
|
import { odeServices } from "@edifice.io/client";
|
|
4
4
|
import { getBestSupportedMimeType, convertMsToMS } from "@edifice.io/utilities";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
|
+
import SvgIconPause from "../../icons/components/IconPause.js";
|
|
7
|
+
import SvgIconPlayFilled from "../../icons/components/IconPlayFilled.js";
|
|
8
|
+
import SvgIconRecordStop from "../../icons/components/IconRecordStop.js";
|
|
6
9
|
import SvgIconRecordVideo from "../../icons/components/IconRecordVideo.js";
|
|
7
10
|
import SvgIconRecord from "../../icons/components/IconRecord.js";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
11
|
+
import SvgIconRefresh from "../../icons/components/IconRefresh.js";
|
|
12
|
+
import SvgIconSave from "../../icons/components/IconSave.js";
|
|
10
13
|
import useUpload from "../../../hooks/useUpload/useUpload.js";
|
|
14
|
+
import useBrowserInfo from "../../../hooks/useBrowserInfo/useBrowserInfo.js";
|
|
11
15
|
import FormControl from "../../../components/Form/FormControl.js";
|
|
12
16
|
import Label from "../../../components/Label/Label.js";
|
|
13
17
|
import Select from "../../../components/Select/Select.js";
|
|
14
18
|
import LoadingScreen from "../../../components/LoadingScreen/LoadingScreen.js";
|
|
15
|
-
|
|
19
|
+
import { Toolbar } from "../../../components/Toolbar/Toolbar.js";
|
|
20
|
+
const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
16
21
|
appCode,
|
|
17
22
|
caption,
|
|
18
23
|
onSuccess,
|
|
@@ -20,14 +25,17 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
20
25
|
onRecordUpdated,
|
|
21
26
|
hideSaveAction = !1
|
|
22
27
|
}, ref) => {
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const [maxDuration, setMaxDuration] = useState(18e4), [inputDevices, setInputDevices] = useState([]), [recording, setRecording] = useState(!1), [recorded, setRecorded] = useState(!1), [playing, setPlaying] = useState(!1), [saving, setSaving] = useState(!1), [saved, setSaved] = useState(!1), [mediaStreamConstraints, setMediaStreamConstraints] = useState({
|
|
29
|
+
audio: !0,
|
|
30
|
+
video: {
|
|
31
|
+
facingMode: "environment",
|
|
32
|
+
aspectRatio: VIDEO_WIDTH / VIDEO_HEIGHT
|
|
33
|
+
}
|
|
34
|
+
}), [stream, setStream] = useState(), [mimeType, setMimeType] = useState(""), [recordedChunks, setRecordedChunks] = useState([]), [recordedVideo, setRecordedVideo] = useState(), [recordedTime, setRecordedTime] = useState(0), [playedTime, setPlayedTime] = useState(0), videoRef = useRef(null), recorderRef = useRef(null), {
|
|
29
35
|
uploadBlob
|
|
30
|
-
} = useUpload(void 0, appCode)
|
|
36
|
+
} = useUpload(void 0, appCode), {
|
|
37
|
+
device
|
|
38
|
+
} = useBrowserInfo(navigator.userAgent);
|
|
31
39
|
useImperativeHandle(ref, () => ({
|
|
32
40
|
save: handleSave
|
|
33
41
|
}));
|
|
@@ -35,23 +43,10 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
35
43
|
t
|
|
36
44
|
} = useTranslation();
|
|
37
45
|
useEffect(() => {
|
|
38
|
-
initMaxDuration();
|
|
39
|
-
}, [])
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const videoConfResponse = await odeServices.video().getVideoConf();
|
|
43
|
-
setMaxDuration(videoConfResponse.maxDuration * 60 * 1e3);
|
|
44
|
-
} catch {
|
|
45
|
-
setMaxDuration(3 * 60 * 1e3);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
try {
|
|
50
|
-
videoRef.current && (videoRef.current.src && (window.URL.revokeObjectURL(videoRef.current.src), videoRef.current.src = ""), stream && (videoRef.current.srcObject = stream, videoRef.current.autoplay = !0, videoRef.current.volume = 1, videoRef.current.muted = !0));
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.error(err);
|
|
53
|
-
}
|
|
54
|
-
}, [stream]), useEffect(() => {
|
|
46
|
+
initMaxDuration(), initInputDevices();
|
|
47
|
+
}, []), useEffect(() => (stream || enableStream(mediaStreamConstraints), () => {
|
|
48
|
+
stream && stream.getTracks().forEach((track) => track.stop());
|
|
49
|
+
}), [stream]), useEffect(() => {
|
|
55
50
|
if (recordedChunks.length && !recording && videoRef.current) {
|
|
56
51
|
const finalVideo = new Blob(recordedChunks, {
|
|
57
52
|
type: mimeType
|
|
@@ -81,7 +76,40 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
81
76
|
};
|
|
82
77
|
}
|
|
83
78
|
}, [playing]);
|
|
84
|
-
const
|
|
79
|
+
const initMaxDuration = async () => {
|
|
80
|
+
const videoConfResponse = await odeServices.video().getVideoConf();
|
|
81
|
+
setMaxDuration((videoConfResponse.maxDuration ?? 3) * 60 * 1e3);
|
|
82
|
+
}, initInputDevices = async () => {
|
|
83
|
+
const videoDevices = (await navigator.mediaDevices.enumerateDevices()).filter((device2) => device2.kind === "videoinput");
|
|
84
|
+
switch (device.type) {
|
|
85
|
+
case "mobile":
|
|
86
|
+
case "tablet": {
|
|
87
|
+
const backCamera = {
|
|
88
|
+
deviceId: "environment",
|
|
89
|
+
label: t("video.back.camera"),
|
|
90
|
+
groupId: "",
|
|
91
|
+
kind: "videoinput"
|
|
92
|
+
}, frontCamera = {
|
|
93
|
+
deviceId: "user",
|
|
94
|
+
label: t("video.front.camera"),
|
|
95
|
+
groupId: "",
|
|
96
|
+
kind: "videoinput"
|
|
97
|
+
};
|
|
98
|
+
(videoDevices == null ? void 0 : videoDevices.length) > 1 ? setInputDevices([backCamera, frontCamera]) : setInputDevices([backCamera]);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
setInputDevices(videoDevices);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}, enableStream = async (mediaStreamConstraints2) => {
|
|
106
|
+
try {
|
|
107
|
+
const mediaStream = await navigator.mediaDevices.getUserMedia(mediaStreamConstraints2);
|
|
108
|
+
setStream(mediaStream), videoRef.current && (videoRef.current.src && (window.URL.revokeObjectURL(videoRef.current.src), videoRef.current.src = ""), videoRef.current.srcObject = mediaStream, videoRef.current.autoplay = !0, videoRef.current.volume = 1, videoRef.current.muted = !0);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(err);
|
|
111
|
+
}
|
|
112
|
+
}, handleRecord = useCallback(() => {
|
|
85
113
|
setRecording(!0), videoRef && videoRef.current && (videoRef.current.muted = !0);
|
|
86
114
|
const mimeType2 = getBestSupportedMimeType();
|
|
87
115
|
setMimeType(mimeType2), stream && (recorderRef.current = new MediaRecorder(stream, {
|
|
@@ -98,7 +126,7 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
98
126
|
var _a, _b;
|
|
99
127
|
videoRef && videoRef.current && (videoRef.current.muted = !1), playing ? ((_b = videoRef == null ? void 0 : videoRef.current) == null || _b.pause(), setPlaying(!1)) : ((_a = videoRef == null ? void 0 : videoRef.current) == null || _a.play(), setPlaying(!0));
|
|
100
128
|
}, [playing]), handleReset = () => {
|
|
101
|
-
setRecorded(!1), setRecording(!1), setPlaying(!1), setSaved(!1), setRecordedTime(0), setRecordedChunks([]), setRecordedVideo(void 0),
|
|
129
|
+
setRecorded(!1), setRecording(!1), setPlaying(!1), setSaved(!1), setRecordedTime(0), setRecordedChunks([]), setRecordedVideo(void 0), enableStream(mediaStreamConstraints), onRecordUpdated && onRecordUpdated();
|
|
102
130
|
}, handleSave = async () => {
|
|
103
131
|
var _a;
|
|
104
132
|
if ((_a = videoRef == null ? void 0 : videoRef.current) == null || _a.pause(), setSaving(!0), !recordedVideo) {
|
|
@@ -113,14 +141,95 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
113
141
|
onError("Error while uploading video"), setSaving(!1), setSaved(!0);
|
|
114
142
|
}, handleEnded = () => {
|
|
115
143
|
setPlaying(!1), setPlayedTime(0), videoRef.current && (videoRef.current.currentTime = 0);
|
|
116
|
-
}, handleInputDeviceChange =
|
|
144
|
+
}, handleInputDeviceChange = (option) => {
|
|
117
145
|
var _a;
|
|
118
146
|
const selectedDevice = inputDevices.find((inputDevice) => inputDevice.label === option);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
147
|
+
let mediaStreamConstraints2 = {};
|
|
148
|
+
selectedDevice != null && selectedDevice.deviceId ? ((selectedDevice == null ? void 0 : selectedDevice.deviceId) === "environment" || (selectedDevice == null ? void 0 : selectedDevice.deviceId) === "user" ? mediaStreamConstraints2 = {
|
|
149
|
+
audio: !0,
|
|
150
|
+
video: {
|
|
151
|
+
aspectRatio: VIDEO_WIDTH / VIDEO_HEIGHT,
|
|
152
|
+
facingMode: selectedDevice == null ? void 0 : selectedDevice.deviceId
|
|
153
|
+
}
|
|
154
|
+
} : mediaStreamConstraints2 = {
|
|
155
|
+
audio: !0,
|
|
156
|
+
video: {
|
|
157
|
+
aspectRatio: VIDEO_WIDTH / VIDEO_HEIGHT,
|
|
158
|
+
deviceId: selectedDevice.deviceId
|
|
159
|
+
}
|
|
160
|
+
}, setMediaStreamConstraints(mediaStreamConstraints2), stream && (((_a = recorderRef.current) == null ? void 0 : _a.state) === "recording" && (recorderRef.current.requestData(), recorderRef.current.stop()), stream.getTracks().forEach((track) => track.stop()), setStream(void 0)), enableStream(mediaStreamConstraints2)) : console.error("Selected input device id is null");
|
|
161
|
+
};
|
|
162
|
+
useEffect(() => {
|
|
122
163
|
recordedTime >= maxDuration && handleStop();
|
|
123
|
-
}, [recordedTime, handleStop])
|
|
164
|
+
}, [recordedTime, handleStop]);
|
|
165
|
+
const toolbarItems = [{
|
|
166
|
+
type: "icon",
|
|
167
|
+
name: "record",
|
|
168
|
+
props: {
|
|
169
|
+
icon: /* @__PURE__ */ jsx(SvgIconRecord, { color: recording || recorded ? "" : "red" }),
|
|
170
|
+
color: "danger",
|
|
171
|
+
disabled: recording || recorded || saving,
|
|
172
|
+
onClick: handleRecord,
|
|
173
|
+
"aria-label": t("bbm.video.record.start")
|
|
174
|
+
},
|
|
175
|
+
tooltip: t("bbm.video.record.start")
|
|
176
|
+
}, {
|
|
177
|
+
type: "icon",
|
|
178
|
+
name: "stop",
|
|
179
|
+
props: {
|
|
180
|
+
icon: /* @__PURE__ */ jsx(SvgIconRecordStop, {}),
|
|
181
|
+
disabled: !recording || recorded || saving,
|
|
182
|
+
onClick: handleStop,
|
|
183
|
+
"aria-label": t("bbm.video.record.stop")
|
|
184
|
+
},
|
|
185
|
+
tooltip: t("bbm.video.record.stop")
|
|
186
|
+
}, {
|
|
187
|
+
type: "icon",
|
|
188
|
+
name: "play",
|
|
189
|
+
visibility: playing ? "hide" : "show",
|
|
190
|
+
props: {
|
|
191
|
+
icon: /* @__PURE__ */ jsx(SvgIconPlayFilled, {}),
|
|
192
|
+
disabled: !recorded || saving,
|
|
193
|
+
onClick: handlePlayPause,
|
|
194
|
+
"aria-label": t("bbm.video.play.start")
|
|
195
|
+
},
|
|
196
|
+
tooltip: t("bbm.video.play.start")
|
|
197
|
+
}, {
|
|
198
|
+
type: "icon",
|
|
199
|
+
name: "pause",
|
|
200
|
+
visibility: playing ? "show" : "hide",
|
|
201
|
+
props: {
|
|
202
|
+
icon: /* @__PURE__ */ jsx(SvgIconPause, {}),
|
|
203
|
+
disabled: !recorded || saving,
|
|
204
|
+
onClick: handlePlayPause,
|
|
205
|
+
"aria-label": t("bbm.video.play.pause")
|
|
206
|
+
},
|
|
207
|
+
tooltip: t("bbm.video.play.pause")
|
|
208
|
+
}, {
|
|
209
|
+
type: "divider"
|
|
210
|
+
}, {
|
|
211
|
+
type: "icon",
|
|
212
|
+
name: "reset",
|
|
213
|
+
props: {
|
|
214
|
+
icon: /* @__PURE__ */ jsx(SvgIconRefresh, {}),
|
|
215
|
+
disabled: !recorded || saving,
|
|
216
|
+
onClick: handleReset,
|
|
217
|
+
"aria-label": t("bbm.video.record.reset")
|
|
218
|
+
},
|
|
219
|
+
tooltip: t("bbm.video.record.reset")
|
|
220
|
+
}, {
|
|
221
|
+
type: "icon",
|
|
222
|
+
name: "save",
|
|
223
|
+
visibility: hideSaveAction ? "hide" : "show",
|
|
224
|
+
props: {
|
|
225
|
+
icon: /* @__PURE__ */ jsx(SvgIconSave, {}),
|
|
226
|
+
disabled: !recorded || saving || saved,
|
|
227
|
+
onClick: handleSave,
|
|
228
|
+
"aria-label": t("bbm.video.record.save")
|
|
229
|
+
},
|
|
230
|
+
tooltip: t("bbm.video.record.save")
|
|
231
|
+
}];
|
|
232
|
+
return /* @__PURE__ */ jsxs("div", { className: "video-recorder d-flex flex-fill flex-column align-items-center pb-8", children: [
|
|
124
233
|
/* @__PURE__ */ jsx("div", { className: "video-recorder-caption d-none d-md-block", children: caption }),
|
|
125
234
|
inputDevices.length > 1 && /* @__PURE__ */ jsx("div", { className: "video-recorder-devices mb-12", children: /* @__PURE__ */ jsxs(FormControl, { id: "selectInputDevice", children: [
|
|
126
235
|
/* @__PURE__ */ jsx(Label, { className: "d-none d-md-block", children: t("bbm.video.record.select.devices.label") }),
|
|
@@ -146,7 +255,7 @@ const VideoRecorder = /* @__PURE__ */ forwardRef(({
|
|
|
146
255
|
] })
|
|
147
256
|
] })
|
|
148
257
|
] }),
|
|
149
|
-
stream && /* @__PURE__ */ jsx(
|
|
258
|
+
stream && /* @__PURE__ */ jsx(Toolbar, { items: toolbarItems, className: "position-absolute bottom-0 start-50 bg-white" })
|
|
150
259
|
] }),
|
|
151
260
|
saving && /* @__PURE__ */ jsx(LoadingScreen, { position: !1, caption: t("bbm.video.save.loader.caption") })
|
|
152
261
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edifice.io/react",
|
|
3
|
-
"version": "2.3.1-develop-b2school.
|
|
3
|
+
"version": "2.3.1-develop-b2school-actualites.20250916153920",
|
|
4
4
|
"description": "Edifice React Library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -130,9 +130,9 @@
|
|
|
130
130
|
"react-slugify": "^3.0.3",
|
|
131
131
|
"swiper": "^10.1.0",
|
|
132
132
|
"ua-parser-js": "^1.0.36",
|
|
133
|
-
"@edifice.io/bootstrap": "2.3.1-develop-b2school.
|
|
134
|
-
"@edifice.io/tiptap-extensions": "2.3.1-develop-b2school.
|
|
135
|
-
"@edifice.io/utilities": "2.3.1-develop-b2school.
|
|
133
|
+
"@edifice.io/bootstrap": "2.3.1-develop-b2school-actualites.20250916153920",
|
|
134
|
+
"@edifice.io/tiptap-extensions": "2.3.1-develop-b2school-actualites.20250916153920",
|
|
135
|
+
"@edifice.io/utilities": "2.3.1-develop-b2school-actualites.20250916153920"
|
|
136
136
|
},
|
|
137
137
|
"devDependencies": {
|
|
138
138
|
"@babel/plugin-transform-react-pure-annotations": "^7.23.3",
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
"vite": "^5.4.11",
|
|
164
164
|
"vite-plugin-dts": "^4.1.0",
|
|
165
165
|
"vite-tsconfig-paths": "^5.0.1",
|
|
166
|
-
"@edifice.io/client": "2.3.1-develop-b2school.
|
|
167
|
-
"@edifice.io/config": "2.3.1-develop-b2school.
|
|
166
|
+
"@edifice.io/client": "2.3.1-develop-b2school-actualites.20250916153920",
|
|
167
|
+
"@edifice.io/config": "2.3.1-develop-b2school-actualites.20250916153920"
|
|
168
168
|
},
|
|
169
169
|
"peerDependencies": {
|
|
170
170
|
"@react-spring/web": "^9.7.5",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { WorkspaceElement } from '@edifice.io/client';
|
|
2
|
-
export interface VideoRecorderToolbarProps {
|
|
3
|
-
playing: boolean;
|
|
4
|
-
recording: boolean;
|
|
5
|
-
recorded: boolean;
|
|
6
|
-
saving: boolean;
|
|
7
|
-
saved: boolean;
|
|
8
|
-
hideSaveAction: boolean;
|
|
9
|
-
handleRecord: () => void;
|
|
10
|
-
handleStop: () => void;
|
|
11
|
-
handlePlayPause: () => void;
|
|
12
|
-
handleReset: () => void;
|
|
13
|
-
handleSave: () => void;
|
|
14
|
-
}
|
|
15
|
-
export interface VideoRecorderRef {
|
|
16
|
-
save: () => Promise<WorkspaceElement | undefined>;
|
|
17
|
-
}
|
|
18
|
-
export declare const VideoRecorderToolbar: ({ playing, recording, recorded, saving, saved, hideSaveAction, handleRecord, handleStop, handlePlayPause, handleReset, handleSave, }: VideoRecorderToolbarProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useTranslation } from "react-i18next";
|
|
3
|
-
import SvgIconPause from "../../icons/components/IconPause.js";
|
|
4
|
-
import SvgIconPlayFilled from "../../icons/components/IconPlayFilled.js";
|
|
5
|
-
import SvgIconRecordStop from "../../icons/components/IconRecordStop.js";
|
|
6
|
-
import SvgIconRecord from "../../icons/components/IconRecord.js";
|
|
7
|
-
import SvgIconRefresh from "../../icons/components/IconRefresh.js";
|
|
8
|
-
import SvgIconSave from "../../icons/components/IconSave.js";
|
|
9
|
-
import { Toolbar } from "../../../components/Toolbar/Toolbar.js";
|
|
10
|
-
const VideoRecorderToolbar = ({
|
|
11
|
-
playing,
|
|
12
|
-
recording,
|
|
13
|
-
recorded,
|
|
14
|
-
saving,
|
|
15
|
-
saved,
|
|
16
|
-
hideSaveAction,
|
|
17
|
-
handleRecord,
|
|
18
|
-
handleStop,
|
|
19
|
-
handlePlayPause,
|
|
20
|
-
handleReset,
|
|
21
|
-
handleSave
|
|
22
|
-
}) => {
|
|
23
|
-
const {
|
|
24
|
-
t
|
|
25
|
-
} = useTranslation(), toolbarItems = [{
|
|
26
|
-
type: "icon",
|
|
27
|
-
name: "record",
|
|
28
|
-
props: {
|
|
29
|
-
icon: /* @__PURE__ */ jsx(SvgIconRecord, { color: recording || recorded ? "" : "red" }),
|
|
30
|
-
color: "danger",
|
|
31
|
-
disabled: recording || recorded || saving,
|
|
32
|
-
onClick: handleRecord,
|
|
33
|
-
"aria-label": t("bbm.video.record.start")
|
|
34
|
-
},
|
|
35
|
-
tooltip: t("bbm.video.record.start")
|
|
36
|
-
}, {
|
|
37
|
-
type: "icon",
|
|
38
|
-
name: "stop",
|
|
39
|
-
props: {
|
|
40
|
-
icon: /* @__PURE__ */ jsx(SvgIconRecordStop, {}),
|
|
41
|
-
disabled: !recording || recorded || saving,
|
|
42
|
-
onClick: handleStop,
|
|
43
|
-
"aria-label": t("bbm.video.record.stop")
|
|
44
|
-
},
|
|
45
|
-
tooltip: t("bbm.video.record.stop")
|
|
46
|
-
}, {
|
|
47
|
-
type: "icon",
|
|
48
|
-
name: "play",
|
|
49
|
-
visibility: playing ? "hide" : "show",
|
|
50
|
-
props: {
|
|
51
|
-
icon: /* @__PURE__ */ jsx(SvgIconPlayFilled, {}),
|
|
52
|
-
disabled: !recorded || saving,
|
|
53
|
-
onClick: handlePlayPause,
|
|
54
|
-
"aria-label": t("bbm.video.play.start")
|
|
55
|
-
},
|
|
56
|
-
tooltip: t("bbm.video.play.start")
|
|
57
|
-
}, {
|
|
58
|
-
type: "icon",
|
|
59
|
-
name: "pause",
|
|
60
|
-
visibility: playing ? "show" : "hide",
|
|
61
|
-
props: {
|
|
62
|
-
icon: /* @__PURE__ */ jsx(SvgIconPause, {}),
|
|
63
|
-
disabled: !recorded || saving,
|
|
64
|
-
onClick: handlePlayPause,
|
|
65
|
-
"aria-label": t("bbm.video.play.pause")
|
|
66
|
-
},
|
|
67
|
-
tooltip: t("bbm.video.play.pause")
|
|
68
|
-
}, {
|
|
69
|
-
type: "divider"
|
|
70
|
-
}, {
|
|
71
|
-
type: "icon",
|
|
72
|
-
name: "reset",
|
|
73
|
-
props: {
|
|
74
|
-
icon: /* @__PURE__ */ jsx(SvgIconRefresh, {}),
|
|
75
|
-
disabled: !recorded || saving,
|
|
76
|
-
onClick: handleReset,
|
|
77
|
-
"aria-label": t("bbm.video.record.reset")
|
|
78
|
-
},
|
|
79
|
-
tooltip: t("bbm.video.record.reset")
|
|
80
|
-
}, {
|
|
81
|
-
type: "icon",
|
|
82
|
-
name: "save",
|
|
83
|
-
visibility: hideSaveAction ? "hide" : "show",
|
|
84
|
-
props: {
|
|
85
|
-
icon: /* @__PURE__ */ jsx(SvgIconSave, {}),
|
|
86
|
-
disabled: !recorded || saving || saved,
|
|
87
|
-
onClick: handleSave,
|
|
88
|
-
"aria-label": t("bbm.video.record.save")
|
|
89
|
-
},
|
|
90
|
-
tooltip: t("bbm.video.record.save")
|
|
91
|
-
}];
|
|
92
|
-
return /* @__PURE__ */ jsx(Toolbar, { items: toolbarItems, className: "position-absolute bottom-0 start-50 bg-white" });
|
|
93
|
-
};
|
|
94
|
-
export {
|
|
95
|
-
VideoRecorderToolbar
|
|
96
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export declare function useCameras(): {
|
|
2
|
-
/** Readonly list (array) of available video input devices. */
|
|
3
|
-
inputDevices: MediaDeviceInfo[];
|
|
4
|
-
/** Select which input video device to use. */
|
|
5
|
-
setPreferedDevice: (device?: MediaDeviceInfo) => void;
|
|
6
|
-
/** The current video stream. */
|
|
7
|
-
stream: MediaStream | undefined;
|
|
8
|
-
/** Start a video stream from the default or prefered device. */
|
|
9
|
-
restartStream: () => void;
|
|
10
|
-
};
|