@equinor/cpl-top-bar-react 0.2.4 → 0.3.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/dist/index.d.mts CHANGED
@@ -1,16 +1,46 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as styled_components_dist_types from 'styled-components/dist/types';
3
+ import * as styled_components from 'styled-components';
4
+ import * as react from 'react';
5
+ import { ReactNode } from 'react';
6
+
7
+ interface FeedbackLinkProps {
8
+ link: string;
9
+ subject: string;
10
+ body: string;
11
+ }
12
+ /**
13
+ * `FeedbackLink`
14
+ * component renders a link that opens the user's email client
15
+ * with pre-filled subject and body for feedback. The email link should be the link to a Teams channel.
16
+ */
17
+ declare function FeedbackLink({ link, subject, body }: FeedbackLinkProps): react_jsx_runtime.JSX.Element;
2
18
 
3
19
  interface TopBarProps {
4
20
  appName: string;
5
21
  logoLink: string;
6
- documentationLink: string;
22
+ sideMenuOpen?: boolean;
23
+ setSideMenuOpen?: (open: boolean) => void;
24
+ /**
25
+ * optional custom button component to trigger the side menu
26
+ * If provided, it will be rendered instead of the default menu button.
27
+ */
28
+ menuButton?: (onClick: () => void) => ReactNode;
29
+ documentationLink?: string;
7
30
  documentationName?: string;
31
+ feedbackLink?: React.ReactNode;
8
32
  userMenu?: React.ReactNode;
9
- darkMode?: boolean;
10
33
  logoPath?: string;
11
34
  logoAlt?: string;
12
35
  }
13
- declare function TopBar({ appName, logoLink, documentationLink, documentationName, userMenu, darkMode, logoPath, logoAlt, }: TopBarProps): react_jsx_runtime.JSX.Element;
36
+ /**
37
+ * `Dark mode usage`
38
+ *
39
+ * To use the Topbar component in dark mode, you need to wrap it in the `ThemeProvider` from `@equinor/cpl-theme-react`
40
+ * and set the theme to 'dark'.
41
+ */
42
+ declare function TopBar({ appName, logoLink, sideMenuOpen, setSideMenuOpen, menuButton, feedbackLink, documentationLink, documentationName, userMenu, logoPath, logoAlt, }: TopBarProps): react_jsx_runtime.JSX.Element;
43
+ declare const StyledLink: styled_components_dist_types.IStyledComponentBase<"web", styled_components.FastOmit<react.DetailedHTMLProps<react.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, never>> & string;
14
44
 
15
45
  interface UserMenuProps {
16
46
  logout: string | (() => void);
@@ -18,10 +48,9 @@ interface UserMenuProps {
18
48
  name: string;
19
49
  email: string;
20
50
  };
21
- darkMode?: boolean;
22
51
  settingsLink?: string;
23
52
  children?: React.ReactNode;
24
53
  }
25
- declare function UserMenu({ user, logout, darkMode, settingsLink, children, }: UserMenuProps): react_jsx_runtime.JSX.Element;
54
+ declare function UserMenu({ user, logout, settingsLink, children, }: UserMenuProps): react_jsx_runtime.JSX.Element;
26
55
 
27
- export { TopBar, UserMenu };
56
+ export { FeedbackLink, StyledLink, TopBar, UserMenu };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,46 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as styled_components_dist_types from 'styled-components/dist/types';
3
+ import * as styled_components from 'styled-components';
4
+ import * as react from 'react';
5
+ import { ReactNode } from 'react';
6
+
7
+ interface FeedbackLinkProps {
8
+ link: string;
9
+ subject: string;
10
+ body: string;
11
+ }
12
+ /**
13
+ * `FeedbackLink`
14
+ * component renders a link that opens the user's email client
15
+ * with pre-filled subject and body for feedback. The email link should be the link to a Teams channel.
16
+ */
17
+ declare function FeedbackLink({ link, subject, body }: FeedbackLinkProps): react_jsx_runtime.JSX.Element;
2
18
 
3
19
  interface TopBarProps {
4
20
  appName: string;
5
21
  logoLink: string;
6
- documentationLink: string;
22
+ sideMenuOpen?: boolean;
23
+ setSideMenuOpen?: (open: boolean) => void;
24
+ /**
25
+ * optional custom button component to trigger the side menu
26
+ * If provided, it will be rendered instead of the default menu button.
27
+ */
28
+ menuButton?: (onClick: () => void) => ReactNode;
29
+ documentationLink?: string;
7
30
  documentationName?: string;
31
+ feedbackLink?: React.ReactNode;
8
32
  userMenu?: React.ReactNode;
9
- darkMode?: boolean;
10
33
  logoPath?: string;
11
34
  logoAlt?: string;
12
35
  }
13
- declare function TopBar({ appName, logoLink, documentationLink, documentationName, userMenu, darkMode, logoPath, logoAlt, }: TopBarProps): react_jsx_runtime.JSX.Element;
36
+ /**
37
+ * `Dark mode usage`
38
+ *
39
+ * To use the Topbar component in dark mode, you need to wrap it in the `ThemeProvider` from `@equinor/cpl-theme-react`
40
+ * and set the theme to 'dark'.
41
+ */
42
+ declare function TopBar({ appName, logoLink, sideMenuOpen, setSideMenuOpen, menuButton, feedbackLink, documentationLink, documentationName, userMenu, logoPath, logoAlt, }: TopBarProps): react_jsx_runtime.JSX.Element;
43
+ declare const StyledLink: styled_components_dist_types.IStyledComponentBase<"web", styled_components.FastOmit<react.DetailedHTMLProps<react.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, never>> & string;
14
44
 
15
45
  interface UserMenuProps {
16
46
  logout: string | (() => void);
@@ -18,10 +48,9 @@ interface UserMenuProps {
18
48
  name: string;
19
49
  email: string;
20
50
  };
21
- darkMode?: boolean;
22
51
  settingsLink?: string;
23
52
  children?: React.ReactNode;
24
53
  }
25
- declare function UserMenu({ user, logout, darkMode, settingsLink, children, }: UserMenuProps): react_jsx_runtime.JSX.Element;
54
+ declare function UserMenu({ user, logout, settingsLink, children, }: UserMenuProps): react_jsx_runtime.JSX.Element;
26
55
 
27
- export { TopBar, UserMenu };
56
+ export { FeedbackLink, StyledLink, TopBar, UserMenu };
package/dist/index.js CHANGED
@@ -30,39 +30,61 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ FeedbackLink: () => FeedbackLink,
34
+ StyledLink: () => StyledLink,
33
35
  TopBar: () => TopBar,
34
36
  UserMenu: () => UserMenu
35
37
  });
36
38
  module.exports = __toCommonJS(index_exports);
37
39
 
40
+ // src/FeedbackLink/FeedbackLink.tsx
41
+ var import_eds_core_react2 = require("@equinor/eds-core-react");
42
+ var import_eds_icons2 = require("@equinor/eds-icons");
43
+
38
44
  // src/TopBar/TopBar.tsx
39
45
  var import_eds_core_react = require("@equinor/eds-core-react");
40
46
  var import_eds_icons = require("@equinor/eds-icons");
41
- var import_styled_components = __toESM(require("styled-components"));
42
47
  var import_eds_tokens = require("@equinor/eds-tokens");
48
+ var import_styled_components = __toESM(require("styled-components"));
43
49
  var import_jsx_runtime = require("react/jsx-runtime");
44
50
  function TopBar({
45
51
  appName,
46
52
  logoLink,
53
+ sideMenuOpen,
54
+ setSideMenuOpen,
55
+ menuButton,
56
+ feedbackLink,
47
57
  documentationLink,
48
58
  documentationName = "Documentation",
49
59
  userMenu,
50
- darkMode = false,
51
60
  logoPath = ".",
52
61
  logoAlt = "logo"
53
62
  }) {
54
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledEDSTopBar, { $darkMode: darkMode, children: [
55
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.TopBar.Header, { style: { padding: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AppNameContainer, { children: [
56
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: logoPath, alt: logoAlt, height: 24, width: 22 }) }),
57
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: logoLink, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledTypography, { $darkMode: darkMode, children: appName }) })
58
- ] }) }),
59
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_eds_core_react.TopBar.Actions, { children: [
60
- documentationLink && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DocumentationDiv, { $darkMode: darkMode, children: [
61
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: documentationLink, children: documentationName }),
63
+ const hasSideMenu = setSideMenuOpen && sideMenuOpen !== void 0;
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledEDSTopBar, { children: [
65
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_eds_core_react.TopBar.Header, { style: { padding: 0 }, children: [
66
+ hasSideMenu && (menuButton ? menuButton(() => setSideMenuOpen(!sideMenuOpen)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
67
+ import_eds_core_react.Button,
68
+ {
69
+ variant: "ghost_icon",
70
+ "aria-label": "menu action",
71
+ onClick: () => setSideMenuOpen(!sideMenuOpen),
72
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.Icon, { data: import_eds_icons.menu, size: 24 })
73
+ }
74
+ )),
75
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AppNameContainer, { children: [
76
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: logoPath, alt: logoAlt, height: 24, width: 22 }) }),
77
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: logoLink, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledTypography, { children: appName }) })
78
+ ] })
79
+ ] }),
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.TopBar.Actions, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(LinkContainer, { children: [
81
+ feedbackLink && feedbackLink,
82
+ documentationLink && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledLink, { href: documentationLink, children: [
83
+ documentationName,
62
84
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.Icon, { data: import_eds_icons.external_link, size: 16 })
63
85
  ] }),
64
86
  userMenu
65
- ] })
87
+ ] }) })
66
88
  ] });
67
89
  }
68
90
  var StyledEDSTopBar = (0, import_styled_components.default)(import_eds_core_react.TopBar)`
@@ -70,10 +92,8 @@ var StyledEDSTopBar = (0, import_styled_components.default)(import_eds_core_reac
70
92
  gap: 0;
71
93
  padding: 0px 20px;
72
94
  margin: 0px;
73
- ${({ $darkMode }) => $darkMode ? import_styled_components.css`
74
- background: ${import_eds_tokens.tokens.colors.interactive.table__cell__fill_resting.hex};
75
- color: #fff;
76
- ` : ""}
95
+ background: var(--background-default, rgba(255, 255, 255, 1));
96
+ color: var(--color-text);
77
97
  `;
78
98
  var AppNameContainer = import_styled_components.default.div`
79
99
  display: flex;
@@ -82,38 +102,51 @@ var AppNameContainer = import_styled_components.default.div`
82
102
  `;
83
103
  var StyledTypography = (0, import_styled_components.default)(import_eds_core_react.Typography)`
84
104
  font-weight: 300;
85
- ${({ $darkMode }) => $darkMode ? import_styled_components.css`
86
- color: #fff;
87
- ` : ""}
105
+ color: var(--color-text);
88
106
  `;
89
- var DocumentationDiv = import_styled_components.default.div`
107
+ var LinkContainer = import_styled_components.default.div`
108
+ display: flex;
109
+ align-items: center;
110
+ gap: ${import_eds_tokens.tokens.spacings.comfortable.large};
111
+ `;
112
+ var StyledLink = import_styled_components.default.a`
90
113
  text-decoration: none;
91
114
  display: flex;
115
+ align-items: center;
92
116
  gap: 0.3rem;
93
117
  font-weight: 300;
94
- a {
95
- text-decoration: none;
96
- color: inherit;
97
- }
98
- ${({ $darkMode }) => $darkMode ? import_styled_components.css`
99
- color: ${import_eds_tokens.tokens.colors.interactive.table__cell__fill_resting.hex};
100
- a {
101
- color: #fff;
102
- }
103
- ` : ""}
118
+
119
+ text-decoration: none;
120
+ color: var(--color-text);
104
121
  `;
105
122
 
123
+ // src/FeedbackLink/FeedbackLink.tsx
124
+ var import_jsx_runtime2 = require("react/jsx-runtime");
125
+ function FeedbackLink({ link, subject, body }) {
126
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
127
+ StyledLink,
128
+ {
129
+ href: `mailto:${link}?subject=${subject}&body=${body}`,
130
+ target: "_blank",
131
+ rel: "noreferrer",
132
+ children: [
133
+ "Feedback",
134
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_eds_core_react2.Icon, { data: import_eds_icons2.email, size: 16 })
135
+ ]
136
+ }
137
+ );
138
+ }
139
+
106
140
  // src/UserMenu/UserMenu.tsx
107
- var import_eds_core_react2 = require("@equinor/eds-core-react");
108
- var import_eds_icons2 = require("@equinor/eds-icons");
141
+ var import_eds_core_react3 = require("@equinor/eds-core-react");
142
+ var import_eds_icons3 = require("@equinor/eds-icons");
109
143
  var import_eds_tokens2 = require("@equinor/eds-tokens");
110
144
  var import_react = require("react");
111
145
  var import_styled_components2 = __toESM(require("styled-components"));
112
- var import_jsx_runtime2 = require("react/jsx-runtime");
146
+ var import_jsx_runtime3 = require("react/jsx-runtime");
113
147
  function UserMenu({
114
148
  user,
115
149
  logout,
116
- darkMode = false,
117
150
  settingsLink,
118
151
  children
119
152
  }) {
@@ -128,20 +161,20 @@ function UserMenu({
128
161
  };
129
162
  const LogOutMenuItem = () => {
130
163
  if (typeof logout === "string") {
131
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_eds_core_react2.Menu.Item, { as: "a", href: logout, className: "menu-item", id: "logout-button", children: [
132
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_eds_core_react2.Icon, { data: import_eds_icons2.log_out }),
133
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Log out" })
164
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_eds_core_react3.Menu.Item, { as: "a", href: logout, className: "menu-item", id: "logout-button", children: [
165
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_eds_core_react3.Icon, { data: import_eds_icons3.log_out }),
166
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Log out" })
134
167
  ] });
135
168
  } else {
136
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_eds_core_react2.Menu.Item, { as: "button", onClick: logout, className: "menu-item", id: "logout-button", children: [
137
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_eds_core_react2.Icon, { data: import_eds_icons2.log_out }),
138
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Log out" })
169
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_eds_core_react3.Menu.Item, { as: "button", onClick: logout, className: "menu-item", id: "logout-button", children: [
170
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_eds_core_react3.Icon, { data: import_eds_icons3.log_out }),
171
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Log out" })
139
172
  ] });
140
173
  }
141
174
  };
142
175
  const firstLetter = (_c = (_b = (_a = user == null ? void 0 : user.email) == null ? void 0 : _a[0]) == null ? void 0 : _b.toUpperCase()) != null ? _c : "-";
143
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
144
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
176
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
177
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
145
178
  StyledUserButton,
146
179
  {
147
180
  id: "user-button",
@@ -151,14 +184,12 @@ function UserMenu({
151
184
  "aria-expanded": isOpen,
152
185
  "aria-controls": "user-menu",
153
186
  onClick: () => isOpen ? closeMenu() : openMenu(),
154
- $darkMode: darkMode,
155
187
  children: firstLetter
156
188
  }
157
189
  ),
158
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
190
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
159
191
  MenuWrapper,
160
192
  {
161
- $darkMode: darkMode,
162
193
  id: "user-menu",
163
194
  "aria-labelledby": "user-button",
164
195
  open: isOpen,
@@ -166,16 +197,16 @@ function UserMenu({
166
197
  anchorEl,
167
198
  style: { padding: 0, paddingBottom: 2 },
168
199
  children: [
169
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(IconAndTextWrapper, { $darkMode: darkMode, children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LetterCircle, { $darkMode: darkMode, children: firstLetter }),
171
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
172
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: "bold", lineHeight: 0.9, marginBottom: 2 }, children: (_d = user == null ? void 0 : user.name) != null ? _d : "-" }),
173
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: (_e = user == null ? void 0 : user.email) != null ? _e : "-" })
200
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(IconAndTextWrapper, { children: [
201
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LetterCircle, { children: firstLetter }),
202
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
203
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: "bold", lineHeight: 0.9, marginBottom: 2 }, children: (_d = user == null ? void 0 : user.name) != null ? _d : "-" }),
204
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: (_e = user == null ? void 0 : user.email) != null ? _e : "-" })
174
205
  ] })
175
206
  ] }),
176
- settingsLink && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_eds_core_react2.Menu.Item, { as: "a", href: settingsLink, className: "menu-item", children: [
177
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_eds_core_react2.Icon, { data: import_eds_icons2.settings }),
178
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Settings" })
207
+ settingsLink && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_eds_core_react3.Menu.Item, { as: "a", href: settingsLink, className: "menu-item", children: [
208
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_eds_core_react3.Icon, { data: import_eds_icons3.settings }),
209
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Settings" })
179
210
  ] }),
180
211
  LogOutMenuItem(),
181
212
  children
@@ -184,7 +215,7 @@ function UserMenu({
184
215
  )
185
216
  ] });
186
217
  }
187
- var MenuWrapper = (0, import_styled_components2.default)(import_eds_core_react2.Menu)`
218
+ var MenuWrapper = (0, import_styled_components2.default)(import_eds_core_react3.Menu)`
188
219
  border-radius: ${import_eds_tokens2.tokens.shape.corners.borderRadius};
189
220
  margin-top: ${import_eds_tokens2.tokens.spacings.comfortable.small};
190
221
  margin-bottom: -${import_eds_tokens2.tokens.spacings.comfortable.small};
@@ -194,32 +225,28 @@ var MenuWrapper = (0, import_styled_components2.default)(import_eds_core_react2.
194
225
  padding-top: ${import_eds_tokens2.tokens.spacings.comfortable.small};
195
226
  width: 315px;
196
227
 
228
+ background: var(--ui-background-temporary-nav, #fff);
229
+ color: var(--color-text);
230
+
197
231
  .menu-item {
198
232
  align-items: center;
199
233
  display: flex;
200
234
  gap: ${import_eds_tokens2.tokens.spacings.comfortable.medium};
201
235
  opacity: 0.85;
202
236
  padding: ${import_eds_tokens2.tokens.spacings.comfortable.small} ${import_eds_tokens2.tokens.spacings.comfortable.large};
237
+
238
+ color: var(--color-text);
203
239
  svg {
204
240
  opacity: 0.7;
205
241
  }
206
242
  &:hover {
207
243
  opacity: 1;
244
+ background: var(--menu-item-hover-color);
208
245
  svg {
209
246
  opacity: 1;
210
247
  }
211
248
  }
212
249
  }
213
- ${({ $darkMode }) => $darkMode ? import_styled_components2.css`
214
- background: #3e4f5c; //TODO: get color from token in the future
215
- color: #fff;
216
- .menu-item {
217
- color: #fff;
218
- &:hover {
219
- background: #305c75;
220
- }
221
- }
222
- ` : ``}
223
250
  `;
224
251
  var LetterCircle = import_styled_components2.default.span`
225
252
  align-items: center;
@@ -230,28 +257,22 @@ var LetterCircle = import_styled_components2.default.span`
230
257
  height: 32px;
231
258
  justify-content: center;
232
259
  width: 32px;
233
- background-color: ${import_eds_tokens2.tokens.colors.interactive.primary__resting.hex};
234
- color: #fff;
235
- ${({ $darkMode }) => $darkMode ? import_styled_components2.css`
236
- background: ${import_eds_tokens2.tokens.colors.interactive.link_in_snackbars.hex};
237
- color: ${import_eds_tokens2.tokens.colors.interactive.table__cell__fill_resting.hex};
238
- ` : ``};
260
+ background-color: var(--interactive-focus-border, ${import_eds_tokens2.tokens.colors.interactive.primary__resting.hex} );
261
+ color: var(--color-text-inverse, #fff);
239
262
  `;
240
- var StyledUserButton = (0, import_styled_components2.default)(import_eds_core_react2.Button)`
263
+ var StyledUserButton = (0, import_styled_components2.default)(import_eds_core_react3.Button)`
241
264
  margin-left: 12px;
242
265
  font-weight: bold;
243
266
  width: 32px;
244
267
  height: 32px;
268
+ background: var(--interactive-focus-border, ${import_eds_tokens2.tokens.colors.interactive.primary__resting.hex});
269
+ color: var(--color-text-inverse, #fff);
245
270
 
246
- ${({ $darkMode }) => $darkMode && import_styled_components2.css`
247
- background: ${import_eds_tokens2.tokens.colors.interactive.link_in_snackbars.hex};
248
- color: ${import_eds_tokens2.tokens.colors.interactive.table__cell__fill_resting.hex};
249
- &:hover {
250
- background: #fff;
251
- }
252
- `}
271
+ &:hover {
272
+ background-color: var(--color-text, rgba(0, 79, 85, 1));
273
+ }
253
274
  `;
254
- var IconAndTextWrapper = (0, import_styled_components2.default)(import_eds_core_react2.Menu.Item)`
275
+ var IconAndTextWrapper = (0, import_styled_components2.default)(import_eds_core_react3.Menu.Item)`
255
276
  display: flex;
256
277
  gap: 12px;
257
278
  padding: 12px 20px;
@@ -266,6 +287,8 @@ var IconAndTextWrapper = (0, import_styled_components2.default)(import_eds_core_
266
287
  `;
267
288
  // Annotate the CommonJS export names for ESM import in node:
268
289
  0 && (module.exports = {
290
+ FeedbackLink,
291
+ StyledLink,
269
292
  TopBar,
270
293
  UserMenu
271
294
  });
package/dist/index.mjs CHANGED
@@ -1,31 +1,51 @@
1
+ // src/FeedbackLink/FeedbackLink.tsx
2
+ import { Icon as Icon2 } from "@equinor/eds-core-react";
3
+ import { email } from "@equinor/eds-icons";
4
+
1
5
  // src/TopBar/TopBar.tsx
2
- import { TopBar as EDSTopBar, Icon, Typography } from "@equinor/eds-core-react";
3
- import { external_link } from "@equinor/eds-icons";
4
- import styled, { css } from "styled-components";
6
+ import { Button, TopBar as EDSTopBar, Icon, Typography } from "@equinor/eds-core-react";
7
+ import { external_link, menu } from "@equinor/eds-icons";
5
8
  import { tokens } from "@equinor/eds-tokens";
9
+ import styled from "styled-components";
6
10
  import { jsx, jsxs } from "react/jsx-runtime";
7
11
  function TopBar({
8
12
  appName,
9
13
  logoLink,
14
+ sideMenuOpen,
15
+ setSideMenuOpen,
16
+ menuButton,
17
+ feedbackLink,
10
18
  documentationLink,
11
19
  documentationName = "Documentation",
12
20
  userMenu,
13
- darkMode = false,
14
21
  logoPath = ".",
15
22
  logoAlt = "logo"
16
23
  }) {
17
- return /* @__PURE__ */ jsxs(StyledEDSTopBar, { $darkMode: darkMode, children: [
18
- /* @__PURE__ */ jsx(EDSTopBar.Header, { style: { padding: 0 }, children: /* @__PURE__ */ jsxs(AppNameContainer, { children: [
19
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("img", { src: logoPath, alt: logoAlt, height: 24, width: 22 }) }),
20
- /* @__PURE__ */ jsx("a", { href: logoLink, children: /* @__PURE__ */ jsx(StyledTypography, { $darkMode: darkMode, children: appName }) })
21
- ] }) }),
22
- /* @__PURE__ */ jsxs(EDSTopBar.Actions, { children: [
23
- documentationLink && /* @__PURE__ */ jsxs(DocumentationDiv, { $darkMode: darkMode, children: [
24
- /* @__PURE__ */ jsx("a", { href: documentationLink, children: documentationName }),
24
+ const hasSideMenu = setSideMenuOpen && sideMenuOpen !== void 0;
25
+ return /* @__PURE__ */ jsxs(StyledEDSTopBar, { children: [
26
+ /* @__PURE__ */ jsxs(EDSTopBar.Header, { style: { padding: 0 }, children: [
27
+ hasSideMenu && (menuButton ? menuButton(() => setSideMenuOpen(!sideMenuOpen)) : /* @__PURE__ */ jsx(
28
+ Button,
29
+ {
30
+ variant: "ghost_icon",
31
+ "aria-label": "menu action",
32
+ onClick: () => setSideMenuOpen(!sideMenuOpen),
33
+ children: /* @__PURE__ */ jsx(Icon, { data: menu, size: 24 })
34
+ }
35
+ )),
36
+ /* @__PURE__ */ jsxs(AppNameContainer, { children: [
37
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("img", { src: logoPath, alt: logoAlt, height: 24, width: 22 }) }),
38
+ /* @__PURE__ */ jsx("a", { href: logoLink, children: /* @__PURE__ */ jsx(StyledTypography, { children: appName }) })
39
+ ] })
40
+ ] }),
41
+ /* @__PURE__ */ jsx(EDSTopBar.Actions, { children: /* @__PURE__ */ jsxs(LinkContainer, { children: [
42
+ feedbackLink && feedbackLink,
43
+ documentationLink && /* @__PURE__ */ jsxs(StyledLink, { href: documentationLink, children: [
44
+ documentationName,
25
45
  /* @__PURE__ */ jsx(Icon, { data: external_link, size: 16 })
26
46
  ] }),
27
47
  userMenu
28
- ] })
48
+ ] }) })
29
49
  ] });
30
50
  }
31
51
  var StyledEDSTopBar = styled(EDSTopBar)`
@@ -33,10 +53,8 @@ var StyledEDSTopBar = styled(EDSTopBar)`
33
53
  gap: 0;
34
54
  padding: 0px 20px;
35
55
  margin: 0px;
36
- ${({ $darkMode }) => $darkMode ? css`
37
- background: ${tokens.colors.interactive.table__cell__fill_resting.hex};
38
- color: #fff;
39
- ` : ""}
56
+ background: var(--background-default, rgba(255, 255, 255, 1));
57
+ color: var(--color-text);
40
58
  `;
41
59
  var AppNameContainer = styled.div`
42
60
  display: flex;
@@ -45,38 +63,51 @@ var AppNameContainer = styled.div`
45
63
  `;
46
64
  var StyledTypography = styled(Typography)`
47
65
  font-weight: 300;
48
- ${({ $darkMode }) => $darkMode ? css`
49
- color: #fff;
50
- ` : ""}
66
+ color: var(--color-text);
51
67
  `;
52
- var DocumentationDiv = styled.div`
68
+ var LinkContainer = styled.div`
69
+ display: flex;
70
+ align-items: center;
71
+ gap: ${tokens.spacings.comfortable.large};
72
+ `;
73
+ var StyledLink = styled.a`
53
74
  text-decoration: none;
54
75
  display: flex;
76
+ align-items: center;
55
77
  gap: 0.3rem;
56
78
  font-weight: 300;
57
- a {
58
- text-decoration: none;
59
- color: inherit;
60
- }
61
- ${({ $darkMode }) => $darkMode ? css`
62
- color: ${tokens.colors.interactive.table__cell__fill_resting.hex};
63
- a {
64
- color: #fff;
65
- }
66
- ` : ""}
79
+
80
+ text-decoration: none;
81
+ color: var(--color-text);
67
82
  `;
68
83
 
84
+ // src/FeedbackLink/FeedbackLink.tsx
85
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
86
+ function FeedbackLink({ link, subject, body }) {
87
+ return /* @__PURE__ */ jsxs2(
88
+ StyledLink,
89
+ {
90
+ href: `mailto:${link}?subject=${subject}&body=${body}`,
91
+ target: "_blank",
92
+ rel: "noreferrer",
93
+ children: [
94
+ "Feedback",
95
+ /* @__PURE__ */ jsx2(Icon2, { data: email, size: 16 })
96
+ ]
97
+ }
98
+ );
99
+ }
100
+
69
101
  // src/UserMenu/UserMenu.tsx
70
- import { Button, Icon as Icon2, Menu } from "@equinor/eds-core-react";
102
+ import { Button as Button2, Icon as Icon3, Menu } from "@equinor/eds-core-react";
71
103
  import { log_out, settings } from "@equinor/eds-icons";
72
104
  import { tokens as tokens2 } from "@equinor/eds-tokens";
73
105
  import { useState } from "react";
74
- import styled2, { css as css2 } from "styled-components";
75
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
106
+ import styled2 from "styled-components";
107
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
76
108
  function UserMenu({
77
109
  user,
78
110
  logout,
79
- darkMode = false,
80
111
  settingsLink,
81
112
  children
82
113
  }) {
@@ -91,20 +122,20 @@ function UserMenu({
91
122
  };
92
123
  const LogOutMenuItem = () => {
93
124
  if (typeof logout === "string") {
94
- return /* @__PURE__ */ jsxs2(Menu.Item, { as: "a", href: logout, className: "menu-item", id: "logout-button", children: [
95
- /* @__PURE__ */ jsx2(Icon2, { data: log_out }),
96
- /* @__PURE__ */ jsx2("span", { children: "Log out" })
125
+ return /* @__PURE__ */ jsxs3(Menu.Item, { as: "a", href: logout, className: "menu-item", id: "logout-button", children: [
126
+ /* @__PURE__ */ jsx3(Icon3, { data: log_out }),
127
+ /* @__PURE__ */ jsx3("span", { children: "Log out" })
97
128
  ] });
98
129
  } else {
99
- return /* @__PURE__ */ jsxs2(Menu.Item, { as: "button", onClick: logout, className: "menu-item", id: "logout-button", children: [
100
- /* @__PURE__ */ jsx2(Icon2, { data: log_out }),
101
- /* @__PURE__ */ jsx2("span", { children: "Log out" })
130
+ return /* @__PURE__ */ jsxs3(Menu.Item, { as: "button", onClick: logout, className: "menu-item", id: "logout-button", children: [
131
+ /* @__PURE__ */ jsx3(Icon3, { data: log_out }),
132
+ /* @__PURE__ */ jsx3("span", { children: "Log out" })
102
133
  ] });
103
134
  }
104
135
  };
105
136
  const firstLetter = (_c = (_b = (_a = user == null ? void 0 : user.email) == null ? void 0 : _a[0]) == null ? void 0 : _b.toUpperCase()) != null ? _c : "-";
106
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
107
- /* @__PURE__ */ jsx2(
137
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
138
+ /* @__PURE__ */ jsx3(
108
139
  StyledUserButton,
109
140
  {
110
141
  id: "user-button",
@@ -114,14 +145,12 @@ function UserMenu({
114
145
  "aria-expanded": isOpen,
115
146
  "aria-controls": "user-menu",
116
147
  onClick: () => isOpen ? closeMenu() : openMenu(),
117
- $darkMode: darkMode,
118
148
  children: firstLetter
119
149
  }
120
150
  ),
121
- /* @__PURE__ */ jsxs2(
151
+ /* @__PURE__ */ jsxs3(
122
152
  MenuWrapper,
123
153
  {
124
- $darkMode: darkMode,
125
154
  id: "user-menu",
126
155
  "aria-labelledby": "user-button",
127
156
  open: isOpen,
@@ -129,16 +158,16 @@ function UserMenu({
129
158
  anchorEl,
130
159
  style: { padding: 0, paddingBottom: 2 },
131
160
  children: [
132
- /* @__PURE__ */ jsxs2(IconAndTextWrapper, { $darkMode: darkMode, children: [
133
- /* @__PURE__ */ jsx2(LetterCircle, { $darkMode: darkMode, children: firstLetter }),
134
- isOpen && /* @__PURE__ */ jsxs2("div", { children: [
135
- /* @__PURE__ */ jsx2("div", { style: { fontWeight: "bold", lineHeight: 0.9, marginBottom: 2 }, children: (_d = user == null ? void 0 : user.name) != null ? _d : "-" }),
136
- /* @__PURE__ */ jsx2("div", { children: (_e = user == null ? void 0 : user.email) != null ? _e : "-" })
161
+ /* @__PURE__ */ jsxs3(IconAndTextWrapper, { children: [
162
+ /* @__PURE__ */ jsx3(LetterCircle, { children: firstLetter }),
163
+ isOpen && /* @__PURE__ */ jsxs3("div", { children: [
164
+ /* @__PURE__ */ jsx3("div", { style: { fontWeight: "bold", lineHeight: 0.9, marginBottom: 2 }, children: (_d = user == null ? void 0 : user.name) != null ? _d : "-" }),
165
+ /* @__PURE__ */ jsx3("div", { children: (_e = user == null ? void 0 : user.email) != null ? _e : "-" })
137
166
  ] })
138
167
  ] }),
139
- settingsLink && /* @__PURE__ */ jsxs2(Menu.Item, { as: "a", href: settingsLink, className: "menu-item", children: [
140
- /* @__PURE__ */ jsx2(Icon2, { data: settings }),
141
- /* @__PURE__ */ jsx2("span", { children: "Settings" })
168
+ settingsLink && /* @__PURE__ */ jsxs3(Menu.Item, { as: "a", href: settingsLink, className: "menu-item", children: [
169
+ /* @__PURE__ */ jsx3(Icon3, { data: settings }),
170
+ /* @__PURE__ */ jsx3("span", { children: "Settings" })
142
171
  ] }),
143
172
  LogOutMenuItem(),
144
173
  children
@@ -157,32 +186,28 @@ var MenuWrapper = styled2(Menu)`
157
186
  padding-top: ${tokens2.spacings.comfortable.small};
158
187
  width: 315px;
159
188
 
189
+ background: var(--ui-background-temporary-nav, #fff);
190
+ color: var(--color-text);
191
+
160
192
  .menu-item {
161
193
  align-items: center;
162
194
  display: flex;
163
195
  gap: ${tokens2.spacings.comfortable.medium};
164
196
  opacity: 0.85;
165
197
  padding: ${tokens2.spacings.comfortable.small} ${tokens2.spacings.comfortable.large};
198
+
199
+ color: var(--color-text);
166
200
  svg {
167
201
  opacity: 0.7;
168
202
  }
169
203
  &:hover {
170
204
  opacity: 1;
205
+ background: var(--menu-item-hover-color);
171
206
  svg {
172
207
  opacity: 1;
173
208
  }
174
209
  }
175
210
  }
176
- ${({ $darkMode }) => $darkMode ? css2`
177
- background: #3e4f5c; //TODO: get color from token in the future
178
- color: #fff;
179
- .menu-item {
180
- color: #fff;
181
- &:hover {
182
- background: #305c75;
183
- }
184
- }
185
- ` : ``}
186
211
  `;
187
212
  var LetterCircle = styled2.span`
188
213
  align-items: center;
@@ -193,26 +218,20 @@ var LetterCircle = styled2.span`
193
218
  height: 32px;
194
219
  justify-content: center;
195
220
  width: 32px;
196
- background-color: ${tokens2.colors.interactive.primary__resting.hex};
197
- color: #fff;
198
- ${({ $darkMode }) => $darkMode ? css2`
199
- background: ${tokens2.colors.interactive.link_in_snackbars.hex};
200
- color: ${tokens2.colors.interactive.table__cell__fill_resting.hex};
201
- ` : ``};
221
+ background-color: var(--interactive-focus-border, ${tokens2.colors.interactive.primary__resting.hex} );
222
+ color: var(--color-text-inverse, #fff);
202
223
  `;
203
- var StyledUserButton = styled2(Button)`
224
+ var StyledUserButton = styled2(Button2)`
204
225
  margin-left: 12px;
205
226
  font-weight: bold;
206
227
  width: 32px;
207
228
  height: 32px;
229
+ background: var(--interactive-focus-border, ${tokens2.colors.interactive.primary__resting.hex});
230
+ color: var(--color-text-inverse, #fff);
208
231
 
209
- ${({ $darkMode }) => $darkMode && css2`
210
- background: ${tokens2.colors.interactive.link_in_snackbars.hex};
211
- color: ${tokens2.colors.interactive.table__cell__fill_resting.hex};
212
- &:hover {
213
- background: #fff;
214
- }
215
- `}
232
+ &:hover {
233
+ background-color: var(--color-text, rgba(0, 79, 85, 1));
234
+ }
216
235
  `;
217
236
  var IconAndTextWrapper = styled2(Menu.Item)`
218
237
  display: flex;
@@ -228,6 +247,8 @@ var IconAndTextWrapper = styled2(Menu.Item)`
228
247
  }
229
248
  `;
230
249
  export {
250
+ FeedbackLink,
251
+ StyledLink,
231
252
  TopBar,
232
253
  UserMenu
233
254
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/cpl-top-bar-react",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -14,8 +14,7 @@
14
14
  },
15
15
  "devDependencies": {
16
16
  "@equinor/eds-core-react": "^0.42.5",
17
- "@storybook/react": "^8.5.2",
18
- "@storybook/test": "^8.5.2",
17
+ "@storybook/react": "^9.0.12",
19
18
  "@types/react": "^18.3.18",
20
19
  "@types/react-dom": "^18.3.5",
21
20
  "@types/styled-components": "^5.1.34",
@@ -24,8 +23,8 @@
24
23
  "react-dom": "^18.2.0",
25
24
  "styled-components": "^6.1.14",
26
25
  "tsup": "^8.3.6",
27
- "eslint-config-custom": "0.0.7",
28
- "tsconfig": "0.0.1"
26
+ "@equinor/cpl-eslint-config": "0.0.8",
27
+ "@equinor/cpl-typescript-config": "0.0.2"
29
28
  },
30
29
  "peerDependencies": {
31
30
  "@equinor/eds-core-react": ">=0.42.1",
@@ -40,6 +39,7 @@
40
39
  "build": "tsup src/index.ts --format esm,cjs --dts --external react",
41
40
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
42
41
  "dev": "tsup src/index.ts --format esm,cjs --watch --dts --external react",
43
- "lint": "TIMING=1 eslint . --fix"
42
+ "lint": "TIMING=1 eslint . --fix",
43
+ "typecheck": "tsc --noEmit"
44
44
  }
45
45
  }