@hortiview/shared-components 2.24.3 → 2.25.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.
@@ -1,129 +1,90 @@
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"
1
+ import { jsx as t, jsxs as I } from "react/jsx-runtime";
2
+ import { I as A } from "../../index.es-CkB4776y.js";
3
+ import { M as h, L as k, a as c, b as y } from "../../index.es-Cg57snrN.js";
4
+ import { useState as q, useCallback as m, useEffect as L, useMemo as V, Fragment as B } from "react";
5
+ import { u as N } from "../../uniqueId-CJo-XRQb.js";
6
+ import { OfflineView as b } from "../OfflineView/OfflineView.js";
7
+ import { useIsAllowed as $ } from "../PermissionChecks/PermissionService.js";
8
+ import '../../assets/ContextMenu.css';const j = "_menu_x6qd9_1", z = "_icon_x6qd9_6", H = "_listItem_x6qd9_10", O = "_offlineViewMargin_x6qd9_20", n = {
9
+ menu: j,
10
+ icon: z,
11
+ listItem: H,
12
+ offlineViewMargin: O
13
+ }, U = ({
14
+ triggerOpen: s = null,
15
+ actions: r,
16
+ iconOrientation: _ = "vertical",
17
+ "data-testid": a,
18
+ isOnline: p = !0,
19
+ offlineViewProps: M
22
20
  }) => {
23
- const [r, n] = j(!1), a = x(() => {
24
- n(!1);
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,
21
+ const [f, i] = q(!1), u = $(), d = m(() => {
22
+ i(!1);
23
+ }, []), g = m(() => {
24
+ i((e) => !e);
25
+ }, []);
26
+ L(() => {
27
+ i(s !== null ? s : !1);
28
+ }, [s]);
29
+ const o = V(() => r.filter((e) => e.isHidden || e.isAllowed === !1 ? !1 : !(e.permissionConfiguration && !u(e.permissionConfiguration))), [r, u]);
30
+ return o.length === 0 ? null : /* @__PURE__ */ t(
31
+ h,
45
32
  {
46
- className: o(t.menu, l && t.fabMenu),
47
- "data-testid": M ?? "selection-menu",
48
- open: r,
33
+ className: n.menu,
34
+ "data-testid": a ?? "contextMenu-undefined",
35
+ open: f,
49
36
  surfaceOnly: !0,
50
- hoistToBody: !l,
51
- onClose: a,
52
- trigger: /* @__PURE__ */ i(
53
- z,
37
+ hoistToBody: !0,
38
+ onClose: d,
39
+ trigger: /* @__PURE__ */ t(
40
+ A,
54
41
  {
55
- className: o(t.icon, l && t.fabIcon),
56
- variant: r || l ? "filled-primary" : void 0,
57
- iconSize: l ? "xlarge" : void 0,
42
+ className: n.icon,
43
+ variant: f ? "filled-primary" : void 0,
58
44
  "data-testid": "open-button",
59
- icon: k,
60
- onClick: () => {
61
- s.length === 1 && L ? (s[0].onClick?.(), a()) : w();
62
- },
63
- "data-icon": k
45
+ icon: _ === "vertical" ? "more_vert" : "more_horiz",
46
+ onClick: g
64
47
  }
65
48
  ),
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
- $,
70
- {
71
- className: t.listItem,
72
- ...e,
73
- leadingBlockType: "icon",
74
- "data-testid": e["data-testid"],
75
- onClick: () => {
76
- e?.onClick?.(), e.closeOnClick !== !1 && a();
49
+ children: p ? /* @__PURE__ */ t(k, { "data-testid": "selection-list", children: o.map((e, l) => {
50
+ const {
51
+ closeOnClick: w,
52
+ dividerBefore: x,
53
+ dividerAfter: C,
54
+ permissionConfiguration: S,
55
+ isAllowed: T,
56
+ isHidden: D,
57
+ ...v
58
+ } = e;
59
+ return /* @__PURE__ */ I(B, { children: [
60
+ x && l !== 0 && /* @__PURE__ */ t(c, {}),
61
+ /* @__PURE__ */ t(
62
+ y,
63
+ {
64
+ className: n.listItem,
65
+ ...v,
66
+ leadingBlockType: "icon",
67
+ "data-testid": e["data-testid"] ?? `contextMenu-action-${l}`,
68
+ onClick: () => {
69
+ e?.onClick?.(), w !== !1 && d();
70
+ }
77
71
  }
78
- }
79
- ),
80
- e.dividerAfter && /* @__PURE__ */ i(h, {})
81
- ] }, `LI_${e.primaryText?.toString()}_${I}`)) }) : /* @__PURE__ */ i(
82
- T,
72
+ ),
73
+ C && l !== o.length - 1 && /* @__PURE__ */ t(c, {})
74
+ ] }, N(`LI_${e.primaryText?.toString()}_`));
75
+ }) }) : /* @__PURE__ */ t(
76
+ b,
83
77
  {
84
78
  size: "small",
85
79
  variant: "filled",
86
- className: t.offlineViewMargin,
87
- ...N
80
+ className: n.offlineViewMargin,
81
+ ...M
88
82
  }
89
83
  )
90
84
  },
91
- "selectionmenu"
85
+ `contextMenu-${a ?? "undefined"}`
92
86
  );
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;
126
87
  };
127
88
  export {
128
- X as ContextMenu
89
+ U as ContextMenu
129
90
  };
@@ -8,8 +8,8 @@ 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";
12
11
  import "../../uniqueId-CJo-XRQb.js";
12
+ import "react-dom";
13
13
  import { LoadingSpinner as w } from "../LoadingSpinner/Default/LoadingSpinner.js";
14
14
  import "react-hook-form";
15
15
  import "../../get-CBFiuc3f.js";
@@ -14,8 +14,8 @@ 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";
18
17
  import "../../uniqueId-CJo-XRQb.js";
18
+ import "react-dom";
19
19
  import { Select as M } from "../Select/Select.js";
20
20
  import "react-hook-form";
21
21
  import "../../get-CBFiuc3f.js";
@@ -0,0 +1,76 @@
1
+ import { OfflineViewProps } from '../OfflineView/OfflineView';
2
+ import { ActionProps } from '../ContextMenu/ContextMenu.tsx';
3
+
4
+ export type FloatingActionButtonProps = {
5
+ /**
6
+ * List of actions to display in the FAB as ListItems
7
+ */
8
+ actions: ActionProps[];
9
+ /**
10
+ * If not null, the menu will be open
11
+ */
12
+ triggerOpen?: boolean | null;
13
+ /**
14
+ * Determines if the menu icon should be vertical or horizontal three dots when multiple actions are present
15
+ * Default is 'vertical'
16
+ */
17
+ iconOrientation?: 'vertical' | 'horizontal';
18
+ 'data-testid'?: string;
19
+ /**
20
+ * Whether the user is online; shows OfflineView when false.
21
+ */
22
+ isOnline?: boolean;
23
+ /**
24
+ * Props forwarded to <OfflineView /> when offline.
25
+ */
26
+ offlineViewProps?: Partial<OfflineViewProps>;
27
+ /**
28
+ * If only one action is provided/allowed, trigger that action without opening the menu
29
+ * @remarks Basically turns the component into an icon button
30
+ * @default true
31
+ */
32
+ isSingleActionTriggeredOnClick?: boolean;
33
+ /**
34
+ * If only one action is provided/visible, show the icon of that action in the FAB button instead of the default menu icon
35
+ * @default true
36
+ */
37
+ hasActionIconForSingleAction?: boolean;
38
+ /**
39
+ * Specify a target element (query selector) to insert an extra padding element below.
40
+ * The padding element is used to make sure the FAB doesn't block any elements at the end of a view.
41
+ * @example '#layout-container'
42
+ */
43
+ floatingButtonPaddingInsertTarget?: string;
44
+ /**
45
+ * Determines the distance/offset of the floating action button from the bottom and right edge of the screen
46
+ * - 'buttonAppBar' adds offset for when the element ButtonAppBar is used, so the button stays slightly above the bar
47
+ * - 'fullScreen' adds offset for a full-screen view, with the button sitting slightly above the screen edges
48
+ * @default 'buttonAppBar'
49
+ */
50
+ floatingButtonScreenOffsetType?: 'buttonAppBar' | 'fullScreen';
51
+ /**
52
+ * Variants prefixed with filled- will add a background color to the icon according to the theme.
53
+ * Variants prefixed with color- will change the color of the icon according to the theme.
54
+ * Default: 'filled-primary'
55
+ */
56
+ variant?: 'filled-danger-alt' | 'filled-danger' | 'filled-primary' | 'filled-secondary' | 'color-primary' | 'color-secondary' | 'color-on-dark' | 'color-on-unknown-black' | 'secondary-on-surface';
57
+ };
58
+ /**
59
+ * FloatingActionButton (FAB) for mobile and tablet layouts.
60
+ *
61
+ * Renders a floating action button fixed near the bottom-right of the viewport,
62
+ * providing quick access to contextual actions. Not rendered on desktop breakpoints.
63
+ *
64
+ * Behavior depends on the amount of actions:
65
+ * - No actions: renders nothing
66
+ * - Single action: clicking the FAB triggers it directly; optionally displays that action's icon on the FAB.
67
+ * This can be controlled using the `isSingleActionTriggeredOnClick` and `hasActionIconForSingleAction` props
68
+ * - Multiple actions: clicking the FAB toggles a menu with all available actions
69
+ *
70
+ * FAB and scrim are portaled to `document.body` to float above layout constraints
71
+ * Optional spacer element can be inserted into a target element via `floatingButtonPaddingInsertTarget` to prevent the FAB from covering content
72
+ *
73
+ * This component is anchored as a floating overlay
74
+ * Use `floatingButtonScreenOffsetType` to control the distance from screen edges (above bottom app bar or full-screen layout)
75
+ */
76
+ export declare const FloatingActionButton: ({ actions, triggerOpen, iconOrientation, "data-testid": dataTestId, isOnline, offlineViewProps, hasActionIconForSingleAction, isSingleActionTriggeredOnClick, floatingButtonPaddingInsertTarget, floatingButtonScreenOffsetType, variant, }: FloatingActionButtonProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,150 @@
1
+ import { jsx as n, jsxs as M, Fragment as z } from "react/jsx-runtime";
2
+ import { I as F } from "../../index.es-CkB4776y.js";
3
+ import { M as j, L as D, a as k, b as H } from "../../index.es-Cg57snrN.js";
4
+ import { c as r } from "../../index-Df2FYN-K.js";
5
+ import { useState as E, useCallback as w, useEffect as G, useMemo as f, Fragment as J } from "react";
6
+ import { createPortal as d } from "react-dom";
7
+ import { useBreakpoints as K } from "../../hooks/useBreakpoints.js";
8
+ import { OfflineView as O } from "../OfflineView/OfflineView.js";
9
+ import { useIsAllowed as Q } from "../PermissionChecks/PermissionService.js";
10
+ import '../../assets/FloatingActionButton.css';const R = "_menu_1bdpq_1", T = "_icon_1bdpq_6", U = "_listItem_1bdpq_10", W = "_offlineViewMargin_1bdpq_20", X = "_fabContainer_1bdpq_24", Y = "_buttonAppBar_1bdpq_29", Z = "_fullScreen_1bdpq_34", P = "_fabIcon_1bdpq_39", ee = "_fabMenu_1bdpq_43", te = "_scrim_1bdpq_47", ne = "_scrimVisible_1bdpq_60", ie = "_fabSpacer_1bdpq_65", t = {
11
+ menu: R,
12
+ icon: T,
13
+ listItem: U,
14
+ offlineViewMargin: W,
15
+ fabContainer: X,
16
+ buttonAppBar: Y,
17
+ fullScreen: Z,
18
+ fabIcon: P,
19
+ fabMenu: ee,
20
+ scrim: te,
21
+ scrimVisible: ne,
22
+ fabSpacer: ie
23
+ }, _e = ({
24
+ actions: m,
25
+ triggerOpen: a = null,
26
+ iconOrientation: u = "vertical",
27
+ "data-testid": b,
28
+ isOnline: B = !0,
29
+ offlineViewProps: S,
30
+ hasActionIconForSingleAction: p = !0,
31
+ isSingleActionTriggeredOnClick: h = !0,
32
+ floatingButtonPaddingInsertTarget: l,
33
+ floatingButtonScreenOffsetType: _ = "buttonAppBar",
34
+ variant: v = "filled-primary"
35
+ }) => {
36
+ const [g, c] = E(!1), { isDesktop: I } = K(), C = Q(), s = w(() => {
37
+ c(!1);
38
+ }, []), y = w(() => {
39
+ c((e) => !e);
40
+ }, []);
41
+ G(() => {
42
+ a !== null && c(!!a);
43
+ }, [a]);
44
+ const i = f(() => m.filter((e) => e.isHidden || e.isAllowed === !1 ? !1 : !(e.permissionConfiguration && !C(e.permissionConfiguration))), [m, C]), q = f(() => {
45
+ if (i.length === 1 && p) {
46
+ const e = i[0];
47
+ if (typeof e.leadingBlock == "string")
48
+ return e.leadingBlock;
49
+ }
50
+ return u === "vertical" ? "more_vert" : "more_horiz";
51
+ }, [i, u, p]), A = f(() => l ? document.querySelector(l) : null, [l]);
52
+ if (I || i.length === 0)
53
+ return null;
54
+ const V = /* @__PURE__ */ n(
55
+ j,
56
+ {
57
+ className: r(t.menu, t.fabMenu),
58
+ "data-testid": b ?? "fab-undefined",
59
+ open: g,
60
+ surfaceOnly: !0,
61
+ hoistToBody: !1,
62
+ onClose: s,
63
+ trigger: /* @__PURE__ */ n(
64
+ F,
65
+ {
66
+ className: r(t.icon, t.fabIcon),
67
+ variant: v,
68
+ iconSize: "xlarge",
69
+ "data-testid": "open-button",
70
+ icon: q,
71
+ onClick: () => {
72
+ i.length === 1 && h ? (i[0].onClick?.(), s()) : y();
73
+ },
74
+ "data-icon": q
75
+ }
76
+ ),
77
+ children: B ? /* @__PURE__ */ n(D, { "data-testid": "selection-list", children: i.map((e, o) => {
78
+ const {
79
+ closeOnClick: N,
80
+ dividerBefore: L,
81
+ dividerAfter: $,
82
+ permissionConfiguration: se,
83
+ isAllowed: oe,
84
+ isHidden: re,
85
+ ...x
86
+ } = e;
87
+ return /* @__PURE__ */ M(J, { children: [
88
+ L && o !== 0 && /* @__PURE__ */ n(k, {}),
89
+ /* @__PURE__ */ n(
90
+ H,
91
+ {
92
+ className: t.listItem,
93
+ ...x,
94
+ leadingBlockType: "icon",
95
+ "data-testid": e["data-testid"] ?? `fab-action-${o}`,
96
+ onClick: () => {
97
+ e?.onClick?.(), N !== !1 && s();
98
+ }
99
+ }
100
+ ),
101
+ $ && o !== i.length - 1 && /* @__PURE__ */ n(k, {})
102
+ ] }, `LI_${e.primaryText?.toString()}_${o}`);
103
+ }) }) : /* @__PURE__ */ n(
104
+ O,
105
+ {
106
+ size: "small",
107
+ variant: "filled",
108
+ className: t.offlineViewMargin,
109
+ ...S
110
+ }
111
+ )
112
+ },
113
+ `fab-${b ?? "undefined"}`
114
+ );
115
+ return /* @__PURE__ */ M(z, { children: [
116
+ d(
117
+ /* @__PURE__ */ n(
118
+ "div",
119
+ {
120
+ className: r(
121
+ t.fabContainer,
122
+ _ === "buttonAppBar" && t.buttonAppBar,
123
+ _ === "fullScreen" && t.fullScreen
124
+ ),
125
+ "data-testid": "fab-container",
126
+ children: V
127
+ }
128
+ ),
129
+ document.body
130
+ ),
131
+ d(
132
+ /* @__PURE__ */ n(
133
+ "div",
134
+ {
135
+ className: r(t.scrim, g && t.scrimVisible),
136
+ onClick: s,
137
+ "data-testid": "context-menu-scrim"
138
+ }
139
+ ),
140
+ document.body
141
+ ),
142
+ A && d(
143
+ /* @__PURE__ */ n("div", { className: t.fabSpacer, "data-testid": "fab-spacer" }),
144
+ A
145
+ )
146
+ ] });
147
+ };
148
+ export {
149
+ _e as FloatingActionButton
150
+ };
@@ -7,8 +7,8 @@ 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";
11
10
  import "../../uniqueId-CJo-XRQb.js";
11
+ import "react-dom";
12
12
  import "react-hook-form";
13
13
  import "../../get-CBFiuc3f.js";
14
14
  import "../../isArray-olhCpv2e.js";
package/dist/main.d.ts CHANGED
@@ -14,6 +14,7 @@ export { EmptyView } from './components/EmptyView/EmptyView';
14
14
  export { ErrorBanner } from './components/ErrorBanner/ErrorBanner';
15
15
  export { Filter } from './components/Filter/Filter';
16
16
  export { FormattedNumberDisplay } from './components/FormattedNumberDisplay/FormattedNumberDisplay';
17
+ export { FloatingActionButton } from './components/FloatingActionButton/FloatingActionButton';
17
18
  export { GenericTable } from './components/GenericTable/GenericTable';
18
19
  export { HashTabView } from './components/HashTabView/HashTabView';
19
20
  export { HeaderFilter } from './components/HeaderFilter/HeaderFilter';