@edifice.io/react 2.5.9 → 2.5.10-develop-pedago.20260216173040

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.
Files changed (107) hide show
  1. package/README.md +5 -0
  2. package/dist/_virtual/isSameOrAfter.js +4 -0
  3. package/dist/_virtual/isToday.js +4 -0
  4. package/dist/components/AddAttachments/AddAttachments.d.ts +18 -0
  5. package/dist/components/AddAttachments/AddAttachments.js +87 -0
  6. package/dist/components/AddAttachments/components/AddAttachmentToWorkspaceModal.d.ts +9 -0
  7. package/dist/components/AddAttachments/components/AddAttachmentToWorkspaceModal.js +41 -0
  8. package/dist/components/AddAttachments/components/SingleAttachment.d.ts +13 -0
  9. package/dist/components/AddAttachments/components/SingleAttachment.js +27 -0
  10. package/dist/components/AddAttachments/index.d.ts +2 -0
  11. package/dist/components/AddAttachments/models/attachment.d.ts +9 -0
  12. package/dist/components/Badge/Badge.d.ts +7 -1
  13. package/dist/components/Badge/Badge.js +14 -11
  14. package/dist/components/DatePicker/DatePicker.d.ts +57 -0
  15. package/dist/components/DatePicker/DatePicker.js +6 -3
  16. package/dist/components/Layout/components/WidgetApps.js +2 -2
  17. package/dist/components/MediaViewer/MediaViewer.d.ts +17 -0
  18. package/dist/components/MediaViewer/MediaViewer.js +36 -0
  19. package/dist/components/MediaViewer/MediaWrapper.d.ts +7 -0
  20. package/dist/components/MediaViewer/MediaWrapper.js +72 -0
  21. package/dist/components/MediaViewer/PdfViewer.d.ts +4 -0
  22. package/dist/components/MediaViewer/PdfViewer.js +26 -0
  23. package/dist/components/MediaViewer/ToolbarViewer.d.ts +7 -0
  24. package/dist/components/MediaViewer/ToolbarViewer.js +41 -0
  25. package/dist/components/MediaViewer/ToolbarZoom.d.ts +4 -0
  26. package/dist/components/MediaViewer/ToolbarZoom.js +19 -0
  27. package/dist/components/MediaViewer/index.d.ts +2 -0
  28. package/dist/components/Modal/Modal.d.ts +4 -0
  29. package/dist/components/Modal/Modal.js +13 -12
  30. package/dist/components/PromotionCard/PromotionCard.d.ts +74 -0
  31. package/dist/components/PromotionCard/PromotionCard.js +31 -0
  32. package/dist/components/PromotionCard/PromotionCardBody.d.ts +10 -0
  33. package/dist/components/PromotionCard/PromotionCardBody.js +15 -0
  34. package/dist/components/PromotionCard/PromotionCardDescription.d.ts +9 -0
  35. package/dist/components/PromotionCard/PromotionCardDescription.js +12 -0
  36. package/dist/components/PromotionCard/PromotionCardFooter.d.ts +9 -0
  37. package/dist/components/PromotionCard/PromotionCardFooter.js +12 -0
  38. package/dist/components/PromotionCard/PromotionCardHeader.d.ts +11 -0
  39. package/dist/components/PromotionCard/PromotionCardHeader.js +17 -0
  40. package/dist/components/PromotionCard/PromotionCardIcon.d.ts +10 -0
  41. package/dist/components/PromotionCard/PromotionCardIcon.js +15 -0
  42. package/dist/components/PromotionCard/PromotionCardTitle.d.ts +9 -0
  43. package/dist/components/PromotionCard/PromotionCardTitle.js +12 -0
  44. package/dist/components/PromotionCard/index.d.ts +2 -0
  45. package/dist/components/SmartEllipsis/SmartEllipsis.d.ts +5 -0
  46. package/dist/components/SmartEllipsis/SmartEllipsis.js +21 -0
  47. package/dist/components/SmartEllipsis/index.d.ts +2 -0
  48. package/dist/components/index.d.ts +3 -0
  49. package/dist/hooks/useConf/useConf.d.ts +1 -1
  50. package/dist/hooks/useConversation/useConversation.js +3 -1
  51. package/dist/hooks/useDate/useDate.d.ts +5 -1
  52. package/dist/hooks/useDate/useDate.js +18 -2
  53. package/dist/hooks/useDropzone/useDropzone.js +21 -16
  54. package/dist/hooks/useEdificeIcons/useEdificeIcons.d.ts +1 -0
  55. package/dist/hooks/useEdificeIcons/useEdificeIcons.js +5 -0
  56. package/dist/hooks/useSession/useSession.d.ts +1 -1
  57. package/dist/hooks/useZoom/index.d.ts +1 -0
  58. package/dist/hooks/useZoom/useZoom.d.ts +7 -0
  59. package/dist/hooks/useZoom/useZoom.js +14 -0
  60. package/dist/icons.js +366 -350
  61. package/dist/index.js +147 -140
  62. package/dist/modules/audience/ViewsCounter.d.ts +3 -17
  63. package/dist/modules/audience/ViewsCounter.js +9 -7
  64. package/dist/modules/comments/components/Comment.js +4 -4
  65. package/dist/modules/comments/components/CommentDate.js +7 -10
  66. package/dist/modules/comments/components/CommentDeleted.js +1 -1
  67. package/dist/modules/comments/components/CommentForm.d.ts +1 -1
  68. package/dist/modules/comments/components/CommentForm.js +6 -6
  69. package/dist/modules/comments/components/CommentTitle.js +1 -1
  70. package/dist/modules/comments/provider/CommentProvider.js +4 -4
  71. package/dist/modules/comments/types.d.ts +3 -1
  72. package/dist/modules/icons/components/IconAdjustSettings.d.ts +7 -0
  73. package/dist/modules/icons/components/IconAdjustSettings.js +12 -0
  74. package/dist/modules/icons/components/IconAiFill.d.ts +7 -0
  75. package/dist/modules/icons/components/IconAiFill.js +12 -0
  76. package/dist/modules/icons/components/IconCalendarEdit.d.ts +7 -0
  77. package/dist/modules/icons/components/IconCalendarEdit.js +12 -0
  78. package/dist/modules/icons/components/IconCollect.d.ts +7 -0
  79. package/dist/modules/icons/components/IconCollect.js +12 -0
  80. package/dist/modules/icons/components/IconExercizerAi.d.ts +7 -0
  81. package/dist/modules/icons/components/IconExercizerAi.js +14 -0
  82. package/dist/modules/icons/components/IconLabel.d.ts +7 -0
  83. package/dist/modules/icons/components/IconLabel.js +12 -0
  84. package/dist/modules/icons/components/IconSubmission.d.ts +7 -0
  85. package/dist/modules/icons/components/IconSubmission.js +12 -0
  86. package/dist/modules/icons/components/IconTeacher.d.ts +7 -0
  87. package/dist/modules/icons/components/IconTeacher.js +12 -0
  88. package/dist/modules/icons/components/index.d.ts +8 -0
  89. package/dist/modules/modals/OnboardingModal/OnboardingModal.js +5 -5
  90. package/dist/modules/modals/ResourceModal/ResourceModal.d.ts +1 -1
  91. package/dist/modules/modals/ResourceModal/hooks/useUpdateMutation.d.ts +1 -1
  92. package/dist/modules/modals/ShareModal/ShareResources.d.ts +4 -1
  93. package/dist/modules/modals/ShareModal/ShareResources.js +9 -5
  94. package/dist/modules/modals/ShareModal/apps/ShareBlog.d.ts +1 -1
  95. package/dist/modules/modals/ShareModal/hooks/useShareMutation.d.ts +1 -1
  96. package/dist/modules/multimedia/FileCard/FileCard.js +1 -1
  97. package/dist/node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/plugin/isSameOrAfter.js +18 -0
  98. package/dist/node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/plugin/isToday.js +19 -0
  99. package/dist/providers/EdificeClientProvider/EdificeClientProvider.context.d.ts +1 -1
  100. package/dist/types/color.d.ts +3 -0
  101. package/dist/utilities/mime-types/index.d.ts +1 -0
  102. package/dist/utilities/mime-types/mime-types-utils.d.ts +1 -0
  103. package/dist/utilities/mime-types/mime-types-utils.js +4 -0
  104. package/dist/utilities/react-query/react-query-utils.d.ts +1 -1
  105. package/package.json +7 -6
  106. package/dist/modules/comments/components/CommentHeader.d.ts +0 -3
  107. package/dist/modules/comments/components/CommentHeader.js +0 -8
package/README.md CHANGED
@@ -105,6 +105,11 @@ export interface ButtonProps {
105
105
  export * from './Button';
106
106
  ```
107
107
 
108
+ ## Adding Icons
109
+
110
+ https://edifice-community.atlassian.net/wiki/spaces/ODE/pages/4371611649/Overview#Ajout-de-l%E2%80%99ic%C3%B4ne
111
+
108
112
  ## Dev
109
113
 
110
114
  You can build your component using `Storybook`. See [README](../../docs//README.md)
115
+
@@ -0,0 +1,4 @@
1
+ var isSameOrAfter = { exports: {} };
2
+ export {
3
+ isSameOrAfter as __module
4
+ };
@@ -0,0 +1,4 @@
1
+ var isToday = { exports: {} };
2
+ export {
3
+ isToday as __module
4
+ };
@@ -0,0 +1,18 @@
1
+ import { Attachment } from './models/attachment';
2
+ export interface AddAttachmentsProps {
3
+ attachments: Attachment[];
4
+ onFilesSelected: (files: File[]) => void;
5
+ onRemoveAttachment: (attachmentId: string) => void;
6
+ editMode?: boolean;
7
+ isMutating?: boolean;
8
+ onCopyToWorkspace?: (attachments: Attachment[], folderId: string) => Promise<boolean>;
9
+ /** Si fourni, chaque pièce jointe affiche un bouton télécharger avec l'URL retournée. */
10
+ getDownloadUrl?: (attachmentId: string) => string;
11
+ /** Si fourni et qu'il y a plusieurs pièces jointes, affiche un bouton « télécharger tout ». */
12
+ downloadAllUrl?: string;
13
+ }
14
+ export declare const AddAttachments: {
15
+ ({ attachments, onFilesSelected, onRemoveAttachment, editMode, isMutating, onCopyToWorkspace, getDownloadUrl, downloadAllUrl, }: AddAttachmentsProps): import("react/jsx-runtime").JSX.Element | null;
16
+ displayName: string;
17
+ };
18
+ export default AddAttachments;
@@ -0,0 +1,87 @@
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import clsx from "clsx";
3
+ import { useRef, useState, useEffect } from "react";
4
+ import { useTranslation } from "react-i18next";
5
+ import SvgIconDelete from "../../modules/icons/components/IconDelete.js";
6
+ import SvgIconDownload from "../../modules/icons/components/IconDownload.js";
7
+ import SvgIconFolderAdd from "../../modules/icons/components/IconFolderAdd.js";
8
+ import SvgIconPlus from "../../modules/icons/components/IconPlus.js";
9
+ import { AddAttachmentToWorkspaceModal } from "./components/AddAttachmentToWorkspaceModal.js";
10
+ import { SingleAttachment } from "./components/SingleAttachment.js";
11
+ import Flex from "../Flex/Flex.js";
12
+ import IconButton from "../Button/IconButton.js";
13
+ import Button from "../Button/Button.js";
14
+ function fileToAttachment(file) {
15
+ return {
16
+ id: `${file.name}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
17
+ charset: "UTF-8",
18
+ contentTransferEncoding: "binary",
19
+ contentType: file.type || "application/octet-stream",
20
+ filename: file.name,
21
+ name: file.name,
22
+ size: file.size
23
+ };
24
+ }
25
+ const AddAttachments = ({
26
+ attachments,
27
+ onFilesSelected,
28
+ onRemoveAttachment,
29
+ editMode = !1,
30
+ isMutating = !1,
31
+ onCopyToWorkspace,
32
+ getDownloadUrl,
33
+ downloadAllUrl
34
+ }) => {
35
+ const {
36
+ t
37
+ } = useTranslation(), inputRef = useRef(null), [optimisticAttachments, setOptimisticAttachments] = useState([]), [attachmentsToAddToWorkspace, setAttachmentsToAddToWorkspace] = useState(void 0), prevAttachmentsLengthRef = useRef(attachments.length), displayedAttachments = [...attachments, ...optimisticAttachments];
38
+ if (useEffect(() => {
39
+ attachments.length > prevAttachmentsLengthRef.current && setOptimisticAttachments([]), prevAttachmentsLengthRef.current = attachments.length;
40
+ }, [attachments.length]), !editMode && !displayedAttachments.length) return null;
41
+ const resetInputValue = () => {
42
+ inputRef.current && (inputRef.current.value = "");
43
+ }, handleAttachClick = () => {
44
+ var _a;
45
+ return (_a = inputRef == null ? void 0 : inputRef.current) == null ? void 0 : _a.click();
46
+ }, handleFileChange = (event) => {
47
+ const files = Array.from(event.target.files ?? []);
48
+ if (files.length > 0) {
49
+ onFilesSelected(files);
50
+ const newOptimistic = files.map(fileToAttachment);
51
+ setOptimisticAttachments((prev) => [...prev, ...newOptimistic]);
52
+ }
53
+ resetInputValue();
54
+ }, handleDetachAllClick = () => {
55
+ setOptimisticAttachments([]), attachments.forEach((attachment) => {
56
+ onRemoveAttachment(attachment.id);
57
+ }), resetInputValue();
58
+ }, handleDetachClick = (attachmentId) => {
59
+ optimisticAttachments.some((attachment) => attachment.id === attachmentId) ? setOptimisticAttachments((prev) => prev.filter((attachment) => attachment.id !== attachmentId)) : onRemoveAttachment(attachmentId), resetInputValue();
60
+ }, handleCopyToWorkspace = (attachments2) => {
61
+ setAttachmentsToAddToWorkspace(attachments2);
62
+ }, className = clsx("bg-gray-200 rounded px-12 py-8 message-attachments align-self-start gap-8 d-flex flex-column mw-100", {
63
+ "border add-attachments-edit mx-16": editMode
64
+ });
65
+ return /* @__PURE__ */ jsxs("div", { className, "data-drag-handle": !0, children: [
66
+ !!displayedAttachments.length && /* @__PURE__ */ jsxs(Fragment, { children: [
67
+ /* @__PURE__ */ jsxs(Flex, { direction: "row", align: "center", justify: "between", className: "border-bottom", children: [
68
+ /* @__PURE__ */ jsx("span", { className: "caption fw-bold my-8", children: t("attachments") }),
69
+ displayedAttachments.length > 1 && /* @__PURE__ */ jsxs("div", { children: [
70
+ onCopyToWorkspace && /* @__PURE__ */ jsx(IconButton, { title: t("conversation.copy.all.toworkspace"), color: "tertiary", type: "button", icon: /* @__PURE__ */ jsx(SvgIconFolderAdd, {}), onClick: () => handleCopyToWorkspace(displayedAttachments), variant: "ghost" }),
71
+ downloadAllUrl && /* @__PURE__ */ jsx("a", { href: downloadAllUrl, download: !0, children: /* @__PURE__ */ jsx(IconButton, { title: t("download.all.attachment"), color: "tertiary", type: "button", icon: /* @__PURE__ */ jsx(SvgIconDownload, {}), variant: "ghost" }) }),
72
+ editMode && /* @__PURE__ */ jsx(IconButton, { title: t("remove.all.attachment"), color: "danger", type: "button", icon: /* @__PURE__ */ jsx(SvgIconDelete, {}), variant: "ghost", onClick: handleDetachAllClick, disabled: isMutating })
73
+ ] })
74
+ ] }),
75
+ /* @__PURE__ */ jsx("ul", { className: "d-flex gap-8 flex-column list-unstyled m-0", children: displayedAttachments.map((attachment) => /* @__PURE__ */ jsx("li", { className: "mw-100", children: /* @__PURE__ */ jsx(SingleAttachment, { attachment, editMode, onDelete: handleDetachClick, onCopyToWorkspace: onCopyToWorkspace ? (attachment2) => handleCopyToWorkspace([attachment2]) : void 0, getDownloadUrl, disabled: isMutating }) }, attachment.id)) })
76
+ ] }),
77
+ editMode && /* @__PURE__ */ jsxs(Fragment, { children: [
78
+ /* @__PURE__ */ jsx(Button, { color: "secondary", variant: "ghost", isLoading: isMutating, onClick: handleAttachClick, disabled: isMutating, className: "align-self-start", leftIcon: /* @__PURE__ */ jsx(SvgIconPlus, {}), children: t("add.attachment") }),
79
+ /* @__PURE__ */ jsx("input", { ref: inputRef, multiple: !0, type: "file", name: "attachment-input", id: "attachment-input", onChange: handleFileChange, hidden: !0 })
80
+ ] }),
81
+ onCopyToWorkspace && !!attachmentsToAddToWorkspace && /* @__PURE__ */ jsx(AddAttachmentToWorkspaceModal, { isOpen: !0, onModalClose: () => setAttachmentsToAddToWorkspace(void 0), attachments: attachmentsToAddToWorkspace, onCopyToWorkspace })
82
+ ] });
83
+ };
84
+ export {
85
+ AddAttachments,
86
+ AddAttachments as default
87
+ };
@@ -0,0 +1,9 @@
1
+ import { Attachment } from '../models/attachment';
2
+ interface AddAttachmentToWorkspaceModalProps {
3
+ attachments: Attachment[];
4
+ onModalClose: () => void;
5
+ isOpen?: boolean;
6
+ onCopyToWorkspace: (attachments: Attachment[], folderId: string) => Promise<boolean>;
7
+ }
8
+ export declare function AddAttachmentToWorkspaceModal({ attachments, isOpen, onModalClose, onCopyToWorkspace, }: AddAttachmentToWorkspaceModalProps): import('react').ReactPortal;
9
+ export {};
@@ -0,0 +1,41 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { toast } from "react-hot-toast";
5
+ import { useTranslation } from "react-i18next";
6
+ import Modal from "../../Modal/Modal.js";
7
+ import WorkspaceFolders from "../../../modules/multimedia/WorkspaceFolders/WorkspaceFolders.js";
8
+ import Button from "../../Button/Button.js";
9
+ function AddAttachmentToWorkspaceModal({
10
+ attachments,
11
+ isOpen = !1,
12
+ onModalClose,
13
+ onCopyToWorkspace
14
+ }) {
15
+ const {
16
+ t
17
+ } = useTranslation(), [selectedFolderIdToCopyFile, setSelectedFolderIdToCopyFile] = useState(void 0), [isLoading, setIsLoading] = useState(!1), [disabled, setDisabled] = useState(!1), handleFolderSelected = (folderId, canCopyFileInto) => {
18
+ setSelectedFolderIdToCopyFile(canCopyFileInto ? folderId : void 0);
19
+ }, handleAddAttachmentToWorkspace = async () => {
20
+ if (selectedFolderIdToCopyFile === void 0) return;
21
+ setIsLoading(!0), await onCopyToWorkspace(attachments, selectedFolderIdToCopyFile) ? onModalClose() : toast.error(t("attachments.add.to.folder.modal.error")), setIsLoading(!1);
22
+ };
23
+ return useEffect(() => {
24
+ setDisabled(selectedFolderIdToCopyFile === void 0);
25
+ }, [selectedFolderIdToCopyFile]), /* @__PURE__ */ createPortal(/* @__PURE__ */ jsxs(Modal, { isOpen, onModalClose, id: "add-attachment-to-workspace-modal", size: "md", children: [
26
+ /* @__PURE__ */ jsx(Modal.Header, { onModalClose, children: t("attachments.add.to.folder.modal.title") }),
27
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs("div", { className: "d-flex flex-column gap-12", children: [
28
+ /* @__PURE__ */ jsx("p", { children: t("attachments.add.to.folder.modal.description", {
29
+ count: attachments.length
30
+ }) }),
31
+ /* @__PURE__ */ jsx(WorkspaceFolders, { onFolderSelected: handleFolderSelected })
32
+ ] }) }),
33
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
34
+ /* @__PURE__ */ jsx(Button, { type: "button", color: "tertiary", variant: "ghost", onClick: onModalClose, children: t("attachments.add.to.folder.modal.cancel") }),
35
+ /* @__PURE__ */ jsx(Button, { color: "primary", variant: "filled", onClick: handleAddAttachmentToWorkspace, disabled: isLoading || disabled, isLoading, children: t("attachments.add.to.folder.modal.add") })
36
+ ] })
37
+ ] }), document.getElementById("portal"));
38
+ }
39
+ export {
40
+ AddAttachmentToWorkspaceModal
41
+ };
@@ -0,0 +1,13 @@
1
+ import { Attachment } from '../models/attachment';
2
+ export interface SingleAttachmentProps {
3
+ attachment: Attachment;
4
+ onDelete: (attachmentId: string) => void;
5
+ editMode?: boolean;
6
+ /** Si fourni, affiche le bouton « copier vers l'espace » et appelle ce callback au clic. */
7
+ onCopyToWorkspace?: (attachment: Attachment) => void;
8
+ /** Si fourni, affiche le bouton télécharger avec l'URL retournée. */
9
+ getDownloadUrl?: (attachmentId: string) => string;
10
+ /** Désactive les boutons d'action (ex. pendant une suppression). */
11
+ disabled?: boolean;
12
+ }
13
+ export declare function SingleAttachment({ attachment, onDelete, editMode, onCopyToWorkspace, getDownloadUrl, disabled, }: SingleAttachmentProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import SvgIconDelete from "../../../modules/icons/components/IconDelete.js";
3
+ import SvgIconDownload from "../../../modules/icons/components/IconDownload.js";
4
+ import SvgIconFolderAdd from "../../../modules/icons/components/IconFolderAdd.js";
5
+ import { useTranslation } from "react-i18next";
6
+ import Attachment from "../../Attachment/Attachment.js";
7
+ import IconButton from "../../Button/IconButton.js";
8
+ function SingleAttachment({
9
+ attachment,
10
+ onDelete,
11
+ editMode = !1,
12
+ onCopyToWorkspace,
13
+ getDownloadUrl,
14
+ disabled = !1
15
+ }) {
16
+ const {
17
+ t
18
+ } = useTranslation(), downloadUrl = getDownloadUrl == null ? void 0 : getDownloadUrl(attachment.id);
19
+ return /* @__PURE__ */ jsx(Attachment, { name: attachment.filename, options: /* @__PURE__ */ jsxs(Fragment, { children: [
20
+ onCopyToWorkspace && /* @__PURE__ */ jsx(IconButton, { title: t("conversation.copy.toworkspace"), color: "tertiary", type: "button", icon: /* @__PURE__ */ jsx(SvgIconFolderAdd, {}), variant: "ghost", onClick: () => onCopyToWorkspace(attachment), disabled }),
21
+ downloadUrl !== void 0 && /* @__PURE__ */ jsx("a", { href: downloadUrl, download: !0, children: /* @__PURE__ */ jsx(IconButton, { title: t("download.attachment"), color: "tertiary", type: "button", icon: /* @__PURE__ */ jsx(SvgIconDownload, {}), variant: "ghost", disabled }) }),
22
+ editMode && /* @__PURE__ */ jsx(IconButton, { title: t("remove.attachment"), color: "danger", type: "button", icon: /* @__PURE__ */ jsx(SvgIconDelete, {}), variant: "ghost", onClick: () => onDelete(attachment.id), disabled })
23
+ ] }) });
24
+ }
25
+ export {
26
+ SingleAttachment
27
+ };
@@ -0,0 +1,2 @@
1
+ export { default as AddAttachments } from './AddAttachments';
2
+ export * from './AddAttachments';
@@ -0,0 +1,9 @@
1
+ export type Attachment = {
2
+ id: string;
3
+ charset: string;
4
+ contentTransferEncoding: string;
5
+ contentType: string;
6
+ filename: string;
7
+ name: string;
8
+ size: number;
9
+ };
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { UserProfile } from '@edifice.io/client';
2
+ import { IWebApp, UserProfile } from '@edifice.io/client';
3
3
  export type BadgeRef = HTMLSpanElement;
4
4
  /** Badge variant : notification */
5
5
  export type NotificationBadgeVariant = {
@@ -31,10 +31,16 @@ export type LinkBadgeVariant = {
31
31
  * Beta Badge is used to indicate that a feature is in beta phase.
32
32
  * The color prop allows to customize the badge color to match the app color.
33
33
  * Defaults to black if not provided.
34
+ * Beta Badge has a fixed text 'BÊTA' unless children is provided.
35
+ * If app is provided, the color of the Beta Badge is derived from the application colors.
36
+ * Example:
37
+ * <Badge variant={{ type: 'beta', color: '#823AA1', app: myApp }} />
38
+ * where myApp is of type IWebApp.
34
39
  */
35
40
  export type BetaBadgeVariant = {
36
41
  type: 'beta';
37
42
  color?: string;
43
+ app?: IWebApp;
38
44
  };
39
45
  export type BadgeVariants = NotificationBadgeVariant | ContentBadgeVariant | ProfileBadgeVariant | ChipBadgeVariant | LinkBadgeVariant | BetaBadgeVariant;
40
46
  export interface BadgeProps extends React.ComponentPropsWithRef<'span'> {
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import clsx from "clsx";
4
+ import useEdificeIcons from "../../hooks/useEdificeIcons/useEdificeIcons.js";
4
5
  const Badge = /* @__PURE__ */ forwardRef(({
5
6
  className,
6
7
  variant = {
@@ -10,17 +11,19 @@ const Badge = /* @__PURE__ */ forwardRef(({
10
11
  children,
11
12
  ...restProps
12
13
  }, ref) => {
13
- const classes = clsx("badge rounded-pill", (variant.type === "content" || variant.type === "user") && "background" in variant ? "bg-gray-200" : (variant.type === "content" || variant.type === "user") && !("background" in variant) ? "border border-0" : "", variant.type === "content" && `text-${variant.level}`, variant.type === "notification" && `badge-notification bg-${variant.level} text-light border border-0`, variant.type === "user" && `badge-profile-${variant.profile.toLowerCase()}`, variant.type === "link" && "badge-link border border-0", variant.type === "chip" && "bg-gray-200", className);
14
- return /* @__PURE__ */ jsxs("span", { ref, className: classes, style: (() => {
15
- if (variant.type !== "beta") return;
16
- const color = variant.color ?? "#000000";
17
- return {
18
- borderColor: color,
19
- color,
20
- backgroundColor: `${color}10`
21
- // the 2 last hexadecimal numbers are for opacity
22
- };
23
- })(), ...restProps, children: [
14
+ const {
15
+ getIconClass,
16
+ getBackgroundLightIconClass,
17
+ getBorderIconClass
18
+ } = useEdificeIcons();
19
+ let badgeColorClassName = "";
20
+ if (variant.type === "beta" && variant.app) {
21
+ const colorAppClassName = getIconClass(variant.app), backgroundLightAppClassName = getBackgroundLightIconClass(variant.app), borderAppClassName = getBorderIconClass(variant.app);
22
+ badgeColorClassName = `${colorAppClassName} ${backgroundLightAppClassName} ${borderAppClassName}`;
23
+ }
24
+ console.log(badgeColorClassName);
25
+ const classes = clsx("badge rounded-pill", (variant.type === "content" || variant.type === "user") && "background" in variant ? "bg-gray-200" : (variant.type === "content" || variant.type === "user") && !("background" in variant) ? "border border-0" : "", variant.type === "content" && `text-${variant.level}`, variant.type === "notification" && `badge-notification bg-${variant.level} text-light border border-0`, variant.type === "user" && `badge-profile-${variant.profile.toLowerCase()}`, variant.type === "link" && "badge-link border border-0", variant.type === "chip" && "bg-gray-200", variant.type === "beta" && badgeColorClassName, className);
26
+ return /* @__PURE__ */ jsxs("span", { ref, className: classes, ...restProps, children: [
24
27
  variant.type === "chip" && /* @__PURE__ */ jsx("div", { className: "d-flex fw-800 align-items-center", children }),
25
28
  variant.type === "beta" && (children ?? "BÊTA"),
26
29
  variant.type !== "chip" && variant.type !== "beta" && children
@@ -0,0 +1,57 @@
1
+ /**
2
+ * DatePicker component props
3
+ *
4
+ * Minimal interface that only exposes what is necessary.
5
+ * Ant Design implementation is hidden and no Ant Design-specific props are exposed.
6
+ * Standard HTML div attributes are supported (passed through to the underlying DOM element).
7
+ */
8
+ export interface DatePickerProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange' | 'value' | 'defaultValue'> {
9
+ /**
10
+ * Selected date values
11
+ * @default today's date is setted by ant design if no value is provided
12
+ */
13
+ value?: Date;
14
+ /**
15
+ * Callback called when date changes
16
+ */
17
+ onChange?: (date?: Date) => void;
18
+ /**
19
+ * Date format to display in the picker
20
+ * @default 'DD / MM / YYYY'
21
+ */
22
+ dateFormat?: string;
23
+ /**
24
+ * Minimum selectable date
25
+ */
26
+ minDate?: Date;
27
+ /**
28
+ * Maximum selectable date
29
+ */
30
+ maxDate?: Date;
31
+ }
32
+ /**
33
+ * Type for DatePicker ref
34
+ */
35
+ /**
36
+ * DatePicker component
37
+ *
38
+ * Date picker component for selecting a date.
39
+ *
40
+ * **Note:** This component uses Ant Design's DatePicker component internally.
41
+ * Only the props defined in DatePickerProps are allowed to prevent
42
+ * dependency on Ant Design-specific features. To replace the implementation,
43
+ * modify the component body below.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * <DatePicker
48
+ * value={date}
49
+ * onChange={(date) => setDate(date)}
50
+ * dateFormat="YYYY-MM-DD"
51
+ * minDate={new Date(today.setDate(today.getDate() - 2))}
52
+ * maxDate={new Date(today.setDate(today.getDate() + 3))}
53
+ * />
54
+ * ```
55
+ */
56
+ declare const DatePicker: import('react').ForwardRefExoticComponent<DatePickerProps & import('react').RefAttributes<HTMLElement>>;
57
+ export default DatePicker;
@@ -16,7 +16,8 @@ const DatePicker = /* @__PURE__ */ forwardRef(({
16
16
  onChange,
17
17
  dateFormat = "DD / MM / YYYY",
18
18
  minDate,
19
- maxDate
19
+ maxDate,
20
+ ...htmlProps
20
21
  }, ref) => {
21
22
  const handleChange = (date) => {
22
23
  onChange == null || onChange(date ? date.toDate() : void 0);
@@ -26,9 +27,11 @@ const DatePicker = /* @__PURE__ */ forwardRef(({
26
27
  format: dateFormat,
27
28
  minDate: minDate ? dayjs(minDate) : void 0,
28
29
  maxDate: maxDate ? dayjs(maxDate) : void 0,
29
- ref
30
+ ref,
31
+ // Cast necessary because AntDatePicker expects a specific type, but our API exposes only HTMLElement to avoid dependency on Ant Design-specific features.
32
+ ...htmlProps
30
33
  };
31
- return /* @__PURE__ */ jsx(DatePicker$1, { ...antProps });
34
+ return /* @__PURE__ */ jsx(DatePicker$1, { ...antProps, getPopupContainer: (triggerNode) => triggerNode.parentElement || document.body });
32
35
  });
33
36
  export {
34
37
  DatePicker as default
@@ -6,7 +6,7 @@ const WidgetAppsFooter = () => {
6
6
  t
7
7
  } = useTranslation();
8
8
  return /* @__PURE__ */ jsx("div", { className: "widget-footer", children: /* @__PURE__ */ jsx("div", { className: "widget-footer-action", children: /* @__PURE__ */ jsx("a", { href: "/welcome", className: "link", children: t("plus") }) }) });
9
- }, WidgetAppsBody = ({
9
+ }, appToOpenOnBlank = ["Administration"], WidgetAppsBody = ({
10
10
  bookmarkedApps
11
11
  }) => {
12
12
  const {
@@ -14,7 +14,7 @@ const WidgetAppsFooter = () => {
14
14
  } = useTranslation();
15
15
  return /* @__PURE__ */ jsxs("div", { className: "widget-body d-flex flex-wrap", children: [
16
16
  !bookmarkedApps.length && /* @__PURE__ */ jsx("div", { className: "text-dark", children: t("navbar.myapps.more") }),
17
- bookmarkedApps.slice(0, 6).map((app, index) => /* @__PURE__ */ jsx("a", { href: app.address, className: "bookmarked-app", target: app.isExternal || app.category === "connector" ? "_blank" : void 0, children: /* @__PURE__ */ jsx(AppIcon, { app, size: "32" }) }, index))
17
+ bookmarkedApps.slice(0, 6).map((app, index) => /* @__PURE__ */ jsx("a", { href: app.address, className: "bookmarked-app", target: appToOpenOnBlank.includes(app.name) || app.isExternal || app.category === "connector" ? "_blank" : void 0, rel: appToOpenOnBlank.includes(app.name) || app.isExternal || app.category === "connector" ? "noopener noreferrer" : void 0, children: /* @__PURE__ */ jsx(AppIcon, { app, size: "32" }) }, index))
18
18
  ] });
19
19
  };
20
20
  export {
@@ -0,0 +1,17 @@
1
+ import { MediaLibraryType } from 'src/modules/multimedia';
2
+ export interface MediaProps {
3
+ name: string;
4
+ url: string;
5
+ type: MediaLibraryType;
6
+ mimeType?: string;
7
+ }
8
+ interface MediaViewerProps {
9
+ onClose: () => void;
10
+ media: MediaProps[];
11
+ indexMedia?: number;
12
+ }
13
+ declare const MediaViewer: {
14
+ ({ onClose, media, indexMedia }: MediaViewerProps): import("react/jsx-runtime").JSX.Element;
15
+ displayName: string;
16
+ };
17
+ export default MediaViewer;
@@ -0,0 +1,36 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { Carousel } from "antd";
3
+ import ToolbarZoom from "./ToolbarZoom.js";
4
+ import useZoom from "../../hooks/useZoom/useZoom.js";
5
+ import ToolbarViewer from "./ToolbarViewer.js";
6
+ import { useState, useEffect } from "react";
7
+ import { MediaWrapper } from "./MediaWrapper.js";
8
+ import Flex from "../Flex/Flex.js";
9
+ const MediaViewer = ({
10
+ onClose,
11
+ media,
12
+ indexMedia = 0
13
+ }) => {
14
+ const {
15
+ zoomIn,
16
+ zoomOut,
17
+ setScale,
18
+ scale
19
+ } = useZoom(1), [currentIndex, setCurrentIndex] = useState(indexMedia);
20
+ return useEffect(() => {
21
+ setCurrentIndex(indexMedia);
22
+ }, [indexMedia]), /* @__PURE__ */ jsxs("div", { className: "media-viewer", children: [
23
+ /* @__PURE__ */ jsx(ToolbarViewer, { onClose, mediaUrl: media[currentIndex].url, mediaName: media[currentIndex].name, nbMedia: media.length, currentIndex }),
24
+ /* @__PURE__ */ jsx(Flex, { className: "media-viewer-inner-overlay", onClick: onClose, children: /* @__PURE__ */ jsxs("div", { className: "media-viewer-inner", onClick: (e) => e.stopPropagation(), children: [
25
+ /* @__PURE__ */ jsx(Carousel, { initialSlide: indexMedia, dots: !1, arrows: !0, draggable: !0, infinite: !1, afterChange: (current) => {
26
+ setCurrentIndex(current);
27
+ }, beforeChange: () => {
28
+ setScale(1);
29
+ }, children: media.map((item, index) => /* @__PURE__ */ jsx("div", { className: "viewer-slide", children: /* @__PURE__ */ jsx(MediaWrapper, { mediaUrl: item.url, mediaType: item.type, mimeType: item.mimeType, scale: index === currentIndex ? scale : 1 }) }, index)) }),
30
+ /* @__PURE__ */ jsx(ToolbarZoom, { zoomIn, zoomOut })
31
+ ] }) })
32
+ ] });
33
+ };
34
+ export {
35
+ MediaViewer as default
36
+ };
@@ -0,0 +1,7 @@
1
+ import { MediaLibraryType } from 'src/modules/multimedia';
2
+ export declare const MediaWrapper: ({ mediaUrl, mediaType, mimeType, scale, }: {
3
+ mediaUrl: string;
4
+ mediaType: MediaLibraryType;
5
+ mimeType?: string;
6
+ scale?: number;
7
+ }) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,72 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import SvgIconTextPage from "../../modules/icons/components/IconTextPage.js";
3
+ import SvgIconLink from "../../modules/icons/components/IconLink.js";
4
+ import SvgIconHeadphone from "../../modules/icons/components/IconHeadphone.js";
5
+ import SvgIconDownload from "../../modules/icons/components/IconDownload.js";
6
+ import SvgIconExternalLink from "../../modules/icons/components/IconExternalLink.js";
7
+ import { useTranslation } from "react-i18next";
8
+ import PdfViewer from "./PdfViewer.js";
9
+ import Flex from "../Flex/Flex.js";
10
+ import Button from "../Button/Button.js";
11
+ import Image from "../Image/Image.js";
12
+ const MediaWrapper = ({
13
+ mediaUrl,
14
+ mediaType,
15
+ mimeType,
16
+ scale
17
+ }) => {
18
+ const {
19
+ t
20
+ } = useTranslation(), imageMediaStyle = {
21
+ flex: "none",
22
+ height: "100%",
23
+ transform: `scale(${scale})`,
24
+ maxHeight: "70vh"
25
+ }, audioStyle = {
26
+ width: "100%",
27
+ maxWidth: "500px"
28
+ }, videoMediaStyle = {
29
+ height: "100%",
30
+ objectFit: "cover",
31
+ transform: `scale(${scale})`
32
+ }, iframeMediaStyle = {
33
+ width: "100%",
34
+ height: "600px",
35
+ maxWidth: "900px",
36
+ transform: `scale(${scale})`
37
+ };
38
+ switch (mediaType) {
39
+ case "image":
40
+ return /* @__PURE__ */ jsx(Image, { className: "rounded-2", src: mediaUrl, alt: mediaType, width: "100%", objectFit: "contain", style: imageMediaStyle });
41
+ case "audio":
42
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", align: "center", style: {
43
+ height: "200px"
44
+ }, children: [
45
+ /* @__PURE__ */ jsx(Flex, { justify: "center", align: "center", className: "bg-gray-300 h-100 w-100 rounded-2 mb-8", style: {
46
+ maxWidth: "500px"
47
+ }, children: /* @__PURE__ */ jsx(SvgIconHeadphone, { width: 40, height: 40, color: "#B0B0B0" }) }),
48
+ /* @__PURE__ */ jsx("audio", { src: mediaUrl, className: "media-audio", controls: !0, style: audioStyle })
49
+ ] });
50
+ case "video":
51
+ return /* @__PURE__ */ jsx(Flex, { justify: "center", align: "center", children: /* @__PURE__ */ jsx("video", { src: mediaUrl, controls: !0, className: "media-video", style: videoMediaStyle }) });
52
+ case "embedder":
53
+ return /* @__PURE__ */ jsx(Flex, { justify: "center", align: "center", children: /* @__PURE__ */ jsx("iframe", { title: "Embedded media content", src: mediaUrl, className: "media-video", style: iframeMediaStyle }) });
54
+ case "hyperlink":
55
+ case "attachment":
56
+ return mimeType && mimeType === "application/pdf" ? /* @__PURE__ */ jsx(PdfViewer, { mediaUrl, scale }) : /* @__PURE__ */ jsxs(Flex, { direction: "column", align: "center", children: [
57
+ /* @__PURE__ */ jsx(Flex, { justify: "center", align: "center", className: "bg-gray-300 w-100 rounded-2 mb-8", style: {
58
+ maxWidth: "500px",
59
+ height: "200px"
60
+ }, children: mediaType === "hyperlink" ? /* @__PURE__ */ jsx(SvgIconLink, { width: 40, height: 40, color: "#B0B0B0" }) : /* @__PURE__ */ jsx(SvgIconTextPage, { width: 40, height: 40, color: "#B0B0B0" }) }),
61
+ /* @__PURE__ */ jsx("a", { className: "w-100 d-flex justify-content-center", href: mediaUrl, download: mediaType !== "hyperlink", target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx(Button, { className: "w-100", style: {
62
+ height: "40px",
63
+ maxWidth: "500px"
64
+ }, leftIcon: mediaType === "hyperlink" ? /* @__PURE__ */ jsx(SvgIconExternalLink, {}) : /* @__PURE__ */ jsx(SvgIconDownload, {}), color: "tertiary", children: t(mediaType === "hyperlink" ? "mediaWrapper.attachment.open" : "mediaWrapper.attachment.download") }) })
65
+ ] });
66
+ default:
67
+ return null;
68
+ }
69
+ };
70
+ export {
71
+ MediaWrapper
72
+ };
@@ -0,0 +1,4 @@
1
+ export default function PdfViewer({ mediaUrl, scale, }: {
2
+ mediaUrl: string;
3
+ scale?: number;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState, useRef } from "react";
3
+ import { Document, Page } from "react-pdf";
4
+ import LoadingScreen from "../LoadingScreen/LoadingScreen.js";
5
+ function PdfViewer({
6
+ mediaUrl,
7
+ scale
8
+ }) {
9
+ const [numPages, setNumPages] = useState(null), pagesRef = useRef([]), onDocumentLoadSuccess = ({
10
+ numPages: numPages2
11
+ }) => {
12
+ setNumPages(numPages2);
13
+ };
14
+ return /* @__PURE__ */ jsx("div", { style: {
15
+ width: `calc(600px * ${scale})`,
16
+ height: "calc(100vh - 52px)",
17
+ overflowY: "auto",
18
+ marginTop: "20px"
19
+ }, children: /* @__PURE__ */ jsx(Document, { file: mediaUrl, onLoadSuccess: onDocumentLoadSuccess, loading: /* @__PURE__ */ jsx(LoadingScreen, {}), children: Array.from(new Array(numPages), (_, index) => /* @__PURE__ */ jsx("div", { ref: (el) => pagesRef.current[index] = el, style: {
20
+ marginBottom: 32,
21
+ transformOrigin: "top center"
22
+ }, children: /* @__PURE__ */ jsx(Page, { className: "pdf-page", pageNumber: index + 1, renderTextLayer: !1, renderAnnotationLayer: !1, width: 600 * (scale ?? 1), loading: /* @__PURE__ */ jsx(LoadingScreen, {}) }) }, index)) }) });
23
+ }
24
+ export {
25
+ PdfViewer as default
26
+ };
@@ -0,0 +1,7 @@
1
+ export default function ToolbarViewer({ onClose, mediaName, mediaUrl, nbMedia, currentIndex, }: {
2
+ onClose: () => void;
3
+ mediaName: string;
4
+ nbMedia?: number;
5
+ mediaUrl?: string;
6
+ currentIndex: number;
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,41 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import SvgIconClose from "../../modules/icons/components/IconClose.js";
4
+ import SvgIconDownload from "../../modules/icons/components/IconDownload.js";
5
+ import SvgIconExternalLink from "../../modules/icons/components/IconExternalLink.js";
6
+ import Flex from "../Flex/Flex.js";
7
+ import IconButton from "../Button/IconButton.js";
8
+ import SmartEllipsis from "../SmartEllipsis/SmartEllipsis.js";
9
+ function ToolbarViewer({
10
+ onClose,
11
+ mediaName,
12
+ mediaUrl,
13
+ nbMedia,
14
+ currentIndex
15
+ }) {
16
+ return useEffect(() => {
17
+ const handleKeyDown = (e) => {
18
+ e.key === "Escape" && onClose();
19
+ };
20
+ return window.addEventListener("keydown", handleKeyDown), () => {
21
+ window.removeEventListener("keydown", handleKeyDown);
22
+ };
23
+ }, [onClose]), /* @__PURE__ */ jsxs(Flex, { className: "media-viewer-toolbar p-8", align: "center", children: [
24
+ /* @__PURE__ */ jsxs(Flex, { gap: "8", align: "center", style: {
25
+ minWidth: "50%"
26
+ }, children: [
27
+ /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(SvgIconClose, { color: "#fff" }), onClick: onClose, variant: "ghost" }),
28
+ /* @__PURE__ */ jsx(SmartEllipsis, { text: mediaName })
29
+ ] }),
30
+ /* @__PURE__ */ jsxs(Flex, { gap: "8", align: "center", justify: "between", className: "w-100", children: [
31
+ nbMedia ? /* @__PURE__ */ jsx("p", { children: `${currentIndex + 1}/${nbMedia} ` }) : /* @__PURE__ */ jsx("p", { children: `${currentIndex + 1}` }),
32
+ mediaUrl && /* @__PURE__ */ jsxs(Flex, { className: "ms-8", gap: "8", align: "center", children: [
33
+ /* @__PURE__ */ jsx("a", { href: mediaUrl, download: !0, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(SvgIconDownload, { color: "#fff" }), variant: "ghost" }) }),
34
+ /* @__PURE__ */ jsx("a", { href: mediaUrl, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(SvgIconExternalLink, { color: "#fff" }), variant: "ghost" }) })
35
+ ] })
36
+ ] })
37
+ ] });
38
+ }
39
+ export {
40
+ ToolbarViewer as default
41
+ };
@@ -0,0 +1,4 @@
1
+ export default function ToolbarZoom({ zoomIn, zoomOut, }: {
2
+ zoomIn: () => void;
3
+ zoomOut: () => void;
4
+ }): import("react/jsx-runtime").JSX.Element;