@ilo-org/react 0.16.4 → 0.17.1
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/lib/cjs/components/Breadcrumb/Breadcrumb.js +171 -19
- package/lib/cjs/components/ContextMenu/ContextMenu.js +4 -4
- package/lib/cjs/components/ContextMenu/index.js +1 -1
- package/lib/cjs/components/SocialMedia/SocialMedia.js +3 -2
- package/lib/cjs/components/SocialMedia/index.js +4 -3
- package/lib/esm/components/Breadcrumb/Breadcrumb.js +173 -21
- package/lib/esm/components/ContextMenu/ContextMenu.js +4 -4
- package/lib/esm/components/ContextMenu/index.js +1 -1
- package/lib/esm/components/SocialMedia/SocialMedia.js +3 -2
- package/lib/esm/components/SocialMedia/index.js +4 -3
- package/lib/styles/components/socialmedia.css +1 -1
- package/lib/styles/index.css +1 -1
- package/lib/styles/monorepo.css +1 -1
- package/lib/types/react/src/components/Breadcrumb/Breadcrumb.props.d.ts +25 -4
- package/lib/types/react/src/components/ContextMenu/ContextMenu.d.ts +2 -2
- package/lib/types/react/src/components/SocialMedia/SocialMedia.props.d.ts +4 -0
- package/lib/types/react/src/types/index.d.ts +1 -1
- package/package.json +4 -4
|
@@ -8,30 +8,182 @@ var components_ContextMenu_ContextMenu = require('../ContextMenu/ContextMenu.js'
|
|
|
8
8
|
require('tslib');
|
|
9
9
|
require('../../GlobalCtx-10114bdd.js');
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const BreadcrumbItem = ({ url, label, className, labelShown = true, }) => {
|
|
12
12
|
const { prefix } = hooks_useGlobalSettings();
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
};
|
|
13
|
+
const baseClass = `${prefix}--breadcrumb--item`;
|
|
14
|
+
const linkClass = `${prefix}--breadcrumb--link`;
|
|
15
|
+
const labelClass = `${linkClass}--label`;
|
|
16
|
+
const breadcrumbLinkClass = classNames(baseClass, className);
|
|
17
|
+
return (jsxRuntime.jsx("li", Object.assign({ className: breadcrumbLinkClass }, { children: labelShown ? (jsxRuntime.jsx("a", Object.assign({ className: linkClass, href: url }, { children: jsxRuntime.jsx("span", Object.assign({ className: labelClass }, { children: label })) }))) : (jsxRuntime.jsx("a", { "aria-label": label, className: linkClass, href: url })) })));
|
|
18
|
+
};
|
|
19
|
+
const Breadcrumb = ({ className, links, buttonLabel }) => {
|
|
20
|
+
const { prefix } = hooks_useGlobalSettings();
|
|
21
|
+
// State
|
|
22
|
+
const [isCtxMenuOpen, setIsCtxMenuOpen] = React.useState(false);
|
|
23
|
+
const [ctxMenuPosition, setCtxMenuPosition] = React.useState({
|
|
24
|
+
start: 0,
|
|
25
|
+
top: 0,
|
|
26
|
+
});
|
|
27
|
+
const [isMenuCollapsed, setIsMenuCollapsed] = React.useState(false);
|
|
28
|
+
// Refs
|
|
29
|
+
const breadcrumbsRef = React.useRef(null);
|
|
30
|
+
const breadcrumbsWidth = React.useRef(0);
|
|
31
|
+
const buttonRef = React.useRef(null);
|
|
32
|
+
const ctxMenuRef = React.useRef(null);
|
|
33
|
+
// Shortcuts to classnames
|
|
34
|
+
const baseClass = `${prefix}--breadcrumb`;
|
|
35
|
+
const innerClass = `${baseClass}--inner`;
|
|
36
|
+
const itemsClass = `${baseClass}--items`;
|
|
37
|
+
const itemClass = `${baseClass}--item`;
|
|
38
|
+
const itemFirstClass = `${itemClass}__first`;
|
|
39
|
+
const contextClass = `${baseClass}--context`;
|
|
40
|
+
const contextCollapsedClass = `${contextClass}__collapse`;
|
|
41
|
+
const contextId = `${baseClass}--menu`;
|
|
42
|
+
const buttonClass = `${contextClass}--button`;
|
|
43
|
+
// Dynamic classnames
|
|
44
|
+
const breadcrumbClass = classNames(baseClass, className);
|
|
45
|
+
const contextItemsClass = classNames(contextClass, {
|
|
46
|
+
[contextCollapsedClass]: isMenuCollapsed,
|
|
47
|
+
});
|
|
48
|
+
const contextMenuClass = classNames(`${contextClass}--menu`, {
|
|
49
|
+
[`${contextClass}--menu__visible`]: isCtxMenuOpen,
|
|
50
|
+
});
|
|
51
|
+
// Handlers
|
|
52
|
+
function handleButtonClick() {
|
|
53
|
+
setIsCtxMenuOpen(!isCtxMenuOpen);
|
|
54
|
+
}
|
|
55
|
+
const collapseMenu = React.useCallback((collapse) => {
|
|
56
|
+
if (collapse && !isMenuCollapsed) {
|
|
57
|
+
setIsMenuCollapsed(true);
|
|
58
|
+
}
|
|
59
|
+
if (!collapse && isMenuCollapsed) {
|
|
60
|
+
setIsMenuCollapsed(false);
|
|
61
|
+
}
|
|
62
|
+
}, [isMenuCollapsed]);
|
|
63
|
+
// Get the width of the breadcrumbs and store it in a ref
|
|
64
|
+
React.useLayoutEffect(() => {
|
|
65
|
+
const breadcrumbs = breadcrumbsRef === null || breadcrumbsRef === void 0 ? void 0 : breadcrumbsRef.current;
|
|
66
|
+
if (!breadcrumbs || !window || !document) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
breadcrumbsWidth.current = breadcrumbs.offsetWidth;
|
|
70
|
+
}, []);
|
|
71
|
+
// Collapse or uncollapse the Context Menu depending on body width
|
|
72
|
+
React.useLayoutEffect(() => {
|
|
73
|
+
const breadcrumbs = breadcrumbsRef === null || breadcrumbsRef === void 0 ? void 0 : breadcrumbsRef.current;
|
|
74
|
+
if (!breadcrumbs || !window || !document) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const observer = new ResizeObserver((entries) => {
|
|
78
|
+
const bodyWidth = entries[0].contentRect.width;
|
|
79
|
+
if (breadcrumbsWidth.current >= bodyWidth / 1.5) {
|
|
80
|
+
collapseMenu(true);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
collapseMenu(false);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
observer.observe(document.body);
|
|
87
|
+
return () => {
|
|
88
|
+
observer.disconnect();
|
|
89
|
+
};
|
|
90
|
+
}, [collapseMenu]);
|
|
91
|
+
// Position the Context Menu right below the button
|
|
92
|
+
React.useLayoutEffect(() => {
|
|
93
|
+
if (!buttonRef.current || !ctxMenuRef.current) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (isMenuCollapsed && isCtxMenuOpen) {
|
|
97
|
+
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
98
|
+
const buttonCenterX = buttonRect.left + buttonRect.width / 2;
|
|
99
|
+
const contextMenuWidth = ctxMenuRef.current.offsetWidth;
|
|
100
|
+
const navStart = buttonCenterX - contextMenuWidth / 2;
|
|
101
|
+
const navTop = buttonRect.bottom + 16;
|
|
102
|
+
setCtxMenuPosition({ start: navStart, top: navTop });
|
|
103
|
+
}
|
|
104
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
105
|
+
// If the ContextMenu is open, close it if the user clicks outside of it
|
|
18
106
|
React.useEffect(() => {
|
|
19
|
-
|
|
20
|
-
|
|
107
|
+
function handleClickOutside(event) {
|
|
108
|
+
if (isCtxMenuOpen &&
|
|
109
|
+
ctxMenuRef.current &&
|
|
110
|
+
!ctxMenuRef.current.contains(event.target) &&
|
|
111
|
+
buttonRef.current &&
|
|
112
|
+
!buttonRef.current.contains(event.target)) {
|
|
113
|
+
setIsCtxMenuOpen(false);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
21
117
|
return () => {
|
|
22
|
-
|
|
118
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
23
119
|
};
|
|
24
|
-
}, []);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
120
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
121
|
+
// Close the context menu if the breadcrumbs should un-collapse
|
|
122
|
+
React.useEffect(() => {
|
|
123
|
+
if (isCtxMenuOpen && !isMenuCollapsed) {
|
|
124
|
+
setIsCtxMenuOpen(false);
|
|
125
|
+
}
|
|
126
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
127
|
+
// handle tab navigation when the context menu is open
|
|
128
|
+
React.useEffect(() => {
|
|
129
|
+
if (!buttonRef.current || !ctxMenuRef.current) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
function handleKeyDown(event) {
|
|
133
|
+
var _a, _b, _c, _d;
|
|
134
|
+
if (!isCtxMenuOpen || !isMenuCollapsed) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (event.key === "Tab") {
|
|
138
|
+
const links = (_a = ctxMenuRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("a");
|
|
139
|
+
const lastBreadCrumb = (_c = (_b = breadcrumbsRef.current) === null || _b === void 0 ? void 0 : _b.lastElementChild) === null || _c === void 0 ? void 0 : _c.querySelector("a");
|
|
140
|
+
if (!links || !lastBreadCrumb) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const firstLink = links[0];
|
|
144
|
+
const lastLink = links[links.length - 1];
|
|
145
|
+
// If the user is tabbing...
|
|
146
|
+
if (!event.shiftKey) {
|
|
147
|
+
// If the context button is focused then the next focusable item
|
|
148
|
+
// should be the first item in the context menu
|
|
149
|
+
if (document.activeElement === buttonRef.current) {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
firstLink.focus();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// If the last context item is focused then the focus should go to
|
|
155
|
+
// the last breadcrumb item
|
|
156
|
+
if (document.activeElement === lastLink) {
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
lastBreadCrumb.focus();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// If the user is shift-tabbing...
|
|
162
|
+
if (event.shiftKey) {
|
|
163
|
+
// If the first item is focused then the focus should go back to the context button
|
|
164
|
+
if (event.shiftKey && document.activeElement === firstLink) {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
(_d = buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current) === null || _d === void 0 ? void 0 : _d.focus();
|
|
167
|
+
}
|
|
168
|
+
// If the focus is on the last breadcrumb item then the focus should go
|
|
169
|
+
// to the last item in the context menu
|
|
170
|
+
if (event.shiftKey && document.activeElement === lastBreadCrumb) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
lastLink.focus();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
178
|
+
return () => {
|
|
179
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
// Separate out the links into first, context and last
|
|
183
|
+
const firstLink = links[0];
|
|
184
|
+
const contextLinks = links.slice(1, links.length - 1);
|
|
31
185
|
const lastLink = links[links.length - 1];
|
|
32
|
-
|
|
33
|
-
return (jsxRuntime.jsx("nav", Object.assign({ className: `${BreadcrumbClasses} ${showContext ? " contextmenu" : ""}` }, { children: jsxRuntime.jsxs("ol", Object.assign({ className: `${baseClass}--items` }, { children: [jsxRuntime.jsx("li", Object.assign({ className: `${baseClass}--item home` }, { children: jsxRuntime.jsx("a", Object.assign({ className: `${baseClass}--link`, href: home.url }, { children: jsxRuntime.jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: home.label })) })) })), jsxRuntime.jsx("li", Object.assign({ className: `${baseClass}--item--context`, onClick: handleContextMenuToggle }, { children: jsxRuntime.jsxs("ul", Object.assign({ className: `${baseClass}--items context--menu ${toggleMenuOpen ? " open" : ""}` }, { children: [showContext && jsxRuntime.jsx(components_ContextMenu_ContextMenu, { links: menuLinks }), !showContext &&
|
|
34
|
-
menuLinks.map((link, index) => (jsxRuntime.jsx("li", Object.assign({ className: `${baseClass}--item` }, { children: jsxRuntime.jsx("a", Object.assign({ href: link.url, className: `${baseClass}--link` }, { children: jsxRuntime.jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: link.label })) })) }), index)))] })) })), jsxRuntime.jsx("li", Object.assign({ className: `${baseClass}--item final` }, { children: jsxRuntime.jsx("a", Object.assign({ className: `${baseClass}--link`, href: lastLink.url }, { children: jsxRuntime.jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: lastLink.label })) })) }))] })) })));
|
|
186
|
+
return (jsxRuntime.jsxs("nav", Object.assign({ className: breadcrumbClass }, { children: [jsxRuntime.jsx("div", Object.assign({ className: innerClass }, { children: jsxRuntime.jsxs("ol", Object.assign({ className: itemsClass, ref: breadcrumbsRef }, { children: [jsxRuntime.jsx(BreadcrumbItem, { url: firstLink.url, label: firstLink.label, labelShown: false, className: itemFirstClass }), contextLinks && contextLinks.length > 0 ? (jsxRuntime.jsxs("li", Object.assign({ className: contextItemsClass }, { children: [jsxRuntime.jsx("ol", Object.assign({ className: itemsClass }, { children: contextLinks.map((contextLink, i) => (jsxRuntime.jsx(BreadcrumbItem, { url: contextLink.url, label: contextLink.label }, i))) })), jsxRuntime.jsx("button", { "aria-label": buttonLabel, "aria-expanded": isCtxMenuOpen, "aria-controls": contextId, className: buttonClass, onClick: handleButtonClick, ref: buttonRef })] }))) : null, lastLink && (jsxRuntime.jsx(BreadcrumbItem, { url: lastLink.url, label: lastLink.label }))] })) })), jsxRuntime.jsx("div", Object.assign({ className: contextMenuClass, id: contextId, hidden: !isCtxMenuOpen, style: { left: ctxMenuPosition.start, top: ctxMenuPosition.top } }, { children: jsxRuntime.jsx(components_ContextMenu_ContextMenu, { links: contextLinks, ref: ctxMenuRef }) }))] })));
|
|
35
187
|
};
|
|
36
188
|
|
|
37
189
|
module.exports = Breadcrumb;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
4
5
|
var classNames = require('classnames');
|
|
5
6
|
var hooks_useGlobalSettings = require('../../hooks/useGlobalSettings.js');
|
|
6
7
|
require('tslib');
|
|
7
|
-
require('react');
|
|
8
8
|
require('../../GlobalCtx-10114bdd.js');
|
|
9
9
|
|
|
10
|
-
const ContextMenu = ({ className, links }) => {
|
|
10
|
+
const ContextMenu = React.forwardRef(({ className, links }, ref) => {
|
|
11
11
|
const { prefix } = hooks_useGlobalSettings();
|
|
12
12
|
const baseClass = `${prefix}--context-menu`;
|
|
13
13
|
const contextMenuClasses = classNames(className, {
|
|
14
14
|
[baseClass]: true,
|
|
15
15
|
});
|
|
16
|
-
return (jsxRuntime.jsx("
|
|
16
|
+
return (jsxRuntime.jsx("ol", Object.assign({ className: contextMenuClasses, ref: ref }, { children: links &&
|
|
17
17
|
links.map((link, i) => (jsxRuntime.jsx("li", Object.assign({ className: `${baseClass}--item ${link.endsection ? "endsection" : ""}` }, { children: jsxRuntime.jsx("a", Object.assign({ href: link.url, className: `${baseClass}--link` }, { children: jsxRuntime.jsx("span", Object.assign({ className: `${baseClass}--label` }, { children: link.label })) })) }), `${baseClass}--item-${i}`))) })));
|
|
18
|
-
};
|
|
18
|
+
});
|
|
19
19
|
|
|
20
20
|
module.exports = ContextMenu;
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var components_ContextMenu_ContextMenu = require('./ContextMenu.js');
|
|
4
4
|
require('react/jsx-runtime');
|
|
5
|
+
require('react');
|
|
5
6
|
require('classnames');
|
|
6
7
|
require('../../hooks/useGlobalSettings.js');
|
|
7
8
|
require('tslib');
|
|
8
|
-
require('react');
|
|
9
9
|
require('../../GlobalCtx-10114bdd.js');
|
|
10
10
|
|
|
11
11
|
|
|
@@ -7,7 +7,7 @@ require('tslib');
|
|
|
7
7
|
require('react');
|
|
8
8
|
require('../../GlobalCtx-10114bdd.js');
|
|
9
9
|
|
|
10
|
-
const SocialMedia = ({ className, theme = "light", justify = "start", headline, icons, }) => {
|
|
10
|
+
const SocialMedia = ({ className, theme = "light", justify = "start", headline, icons, iconSize = "normal", }) => {
|
|
11
11
|
const { prefix } = hooks_useGlobalSettings();
|
|
12
12
|
// Classes to be applied to the outer element
|
|
13
13
|
const baseClass = `${prefix}--social-media`;
|
|
@@ -19,7 +19,8 @@ const SocialMedia = ({ className, theme = "light", justify = "start", headline,
|
|
|
19
19
|
const listClass = `${baseClass}--list`;
|
|
20
20
|
const listItemClass = `${listClass}--item`;
|
|
21
21
|
const iconClass = `${listItemClass}--icon`;
|
|
22
|
-
|
|
22
|
+
const iconSizeClass = `${listItemClass}--icon__${iconSize}`;
|
|
23
|
+
return (jsxRuntime.jsxs("div", Object.assign({ className: classes }, { children: [headline && jsxRuntime.jsx("h5", Object.assign({ className: headlineClass }, { children: headline })), jsxRuntime.jsx("ul", Object.assign({ className: listClass }, { children: icons.map((item) => (jsxRuntime.jsx("li", Object.assign({ className: listItemClass }, { children: jsxRuntime.jsx("a", Object.assign({ title: item.label, className: classNames(iconClass, iconSizeClass, `${iconClass}__${item.icon}`), href: item.url }, { children: item.label })) })))) }))] })));
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
module.exports = SocialMedia;
|
|
@@ -12,6 +12,7 @@ const defaultArgs = {
|
|
|
12
12
|
headline: "Follow us on social media",
|
|
13
13
|
theme: "light",
|
|
14
14
|
justify: "start",
|
|
15
|
+
iconSize: "normal",
|
|
15
16
|
icons: [
|
|
16
17
|
{
|
|
17
18
|
icon: "facebook",
|
|
@@ -19,9 +20,9 @@ const defaultArgs = {
|
|
|
19
20
|
label: "Facebook",
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
|
-
icon: "
|
|
23
|
-
url: "https://
|
|
24
|
-
label: "
|
|
23
|
+
icon: "x",
|
|
24
|
+
url: "https://x.com/ilo",
|
|
25
|
+
label: "x",
|
|
25
26
|
},
|
|
26
27
|
{
|
|
27
28
|
icon: "instagram",
|
|
@@ -1,35 +1,187 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useRef, useCallback, useLayoutEffect, useEffect } from 'react';
|
|
3
3
|
import useGlobalSettings from '../../hooks/useGlobalSettings.js';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import ContextMenu from '../ContextMenu/ContextMenu.js';
|
|
6
6
|
import 'tslib';
|
|
7
7
|
import '../../GlobalCtx-7fb23cfa.js';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const BreadcrumbItem = ({ url, label, className, labelShown = true, }) => {
|
|
10
10
|
const { prefix } = useGlobalSettings();
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
};
|
|
11
|
+
const baseClass = `${prefix}--breadcrumb--item`;
|
|
12
|
+
const linkClass = `${prefix}--breadcrumb--link`;
|
|
13
|
+
const labelClass = `${linkClass}--label`;
|
|
14
|
+
const breadcrumbLinkClass = classNames(baseClass, className);
|
|
15
|
+
return (jsx("li", Object.assign({ className: breadcrumbLinkClass }, { children: labelShown ? (jsx("a", Object.assign({ className: linkClass, href: url }, { children: jsx("span", Object.assign({ className: labelClass }, { children: label })) }))) : (jsx("a", { "aria-label": label, className: linkClass, href: url })) })));
|
|
16
|
+
};
|
|
17
|
+
const Breadcrumb = ({ className, links, buttonLabel }) => {
|
|
18
|
+
const { prefix } = useGlobalSettings();
|
|
19
|
+
// State
|
|
20
|
+
const [isCtxMenuOpen, setIsCtxMenuOpen] = useState(false);
|
|
21
|
+
const [ctxMenuPosition, setCtxMenuPosition] = useState({
|
|
22
|
+
start: 0,
|
|
23
|
+
top: 0,
|
|
24
|
+
});
|
|
25
|
+
const [isMenuCollapsed, setIsMenuCollapsed] = useState(false);
|
|
26
|
+
// Refs
|
|
27
|
+
const breadcrumbsRef = useRef(null);
|
|
28
|
+
const breadcrumbsWidth = useRef(0);
|
|
29
|
+
const buttonRef = useRef(null);
|
|
30
|
+
const ctxMenuRef = useRef(null);
|
|
31
|
+
// Shortcuts to classnames
|
|
32
|
+
const baseClass = `${prefix}--breadcrumb`;
|
|
33
|
+
const innerClass = `${baseClass}--inner`;
|
|
34
|
+
const itemsClass = `${baseClass}--items`;
|
|
35
|
+
const itemClass = `${baseClass}--item`;
|
|
36
|
+
const itemFirstClass = `${itemClass}__first`;
|
|
37
|
+
const contextClass = `${baseClass}--context`;
|
|
38
|
+
const contextCollapsedClass = `${contextClass}__collapse`;
|
|
39
|
+
const contextId = `${baseClass}--menu`;
|
|
40
|
+
const buttonClass = `${contextClass}--button`;
|
|
41
|
+
// Dynamic classnames
|
|
42
|
+
const breadcrumbClass = classNames(baseClass, className);
|
|
43
|
+
const contextItemsClass = classNames(contextClass, {
|
|
44
|
+
[contextCollapsedClass]: isMenuCollapsed,
|
|
45
|
+
});
|
|
46
|
+
const contextMenuClass = classNames(`${contextClass}--menu`, {
|
|
47
|
+
[`${contextClass}--menu__visible`]: isCtxMenuOpen,
|
|
48
|
+
});
|
|
49
|
+
// Handlers
|
|
50
|
+
function handleButtonClick() {
|
|
51
|
+
setIsCtxMenuOpen(!isCtxMenuOpen);
|
|
52
|
+
}
|
|
53
|
+
const collapseMenu = useCallback((collapse) => {
|
|
54
|
+
if (collapse && !isMenuCollapsed) {
|
|
55
|
+
setIsMenuCollapsed(true);
|
|
56
|
+
}
|
|
57
|
+
if (!collapse && isMenuCollapsed) {
|
|
58
|
+
setIsMenuCollapsed(false);
|
|
59
|
+
}
|
|
60
|
+
}, [isMenuCollapsed]);
|
|
61
|
+
// Get the width of the breadcrumbs and store it in a ref
|
|
62
|
+
useLayoutEffect(() => {
|
|
63
|
+
const breadcrumbs = breadcrumbsRef === null || breadcrumbsRef === void 0 ? void 0 : breadcrumbsRef.current;
|
|
64
|
+
if (!breadcrumbs || !window || !document) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
breadcrumbsWidth.current = breadcrumbs.offsetWidth;
|
|
68
|
+
}, []);
|
|
69
|
+
// Collapse or uncollapse the Context Menu depending on body width
|
|
70
|
+
useLayoutEffect(() => {
|
|
71
|
+
const breadcrumbs = breadcrumbsRef === null || breadcrumbsRef === void 0 ? void 0 : breadcrumbsRef.current;
|
|
72
|
+
if (!breadcrumbs || !window || !document) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const observer = new ResizeObserver((entries) => {
|
|
76
|
+
const bodyWidth = entries[0].contentRect.width;
|
|
77
|
+
if (breadcrumbsWidth.current >= bodyWidth / 1.5) {
|
|
78
|
+
collapseMenu(true);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
collapseMenu(false);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
observer.observe(document.body);
|
|
85
|
+
return () => {
|
|
86
|
+
observer.disconnect();
|
|
87
|
+
};
|
|
88
|
+
}, [collapseMenu]);
|
|
89
|
+
// Position the Context Menu right below the button
|
|
90
|
+
useLayoutEffect(() => {
|
|
91
|
+
if (!buttonRef.current || !ctxMenuRef.current) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (isMenuCollapsed && isCtxMenuOpen) {
|
|
95
|
+
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
96
|
+
const buttonCenterX = buttonRect.left + buttonRect.width / 2;
|
|
97
|
+
const contextMenuWidth = ctxMenuRef.current.offsetWidth;
|
|
98
|
+
const navStart = buttonCenterX - contextMenuWidth / 2;
|
|
99
|
+
const navTop = buttonRect.bottom + 16;
|
|
100
|
+
setCtxMenuPosition({ start: navStart, top: navTop });
|
|
101
|
+
}
|
|
102
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
103
|
+
// If the ContextMenu is open, close it if the user clicks outside of it
|
|
16
104
|
useEffect(() => {
|
|
17
|
-
|
|
18
|
-
|
|
105
|
+
function handleClickOutside(event) {
|
|
106
|
+
if (isCtxMenuOpen &&
|
|
107
|
+
ctxMenuRef.current &&
|
|
108
|
+
!ctxMenuRef.current.contains(event.target) &&
|
|
109
|
+
buttonRef.current &&
|
|
110
|
+
!buttonRef.current.contains(event.target)) {
|
|
111
|
+
setIsCtxMenuOpen(false);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
19
115
|
return () => {
|
|
20
|
-
|
|
116
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
21
117
|
};
|
|
22
|
-
}, []);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
118
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
119
|
+
// Close the context menu if the breadcrumbs should un-collapse
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (isCtxMenuOpen && !isMenuCollapsed) {
|
|
122
|
+
setIsCtxMenuOpen(false);
|
|
123
|
+
}
|
|
124
|
+
}, [isMenuCollapsed, isCtxMenuOpen]);
|
|
125
|
+
// handle tab navigation when the context menu is open
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (!buttonRef.current || !ctxMenuRef.current) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
function handleKeyDown(event) {
|
|
131
|
+
var _a, _b, _c, _d;
|
|
132
|
+
if (!isCtxMenuOpen || !isMenuCollapsed) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (event.key === "Tab") {
|
|
136
|
+
const links = (_a = ctxMenuRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("a");
|
|
137
|
+
const lastBreadCrumb = (_c = (_b = breadcrumbsRef.current) === null || _b === void 0 ? void 0 : _b.lastElementChild) === null || _c === void 0 ? void 0 : _c.querySelector("a");
|
|
138
|
+
if (!links || !lastBreadCrumb) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const firstLink = links[0];
|
|
142
|
+
const lastLink = links[links.length - 1];
|
|
143
|
+
// If the user is tabbing...
|
|
144
|
+
if (!event.shiftKey) {
|
|
145
|
+
// If the context button is focused then the next focusable item
|
|
146
|
+
// should be the first item in the context menu
|
|
147
|
+
if (document.activeElement === buttonRef.current) {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
firstLink.focus();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// If the last context item is focused then the focus should go to
|
|
153
|
+
// the last breadcrumb item
|
|
154
|
+
if (document.activeElement === lastLink) {
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
lastBreadCrumb.focus();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// If the user is shift-tabbing...
|
|
160
|
+
if (event.shiftKey) {
|
|
161
|
+
// If the first item is focused then the focus should go back to the context button
|
|
162
|
+
if (event.shiftKey && document.activeElement === firstLink) {
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
(_d = buttonRef === null || buttonRef === void 0 ? void 0 : buttonRef.current) === null || _d === void 0 ? void 0 : _d.focus();
|
|
165
|
+
}
|
|
166
|
+
// If the focus is on the last breadcrumb item then the focus should go
|
|
167
|
+
// to the last item in the context menu
|
|
168
|
+
if (event.shiftKey && document.activeElement === lastBreadCrumb) {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
lastLink.focus();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
176
|
+
return () => {
|
|
177
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
// Separate out the links into first, context and last
|
|
181
|
+
const firstLink = links[0];
|
|
182
|
+
const contextLinks = links.slice(1, links.length - 1);
|
|
29
183
|
const lastLink = links[links.length - 1];
|
|
30
|
-
|
|
31
|
-
return (jsx("nav", Object.assign({ className: `${BreadcrumbClasses} ${showContext ? " contextmenu" : ""}` }, { children: jsxs("ol", Object.assign({ className: `${baseClass}--items` }, { children: [jsx("li", Object.assign({ className: `${baseClass}--item home` }, { children: jsx("a", Object.assign({ className: `${baseClass}--link`, href: home.url }, { children: jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: home.label })) })) })), jsx("li", Object.assign({ className: `${baseClass}--item--context`, onClick: handleContextMenuToggle }, { children: jsxs("ul", Object.assign({ className: `${baseClass}--items context--menu ${toggleMenuOpen ? " open" : ""}` }, { children: [showContext && jsx(ContextMenu, { links: menuLinks }), !showContext &&
|
|
32
|
-
menuLinks.map((link, index) => (jsx("li", Object.assign({ className: `${baseClass}--item` }, { children: jsx("a", Object.assign({ href: link.url, className: `${baseClass}--link` }, { children: jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: link.label })) })) }), index)))] })) })), jsx("li", Object.assign({ className: `${baseClass}--item final` }, { children: jsx("a", Object.assign({ className: `${baseClass}--link`, href: lastLink.url }, { children: jsx("span", Object.assign({ className: `${baseClass}--link--label` }, { children: lastLink.label })) })) }))] })) })));
|
|
184
|
+
return (jsxs("nav", Object.assign({ className: breadcrumbClass }, { children: [jsx("div", Object.assign({ className: innerClass }, { children: jsxs("ol", Object.assign({ className: itemsClass, ref: breadcrumbsRef }, { children: [jsx(BreadcrumbItem, { url: firstLink.url, label: firstLink.label, labelShown: false, className: itemFirstClass }), contextLinks && contextLinks.length > 0 ? (jsxs("li", Object.assign({ className: contextItemsClass }, { children: [jsx("ol", Object.assign({ className: itemsClass }, { children: contextLinks.map((contextLink, i) => (jsx(BreadcrumbItem, { url: contextLink.url, label: contextLink.label }, i))) })), jsx("button", { "aria-label": buttonLabel, "aria-expanded": isCtxMenuOpen, "aria-controls": contextId, className: buttonClass, onClick: handleButtonClick, ref: buttonRef })] }))) : null, lastLink && (jsx(BreadcrumbItem, { url: lastLink.url, label: lastLink.label }))] })) })), jsx("div", Object.assign({ className: contextMenuClass, id: contextId, hidden: !isCtxMenuOpen, style: { left: ctxMenuPosition.start, top: ctxMenuPosition.top } }, { children: jsx(ContextMenu, { links: contextLinks, ref: ctxMenuRef }) }))] })));
|
|
33
185
|
};
|
|
34
186
|
|
|
35
187
|
export { Breadcrumb as default };
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import classNames from 'classnames';
|
|
3
4
|
import useGlobalSettings from '../../hooks/useGlobalSettings.js';
|
|
4
5
|
import 'tslib';
|
|
5
|
-
import 'react';
|
|
6
6
|
import '../../GlobalCtx-7fb23cfa.js';
|
|
7
7
|
|
|
8
|
-
const ContextMenu = ({ className, links }) => {
|
|
8
|
+
const ContextMenu = React.forwardRef(({ className, links }, ref) => {
|
|
9
9
|
const { prefix } = useGlobalSettings();
|
|
10
10
|
const baseClass = `${prefix}--context-menu`;
|
|
11
11
|
const contextMenuClasses = classNames(className, {
|
|
12
12
|
[baseClass]: true,
|
|
13
13
|
});
|
|
14
|
-
return (jsx("
|
|
14
|
+
return (jsx("ol", Object.assign({ className: contextMenuClasses, ref: ref }, { children: links &&
|
|
15
15
|
links.map((link, i) => (jsx("li", Object.assign({ className: `${baseClass}--item ${link.endsection ? "endsection" : ""}` }, { children: jsx("a", Object.assign({ href: link.url, className: `${baseClass}--link` }, { children: jsx("span", Object.assign({ className: `${baseClass}--label` }, { children: link.label })) })) }), `${baseClass}--item-${i}`))) })));
|
|
16
|
-
};
|
|
16
|
+
});
|
|
17
17
|
|
|
18
18
|
export { ContextMenu as default };
|
|
@@ -5,7 +5,7 @@ import 'tslib';
|
|
|
5
5
|
import 'react';
|
|
6
6
|
import '../../GlobalCtx-7fb23cfa.js';
|
|
7
7
|
|
|
8
|
-
const SocialMedia = ({ className, theme = "light", justify = "start", headline, icons, }) => {
|
|
8
|
+
const SocialMedia = ({ className, theme = "light", justify = "start", headline, icons, iconSize = "normal", }) => {
|
|
9
9
|
const { prefix } = useGlobalSettings();
|
|
10
10
|
// Classes to be applied to the outer element
|
|
11
11
|
const baseClass = `${prefix}--social-media`;
|
|
@@ -17,7 +17,8 @@ const SocialMedia = ({ className, theme = "light", justify = "start", headline,
|
|
|
17
17
|
const listClass = `${baseClass}--list`;
|
|
18
18
|
const listItemClass = `${listClass}--item`;
|
|
19
19
|
const iconClass = `${listItemClass}--icon`;
|
|
20
|
-
|
|
20
|
+
const iconSizeClass = `${listItemClass}--icon__${iconSize}`;
|
|
21
|
+
return (jsxs("div", Object.assign({ className: classes }, { children: [headline && jsx("h5", Object.assign({ className: headlineClass }, { children: headline })), jsx("ul", Object.assign({ className: listClass }, { children: icons.map((item) => (jsx("li", Object.assign({ className: listItemClass }, { children: jsx("a", Object.assign({ title: item.label, className: classNames(iconClass, iconSizeClass, `${iconClass}__${item.icon}`), href: item.url }, { children: item.label })) })))) }))] })));
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
export { SocialMedia as default };
|
|
@@ -10,6 +10,7 @@ const defaultArgs = {
|
|
|
10
10
|
headline: "Follow us on social media",
|
|
11
11
|
theme: "light",
|
|
12
12
|
justify: "start",
|
|
13
|
+
iconSize: "normal",
|
|
13
14
|
icons: [
|
|
14
15
|
{
|
|
15
16
|
icon: "facebook",
|
|
@@ -17,9 +18,9 @@ const defaultArgs = {
|
|
|
17
18
|
label: "Facebook",
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
|
-
icon: "
|
|
21
|
-
url: "https://
|
|
22
|
-
label: "
|
|
21
|
+
icon: "x",
|
|
22
|
+
url: "https://x.com/ilo",
|
|
23
|
+
label: "x",
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
26
|
icon: "instagram",
|