import type { DPartialConfigContextData } from './contex';
import type { DIconContextData } from '@react-devui/icons/Icon';
import { useContext, useEffect, useMemo, useRef } from 'react';
import ReactDOM from 'react-dom';
import { useRefExtra, useEvent } from '@react-devui/hooks';
import { DIconContext } from '@react-devui/icons/Icon';
import { getClassName } from '@react-devui/utils';
import dayjs from '../../dayjs';
import { DConfigContextManager } from './contex';
import { DConfigContext } from './contex';
import resources from './resources.json';
const ROOT = new DConfigContextManager({
namespace: 'rd',
componentConfigs: {},
i18n: {
lang: 'en-US',
resources,
},
layout: {
pageScrollEl: ':root',
},
globalScroll: false,
});
export const ROOT_DATA: {
clickEvent?: {
time: number;
x: number;
y: number;
};
pageSize: { width: number; height: number };
} = {
pageSize: typeof window !== 'undefined' ? { width: window.innerWidth, height: window.innerHeight } : { width: 0, height: 0 },
};
export interface DRootProps {
children: React.ReactNode;
context?: DPartialConfigContextData;
}
export function DRoot(props: DRootProps): JSX.Element | null {
const { children, context: _context } = props;
const parent = useContext(DConfigContext);
const windowRef = useRefExtra(() => window);
const pageSizeRef = useRef<HTMLDivElement>(null);
const [context, iconContext] = useMemo<[DConfigContextManager, DIconContextData]>(() => {
const context = new DConfigContextManager((parent ?? ROOT).mergeContext(_context ?? {}));
if (parent) {
context.setParent(parent);
}
const namespace = context.namespace;
const iconProps = context.componentConfigs.DIcon;
return [
context,
{
props: iconProps,
className: (theme) => getClassName(`${namespace}-icon`, { [`t-${theme}`]: theme }),
twoToneColor: (theme) => [
theme ? `var(--${namespace}-color-${theme})` : `var(--${namespace}-text-color)`,
theme ? `var(--${namespace}-background-color-${theme})` : `rgb(var(--${namespace}-text-color-rgb) / 10%)`,
],
},
];
}, [_context, parent]);
switch (context.i18n.lang) {
case 'en-US':
dayjs.locale('en');
break;
case 'zh-CN':
dayjs.locale('zh-cn');
dayjs.updateLocale('zh-cn', {
meridiem: (hour: number, minute: number, isLowercase: number) => {
return hour > 12 ? 'PM' : 'AM';
},
});
break;
default:
break;
}
useEvent<MouseEvent>(
windowRef,
'click',
(e) => {
if (!(e.clientX === 0 && e.clientY === 0)) {
const rect = e.target instanceof Element ? e.target.getBoundingClientRect() : null;
if (rect) {
ROOT_DATA.clickEvent = {
time: performance.now(),
x: e.offsetX + rect.x,
y: e.offsetX + rect.y,
};
}
}
},
{ capture: true }
);
useEffect(() => {
if (pageSizeRef.current) {
const observer = new ResizeObserver(() => {
ROOT_DATA.pageSize = { width: pageSizeRef.current!.clientWidth, height: pageSizeRef.current!.clientHeight };
});
observer.observe(pageSizeRef.current);
return () => {
observer.disconnect();
};
}
});
return (
<>
<DConfigContext.Provider value={context}>
{parent ? children : <DIconContext.Provider value={iconContext}>{children}</DIconContext.Provider>}
</DConfigContext.Provider>
{windowRef.current &&
ReactDOM.createPortal(
<div
ref={pageSizeRef}
style={{
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
pointerEvents: 'none',
}}
></div>,
windowRef.current.document.body
)}
</>
);
}