@hortiview/shared-components 2.24.3 → 2.26.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,16 @@
1
+ ## [2.26.0](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.25.0...v2.26.0) (2026-05-11)
2
+
3
+ ### Features
4
+
5
+ * add truncation handling for primary text in ContextMenu and update styles and tests ([9ed40a5](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/9ed40a5e66e49bd42cfd94fd1213a60ebcf8c4a9))
6
+ * enhance ContextMenu with responsive styles and add story for long text handling ([c712489](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/c7124897ced3931f32e65b65c16654053417ae9d))
7
+
8
+ ## [2.25.0](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.24.3...v2.25.0) (2026-05-07)
9
+
10
+ ### Features
11
+
12
+ * add standalone FloatingActionButton and adjust existing components ([6164fa7](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/6164fa763e7943ae58d33179ab791dee823900d2)), closes [#20679](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/issues/20679)
13
+
1
14
  ## [2.24.3](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.24.2...v2.24.3) (2026-05-07)
2
15
 
3
16
  ### Bug Fixes
package/README.md CHANGED
@@ -33,6 +33,7 @@ Additionally the library provides form components using [react-hook-form](https:
33
33
  1. [EmptyView](#emptyview)
34
34
  1. [ErrorBanner] (#errorbanner)
35
35
  1. [Filter](#filter)
36
+ 1. [FloatingActionButton](#floatingactionbutton)
36
37
  1. [FormattedNumberDisplay](#formattednumberdisplay)
37
38
  1. [FormComponents](#formcomponents)
38
39
  1. [FormCheckBox](#formcheckbox)
@@ -202,32 +203,6 @@ const actions = [
202
203
  <ContextMenu actions={actions} />;
203
204
  ```
204
205
 
205
- #### Render ContextMenu as a Floating Action Button (FAB)
206
-
207
- On mobile and tablet devices, you can display the context menu as a floating action button (FAB) by setting
208
- `isFloatingActionButtonOnMobile` to true. This removes the context menu from the DOM and positions it
209
- statically in the bottom right corner of the screen.
210
-
211
- You can control the offset from the screen edges using `floatingButtonScreenOffsetType`, which includes
212
- presets for full-screen implementations and screens with a BottomAppBar.
213
-
214
- To prevent the FAB from blocking any elements in the rendered view, provide a DOM element selector to
215
- `floatingButtonPaddingInsertTarget`. A spacer element will be attached to this target, increasing its
216
- height by the appropriate amount.
217
-
218
- ```jsx
219
- import { ContextMenu } from '@hortiview/shared-components';
220
-
221
- const actions = [...];
222
-
223
- <ContextMenu
224
- actions={actions}
225
- isFloatingActionButtonOnMobile={true}
226
- floatingButtonScreenOffsetType={'buttonAppBar'}
227
- floatingButtonPaddingInsertTarget={'#layout-container'}
228
- />;
229
- ```
230
-
231
206
  ### DeleteModal
232
207
 
233
208
  A modal to confirm a deletion.
@@ -374,6 +349,35 @@ const MyComponent = () => {
374
349
  export default MyComponent;
375
350
  ```
376
351
 
352
+ ### FloatingActionButton
353
+
354
+ A component to show a floating action button for mobile and tablet views, giving users quick access to one or
355
+ more contextual actions without taking permanent space in layout.
356
+
357
+ It automatically hides when no visible/allowed actions exist,
358
+ can trigger a single action directly or open a menu for multiple actions,
359
+ supports an offline fallback view.
360
+
361
+ You can control the offset from the screen edges using `floatingButtonScreenOffsetType`, which includes
362
+ presets for full-screen implementations and screens with a BottomAppBar.
363
+
364
+ To prevent the FAB from blocking any elements in the rendered view, provide a DOM element selector to
365
+ `floatingButtonPaddingInsertTarget`. A spacer element will be attached to this target, increasing its
366
+ height by the appropriate amount.
367
+
368
+ ```jsx
369
+ import { FloatingActionButton } from '@hortiview/shared-components';
370
+
371
+ const actions = [...];
372
+
373
+ <FloatingActionButton
374
+ actions={actions}
375
+ floatingButtonPaddingInsertTarget={'#fab-padding-target'}
376
+ isSingleActionTriggeredOnClick={false}
377
+ hasActionIconForSingleAction={false}
378
+ />;
379
+ ```
380
+
377
381
  ### FormattedNumberDisplay
378
382
 
379
383
  A component to display a formatted number based on the given language code, wrapped in a given typography component to style it as needed.
@@ -1124,12 +1128,6 @@ function BlockActions({ blockId, farmId }) {
1124
1128
  }
1125
1129
  ```
1126
1130
 
1127
- #### Render AllowedIconButton as Floating Action Button (FAB)
1128
-
1129
- On mobile and tablet devices, you can display the AllowedIconButton as a floating action button (FAB).
1130
- For more information, see the [Context Menu documentation](#render-contextmenu-as-a-floating-action-button-fab),
1131
- as both implementations are identical.
1132
-
1133
1131
  ### SafeForm
1134
1132
 
1135
1133
  A wrapper around a form that prevents accidental submission when pressing Enter in input fields.
@@ -0,0 +1 @@
1
+ ._menu_52omh_1{min-width:10rem;width:max-content;border-radius:.5rem!important}._mobile_52omh_7{max-width:12.5rem}._desktop_52omh_11{max-width:21.25rem}._icon_52omh_15{color:var(--lmnt-theme-on-secondary-inactive)}._listItem_52omh_19 [class*=mdc-list-item__primary-text],._listItem_52omh_19 [class*=mdc-list-item__secondary-text]{display:-webkit-box!important;-webkit-line-clamp:2!important;line-clamp:2!important;-webkit-box-orient:vertical!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:normal!important}._listItem_52omh_19 [class*=mdc-list-item__start]{color:var(--lmnt-theme-on-secondary-inactive);align-self:center!important;margin:0 1rem!important}._listItem_52omh_19 [class*=mdc-list-item__end]{color:var(--lmnt-theme-on-secondary-inactive)}._offlineViewMargin_52omh_51{margin:.5rem}._primaryTextTruncated_52omh_55 [class*=mdc-list-item__secondary-text]{padding-top:1rem!important}
@@ -1,7 +1,5 @@
1
1
  import { IconButtonProps } from '@element-public/react-icon-button';
2
- import { FloatingActionButtonProps } from '../ContextMenu/ContextMenu';
3
2
  import { IsAllowedProps } from '../PermissionChecks/PermissionService';
4
- import { default as React } from 'react';
5
3
 
6
4
  export type AllowedIconButtonProps = Omit<IconButtonProps & React.HTMLProps<HTMLButtonElement>, 'variant' | 'iconType' | 'iconSize' | 'size'> & {
7
5
  /**
@@ -36,21 +34,10 @@ export type AllowedIconButtonProps = Omit<IconButtonProps & React.HTMLProps<HTML
36
34
  * Default: 'medium'
37
35
  */
38
36
  size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
39
- } & FloatingActionButtonProps;
37
+ };
40
38
  /**
41
- * Renders an icon button only when the required permissions are granted.
42
- *
43
- * Supports optional mobile floating action button behavior through
44
- * `FloatingActionButtonProps` -> {@link FloatingActionButtonProps}
45
- *
46
- * @param props Component props.
47
- * @param props.data-testid Test id suffix used to generate the rendered button test id.
48
- * @param props.entityIds Entity id or ids used for permission evaluation.
49
- * @param props.formId Optional form id used to associate the button with a form.
50
- * @param props.variant Visual variant of the icon button.
51
- * @param props.iconType Icon style variant.
52
- * @param props.permissions Permissions required to render the button.
53
- * @param props.size Size of the icon button.
54
- * @returns The rendered icon button, or `null` when access is not allowed.
39
+ * A permission-gated icon button component that only renders when the user has the required permissions.
40
+ * @param {AllowedIconButtonProps} props - Component properties
41
+ * @returns {JSX.Element | null} The icon button component or null if permissions are not met
55
42
  */
56
- export declare const AllowedIconButton: (props: AllowedIconButtonProps) => import("react/jsx-runtime").JSX.Element;
43
+ export declare const AllowedIconButton: ({ "data-testid": testId, variant, iconType, size, ...props }: AllowedIconButtonProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,58 +1,23 @@
1
- import { jsx as e, jsxs as A, Fragment as S } from "react/jsx-runtime";
2
- import { I as x } from "../../index.es-CkB4776y.js";
3
- import { c as i } from "../../index-Df2FYN-K.js";
4
- import { createPortal as d } from "react-dom";
5
- import { useBreakpoints as P } from "../../hooks/useBreakpoints.js";
6
- import { Allowed as T } from "../Allowed/Allowed.js";
7
- import { s as t } from "../../contextMenu.module-RWPDK7Ds.js";
8
- import { useMemo as h } from "react";
9
- const O = (c) => {
10
- const {
11
- "data-testid": l,
12
- variant: m = "filled-primary",
13
- iconType: f = "filled",
14
- size: p = "medium",
15
- permissions: u,
16
- entityIds: b,
17
- formId: B,
18
- isFloatingActionButtonOnMobile: g = !1,
19
- floatingButtonPaddingInsertTarget: o,
20
- floatingButtonScreenOffsetType: n = "buttonAppBar",
21
- ...I
22
- } = c, { isDesktop: y } = P(), r = g && !y, a = /* @__PURE__ */ e(
23
- x,
24
- {
25
- className: i(r && t.fabIcon),
26
- "data-testid": `allowed-icon-button-${l}`,
27
- form: B,
28
- iconSize: r ? "xlarge" : p,
29
- iconType: f,
30
- variant: m,
31
- ...I
32
- }
33
- ), s = h(() => o ? document.querySelector(o) : null, [o]);
34
- return /* @__PURE__ */ e(T, { neededPermissions: u, entityIds: b, children: r ? /* @__PURE__ */ A(S, { children: [
35
- d(
36
- /* @__PURE__ */ e(
37
- "div",
38
- {
39
- className: i(
40
- t.fabContainer,
41
- n === "buttonAppBar" && t.buttonAppBar,
42
- n === "fullScreen" && t.fullScreen
43
- ),
44
- "data-testid": "fab-container",
45
- children: a
46
- }
47
- ),
48
- document.body
49
- ),
50
- s && d(
51
- /* @__PURE__ */ e("div", { className: t.fabSpacer, "data-testid": "fab-spacer" }),
52
- s
53
- )
54
- ] }) : a });
55
- };
1
+ import { jsx as i } from "react/jsx-runtime";
2
+ import { I as m } from "../../index.es-CkB4776y.js";
3
+ import { Allowed as l } from "../Allowed/Allowed.js";
4
+ const f = ({
5
+ "data-testid": o,
6
+ variant: e = "filled-primary",
7
+ iconType: d = "filled",
8
+ size: n = "medium",
9
+ ...t
10
+ }) => /* @__PURE__ */ i(l, { neededPermissions: t.permissions, entityIds: t.entityIds, children: /* @__PURE__ */ i(
11
+ m,
12
+ {
13
+ "data-testid": `allowed-icon-button-${o}`,
14
+ form: t.formId,
15
+ iconSize: n,
16
+ iconType: d,
17
+ variant: e,
18
+ ...t
19
+ }
20
+ ) });
56
21
  export {
57
- O as AllowedIconButton
22
+ f as AllowedIconButton
58
23
  };
@@ -1,6 +1,7 @@
1
1
  import { BaseListElement } from '../../types/ListElement';
2
2
  import { LinkProps } from '../../types/internal/ReactRouterTypes';
3
3
  import { OfflineViewProps } from '../OfflineView/OfflineView';
4
+ import { FloatingActionButton } from '../FloatingActionButton/FloatingActionButton.tsx';
4
5
 
5
6
  type BaseViewProps = {
6
7
  /**
@@ -32,6 +33,13 @@ type BaseViewProps = {
32
33
  * action to be displayed in the headings ActionButton
33
34
  */
34
35
  action?: JSX.Element;
36
+ /**
37
+ * An additional action element that is rendered outside conditional wrappers, so it is always visible
38
+ * Only rendered on mobile devices.
39
+ *
40
+ * @Used to render FloatingActionButtons when the header is hidden (which hides the action)
41
+ */
42
+ floatingActionButton?: React.ReactElement<typeof FloatingActionButton>;
35
43
  /**
36
44
  * hint to be displayed below the heading
37
45
  */
@@ -96,5 +104,5 @@ type BaseViewProps = {
96
104
  /**
97
105
  * `BaseView` is a layout component that displays a main (a list) and a detail section.
98
106
  */
99
- export declare const BaseView: ({ heading, action, hint, elements, emptyText, hasSearch, isSorted, className, withAvatar, listMaxHeight, titleLevel, detailTitleLevel, pathname, basicHeadingIcon, isOnline, offlineViewProps, noRoundedListItemEdges, routerLinkElement, searchPlaceholder, isGrouped, isHeaderVisibleOnMobile, }: BaseViewProps) => import("react/jsx-runtime").JSX.Element;
107
+ export declare const BaseView: ({ heading, action, floatingActionButton, hint, elements, emptyText, hasSearch, isSorted, className, withAvatar, listMaxHeight, titleLevel, detailTitleLevel, pathname, basicHeadingIcon, isOnline, offlineViewProps, noRoundedListItemEdges, routerLinkElement, searchPlaceholder, isGrouped, isHeaderVisibleOnMobile, }: BaseViewProps) => import("react/jsx-runtime").JSX.Element;
100
108
  export {};
@@ -1,133 +1,138 @@
1
- import { jsx as e, Fragment as d, jsxs as c } from "react/jsx-runtime";
1
+ import { jsx as e, Fragment as l, jsxs as n } from "react/jsx-runtime";
2
2
  import { D as $ } from "../../index.es-C27R5Xae.js";
3
- import { G as s } from "../../index.es-Z0aF-7Cn.js";
4
- import { P as F } from "../../index.es-DgncYOqO.js";
3
+ import { G as a } from "../../index.es-Z0aF-7Cn.js";
4
+ import { P as M } from "../../index.es-DgncYOqO.js";
5
5
  import { c as v } from "../../index-Df2FYN-K.js";
6
- import { useMemo as l } from "react";
6
+ import { useMemo as d } from "react";
7
7
  import { BasicHeading as D } from "../BasicHeading/BasicHeading.js";
8
- import { EmptyView as M } from "../EmptyView/EmptyView.js";
9
- import { ListArea as P } from "../ListArea/ListArea.js";
10
- import { useBreakpoints as T } from "../../hooks/useBreakpoints.js";
11
- import { OfflineView as q } from "../OfflineView/OfflineView.js";
12
- import { useScrollableInfo as z } from "./BaseView.service.js";
13
- import '../../assets/BaseView.css';const J = "_fullHeight_1yui7_1", K = "_fullWidth_1yui7_5", O = "_heading_1yui7_9", Q = "_list_1yui7_18", U = "_desktopList_1yui7_27", X = "_noRoundedCorners_1yui7_32", Y = "_detail_1yui7_36", Z = "_desktopDetail_1yui7_44", i = {
14
- fullHeight: J,
15
- fullWidth: K,
16
- heading: O,
17
- list: Q,
18
- desktopList: U,
19
- noRoundedCorners: X,
20
- detail: Y,
21
- desktopDetail: Z
22
- }, mt = ({
23
- heading: u,
24
- action: m = /* @__PURE__ */ e(d, {}),
25
- hint: k = /* @__PURE__ */ e(d, {}),
26
- elements: f,
27
- emptyText: h,
28
- hasSearch: y = !0,
29
- isSorted: L = !0,
30
- className: b,
8
+ import { EmptyView as P } from "../EmptyView/EmptyView.js";
9
+ import { ListArea as T } from "../ListArea/ListArea.js";
10
+ import { useBreakpoints as q } from "../../hooks/useBreakpoints.js";
11
+ import { OfflineView as z } from "../OfflineView/OfflineView.js";
12
+ import { useScrollableInfo as J } from "./BaseView.service.js";
13
+ import '../../assets/BaseView.css';const K = "_fullHeight_1yui7_1", O = "_fullWidth_1yui7_5", Q = "_heading_1yui7_9", U = "_list_1yui7_18", X = "_desktopList_1yui7_27", Y = "_noRoundedCorners_1yui7_32", Z = "_detail_1yui7_36", tt = "_desktopDetail_1yui7_44", i = {
14
+ fullHeight: K,
15
+ fullWidth: O,
16
+ heading: Q,
17
+ list: U,
18
+ desktopList: X,
19
+ noRoundedCorners: Y,
20
+ detail: Z,
21
+ desktopDetail: tt
22
+ }, ft = ({
23
+ heading: m,
24
+ action: f = /* @__PURE__ */ e(l, {}),
25
+ floatingActionButton: k,
26
+ hint: y = /* @__PURE__ */ e(l, {}),
27
+ elements: h,
28
+ emptyText: p,
29
+ hasSearch: L = !0,
30
+ isSorted: b = !0,
31
+ className: B,
31
32
  withAvatar: H = !1,
32
33
  listMaxHeight: N = "calc(100vh - 220px)",
33
34
  titleLevel: W = 5,
34
- detailTitleLevel: B,
35
+ detailTitleLevel: x,
35
36
  pathname: r,
36
- basicHeadingIcon: x,
37
- isOnline: p = !0,
38
- offlineViewProps: _,
39
- noRoundedListItemEdges: g = !0,
37
+ basicHeadingIcon: A,
38
+ isOnline: _ = !0,
39
+ offlineViewProps: g,
40
+ noRoundedListItemEdges: w = !0,
40
41
  routerLinkElement: R,
41
- searchPlaceholder: A,
42
- isGrouped: C = !1,
43
- isHeaderVisibleOnMobile: I = !0
42
+ searchPlaceholder: C,
43
+ isGrouped: I = !1,
44
+ isHeaderVisibleOnMobile: S = !0
44
45
  }) => {
45
- const { isDesktopNavbar: o, isDesktop: w } = T(), n = l(() => f.filter((a) => a.isAllowed !== !1), [f]), t = l(() => n.find((a) => a.route === r), [r, n]), S = l(() => p ? t?.component ? t.component : o ? /* @__PURE__ */ e(F, { className: i.fullWidth, children: /* @__PURE__ */ e(M, { title: h }) }) : /* @__PURE__ */ e(d, {}) : /* @__PURE__ */ e(q, { ..._, fullWidth: !0 }), [t?.component, h, o, p, _]), { showList: E, showDetail: j } = l(() => o ? { showList: !0, showDetail: !0 } : { showList: !t, showDetail: !!t }, [t, o]), { ref: G, hasScrolled: V } = z([
46
+ const { isDesktopNavbar: o, isDesktop: s } = q(), c = d(() => h.filter((u) => u.isAllowed !== !1), [h]), t = d(() => c.find((u) => u.route === r), [r, c]), E = d(() => _ ? t?.component ? t.component : o ? /* @__PURE__ */ e(M, { className: i.fullWidth, children: /* @__PURE__ */ e(P, { title: p }) }) : /* @__PURE__ */ e(l, {}) : /* @__PURE__ */ e(z, { ...g, fullWidth: !0 }), [t?.component, p, o, _, g]), { showList: j, showDetail: F } = d(() => o ? { showList: !0, showDetail: !0 } : { showList: !t, showDetail: !!t }, [t, o]), { ref: G, hasScrolled: V } = J([
46
47
  r,
47
48
  o
48
49
  ]);
49
- return /* @__PURE__ */ c(
50
- s,
50
+ return /* @__PURE__ */ n(
51
+ a,
51
52
  {
52
53
  "data-testid": "base-view-container",
53
- className: `${w ? i.fullHeight : ""} ${b ?? ""}`,
54
+ className: `${s ? i.fullHeight : ""} ${B ?? ""}`,
54
55
  fullWidth: !0,
55
56
  children: [
56
- E && /* @__PURE__ */ c(
57
- s,
58
- {
59
- "data-testid": "show-list-container",
60
- gap: "none",
61
- direction: "vertical",
62
- className: v(
63
- i.list,
64
- o && i.desktopList,
65
- g && i.noRoundedCorners
66
- ),
67
- children: [
68
- u && /* @__PURE__ */ e(
69
- D,
70
- {
71
- icon: x,
72
- "data-testid": "heading",
73
- heading: u,
74
- level: W,
75
- marginBottom: 0,
76
- inList: !0,
77
- children: m
78
- }
57
+ j && /* @__PURE__ */ n(l, { children: [
58
+ /* @__PURE__ */ n(
59
+ a,
60
+ {
61
+ "data-testid": "show-list-container",
62
+ gap: "none",
63
+ direction: "vertical",
64
+ className: v(
65
+ i.list,
66
+ o && i.desktopList,
67
+ w && i.noRoundedCorners
79
68
  ),
80
- k,
81
- /* @__PURE__ */ e(
82
- P,
83
- {
84
- hasLastItemNoRoundedEdges: g,
85
- elements: n,
86
- hasSearch: y,
87
- maxHeight: N,
88
- isSorted: L,
89
- pathname: r,
90
- routerLinkElement: R,
91
- searchPlaceholder: A,
92
- isGrouped: C
93
- }
94
- )
95
- ]
96
- }
97
- ),
98
- j && /* @__PURE__ */ c(
99
- s,
69
+ children: [
70
+ m && /* @__PURE__ */ e(
71
+ D,
72
+ {
73
+ icon: A,
74
+ "data-testid": "heading",
75
+ heading: m,
76
+ level: W,
77
+ marginBottom: 0,
78
+ inList: !0,
79
+ children: f
80
+ }
81
+ ),
82
+ y,
83
+ /* @__PURE__ */ e(
84
+ T,
85
+ {
86
+ hasLastItemNoRoundedEdges: w,
87
+ elements: c,
88
+ hasSearch: L,
89
+ maxHeight: N,
90
+ isSorted: b,
91
+ pathname: r,
92
+ routerLinkElement: R,
93
+ searchPlaceholder: C,
94
+ isGrouped: I
95
+ }
96
+ )
97
+ ]
98
+ }
99
+ ),
100
+ !s && k
101
+ ] }),
102
+ F && /* @__PURE__ */ n(
103
+ a,
100
104
  {
101
105
  "data-testid": "show-details-container",
102
106
  gap: "none",
103
107
  direction: "vertical",
104
108
  className: v(i.detail, o && i.desktopDetail),
105
109
  children: [
106
- (I || w) && /* @__PURE__ */ e(
110
+ (S || s) && /* @__PURE__ */ e(
107
111
  D,
108
112
  {
109
113
  className: i.heading,
110
114
  heading: t?.detailTitle ?? t?.title ?? "",
111
- level: B,
115
+ level: x,
112
116
  icon: t?.hideIconInDetail === !0 ? void 0 : t?.detailIcon ?? t?.icon,
113
117
  marginBottom: 0,
114
118
  invisibleButton: t?.detailAction === void 0,
115
119
  withAvatar: H,
116
120
  subHeading: t?.detailSubTitle,
117
- children: t?.detailAction ?? m
121
+ children: t?.detailAction ?? f
118
122
  }
119
123
  ),
120
124
  V && /* @__PURE__ */ e($, {}),
121
125
  /* @__PURE__ */ e(
122
- s,
126
+ a,
123
127
  {
124
128
  "data-testid": "base-view-show-details-scroll-component-group",
125
129
  fullWidth: !0,
126
130
  direction: "vertical",
127
131
  ref: G,
128
- children: S
132
+ children: E
129
133
  }
130
- )
134
+ ),
135
+ !s && t?.detailFloatingActionButton
131
136
  ]
132
137
  }
133
138
  )
@@ -136,5 +141,5 @@ import '../../assets/BaseView.css';const J = "_fullHeight_1yui7_1", K = "_fullWi
136
141
  );
137
142
  };
138
143
  export {
139
- mt as BaseView
144
+ ft as BaseView
140
145
  };
@@ -1,5 +1,6 @@
1
1
  import { ListItemProps } from '@element-public/react-list';
2
2
  import { OfflineViewProps } from '../OfflineView/OfflineView';
3
+ import { IsAllowedProps } from '../PermissionChecks/PermissionService.tsx';
3
4
 
4
5
  type ContextMenuProps = {
5
6
  /**
@@ -16,9 +17,6 @@ type ContextMenuProps = {
16
17
  * Default is 'vertical'
17
18
  */
18
19
  iconOrientation?: 'vertical' | 'horizontal';
19
- /**
20
- * data-testid for testing
21
- */
22
20
  'data-testid'?: string;
23
21
  /**
24
22
  * Whether the user is online; shows OfflineView when false.
@@ -28,40 +26,6 @@ type ContextMenuProps = {
28
26
  * Props forwarded to <OfflineView /> when offline.
29
27
  */
30
28
  offlineViewProps?: Partial<OfflineViewProps>;
31
- /**
32
- * If only one action is provided/allowed, trigger that action without opening the context menu
33
- * @remarks Basically turns the component into an icon button
34
- * @default false
35
- */
36
- isSingleActionTriggeredOnClick?: boolean;
37
- /**
38
- * If only one action is provided/allowed, show the icon of that action, instead of the default menu one
39
- *
40
- * @default true
41
- */
42
- hasActionIconForSingleAction?: boolean;
43
- } & FloatingActionButtonProps;
44
- export type FloatingActionButtonProps = {
45
- /**
46
- * Determines if the button should be rendered as a floating action button (FAB) on mobile devices.
47
- * @default false
48
- */
49
- isFloatingActionButtonOnMobile?: boolean;
50
- /**
51
- * Specify a target element (query selector) to insert an extra padding element below.
52
- * The padding element is used to make sure the FAB doesn't block any elements at the end of a view.
53
- * @example '#layout-container'
54
- * @remarks This padding attribute is not related to floatingButtonScreenOffsetType. The inserted padding is always the same size, slightly taller than the button height
55
- */
56
- floatingButtonPaddingInsertTarget?: string;
57
- /**
58
- * Determines the distance/offset of the floating action button from the bottom and right edge of the screen
59
- * - 'buttonAppBar' adds offset for when the element ButtonAppBar is used, so the button stays slightly above the bar
60
- * - 'fullScreen' adds offset for a full-screen view, with the button sitting slightly above the screen edges
61
- * @default 'buttonAppBar'
62
- * @remarks This padding attribute is not related to floatingButtonPaddingInsertTarget. The paddingType just controls the offset of the button to the screen edges.
63
- */
64
- floatingButtonScreenOffsetType?: 'buttonAppBar' | 'fullScreen';
65
29
  };
66
30
  export type ActionProps = ListItemProps & {
67
31
  closeOnClick?: boolean;
@@ -70,35 +34,38 @@ export type ActionProps = ListItemProps & {
70
34
  dividerAfter?: boolean;
71
35
  /**
72
36
  * whether the user has the permission to trigger the action, if false the action will not be shown
37
+ * @deprecated Use `permissionConfiguration` to simplify or `isHidden` instead
73
38
  */
74
39
  isAllowed?: boolean;
40
+ /**
41
+ * Permission configuration used to determine whether this action is shown.
42
+ * If the current user does not meet them, the action is hidden.
43
+ *
44
+ * Leave blank to always show the action.
45
+ */
46
+ permissionConfiguration?: IsAllowedProps;
47
+ /**
48
+ * Whether the action should be hidden. If true, the action will not be shown.
49
+ * @remarks Use to control visibility based on specific conditions (aside from permissions)
50
+ * @default false
51
+ */
52
+ isHidden?: boolean;
75
53
  };
76
54
  /**
77
- * Renders action menu with optional permission-aware filtering, offline fallback,
78
- * and mobile FAB presentation.
79
55
  *
80
- * On mobile, the button can be rendered as a floating action button by enabling
81
- * `isFloatingActionButtonOnMobile`. If exactly one allowed action is available,
82
- * trigger can optionally execute the action directly and reuse the action icon.
83
- *
84
- * @param triggerOpen External open-state control. Leave blank for uncontrolled mode.
85
- * @param actions Menu actions to render.
56
+ * @param {boolean} triggerOpen indicates if the menu should be open
57
+ * @param {ListItemProps[]} actions list of actions to display in the context menu as ListItems
58
+ * @param testId id for testing, automatically prefixed
59
+ * @recommended `primaryText`, `onClick`, `leadingBlock`
60
+ * @requires `ListItemProps` from `@element-public/react-components`
86
61
  * @example const actions = [
87
62
  * { primaryText: 'Open', onClick: () => openSomeModal(), leadingBlock: 'add' },
88
63
  * { primaryText: 'Delete', onClick: () => DeleteSomeThing(), leadingBlock: 'delete_outline'},
89
64
  * { primaryText: 'Edit', onClick: () => EditSomeThing(), leadingBlock: 'edit'},
90
65
  * ];
91
- *
92
- * @param iconOrientation Orientation of default menu icon.
93
- * @param isOnline Whether menu should render actions or offline placeholder.
94
- * @param offlineViewProps Props forwarded to `OfflineView`.
95
- *
96
- * @param isSingleActionTriggeredOnClick Whether single allowed action should execute immediately.
97
- * @param hasActionIconForSingleAction Whether single allowed action icon should replace default button icon.
98
- * @param isFloatingActionButtonOnMobile Whether to render the button as a FAB on mobile.
99
- * @param floatingButtonPaddingInsertTarget Selector for optional spacer insertion target.
100
- * @param floatingButtonScreenOffsetType FAB offset preset for bottom spacing.
101
- * @returns Context menu trigger and menu content, or `null` when no allowed actions exist.
66
+ * @param {boolean} isOnline Whether the user is online; shows OfflineView when false.
67
+ * @param {OfflineViewProps} offlineViewProps Props forwarded to OfflineView when offline.
68
+ * @returns a context menu with the given actions as ListItems
102
69
  */
103
- export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, hasActionIconForSingleAction, isSingleActionTriggeredOnClick, isFloatingActionButtonOnMobile, floatingButtonPaddingInsertTarget, floatingButtonScreenOffsetType, }: ContextMenuProps) => import("react/jsx-runtime").JSX.Element | null;
70
+ export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, }: ContextMenuProps) => import("react/jsx-runtime").JSX.Element | null;
104
71
  export {};