@edifice.io/react 2.3.1-develop-b2school-actualites.20250916153920 → 2.3.1-develop-b2school.20250918153251

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,14 +98,12 @@ 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";
102
101
  import { DropzoneContext, useDropzoneContext } from "./components/Dropzone/DropzoneContext.js";
103
102
  import { Column, Grid } from "./components/Grid/Grid.js";
104
103
  import { Layout } from "./components/Layout/Layout.js";
105
104
  import { List } from "./components/List/List.js";
106
105
  import { Menu } from "./components/Menu/components/Menu.js";
107
106
  import { Popover, PopoverBody, PopoverFooter, PopoverHeader } from "./components/Popover/Popover.js";
108
- import { SeparatedInfo } from "./components/SeparatedInfo/SeparatedInfo.js";
109
107
  import { Tabs } from "./components/Tabs/components/Tabs.js";
110
108
  import { Toolbar } from "./components/Toolbar/Toolbar.js";
111
109
  import { useTreeSortable } from "./components/Tree/hooks/useTreeSortable.js";
@@ -150,7 +148,6 @@ export {
150
148
  default18 as Combobox,
151
149
  default83 as ConfirmModal,
152
150
  DefaultPalette,
153
- Divider,
154
151
  DndTree,
155
152
  default19 as Dropdown,
156
153
  default20 as Dropzone,
@@ -195,7 +192,6 @@ export {
195
192
  default35 as SearchBar,
196
193
  default13 as SearchButton,
197
194
  default36 as Select,
198
- SeparatedInfo,
199
195
  default89 as ShareBlog,
200
196
  default88 as ShareModal,
201
197
  default44 as SortableTree,
@@ -1,5 +1,3 @@
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';
5
3
  export { default as EditorSkeleton } from './EditorSkeleton';
@@ -24,7 +24,6 @@ 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';
28
27
  export { default as IconClock } from './IconClock';
29
28
  export { default as IconCloseFullScreen } from './IconCloseFullScreen';
30
29
  export { default as IconClose } from './IconClose';
@@ -1,23 +1,18 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
1
+ import { jsxs, jsx, 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";
9
6
  import SvgIconRecordVideo from "../../icons/components/IconRecordVideo.js";
10
7
  import SvgIconRecord from "../../icons/components/IconRecord.js";
11
- import SvgIconRefresh from "../../icons/components/IconRefresh.js";
12
- import SvgIconSave from "../../icons/components/IconSave.js";
8
+ import { useCameras } from "./useCameras.js";
9
+ import { VideoRecorderToolbar } from "./VideoRecorderToolbar.js";
13
10
  import useUpload from "../../../hooks/useUpload/useUpload.js";
14
- import useBrowserInfo from "../../../hooks/useBrowserInfo/useBrowserInfo.js";
15
11
  import FormControl from "../../../components/Form/FormControl.js";
16
12
  import Label from "../../../components/Label/Label.js";
17
13
  import Select from "../../../components/Select/Select.js";
18
14
  import LoadingScreen from "../../../components/LoadingScreen/LoadingScreen.js";
19
- import { Toolbar } from "../../../components/Toolbar/Toolbar.js";
20
- const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwardRef(({
15
+ const VideoRecorder = /* @__PURE__ */ forwardRef(({
21
16
  appCode,
22
17
  caption,
23
18
  onSuccess,
@@ -25,17 +20,14 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
25
20
  onRecordUpdated,
26
21
  hideSaveAction = !1
27
22
  }, ref) => {
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), {
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), {
35
29
  uploadBlob
36
- } = useUpload(void 0, appCode), {
37
- device
38
- } = useBrowserInfo(navigator.userAgent);
30
+ } = useUpload(void 0, appCode);
39
31
  useImperativeHandle(ref, () => ({
40
32
  save: handleSave
41
33
  }));
@@ -43,10 +35,23 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
43
35
  t
44
36
  } = useTranslation();
45
37
  useEffect(() => {
46
- initMaxDuration(), initInputDevices();
47
- }, []), useEffect(() => (stream || enableStream(mediaStreamConstraints), () => {
48
- stream && stream.getTracks().forEach((track) => track.stop());
49
- }), [stream]), 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 = ""), videoRef.current.srcObject instanceof MediaStream && (videoRef.current.srcObject = null), stream && (videoRef.current.srcObject = stream, videoRef.current.autoplay = !0, videoRef.current.volume = 1, videoRef.current.muted = !0, videoRef.current.load()));
51
+ } catch (err) {
52
+ console.error(err);
53
+ }
54
+ }, [stream]), useEffect(() => {
50
55
  if (recordedChunks.length && !recording && videoRef.current) {
51
56
  const finalVideo = new Blob(recordedChunks, {
52
57
  type: mimeType
@@ -76,40 +81,7 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
76
81
  };
77
82
  }
78
83
  }, [playing]);
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(() => {
84
+ const handleRecord = useCallback(() => {
113
85
  setRecording(!0), videoRef && videoRef.current && (videoRef.current.muted = !0);
114
86
  const mimeType2 = getBestSupportedMimeType();
115
87
  setMimeType(mimeType2), stream && (recorderRef.current = new MediaRecorder(stream, {
@@ -126,7 +98,7 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
126
98
  var _a, _b;
127
99
  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));
128
100
  }, [playing]), handleReset = () => {
129
- setRecorded(!1), setRecording(!1), setPlaying(!1), setSaved(!1), setRecordedTime(0), setRecordedChunks([]), setRecordedVideo(void 0), enableStream(mediaStreamConstraints), onRecordUpdated && onRecordUpdated();
101
+ setRecorded(!1), setRecording(!1), setPlaying(!1), setSaved(!1), setRecordedTime(0), setRecordedChunks([]), setRecordedVideo(void 0), restartStream(), onRecordUpdated && onRecordUpdated();
130
102
  }, handleSave = async () => {
131
103
  var _a;
132
104
  if ((_a = videoRef == null ? void 0 : videoRef.current) == null || _a.pause(), setSaving(!0), !recordedVideo) {
@@ -144,92 +116,11 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
144
116
  }, handleInputDeviceChange = (option) => {
145
117
  var _a;
146
118
  const selectedDevice = inputDevices.find((inputDevice) => inputDevice.label === option);
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");
119
+ ((_a = recorderRef.current) == null ? void 0 : _a.state) === "recording" && (recorderRef.current.requestData(), recorderRef.current.stop()), setPreferedDevice(selectedDevice);
161
120
  };
162
- useEffect(() => {
121
+ return useEffect(() => {
163
122
  recordedTime >= maxDuration && 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: [
123
+ }, [recordedTime, handleStop]), /* @__PURE__ */ jsxs("div", { className: "video-recorder d-flex flex-fill flex-column align-items-center pb-8", children: [
233
124
  /* @__PURE__ */ jsx("div", { className: "video-recorder-caption d-none d-md-block", children: caption }),
234
125
  inputDevices.length > 1 && /* @__PURE__ */ jsx("div", { className: "video-recorder-devices mb-12", children: /* @__PURE__ */ jsxs(FormControl, { id: "selectInputDevice", children: [
235
126
  /* @__PURE__ */ jsx(Label, { className: "d-none d-md-block", children: t("bbm.video.record.select.devices.label") }),
@@ -255,7 +146,7 @@ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16, VideoRecorder = /* @__PURE__ */ forwar
255
146
  ] })
256
147
  ] })
257
148
  ] }),
258
- stream && /* @__PURE__ */ jsx(Toolbar, { items: toolbarItems, className: "position-absolute bottom-0 start-50 bg-white" })
149
+ stream && /* @__PURE__ */ jsx(VideoRecorderToolbar, { playing, recording, recorded, saving, saved, hideSaveAction, handleRecord, handleStop, handlePlayPause, handleReset, handleSave })
259
150
  ] }),
260
151
  saving && /* @__PURE__ */ jsx(LoadingScreen, { position: !1, caption: t("bbm.video.save.loader.caption") })
261
152
  ] });
@@ -0,0 +1,18 @@
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;
@@ -0,0 +1,96 @@
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
+ };
@@ -0,0 +1,10 @@
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
+ };
@@ -0,0 +1,86 @@
1
+ import { useState, useEffect } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import useBrowserInfo from "../../../hooks/useBrowserInfo/useBrowserInfo.js";
4
+ const VIDEO_HEIGHT = 9, VIDEO_WIDTH = 16;
5
+ function useCameras() {
6
+ const {
7
+ device
8
+ } = useBrowserInfo(navigator.userAgent), {
9
+ t
10
+ } = useTranslation(), [inputDevices, setInputDevices] = useState([]), [mediaStreamConstraints, setMediaStreamConstraints] = useState({
11
+ audio: !0,
12
+ video: !0
13
+ }), [stream, setStream] = useState();
14
+ async function getVideoInputDevices() {
15
+ return (await navigator.mediaDevices.enumerateDevices()).filter((device2) => device2.kind === "videoinput");
16
+ }
17
+ const enableStream = async (constraints) => {
18
+ try {
19
+ const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
20
+ setStream(mediaStream);
21
+ } catch (err) {
22
+ console.error(err);
23
+ }
24
+ }, restartStream = () => {
25
+ stream == null || stream.getTracks().forEach((track) => track.stop()), enableStream(mediaStreamConstraints);
26
+ }, setPreferedDevice = (device2) => {
27
+ let constraints = {};
28
+ device2 != null && device2.deviceId ? (device2.deviceId === "environment" || device2.deviceId === "user" ? constraints = {
29
+ audio: !0,
30
+ video: {
31
+ aspectRatio: VIDEO_WIDTH / VIDEO_HEIGHT,
32
+ facingMode: device2 == null ? void 0 : device2.deviceId
33
+ }
34
+ } : constraints = {
35
+ audio: !0,
36
+ video: {
37
+ aspectRatio: VIDEO_WIDTH / VIDEO_HEIGHT,
38
+ deviceId: {
39
+ exact: device2.deviceId
40
+ }
41
+ }
42
+ }, setMediaStreamConstraints(constraints)) : console.error("Selected input device id is null");
43
+ };
44
+ return useEffect(() => {
45
+ restartStream();
46
+ }, [mediaStreamConstraints]), useEffect(() => {
47
+ async function initInputDevices() {
48
+ await enableStream(mediaStreamConstraints);
49
+ const videoDevices = await getVideoInputDevices();
50
+ switch (device.type) {
51
+ case "mobile":
52
+ case "tablet": {
53
+ const backCamera = {
54
+ deviceId: "environment",
55
+ label: t("video.back.camera"),
56
+ groupId: "",
57
+ kind: "videoinput"
58
+ }, frontCamera = {
59
+ deviceId: "user",
60
+ label: t("video.front.camera"),
61
+ groupId: "",
62
+ kind: "videoinput"
63
+ };
64
+ (videoDevices == null ? void 0 : videoDevices.length) > 1 ? setInputDevices([backCamera, frontCamera]) : setInputDevices([backCamera]);
65
+ break;
66
+ }
67
+ default:
68
+ setInputDevices(videoDevices);
69
+ break;
70
+ }
71
+ }
72
+ initInputDevices();
73
+ }, []), {
74
+ /** Readonly list (array) of available video input devices. */
75
+ inputDevices,
76
+ /** Select which input video device to use. */
77
+ setPreferedDevice,
78
+ /** The current video stream. */
79
+ stream,
80
+ /** Start a video stream from the default or prefered device. */
81
+ restartStream
82
+ };
83
+ }
84
+ export {
85
+ useCameras
86
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.3.1-develop-b2school-actualites.20250916153920",
3
+ "version": "2.3.1-develop-b2school.20250918153251",
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-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"
133
+ "@edifice.io/bootstrap": "2.3.1-develop-b2school.20250918153251",
134
+ "@edifice.io/tiptap-extensions": "2.3.1-develop-b2school.20250918153251",
135
+ "@edifice.io/utilities": "2.3.1-develop-b2school.20250918153251"
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-actualites.20250916153920",
167
- "@edifice.io/config": "2.3.1-develop-b2school-actualites.20250916153920"
166
+ "@edifice.io/client": "2.3.1-develop-b2school.20250918153251",
167
+ "@edifice.io/config": "2.3.1-develop-b2school.20250918153251"
168
168
  },
169
169
  "peerDependencies": {
170
170
  "@react-spring/web": "^9.7.5",
@@ -1,5 +0,0 @@
1
- import { ReactNode } from 'react';
2
- export declare function Divider({ children, color, }: {
3
- children: ReactNode[];
4
- color: string;
5
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,21 +0,0 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import Flex from "../Flex/Flex.js";
3
- function Divider({
4
- children,
5
- color = "var(--edifice-gray-400)"
6
- }) {
7
- return /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "around", gap: "16", wrap: "nowrap", className: "flex-fill", children: [
8
- /* @__PURE__ */ jsx("hr", { className: "divider m-12 ms-0 flex-fill", style: {
9
- borderColor: color
10
- } }),
11
- /* @__PURE__ */ jsxs(Flex, { gap: "12", align: "center", justify: "around", children: [
12
- ...children
13
- ] }),
14
- /* @__PURE__ */ jsx("hr", { className: "divider m-12 me-0 flex-fill", style: {
15
- borderColor: color
16
- } })
17
- ] });
18
- }
19
- export {
20
- Divider
21
- };
@@ -1 +0,0 @@
1
- export * from './Divider';
@@ -1,6 +0,0 @@
1
- import { ReactNode } from 'react';
2
- export type SeparatedInfoProps = {
3
- children: ReactNode[];
4
- className?: string;
5
- };
6
- export declare function SeparatedInfo({ children, className }: SeparatedInfoProps): import("react/jsx-runtime").JSX.Element;
@@ -1,13 +0,0 @@
1
- import { jsxs } from "react/jsx-runtime";
2
- import Flex from "../Flex/Flex.js";
3
- function SeparatedInfo({
4
- children,
5
- className
6
- }) {
7
- return /* @__PURE__ */ jsxs(Flex, { direction: "row", className: `separated-info ${className}`, children: [
8
- ...children
9
- ] });
10
- }
11
- export {
12
- SeparatedInfo
13
- };
@@ -1 +0,0 @@
1
- export * from './SeparatedInfo';
@@ -1,14 +0,0 @@
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;
@@ -1,56 +0,0 @@
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
- };