Skip to content

Commit

Permalink
feat: update dropdown component props and add function for changing a…
Browse files Browse the repository at this point in the history
…ctiveKey(ZhongAnTech#986)
  • Loading branch information
JaysonZou committed Dec 28, 2022
1 parent 6de9f19 commit 9989208
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 91 deletions.
74 changes: 51 additions & 23 deletions packages/zarm/src/dropdown/Dropdown.tsx
@@ -1,54 +1,82 @@
import * as React from 'react';
import classnames from 'classnames';
import {createBEM} from "@zarm-design/bem";
import {cloneElement} from "react";
import { ConfigContext } from '../config-provider';
import type { HTMLProps } from '../utils/utilityTypes';
import type { BaseDropdownProps, BaseDropdownItemProps } from './interface';
import {TabPanelProps} from "../tabs";
import TabPanel from "../tabs/TabPanel";
import type { BaseDropdownProps } from './interface';
import DropdownItem, {DropdownItemProps} from "./DropdownItem";

export type DropdownProps = React.PropsWithChildren<BaseDropdownProps & HTMLProps>;

interface CompoundedComponent
extends React.ForwardRefExoticComponent<DropdownProps & React.RefAttributes<HTMLDivElement>> {
Item: typeof DropdownItem;
}

const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>((props, ref) => {
const { className, children, onChange, activeKey, defaultActiveKey, ...restProps } = props;
const { prefixCls: globalPrefixCls } = React.useContext(ConfigContext);
const prefixCls = `${globalPrefixCls}-dropdown`;
const { prefixCls } = React.useContext(ConfigContext);
const bem = createBEM('dropdown', { prefixCls });

const onTriggerClick = (trigger: React.ReactElement<TabPanelProps, typeof TabPanel>, index: number) => {
onChange(index);
};
const [selectedKey, setSelectedKey] = React.useState(defaultActiveKey);

const renderTrigger = (trigger: React.ReactElement<DropdownItemProps, typeof TabPanel>, index: number) => {
const itemCls = classnames(`${prefixCls}__trigger`, trigger.props.className, {
});
const onTriggerClick = (dropdownItem: React.ReactElement<DropdownItemProps, typeof DropdownItem>, index: number) => {
setSelectedKey(dropdownItem.props.itemKey);
onChange?.(index);
};

const renderTrigger = (dropdownItem: React.ReactElement<DropdownItemProps, typeof DropdownItem>, index: number) => {
return (
<li role="tab" key={+index} className={itemCls} onClick={() => onTriggerClick(trigger, index)}>
{trigger.props.title}
<li key={index} className={bem('trigger')} onClick={() => onTriggerClick(dropdownItem, index)}>
{dropdownItem.props.title}
</li>
);
};

const triggersRender = React.Children.map(children, renderTrigger);

const getSelected = (index: number, itemKey: string | number) => {
if (!activeKey) {
if (!defaultActiveKey && index === 0) {
return true;
}
return defaultActiveKey === itemKey;
}
return activeKey === itemKey;
};

const contentRender = React.Children.map(
children,
(item: React.ReactElement<DropdownItemProps, typeof DropdownItem>, index: number) => (
<DropdownItem {...item.props} />
),
(element: React.ReactElement<DropdownItemProps, typeof DropdownItem>, index: number) => {
if (!React.isValidElement(element)) return null;
const itemKey = element.props.itemKey || index;
let selected = getSelected(index, itemKey);
if (!activeKey) {
selected = selectedKey === itemKey;
if (!selectedKey && index === 0) {
selected = true;
}
}
return cloneElement(element, {
key: index,
title: element.props.title,
itemKey,
style: element.props.style,
selected,
});
}
);

return (
<div ref={ref}>
<div className={`${prefixCls}__header`}>
<ul className={`${prefixCls}__trigger-list`}>
<div ref={ref} className={bem([className])} {...restProps}>
{selectedKey}
<ul className={bem('trigger-list')}>
{triggersRender}
</ul>
{contentRender}
</div>
<div className={`${prefixCls}__body`}>{contentRender}</div>
</div>
);
});
}) as CompoundedComponent;

Dropdown.displayName = 'Dropdown';

Expand Down
33 changes: 11 additions & 22 deletions packages/zarm/src/dropdown/DropdownItem.tsx
Expand Up @@ -2,45 +2,34 @@ import * as React from 'react';
import { createBEM } from '@zarm-design/bem';
import { ConfigContext } from '../config-provider';
import type { BaseDropdownItemProps } from './interface';
import type { HTMLProps } from '../utils/utilityTypes';

export type DropdownItemProps = BaseDropdownItemProps &
HTMLProps & {
onClick?: React.MouseEventHandler<HTMLLIElement>;
};
export interface DropdownItemProps
extends BaseDropdownItemProps,
Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {}

const DropdownItem = React.forwardRef<HTMLLIElement, DropdownItemProps>((props, ref) => {
const dropdownItemRef = (ref as any) || React.createRef<HTMLDivElement>();
const {
className,
title,
onClick,
arrow,
children,
selected,
...restProps
} = props;
const { prefixCls } = React.useContext(ConfigContext);
const bem = createBEM('list-item', { prefixCls });
const bem = createBEM('dropdown', { prefixCls });

const cls = bem([
const cls = bem('content', [
{
inline: !!children,
arrow: true,
active: selected,
},
className,
]);

const contentRender = children && <div className={bem('content')}>{children}</div>;
const arrowRender = !!onClick && arrow && <div className={bem('arrow')} />;

return (
<li ref={ref} className={cls} onClick={onClick} onTouchStart={() => {}} {...restProps}>
<div className={bem('wrapper')}>
<div className={bem('inner')}>
{contentRender}
{arrowRender}
</div>
</div>
</li>
<div ref={dropdownItemRef} className={cls} {...restProps}>
{children}
</div>
);
});

Expand Down
13 changes: 7 additions & 6 deletions packages/zarm/src/dropdown/demo.md
@@ -1,4 +1,4 @@
# Dropdown hhhhhh
# Dropdown 下拉菜单

## 基础用法

Expand All @@ -7,12 +7,13 @@ import { useState } from 'react';
import { Dropdown } from 'zarm';

const Demo = () => {
return <>
<Dropdown>
<Dropdown.Item key="key1" title="菜单一">内容一</Dropdown.Item>
<Dropdown.Item key="key2" title="菜单二">内容二</Dropdown.Item>
const [activeKey, setActiveKey] = useState('');
return (
<Dropdown defaultActiveKey='key1'>
<Dropdown.Item itemKey="key1" title="菜单一">内容一</Dropdown.Item>
<Dropdown.Item itemKey="key2" title="菜单二">内容二</Dropdown.Item>
</Dropdown>
</>
)
};

ReactDOM.render(<Demo />, mountNode);
Expand Down
3 changes: 2 additions & 1 deletion packages/zarm/src/dropdown/interface.ts
Expand Up @@ -8,8 +8,9 @@ export interface BaseDropdownProps {
}

export interface BaseDropdownItemProps {
key?: number | string;
itemKey?: string | number;
title?: React.ReactNode;
arrow?: React.ReactNode;
children?: React.ReactNode;
selected?: boolean;
}
83 changes: 45 additions & 38 deletions packages/zarm/src/dropdown/style/component.scss
@@ -1,51 +1,58 @@
@include b(toast) {
@include define(text-color, var(--za-color-text-inverse));
@include define(icon-color, var(--za-color-text-inverse));
@include define(font-size, 13px);
@include define(icon-size, 36px);
@include define(border-radius, 6px);
@include define(background-color, rgba(0, 0, 0, var(--za-opacity-toast)));

color: var(--text-color);
font-size: var(--font-size);
line-height: 1.5;
@include b(dropdown) {
@include define(font-size, 12px);
@include define(background, #fff);
@include define(z-index, 100);
@include define(height, 50px);
@include define(color, var(--za-color-text));
@include define(active-color, var(--za-theme-primary));

display: flex;
width: 100%;
background: var(--background);
background: red;
height: var(--height);
justify-content: center;
align-content: center;
align-items: center;
text-align: center;
position: relative;
border-radius: var(--border-radius);
background-color: var(--background-color);
overflow: auto;
position: fixed;
left: 0;
bottom: 0;
z-index: var(--z-index);
transition-duration: 0.2s;
overflow: hidden;

@include m(text) {
padding: var(--za-padding-v-md) var(--za-padding-h-md);
}

@include m(icon) {
min-width: 120px;
padding: var(--za-padding-h-xl) var(--za-padding-h-sm);

@include e(text) {
margin-top: var(--za-padding-v-md);
}
@include m(hidden) {
bottom: calc(var(--height) * -1);
height: 0;
}

@include e(text) {
word-break: break-all;
@include e(trigger-list) {
display: flex;
}

@include e(icon) {
color: var(--icon-color);
font-size: var(--icon-size);
justify-content: center;
align-items: center;
display: flex;
@include e(item) {
flex: 1;

@include b(icon) {
--font-size: var(--icon-size);
@include e(title) {
font-size: var(--font-size);
line-height: 1;
margin-top: 2px;
color: var(--color);
}

@include b(activity-indicator) {
--size: var(--icon-size);
--stroke-active-color: var(--icon-color);

@include m(active) {
@include b(tab-bar) {
@include e(title) {
color: var(--active-color);
}
}

@include b(icon) {
color: var(--active-color);
}
}
}
}
1 change: 0 additions & 1 deletion packages/zarm/src/dropdown/style/index.tsx
@@ -1,3 +1,2 @@
import '../../style';
import '../../popup/style';
import './index.scss';

0 comments on commit 9989208

Please sign in to comment.