@hortiview/shared-components 2.23.5 → 2.24.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 +6 -0
- package/README.md +39 -7
- package/dist/assets/Modal.css +1 -1
- package/dist/assets/contextMenu.css +1 -0
- package/dist/components/AllowedIconButton/AllowedIconButton.d.ts +18 -5
- package/dist/components/AllowedIconButton/AllowedIconButton.js +56 -21
- package/dist/components/BaseView/BaseView.js +11 -11
- package/dist/components/ContextMenu/ContextMenu.d.ts +54 -8
- package/dist/components/ContextMenu/ContextMenu.js +100 -52
- package/dist/components/DeleteModal/DeleteModal.js +3 -2
- package/dist/components/EmptyView/EmptyView.js +3 -2
- package/dist/components/Filter/Filter.js +3 -2
- package/dist/components/Modal/Modal.js +1 -1
- package/dist/components/ModulePadding/ModulePadding.js +3 -2
- package/dist/contextMenu.module-RWPDK7Ds.js +17 -0
- package/dist/services/UtilService.js +7 -6
- package/package.json +1 -1
- package/dist/assets/ContextMenu.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [2.24.0](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.23.5...v2.24.0) (2026-04-30)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* extend contextMenu and allowedIconButton for FAB display on mobile and tablet devices ([f194914](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/commit/f1949142376af9f4ce12324b8bf7c074ef892ff3))
|
|
6
|
+
|
|
1
7
|
## [2.23.5](https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared/compare/v2.23.4...v2.23.5) (2026-04-27)
|
|
2
8
|
|
|
3
9
|
### Code Refactoring
|
package/README.md
CHANGED
|
@@ -35,13 +35,13 @@ Additionally the library provides form components using [react-hook-form](https:
|
|
|
35
35
|
1. [Filter](#filter)
|
|
36
36
|
1. [FormattedNumberDisplay](#formattednumberdisplay)
|
|
37
37
|
1. [FormComponents](#formcomponents)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
1. [FormCheckBox](#formcheckbox)
|
|
39
|
+
1. [FormDatePicker](#formdatepicker)
|
|
40
|
+
1. [FormNumber](#formnumber)
|
|
41
|
+
1. [FormRadio](#formradio)
|
|
42
|
+
1. [FormSelect](#formselect)
|
|
43
|
+
1. [FormSlider](#formslider)
|
|
44
|
+
1. [FormText](#formtext)
|
|
45
45
|
1. [GenericTable](#generictable)
|
|
46
46
|
1. [HashTabView](#hashtabview)
|
|
47
47
|
1. [HeaderFilter](#headerfilter)
|
|
@@ -202,6 +202,32 @@ const actions = [
|
|
|
202
202
|
<ContextMenu actions={actions} />;
|
|
203
203
|
```
|
|
204
204
|
|
|
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
|
+
|
|
205
231
|
### DeleteModal
|
|
206
232
|
|
|
207
233
|
A modal to confirm a deletion.
|
|
@@ -1098,6 +1124,12 @@ function BlockActions({ blockId, farmId }) {
|
|
|
1098
1124
|
}
|
|
1099
1125
|
```
|
|
1100
1126
|
|
|
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
|
+
|
|
1101
1133
|
### SafeForm
|
|
1102
1134
|
|
|
1103
1135
|
A wrapper around a form that prevents accidental submission when pressing Enter in input fields.
|
package/dist/assets/Modal.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.
|
|
1
|
+
._modal_1l955_1{z-index:75}._modal_1l955_1 div[class*=lmnt-modal__surface]{max-height:100svh!important;max-width:100svw!important}._modal_1l955_1 div:not([class*=mdc-dialog--fullscreen]) div[class*=lmnt-modal__surface]{border-radius:1rem!important}._modal_1l955_1 footer{margin-bottom:0!important}._gap_1l955_18{gap:4px!important;padding-left:.5rem!important}._title_1l955_23{header{display:flex;justify-content:start;padding-inline:0!important;>div{width:100%;margin-left:0!important}}}._titleWithoutCloseIcon_1l955_36{margin-left:1rem!important}._closeButton_1l955_40{color:var(--lmnt-theme-on-surface-inactive)}._closeButton_1l955_40:before{display:none!important}._closeButton_1l955_40:hover{background-color:var(--lmnt-theme-surface-variant)!important}._errorBanner_1l955_52{width:100%}._headerActions_1l955_56{margin-left:.5rem}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._menu_1bdpq_1{width:15.875rem;border-radius:.5rem!important}._icon_1bdpq_6{color:var(--lmnt-theme-on-secondary-inactive)}._listItem_1bdpq_10 [class*=mdc-list-item__start]{color:var(--lmnt-theme-on-secondary-inactive);align-self:center!important;margin:0 1rem!important}._listItem_1bdpq_10 [class*=mdc-list-item__end]{color:var(--lmnt-theme-on-secondary-inactive)}._offlineViewMargin_1bdpq_20{margin:.5rem}._fabContainer_1bdpq_24{position:fixed;z-index:51}._fabContainer_1bdpq_24._buttonAppBar_1bdpq_29{bottom:5.4rem;right:1rem}._fabContainer_1bdpq_24._fullScreen_1bdpq_34{bottom:1.5rem;right:1rem}._fabIcon_1bdpq_39{box-shadow:0 4px 10px #0000004d}._fabMenu_1bdpq_43{margin-bottom:.5rem}._scrim_1bdpq_47{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#0000004d;z-index:50;opacity:0;pointer-events:none;transition:opacity .15s ease-in}._scrimVisible_1bdpq_60{opacity:1;pointer-events:auto}._fabSpacer_1bdpq_65{height:5.2rem}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { IconButtonProps } from '@element-public/react-icon-button';
|
|
2
|
+
import { FloatingActionButtonProps } from '../ContextMenu/ContextMenu';
|
|
2
3
|
import { IsAllowedProps } from '../PermissionChecks/PermissionService';
|
|
4
|
+
import { default as React } from 'react';
|
|
3
5
|
|
|
4
6
|
export type AllowedIconButtonProps = Omit<IconButtonProps & React.HTMLProps<HTMLButtonElement>, 'variant' | 'iconType' | 'iconSize' | 'size'> & {
|
|
5
7
|
/**
|
|
@@ -34,10 +36,21 @@ export type AllowedIconButtonProps = Omit<IconButtonProps & React.HTMLProps<HTML
|
|
|
34
36
|
* Default: 'medium'
|
|
35
37
|
*/
|
|
36
38
|
size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
|
|
37
|
-
};
|
|
39
|
+
} & FloatingActionButtonProps;
|
|
38
40
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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.
|
|
42
55
|
*/
|
|
43
|
-
export declare const AllowedIconButton: (
|
|
56
|
+
export declare const AllowedIconButton: (props: AllowedIconButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,23 +1,58 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { I as
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
+
};
|
|
21
56
|
export {
|
|
22
|
-
|
|
57
|
+
O as AllowedIconButton
|
|
23
58
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as e, Fragment as d, jsxs as c } from "react/jsx-runtime";
|
|
2
2
|
import { D as V } from "../../index.es-C27R5Xae.js";
|
|
3
|
-
import { G as
|
|
3
|
+
import { G as s } from "../../index.es-Z0aF-7Cn.js";
|
|
4
4
|
import { P as $ } from "../../index.es-DgncYOqO.js";
|
|
5
5
|
import { c as w } from "../../index-Df2FYN-K.js";
|
|
6
|
-
import { useMemo as
|
|
6
|
+
import { useMemo as l } from "react";
|
|
7
7
|
import { BasicHeading as v } from "../BasicHeading/BasicHeading.js";
|
|
8
8
|
import { EmptyView as F } from "../EmptyView/EmptyView.js";
|
|
9
9
|
import { ListArea as M } from "../ListArea/ListArea.js";
|
|
@@ -32,7 +32,7 @@ import '../../assets/BaseView.css';const z = "_fullHeight_1yui7_1", J = "_fullWi
|
|
|
32
32
|
listMaxHeight: H = "calc(100vh - 220px)",
|
|
33
33
|
titleLevel: N = 5,
|
|
34
34
|
detailTitleLevel: W,
|
|
35
|
-
pathname:
|
|
35
|
+
pathname: r,
|
|
36
36
|
basicHeadingIcon: B,
|
|
37
37
|
isOnline: p = !0,
|
|
38
38
|
offlineViewProps: _,
|
|
@@ -41,19 +41,19 @@ import '../../assets/BaseView.css';const z = "_fullHeight_1yui7_1", J = "_fullWi
|
|
|
41
41
|
searchPlaceholder: R,
|
|
42
42
|
isGrouped: A = !1
|
|
43
43
|
}) => {
|
|
44
|
-
const { isDesktopNavbar: o, isDesktop: C } = P(),
|
|
45
|
-
|
|
44
|
+
const { isDesktopNavbar: o, isDesktop: C } = P(), n = l(() => f.filter((a) => a.isAllowed !== !1), [f]), t = l(() => n.find((a) => a.route === r), [r, n]), I = l(() => p ? t?.component ? t.component : o ? /* @__PURE__ */ e($, { className: i.fullWidth, children: /* @__PURE__ */ e(F, { title: h }) }) : /* @__PURE__ */ e(d, {}) : /* @__PURE__ */ e(T, { ..._, fullWidth: !0 }), [t?.component, h, o, p, _]), { showList: S, showDetail: E } = l(() => o ? { showList: !0, showDetail: !0 } : { showList: !t, showDetail: !!t }, [t, o]), { ref: j, hasScrolled: G } = q([
|
|
45
|
+
r,
|
|
46
46
|
o
|
|
47
47
|
]);
|
|
48
48
|
return /* @__PURE__ */ c(
|
|
49
|
-
|
|
49
|
+
s,
|
|
50
50
|
{
|
|
51
51
|
"data-testid": "base-view-container",
|
|
52
52
|
className: `${C ? i.fullHeight : ""} ${L ?? ""}`,
|
|
53
53
|
fullWidth: !0,
|
|
54
54
|
children: [
|
|
55
55
|
S && /* @__PURE__ */ c(
|
|
56
|
-
|
|
56
|
+
s,
|
|
57
57
|
{
|
|
58
58
|
"data-testid": "show-list-container",
|
|
59
59
|
gap: "none",
|
|
@@ -81,11 +81,11 @@ import '../../assets/BaseView.css';const z = "_fullHeight_1yui7_1", J = "_fullWi
|
|
|
81
81
|
M,
|
|
82
82
|
{
|
|
83
83
|
hasLastItemNoRoundedEdges: g,
|
|
84
|
-
elements:
|
|
84
|
+
elements: n,
|
|
85
85
|
hasSearch: k,
|
|
86
86
|
maxHeight: H,
|
|
87
87
|
isSorted: y,
|
|
88
|
-
pathname:
|
|
88
|
+
pathname: r,
|
|
89
89
|
routerLinkElement: x,
|
|
90
90
|
searchPlaceholder: R,
|
|
91
91
|
isGrouped: A
|
|
@@ -95,7 +95,7 @@ import '../../assets/BaseView.css';const z = "_fullHeight_1yui7_1", J = "_fullWi
|
|
|
95
95
|
}
|
|
96
96
|
),
|
|
97
97
|
E && /* @__PURE__ */ c(
|
|
98
|
-
|
|
98
|
+
s,
|
|
99
99
|
{
|
|
100
100
|
"data-testid": "show-details-container",
|
|
101
101
|
gap: "none",
|
|
@@ -118,7 +118,7 @@ import '../../assets/BaseView.css';const z = "_fullHeight_1yui7_1", J = "_fullWi
|
|
|
118
118
|
),
|
|
119
119
|
G && /* @__PURE__ */ e(V, {}),
|
|
120
120
|
/* @__PURE__ */ e(
|
|
121
|
-
|
|
121
|
+
s,
|
|
122
122
|
{
|
|
123
123
|
"data-testid": "base-view-show-details-scroll-component-group",
|
|
124
124
|
fullWidth: !0,
|
|
@@ -28,6 +28,40 @@ type ContextMenuProps = {
|
|
|
28
28
|
* Props forwarded to <OfflineView /> when offline.
|
|
29
29
|
*/
|
|
30
30
|
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';
|
|
31
65
|
};
|
|
32
66
|
export type ActionProps = ListItemProps & {
|
|
33
67
|
closeOnClick?: boolean;
|
|
@@ -40,19 +74,31 @@ export type ActionProps = ListItemProps & {
|
|
|
40
74
|
isAllowed?: boolean;
|
|
41
75
|
};
|
|
42
76
|
/**
|
|
77
|
+
* Renders action menu with optional permission-aware filtering, offline fallback,
|
|
78
|
+
* and mobile FAB presentation.
|
|
43
79
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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.
|
|
48
86
|
* @example const actions = [
|
|
49
87
|
* { primaryText: 'Open', onClick: () => openSomeModal(), leadingBlock: 'add' },
|
|
50
88
|
* { primaryText: 'Delete', onClick: () => DeleteSomeThing(), leadingBlock: 'delete_outline'},
|
|
51
89
|
* { primaryText: 'Edit', onClick: () => EditSomeThing(), leadingBlock: 'edit'},
|
|
52
90
|
* ];
|
|
53
|
-
*
|
|
54
|
-
* @param
|
|
55
|
-
* @
|
|
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.
|
|
56
102
|
*/
|
|
57
|
-
export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, }: ContextMenuProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
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;
|
|
58
104
|
export {};
|
|
@@ -1,59 +1,74 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { I } from "../../index.es-CkB4776y.js";
|
|
3
|
-
import { M as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import { jsx as i, jsxs as g, Fragment as _ } from "react/jsx-runtime";
|
|
2
|
+
import { I as z } from "../../index.es-CkB4776y.js";
|
|
3
|
+
import { M as F, L as V, a as h, b as $ } from "../../index.es-Cg57snrN.js";
|
|
4
|
+
import { c as o } from "../../index-Df2FYN-K.js";
|
|
5
|
+
import { useState as j, useCallback as x, useEffect as D, useMemo as d, Fragment as q } from "react";
|
|
6
|
+
import { createPortal as f } from "react-dom";
|
|
7
|
+
import { useBreakpoints as E } from "../../hooks/useBreakpoints.js";
|
|
8
|
+
import { OfflineView as T } from "../OfflineView/OfflineView.js";
|
|
9
|
+
import { s as t } from "../../contextMenu.module-RWPDK7Ds.js";
|
|
10
|
+
const X = ({
|
|
11
|
+
triggerOpen: c = null,
|
|
12
|
+
actions: u,
|
|
13
|
+
iconOrientation: p = "vertical",
|
|
14
|
+
"data-testid": M,
|
|
15
|
+
isOnline: B = !0,
|
|
16
|
+
offlineViewProps: N,
|
|
17
|
+
hasActionIconForSingleAction: b = !0,
|
|
18
|
+
isSingleActionTriggeredOnClick: L = !0,
|
|
19
|
+
isFloatingActionButtonOnMobile: S = !1,
|
|
20
|
+
floatingButtonPaddingInsertTarget: m,
|
|
21
|
+
floatingButtonScreenOffsetType: v = "buttonAppBar"
|
|
19
22
|
}) => {
|
|
20
|
-
const [
|
|
21
|
-
n(!i);
|
|
22
|
-
}, [i]), a = f(() => {
|
|
23
|
+
const [r, n] = j(!1), a = x(() => {
|
|
23
24
|
n(!1);
|
|
24
|
-
}, [])
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
}, []), w = x(() => {
|
|
26
|
+
r ? a() : n(!0);
|
|
27
|
+
}, [r, a]);
|
|
28
|
+
D(() => {
|
|
29
|
+
n(c !== null ? !!c : !1);
|
|
30
|
+
}, [c]);
|
|
31
|
+
const s = d(
|
|
32
|
+
() => u.filter((e) => e.isAllowed !== !1),
|
|
33
|
+
[u]
|
|
34
|
+
), { isDesktop: A } = E(), l = S && !A, k = d(() => {
|
|
35
|
+
if (s.length === 1 && b) {
|
|
36
|
+
const e = s[0];
|
|
37
|
+
if (typeof e.leadingBlock == "string")
|
|
38
|
+
return e.leadingBlock;
|
|
39
|
+
}
|
|
40
|
+
return p === "vertical" ? "more_vert" : "more_horiz";
|
|
41
|
+
}, [s, p, b]), C = d(() => m ? document.querySelector(m) : null, [m]);
|
|
42
|
+
if (s.length === 0) return null;
|
|
43
|
+
const y = /* @__PURE__ */ i(
|
|
44
|
+
F,
|
|
34
45
|
{
|
|
35
|
-
className:
|
|
36
|
-
"data-testid":
|
|
37
|
-
open:
|
|
46
|
+
className: o(t.menu, l && t.fabMenu),
|
|
47
|
+
"data-testid": M ?? "selection-menu",
|
|
48
|
+
open: r,
|
|
38
49
|
surfaceOnly: !0,
|
|
39
|
-
hoistToBody: !
|
|
50
|
+
hoistToBody: !l,
|
|
40
51
|
onClose: a,
|
|
41
|
-
trigger: /* @__PURE__ */
|
|
42
|
-
|
|
52
|
+
trigger: /* @__PURE__ */ i(
|
|
53
|
+
z,
|
|
43
54
|
{
|
|
44
|
-
className:
|
|
45
|
-
variant:
|
|
55
|
+
className: o(t.icon, l && t.fabIcon),
|
|
56
|
+
variant: r || l ? "filled-primary" : void 0,
|
|
57
|
+
iconSize: l ? "xlarge" : void 0,
|
|
46
58
|
"data-testid": "open-button",
|
|
47
|
-
icon:
|
|
48
|
-
onClick:
|
|
59
|
+
icon: k,
|
|
60
|
+
onClick: () => {
|
|
61
|
+
s.length === 1 && L ? (s[0].onClick?.(), a()) : w();
|
|
62
|
+
},
|
|
63
|
+
"data-icon": k
|
|
49
64
|
}
|
|
50
65
|
),
|
|
51
|
-
children:
|
|
52
|
-
e.dividerBefore && /* @__PURE__ */
|
|
53
|
-
/* @__PURE__ */
|
|
54
|
-
|
|
66
|
+
children: B ? /* @__PURE__ */ i(V, { "data-testid": "selection-list", children: s.map((e, I) => /* @__PURE__ */ g(q, { children: [
|
|
67
|
+
e.dividerBefore && /* @__PURE__ */ i(h, {}),
|
|
68
|
+
/* @__PURE__ */ i(
|
|
69
|
+
$,
|
|
55
70
|
{
|
|
56
|
-
className:
|
|
71
|
+
className: t.listItem,
|
|
57
72
|
...e,
|
|
58
73
|
leadingBlockType: "icon",
|
|
59
74
|
"data-testid": e["data-testid"],
|
|
@@ -62,20 +77,53 @@ import '../../assets/ContextMenu.css';const V = "_menu_148i2_1", B = "_icon_148i
|
|
|
62
77
|
}
|
|
63
78
|
}
|
|
64
79
|
),
|
|
65
|
-
e.dividerAfter && /* @__PURE__ */
|
|
66
|
-
] },
|
|
67
|
-
|
|
80
|
+
e.dividerAfter && /* @__PURE__ */ i(h, {})
|
|
81
|
+
] }, `LI_${e.primaryText?.toString()}_${I}`)) }) : /* @__PURE__ */ i(
|
|
82
|
+
T,
|
|
68
83
|
{
|
|
69
84
|
size: "small",
|
|
70
85
|
variant: "filled",
|
|
71
|
-
className:
|
|
72
|
-
...
|
|
86
|
+
className: t.offlineViewMargin,
|
|
87
|
+
...N
|
|
73
88
|
}
|
|
74
89
|
)
|
|
75
90
|
},
|
|
76
91
|
"selectionmenu"
|
|
77
92
|
);
|
|
93
|
+
if (l) {
|
|
94
|
+
const e = /* @__PURE__ */ i(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
className: o(
|
|
98
|
+
t.fabContainer,
|
|
99
|
+
v === "buttonAppBar" && t.buttonAppBar,
|
|
100
|
+
v === "fullScreen" && t.fullScreen
|
|
101
|
+
),
|
|
102
|
+
"data-testid": "fab-container",
|
|
103
|
+
children: y
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
return /* @__PURE__ */ g(_, { children: [
|
|
107
|
+
f(e, document.body),
|
|
108
|
+
f(
|
|
109
|
+
/* @__PURE__ */ i(
|
|
110
|
+
"div",
|
|
111
|
+
{
|
|
112
|
+
className: o(t.scrim, r && t.scrimVisible),
|
|
113
|
+
onClick: a,
|
|
114
|
+
"data-testid": "context-menu-scrim"
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
document.body
|
|
118
|
+
),
|
|
119
|
+
C && f(
|
|
120
|
+
/* @__PURE__ */ i("div", { className: t.fabSpacer, "data-testid": "fab-spacer" }),
|
|
121
|
+
C
|
|
122
|
+
)
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
return y;
|
|
78
126
|
};
|
|
79
127
|
export {
|
|
80
|
-
|
|
128
|
+
X as ContextMenu
|
|
81
129
|
};
|
|
@@ -13,6 +13,7 @@ import "../../orderBy-Ce85KqD6.js";
|
|
|
13
13
|
import "../../index-CuHybtft.js";
|
|
14
14
|
import "../SharedComponentsPermissionProvider/PermissionContext.js";
|
|
15
15
|
import { Modal as B } from "../Modal/Modal.js";
|
|
16
|
+
import "react-dom";
|
|
16
17
|
import { LoadingSpinner as M } from "../LoadingSpinner/Default/LoadingSpinner.js";
|
|
17
18
|
import "react-hook-form";
|
|
18
19
|
import "../../get-CBFiuc3f.js";
|
|
@@ -26,7 +27,7 @@ import '../../assets/DeleteModal.css';const j = "_bulletPoint_bd412_1", A = "_mo
|
|
|
26
27
|
modal: A,
|
|
27
28
|
colorDanger: G,
|
|
28
29
|
crossedOut: q
|
|
29
|
-
},
|
|
30
|
+
}, mo = ({
|
|
30
31
|
title: r,
|
|
31
32
|
confirmButtonLabel: t,
|
|
32
33
|
cancelButtonLabel: n,
|
|
@@ -123,5 +124,5 @@ import '../../assets/DeleteModal.css';const j = "_bulletPoint_bd412_1", A = "_mo
|
|
|
123
124
|
impossibleDeleteHeader: r
|
|
124
125
|
}) => /* @__PURE__ */ o(l, { level: 1, themeColor: "text-primary-on-background", children: r });
|
|
125
126
|
export {
|
|
126
|
-
|
|
127
|
+
mo as DeleteModal
|
|
127
128
|
};
|
|
@@ -8,6 +8,7 @@ import "../../react-tooltip.min-Dkz5ltCC.js";
|
|
|
8
8
|
import "../../orderBy-Ce85KqD6.js";
|
|
9
9
|
import "../../index-CuHybtft.js";
|
|
10
10
|
import "../SharedComponentsPermissionProvider/PermissionContext.js";
|
|
11
|
+
import "react-dom";
|
|
11
12
|
import "../../uniqueId-CJo-XRQb.js";
|
|
12
13
|
import { LoadingSpinner as w } from "../LoadingSpinner/Default/LoadingSpinner.js";
|
|
13
14
|
import "react-hook-form";
|
|
@@ -23,7 +24,7 @@ import '../../assets/EmptyView.css';const C = "_emptyViewContainer_19inl_1", V =
|
|
|
23
24
|
medium: x,
|
|
24
25
|
small: N,
|
|
25
26
|
title: g
|
|
26
|
-
},
|
|
27
|
+
}, J = ({
|
|
27
28
|
title: e,
|
|
28
29
|
subtitle: r,
|
|
29
30
|
height: m = "medium",
|
|
@@ -57,5 +58,5 @@ import '../../assets/EmptyView.css';const C = "_emptyViewContainer_19inl_1", V =
|
|
|
57
58
|
}
|
|
58
59
|
);
|
|
59
60
|
export {
|
|
60
|
-
|
|
61
|
+
J as EmptyView
|
|
61
62
|
};
|
|
@@ -14,6 +14,7 @@ import { SearchBar as I } from "../SearchBar/SearchBar.js";
|
|
|
14
14
|
import "../../index-CuHybtft.js";
|
|
15
15
|
import "../SharedComponentsPermissionProvider/PermissionContext.js";
|
|
16
16
|
import { Modal as K } from "../Modal/Modal.js";
|
|
17
|
+
import "react-dom";
|
|
17
18
|
import "../../uniqueId-CJo-XRQb.js";
|
|
18
19
|
import { Select as M } from "../Select/Select.js";
|
|
19
20
|
import "react-hook-form";
|
|
@@ -31,7 +32,7 @@ import '../../assets/Filter.css';const T = "_filterButton_1qtzn_1", V = "_relati
|
|
|
31
32
|
dense: Q,
|
|
32
33
|
filterModal: U,
|
|
33
34
|
borderRadius: X
|
|
34
|
-
},
|
|
35
|
+
}, yt = ({
|
|
35
36
|
clearFilterText: u,
|
|
36
37
|
closeCallback: d,
|
|
37
38
|
currentFilter: i,
|
|
@@ -203,5 +204,5 @@ import '../../assets/Filter.css';const T = "_filterButton_1qtzn_1", V = "_relati
|
|
|
203
204
|
);
|
|
204
205
|
};
|
|
205
206
|
export {
|
|
206
|
-
|
|
207
|
+
yt as Filter
|
|
207
208
|
};
|
|
@@ -806,7 +806,7 @@ var f = Gt.strings, ye = (
|
|
|
806
806
|
});
|
|
807
807
|
ot.displayName = "Modal";
|
|
808
808
|
ot.propTypes = Oe;
|
|
809
|
-
const be = "
|
|
809
|
+
const be = "_modal_1l955_1", Ie = "_gap_1l955_18", Ne = "_title_1l955_23", Be = "_titleWithoutCloseIcon_1l955_36", De = "_closeButton_1l955_40", Fe = "_errorBanner_1l955_52", y = {
|
|
810
810
|
modal: be,
|
|
811
811
|
gap: Ie,
|
|
812
812
|
title: Ne,
|
|
@@ -7,6 +7,7 @@ import "../../react-tooltip.min-Dkz5ltCC.js";
|
|
|
7
7
|
import "../../orderBy-Ce85KqD6.js";
|
|
8
8
|
import "../../index-CuHybtft.js";
|
|
9
9
|
import "../SharedComponentsPermissionProvider/PermissionContext.js";
|
|
10
|
+
import "react-dom";
|
|
10
11
|
import "../../uniqueId-CJo-XRQb.js";
|
|
11
12
|
import "react-hook-form";
|
|
12
13
|
import "../../get-CBFiuc3f.js";
|
|
@@ -15,7 +16,7 @@ import "../../isString-BNdV0Jpg.js";
|
|
|
15
16
|
import "../../omit-BWQrFyQ-.js";
|
|
16
17
|
import "../../types/Time.js";
|
|
17
18
|
import "../../react.esm-DF7i80eN.js";
|
|
18
|
-
const
|
|
19
|
+
const M = ({ children: o }) => {
|
|
19
20
|
const { isDesktop: t } = m();
|
|
20
21
|
return /* @__PURE__ */ i(
|
|
21
22
|
r,
|
|
@@ -28,5 +29,5 @@ const D = ({ children: o }) => {
|
|
|
28
29
|
);
|
|
29
30
|
};
|
|
30
31
|
export {
|
|
31
|
-
|
|
32
|
+
M as ModulePadding
|
|
32
33
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import './assets/contextMenu.css';const n = "_menu_1bdpq_1", _ = "_icon_1bdpq_6", e = "_listItem_1bdpq_10", c = "_offlineViewMargin_1bdpq_20", b = "_fabContainer_1bdpq_24", i = "_buttonAppBar_1bdpq_29", t = "_fullScreen_1bdpq_34", o = "_fabIcon_1bdpq_39", s = "_fabMenu_1bdpq_43", a = "_scrim_1bdpq_47", p = "_scrimVisible_1bdpq_60", r = "_fabSpacer_1bdpq_65", f = {
|
|
2
|
+
menu: n,
|
|
3
|
+
icon: _,
|
|
4
|
+
listItem: e,
|
|
5
|
+
offlineViewMargin: c,
|
|
6
|
+
fabContainer: b,
|
|
7
|
+
buttonAppBar: i,
|
|
8
|
+
fullScreen: t,
|
|
9
|
+
fabIcon: o,
|
|
10
|
+
fabMenu: s,
|
|
11
|
+
scrim: a,
|
|
12
|
+
scrimVisible: p,
|
|
13
|
+
fabSpacer: r
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
f as s
|
|
17
|
+
};
|
|
@@ -8,25 +8,26 @@ import "../react-tooltip.min-Dkz5ltCC.js";
|
|
|
8
8
|
import "../orderBy-Ce85KqD6.js";
|
|
9
9
|
import "../index-CuHybtft.js";
|
|
10
10
|
import "../components/SharedComponentsPermissionProvider/PermissionContext.js";
|
|
11
|
+
import "react-dom";
|
|
11
12
|
import "../uniqueId-CJo-XRQb.js";
|
|
12
13
|
import "react-hook-form";
|
|
13
14
|
import "../get-CBFiuc3f.js";
|
|
14
15
|
import "../omit-BWQrFyQ-.js";
|
|
15
16
|
import { DATE_FORMAT as c } from "../types/Time.js";
|
|
16
17
|
import "../react.esm-DF7i80eN.js";
|
|
17
|
-
const
|
|
18
|
+
const P = (t) => t.split(" ").map((r) => r.charAt(0).toUpperCase() + r.slice(1).toLowerCase()).join(" "), f = (t) => Object.fromEntries(
|
|
18
19
|
Object.entries(t).map(([r, i]) => [r, o(i)])
|
|
19
|
-
), o = (t) => n(t) ? t.map(o) : p(t) ? f(t) : s(t) ? t.trim() : t,
|
|
20
|
+
), o = (t) => n(t) ? t.map(o) : p(t) ? f(t) : s(t) ? t.trim() : t, U = (t, r, i = 2) => {
|
|
20
21
|
if (!r) return "0";
|
|
21
22
|
const m = e[t];
|
|
22
23
|
return r.toLocaleString(m, { maximumFractionDigits: i });
|
|
23
|
-
},
|
|
24
|
+
}, y = (t, r = "en-US", i = c) => a.includes(r) ? new Intl.DateTimeFormat(
|
|
24
25
|
e[r],
|
|
25
26
|
i
|
|
26
27
|
).format(new Date(t)) : new Intl.DateTimeFormat(r, i).format(new Date(t));
|
|
27
28
|
export {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
P as capitalizeFirstLetters,
|
|
30
|
+
y as getFormattedDateTime,
|
|
31
|
+
U as getNumberAsLocaleString,
|
|
31
32
|
f as trimLeadingAndTrailingSpaces
|
|
32
33
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hortiview/shared-components",
|
|
3
3
|
"description": "This is a shared component library. It should used in the HortiView platform and its modules.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.24.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://dev.azure.com/sdundc/HV%20Platform/_git/HortiView-Frontend-Shared",
|
|
7
7
|
"author": "Falk Menge <falk.menge.ext@bayer.com>",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._menu_148i2_1{width:15.875rem;border-radius:.5rem!important}._icon_148i2_6{color:var(--lmnt-theme-on-secondary-inactive)}._listItem_148i2_10 [class*=mdc-list-item__start]{color:var(--lmnt-theme-on-secondary-inactive);align-self:center!important;margin:0 1rem!important}._listItem_148i2_10 [class*=mdc-list-item__end]{color:var(--lmnt-theme-on-secondary-inactive)}._offlineViewMargin_148i2_20{margin:.5rem}
|