@blocklet/ui-react
Version:
Some useful front-end web components that can be used in Blocklets.
114 lines (97 loc) • 4.33 kB
JSX
import 'iconify-icon';
import { use, createElement } from 'react';
import PropTypes from 'prop-types';
// FIXME: 直接从 react 中 import Fragment 可能会在 vite 下出错,先暂时从 react/jsx-runtime 导入 Fragment 来跳过这个问题
import { Fragment } from 'react/jsx-runtime';
import { SessionContext } from '@arcblock/did-connect/lib/Session';
import SessionUser from '@arcblock/ux/lib/SessionUser';
import SessionBlocklet from '@arcblock/ux/lib/SessionBlocklet';
import LocaleSelector from '@arcblock/ux/lib/Locale/selector';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import ThemeModeToggle from '@arcblock/ux/lib/Config/theme-mode-toggle';
import { SessionManagerProps } from '../types';
import { getLocalizedNavigation, filterNavByRole } from '../blocklets';
import NotificationAddon from './notification-addon';
import DomainWarning from './domain-warning';
const hasNotification = () => {
const navigations = window?.blocklet?.navigation ?? [];
return !!navigations.find((n) => n.id === '/userCenter/notification');
};
// eslint-disable-next-line no-shadow
export default function HeaderAddons({
formattedBlocklet,
addons = null,
showDomainWarningDialog = true,
sessionManagerProps = { showRole: true },
}) {
const sessionCtx = use(SessionContext);
const { locale, languages } = useLocaleContext() || {};
const { enableConnect = true, enableLocale = true } = formattedBlocklet;
const authenticated = !!sessionCtx?.session?.user;
let localizedNav = getLocalizedNavigation(formattedBlocklet?.navigation?.sessionManager, locale) || [];
// 根据 role 筛选 nav 数据
localizedNav = filterNavByRole(localizedNav, sessionCtx?.session?.user?.role);
const renderAddons = () => {
// 不关心内置的 session manager 和 locale selector, 直接覆盖 UX Header 的 addons
if (addons && typeof addons !== 'function') {
return Array.isArray(addons) ? addons : [addons];
}
let addonsArray = [];
if (hasNotification()) {
addonsArray.push(<NotificationAddon key="notification-addon" session={sessionCtx.session} />);
}
// 启用了多语言,且检测到了 locale context,且有多种语言可以切换
if (enableLocale && locale && languages.length > 1) {
addonsArray.push(<LocaleSelector key="locale-selector" showText={false} />);
}
// 切换明暗主题
addonsArray.push(<ThemeModeToggle key="theme-mode-toggle" />);
// 启用了连接钱包并且检测到了 session context
if (enableConnect && sessionCtx) {
const menu = [];
if (authenticated) {
const navList = localizedNav ? localizedNav.slice(0, 5) : [];
navList.forEach((x) => {
menu.push({
label: x.title,
icon: x.icon ? <iconify-icon icon={x.icon} height={24} style={{ marginRight: 8 }} /> : null,
component: 'a',
href: x.link,
key: x.link,
});
});
}
addonsArray.push(<SessionBlocklet key="session-blocklet" session={sessionCtx.session} locale={locale} />);
addonsArray.push(
<SessionUser
key="session-user"
session={sessionCtx.session}
locale={locale}
menu={menu}
showRole
{...sessionManagerProps}
/>
);
}
if (typeof addons === 'function') {
addonsArray = addons(addonsArray) || [];
}
return addonsArray;
};
const renderedAddons = renderAddons();
const nodes = Array.isArray(renderedAddons) ? renderedAddons : [renderedAddons];
const mergedNodes = [
showDomainWarningDialog ? <DomainWarning session={sessionCtx?.session} locale={locale} /> : null,
...nodes,
].filter(Boolean);
return createElement(Fragment, null, ...mergedNodes);
}
HeaderAddons.propTypes = {
formattedBlocklet: PropTypes.object.isRequired,
// 需要考虑 定制的 addons 与内置的 连接钱包/选择语言 addons 共存的情况
// - PropTypes.func: 可以把自定义 addons 插在 session-manager 或 locale-selector (如果存在的话) 前/中/后
// - PropTypes.node: 将 addons 原样传给 UX Header 组件
addons: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
sessionManagerProps: SessionManagerProps,
showDomainWarningDialog: PropTypes.bool,
};