@hortiview/shared-components 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [2.4.0](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.3.0...v2.4.0) (2025-08-21)
2
+
3
+ ### Features
4
+
5
+ * add button and tests ([fe8ba0d](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/fe8ba0d7e6439e8c8abf163c4b16d8c9aef1d36a))
6
+ * create OfflineView component ([b6ff2d7](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/b6ff2d78125216875f3d6345f06100aeb578f1b6))
7
+ * import offlineView and create tests and stories ([b577ae6](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/b577ae69559b1e215f0888f6da921b7cedf1e1ce))
8
+
9
+ ### Code Refactoring
10
+
11
+ * add new props and clarify prop descriptions and defaults ([e81d321](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/e81d3219597a7aba649658dc055729eb6d6d5596))
12
+ * change props and add tests and storybook ([e742da8](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/e742da85acec7163125b4817728a07d011093046))
13
+
14
+ ### Styles
15
+
16
+ * adjust .bgGrey and .bgWhite text color and add new .subtitle class ([5cbfb14](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/5cbfb14cbd0c560b5e00efba09b4683ef8a7bc9d))
17
+
1
18
  ## [2.3.0](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.2.0...v2.3.0) (2025-08-20)
2
19
 
3
20
  ### Features
package/README.md CHANGED
@@ -51,6 +51,7 @@ Additionally the library provides form components using [react-hook-form](https:
51
51
  1. [LoadingSpinner](#loadingspinner)
52
52
  1. [Modal](#modal)
53
53
  1. [ModulePadding](#modulepadding)
54
+ 1. [OfflineView](#offlineview)
54
55
  1. [OnboardingBanner](#onboardingbanner)
55
56
  1. [OverflowTooltip](#overflowtooltip)
56
57
  1. [ScrollBar](#scrollbar)
@@ -888,6 +889,16 @@ import { ModulePadding } from '@hortiview/shared-components';
888
889
  </ModulePadding>;
889
890
  ```
890
891
 
892
+ ### OfflineView
893
+
894
+ Shows an offline state with icon, title, and optional subtitle. Use `size` 'small' inline and 'large' for full pages.
895
+
896
+ ```jsx
897
+ import { OfflineView } from '@hortiview/shared-components';
898
+
899
+ <OfflineView title="Title" subtitle="Subtitle" />
900
+ ```
901
+
891
902
  ### OnboardingBanner
892
903
 
893
904
  A responsive onboarding banner that adapts its layout for desktop and mobile.
@@ -0,0 +1,48 @@
1
+ import { jsxs as o, jsx as e } from "react/jsx-runtime";
2
+ import { G as s } from "./index.es-DntoATwO.js";
3
+ import { Iconify as _ } from "./components/Iconify/Iconify.js";
4
+ import { b as m, d as y, T as h } from "./index.es-D54RuMc_.js";
5
+ import { B as v } from "./index.es-CiqbARoC.js";
6
+ import './assets/OfflineView.css';const w = "_gap_18we6_1", G = "_container_18we6_5", T = "_bgWhite_18we6_11", x = "_bgGrey_18we6_16", W = "_subtitle_18we6_21", i = {
7
+ gap: w,
8
+ container: G,
9
+ bgWhite: T,
10
+ bgGrey: x,
11
+ subtitle: W
12
+ }, z = ({
13
+ title: t = "You’re currently offline",
14
+ subtitle: a = "This feature is unavailable until you reconnect",
15
+ icon: l = "cloud_off",
16
+ size: c = "large",
17
+ variant: d = "basic",
18
+ "data-testid": f = "offline-view-container",
19
+ buttonLabel: n,
20
+ fullWidth: g = !1,
21
+ className: b,
22
+ onClick: p
23
+ }) => {
24
+ const r = c === "large", u = d === "filled";
25
+ return /* @__PURE__ */ o(
26
+ s,
27
+ {
28
+ className: `${b} ${i.container} ${u ? i.bgGrey : i.bgWhite}`,
29
+ gap: "standard",
30
+ direction: "vertical",
31
+ "data-testid": f,
32
+ secondaryAlign: "center",
33
+ fullWidth: g,
34
+ children: [
35
+ /* @__PURE__ */ o(s, { direction: "vertical", secondaryAlign: "center", className: i.gap, children: [
36
+ /* @__PURE__ */ e(_, { icon: l, iconSize: r ? "xlarge" : "medium" }),
37
+ r ? /* @__PURE__ */ e(m, { level: 6, children: t }) : /* @__PURE__ */ e(y, { level: 1, bold: !0, children: t })
38
+ ] }),
39
+ a && /* @__PURE__ */ e(h, { className: i.subtitle, level: 2, children: a }),
40
+ n && /* @__PURE__ */ e(v, { "data-testid": "offline-view-action-button", label: n, onClick: p })
41
+ ]
42
+ }
43
+ );
44
+ };
45
+ export {
46
+ z as O,
47
+ i as s
48
+ };
@@ -1 +1 @@
1
- ._menu_ol91v_1{width:15.875rem}._icon_ol91v_5{color:var(--lmnt-theme-on-secondary-inactive)}._listItem_ol91v_9 [class*=mdc-list-item__start]{color:var(--lmnt-theme-on-secondary-inactive);align-self:center!important;margin:0 1rem!important}._listItem_ol91v_9 [class*=mdc-list-item__end]{color:var(--lmnt-theme-on-secondary-inactive)}
1
+ ._menu_1xwk3_1{width:15.875rem}._icon_1xwk3_5{color:var(--lmnt-theme-on-secondary-inactive)}._listItem_1xwk3_9 [class*=mdc-list-item__start]{color:var(--lmnt-theme-on-secondary-inactive);align-self:center!important;margin:0 1rem!important}._listItem_1xwk3_9 [class*=mdc-list-item__end]{color:var(--lmnt-theme-on-secondary-inactive)}._offlineViewMargin_1xwk3_19{margin:.5rem}
@@ -0,0 +1 @@
1
+ ._gap_18we6_1{gap:.125rem!important}._container_18we6_5{border-radius:.5rem;padding:2.5rem 2rem;width:auto}._bgWhite_18we6_11{background:var(--lmnt-theme-surface);color:var(--lmnt-theme-on-surface-active)}._bgGrey_18we6_16{background:var(--lmnt-theme-surface-variant);color:var(--lmnt-theme-on-surface-active)}._subtitle_18we6_21{color:var(--on-colors-on-surface-inactive-medium, #000000BA);font-weight:500}
@@ -1,5 +1,6 @@
1
1
  import { BaseListElement } from '../../types/ListElement';
2
2
  import { LinkProps } from '../../types/internal/ReactRouterTypes';
3
+ import { OfflineViewProps } from '../OfflineView/OfflineView';
3
4
 
4
5
  type BaseViewProps = {
5
6
  /**
@@ -50,6 +51,14 @@ type BaseViewProps = {
50
51
  * searchPlaceholder is the placeholder of the search input, @default ''
51
52
  */
52
53
  searchPlaceholder?: string;
54
+ /**
55
+ * Whether the user is online; shows OfflineView when false.
56
+ */
57
+ isOnline?: boolean;
58
+ /**
59
+ * Props forwarded to <OfflineView /> when offline.
60
+ */
61
+ offlineViewProps?: Partial<OfflineViewProps>;
53
62
  /**
54
63
  * routerLinkElement is the element to be used for the elements link, use react-router Link component for the best experience.
55
64
  * If the element has `noNavigation=false` and the `routerLinkElement` is undefined an `<a>` tag is used.
@@ -62,5 +71,5 @@ type BaseViewProps = {
62
71
  /**
63
72
  * `BaseView` is a layout component that displays a main (a list) and a detail section.
64
73
  */
65
- export declare const BaseView: ({ heading, action, hint, elements, emptyText, hasSearch, isSorted, className, withAvatar, listMaxHeight, pathname, routerLinkElement, searchPlaceholder, }: BaseViewProps) => import("react/jsx-runtime").JSX.Element;
74
+ export declare const BaseView: ({ heading, action, hint, elements, emptyText, hasSearch, isSorted, className, withAvatar, listMaxHeight, pathname, isOnline, offlineViewProps, routerLinkElement, searchPlaceholder, }: BaseViewProps) => import("react/jsx-runtime").JSX.Element;
66
75
  export {};
@@ -1,70 +1,73 @@
1
1
  import { jsx as i, Fragment as d, jsxs as s } from "react/jsx-runtime";
2
2
  import { G as r } from "../../index.es-DntoATwO.js";
3
3
  import { useMemo as a } from "react";
4
- import { BasicHeading as u } from "../BasicHeading/BasicHeading.js";
5
- import { EmptyView as W } from "../EmptyView/EmptyView.js";
6
- import { ListArea as B } from "../ListArea/ListArea.js";
7
- import { u as G } from "../../useBreakpoints-MzTZ0tCT.js";
8
- import { VerticalDivider as N } from "../VerticalDivider/VerticalDivider.js";
9
- import '../../assets/BaseView.css';const A = "_parentGroup_w7vsz_1", V = "_divider_w7vsz_5", j = "_maxWidth_w7vsz_10", E = "_desktopList_w7vsz_14", H = "_mobileList_w7vsz_19", I = "_desktopDetail_w7vsz_23", $ = "_mobileDetail_w7vsz_28", o = {
10
- parentGroup: A,
11
- divider: V,
12
- maxWidth: j,
13
- desktopList: E,
14
- mobileList: H,
15
- desktopDetail: I,
16
- mobileDetail: $
17
- }, P = ({
4
+ import { BasicHeading as h } from "../BasicHeading/BasicHeading.js";
5
+ import { EmptyView as G } from "../EmptyView/EmptyView.js";
6
+ import { ListArea as N } from "../ListArea/ListArea.js";
7
+ import { u as A } from "../../useBreakpoints-MzTZ0tCT.js";
8
+ import { VerticalDivider as V } from "../VerticalDivider/VerticalDivider.js";
9
+ import { O as j } from "../../OfflineView-BW19N4Cu.js";
10
+ import '../../assets/BaseView.css';const E = "_parentGroup_w7vsz_1", H = "_divider_w7vsz_5", I = "_maxWidth_w7vsz_10", $ = "_desktopList_w7vsz_14", y = "_mobileList_w7vsz_19", F = "_desktopDetail_w7vsz_23", M = "_mobileDetail_w7vsz_28", o = {
11
+ parentGroup: E,
12
+ divider: H,
13
+ maxWidth: I,
14
+ desktopList: $,
15
+ mobileList: y,
16
+ desktopDetail: F,
17
+ mobileDetail: M
18
+ }, U = ({
18
19
  heading: c,
19
20
  action: m = /* @__PURE__ */ i(d, {}),
20
- hint: v = /* @__PURE__ */ i(d, {}),
21
+ hint: _ = /* @__PURE__ */ i(d, {}),
21
22
  elements: n,
22
23
  emptyText: p,
23
- hasSearch: _ = !0,
24
- isSorted: h = !0,
25
- className: f,
26
- withAvatar: b = !1,
27
- listMaxHeight: w = "calc(100vh - 200px)",
24
+ hasSearch: f = !0,
25
+ isSorted: b = !0,
26
+ className: w,
27
+ withAvatar: D = !1,
28
+ listMaxHeight: g = "calc(100vh - 200px)",
28
29
  pathname: l,
29
- routerLinkElement: D,
30
- searchPlaceholder: g
30
+ isOnline: u = !0,
31
+ offlineViewProps: v,
32
+ routerLinkElement: k,
33
+ searchPlaceholder: L
31
34
  }) => {
32
- const { isDesktopNavbar: e } = G(), t = a(() => n.find((z) => z.route === l), [l, n]), k = a(() => t?.component ?? (e ? /* @__PURE__ */ i(W, { subtitle: p }) : /* @__PURE__ */ i(d, {})), [t, e, p]), L = a(() => e ? !0 : !t, [t, e]), x = a(() => e ? !0 : t, [t, e]);
35
+ const { isDesktopNavbar: e } = A(), t = a(() => n.find((B) => B.route === l), [l, n]), x = a(() => u ? t?.component ?? (e ? /* @__PURE__ */ i(G, { subtitle: p }) : /* @__PURE__ */ i(d, {})) : /* @__PURE__ */ i(j, { ...v, fullWidth: !0 }), [t?.component, p, e, u, v]), W = a(() => e ? !0 : !t, [t, e]), z = a(() => e ? !0 : t, [t, e]);
33
36
  return /* @__PURE__ */ s(
34
37
  r,
35
38
  {
36
39
  "data-testid": "base-view-container",
37
- className: `${o.parentGroup} ${f ?? ""}`,
40
+ className: `${o.parentGroup} ${w ?? ""}`,
38
41
  gap: "none",
39
42
  fullWidth: !0,
40
43
  children: [
41
- L && /* @__PURE__ */ i(r, { gap: "none", className: e ? o.desktopList : o.mobileList, children: /* @__PURE__ */ s(r, { direction: "vertical", fullWidth: !0, gap: e ? "standard" : "dense", children: [
42
- c && /* @__PURE__ */ i(u, { "data-testid": "heading", heading: c, level: 4, marginBottom: 0, children: m }),
43
- v,
44
+ W && /* @__PURE__ */ i(r, { gap: "none", className: e ? o.desktopList : o.mobileList, children: /* @__PURE__ */ s(r, { direction: "vertical", fullWidth: !0, gap: e ? "standard" : "dense", children: [
45
+ c && /* @__PURE__ */ i(h, { "data-testid": "heading", heading: c, level: 4, marginBottom: 0, children: m }),
46
+ _,
44
47
  /* @__PURE__ */ i(
45
- B,
48
+ N,
46
49
  {
47
50
  elements: n,
48
- hasSearch: _,
49
- maxHeight: w,
50
- isSorted: h,
51
+ hasSearch: f,
52
+ maxHeight: g,
53
+ isSorted: b,
51
54
  pathname: l,
52
- routerLinkElement: D,
53
- searchPlaceholder: g
55
+ routerLinkElement: k,
56
+ searchPlaceholder: L
54
57
  }
55
58
  )
56
59
  ] }) }),
57
- x && /* @__PURE__ */ s(
60
+ z && /* @__PURE__ */ s(
58
61
  r,
59
62
  {
60
63
  "data-testid": "details",
61
64
  gap: "none",
62
65
  className: e ? o.desktopDetail : o.mobileDetail,
63
66
  children: [
64
- e && /* @__PURE__ */ i(N, { className: o.divider, height: "100%" }),
67
+ e && /* @__PURE__ */ i(V, { className: o.divider, height: "100%" }),
65
68
  /* @__PURE__ */ s(r, { direction: "vertical", fullWidth: !0, children: [
66
69
  /* @__PURE__ */ i(
67
- u,
70
+ h,
68
71
  {
69
72
  className: o.maxWidth,
70
73
  heading: t?.detailTitle ?? t?.title ?? "",
@@ -72,11 +75,11 @@ import '../../assets/BaseView.css';const A = "_parentGroup_w7vsz_1", V = "_divid
72
75
  icon: t?.hideIconInDetail === !0 ? void 0 : t?.icon,
73
76
  marginBottom: 0,
74
77
  invisibleButton: t?.detailAction === void 0,
75
- withAvatar: b,
78
+ withAvatar: D,
76
79
  children: t?.detailAction ?? m
77
80
  }
78
81
  ),
79
- k
82
+ x
80
83
  ] })
81
84
  ]
82
85
  }
@@ -86,5 +89,5 @@ import '../../assets/BaseView.css';const A = "_parentGroup_w7vsz_1", V = "_divid
86
89
  );
87
90
  };
88
91
  export {
89
- P as BaseView
92
+ U as BaseView
90
93
  };
@@ -1,10 +1,10 @@
1
- import { jsx as a, Fragment as s } from "react/jsx-runtime";
2
- import { a as r, s as e, f as p } from "../../react.esm-CX1WJ2Pp.js";
1
+ import { jsx as o, Fragment as s } from "react/jsx-runtime";
2
+ import { a as n, s as e, f as p } from "../../react.esm-CX1WJ2Pp.js";
3
3
  import { a as l } from "../../useBreakpoints-MzTZ0tCT.js";
4
- import { BaseView as i } from "./BaseView.js";
5
- import { d as u, b as m, a as c, t as n, g as t } from "../../vi.CjhMlMwf-CKxPQtd6.js";
4
+ import { BaseView as r } from "./BaseView.js";
5
+ import { d as u, b as f, a as c, t as i, g as t } from "../../vi.CjhMlMwf-CKxPQtd6.js";
6
6
  u("BaseView Test", () => {
7
- m(() => {
7
+ f(() => {
8
8
  c.spyOn(l, "useBreakpoints").mockReturnValue({
9
9
  isMobile: !1,
10
10
  isTablet: !1,
@@ -12,20 +12,20 @@ u("BaseView Test", () => {
12
12
  isDesktopNavbar: !0
13
13
  });
14
14
  });
15
- const o = [
15
+ const a = [
16
16
  {
17
17
  id: "1",
18
18
  title: "user.personal_information",
19
19
  icon: "account_circle",
20
20
  route: "/personal-profile/personal-information",
21
- component: /* @__PURE__ */ a(s, { children: "Personal information selected" })
21
+ component: /* @__PURE__ */ o(s, { children: "Personal information selected" })
22
22
  },
23
23
  {
24
24
  id: "2",
25
25
  title: "user.data_privacy",
26
26
  icon: "privacy_tip",
27
27
  route: "/personal-profile/data-privacy",
28
- component: /* @__PURE__ */ a(s, { children: "Data Privacy selected" }),
28
+ component: /* @__PURE__ */ o(s, { children: "Data Privacy selected" }),
29
29
  detailTitle: "Data Privacy 2000",
30
30
  hideIconInDetail: !0
31
31
  },
@@ -34,16 +34,16 @@ u("BaseView Test", () => {
34
34
  title: "user.security",
35
35
  icon: "security",
36
36
  route: "/personal-profile/security",
37
- component: /* @__PURE__ */ a(s, { children: "Security selected" })
37
+ component: /* @__PURE__ */ o(s, { children: "Security selected" })
38
38
  }
39
39
  ];
40
- n("render BaseView with empty view and navigation list", () => {
41
- r(
42
- /* @__PURE__ */ a(
43
- i,
40
+ i("render BaseView with empty view and navigation list", () => {
41
+ n(
42
+ /* @__PURE__ */ o(
43
+ r,
44
44
  {
45
45
  pathname: "/personal-profile",
46
- elements: o,
46
+ elements: a,
47
47
  heading: "user.personal-profile",
48
48
  hasSearch: !1,
49
49
  emptyText: "user.noselection",
@@ -52,13 +52,13 @@ u("BaseView Test", () => {
52
52
  }
53
53
  )
54
54
  ), t(e.getByText("user.noselection")).toBeInTheDocument(), t(e.getByText("user.personal-profile")).toBeInTheDocument(), t(e.getByText("user.personal_information")).toBeInTheDocument(), t(e.getByText("user.data_privacy")).toBeInTheDocument(), t(e.getByText("user.security")).toBeInTheDocument();
55
- }), n("render BaseView with data and navigation list", () => {
56
- r(
57
- /* @__PURE__ */ a(
58
- i,
55
+ }), i("render BaseView with data and navigation list", () => {
56
+ n(
57
+ /* @__PURE__ */ o(
58
+ r,
59
59
  {
60
60
  pathname: "/personal-profile/personal-information",
61
- elements: o,
61
+ elements: a,
62
62
  heading: "user.personal-profile",
63
63
  hasSearch: !1,
64
64
  emptyText: "user.noselection",
@@ -67,13 +67,13 @@ u("BaseView Test", () => {
67
67
  }
68
68
  )
69
69
  ), t(e.getByText("Personal information selected")).toBeInTheDocument(), t(e.getAllByText("account_circle")).toHaveLength(2), t(e.getAllByText("user.personal_information")).toHaveLength(2);
70
- }), n("render BaseView with custom detail title and no detail icon", () => {
71
- r(
72
- /* @__PURE__ */ a(
73
- i,
70
+ }), i("render BaseView with custom detail title and no detail icon", () => {
71
+ n(
72
+ /* @__PURE__ */ o(
73
+ r,
74
74
  {
75
75
  pathname: "/personal-profile/data-privacy",
76
- elements: o,
76
+ elements: a,
77
77
  heading: "user.personal-profile",
78
78
  hasSearch: !1,
79
79
  emptyText: "user.noselection",
@@ -82,18 +82,18 @@ u("BaseView Test", () => {
82
82
  }
83
83
  )
84
84
  ), t(e.getByText("Data Privacy selected")).toBeInTheDocument(), t(e.getByText("Data Privacy 2000")).toBeInTheDocument(), t(e.getAllByText("privacy_tip")).toHaveLength(1), t(e.getAllByText("user.data_privacy")).toHaveLength(1);
85
- }), n("hide empty view when screen is small", () => {
85
+ }), i("hide empty view when screen is small", () => {
86
86
  c.spyOn(l, "useBreakpoints").mockReturnValue({
87
87
  isMobile: !0,
88
88
  isTablet: !1,
89
89
  isDesktop: !1,
90
90
  isDesktopNavbar: !1
91
- }), r(
92
- /* @__PURE__ */ a(
93
- i,
91
+ }), n(
92
+ /* @__PURE__ */ o(
93
+ r,
94
94
  {
95
95
  pathname: "/personal-profile/data-privacy",
96
- elements: o,
96
+ elements: a,
97
97
  heading: "user.personal-profile",
98
98
  hasSearch: !1,
99
99
  emptyText: "user.noselection",
@@ -102,13 +102,13 @@ u("BaseView Test", () => {
102
102
  }
103
103
  )
104
104
  ), t(e.queryByText("user.noselection")).not.toBeInTheDocument();
105
- }), n("render BaseView with selected detail section", () => {
106
- r(
107
- /* @__PURE__ */ a(
108
- i,
105
+ }), i("render BaseView with selected detail section", () => {
106
+ n(
107
+ /* @__PURE__ */ o(
108
+ r,
109
109
  {
110
110
  pathname: "/personal-profile/data-privacy",
111
- elements: o,
111
+ elements: a,
112
112
  heading: "user.personal-profile",
113
113
  hasSearch: !1,
114
114
  emptyText: "user.noselection",
@@ -117,5 +117,22 @@ u("BaseView Test", () => {
117
117
  }
118
118
  )
119
119
  ), p.click(e.getAllByRole("option")[1]), t(e.getByText("Data Privacy selected")).toBeInTheDocument();
120
+ }), i("renders only offline view when offline", () => {
121
+ n(
122
+ /* @__PURE__ */ o(
123
+ r,
124
+ {
125
+ pathname: "/personal-profile/personal-information",
126
+ elements: a,
127
+ heading: "user.personal-profile",
128
+ hasSearch: !1,
129
+ emptyText: "user.noselection",
130
+ isSorted: !1,
131
+ isOnline: !1,
132
+ offlineViewProps: { "data-testid": "offline-test" },
133
+ routerLinkElement: void 0
134
+ }
135
+ )
136
+ ), t(e.queryByText("Personal information selected")).not.toBeInTheDocument(), t(e.getByTestId("offline-test")).toBeInTheDocument();
120
137
  });
121
138
  });
@@ -1,4 +1,5 @@
1
1
  import { ListItemProps } from '@element-public/react-list';
2
+ import { OfflineViewProps } from '../OfflineView/OfflineView';
2
3
 
3
4
  type ContextMenuProps = {
4
5
  /**
@@ -19,6 +20,14 @@ type ContextMenuProps = {
19
20
  * data-testid for testing
20
21
  */
21
22
  'data-testid'?: string;
23
+ /**
24
+ * Whether the user is online; shows OfflineView when false.
25
+ */
26
+ isOnline?: boolean;
27
+ /**
28
+ * Props forwarded to <OfflineView /> when offline.
29
+ */
30
+ offlineViewProps?: Partial<OfflineViewProps>;
22
31
  };
23
32
  export type ActionProps = ListItemProps & {
24
33
  closeOnClick?: boolean;
@@ -35,7 +44,9 @@ export type ActionProps = ListItemProps & {
35
44
  * { primaryText: 'Delete', onClick: () => DeleteSomeThing(), leadingBlock: 'delete_outline'},
36
45
  * { primaryText: 'Edit', onClick: () => EditSomeThing(), leadingBlock: 'edit'},
37
46
  * ];
47
+ * @param {boolean} isOnline Whether the user is online; shows OfflineView when false.
48
+ * @param {OfflineViewProps} offlineViewProps Props forwarded to OfflineView when offline.
38
49
  * @returns a context menu with the given actions as ListItems
39
50
  */
40
- export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, }: ContextMenuProps) => import("react/jsx-runtime").JSX.Element;
51
+ export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, }: ContextMenuProps) => import("react/jsx-runtime").JSX.Element;
41
52
  export {};
@@ -1,48 +1,52 @@
1
- import { jsx as o } from "react/jsx-runtime";
2
- import { I as d } from "../../index.es-0lQcz8m1.js";
3
- import { M as f, L as _, a as I } from "../../index.es-fnFnw2P1.js";
4
- import { useState as p, useCallback as a, useEffect as v } from "react";
5
- import { u as C } from "../../uniqueId-NU3-C36A.js";
6
- import '../../assets/ContextMenu.css';const k = "_menu_ol91v_1", y = "_icon_ol91v_5", M = "_listItem_ol91v_9", i = {
7
- menu: k,
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { I as _ } from "../../index.es-0lQcz8m1.js";
3
+ import { M as k, L as p, a as w } from "../../index.es-fnFnw2P1.js";
4
+ import { useState as I, useCallback as a, useEffect as M } from "react";
5
+ import { u as x } from "../../uniqueId-NU3-C36A.js";
6
+ import { O as C } from "../../OfflineView-BW19N4Cu.js";
7
+ import '../../assets/ContextMenu.css';const v = "_menu_1xwk3_1", y = "_icon_1xwk3_5", V = "_listItem_1xwk3_9", g = "_offlineViewMargin_1xwk3_19", s = {
8
+ menu: v,
8
9
  icon: y,
9
- listItem: M
10
- }, T = ({
11
- triggerOpen: n = null,
12
- actions: c,
13
- iconOrientation: m = "vertical",
14
- "data-testid": r
10
+ listItem: V,
11
+ offlineViewMargin: g
12
+ }, b = ({
13
+ triggerOpen: o = null,
14
+ actions: r,
15
+ iconOrientation: c = "vertical",
16
+ "data-testid": m,
17
+ isOnline: f = !0,
18
+ offlineViewProps: u
15
19
  }) => {
16
- const [t, s] = p(!1), u = a(() => {
17
- s(!t);
18
- }, [t]), l = a(() => {
19
- s(!1);
20
+ const [i, n] = I(!1), d = a(() => {
21
+ n(!i);
22
+ }, [i]), l = a(() => {
23
+ n(!1);
20
24
  }, []);
21
- return v(() => {
22
- s(n !== null ? n : !1);
23
- }, [n]), /* @__PURE__ */ o(
24
- f,
25
+ return M(() => {
26
+ n(o !== null ? o : !1);
27
+ }, [o]), /* @__PURE__ */ t(
28
+ k,
25
29
  {
26
- className: i.menu,
27
- "data-testid": r ?? "selection-menu",
28
- open: t,
30
+ className: s.menu,
31
+ "data-testid": m ?? "selection-menu",
32
+ open: i,
29
33
  surfaceOnly: !0,
30
34
  hoistToBody: !0,
31
35
  onClose: l,
32
- trigger: /* @__PURE__ */ o(
33
- d,
36
+ trigger: /* @__PURE__ */ t(
37
+ _,
34
38
  {
35
- className: i.icon,
36
- variant: t ? "filled-primary" : void 0,
39
+ className: s.icon,
40
+ variant: i ? "filled-primary" : void 0,
37
41
  "data-testid": "open-button",
38
- icon: m === "vertical" ? "more_vert" : "more_horiz",
39
- onClick: u
42
+ icon: c === "vertical" ? "more_vert" : "more_horiz",
43
+ onClick: d
40
44
  }
41
45
  ),
42
- children: /* @__PURE__ */ o(_, { "data-testid": "selection-list", children: c.map((e) => /* @__PURE__ */ o(
43
- I,
46
+ children: f ? /* @__PURE__ */ t(p, { "data-testid": "selection-list", children: r.map((e) => /* @__PURE__ */ t(
47
+ w,
44
48
  {
45
- className: i.listItem,
49
+ className: s.listItem,
46
50
  ...e,
47
51
  leadingBlockType: "icon",
48
52
  "data-testid": e["data-testid"],
@@ -50,12 +54,12 @@ import '../../assets/ContextMenu.css';const k = "_menu_ol91v_1", y = "_icon_ol91
50
54
  e?.onClick?.(), e.closeOnClick !== !1 && l();
51
55
  }
52
56
  },
53
- C(`LI_${e.primaryText?.toString()}_`)
54
- )) })
57
+ x(`LI_${e.primaryText?.toString()}_`)
58
+ )) }) : /* @__PURE__ */ t(C, { size: "small", variant: "filled", className: s.offlineViewMargin, ...u })
55
59
  },
56
60
  "selectionmenu"
57
61
  );
58
62
  };
59
63
  export {
60
- T as ContextMenu
64
+ b as ContextMenu
61
65
  };
@@ -1,22 +1,45 @@
1
- import { jsx as r } from "react/jsx-runtime";
2
- import { a as B, s as t, f as o, w as s } from "../../react.esm-CX1WJ2Pp.js";
3
- import { ContextMenu as p } from "./ContextMenu.js";
4
- import { a as d, d as k, t as T, g as e } from "../../vi.CjhMlMwf-CKxPQtd6.js";
5
- const C = d.fn(), a = d.fn(), i = d.fn(), g = [
6
- { primaryText: "Open", onClick: C, leadingBlock: "add", "data-testid": "open-testid" },
7
- { primaryText: "Delete", onClick: i, leadingBlock: "delete_outline", "data-testid": "delete-testid" },
8
- { primaryText: "Edit", onClick: a, leadingBlock: "edit", "data-testid": "edit-testid" }
1
+ import { jsx as a } from "react/jsx-runtime";
2
+ import { a as i, s as t, f as o, w as c } from "../../react.esm-CX1WJ2Pp.js";
3
+ import { ContextMenu as d } from "./ContextMenu.js";
4
+ import { a as B, d as I, t as l, g as e } from "../../vi.CjhMlMwf-CKxPQtd6.js";
5
+ const g = B.fn(), m = B.fn(), r = B.fn(), u = [
6
+ { primaryText: "Open", onClick: g, leadingBlock: "add", "data-testid": "open-testid" },
7
+ {
8
+ primaryText: "Delete",
9
+ onClick: r,
10
+ leadingBlock: "delete_outline",
11
+ "data-testid": "delete-testid"
12
+ },
13
+ { primaryText: "Edit", onClick: m, leadingBlock: "edit", "data-testid": "edit-testid" }
9
14
  ];
10
- k("ContextMenu Test", () => {
11
- T("render contextMenu and close it", () => {
12
- B(/* @__PURE__ */ r(p, { actions: g }));
13
- const c = t.getByTestId("open-button"), n = t.getByTestId("selection-menu");
14
- e(n).toBeInTheDocument(), e(n).not.toHaveClass("mdc-menu-surface--open"), o.click(c), s(() => e(n).toHaveClass("mdc-menu-surface--open")), o.click(c), s(() => e(n).not.toHaveClass("mdc-menu-surface--open"));
15
- }), T("render ContextMenu and open it", async () => {
16
- B(/* @__PURE__ */ r(p, { actions: g, triggerOpen: !0 }));
17
- const c = t.getByTestId("open-button"), n = t.getByTestId("selection-menu");
18
- e(n).toBeInTheDocument(), e(n).not.toHaveClass("mdc-menu-surface--open"), o.click(c), await s(() => e(n).toHaveClass("mdc-menu-surface--animating-open")), e(t.getByText("Open")).toBeInTheDocument(), e(t.getByText("Delete")).toBeInTheDocument(), e(t.getByText("Edit")).toBeInTheDocument();
19
- const l = t.getByTestId("open-testid"), m = t.getByTestId("delete-testid"), u = t.getByTestId("edit-testid");
20
- e(l).toBeInTheDocument(), e(m).toBeInTheDocument(), e(u).toBeInTheDocument(), o.click(l), e(C).toHaveBeenCalled(), e(i).not.toHaveBeenCalled(), e(a).not.toHaveBeenCalled(), o.click(m), e(i).toHaveBeenCalled(), o.click(u), e(a).toHaveBeenCalled();
15
+ I("ContextMenu Test", () => {
16
+ l("render contextMenu and close it", () => {
17
+ i(/* @__PURE__ */ a(d, { actions: u }));
18
+ const s = t.getByTestId("open-button"), n = t.getByTestId("selection-menu");
19
+ e(n).toBeInTheDocument(), e(n).not.toHaveClass("mdc-menu-surface--open"), o.click(s), c(() => e(n).toHaveClass("mdc-menu-surface--open")), o.click(s), c(() => e(n).not.toHaveClass("mdc-menu-surface--open"));
20
+ }), l("render ContextMenu and open it", async () => {
21
+ i(/* @__PURE__ */ a(d, { actions: u, triggerOpen: !0 }));
22
+ const s = t.getByTestId("open-button"), n = t.getByTestId("selection-menu");
23
+ e(n).toBeInTheDocument(), e(n).not.toHaveClass("mdc-menu-surface--open"), o.click(s), await c(() => e(n).toHaveClass("mdc-menu-surface--animating-open")), e(t.getByText("Open")).toBeInTheDocument(), e(t.getByText("Delete")).toBeInTheDocument(), e(t.getByText("Edit")).toBeInTheDocument();
24
+ const p = t.getByTestId("open-testid"), T = t.getByTestId("delete-testid"), f = t.getByTestId("edit-testid");
25
+ e(p).toBeInTheDocument(), e(T).toBeInTheDocument(), e(f).toBeInTheDocument(), o.click(p), e(g).toHaveBeenCalled(), e(r).not.toHaveBeenCalled(), e(m).not.toHaveBeenCalled(), o.click(T), e(r).toHaveBeenCalled(), o.click(f), e(m).toHaveBeenCalled();
26
+ }), l("render ContextMenu with offlineView", async () => {
27
+ i(
28
+ /* @__PURE__ */ a(
29
+ d,
30
+ {
31
+ actions: u,
32
+ triggerOpen: !0,
33
+ isOnline: !1,
34
+ offlineViewProps: {
35
+ "data-testid": "offline-test"
36
+ }
37
+ }
38
+ )
39
+ );
40
+ const s = t.getByTestId("open-button");
41
+ o.click(s);
42
+ const n = t.getByTestId("selection-menu");
43
+ await c(() => e(n).toHaveClass("mdc-menu-surface--animating-open")), e(t.getByTestId("offline-test")).toBeInTheDocument();
21
44
  });
22
45
  });