@edifice.io/react 2.5.15-develop-pedago.20260324175543 → 2.5.15-develop-pedago.20260327124327

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 (30) hide show
  1. package/dist/components/Tree/components/SortableTree.js +4 -3
  2. package/dist/components/Tree/components/Tree.js +4 -3
  3. package/dist/components/UserRightsList/SaveBookmark.d.ts +5 -0
  4. package/dist/components/UserRightsList/SaveBookmark.js +29 -0
  5. package/dist/components/UserRightsList/UserRightsBookmarkRow.d.ts +11 -0
  6. package/dist/components/UserRightsList/UserRightsBookmarkRow.js +30 -0
  7. package/dist/components/UserRightsList/UserRightsItem.d.ts +13 -0
  8. package/dist/components/UserRightsList/UserRightsItem.js +36 -0
  9. package/dist/components/UserRightsList/UserRightsList.d.ts +19 -0
  10. package/dist/components/UserRightsList/UserRightsList.js +94 -0
  11. package/dist/components/UserRightsList/helpers/rightsHelpers.d.ts +9 -0
  12. package/dist/components/UserRightsList/helpers/rightsHelpers.js +53 -0
  13. package/dist/components/UserRightsList/hooks/useBookmarkEntries.d.ts +19 -0
  14. package/dist/components/UserRightsList/hooks/useBookmarkEntries.js +58 -0
  15. package/dist/components/UserRightsList/hooks/useSharingItems.d.ts +20 -0
  16. package/dist/components/UserRightsList/hooks/useSharingItems.js +57 -0
  17. package/dist/components/UserRightsList/index.d.ts +2 -0
  18. package/dist/components/UserRightsList/types/types.d.ts +34 -0
  19. package/dist/components/UserRightsList/types/types.js +6 -0
  20. package/dist/components/UserSearch/types/types.d.ts +2 -7
  21. package/dist/components/index.d.ts +1 -0
  22. package/dist/hooks/useDirectory/useDirectory.d.ts +3 -2
  23. package/dist/index.js +4 -0
  24. package/dist/types/index.d.ts +1 -0
  25. package/dist/types/sharing.d.ts +8 -0
  26. package/dist/utilities/index.d.ts +1 -0
  27. package/dist/utilities/rotate-transition-style/get-rotate-transition-style.d.ts +5 -0
  28. package/dist/utilities/rotate-transition-style/get-rotate-transition-style.js +12 -0
  29. package/dist/utilities/rotate-transition-style/index.d.ts +1 -0
  30. package/package.json +6 -6
@@ -11,6 +11,7 @@ import SvgIconRafterRight from "../../../modules/icons/components/IconRafterRigh
11
11
  import { useTree } from "../hooks/useTree.js";
12
12
  import { useTreeSortable } from "../hooks/useTreeSortable.js";
13
13
  import { flattenNodes } from "../utilities/tree-sortable.js";
14
+ import { getRotateTransitionStyle } from "../../../utilities/rotate-transition-style/get-rotate-transition-style.js";
14
15
  import { mergeRefs } from "../../../utilities/refs/ref.js";
15
16
  const SortableTree = ({
16
17
  nodes,
@@ -113,9 +114,9 @@ const SortableTree = ({
113
114
  ...style,
114
115
  marginLeft: spaceGestion()
115
116
  }, ...listeners, children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: treeItemClasses.action, children: [
116
- node.haveChilds && /* @__PURE__ */ jsx("div", { tabIndex: 0, role: "button", onClick: () => onToggleNode == null ? void 0 : onToggleNode(node.id), onKeyDown: handleItemToggleKeyDown, "aria-label": t("foldUnfold"), children: /* @__PURE__ */ jsx(SvgIconRafterRight, { width: 16, style: {
117
- transform: expanded ? "rotate(90deg)" : ""
118
- } }) }),
117
+ node.haveChilds && /* @__PURE__ */ jsx("div", { tabIndex: 0, role: "button", onClick: () => onToggleNode == null ? void 0 : onToggleNode(node.id), onKeyDown: handleItemToggleKeyDown, "aria-label": t("foldUnfold"), children: /* @__PURE__ */ jsx(SvgIconRafterRight, { width: 16, style: getRotateTransitionStyle(expanded, {
118
+ degrees: 90
119
+ }) }) }),
119
120
  node.children && showIcon ? /* @__PURE__ */ jsx(SvgIconFolder, { title: "folder", width: 20, height: 20 }) : null,
120
121
  /* @__PURE__ */ jsx("div", { tabIndex: 0, role: "button", className: treeItemClasses.button, onClick: () => onTreeItemClick(node.id), onKeyDown: handleItemKeyDown, children: renderNode ? renderNode({
121
122
  node,
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
5
5
  import SvgIconFolder from "../../../modules/icons/components/IconFolder.js";
6
6
  import SvgIconRafterRight from "../../../modules/icons/components/IconRafterRight.js";
7
7
  import { useTree } from "../hooks/useTree.js";
8
+ import { getRotateTransitionStyle } from "../../../utilities/rotate-transition-style/get-rotate-transition-style.js";
8
9
  const Tree = ({
9
10
  nodes,
10
11
  selectedNodeId: externalSelectedNodeId,
@@ -66,9 +67,9 @@ const Tree = ({
66
67
  };
67
68
  return /* @__PURE__ */ createElement("li", { ...restProps, ref, key: node.id, id: `treeitem-${node.id}`, role: "treeitem", "aria-selected": selected, "aria-expanded": expanded }, /* @__PURE__ */ jsxs("div", { children: [
68
69
  /* @__PURE__ */ jsxs("div", { className: treeItemClasses.action, children: [
69
- node.children && node.children.length > 0 ? /* @__PURE__ */ jsx("div", { className: treeItemClasses.arrow, tabIndex: 0, role: "button", onClick: () => onToggleNode == null ? void 0 : onToggleNode(node.id), onKeyDown: handleItemToggleKeyDown, "aria-label": t("foldUnfold"), children: /* @__PURE__ */ jsx(SvgIconRafterRight, { width: 16, style: {
70
- transform: expanded ? "rotate(90deg)" : ""
71
- } }) }) : /* @__PURE__ */ jsx("div", { className: "py-8 invisible" }),
70
+ node.children && node.children.length > 0 ? /* @__PURE__ */ jsx("div", { className: treeItemClasses.arrow, tabIndex: 0, role: "button", onClick: () => onToggleNode == null ? void 0 : onToggleNode(node.id), onKeyDown: handleItemToggleKeyDown, "aria-label": t("foldUnfold"), children: /* @__PURE__ */ jsx(SvgIconRafterRight, { width: 16, style: getRotateTransitionStyle(expanded, {
71
+ degrees: 90
72
+ }) }) }) : /* @__PURE__ */ jsx("div", { className: "py-8 invisible" }),
72
73
  node.children && showIcon ? /* @__PURE__ */ jsx(SvgIconFolder, { title: "folder", width: 20, height: 20 }) : null,
73
74
  /* @__PURE__ */ jsx("div", { tabIndex: 0, role: "button", className: treeItemClasses.button, onClick: () => onTreeItemClick(node.id), onKeyDown: handleItemKeyDown, children: renderNode ? renderNode({
74
75
  node,
@@ -0,0 +1,5 @@
1
+ interface SaveBookmarkProps {
2
+ onSave: (bookmarkName: string) => Promise<void>;
3
+ }
4
+ export declare const SaveBookmark: ({ onSave }: SaveBookmarkProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,29 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconSave from "../../modules/icons/components/IconSave.js";
5
+ import FormControl from "../Form/FormControl.js";
6
+ import Button from "../Button/Button.js";
7
+ const SaveBookmark = ({
8
+ onSave
9
+ }) => {
10
+ const [bookmarkName, setBookmarkName] = useState(""), [isSaving, setIsSaving] = useState(!1), {
11
+ t
12
+ } = useTranslation(), handleBookmarkNameChange = (e) => {
13
+ setBookmarkName(e.target.value);
14
+ }, handleSaveClick = async () => {
15
+ setIsSaving(!0);
16
+ try {
17
+ await onSave(bookmarkName), setBookmarkName("");
18
+ } finally {
19
+ setIsSaving(!1);
20
+ }
21
+ };
22
+ return /* @__PURE__ */ jsx("div", { className: "mt-16", children: /* @__PURE__ */ jsxs(FormControl, { id: "bookmarkName", className: "d-flex flex-wrap align-items-center gap-16", children: [
23
+ /* @__PURE__ */ jsx("div", { className: "flex-fill", children: /* @__PURE__ */ jsx(FormControl.Input, { "data-testid": "common-save-bookmark-name-input", value: bookmarkName, onChange: handleBookmarkNameChange, placeholder: t("explorer.modal.share.sharebookmark.placeholder"), size: "sm", type: "text" }) }),
24
+ /* @__PURE__ */ jsx(Button, { "data-testid": "common-save-bookmark-save-button", color: "primary", variant: "ghost", disabled: bookmarkName.length === 0 || isSaving, leftIcon: /* @__PURE__ */ jsx(SvgIconSave, {}), onClick: handleSaveClick, className: "text-nowrap", isLoading: isSaving, children: t("explorer.modal.share.sharebookmark.save") })
25
+ ] }) });
26
+ };
27
+ export {
28
+ SaveBookmark
29
+ };
@@ -0,0 +1,11 @@
1
+ import { BookmarkState, ResourceRightName, ResourceRights } from './types/types';
2
+ interface UserRightsBookmarkRowProps {
3
+ bookmark: BookmarkState;
4
+ resourceRights: ResourceRights;
5
+ isReadOnly: boolean;
6
+ onToggleRight: (bookmarkId: string, rightName: ResourceRightName) => void;
7
+ onDelete: (bookmarkId: string) => void;
8
+ onToggleExpand: (bookmarkId: string) => void;
9
+ }
10
+ declare const UserRightsBookmarkRow: ({ bookmark, resourceRights, isReadOnly, onToggleRight, onDelete, onToggleExpand, }: UserRightsBookmarkRowProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default UserRightsBookmarkRow;
@@ -0,0 +1,30 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import SvgIconBookmark from "../../modules/icons/components/IconBookmark.js";
4
+ import SvgIconClose from "../../modules/icons/components/IconClose.js";
5
+ import SvgIconRafterDown from "../../modules/icons/components/IconRafterDown.js";
6
+ import Button from "../Button/Button.js";
7
+ import Checkbox from "../Checkbox/Checkbox.js";
8
+ import IconButton from "../Button/IconButton.js";
9
+ import { getRotateTransitionStyle } from "../../utilities/rotate-transition-style/get-rotate-transition-style.js";
10
+ const UserRightsBookmarkRow = ({
11
+ bookmark,
12
+ resourceRights,
13
+ isReadOnly,
14
+ onToggleRight,
15
+ onDelete,
16
+ onToggleExpand
17
+ }) => {
18
+ const {
19
+ t
20
+ } = useTranslation();
21
+ return /* @__PURE__ */ jsxs("tr", { "data-testid": "user-rights-list-bookmark-row", children: [
22
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(SvgIconBookmark, {}) }),
23
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Button, { color: "tertiary", variant: "ghost", className: "fw-normal ps-0", "aria-expanded": bookmark.isExpanded, rightIcon: /* @__PURE__ */ jsx(SvgIconRafterDown, { title: bookmark.isExpanded ? t("hide") : t("show"), className: "w-16 min-w-0", style: getRotateTransitionStyle(bookmark.isExpanded) }), onClick: () => onToggleExpand(bookmark.id), children: bookmark.name }) }),
24
+ Object.entries(resourceRights).map(([rightName]) => /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Checkbox, { checked: bookmark.permission.includes(rightName), onChange: () => onToggleRight(bookmark.id, rightName), disabled: isReadOnly, "aria-label": `${bookmark.name} - ${rightName}`, "data-testid": `user-rights-list-bookmark-${rightName}-checkbox` }) }, rightName)),
25
+ /* @__PURE__ */ jsx("td", { children: !isReadOnly && /* @__PURE__ */ jsx(IconButton, { "data-testid": "user-rights-list-bookmark-close-button", color: "tertiary", onClick: () => onDelete(bookmark.id), icon: /* @__PURE__ */ jsx(SvgIconClose, {}), title: `${t("close")} ${bookmark.name}`, variant: "ghost" }) })
26
+ ] });
27
+ };
28
+ export {
29
+ UserRightsBookmarkRow as default
30
+ };
@@ -0,0 +1,13 @@
1
+ import { ResourceRightName, ResourceRights, SharingItem } from './types/types';
2
+ interface UserRightsItemProps {
3
+ item: SharingItem;
4
+ resourceRights: ResourceRights;
5
+ isReadOnly: boolean;
6
+ isDeletable?: boolean;
7
+ rowClassName?: string;
8
+ bookmarkName?: string;
9
+ onChange?: (item: SharingItem, rightName: ResourceRightName) => void;
10
+ onDeleteItem?: (item: SharingItem) => void;
11
+ }
12
+ declare const UserRightsItem: ({ item, resourceRights, isReadOnly, isDeletable, rowClassName, bookmarkName, onChange, onDeleteItem, }: UserRightsItemProps) => import("react/jsx-runtime").JSX.Element;
13
+ export default UserRightsItem;
@@ -0,0 +1,36 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import SvgIconClose from "../../modules/icons/components/IconClose.js";
4
+ import useDirectory from "../../hooks/useDirectory/useDirectory.js";
5
+ import Avatar from "../Avatar/Avatar.js";
6
+ import Checkbox from "../Checkbox/Checkbox.js";
7
+ import IconButton from "../Button/IconButton.js";
8
+ const UserRightsItem = ({
9
+ item,
10
+ resourceRights,
11
+ isReadOnly,
12
+ isDeletable = !0,
13
+ rowClassName,
14
+ bookmarkName,
15
+ onChange,
16
+ onDeleteItem
17
+ }) => {
18
+ const {
19
+ getAvatarURL
20
+ } = useDirectory(), {
21
+ t
22
+ } = useTranslation(), handleChange = (rightName) => {
23
+ onChange == null || onChange(item, rightName);
24
+ }, handleDeleteItem = () => {
25
+ onDeleteItem == null || onDeleteItem(item);
26
+ };
27
+ return /* @__PURE__ */ jsxs("tr", { "data-testid": "user-rights-list-item-row", className: rowClassName, "aria-label": bookmarkName ? `${item.displayName} - ${bookmarkName}` : void 0, children: [
28
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Avatar, { src: getAvatarURL(item.recipientId, item.recipientType), size: "xs", alt: item.displayName, variant: "circle" }) }),
29
+ /* @__PURE__ */ jsx("td", { children: item.displayName }),
30
+ Object.entries(resourceRights).map(([rightName]) => /* @__PURE__ */ jsx("td", { "data-testid": `user-rights-list-item-${rightName}-checkbox`, children: /* @__PURE__ */ jsx(Checkbox, { checked: item.permission.includes(rightName), onChange: () => handleChange(rightName), disabled: isReadOnly, "aria-label": `${item.displayName} - ${rightName}` }) }, rightName)),
31
+ /* @__PURE__ */ jsx("td", { children: !isReadOnly && isDeletable && /* @__PURE__ */ jsx(IconButton, { "data-testid": "user-rights-list-close-button", color: "tertiary", onClick: () => handleDeleteItem(), icon: /* @__PURE__ */ jsx(SvgIconClose, {}), title: `${t("close")} ${item.displayName}`, variant: "ghost", type: "button" }) })
32
+ ] });
33
+ };
34
+ export {
35
+ UserRightsItem as default
36
+ };
@@ -0,0 +1,19 @@
1
+ import { SharingItem } from '../../types';
2
+ import { BookmarkInput, ResourceRights } from './types/types';
3
+ interface UserRightsListProps {
4
+ resourceRights: ResourceRights;
5
+ isReadOnly: boolean;
6
+ isLoading: boolean;
7
+ ownerId: string;
8
+ isCreating: boolean;
9
+ initialSharings?: SharingItem[];
10
+ onChange: (value: SharingItem[]) => void;
11
+ onAddItems: (value: SharingItem[]) => void;
12
+ onDeleteItems: (value: SharingItem[]) => void;
13
+ onSaveBookmark?: (bookmarkName: string, items: SharingItem[]) => Promise<void>;
14
+ }
15
+ export interface UserRightsListRef {
16
+ addItem: (item: SharingItem | BookmarkInput) => void;
17
+ }
18
+ export declare const UserRightsList: import('react').ForwardRefExoticComponent<UserRightsListProps & import('react').RefAttributes<UserRightsListRef>>;
19
+ export {};
@@ -0,0 +1,94 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { forwardRef, useState, useRef, useMemo, useImperativeHandle, Fragment as Fragment$1 } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconBookmark from "../../modules/icons/components/IconBookmark.js";
5
+ import SvgIconRafterDown from "../../modules/icons/components/IconRafterDown.js";
6
+ import { createRightsHelpers } from "./helpers/rightsHelpers.js";
7
+ import { useBookmarkEntries } from "./hooks/useBookmarkEntries.js";
8
+ import { useSharingItems } from "./hooks/useSharingItems.js";
9
+ import { SaveBookmark } from "./SaveBookmark.js";
10
+ import { isBookmarkInput } from "./types/types.js";
11
+ import UserRightsBookmarkRow from "./UserRightsBookmarkRow.js";
12
+ import UserRightsItem from "./UserRightsItem.js";
13
+ import LoadingScreen from "../LoadingScreen/LoadingScreen.js";
14
+ import VisuallyHidden from "../VisuallyHidden/VisuallyHidden.js";
15
+ import Button from "../Button/Button.js";
16
+ import { useEdificeClient } from "../../providers/EdificeClientProvider/EdificeClientProvider.hook.js";
17
+ import { getRotateTransitionStyle } from "../../utilities/rotate-transition-style/get-rotate-transition-style.js";
18
+ const UserRightsList = /* @__PURE__ */ forwardRef(({
19
+ resourceRights,
20
+ isReadOnly = !0,
21
+ isLoading = !1,
22
+ ownerId,
23
+ isCreating = !1,
24
+ initialSharings = [],
25
+ onChange,
26
+ onAddItems,
27
+ onDeleteItems,
28
+ onSaveBookmark
29
+ }, ref) => {
30
+ const [showBookmarkInput, setBookmarkInput] = useState(!1), tableRef = useRef(null), {
31
+ t
32
+ } = useTranslation(), {
33
+ user
34
+ } = useEdificeClient(), {
35
+ applyRight,
36
+ toggleRight,
37
+ getOwnerItem
38
+ } = useMemo(() => createRightsHelpers(resourceRights), [resourceRights]), ownerItem = getOwnerItem(ownerId, user, isCreating), sharingItems = useSharingItems({
39
+ initialSharings,
40
+ toggleRight,
41
+ applyRight,
42
+ onChange,
43
+ onAddItems,
44
+ onDeleteItems
45
+ }), itemsByRecipientId = useMemo(() => new Map(sharingItems.items.map((item) => [item.recipientId, item])), [sharingItems.items]), existingRecipientIds = useMemo(() => new Set(itemsByRecipientId.keys()), [itemsByRecipientId]), bookmarks = useBookmarkEntries({
46
+ resourceRights,
47
+ existingRecipientIds,
48
+ toggleRight,
49
+ addItems: sharingItems.addItems,
50
+ deleteItemsByIds: sharingItems.deleteItemsByIds,
51
+ applyRightToIds: sharingItems.applyRightToIds
52
+ }), regularItems = useMemo(() => sharingItems.items.filter((item) => !bookmarks.bookmarkUserIds.has(item.recipientId)), [sharingItems.items, bookmarks.bookmarkUserIds]), focusTable = () => {
53
+ var _a;
54
+ (_a = tableRef.current) == null || _a.focus();
55
+ }, handleAddItem = (item) => {
56
+ isBookmarkInput(item) ? bookmarks.addBookmark(item) : sharingItems.addItem(item);
57
+ }, handleDeleteItem = (item) => {
58
+ sharingItems.deleteItem(item), focusTable();
59
+ }, handleDeleteBookmark = (bookmarkId) => {
60
+ bookmarks.deleteBookmark(bookmarkId), focusTable();
61
+ }, handleOnSaveBookmark = (bookmarkName) => onSaveBookmark ? onSaveBookmark(bookmarkName, sharingItems.items) : Promise.resolve(), toggleBookmarkInput = () => {
62
+ setBookmarkInput((prev) => !prev);
63
+ };
64
+ return useImperativeHandle(ref, () => ({
65
+ addItem: handleAddItem
66
+ })), /* @__PURE__ */ jsx("div", { className: "user-rights-list", children: isLoading ? /* @__PURE__ */ jsx(LoadingScreen, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
67
+ /* @__PURE__ */ jsx("div", { className: "table-responsive", children: /* @__PURE__ */ jsxs("table", { ref: tableRef, tabIndex: -1, className: "table border align-middle", children: [
68
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
69
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "w-32", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.avatar.shared.alt") }) }),
70
+ /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.search.placeholder") }) }),
71
+ Object.entries(resourceRights).map(([rightName]) => /* @__PURE__ */ jsx("th", { children: rightName }, rightName)),
72
+ !isReadOnly && /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("close") }) })
73
+ ] }) }),
74
+ /* @__PURE__ */ jsxs("tbody", { children: [
75
+ /* @__PURE__ */ jsx(UserRightsItem, { item: ownerItem, resourceRights, isReadOnly: !0 }, ownerItem == null ? void 0 : ownerItem.recipientId),
76
+ bookmarks.bookmarkEntries.map((bookmark) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
77
+ /* @__PURE__ */ jsx(UserRightsBookmarkRow, { bookmark, resourceRights, isReadOnly, onToggleRight: bookmarks.toggleBookmarkRight, onDelete: handleDeleteBookmark, onToggleExpand: bookmarks.toggleExpand }),
78
+ bookmark.isExpanded && bookmark.userIds.map((userId) => {
79
+ const item = itemsByRecipientId.get(userId);
80
+ return item ? /* @__PURE__ */ jsx(UserRightsItem, { item, resourceRights, isReadOnly, isDeletable: !1, rowClassName: "bg-light", bookmarkName: bookmark.name, onChange: sharingItems.changeRight }, item.recipientId) : null;
81
+ })
82
+ ] }, bookmark.id)),
83
+ regularItems.map((item) => /* @__PURE__ */ jsx(UserRightsItem, { item, resourceRights, isReadOnly: isReadOnly || (ownerItem == null ? void 0 : ownerItem.recipientId) === item.recipientId, onChange: sharingItems.changeRight, onDeleteItem: handleDeleteItem }, item.recipientId))
84
+ ] })
85
+ ] }) }),
86
+ onSaveBookmark && /* @__PURE__ */ jsxs("div", { className: "mt-16", children: [
87
+ /* @__PURE__ */ jsx(Button, { "data-testid": "common-user-rights-list-share-bookmark-show-button", color: "tertiary", leftIcon: /* @__PURE__ */ jsx(SvgIconBookmark, {}), rightIcon: /* @__PURE__ */ jsx(SvgIconRafterDown, { title: t("show"), className: "w-16 min-w-0", style: getRotateTransitionStyle(showBookmarkInput) }), type: "button", variant: "ghost", className: "fw-normal", onClick: () => toggleBookmarkInput(), children: t("share.save.sharebookmark") }),
88
+ showBookmarkInput && /* @__PURE__ */ jsx(SaveBookmark, { onSave: handleOnSaveBookmark })
89
+ ] })
90
+ ] }) });
91
+ });
92
+ export {
93
+ UserRightsList
94
+ };
@@ -0,0 +1,9 @@
1
+ import { IUserInfo } from '@edifice.io/client';
2
+ import { SharingItem } from '../../../types';
3
+ import { ResourceRightName, ResourceRights } from '../types/types';
4
+ export declare const createRightsHelpers: (resourceRights: ResourceRights) => {
5
+ applyRight: (item: SharingItem, rightName: ResourceRightName, add: boolean) => SharingItem;
6
+ toggleRight: (item: SharingItem, rightName: ResourceRightName) => SharingItem;
7
+ createOwnerItem: (user: IUserInfo) => SharingItem;
8
+ getOwnerItem: (ownerId: string, user: IUserInfo | undefined, isCreating: boolean) => SharingItem;
9
+ };
@@ -0,0 +1,53 @@
1
+ const createRightsHelpers = (resourceRights) => {
2
+ const getOwnerItem = (ownerId, user, isCreating) => {
3
+ if (!ownerId && user && isCreating || user && ownerId === user.userId)
4
+ return createOwnerItem(user);
5
+ if (!ownerId)
6
+ throw new Error("Owner ID or user is required");
7
+ return {
8
+ recipientId: ownerId,
9
+ recipientType: "user",
10
+ displayName: "owner",
11
+ permission: Object.keys(resourceRights)
12
+ };
13
+ }, createOwnerItem = (user) => ({
14
+ recipientId: user.userId ?? "",
15
+ recipientType: "user",
16
+ displayName: user.username,
17
+ permission: Object.keys(resourceRights)
18
+ }), applyRight = (item, rightName, add) => {
19
+ const {
20
+ requires,
21
+ excludes
22
+ } = resourceRights[rightName];
23
+ let newPermission;
24
+ if (add)
25
+ newPermission = [.../* @__PURE__ */ new Set([...item.permission.filter((perm) => !excludes.includes(perm)), ...requires, rightName])];
26
+ else {
27
+ const toRemove = /* @__PURE__ */ new Set([rightName]);
28
+ let changed = !0;
29
+ for (; changed; ) {
30
+ changed = !1;
31
+ for (const [name, definition] of Object.entries(resourceRights))
32
+ !toRemove.has(name) && definition.requires.some((required) => toRemove.has(required)) && (toRemove.add(name), changed = !0);
33
+ }
34
+ newPermission = item.permission.filter((perm) => !toRemove.has(perm));
35
+ }
36
+ return {
37
+ ...item,
38
+ permission: newPermission
39
+ };
40
+ };
41
+ return {
42
+ applyRight,
43
+ toggleRight: (item, rightName) => {
44
+ const hasRight = item.permission.includes(rightName);
45
+ return applyRight(item, rightName, !hasRight);
46
+ },
47
+ createOwnerItem,
48
+ getOwnerItem
49
+ };
50
+ };
51
+ export {
52
+ createRightsHelpers
53
+ };
@@ -0,0 +1,19 @@
1
+ import { SharingItem } from '../../../types';
2
+ import { BookmarkInput, BookmarkState, ResourceRightName, ResourceRights } from '../types/types';
3
+ interface UseBookmarkEntriesParams {
4
+ resourceRights: ResourceRights;
5
+ existingRecipientIds: Set<string>;
6
+ toggleRight: (item: SharingItem, rightName: ResourceRightName) => SharingItem;
7
+ addItems: (items: SharingItem[]) => void;
8
+ deleteItemsByIds: (ids: Set<string>) => void;
9
+ applyRightToIds: (ids: Set<string>, rightName: ResourceRightName, shouldAdd: boolean) => void;
10
+ }
11
+ export declare const useBookmarkEntries: ({ resourceRights, existingRecipientIds, toggleRight, addItems, deleteItemsByIds, applyRightToIds, }: UseBookmarkEntriesParams) => {
12
+ bookmarkEntries: BookmarkState[];
13
+ bookmarkUserIds: Set<string>;
14
+ addBookmark: (bookmark: BookmarkInput) => void;
15
+ deleteBookmark: (bookmarkId: string) => void;
16
+ toggleBookmarkRight: (bookmarkId: string, rightName: ResourceRightName) => void;
17
+ toggleExpand: (bookmarkId: string) => void;
18
+ };
19
+ export {};
@@ -0,0 +1,58 @@
1
+ import { useState, useMemo } from "react";
2
+ const useBookmarkEntries = ({
3
+ resourceRights,
4
+ existingRecipientIds,
5
+ toggleRight,
6
+ addItems,
7
+ deleteItemsByIds,
8
+ applyRightToIds
9
+ }) => {
10
+ const [bookmarkEntries, setBookmarkEntries] = useState([]), bookmarkUserIds = useMemo(() => new Set(bookmarkEntries.flatMap((entry) => entry.userIds)), [bookmarkEntries]), getDefaultPermissions = () => Object.entries(resourceRights).filter(([, definition]) => definition.default).map(([name]) => name);
11
+ return {
12
+ bookmarkEntries,
13
+ bookmarkUserIds,
14
+ addBookmark: (bookmark) => {
15
+ if (bookmarkEntries.some((entry) => entry.id === bookmark.id)) return;
16
+ const defaultPermissions = getDefaultPermissions(), newBookmarkUsers = bookmark.users.filter((bookmarkUser) => !existingRecipientIds.has(bookmarkUser.id)), newUsers = newBookmarkUsers.map((bookmarkUser) => ({
17
+ recipientId: bookmarkUser.id,
18
+ recipientType: "user",
19
+ displayName: bookmarkUser.displayName,
20
+ permission: [...defaultPermissions]
21
+ })), bookmarkState = {
22
+ id: bookmark.id,
23
+ name: bookmark.name,
24
+ permission: [...defaultPermissions],
25
+ userIds: newBookmarkUsers.map((bookmarkUser) => bookmarkUser.id),
26
+ isExpanded: !1
27
+ };
28
+ setBookmarkEntries((prev) => [...prev, bookmarkState]), addItems(newUsers);
29
+ },
30
+ deleteBookmark: (bookmarkId) => {
31
+ const bookmark = bookmarkEntries.find((entry) => entry.id === bookmarkId);
32
+ bookmark && (setBookmarkEntries((prev) => prev.filter((entry) => entry.id !== bookmarkId)), deleteItemsByIds(new Set(bookmark.userIds)));
33
+ },
34
+ toggleBookmarkRight: (bookmarkId, rightName) => {
35
+ const bookmark = bookmarkEntries.find((entry) => entry.id === bookmarkId);
36
+ if (!bookmark) return;
37
+ const shouldAdd = !bookmark.permission.includes(rightName), bookmarkAsSharingItem = {
38
+ recipientId: bookmark.id,
39
+ recipientType: "bookmark",
40
+ displayName: bookmark.name,
41
+ permission: bookmark.permission
42
+ }, toggledBookmark = toggleRight(bookmarkAsSharingItem, rightName);
43
+ setBookmarkEntries((prev) => prev.map((entry) => entry.id === bookmarkId ? {
44
+ ...entry,
45
+ permission: toggledBookmark.permission
46
+ } : entry)), applyRightToIds(new Set(bookmark.userIds), rightName, shouldAdd);
47
+ },
48
+ toggleExpand: (bookmarkId) => {
49
+ setBookmarkEntries((prev) => prev.map((entry) => entry.id === bookmarkId ? {
50
+ ...entry,
51
+ isExpanded: !entry.isExpanded
52
+ } : entry));
53
+ }
54
+ };
55
+ };
56
+ export {
57
+ useBookmarkEntries
58
+ };
@@ -0,0 +1,20 @@
1
+ import { SharingItem } from '../../../types';
2
+ import { ResourceRightName } from '../types/types';
3
+ interface UseSharingItemsParams {
4
+ initialSharings: SharingItem[];
5
+ toggleRight: (item: SharingItem, rightName: ResourceRightName) => SharingItem;
6
+ applyRight: (item: SharingItem, rightName: ResourceRightName, add: boolean) => SharingItem;
7
+ onChange: (value: SharingItem[]) => void;
8
+ onAddItems: (value: SharingItem[]) => void;
9
+ onDeleteItems: (value: SharingItem[]) => void;
10
+ }
11
+ export declare const useSharingItems: ({ initialSharings, toggleRight, applyRight, onChange, onAddItems, onDeleteItems, }: UseSharingItemsParams) => {
12
+ items: SharingItem[];
13
+ addItem: (item: SharingItem) => void;
14
+ addItems: (newItems: SharingItem[]) => void;
15
+ deleteItem: (item: SharingItem) => void;
16
+ deleteItemsByIds: (ids: Set<string>) => void;
17
+ changeRight: (item: SharingItem, rightName: ResourceRightName) => void;
18
+ applyRightToIds: (ids: Set<string>, rightName: ResourceRightName, shouldAdd: boolean) => void;
19
+ };
20
+ export {};
@@ -0,0 +1,57 @@
1
+ import { useState } from "react";
2
+ const useSharingItems = ({
3
+ initialSharings,
4
+ toggleRight,
5
+ applyRight,
6
+ onChange,
7
+ onAddItems,
8
+ onDeleteItems
9
+ }) => {
10
+ const [items, setItems] = useState(initialSharings ?? []);
11
+ return {
12
+ items,
13
+ addItem: (item) => {
14
+ setItems((prev) => {
15
+ if (new Set(prev.map((sharing) => sharing.recipientId)).has(item.recipientId)) return prev;
16
+ const nextItems = [...prev, item];
17
+ return onChange(nextItems), onAddItems([item]), nextItems;
18
+ });
19
+ },
20
+ addItems: (newItems) => {
21
+ setItems((prev) => {
22
+ const existingIds = new Set(prev.map((sharing) => sharing.recipientId)), uniqueItems = newItems.filter((newItem) => !existingIds.has(newItem.recipientId));
23
+ if (uniqueItems.length === 0) return prev;
24
+ const nextItems = [...prev, ...uniqueItems];
25
+ return onChange(nextItems), onAddItems(uniqueItems), nextItems;
26
+ });
27
+ },
28
+ deleteItem: (item) => {
29
+ setItems((prev) => {
30
+ const nextItems = prev.filter((sharing) => sharing.recipientId !== item.recipientId);
31
+ return nextItems.length === prev.length ? prev : (onChange(nextItems), onDeleteItems([item]), nextItems);
32
+ });
33
+ },
34
+ deleteItemsByIds: (ids) => {
35
+ setItems((prev) => {
36
+ const nextItems = prev.filter((sharing) => !ids.has(sharing.recipientId)), removedItems = prev.filter((sharing) => ids.has(sharing.recipientId));
37
+ return onChange(nextItems), onDeleteItems(removedItems), nextItems;
38
+ });
39
+ },
40
+ changeRight: (item, rightName) => {
41
+ const updatedItem = toggleRight(item, rightName);
42
+ setItems((prevItems) => {
43
+ const nextItems = prevItems.map((prevItem) => prevItem.recipientId === item.recipientId ? updatedItem : prevItem);
44
+ return onChange(nextItems), nextItems;
45
+ });
46
+ },
47
+ applyRightToIds: (ids, rightName, shouldAdd) => {
48
+ setItems((prev) => {
49
+ const nextItems = prev.map((sharing) => ids.has(sharing.recipientId) ? applyRight(sharing, rightName, shouldAdd) : sharing);
50
+ return onChange(nextItems), nextItems;
51
+ });
52
+ }
53
+ };
54
+ };
55
+ export {
56
+ useSharingItems
57
+ };
@@ -0,0 +1,2 @@
1
+ export * from './UserRightsList';
2
+ export type { BookmarkInput, BookmarkUser } from './types/types';
@@ -0,0 +1,34 @@
1
+ import { SharingItem } from '../../../types';
2
+ export type { SearchResultType, SharingItem } from '../../../types';
3
+ export type ResourceRightName = 'read' | 'contrib' | 'publish' | 'manager' | 'comment';
4
+ export type ResourceRightDefinition = {
5
+ priority: number;
6
+ default: boolean;
7
+ requires: ResourceRightName[];
8
+ excludes: ResourceRightName[];
9
+ };
10
+ export type ResourceRights = Record<ResourceRightName, ResourceRightDefinition>;
11
+ export interface BookmarkUser {
12
+ id: string;
13
+ displayName: string;
14
+ profile?: string;
15
+ activationCode?: boolean;
16
+ }
17
+ export interface BookmarkInput {
18
+ id: string;
19
+ name: string;
20
+ notVisibleCount?: number;
21
+ groups?: {
22
+ id: string;
23
+ displayName: string;
24
+ }[];
25
+ users: BookmarkUser[];
26
+ }
27
+ export interface BookmarkState {
28
+ id: string;
29
+ name: string;
30
+ permission: string[];
31
+ userIds: string[];
32
+ isExpanded: boolean;
33
+ }
34
+ export declare function isBookmarkInput(item: SharingItem | BookmarkInput): item is BookmarkInput;
@@ -0,0 +1,6 @@
1
+ function isBookmarkInput(item) {
2
+ return "users" in item && Array.isArray(item.users);
3
+ }
4
+ export {
5
+ isBookmarkInput
6
+ };
@@ -1,5 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
+ import { SearchResultType, SharingItem } from '../../../types';
2
3
  import { Visible } from './visible';
4
+ export type { SearchResultType, SharingItem };
3
5
  export interface UserSearchProps {
4
6
  placeholder?: string;
5
7
  isAdmlcOrAdmc?: boolean;
@@ -14,16 +16,9 @@ export interface UserSearchRef {
14
16
  export interface SearchResponse {
15
17
  results: Visible[];
16
18
  }
17
- export type SearchResultType = 'user' | 'group' | 'bookmark';
18
19
  export interface SearchResultBase {
19
20
  id: string;
20
21
  displayName: string;
21
22
  icon: ReactNode;
22
23
  type: SearchResultType;
23
24
  }
24
- export interface SharingItem {
25
- recipientId: string;
26
- recipientType: SearchResultType;
27
- permission: string[];
28
- displayName: string;
29
- }
@@ -52,5 +52,6 @@ export * from './Toolbar';
52
52
  export * from './Tooltip';
53
53
  export * from './Tree';
54
54
  export * from './TreeView';
55
+ export * from './UserRightsList';
55
56
  export * from './UserSearch';
56
57
  export * from './VisuallyHidden';
@@ -1,6 +1,7 @@
1
1
  import { ID } from '@edifice.io/client';
2
+ import { AvatarType } from '../../types';
2
3
  declare const useDirectory: () => {
3
- getAvatarURL: (userId: ID, type: "user" | "group") => string | undefined;
4
- getUserbookURL: (userId: ID, type: "user" | "group") => string;
4
+ getAvatarURL: (userId: ID, type: AvatarType) => string | undefined;
5
+ getUserbookURL: (userId: ID, type: AvatarType) => string;
5
6
  };
6
7
  export default useDirectory;
package/dist/index.js CHANGED
@@ -133,11 +133,13 @@ import { Toolbar } from "./components/Toolbar/Toolbar.js";
133
133
  import { TreeNode } from "./components/TreeView/TreeNode.js";
134
134
  import { TreeNodeFolderWrapper, addNode, arrayUnique, deleteNode, findNodeById, findParentNode, findPathById, findTreeNode, getAncestors, hasChildren, modifyNode, moveNode, updateNode, wrapTreeNode } from "./components/TreeView/utilities/treeview.js";
135
135
  import { Upload } from "./modules/multimedia/MediaLibrary/innertabs/Upload.js";
136
+ import { UserRightsList } from "./components/UserRightsList/UserRightsList.js";
136
137
  import { UserSearch } from "./components/UserSearch/UserSearch.js";
137
138
  import { VisibleType } from "./components/UserSearch/types/visible.js";
138
139
  import { buildTree, determineNewParentId, findItemIndexInTree, flattenNodes, flattenTree, generateUpdateData, getActiveAndOverNodes, getDragDepth, getIndicesToUpdate, getProjection, updateParentIds } from "./components/Tree/utilities/tree-sortable.js";
139
140
  import { checkUserRight } from "./utilities/check-user-rights/check-user-rights.js";
140
141
  import { emptyScreenMapping } from "./utilities/emptyscreen-mapping/emptyscreen-mapping.js";
142
+ import { getRotateTransitionStyle } from "./utilities/rotate-transition-style/get-rotate-transition-style.js";
141
143
  import { invalidateQueriesWithFirstPage } from "./utilities/react-query/react-query-utils.js";
142
144
  import { mergeRefs, setRef } from "./utilities/refs/ref.js";
143
145
  import { useCheckable } from "./hooks/useCheckable/useCheckable.js";
@@ -243,6 +245,7 @@ export {
243
245
  Upload,
244
246
  default67 as UploadCard,
245
247
  default68 as UploadFiles,
248
+ UserRightsList,
246
249
  UserSearch,
247
250
  default69 as VideoEmbed,
248
251
  default70 as VideoRecorder,
@@ -272,6 +275,7 @@ export {
272
275
  getDragDepth,
273
276
  getIndicesToUpdate,
274
277
  getProjection,
278
+ getRotateTransitionStyle,
275
279
  hasChildren,
276
280
  invalidateQueriesWithFirstPage,
277
281
  mergeRefs,
@@ -2,3 +2,4 @@ export { type Size } from './size';
2
2
  export { type Status } from './status';
3
3
  export { type TreeData } from './treedata';
4
4
  export { type Color } from './color';
5
+ export { type AvatarType, type SearchResultType, type SharingItem, } from './sharing';
@@ -0,0 +1,8 @@
1
+ export type AvatarType = 'user' | 'group';
2
+ export type SearchResultType = AvatarType | 'bookmark';
3
+ export interface SharingItem {
4
+ recipientId: string;
5
+ recipientType: SearchResultType;
6
+ permission: string[];
7
+ displayName: string;
8
+ }
@@ -2,3 +2,4 @@ export * from './check-user-rights';
2
2
  export * from './emptyscreen-mapping';
3
3
  export * from './react-query';
4
4
  export * from './refs';
5
+ export * from './rotate-transition-style';
@@ -0,0 +1,5 @@
1
+ import { CSSProperties } from 'react';
2
+ export declare function getRotateTransitionStyle(isOpen: boolean, { degrees, duration, }?: {
3
+ degrees?: number;
4
+ duration?: number;
5
+ }): CSSProperties;
@@ -0,0 +1,12 @@
1
+ function getRotateTransitionStyle(isOpen, {
2
+ degrees = -180,
3
+ duration = 0.2
4
+ } = {}) {
5
+ return {
6
+ transition: `rotate ${duration}s ease-out`,
7
+ rotate: isOpen ? `${degrees}deg` : "0deg"
8
+ };
9
+ }
10
+ export {
11
+ getRotateTransitionStyle
12
+ };
@@ -0,0 +1 @@
1
+ export * from './get-rotate-transition-style';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.5.15-develop-pedago.20260324175543",
3
+ "version": "2.5.15-develop-pedago.20260327124327",
4
4
  "description": "Edifice React Library",
5
5
  "keywords": [
6
6
  "react",
@@ -135,9 +135,9 @@
135
135
  "swiper": "^10.1.0",
136
136
  "ua-parser-js": "^1.0.36",
137
137
  "react-pdf": "10.2.0",
138
- "@edifice.io/bootstrap": "2.5.15-develop-pedago.20260324175543",
139
- "@edifice.io/tiptap-extensions": "2.5.15-develop-pedago.20260324175543",
140
- "@edifice.io/utilities": "2.5.15-develop-pedago.20260324175543"
138
+ "@edifice.io/bootstrap": "2.5.15-develop-pedago.20260327124327",
139
+ "@edifice.io/tiptap-extensions": "2.5.15-develop-pedago.20260327124327",
140
+ "@edifice.io/utilities": "2.5.15-develop-pedago.20260327124327"
141
141
  },
142
142
  "devDependencies": {
143
143
  "@babel/plugin-transform-react-pure-annotations": "^7.23.3",
@@ -168,8 +168,8 @@
168
168
  "vite": "^5.4.11",
169
169
  "vite-plugin-dts": "^4.1.0",
170
170
  "vite-tsconfig-paths": "^5.0.1",
171
- "@edifice.io/client": "2.5.15-develop-pedago.20260324175543",
172
- "@edifice.io/config": "2.5.15-develop-pedago.20260324175543"
171
+ "@edifice.io/client": "2.5.15-develop-pedago.20260327124327",
172
+ "@edifice.io/config": "2.5.15-develop-pedago.20260327124327"
173
173
  },
174
174
  "peerDependencies": {
175
175
  "@react-spring/web": "^9.7.5",