@edifice.io/react 2.5.16-develop-pedago.20260414153809 → 2.5.16-develop-integration.20260421203533

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/Dropdown/Dropdown.d.ts +7 -3
  2. package/dist/components/Dropdown/Dropdown.js +21 -6
  3. package/dist/components/Dropdown/DropdownCheckboxItem.d.ts +6 -1
  4. package/dist/components/Dropdown/DropdownCheckboxItem.js +11 -6
  5. package/dist/components/Dropdown/DropdownContext.d.ts +5 -0
  6. package/dist/components/Dropdown/DropdownItem.d.ts +6 -1
  7. package/dist/components/Dropdown/DropdownItem.js +10 -5
  8. package/dist/components/Dropdown/DropdownItemHidden.d.ts +12 -0
  9. package/dist/components/Dropdown/DropdownItemHidden.js +19 -0
  10. package/dist/components/Dropdown/DropdownRadioItem.d.ts +6 -1
  11. package/dist/components/Dropdown/DropdownRadioItem.js +11 -6
  12. package/dist/components/Dropdown/DropdownSearchInput.d.ts +20 -0
  13. package/dist/components/Dropdown/DropdownSearchInput.js +25 -0
  14. package/dist/components/Dropdown/useDropdownItemFilter.d.ts +12 -0
  15. package/dist/components/Dropdown/useDropdownItemFilter.js +19 -0
  16. package/dist/components/Layout/components/Header.js +0 -7
  17. package/dist/components/Layout/hooks/useHeader.js +2 -3
  18. package/dist/components/Pagination/Pagination.d.ts +17 -0
  19. package/dist/components/Pagination/Pagination.js +14 -0
  20. package/dist/components/Pagination/index.d.ts +1 -0
  21. package/dist/components/UserRightsList/UserRightsBookmarkRow.js +1 -1
  22. package/dist/components/UserRightsList/UserRightsItem.js +1 -1
  23. package/dist/components/UserRightsList/UserRightsList.js +1 -1
  24. package/dist/components/UserRightsList/types/types.d.ts +1 -6
  25. package/dist/components/index.d.ts +1 -0
  26. package/dist/hooks/useDropdown/useDropdown.js +14 -9
  27. package/dist/hooks/useZendeskGuide/useZendeskGuide.js +1 -1
  28. package/dist/index.js +2 -0
  29. package/dist/modules/icons/components/nav/IconCommunities.js +1 -1
  30. package/package.json +6 -6
@@ -81,7 +81,7 @@ declare const Dropdown: import('react').ForwardRefExoticComponent<DropdownProps
81
81
  Trigger: import('react').ForwardRefExoticComponent<Omit<import('./DropdownTrigger').DropdownTriggerProps, "ref"> & import('react').RefAttributes<HTMLButtonElement>>;
82
82
  Menu: import('react').ForwardRefExoticComponent<Omit<import('./DropdownMenu').DropdownMenuProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
83
83
  Item: {
84
- ({ type, icon, onClick, children, className, minWidth, disabled, ...restProps }: import('./DropdownItem').DropdownItemProps): import("react/jsx-runtime").JSX.Element;
84
+ ({ type, icon, onClick, children, className, minWidth, disabled, searchValue, ...restProps }: import('./DropdownItem').DropdownItemProps): import("react/jsx-runtime").JSX.Element;
85
85
  displayName: string;
86
86
  };
87
87
  Separator: {
@@ -89,13 +89,17 @@ declare const Dropdown: import('react').ForwardRefExoticComponent<DropdownProps
89
89
  displayName: string;
90
90
  };
91
91
  CheckboxItem: {
92
- ({ children, value, model, onChange, }: DropdownCheckboxItem): import("react/jsx-runtime").JSX.Element;
92
+ ({ children, value, model, onChange, searchValue, }: DropdownCheckboxItem): import("react/jsx-runtime").JSX.Element;
93
93
  displayName: string;
94
94
  };
95
95
  RadioItem: {
96
- ({ children, value, model, onChange, }: import('./DropdownRadioItem').DropdownRadioItemProps): import("react/jsx-runtime").JSX.Element;
96
+ ({ children, value, model, onChange, searchValue, }: import('./DropdownRadioItem').DropdownRadioItemProps): import("react/jsx-runtime").JSX.Element;
97
97
  displayName: string;
98
98
  };
99
99
  MenuGroup: import('react').ForwardRefExoticComponent<import('./DropdownMenuGroup').DropdownMenuGroupProps & import('react').RefAttributes<HTMLDivElement>>;
100
+ SearchInput: {
101
+ ({ placeholder, noResultsLabel, onSearch, }: import('./DropdownSearchInput').DropdownSearchInputProps): import("react/jsx-runtime").JSX.Element;
102
+ displayName: string;
103
+ };
100
104
  };
101
105
  export default Dropdown;
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { forwardRef, useImperativeHandle, useMemo, useEffect } from "react";
2
+ import { forwardRef, useState, useRef, useCallback, useImperativeHandle, useMemo, useEffect } from "react";
3
3
  import clsx from "clsx";
4
4
  import useDropdown from "../../hooks/useDropdown/useDropdown.js";
5
5
  import DropdownCheckboxItem from "./DropdownCheckboxItem.js";
@@ -8,6 +8,7 @@ import DropdownItem from "./DropdownItem.js";
8
8
  import DropdownMenu from "./DropdownMenu.js";
9
9
  import DropdownMenuGroup from "./DropdownMenuGroup.js";
10
10
  import DropdownRadioItem from "./DropdownRadioItem.js";
11
+ import DropdownSearchInput from "./DropdownSearchInput.js";
11
12
  import DropdownSeparator from "./DropdownSeparator.js";
12
13
  import DropdownTrigger from "./DropdownTrigger.js";
13
14
  import useClickOutside from "../../hooks/useClickOutside/useClickOutside.js";
@@ -24,7 +25,15 @@ const Root = /* @__PURE__ */ forwardRef(({
24
25
  openOnSpace = !0,
25
26
  focusOnMouseEnter = !0
26
27
  }, refDropdown) => {
27
- const {
28
+ const [searchQuery, setSearchQuery] = useState(""), [hasMatches, setHasMatches] = useState(!0), matchMapRef = useRef(/* @__PURE__ */ new Map()), reportMatch = useCallback((id, isMatch) => {
29
+ matchMapRef.current.set(id, isMatch);
30
+ const next = [...matchMapRef.current.values()].some(Boolean);
31
+ setHasMatches((prev) => prev !== next ? next : prev);
32
+ }, []), unregisterMatch = useCallback((id) => {
33
+ matchMapRef.current.delete(id);
34
+ const next = matchMapRef.current.size === 0 || [...matchMapRef.current.values()].some(Boolean);
35
+ setHasMatches((prev) => prev !== next ? next : prev);
36
+ }, []), {
28
37
  visible,
29
38
  isFocused,
30
39
  triggerProps,
@@ -58,14 +67,19 @@ const Root = /* @__PURE__ */ forwardRef(({
58
67
  block,
59
68
  setVisible,
60
69
  openDropdown,
61
- closeDropdown
62
- }), [visible, isFocused, triggerProps, menuProps, itemProps, itemRefs, block, setVisible, openDropdown, closeDropdown]), dropdown = clsx("dropdown", {
70
+ closeDropdown,
71
+ searchQuery,
72
+ setSearchQuery,
73
+ hasMatches,
74
+ reportMatch,
75
+ unregisterMatch
76
+ }), [visible, isFocused, triggerProps, menuProps, itemProps, itemRefs, block, setVisible, openDropdown, closeDropdown, searchQuery, hasMatches, reportMatch, unregisterMatch]), dropdown = clsx("dropdown", {
63
77
  "w-100": block,
64
78
  "dropdown-nowrap": noWrap,
65
79
  overflow
66
80
  });
67
81
  return useEffect(() => {
68
- onToggle == null || onToggle(visible);
82
+ onToggle == null || onToggle(visible), visible || setSearchQuery("");
69
83
  }, [visible]), /* @__PURE__ */ jsx(DropdownContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { ref, className: dropdown, children: typeof children == "function" ? children(triggerProps, itemRefs, setVisible) : children }) });
70
84
  }), Dropdown = /* @__PURE__ */ Object.assign(Root, {
71
85
  Trigger: DropdownTrigger,
@@ -74,7 +88,8 @@ const Root = /* @__PURE__ */ forwardRef(({
74
88
  Separator: DropdownSeparator,
75
89
  CheckboxItem: DropdownCheckboxItem,
76
90
  RadioItem: DropdownRadioItem,
77
- MenuGroup: DropdownMenuGroup
91
+ MenuGroup: DropdownMenuGroup,
92
+ SearchInput: DropdownSearchInput
78
93
  });
79
94
  export {
80
95
  Dropdown as default
@@ -16,9 +16,14 @@ interface DropdownCheckboxItem {
16
16
  * OnKeyDown handler
17
17
  */
18
18
  onChange: (value: string | number) => void;
19
+ /**
20
+ * Value used to filter this item when `Dropdown.SearchInput` is present.
21
+ * If provided, the item is hidden when the search query doesn't match.
22
+ */
23
+ searchValue?: string;
19
24
  }
20
25
  declare const DropdownCheckboxItem: {
21
- ({ children, value, model, onChange, }: DropdownCheckboxItem): import("react/jsx-runtime").JSX.Element;
26
+ ({ children, value, model, onChange, searchValue, }: DropdownCheckboxItem): import("react/jsx-runtime").JSX.Element;
22
27
  displayName: string;
23
28
  };
24
29
  export default DropdownCheckboxItem;
@@ -1,33 +1,38 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useId } from "react";
3
2
  import clsx from "clsx";
4
3
  import { useDropdownContext } from "./DropdownContext.js";
4
+ import { useDropdownItemFilter } from "./useDropdownItemFilter.js";
5
+ import DropdownItemHidden from "./DropdownItemHidden.js";
5
6
  import Checkbox from "../Checkbox/Checkbox.js";
6
7
  const DropdownCheckboxItem = ({
7
8
  children,
8
9
  value,
9
10
  model,
10
- onChange
11
+ onChange,
12
+ searchValue
11
13
  }) => {
12
14
  const {
13
15
  itemProps,
14
16
  itemRefs,
15
17
  isFocused
16
18
  } = useDropdownContext(), {
19
+ id,
20
+ isFiltered
21
+ } = useDropdownItemFilter(searchValue), {
17
22
  onMenuItemKeyDown,
18
23
  onMenuItemMouseEnter
19
- } = itemProps, id = useId(), checked = model.includes(value), checkboxProps = {
24
+ } = itemProps, checked = model.includes(value), checkboxProps = {
20
25
  value,
21
26
  model,
22
27
  checked,
23
28
  readOnly: !0
24
29
  }, dropdownCheckboxItem = clsx("dropdown-item c-pointer", {
25
30
  focus: isFocused === id
26
- });
27
- return /* @__PURE__ */ jsx("div", { id, ref: (el) => itemRefs.current[id] = el, role: "menuitemcheckbox", "aria-checked": checked, onMouseUp: () => onChange(value), onKeyDown: (event) => onMenuItemKeyDown(event, () => onChange(value)), onMouseEnter: onMenuItemMouseEnter, tabIndex: checked ? 0 : -1, className: dropdownCheckboxItem, children: /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center justify-content-between position-relative", children: [
31
+ }), content = /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center justify-content-between position-relative", children: [
28
32
  children,
29
33
  /* @__PURE__ */ jsx(Checkbox, { ...checkboxProps })
30
- ] }) });
34
+ ] });
35
+ return isFiltered ? /* @__PURE__ */ jsx(DropdownItemHidden, { collapse: !0, children: content }) : /* @__PURE__ */ jsx("div", { id, ref: (el) => itemRefs.current[id] = el, role: "menuitemcheckbox", "aria-checked": checked, onMouseUp: () => onChange(value), onKeyDown: (event) => onMenuItemKeyDown(event, () => onChange(value)), onMouseEnter: onMenuItemMouseEnter, tabIndex: checked ? 0 : -1, className: dropdownCheckboxItem, children: content });
31
36
  };
32
37
  export {
33
38
  DropdownCheckboxItem as default
@@ -2,6 +2,11 @@ import { UseDropdownProps } from '../../hooks/useDropdown/useDropdown';
2
2
  type OmittedProps = Omit<UseDropdownProps, 'triggerRef' | 'menuRef'>;
3
3
  export interface DropdownContextProps extends OmittedProps {
4
4
  block?: boolean;
5
+ searchQuery: string;
6
+ setSearchQuery: (query: string) => void;
7
+ hasMatches: boolean;
8
+ reportMatch: (id: string, isMatch: boolean) => void;
9
+ unregisterMatch: (id: string) => void;
5
10
  }
6
11
  export declare const DropdownContext: import('react').Context<DropdownContextProps | null>;
7
12
  export declare const useDropdownContext: () => DropdownContextProps;
@@ -29,9 +29,14 @@ export interface DropdownItemProps {
29
29
  * Disabled status
30
30
  */
31
31
  disabled?: boolean;
32
+ /**
33
+ * Value used to filter this item when `Dropdown.SearchInput` is present.
34
+ * If provided, the item is hidden when the search query doesn't match.
35
+ */
36
+ searchValue?: string;
32
37
  }
33
38
  declare const DropdownItem: {
34
- ({ type, icon, onClick, children, className, minWidth, disabled, ...restProps }: DropdownItemProps): import("react/jsx-runtime").JSX.Element;
39
+ ({ type, icon, onClick, children, className, minWidth, disabled, searchValue, ...restProps }: DropdownItemProps): import("react/jsx-runtime").JSX.Element;
35
40
  displayName: string;
36
41
  };
37
42
  export default DropdownItem;
@@ -1,7 +1,8 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useId } from "react";
3
2
  import clsx from "clsx";
4
3
  import { useDropdownContext } from "./DropdownContext.js";
4
+ import { useDropdownItemFilter } from "./useDropdownItemFilter.js";
5
+ import DropdownItemHidden from "./DropdownItemHidden.js";
5
6
  const DropdownItem = ({
6
7
  type = "action",
7
8
  icon,
@@ -10,6 +11,7 @@ const DropdownItem = ({
10
11
  className,
11
12
  minWidth,
12
13
  disabled,
14
+ searchValue,
13
15
  ...restProps
14
16
  }) => {
15
17
  const {
@@ -17,12 +19,15 @@ const DropdownItem = ({
17
19
  itemRefs,
18
20
  isFocused
19
21
  } = useDropdownContext(), {
22
+ id,
23
+ isFiltered
24
+ } = useDropdownItemFilter(searchValue), {
20
25
  onMenuItemKeyDown,
21
26
  onMenuItemMouseEnter,
22
27
  onMenuItemClick
23
28
  } = itemProps, handleOnClick = (event) => {
24
29
  disabled || (onClick == null || onClick(event), type === "action" && (onMenuItemClick(), event.stopPropagation()));
25
- }, id = useId(), dropdownItem = clsx("dropdown-item", {
30
+ }, dropdownItem = clsx("dropdown-item", {
26
31
  focus: isFocused === id
27
32
  }, {
28
33
  "text-gray-600": disabled
@@ -30,11 +35,11 @@ const DropdownItem = ({
30
35
  ...minWidth && {
31
36
  minWidth: `${minWidth}px`
32
37
  }
33
- };
34
- return /* @__PURE__ */ jsx("div", { id, role: "menuitem", style, ref: (el) => itemRefs.current[id] = el, tabIndex: isFocused === id ? 0 : -1, className: dropdownItem, "aria-current": isFocused === id, onClick: handleOnClick, onMouseEnter: onMenuItemMouseEnter, onKeyDown: (event) => onMenuItemKeyDown(event, onClick), ...restProps, children: /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center", children: [
38
+ }, content = /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center", children: [
35
39
  icon,
36
40
  children
37
- ] }) });
41
+ ] });
42
+ return isFiltered ? /* @__PURE__ */ jsx(DropdownItemHidden, { children: content }) : /* @__PURE__ */ jsx("div", { id, role: "menuitem", style, ref: (el) => itemRefs.current[id] = el, tabIndex: isFocused === id ? 0 : -1, className: dropdownItem, "aria-current": isFocused === id, onClick: handleOnClick, onMouseEnter: onMenuItemMouseEnter, onKeyDown: (event) => onMenuItemKeyDown(event, onClick), ...restProps, children: content });
38
43
  };
39
44
  export {
40
45
  DropdownItem as default
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ interface DropdownItemHiddenProps {
3
+ children: ReactNode;
4
+ /**
5
+ * When true, collapses height to 0 while keeping the item in the flow.
6
+ * Use this when the container width must stay stable during search filtering.
7
+ * Defaults to false (display: none).
8
+ */
9
+ collapse?: boolean;
10
+ }
11
+ declare const DropdownItemHidden: ({ children, collapse, }: DropdownItemHiddenProps) => import("react/jsx-runtime").JSX.Element;
12
+ export default DropdownItemHidden;
@@ -0,0 +1,19 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ const DropdownItemHidden = ({
3
+ children,
4
+ collapse
5
+ }) => /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: collapse ? {
6
+ height: 0,
7
+ overflow: "hidden",
8
+ margin: 0,
9
+ pointerEvents: "none",
10
+ width: "100%",
11
+ maxWidth: "max-content"
12
+ } : {
13
+ display: "none",
14
+ width: "100%",
15
+ maxWidth: "max-content"
16
+ }, children });
17
+ export {
18
+ DropdownItemHidden as default
19
+ };
@@ -16,9 +16,14 @@ export interface DropdownRadioItemProps {
16
16
  * onKeyDown, onMouseUp handlers
17
17
  */
18
18
  onChange: (value: string) => void;
19
+ /**
20
+ * Value used to filter this item when `Dropdown.SearchInput` is present.
21
+ * If provided, the item is hidden when the search query doesn't match.
22
+ */
23
+ searchValue?: string;
19
24
  }
20
25
  declare const DropdownRadioItem: {
21
- ({ children, value, model, onChange, }: DropdownRadioItemProps): import("react/jsx-runtime").JSX.Element;
26
+ ({ children, value, model, onChange, searchValue, }: DropdownRadioItemProps): import("react/jsx-runtime").JSX.Element;
22
27
  displayName: string;
23
28
  };
24
29
  export default DropdownRadioItem;
@@ -1,33 +1,38 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useId } from "react";
3
2
  import clsx from "clsx";
4
3
  import { useDropdownContext } from "./DropdownContext.js";
4
+ import { useDropdownItemFilter } from "./useDropdownItemFilter.js";
5
+ import DropdownItemHidden from "./DropdownItemHidden.js";
5
6
  import Radio from "../Radio/Radio.js";
6
7
  const DropdownRadioItem = ({
7
8
  children,
8
9
  value,
9
10
  model,
10
- onChange
11
+ onChange,
12
+ searchValue
11
13
  }) => {
12
14
  const {
13
15
  itemProps,
14
16
  itemRefs,
15
17
  isFocused
16
18
  } = useDropdownContext(), {
19
+ id,
20
+ isFiltered
21
+ } = useDropdownItemFilter(searchValue), {
17
22
  onMenuItemKeyDown,
18
23
  onMenuItemMouseEnter
19
- } = itemProps, id = useId(), radioProps = {
24
+ } = itemProps, radioProps = {
20
25
  value,
21
26
  model,
22
27
  checked: value === model,
23
28
  readOnly: !0
24
29
  }, dropdownRadioItem = clsx("dropdown-item c-pointer", {
25
30
  focus: isFocused === id
26
- });
27
- return /* @__PURE__ */ jsx("div", { id, ref: (el) => itemRefs.current[id] = el, role: "menuitemradio", "aria-checked": value === model, onMouseUp: () => onChange(value), onKeyDown: (event) => onMenuItemKeyDown(event, () => onChange(value)), onMouseEnter: onMenuItemMouseEnter, tabIndex: value === model ? 0 : -1, className: dropdownRadioItem, children: /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center justify-content-between position-relative", children: [
31
+ }), content = /* @__PURE__ */ jsxs("div", { className: "d-flex gap-8 align-items-center justify-content-between position-relative", children: [
28
32
  children,
29
33
  /* @__PURE__ */ jsx(Radio, { ...radioProps, className: "position-absolute start-0 end-0 top-0 bottom-0 opacity-0" })
30
- ] }) });
34
+ ] });
35
+ return isFiltered ? /* @__PURE__ */ jsx(DropdownItemHidden, { children: content }) : /* @__PURE__ */ jsx("div", { id, ref: (el) => itemRefs.current[id] = el, role: "menuitemradio", "aria-checked": value === model, onMouseUp: () => onChange(value), onKeyDown: (event) => onMenuItemKeyDown(event, () => onChange(value)), onMouseEnter: onMenuItemMouseEnter, tabIndex: value === model ? 0 : -1, className: dropdownRadioItem, children: content });
31
36
  };
32
37
  export {
33
38
  DropdownRadioItem as default
@@ -0,0 +1,20 @@
1
+ export interface DropdownSearchInputProps {
2
+ /**
3
+ * Placeholder text for the search input
4
+ */
5
+ placeholder?: string;
6
+ /**
7
+ * Label shown when no items match the search query
8
+ */
9
+ noResultsLabel?: string;
10
+ /**
11
+ * Called whenever the search query changes.
12
+ * Useful to track the current query outside the Dropdown context.
13
+ */
14
+ onSearch?: (query: string) => void;
15
+ }
16
+ declare const DropdownSearchInput: {
17
+ ({ placeholder, noResultsLabel, onSearch, }: DropdownSearchInputProps): import("react/jsx-runtime").JSX.Element;
18
+ displayName: string;
19
+ };
20
+ export default DropdownSearchInput;
@@ -0,0 +1,25 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useDropdownContext } from "./DropdownContext.js";
3
+ import SearchBar from "../SearchBar/SearchBar.js";
4
+ const DropdownSearchInput = ({
5
+ placeholder = "Rechercher...",
6
+ noResultsLabel = "Pas de résultat",
7
+ onSearch
8
+ }) => {
9
+ const {
10
+ searchQuery,
11
+ setSearchQuery,
12
+ hasMatches
13
+ } = useDropdownContext();
14
+ return /* @__PURE__ */ jsxs("div", { className: "px-8 pb-8", children: [
15
+ /* @__PURE__ */ jsx(SearchBar, { isVariant: !0, clearable: !0, size: "md", placeholder, value: searchQuery, onChange: (e) => {
16
+ setSearchQuery(e.target.value), onSearch == null || onSearch(e.target.value);
17
+ }, onKeyDown: (e) => {
18
+ ["ArrowUp", "ArrowDown", "Enter", " "].includes(e.key) && e.stopPropagation();
19
+ } }),
20
+ searchQuery && !hasMatches && /* @__PURE__ */ jsx("p", { className: "body-2 text-gray-700 text-center mt-8 mb-0", children: noResultsLabel })
21
+ ] });
22
+ };
23
+ export {
24
+ DropdownSearchInput as default
25
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared filtering logic for Dropdown item components.
3
+ * Computes whether the item is hidden by the current search query,
4
+ * and keeps the match registry in sync via reportMatch/unregisterMatch.
5
+ *
6
+ * @returns `id` – stable element id to spread on the DOM node and itemRefs
7
+ * @returns `isFiltered` – true when the item should be hidden
8
+ */
9
+ export declare const useDropdownItemFilter: (searchValue: string | undefined) => {
10
+ id: string;
11
+ isFiltered: boolean;
12
+ };
@@ -0,0 +1,19 @@
1
+ import { useId, useLayoutEffect } from "react";
2
+ import { useDropdownContext } from "./DropdownContext.js";
3
+ const useDropdownItemFilter = (searchValue) => {
4
+ const {
5
+ searchQuery,
6
+ reportMatch,
7
+ unregisterMatch
8
+ } = useDropdownContext(), id = useId(), isFiltered = searchValue !== void 0 && searchQuery !== "" && !searchValue.toLowerCase().includes(searchQuery.toLowerCase());
9
+ return useLayoutEffect(() => {
10
+ if (searchValue !== void 0)
11
+ return reportMatch(id, !isFiltered), () => unregisterMatch(id);
12
+ }, [id, isFiltered, searchValue, reportMatch, unregisterMatch]), {
13
+ id,
14
+ isFiltered
15
+ };
16
+ };
17
+ export {
18
+ useDropdownItemFilter
19
+ };
@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";
4
4
  import { useEdificeClient } from "../../../providers/EdificeClientProvider/EdificeClientProvider.hook.js";
5
5
  import { useEdificeTheme } from "../../../providers/EdificeThemeProvider/EdificeThemeProvider.hook.js";
6
6
  import SvgIconRafterDown from "../../../modules/icons/components/IconRafterDown.js";
7
- import SvgIconCommunities from "../../../modules/icons/components/nav/IconCommunities.js";
8
7
  import SvgIconCommunity from "../../../modules/icons/components/nav/IconCommunity.js";
9
8
  import SvgIconDisconnect from "../../../modules/icons/components/nav/IconDisconnect.js";
10
9
  import SvgIconHome from "../../../modules/icons/components/nav/IconHome.js";
@@ -68,7 +67,6 @@ const Header = ({
68
67
  userName,
69
68
  welcomeUser,
70
69
  communityWorkflow,
71
- communitiesWorkflow,
72
70
  conversationWorflow,
73
71
  searchWorkflow,
74
72
  isCollapsed,
@@ -99,7 +97,6 @@ const Header = ({
99
97
  /* @__PURE__ */ jsx(SvgIconOneMessaging, { className: "icon notification" }),
100
98
  /* @__PURE__ */ jsx(VisuallyHidden, { children: t("navbar.messages") })
101
99
  ] }) }),
102
- communitiesWorkflow && /* @__PURE__ */ jsx(NavItem, { children: /* @__PURE__ */ jsx(NavLink, { link: "/communities", translate: t("navbar.community"), children: /* @__PURE__ */ jsx(SvgIconCommunities, { className: "icon communities text-purple-500" }) }) }),
103
100
  /* @__PURE__ */ jsx(NavItem, { children: /* @__PURE__ */ jsx(NavLink, { link: "/userbook/mon-compte", className: "dropdown-item", translate: t("navbar.myaccount"), children: /* @__PURE__ */ jsx(SvgIconOneProfile, { className: "icon user" }) }) }),
104
101
  currentLanguage === "fr" && hasOldHelpEnableWorkflow ? /* @__PURE__ */ jsxs(NavItem, { children: [
105
102
  /* @__PURE__ */ jsxs("button", { className: "nav-link", onClick: () => {
@@ -180,10 +177,6 @@ const Header = ({
180
177
  /* @__PURE__ */ jsx(SvgIconCommunity, { className: "icon community" }),
181
178
  /* @__PURE__ */ jsx("span", { className: "nav-text", children: t("navbar.community") })
182
179
  ] }) }),
183
- communitiesWorkflow && /* @__PURE__ */ jsx(NavItem, { children: /* @__PURE__ */ jsxs("a", { href: "/communities", className: "nav-link dropdown-item", children: [
184
- /* @__PURE__ */ jsx(SvgIconCommunities, { className: "icon communities" }),
185
- /* @__PURE__ */ jsx("span", { className: "nav-text", children: t("navbar.community") })
186
- ] }) }),
187
180
  searchWorkflow ? /* @__PURE__ */ jsx(SearchEngine, {}) : null,
188
181
  /* @__PURE__ */ jsx(NavItem, { children: /* @__PURE__ */ jsxs("a", { href: "/userbook/mon-compte", className: "nav-link dropdown-item", children: [
189
182
  /* @__PURE__ */ jsx(Avatar, { alt: userName, size: "sm", src: userAvatar, variant: "circle", className: "bg-white", width: "32", height: "32" }),
@@ -14,7 +14,7 @@ function useHeader({
14
14
  t
15
15
  } = useTranslation(), title = t(appCode), [isCollapsed, setIsCollapsed] = useState(!0), [appsRef, isAppsHovered] = useHover(), popoverAppsId = useId(), popoverSearchId = useId(), userAvatar = avatar, userName = user == null ? void 0 : user.username, welcomeUser = t("welcome", {
16
16
  username: user == null ? void 0 : user.firstName
17
- }), bookmarkedApps = useBookmark(), communityWorkflow = useHasWorkflow("net.atos.entng.community.controllers.CommunityController|view"), communitiesWorkflow = useHasWorkflow("community.access"), conversationWorflow = useHasWorkflow("org.entcore.conversation.controllers.ConversationController|view"), searchWorkflow = useHasWorkflow("fr.openent.searchengine.controllers.SearchEngineController|view"), toggleCollapsedNav = useCallback(() => {
17
+ }), bookmarkedApps = useBookmark(), communityWorkflow = useHasWorkflow("net.atos.entng.community.controllers.CommunityController|view"), conversationWorflow = useHasWorkflow("org.entcore.conversation.controllers.ConversationController|view"), searchWorkflow = useHasWorkflow("fr.openent.searchengine.controllers.SearchEngineController|view"), toggleCollapsedNav = useCallback(() => {
18
18
  setIsCollapsed(!isCollapsed);
19
19
  }, [isCollapsed]);
20
20
  return useMemo(() => ({
@@ -28,12 +28,11 @@ function useHeader({
28
28
  userName,
29
29
  welcomeUser,
30
30
  communityWorkflow,
31
- communitiesWorkflow,
32
31
  conversationWorflow,
33
32
  searchWorkflow,
34
33
  isCollapsed,
35
34
  toggleCollapsedNav
36
- }), [appsRef, bookmarkedApps, communitiesWorkflow, communityWorkflow, conversationWorflow, isAppsHovered, isCollapsed, popoverAppsId, popoverSearchId, searchWorkflow, title, toggleCollapsedNav, userAvatar, userName, welcomeUser]);
35
+ }), [appsRef, bookmarkedApps, communityWorkflow, conversationWorflow, isAppsHovered, isCollapsed, popoverAppsId, popoverSearchId, searchWorkflow, title, toggleCollapsedNav, userAvatar, userName, welcomeUser]);
37
36
  }
38
37
  export {
39
38
  useHeader as default
@@ -0,0 +1,17 @@
1
+ export interface PaginationProps {
2
+ /** Current page (1-based) */
3
+ current: number;
4
+ /** Total number of items */
5
+ total: number;
6
+ /** Number of items per page */
7
+ pageSize: number;
8
+ /** Called when the page changes */
9
+ onChange: (page: number) => void;
10
+ /** Optional class for styling purpose */
11
+ className?: string;
12
+ }
13
+ /**
14
+ * Pagination component for navigating through pages of results.
15
+ * Wraps antd Pagination with a simplified, stable API.
16
+ */
17
+ export declare function Pagination({ current, total, pageSize, onChange, className, }: PaginationProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Pagination as Pagination$1 } from "antd";
3
+ function Pagination({
4
+ current,
5
+ total,
6
+ pageSize,
7
+ onChange,
8
+ className
9
+ }) {
10
+ return /* @__PURE__ */ jsx(Pagination$1, { align: "center", showSizeChanger: !1, current, total, pageSize, onChange, className });
11
+ }
12
+ export {
13
+ Pagination
14
+ };
@@ -0,0 +1 @@
1
+ export * from './Pagination';
@@ -21,7 +21,7 @@ const UserRightsBookmarkRow = ({
21
21
  return /* @__PURE__ */ jsxs("tr", { "data-testid": "user-rights-list-bookmark-row", children: [
22
22
  /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(SvgIconBookmark, {}) }),
23
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, rightDef]) => /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Checkbox, { checked: bookmark.permission.includes(rightName), onChange: () => onToggleRight(bookmark.id, rightName), disabled: isReadOnly || rightDef.isReadOnlyCheckbox, "aria-label": `${bookmark.name} - ${rightName}`, "data-testid": `user-rights-list-bookmark-${rightName}-checkbox` }) }, rightName)),
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
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
26
  ] });
27
27
  };
@@ -27,7 +27,7 @@ const UserRightsItem = ({
27
27
  return /* @__PURE__ */ jsxs("tr", { "data-testid": "user-rights-list-item-row", className: rowClassName, "aria-label": bookmarkName ? `${item.displayName} - ${bookmarkName}` : void 0, children: [
28
28
  /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Avatar, { src: getAvatarURL(item.recipientId, item.recipientType), size: "xs", alt: item.displayName, variant: "circle" }) }),
29
29
  /* @__PURE__ */ jsx("td", { children: item.displayName }),
30
- Object.entries(resourceRights).map(([rightName, rightDef]) => /* @__PURE__ */ jsx("td", { "data-testid": `user-rights-list-item-${rightName}-checkbox`, children: /* @__PURE__ */ jsx(Checkbox, { checked: item.permission.includes(rightName), onChange: isReadOnly || rightDef.isReadOnlyCheckbox ? void 0 : () => handleChange(rightName), disabled: isReadOnly || rightDef.isReadOnlyCheckbox, "aria-label": `${item.displayName} - ${rightName}` }) }, rightName)),
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
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
32
  ] });
33
33
  };
@@ -68,7 +68,7 @@ const UserRightsList = /* @__PURE__ */ forwardRef(({
68
68
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
69
69
  /* @__PURE__ */ jsx("th", { scope: "col", className: "w-32", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.avatar.shared.alt") }) }),
70
70
  /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.search.placeholder") }) }),
71
- Object.entries(resourceRights).map(([rightName, rightDef]) => /* @__PURE__ */ jsx("th", { children: rightDef.displayName ?? rightName }, rightName)),
71
+ Object.entries(resourceRights).map(([rightName]) => /* @__PURE__ */ jsx("th", { children: rightName }, rightName)),
72
72
  !isReadOnly && /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("close") }) })
73
73
  ] }) }),
74
74
  /* @__PURE__ */ jsxs("tbody", { children: [
@@ -6,13 +6,8 @@ export type ResourceRightDefinition = {
6
6
  default: boolean;
7
7
  requires: ResourceRightName[];
8
8
  excludes: ResourceRightName[];
9
- displayName?: string;
10
- isReadOnlyCheckbox?: boolean;
11
9
  };
12
- type AtLeastOne<T extends object> = Partial<T> & {
13
- [K in keyof T]: Pick<T, K>;
14
- }[keyof T];
15
- export type ResourceRights = AtLeastOne<Record<ResourceRightName, ResourceRightDefinition>>;
10
+ export type ResourceRights = Record<ResourceRightName, ResourceRightDefinition>;
16
11
  export interface BookmarkUser {
17
12
  id: string;
18
13
  displayName: string;
@@ -33,6 +33,7 @@ export * from './Logo';
33
33
  export * from './MediaViewer';
34
34
  export * from './Menu';
35
35
  export * from './Modal';
36
+ export * from './Pagination';
36
37
  export * from './Popover';
37
38
  export * from './PreventPropagation';
38
39
  export * from './PromotionCard';
@@ -47,17 +47,17 @@ const useDropdown = (placement, extraTriggerKeyDownHandler, isTriggerHovered = !
47
47
  }
48
48
  }
49
49
  }, [activeIndex]);
50
- const nextItem = () => {
51
- const itemCount = Object.values(itemRefs.current).length;
52
- setActiveIndex((prevIndex) => (prevIndex + 1) % itemCount);
50
+ const getVisibleItems = () => Object.values(itemRefs.current).filter((item) => !!item), nextItem = () => {
51
+ const count = getVisibleItems().length;
52
+ count !== 0 && setActiveIndex((prevIndex) => (prevIndex + 1) % count);
53
53
  }, previousItem = () => {
54
- const itemCount = Object.values(itemRefs.current).length;
55
- setActiveIndex((prevIndex) => (prevIndex - 1 + itemCount) % itemCount);
54
+ const count = getVisibleItems().length;
55
+ count !== 0 && setActiveIndex((prevIndex) => (prevIndex - 1 + count) % count);
56
56
  }, firstItem = () => {
57
57
  setActiveIndex(0);
58
58
  }, lastItem = () => {
59
- const itemCount = Object.values(itemRefs.current).length;
60
- setActiveIndex(itemCount - 1);
59
+ const count = getVisibleItems().length;
60
+ count !== 0 && setActiveIndex(count - 1);
61
61
  }, openDropdown = useCallback(() => {
62
62
  setVisible(!0);
63
63
  }, []), closeDropdown = useCallback(() => {
@@ -90,7 +90,7 @@ const useDropdown = (placement, extraTriggerKeyDownHandler, isTriggerHovered = !
90
90
  extraTriggerKeyDownHandler == null || extraTriggerKeyDownHandler(event), stopEvents(flag, event);
91
91
  }, [closeDropdown, openDropdown]), onMenuItemMouseEnter = (event) => {
92
92
  if (focusOnMouseEnter) {
93
- const index = Object.values(itemRefs.current).findIndex((item) => item.id === event.currentTarget.getAttribute("id"));
93
+ const index = Object.values(itemRefs.current).filter((item) => !!item).findIndex((item) => item.id === event.currentTarget.getAttribute("id"));
94
94
  setActiveIndex(index);
95
95
  }
96
96
  }, onMenuItemKeyDown = useCallback((event, onSuccess) => {
@@ -104,7 +104,12 @@ const useDropdown = (placement, extraTriggerKeyDownHandler, isTriggerHovered = !
104
104
  break;
105
105
  case " ":
106
106
  case "Enter":
107
- activeIndex !== -1 && (Object.values(itemRefs.current)[activeIndex].getAttribute("role") === "menuitem" && triggerRef.current && (triggerRef.current.focus(), setVisible(!1)), onSuccess == null || onSuccess()), flag = !0;
107
+ if (activeIndex !== -1) {
108
+ const currentItem = getVisibleItems()[activeIndex];
109
+ if (!currentItem) break;
110
+ currentItem.getAttribute("role") === "menuitem" && triggerRef.current && (triggerRef.current.focus(), setVisible(!1)), onSuccess == null || onSuccess();
111
+ }
112
+ flag = !0;
108
113
  break;
109
114
  case "ArrowDown":
110
115
  case "Down":
@@ -90,7 +90,7 @@ function useZendeskGuide() {
90
90
  suppress: !0
91
91
  }
92
92
  }
93
- }), window.zE("webWidget", "close"), window.open("/support", "_blank"));
93
+ }), window.zE("webWidget", "close"), window.open("/support/tickets/new", "_blank"));
94
94
  });
95
95
  };
96
96
  }
package/dist/index.js CHANGED
@@ -126,6 +126,7 @@ import { Layout } from "./components/Layout/Layout.js";
126
126
  import { List } from "./components/List/List.js";
127
127
  import { Menu } from "./components/Menu/components/Menu.js";
128
128
  import { MockedProvider } from "./providers/MockedProvider/MockedProvider.js";
129
+ import { Pagination } from "./components/Pagination/Pagination.js";
129
130
  import { Popover, PopoverBody, PopoverFooter, PopoverHeader } from "./components/Popover/Popover.js";
130
131
  import { ResourceModal } from "./modules/modals/ResourceModal/ResourceModal.js";
131
132
  import { Tabs } from "./components/Tabs/components/Tabs.js";
@@ -210,6 +211,7 @@ export {
210
211
  MockedProvider,
211
212
  default43 as Modal,
212
213
  default44 as OnboardingModal,
214
+ Pagination,
213
215
  Popover,
214
216
  PopoverBody,
215
217
  PopoverFooter,
@@ -5,7 +5,7 @@ const SvgIconCommunities = ({
5
5
  ...props
6
6
  }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 50 50", "aria-hidden": "true", "aria-labelledby": titleId, ...props, children: [
7
7
  title ? /* @__PURE__ */ jsx("title", { id: titleId, children: title }) : null,
8
- /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M25.807 33.165c4.726.17 8 3.997 8 8.5 0 .984-.795 1.775-1.775 1.775H18.977a1.774 1.774 0 0 1-1.776-1.775v-.201h-.004a8.303 8.303 0 0 1 8.61-8.299M8.61 24.451c4.726.17 8.001 3.997 8.001 8.5 0 .984-.796 1.776-1.775 1.776H1.776A1.774 1.774 0 0 1 0 32.95v-.201a8.303 8.303 0 0 1 8.61-8.299M41.61 24.006c4.499.162 8.001 3.996 8.001 8.5 0 .984-.796 1.775-1.775 1.775H34.779a1.774 1.774 0 0 1-1.775-1.775v-.201H33a8.303 8.303 0 0 1 8.61-8.3M25.142 20a5.143 5.143 0 1 1 0 10.285 5.143 5.143 0 0 1 0-10.285M8.308 11.627a5.141 5.141 0 1 1 0 10.282 5.141 5.141 0 0 1 0-10.282M41.691 11.627a5.142 5.142 0 1 1 .001 10.284 5.142 5.142 0 0 1 0-10.284M24.997 5.557a5.143 5.143 0 1 1 0 10.285 5.143 5.143 0 0 1 0-10.285" })
8
+ /* @__PURE__ */ jsx("path", { d: "M25.807 33.165c4.726.17 8 3.997 8 8.5 0 .984-.795 1.775-1.775 1.775H18.977a1.774 1.774 0 0 1-1.776-1.775v-.201h-.004a8.303 8.303 0 0 1 8.61-8.299M8.61 24.451c4.726.17 8.001 3.997 8.001 8.5 0 .984-.796 1.776-1.775 1.776H1.776A1.774 1.774 0 0 1 0 32.95v-.201a8.303 8.303 0 0 1 8.61-8.299M41.61 24.006c4.499.162 8.001 3.996 8.001 8.5 0 .984-.796 1.775-1.775 1.775H34.779a1.774 1.774 0 0 1-1.775-1.775v-.201H33a8.303 8.303 0 0 1 8.61-8.3M25.142 20a5.143 5.143 0 1 1 0 10.285 5.143 5.143 0 0 1 0-10.285M8.308 11.627a5.141 5.141 0 1 1 0 10.282 5.141 5.141 0 0 1 0-10.282M41.691 11.627a5.142 5.142 0 1 1 .001 10.284 5.142 5.142 0 0 1 0-10.284M24.997 5.557a5.143 5.143 0 1 1 0 10.285 5.143 5.143 0 0 1 0-10.285" })
9
9
  ] });
10
10
  export {
11
11
  SvgIconCommunities as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.5.16-develop-pedago.20260414153809",
3
+ "version": "2.5.16-develop-integration.20260421203533",
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.16-develop-pedago.20260414153809",
139
- "@edifice.io/tiptap-extensions": "2.5.16-develop-pedago.20260414153809",
140
- "@edifice.io/utilities": "2.5.16-develop-pedago.20260414153809"
138
+ "@edifice.io/bootstrap": "2.5.16-develop-integration.20260421203533",
139
+ "@edifice.io/tiptap-extensions": "2.5.16-develop-integration.20260421203533",
140
+ "@edifice.io/utilities": "2.5.16-develop-integration.20260421203533"
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.16-develop-pedago.20260414153809",
172
- "@edifice.io/config": "2.5.16-develop-pedago.20260414153809"
171
+ "@edifice.io/client": "2.5.16-develop-integration.20260421203533",
172
+ "@edifice.io/config": "2.5.16-develop-integration.20260421203533"
173
173
  },
174
174
  "peerDependencies": {
175
175
  "@react-spring/web": "^9.7.5",