@edifice.io/react 2.6.0-develop.20260720155436 → 2.6.0-develop.20260721175941

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.
@@ -1,15 +1,19 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { Suspense, lazy } from "react";
2
3
  import clsx from "clsx";
3
4
  import { Toaster } from "react-hot-toast";
4
5
  import { useTranslation } from "react-i18next";
5
6
  import { useEdificeTheme } from "../../providers/EdificeThemeProvider/EdificeThemeProvider.hook.js";
6
7
  import Header from "./components/Header.js";
8
+ import HeaderNotificationsOverlay from "./components/HeaderNotificationsOverlay.js";
9
+ import { useOverlay } from "../PageLayout/hook/useOverlay.js";
10
+ import useUiOverride from "../../hooks/useUiOverride/useUiOverride.js";
7
11
  import useCookiesConsent from "../../hooks/useCookiesConsent/useCookiesConsent.js";
8
12
  import useZendeskGuide from "../../hooks/useZendeskGuide/useZendeskGuide.js";
9
13
  import useCantoo from "../../hooks/useCantoo/useCantoo.js";
10
14
  import Alert from "../Alert/Alert.js";
11
15
  import Button from "../Button/Button.js";
12
- const Layout = ({
16
+ const HeaderV2 = /* @__PURE__ */ lazy(() => import("../../modules/homepage/components/Header/Header.js")), Layout = ({
13
17
  children,
14
18
  headless = !1,
15
19
  whiteBg = !0,
@@ -18,7 +22,9 @@ const Layout = ({
18
22
  }) => {
19
23
  const {
20
24
  theme
21
- } = useEdificeTheme(), {
25
+ } = useEdificeTheme(), override = useUiOverride("layout.header"), isHeaderV2 = (override == null ? void 0 : override.variant) === "v2", {
26
+ toggleOverlay
27
+ } = useOverlay(), {
22
28
  t
23
29
  } = useTranslation(), {
24
30
  showCookiesConsent,
@@ -31,11 +37,12 @@ const Layout = ({
31
37
  "container-fluid": !headless,
32
38
  "rounded-4 border": (theme == null ? void 0 : theme.is1d) && !headless,
33
39
  "mt-24": (theme == null ? void 0 : theme.is1d) && !headless
34
- }, className), renderHeader = headless ? null : /* @__PURE__ */ jsx(Header, { is1d: theme == null ? void 0 : theme.is1d, src: theme == null ? void 0 : theme.basePath }), renderCookies = showCookiesConsent && /* @__PURE__ */ jsx(Alert, { type: "info", className: "m-12 rgpd", isConfirm: !0, position: "bottom-right", button: /* @__PURE__ */ jsx(Button, { color: "tertiary", variant: "ghost", onClick: handleConsultCookies, children: t("rgpd.cookies.banner.button.consult") }), onClose: handleCloseCookiesConsent, children: t("rgpd.cookies.banner.text1") }), renderToaster = /* @__PURE__ */ jsx(Toaster, { containerClassName: "toaster-container", toastOptions: {
40
+ }, className), renderHeader = headless ? null : isHeaderV2 ? /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(HeaderV2, { src: theme == null ? void 0 : theme.basePath, dataProduct: override == null ? void 0 : override.theme, onNotificationsClick: toggleOverlay }) }) : /* @__PURE__ */ jsx(Header, { is1d: theme == null ? void 0 : theme.is1d, src: theme == null ? void 0 : theme.basePath }), renderNotificationsOverlay = !headless && isHeaderV2 && /* @__PURE__ */ jsx(HeaderNotificationsOverlay, {}), renderCookies = showCookiesConsent && /* @__PURE__ */ jsx(Alert, { type: "info", className: "m-12 rgpd", isConfirm: !0, position: "bottom-right", button: /* @__PURE__ */ jsx(Button, { color: "tertiary", variant: "ghost", onClick: handleConsultCookies, children: t("rgpd.cookies.banner.button.consult") }), onClose: handleCloseCookiesConsent, children: t("rgpd.cookies.banner.text1") }), renderToaster = /* @__PURE__ */ jsx(Toaster, { containerClassName: "toaster-container", toastOptions: {
35
41
  position: "top-right"
36
42
  } });
37
43
  return /* @__PURE__ */ jsxs(Fragment, { children: [
38
44
  renderHeader,
45
+ renderNotificationsOverlay,
39
46
  /* @__PURE__ */ jsx("main", { className: classes, ...restProps, children }),
40
47
  renderToaster,
41
48
  renderCookies
@@ -0,0 +1,5 @@
1
+ declare const HeaderNotificationsOverlay: {
2
+ (): import("react/jsx-runtime").JSX.Element;
3
+ displayName: string;
4
+ };
5
+ export default HeaderNotificationsOverlay;
@@ -0,0 +1,18 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { NotificationListContainer } from "../../../modules/homepage/components/Notifications/NotificationListContainer.js";
3
+ import PageLayoutOverlay from "../../PageLayout/components/PageLayoutOverlay.js";
4
+ import { useOverlay } from "../../PageLayout/hook/useOverlay.js";
5
+ const HeaderNotificationsOverlay = () => {
6
+ const {
7
+ isOverlayOpen,
8
+ updateOverlayOpen
9
+ } = useOverlay(), handleClose = () => updateOverlayOpen(!1);
10
+ return (
11
+ // NotificationList renders its own header with a close button, so
12
+ // PageLayoutOverlay's default close button would be redundant (double X).
13
+ /* @__PURE__ */ jsx(PageLayoutOverlay, { onClose: handleClose, closeButton: !1, children: isOverlayOpen && /* @__PURE__ */ jsx(NotificationListContainer, { onCloseNotifications: handleClose }) })
14
+ );
15
+ };
16
+ export {
17
+ HeaderNotificationsOverlay as default
18
+ };
@@ -1,5 +1,5 @@
1
1
  import { create } from "zustand";
2
- import { createSelectors } from "../../../utilities/create-selectors/createSelectors.js";
2
+ import { createSelectors } from "../../../utilities/create-selectors/create-selectors.js";
3
3
  const useOverlayStore = createSelectors(create((set) => ({
4
4
  overlayOpen: !1,
5
5
  updateOverlayOpen: (value) => set((previousState) => ({
@@ -30,6 +30,7 @@ export * from './useToast';
30
30
  export * from './useToggle';
31
31
  export * from './useTrapFocus';
32
32
  export * from './useTrashedResource';
33
+ export * from './useUiOverride';
33
34
  export * from './useUpload';
34
35
  export * from './useUploadFiles';
35
36
  export * from './useUser';
@@ -0,0 +1 @@
1
+ export { default as useUiOverride } from './useUiOverride';
@@ -0,0 +1,5 @@
1
+ /** Read the platform-driven UI override registered under `key` in the theme-conf, normalized to an object form. */
2
+ export default function useUiOverride(key: string): {
3
+ variant: string;
4
+ theme?: string;
5
+ } | undefined;
@@ -0,0 +1,13 @@
1
+ import { useEdificeTheme } from "../../providers/EdificeThemeProvider/EdificeThemeProvider.hook.js";
2
+ function useUiOverride(key) {
3
+ var _a;
4
+ const {
5
+ theme
6
+ } = useEdificeTheme(), raw = (_a = theme == null ? void 0 : theme.uiOverrides) == null ? void 0 : _a[key];
7
+ return typeof raw == "string" ? {
8
+ variant: raw
9
+ } : raw;
10
+ }
11
+ export {
12
+ useUiOverride as default
13
+ };
package/dist/index.js CHANGED
@@ -106,16 +106,17 @@ import { default as default104 } from "./hooks/useToast/useToast.js";
106
106
  import { default as default105 } from "./hooks/useToggle/useToggle.js";
107
107
  import { default as default106 } from "./hooks/useTrapFocus/useTrapFocus.js";
108
108
  import { default as default107 } from "./hooks/useTrashedResource/useTrashedResource.js";
109
- import { default as default108 } from "./modules/modals/ResourceModal/hooks/useUpdateMutation.js";
110
- import { default as default109 } from "./hooks/useUpload/useUpload.js";
111
- import { default as default110 } from "./hooks/useUploadFiles/useUploadFiles.js";
112
- import { default as default111 } from "./hooks/useUser/useUser.js";
113
- import { default as default112 } from "./hooks/useWorkspaceFile/useWorkspaceFile.js";
114
- import { default as default113 } from "./hooks/useWorkspaceFolders/useWorkspaceFolders.js";
115
- import { WORKSPACE_SHARED_FOLDER_ID, WORKSPACE_USER_FOLDER_ID, default as default114 } from "./hooks/useWorkspaceFolders/useWorkspaceFoldersTree.js";
116
- import { default as default115 } from "./hooks/useWorkspaceSearch/useWorkspaceSearch.js";
117
- import { default as default116 } from "./hooks/useXitiTrackPageLoad/useXitiTrackPageLoad.js";
118
- import { default as default117 } from "./hooks/useZendeskGuide/useZendeskGuide.js";
109
+ import { default as default108 } from "./hooks/useUiOverride/useUiOverride.js";
110
+ import { default as default109 } from "./modules/modals/ResourceModal/hooks/useUpdateMutation.js";
111
+ import { default as default110 } from "./hooks/useUpload/useUpload.js";
112
+ import { default as default111 } from "./hooks/useUploadFiles/useUploadFiles.js";
113
+ import { default as default112 } from "./hooks/useUser/useUser.js";
114
+ import { default as default113 } from "./hooks/useWorkspaceFile/useWorkspaceFile.js";
115
+ import { default as default114 } from "./hooks/useWorkspaceFolders/useWorkspaceFolders.js";
116
+ import { WORKSPACE_SHARED_FOLDER_ID, WORKSPACE_USER_FOLDER_ID, default as default115 } from "./hooks/useWorkspaceFolders/useWorkspaceFoldersTree.js";
117
+ import { default as default116 } from "./hooks/useWorkspaceSearch/useWorkspaceSearch.js";
118
+ import { default as default117 } from "./hooks/useXitiTrackPageLoad/useXitiTrackPageLoad.js";
119
+ import { default as default118 } from "./hooks/useZendeskGuide/useZendeskGuide.js";
119
120
  import { AccessiblePalette, DefaultPalette } from "./components/ColorPicker/ColorPalette.js";
120
121
  import { AntProvider } from "./providers/AntThemeProvider/AntProvider.js";
121
122
  import { BetaSwitch } from "./components/BetaSwitch/BetaSwitch.js";
@@ -146,6 +147,7 @@ import { UserSearch } from "./components/UserSearch/UserSearch.js";
146
147
  import { VisibleType } from "./components/UserSearch/types/visible.js";
147
148
  import { buildTree, determineNewParentId, findItemIndexInTree, flattenNodes, flattenTree, generateUpdateData, getActiveAndOverNodes, getDragDepth, getIndicesToUpdate, getProjection, updateParentIds } from "./components/Tree/utilities/tree-sortable.js";
148
149
  import { checkUserRight } from "./utilities/check-user-rights/check-user-rights.js";
150
+ import { createSelectors } from "./utilities/create-selectors/create-selectors.js";
149
151
  import { emptyScreenMapping } from "./utilities/emptyscreen-mapping/emptyscreen-mapping.js";
150
152
  import { getRotateTransitionStyle } from "./utilities/rotate-transition-style/get-rotate-transition-style.js";
151
153
  import { invalidateQueriesWithFirstPage } from "./utilities/react-query/react-query-utils.js";
@@ -276,6 +278,7 @@ export {
276
278
  arrayUnique,
277
279
  buildTree,
278
280
  checkUserRight,
281
+ createSelectors,
279
282
  deleteNode,
280
283
  determineNewParentId,
281
284
  emptyScreenMapping,
@@ -342,15 +345,16 @@ export {
342
345
  default107 as useTrashedResource,
343
346
  useTreeSortable,
344
347
  useTreeView,
345
- default108 as useUpdateMutation,
346
- default109 as useUpload,
347
- default110 as useUploadFiles,
348
- default111 as useUser,
349
- default112 as useWorkspaceFile,
350
- default113 as useWorkspaceFolders,
351
- default114 as useWorkspaceFoldersTree,
352
- default115 as useWorkspaceSearch,
353
- default116 as useXitiTrackPageLoad,
354
- default117 as useZendeskGuide,
348
+ default108 as useUiOverride,
349
+ default109 as useUpdateMutation,
350
+ default110 as useUpload,
351
+ default111 as useUploadFiles,
352
+ default112 as useUser,
353
+ default113 as useWorkspaceFile,
354
+ default114 as useWorkspaceFolders,
355
+ default115 as useWorkspaceFoldersTree,
356
+ default116 as useWorkspaceSearch,
357
+ default117 as useXitiTrackPageLoad,
358
+ default118 as useZendeskGuide,
355
359
  wrapTreeNode
356
360
  };
@@ -1,9 +1,11 @@
1
1
  export interface HeaderProps {
2
2
  src: string | undefined;
3
3
  onNotificationsClick?: () => void;
4
+ /** Scope this header's CSS theme (`data-product`) to its own subtree, independently of the page's ambient theme. */
5
+ dataProduct?: string;
4
6
  }
5
7
  declare const Header: {
6
- ({ src, onNotificationsClick, }: HeaderProps): JSX.Element;
8
+ ({ src, onNotificationsClick, dataProduct, }: HeaderProps): JSX.Element;
7
9
  displayName: string;
8
10
  };
9
11
  export default Header;
@@ -25,7 +25,8 @@ import Avatar from "../../../../components/Avatar/Avatar.js";
25
25
  import { Popover, PopoverBody } from "../../../../components/Popover/Popover.js";
26
26
  const Header = ({
27
27
  src = "",
28
- onNotificationsClick
28
+ onNotificationsClick,
29
+ dataProduct
29
30
  }) => {
30
31
  const {
31
32
  t
@@ -47,7 +48,7 @@ const Header = ({
47
48
  } = useEdificeTheme(), hasMessages = messages > 0, [userRef, isUserHovered] = useHover(), popoverUserId = useId(), handleNotificationsClick = () => {
48
49
  onNotificationsClick == null || onNotificationsClick();
49
50
  };
50
- return /* @__PURE__ */ jsx("header", { className: classes, children: /* @__PURE__ */ jsxs(Navbar, { className: "px-24", children: [
51
+ return /* @__PURE__ */ jsx("header", { className: classes, "data-product": dataProduct, children: /* @__PURE__ */ jsxs(Navbar, { className: "px-24", children: [
51
52
  /* @__PURE__ */ jsx(LogoBeta, { src: `${src}/img/illustrations/logo.png` }),
52
53
  /* @__PURE__ */ jsxs("ul", { className: "navbar-nav", children: [
53
54
  /* @__PURE__ */ jsx(NavItem, { children: /* @__PURE__ */ jsx(NavLink, { link: "/timeline/timeline", translate: t("navbar.home"), "data-testid": "header-home-button", children: /* @__PURE__ */ jsx(SvgIconHomeBeta, {}) }) }),
@@ -1,12 +1,13 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
2
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
+ import { useState } from "react";
3
4
  import { EdificeClientContext } from "../EdificeClientProvider/EdificeClientProvider.context.js";
4
5
  import { EdificeThemeContext } from "../EdificeThemeProvider/EdificeThemeProvider.context.js";
5
6
  import { mockQueryResult, mockSession, mockConf } from "./MockedProvider.mocks.js";
6
- const queryClient = new QueryClient(), MockedProvider = ({
7
+ const MockedProvider = ({
7
8
  children
8
9
  }) => {
9
- const themeContextValue = {
10
+ const [queryClient] = useState(() => new QueryClient()), themeContextValue = {
10
11
  theme: "default",
11
12
  setTheme: vi.fn()
12
13
  }, clientContextValue = {
@@ -0,0 +1,37 @@
1
+ import { StoreApi, UseBoundStore } from 'zustand';
2
+ type WithSelectors<S> = S extends {
3
+ getState: () => infer T;
4
+ } ? S & {
5
+ use: {
6
+ [K in keyof T]: () => T[K];
7
+ };
8
+ } : never;
9
+ /**
10
+ * Augments a Zustand store with auto-generated, per-field selector hooks,
11
+ * so consumers can call `store.use.myValue()` instead of
12
+ * `store((s) => s.myValue)` and never forget a selector.
13
+ *
14
+ * Pattern from the Zustand docs:
15
+ * https://zustand.docs.pmnd.rs/guides/auto-generating-selectors
16
+ *
17
+ * @param _store - The bound store to augment.
18
+ * @returns The same store instance, mutated with a `use` object exposing one
19
+ * selector hook per state key.
20
+ *
21
+ * @remarks
22
+ * - The store is mutated in place; the returned reference is the input store.
23
+ * - Selectors are generated once, from the keys present at call time. Fields
24
+ * added to the state later won't get a `use.<key>` selector.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const useBearStore = createSelectors(
29
+ * create<BearState>(() => ({ bears: 0 })),
30
+ * );
31
+ *
32
+ * // In a component:
33
+ * const bears = useBearStore.use.bears();
34
+ * ```
35
+ */
36
+ export declare const createSelectors: <S extends UseBoundStore<StoreApi<object>>>(_store: S) => WithSelectors<S>;
37
+ export {};
@@ -0,0 +1 @@
1
+ export * from './create-selectors';
@@ -1,4 +1,5 @@
1
1
  export * from './check-user-rights';
2
+ export * from './create-selectors';
2
3
  export * from './emptyscreen-mapping';
3
4
  export * from './react-query';
4
5
  export * from './refs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.6.0-develop.20260720155436",
3
+ "version": "2.6.0-develop.20260721175941",
4
4
  "description": "Edifice React Library",
5
5
  "keywords": [
6
6
  "react",
@@ -140,9 +140,9 @@
140
140
  "swiper": "10.1.0",
141
141
  "ua-parser-js": "1.0.36",
142
142
  "zustand": "4.5.7",
143
- "@edifice.io/bootstrap": "2.6.0-develop.20260720155436",
144
- "@edifice.io/tiptap-extensions": "2.6.0-develop.20260720155436",
145
- "@edifice.io/utilities": "2.6.0-develop.20260720155436"
143
+ "@edifice.io/bootstrap": "2.6.0-develop.20260721175941",
144
+ "@edifice.io/tiptap-extensions": "2.6.0-develop.20260721175941",
145
+ "@edifice.io/utilities": "2.6.0-develop.20260721175941"
146
146
  },
147
147
  "devDependencies": {
148
148
  "@babel/plugin-transform-react-pure-annotations": "7.27.1",
@@ -173,8 +173,8 @@
173
173
  "vite": "5.4.14",
174
174
  "vite-plugin-dts": "4.5.4",
175
175
  "vite-tsconfig-paths": "5.1.4",
176
- "@edifice.io/client": "2.6.0-develop.20260720155436",
177
- "@edifice.io/config": "2.6.0-develop.20260720155436"
176
+ "@edifice.io/config": "2.6.0-develop.20260721175941",
177
+ "@edifice.io/client": "2.6.0-develop.20260721175941"
178
178
  },
179
179
  "peerDependencies": {
180
180
  "@react-spring/web": "9.7.5",
@@ -198,6 +198,7 @@
198
198
  "format:write": "prettier --write \"src/**/*.{ts,tsx}\"",
199
199
  "lint": "eslint",
200
200
  "test": "vitest",
201
- "test:watch": "vitest --watch"
201
+ "test:watch": "vitest --watch",
202
+ "test:coverage": "vitest run --coverage"
202
203
  }
203
204
  }
@@ -1,10 +0,0 @@
1
- import { StoreApi, UseBoundStore } from 'zustand';
2
- type WithSelectors<S> = S extends {
3
- getState: () => infer T;
4
- } ? S & {
5
- use: {
6
- [K in keyof T]: () => T[K];
7
- };
8
- } : never;
9
- export declare const createSelectors: <S extends UseBoundStore<StoreApi<object>>>(_store: S) => WithSelectors<S>;
10
- export {};