@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/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 { jsxs, jsx, Fragment } from "react/jsx-runtime";
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 { useCameras } from "./useCameras.js";
9
- import { VideoRecorderToolbar } from "./VideoRecorderToolbar.js";
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
- const VideoRecorder = /* @__PURE__ */ forwardRef(({
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
- inputDevices,
25
- setPreferedDevice,
26
- restartStream,
27
- stream
28
- } = useCameras(), [maxDuration, setMaxDuration] = useState(18e4), [recording, setRecording] = useState(!1), [recorded, setRecorded] = useState(!1), [playing, setPlaying] = useState(!1), [saving, setSaving] = useState(!1), [saved, setSaved] = useState(!1), [mimeType, setMimeType] = useState(""), [recordedChunks, setRecordedChunks] = useState([]), [recordedVideo, setRecordedVideo] = useState(), [recordedTime, setRecordedTime] = useState(0), [playedTime, setPlayedTime] = useState(0), videoRef = useRef(null), recorderRef = useRef(null), {
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
- async function initMaxDuration() {
41
- try {
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 handleRecord = useCallback(() => {
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), restartStream(), onRecordUpdated && onRecordUpdated();
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 = useCallback((option) => {
144
+ }, handleInputDeviceChange = (option) => {
117
145
  var _a;
118
146
  const selectedDevice = inputDevices.find((inputDevice) => inputDevice.label === option);
119
- ((_a = recorderRef.current) == null ? void 0 : _a.state) === "recording" && (recorderRef.current.requestData(), recorderRef.current.stop()), setPreferedDevice(selectedDevice);
120
- }, [inputDevices, stream]);
121
- return useEffect(() => {
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]), /* @__PURE__ */ jsxs("div", { className: "video-recorder d-flex flex-fill flex-column align-items-center pb-8", children: [
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(VideoRecorderToolbar, { playing, recording, recorded, saving, saved, hideSaveAction, handleRecord, handleStop, handlePlayPause, handleReset, handleSave })
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.20250916133741",
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.20250916133741",
134
- "@edifice.io/tiptap-extensions": "2.3.1-develop-b2school.20250916133741",
135
- "@edifice.io/utilities": "2.3.1-develop-b2school.20250916133741"
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.20250916133741",
167
- "@edifice.io/config": "2.3.1-develop-b2school.20250916133741"
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
- };