select.stories.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import React from 'react';
  2. import { storiesOf } from '@storybook/react';
  3. import classNames from 'classnames';
  4. import { optionRenderProps, RenderMultipleSelectedItemFn, RenderSingleSelectedItemFn } from '@douyinfe/semi-ui/select/index';
  5. import { Checkbox } from '../../index';
  6. import { Select, Avatar, Tag, Space } from '../../index';
  7. const stories = storiesOf('Select', module);
  8. let optionList = [
  9. { value: 'tony', label: 'Ironman' },
  10. { value: 'Thor', label: 'Thor' },
  11. { value: 'steve', label: 'Caption' },
  12. { value: 'peter', label: 'SpiderBoy' },
  13. ];
  14. stories.add('Select', () => (
  15. <>
  16. <Select style={{ width: 200 }}>
  17. <Select.Option value="1"></Select.Option>
  18. <Select.Option value="2"></Select.Option>
  19. </Select>
  20. </>
  21. ));
  22. const RenderOptionDemo = () => {
  23. const renderOptionItem = (renderProps: optionRenderProps) => {
  24. const {
  25. disabled,
  26. selected,
  27. label,
  28. value,
  29. focused,
  30. className,
  31. style,
  32. onMouseEnter,
  33. onClick,
  34. ...rest
  35. } = renderProps;
  36. const optionCls = classNames({
  37. ['custom-option-render']: true,
  38. ['custom-option-render-focused']: focused,
  39. ['custom-option-render-disabled']: disabled,
  40. ['custom-option-render-selected']: selected,
  41. });
  42. // Notice:
  43. // 1.props传入的style需在wrapper dom上进行消费,否则在虚拟化场景下会无法正常使用
  44. // 2.选中(selected)、聚焦(focused)、禁用(disabled)等状态的样式需自行加上,你可以从props中获取到相对的boolean值
  45. // 3.onMouseEnter需在wrapper dom上绑定,否则上下键盘操作时显示会有问题
  46. return (
  47. <div style={style} className={optionCls} onClick={(e) => onClick(e)} onMouseEnter={e => onMouseEnter(e)}>
  48. <Checkbox checked={selected} />
  49. <div className="option-right">{label}</div>
  50. </div>
  51. );
  52. };
  53. return (
  54. <Select
  55. filter
  56. dropdownClassName="components-select-demo-renderOptionItem"
  57. optionList={optionList}
  58. style={{ width: 300 }}
  59. renderOptionItem={renderOptionItem}
  60. />
  61. );
  62. };
  63. interface OptionNode {
  64. name: string;
  65. email: string;
  66. avatar: string;
  67. }
  68. function CustomRender(props) {
  69. const list = [
  70. {
  71. name: '夏可漫',
  72. email: '[email protected]',
  73. avatar:
  74. 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/dy.png',
  75. },
  76. {
  77. name: '申悦',
  78. email: '[email protected]',
  79. avatar:
  80. 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bag.jpeg',
  81. },
  82. {
  83. name: '曲晨一',
  84. email: '[email protected]',
  85. avatar:
  86. 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/8bd8224511db085ed74fea37205aede5.jpg',
  87. },
  88. {
  89. name: '文嘉茂',
  90. email: '[email protected]',
  91. avatar:
  92. 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/6fbafc2d-e3e6-4cff-a1e2-17709c680624.png',
  93. },
  94. ];
  95. const renderCustomOption = (item) => {
  96. let optionStyle = {
  97. display: 'flex',
  98. paddingLeft: 24,
  99. paddingTop: 10,
  100. paddingBottom: 10,
  101. };
  102. return (
  103. <Select.Option value={item.name} style={optionStyle} showTick={true} {...item} key={item.email}>
  104. <Avatar size="small" src={item.avatar} />
  105. <div style={{ marginLeft: 8 }}>
  106. <div style={{ fontSize: 14 }}>{item.name}</div>
  107. <div
  108. style={{
  109. color: 'var(--semi-color-text-2)',
  110. fontSize: 12,
  111. lineHeight: '16px',
  112. fontWeight: 'normal',
  113. }}
  114. >
  115. {item.email}
  116. </div>
  117. </div>
  118. </Select.Option>
  119. );
  120. }
  121. const renderSelectedItem: RenderSingleSelectedItemFn = (optionNode: OptionNode): React.ReactNode => {
  122. return (
  123. <div key={optionNode.email} style={{ display: 'flex', alignItems: 'center' }}>
  124. <Avatar src={optionNode.avatar} size="small">
  125. {optionNode.avatar}
  126. </Avatar>
  127. <span style={{ marginLeft: 8 }}>{optionNode.email}</span>
  128. </div>
  129. );
  130. }
  131. const renderMultipleWithCustomTag: RenderMultipleSelectedItemFn = (optionNode: OptionNode, { onClose }) => {
  132. let content = (
  133. <Tag
  134. avatarSrc={optionNode.avatar}
  135. avatarShape="circle"
  136. closable={true}
  137. onClose={onClose}
  138. size="large"
  139. key={optionNode.name}
  140. >
  141. {optionNode.name}
  142. </Tag>
  143. );
  144. return {
  145. isRenderInTag: false,
  146. content,
  147. };
  148. }
  149. return (
  150. <Space>
  151. <Select
  152. style={{
  153. width: 300,
  154. height: 40,
  155. }}
  156. defaultValue={'夏可漫'}
  157. renderSelectedItem={renderSelectedItem}
  158. >
  159. {list.map(item => renderCustomOption(item))}
  160. </Select>
  161. <Select
  162. placeholder="请选择"
  163. maxTagCount={2}
  164. style={{ width: 280 }}
  165. onChange={v => console.log(v)}
  166. defaultValue={['夏可漫', '申悦']}
  167. multiple
  168. renderSelectedItem={renderMultipleWithCustomTag}
  169. >
  170. {list.map(item => renderCustomOption(item))}
  171. </Select>
  172. </Space>
  173. );
  174. }
  175. stories.add('自定义已选标签渲染', () => (
  176. <>
  177. <div>renderSelectedItem</div>
  178. <CustomRender />
  179. </>
  180. ));