@ant-design/x
Version:
Craft AI-driven interfaces effortlessly
210 lines (205 loc) • 6.24 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import omit from '@rc-component/util/lib/omit';
import pickAttrs from '@rc-component/util/lib/pickAttrs';
import { clsx } from 'clsx';
import * as React from 'react';
import useProxyImperativeHandle from "../_util/hooks/use-proxy-imperative-handle";
import { useXProviderContext } from "../x-provider";
import Bubble from "./Bubble";
import { BubbleContext } from "./context";
import DividerBubble from "./Divider";
import { useCompatibleScroll } from "./hooks/useCompatibleScroll";
import SystemBubble from "./System";
import useBubbleListStyle from "./style";
function roleCfgIsFunction(roleCfg) {
return typeof roleCfg === 'function' && roleCfg instanceof Function;
}
const MemoedBubble = /*#__PURE__*/React.memo(Bubble);
const MemoedDividerBubble = /*#__PURE__*/React.memo(DividerBubble);
const MemoedSystemBubble = /*#__PURE__*/React.memo(SystemBubble);
const BubbleListItem = props => {
const {
_key,
bubblesRef,
extraInfo,
status,
role,
classNames = {},
styles = {},
...restProps
} = props;
const initBubbleRef = React.useCallback(node => {
if (node) {
bubblesRef.current[_key] = node;
} else {
delete bubblesRef.current[_key];
}
}, [_key]);
const {
bubble: bubbleClassName,
divider: dividerClassName,
system: systemClassName,
...otherClassNames
} = classNames;
const {
bubble: bubbleStyle,
divider: dividerStyle,
system: systemStyle,
...otherStyles
} = styles;
let bubble = /*#__PURE__*/React.createElement(MemoedBubble, _extends({
ref: initBubbleRef,
style: bubbleStyle,
className: bubbleClassName,
classNames: otherClassNames,
styles: otherStyles
}, restProps));
if (role === 'divider') {
bubble = /*#__PURE__*/React.createElement(MemoedDividerBubble, _extends({
ref: initBubbleRef,
style: dividerStyle,
className: dividerClassName,
classNames: otherClassNames,
styles: otherStyles
}, restProps));
} else if (role === 'system') {
bubble = /*#__PURE__*/React.createElement(MemoedSystemBubble, _extends({
ref: initBubbleRef,
style: systemStyle,
className: systemClassName,
classNames: otherClassNames,
styles: otherStyles
}, restProps));
}
return /*#__PURE__*/React.createElement(BubbleContext.Provider, {
value: {
key: _key,
status,
extraInfo
}
}, bubble);
};
const BubbleList = (props, ref) => {
const {
prefixCls: customizePrefixCls,
rootClassName,
className,
styles = {},
classNames = {},
style,
items,
autoScroll = true,
role,
onScroll,
...restProps
} = props;
const domProps = pickAttrs(restProps, {
attr: true,
aria: true
});
// ============================= Refs =============================
const listRef = React.useRef(null);
const bubblesRef = React.useRef({});
// ============================= States =============================
const [scrollBoxDom, setScrollBoxDom] = React.useState();
const [scrollContentDom, setScrollContentDom] = React.useState();
const {
scrollTo
} = useCompatibleScroll(scrollBoxDom, scrollContentDom);
// ============================ Prefix ============================
const {
getPrefixCls
} = useXProviderContext();
const prefixCls = getPrefixCls('bubble', customizePrefixCls);
const listPrefixCls = `${prefixCls}-list`;
const [hashId, cssVarCls] = useBubbleListStyle(prefixCls);
const mergedClassNames = clsx(listPrefixCls, rootClassName, className, classNames.root, hashId, cssVarCls);
const mergedStyle = {
...styles.root,
...style
};
// ============================= Refs =============================
useProxyImperativeHandle(ref, () => {
return {
nativeElement: listRef.current,
scrollBoxNativeElement: scrollBoxDom,
scrollTo: ({
key,
top,
behavior = 'smooth',
block
}) => {
const {
scrollHeight,
clientHeight
} = scrollBoxDom;
if (typeof top === 'number') {
scrollTo({
top: autoScroll ? -scrollHeight + clientHeight + top : top,
behavior
});
} else if (top === 'bottom') {
const bottomOffset = autoScroll ? 0 : scrollHeight;
scrollTo({
top: bottomOffset,
behavior
});
} else if (top === 'top') {
const topOffset = autoScroll ? -scrollHeight : 0;
scrollTo({
top: topOffset,
behavior
});
} else if (key && bubblesRef.current[key]) {
scrollTo({
intoView: {
behavior,
block
},
intoViewDom: bubblesRef.current[key].nativeElement
});
}
}
};
});
// ============================ Render ============================
return /*#__PURE__*/React.createElement("div", _extends({}, domProps, {
className: mergedClassNames,
style: mergedStyle,
ref: listRef
}), /*#__PURE__*/React.createElement("div", {
className: clsx(`${listPrefixCls}-scroll-box`, classNames.scroll, {
[`${listPrefixCls}-autoscroll`]: autoScroll
}),
style: styles.scroll,
ref: node => setScrollBoxDom(node),
onScroll: onScroll
}, /*#__PURE__*/React.createElement("div", {
ref: node => setScrollContentDom(node),
className: clsx(`${listPrefixCls}-scroll-content`)
}, items.map(item => {
let mergedProps;
if (item.role && role) {
const cfg = role[item.role];
mergedProps = {
...(roleCfgIsFunction(cfg) ? cfg(item) : cfg),
...item
};
} else {
mergedProps = item;
}
return /*#__PURE__*/React.createElement(BubbleListItem, _extends({
classNames: classNames,
styles: styles
}, omit(mergedProps, ['key']), {
key: item.key,
_key: item.key,
bubblesRef: bubblesRef
}));
}))));
};
const ForwardBubbleList = /*#__PURE__*/React.forwardRef(BubbleList);
if (process.env.NODE_ENV !== 'production') {
ForwardBubbleList.displayName = 'BubbleList';
}
export default ForwardBubbleList;