@hortiview/shared-components 2.28.2 → 2.28.3
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/components/ContextMenu/ContextMenu.d.ts +11 -3
- package/components/ContextMenu/ContextMenu.js +97 -87
- package/components/ContextMenu/ContextMenuService.d.ts +8 -0
- package/components/ContextMenu/ContextMenuService.js +19 -0
- package/components/GenericTable/GenericTableService.js +22 -22
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ListItemProps } from '@element-public/react-list';
|
|
2
|
+
import { MenuProps } from '@element-public/react-menu';
|
|
2
3
|
import { OfflineViewProps } from '../OfflineView/OfflineView';
|
|
3
4
|
import { IsAllowedProps } from '../PermissionChecks/PermissionService.tsx';
|
|
4
|
-
type ContextMenuProps = {
|
|
5
|
+
type ContextMenuProps = MenuProps & {
|
|
5
6
|
/**
|
|
6
7
|
* If not null, the menu will be open
|
|
7
8
|
*/
|
|
@@ -25,6 +26,10 @@ type ContextMenuProps = {
|
|
|
25
26
|
* Props forwarded to <OfflineView /> when offline.
|
|
26
27
|
*/
|
|
27
28
|
offlineViewProps?: Partial<OfflineViewProps>;
|
|
29
|
+
/**
|
|
30
|
+
* Optional className to apply to the menu container
|
|
31
|
+
*/
|
|
32
|
+
className?: string;
|
|
28
33
|
};
|
|
29
34
|
export type ActionProps = ListItemProps & {
|
|
30
35
|
closeOnClick?: boolean;
|
|
@@ -54,7 +59,8 @@ export type ActionProps = ListItemProps & {
|
|
|
54
59
|
*
|
|
55
60
|
* @param {boolean} triggerOpen indicates if the menu should be open
|
|
56
61
|
* @param {ListItemProps[]} actions list of actions to display in the context menu as ListItems
|
|
57
|
-
* @param
|
|
62
|
+
* @param {'vertical' | 'horizontal'} iconOrientation determines if menu icon should be vertical or horizontal three dots. Default is 'vertical'
|
|
63
|
+
* @param {string} data-testid id for testing, automatically prefixed
|
|
58
64
|
* @recommended `primaryText`, `onClick`, `leadingBlock`
|
|
59
65
|
* @requires `ListItemProps` from `@element-public/react-components`
|
|
60
66
|
* @example const actions = [
|
|
@@ -64,7 +70,9 @@ export type ActionProps = ListItemProps & {
|
|
|
64
70
|
* ];
|
|
65
71
|
* @param {boolean} isOnline Whether the user is online; shows OfflineView when false.
|
|
66
72
|
* @param {OfflineViewProps} offlineViewProps Props forwarded to OfflineView when offline.
|
|
73
|
+
* @param {string} className Optional className to apply to the menu container
|
|
74
|
+
* @param {MenuProps} menuProps Element Menu props, e.g. `hoistToBody`, `themeColor`, etc.
|
|
67
75
|
* @returns a context menu with the given actions as ListItems
|
|
68
76
|
*/
|
|
69
|
-
export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, }: ContextMenuProps) => import("react").JSX.Element | null;
|
|
77
|
+
export declare const ContextMenu: ({ triggerOpen, actions, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, className, ...menuProps }: ContextMenuProps) => import("react").JSX.Element | null;
|
|
70
78
|
export {};
|
|
@@ -1,120 +1,130 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { I as
|
|
3
|
-
import { M as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
import { jsx as t, jsxs as L } from "react/jsx-runtime";
|
|
2
|
+
import { I as A } from "../../index.es-BwhRJBEH.js";
|
|
3
|
+
import { M as B, L as O, a as x, b as V } from "../../index.es-BIgjyLDa.js";
|
|
4
|
+
import { c as C } from "../../index-_-9ybP20.js";
|
|
5
|
+
import { u as E } from "../../uniqueId-CJo-XRQb.js";
|
|
6
|
+
import { useState as I, useRef as T, useCallback as M, useEffect as k, useMemo as N, Fragment as R, useLayoutEffect as z } from "react";
|
|
7
|
+
import { u as H } from "../../useBreakpoints-DDrM9Cfx.js";
|
|
8
|
+
import { OfflineView as S } from "../OfflineView/OfflineView.js";
|
|
9
|
+
import { useIsAllowed as $ } from "../PermissionChecks/PermissionService.js";
|
|
10
|
+
import { repositionMenuVertically as j } from "./ContextMenuService.js";
|
|
11
|
+
import '../../assets/ContextMenu.css';const q = "_menu_52omh_1", D = "_mobile_52omh_7", F = "_desktop_52omh_11", G = "_icon_52omh_15", J = "_listItem_52omh_19", K = "_offlineViewMargin_52omh_51", Q = "_primaryTextTruncated_52omh_55", o = {
|
|
12
|
+
menu: q,
|
|
13
|
+
mobile: D,
|
|
14
|
+
desktop: F,
|
|
15
|
+
icon: G,
|
|
16
|
+
listItem: J,
|
|
17
|
+
offlineViewMargin: K,
|
|
18
|
+
primaryTextTruncated: Q
|
|
19
|
+
}, oe = ({
|
|
20
|
+
triggerOpen: n = null,
|
|
21
|
+
actions: u,
|
|
22
|
+
iconOrientation: m = "vertical",
|
|
23
|
+
"data-testid": f,
|
|
24
|
+
isOnline: d = !0,
|
|
25
|
+
offlineViewProps: y,
|
|
26
|
+
className: g,
|
|
27
|
+
...s
|
|
25
28
|
}) => {
|
|
26
|
-
const { isMobile:
|
|
27
|
-
|
|
28
|
-
}, []),
|
|
29
|
-
|
|
29
|
+
const { isMobile: w } = H(), [l, c] = I(!1), _ = T(null), a = T(null), r = $(), i = M(() => {
|
|
30
|
+
c(!1);
|
|
31
|
+
}, []), p = M(() => {
|
|
32
|
+
c((e) => !e);
|
|
30
33
|
}, []);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}, [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
k(() => {
|
|
35
|
+
c(n !== null ? n : !1);
|
|
36
|
+
}, [n]), k(() => {
|
|
37
|
+
if (!l || !s.hoistToBody) return;
|
|
38
|
+
const e = () => {
|
|
39
|
+
j(_.current, a.current) && i();
|
|
40
|
+
};
|
|
41
|
+
return window.addEventListener("scroll", e, !0), () => window.removeEventListener("scroll", e, !0);
|
|
42
|
+
}, [l, i, s.hoistToBody]);
|
|
43
|
+
const b = C(o.menu, g), v = N(() => u.filter((e) => e.isHidden || e.isAllowed === !1 ? !1 : !(e.permissionConfiguration && !r(e.permissionConfiguration))), [u, r]);
|
|
44
|
+
return v.length === 0 ? null : /* @__PURE__ */ t("div", { ref: _, children: /* @__PURE__ */ t(
|
|
45
|
+
B,
|
|
37
46
|
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
ref: a,
|
|
48
|
+
className: b,
|
|
49
|
+
"data-testid": f ?? "contextMenu-undefined",
|
|
50
|
+
open: l,
|
|
41
51
|
surfaceOnly: !0,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
k,
|
|
52
|
+
onClose: i,
|
|
53
|
+
trigger: /* @__PURE__ */ t(
|
|
54
|
+
A,
|
|
46
55
|
{
|
|
47
|
-
className:
|
|
48
|
-
variant:
|
|
56
|
+
className: o.icon,
|
|
57
|
+
variant: l ? "filled-primary" : void 0,
|
|
49
58
|
"data-testid": "open-button",
|
|
50
|
-
icon:
|
|
51
|
-
onClick:
|
|
59
|
+
icon: m === "vertical" ? "more_vert" : "more_horiz",
|
|
60
|
+
onClick: p
|
|
52
61
|
}
|
|
53
62
|
),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
/* @__PURE__ */
|
|
57
|
-
|
|
63
|
+
...s,
|
|
64
|
+
children: d ? /* @__PURE__ */ t(O, { "data-testid": "selection-list", children: v.map((e, h) => /* @__PURE__ */ L(R, { children: [
|
|
65
|
+
e.dividerBefore && h !== 0 && /* @__PURE__ */ t(x, {}),
|
|
66
|
+
/* @__PURE__ */ t(
|
|
67
|
+
U,
|
|
58
68
|
{
|
|
59
69
|
actionProps: e,
|
|
60
|
-
index:
|
|
61
|
-
isMobile:
|
|
62
|
-
closeMenu:
|
|
70
|
+
index: h,
|
|
71
|
+
isMobile: w,
|
|
72
|
+
closeMenu: i
|
|
63
73
|
}
|
|
64
74
|
),
|
|
65
|
-
e.dividerAfter &&
|
|
66
|
-
] },
|
|
67
|
-
|
|
75
|
+
e.dividerAfter && h !== v.length - 1 && /* @__PURE__ */ t(x, {})
|
|
76
|
+
] }, E(`LI_${e.primaryText?.toString()}_`))) }) : /* @__PURE__ */ t(
|
|
77
|
+
S,
|
|
68
78
|
{
|
|
69
79
|
size: "small",
|
|
70
80
|
variant: "filled",
|
|
71
|
-
className:
|
|
72
|
-
...
|
|
81
|
+
className: o.offlineViewMargin,
|
|
82
|
+
...y
|
|
73
83
|
}
|
|
74
84
|
)
|
|
75
85
|
},
|
|
76
|
-
`contextMenu-${
|
|
77
|
-
);
|
|
78
|
-
},
|
|
79
|
-
actionProps:
|
|
80
|
-
index:
|
|
81
|
-
isMobile:
|
|
82
|
-
closeMenu:
|
|
86
|
+
`contextMenu-${f ?? "undefined"}`
|
|
87
|
+
) });
|
|
88
|
+
}, U = ({
|
|
89
|
+
actionProps: n,
|
|
90
|
+
index: u,
|
|
91
|
+
isMobile: m,
|
|
92
|
+
closeMenu: f
|
|
83
93
|
}) => {
|
|
84
|
-
const
|
|
85
|
-
return
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
const
|
|
94
|
+
const d = T(null), [y, g] = I(!1), { closeOnClick: s, permissionConfiguration: w, isAllowed: l, isHidden: c, ..._ } = n;
|
|
95
|
+
return z(() => {
|
|
96
|
+
const a = d.current;
|
|
97
|
+
if (!a) return;
|
|
98
|
+
const r = a.querySelector(
|
|
89
99
|
"[class*='mdc-list-item__primary-text']"
|
|
90
100
|
);
|
|
91
|
-
if (!
|
|
92
|
-
const
|
|
93
|
-
|
|
101
|
+
if (!r) return;
|
|
102
|
+
const i = () => {
|
|
103
|
+
g(r.scrollHeight > r.clientHeight);
|
|
94
104
|
};
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
return
|
|
98
|
-
|
|
105
|
+
i();
|
|
106
|
+
const p = new ResizeObserver(i);
|
|
107
|
+
return p.observe(r), () => {
|
|
108
|
+
p.disconnect();
|
|
99
109
|
};
|
|
100
|
-
}, [
|
|
101
|
-
|
|
110
|
+
}, [n.primaryText, m]), /* @__PURE__ */ t(
|
|
111
|
+
V,
|
|
102
112
|
{
|
|
103
|
-
ref:
|
|
104
|
-
"data-testid":
|
|
105
|
-
className:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
113
|
+
ref: d,
|
|
114
|
+
"data-testid": n["data-testid"] ?? `contextMenu-action-${u}`,
|
|
115
|
+
className: C(
|
|
116
|
+
o.listItem,
|
|
117
|
+
y && o.primaryTextTruncated,
|
|
118
|
+
m ? o.mobile : o.desktop
|
|
109
119
|
),
|
|
110
|
-
...
|
|
120
|
+
..._,
|
|
111
121
|
leadingBlockType: "icon",
|
|
112
122
|
onClick: () => {
|
|
113
|
-
|
|
123
|
+
n?.onClick?.(), s !== !1 && f();
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
);
|
|
117
127
|
};
|
|
118
128
|
export {
|
|
119
|
-
|
|
129
|
+
oe as ContextMenu
|
|
120
130
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repositions the menu vertically to stick with the trigger while scrolling.
|
|
3
|
+
* Horizontal scrolling is ignored.
|
|
4
|
+
*
|
|
5
|
+
* @returns `true` if the trigger has scrolled outside the vertical boundary of
|
|
6
|
+
* its nearest scrollable ancestor (or the viewport), otherwise `false`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const repositionMenuVertically: (triggerElement: HTMLElement | null, menuElement: HTMLElement | null) => boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const c = (e, t) => {
|
|
2
|
+
const o = e?.getBoundingClientRect();
|
|
3
|
+
if (!o || !t) return !1;
|
|
4
|
+
t.style.top = `${o.bottom}px`;
|
|
5
|
+
const l = r(e), n = l ? l.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
|
|
6
|
+
return o.bottom < n.top || o.top > n.bottom;
|
|
7
|
+
}, r = (e) => {
|
|
8
|
+
let t = e?.parentElement ?? null;
|
|
9
|
+
for (; t; ) {
|
|
10
|
+
const { overflow: o, overflowY: l } = getComputedStyle(t);
|
|
11
|
+
if (/(auto|scroll|overlay)/.test(o + l) && t.scrollHeight > t.clientHeight)
|
|
12
|
+
return t;
|
|
13
|
+
t = t.parentElement;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
c as repositionMenuVertically
|
|
19
|
+
};
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { jsx as p } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo as
|
|
2
|
+
import { useMemo as a } from "react";
|
|
3
3
|
import { ContextMenu as l } from "../ContextMenu/ContextMenu.js";
|
|
4
4
|
const P = ({
|
|
5
5
|
data: n = [],
|
|
6
6
|
order: e = [],
|
|
7
7
|
cellTemplates: r = void 0,
|
|
8
|
-
headerTranslation: t = (
|
|
8
|
+
headerTranslation: t = (d) => d,
|
|
9
9
|
getRowActions: c = void 0,
|
|
10
|
-
customColumnWidth:
|
|
10
|
+
customColumnWidth: i,
|
|
11
11
|
cardTitleColumn: u,
|
|
12
12
|
cardSubTitleColumn: s
|
|
13
|
-
}) =>
|
|
13
|
+
}) => a(() => {
|
|
14
14
|
if (n?.length === 0) return [];
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const d = h(n[0], e).map((o) => {
|
|
16
|
+
const f = i ? i[o] : void 0;
|
|
17
17
|
return {
|
|
18
|
-
id:
|
|
19
|
-
header: t(
|
|
20
|
-
accessor:
|
|
21
|
-
cellTemplate: r ? r[
|
|
22
|
-
cellProps:
|
|
23
|
-
headerCellProps:
|
|
24
|
-
asCardTitle:
|
|
25
|
-
asCardSubtitle:
|
|
18
|
+
id: o,
|
|
19
|
+
header: t(o),
|
|
20
|
+
accessor: o,
|
|
21
|
+
cellTemplate: r ? r[o] : void 0,
|
|
22
|
+
cellProps: f ? { width: f } : void 0,
|
|
23
|
+
headerCellProps: f ? { width: f } : void 0,
|
|
24
|
+
asCardTitle: o === u,
|
|
25
|
+
asCardSubtitle: o === s
|
|
26
26
|
};
|
|
27
27
|
});
|
|
28
28
|
return c ? [
|
|
29
|
-
...
|
|
29
|
+
...d,
|
|
30
30
|
{
|
|
31
31
|
id: "actions",
|
|
32
32
|
header: " ",
|
|
@@ -34,28 +34,28 @@ const P = ({
|
|
|
34
34
|
cellProps: { id: "actions" },
|
|
35
35
|
headerCellProps: { id: "actions" }
|
|
36
36
|
}
|
|
37
|
-
] :
|
|
37
|
+
] : d;
|
|
38
38
|
}, [
|
|
39
39
|
n,
|
|
40
40
|
r,
|
|
41
41
|
e,
|
|
42
42
|
t,
|
|
43
43
|
c,
|
|
44
|
-
|
|
44
|
+
i,
|
|
45
45
|
u,
|
|
46
46
|
s
|
|
47
47
|
]), C = ({
|
|
48
48
|
data: n = [],
|
|
49
49
|
getRowActions: e = void 0
|
|
50
|
-
}) =>
|
|
50
|
+
}) => a(() => e ? n.map((r) => {
|
|
51
51
|
const t = e(r);
|
|
52
|
-
return !t || t.length === 0 ? r : { ...r, actions: /* @__PURE__ */ p(l, { actions: t, iconOrientation: "horizontal" }) };
|
|
53
|
-
}) : n, [n, e]),
|
|
52
|
+
return !t || t.length === 0 ? r : { ...r, actions: /* @__PURE__ */ p(l, { hoistToBody: !0, actions: t, iconOrientation: "horizontal" }) };
|
|
53
|
+
}) : n, [n, e]), h = (n, e) => {
|
|
54
54
|
if (!n) return [];
|
|
55
55
|
let r = Object.keys(n).map((t) => t);
|
|
56
56
|
return e?.length > 0 && (r = r.sort((t, c) => {
|
|
57
|
-
const
|
|
58
|
-
return
|
|
57
|
+
const i = e.findIndex((s) => s === t), u = e.findIndex((s) => s === c);
|
|
58
|
+
return i === -1 ? 1 : u === -1 ? -1 : i - u;
|
|
59
59
|
})), r;
|
|
60
60
|
};
|
|
61
61
|
export {
|
package/package.json
CHANGED