@douyinfe/semi-ui 2.14.0-beta.1 → 2.15.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/autoComplete/index.tsx +0 -1
  2. package/cascader/__test__/cascader.test.js +13 -10
  3. package/cascader/_story/cascader.stories.js +22 -0
  4. package/cascader/index.tsx +53 -35
  5. package/checkbox/checkbox.tsx +1 -0
  6. package/checkbox/checkboxInner.tsx +4 -1
  7. package/datePicker/datePicker.tsx +7 -5
  8. package/dist/css/semi.css +34 -6
  9. package/dist/css/semi.min.css +1 -1
  10. package/dist/umd/semi-ui.js +1332 -572
  11. package/dist/umd/semi-ui.js.map +1 -1
  12. package/dist/umd/semi-ui.min.js +1 -1
  13. package/dist/umd/semi-ui.min.js.map +1 -1
  14. package/dropdown/context.ts +2 -0
  15. package/dropdown/dropdownItem.tsx +2 -1
  16. package/dropdown/dropdownMenu.tsx +24 -1
  17. package/dropdown/index.tsx +10 -2
  18. package/form/_story/form.stories.tsx +32 -17
  19. package/form/hoc/withField.tsx +1 -1
  20. package/form/interface.ts +1 -1
  21. package/input/__test__/input.test.js +31 -0
  22. package/input/_story/input.stories.js +24 -1
  23. package/input/index.tsx +5 -2
  24. package/input/inputGroup.tsx +7 -6
  25. package/inputNumber/index.tsx +5 -3
  26. package/lib/cjs/autoComplete/index.d.ts +0 -1
  27. package/lib/cjs/autoComplete/index.js +0 -1
  28. package/lib/cjs/cascader/index.d.ts +1 -1
  29. package/lib/cjs/cascader/index.js +36 -9
  30. package/lib/cjs/checkbox/checkbox.d.ts +1 -0
  31. package/lib/cjs/checkbox/checkbox.js +2 -1
  32. package/lib/cjs/checkbox/checkboxInner.d.ts +2 -0
  33. package/lib/cjs/checkbox/checkboxInner.js +8 -2
  34. package/lib/cjs/datePicker/datePicker.d.ts +1 -1
  35. package/lib/cjs/datePicker/datePicker.js +21 -6
  36. package/lib/cjs/dropdown/context.d.ts +2 -0
  37. package/lib/cjs/dropdown/dropdownItem.js +3 -1
  38. package/lib/cjs/dropdown/dropdownMenu.d.ts +18 -1
  39. package/lib/cjs/dropdown/dropdownMenu.js +23 -2
  40. package/lib/cjs/dropdown/index.d.ts +4 -0
  41. package/lib/cjs/dropdown/index.js +13 -5
  42. package/lib/cjs/form/baseForm.d.ts +17 -16
  43. package/lib/cjs/form/field.d.ts +17 -16
  44. package/lib/cjs/form/hoc/withField.d.ts +1 -1
  45. package/lib/cjs/form/interface.d.ts +1 -1
  46. package/lib/cjs/input/index.d.ts +2 -1
  47. package/lib/cjs/input/index.js +11 -5
  48. package/lib/cjs/input/inputGroup.js +16 -9
  49. package/lib/cjs/inputNumber/index.d.ts +1 -0
  50. package/lib/cjs/inputNumber/index.js +8 -3
  51. package/lib/cjs/locale/source/de.d.ts +3 -0
  52. package/lib/cjs/locale/source/de.js +165 -0
  53. package/lib/cjs/locale/source/fr.d.ts +3 -0
  54. package/lib/cjs/locale/source/fr.js +165 -0
  55. package/lib/cjs/locale/source/it.d.ts +3 -0
  56. package/lib/cjs/locale/source/it.js +165 -0
  57. package/lib/cjs/modal/ModalContent.d.ts +1 -0
  58. package/lib/cjs/modal/ModalContent.js +17 -4
  59. package/lib/cjs/modal/confirm.d.ts +5 -0
  60. package/lib/cjs/radio/radio.d.ts +2 -0
  61. package/lib/cjs/radio/radio.js +2 -1
  62. package/lib/cjs/radio/radioInner.d.ts +2 -0
  63. package/lib/cjs/radio/radioInner.js +8 -2
  64. package/lib/cjs/rating/index.d.ts +7 -0
  65. package/lib/cjs/rating/index.js +135 -68
  66. package/lib/cjs/rating/item.d.ts +27 -3
  67. package/lib/cjs/rating/item.js +145 -38
  68. package/lib/cjs/select/index.d.ts +2 -0
  69. package/lib/cjs/select/index.js +15 -3
  70. package/lib/cjs/spin/icon.js +1 -1
  71. package/lib/cjs/table/Body/index.js +1 -1
  72. package/lib/cjs/tabs/index.d.ts +1 -0
  73. package/lib/cjs/tabs/index.js +2 -1
  74. package/lib/cjs/tabs/interface.d.ts +1 -0
  75. package/lib/cjs/tag/index.js +4 -5
  76. package/lib/cjs/tag/interface.d.ts +1 -0
  77. package/lib/cjs/tagInput/index.d.ts +2 -0
  78. package/lib/cjs/tagInput/index.js +19 -5
  79. package/lib/cjs/timePicker/TimeInput.d.ts +2 -1
  80. package/lib/cjs/timePicker/TimeInput.js +7 -3
  81. package/lib/cjs/timePicker/TimePicker.d.ts +2 -0
  82. package/lib/cjs/timePicker/TimePicker.js +2 -1
  83. package/lib/cjs/timePicker/index.d.ts +1 -0
  84. package/lib/cjs/tooltip/index.d.ts +2 -0
  85. package/lib/cjs/tooltip/index.js +12 -4
  86. package/lib/cjs/tree/index.d.ts +1 -0
  87. package/lib/cjs/tree/index.js +9 -2
  88. package/lib/cjs/tree/treeNode.js +12 -18
  89. package/lib/cjs/treeSelect/index.js +8 -1
  90. package/lib/cjs/typography/title.d.ts +1 -1
  91. package/lib/es/autoComplete/index.d.ts +0 -1
  92. package/lib/es/autoComplete/index.js +0 -1
  93. package/lib/es/cascader/index.d.ts +1 -1
  94. package/lib/es/cascader/index.js +36 -9
  95. package/lib/es/checkbox/checkbox.d.ts +1 -0
  96. package/lib/es/checkbox/checkbox.js +2 -1
  97. package/lib/es/checkbox/checkboxInner.d.ts +2 -0
  98. package/lib/es/checkbox/checkboxInner.js +8 -2
  99. package/lib/es/datePicker/datePicker.d.ts +1 -1
  100. package/lib/es/datePicker/datePicker.js +21 -6
  101. package/lib/es/dropdown/context.d.ts +2 -0
  102. package/lib/es/dropdown/dropdownItem.js +3 -1
  103. package/lib/es/dropdown/dropdownMenu.d.ts +18 -1
  104. package/lib/es/dropdown/dropdownMenu.js +21 -2
  105. package/lib/es/dropdown/index.d.ts +4 -0
  106. package/lib/es/dropdown/index.js +13 -5
  107. package/lib/es/form/baseForm.d.ts +17 -16
  108. package/lib/es/form/field.d.ts +17 -16
  109. package/lib/es/form/hoc/withField.d.ts +1 -1
  110. package/lib/es/form/interface.d.ts +1 -1
  111. package/lib/es/input/index.d.ts +2 -1
  112. package/lib/es/input/index.js +11 -5
  113. package/lib/es/input/inputGroup.js +15 -9
  114. package/lib/es/inputNumber/index.d.ts +1 -0
  115. package/lib/es/inputNumber/index.js +8 -3
  116. package/lib/es/locale/source/de.d.ts +3 -0
  117. package/lib/es/locale/source/de.js +153 -0
  118. package/lib/es/locale/source/fr.d.ts +3 -0
  119. package/lib/es/locale/source/fr.js +153 -0
  120. package/lib/es/locale/source/it.d.ts +3 -0
  121. package/lib/es/locale/source/it.js +153 -0
  122. package/lib/es/modal/ModalContent.d.ts +1 -0
  123. package/lib/es/modal/ModalContent.js +17 -4
  124. package/lib/es/modal/confirm.d.ts +5 -0
  125. package/lib/es/radio/radio.d.ts +2 -0
  126. package/lib/es/radio/radio.js +2 -1
  127. package/lib/es/radio/radioInner.d.ts +2 -0
  128. package/lib/es/radio/radioInner.js +8 -2
  129. package/lib/es/rating/index.d.ts +7 -0
  130. package/lib/es/rating/index.js +133 -65
  131. package/lib/es/rating/item.d.ts +27 -3
  132. package/lib/es/rating/item.js +145 -32
  133. package/lib/es/select/index.d.ts +2 -0
  134. package/lib/es/select/index.js +15 -3
  135. package/lib/es/spin/icon.js +1 -1
  136. package/lib/es/table/Body/index.js +1 -1
  137. package/lib/es/tabs/index.d.ts +1 -0
  138. package/lib/es/tabs/index.js +2 -1
  139. package/lib/es/tabs/interface.d.ts +1 -0
  140. package/lib/es/tag/index.js +4 -5
  141. package/lib/es/tag/interface.d.ts +1 -0
  142. package/lib/es/tagInput/index.d.ts +2 -0
  143. package/lib/es/tagInput/index.js +19 -5
  144. package/lib/es/timePicker/TimeInput.d.ts +2 -1
  145. package/lib/es/timePicker/TimeInput.js +7 -3
  146. package/lib/es/timePicker/TimePicker.d.ts +2 -0
  147. package/lib/es/timePicker/TimePicker.js +2 -1
  148. package/lib/es/timePicker/index.d.ts +1 -0
  149. package/lib/es/tooltip/index.d.ts +2 -0
  150. package/lib/es/tooltip/index.js +13 -4
  151. package/lib/es/tree/index.d.ts +1 -0
  152. package/lib/es/tree/index.js +9 -2
  153. package/lib/es/tree/treeNode.js +11 -19
  154. package/lib/es/treeSelect/index.js +8 -1
  155. package/lib/es/typography/title.d.ts +1 -1
  156. package/locale/source/de.ts +156 -0
  157. package/locale/source/fr.ts +156 -0
  158. package/locale/source/it.ts +156 -0
  159. package/modal/ModalContent.tsx +7 -4
  160. package/package.json +8 -8
  161. package/radio/radio.tsx +2 -0
  162. package/radio/radioInner.tsx +4 -1
  163. package/rating/__test__/rating.test.js +13 -31
  164. package/rating/_story/rating.stories.js +13 -2
  165. package/rating/index.tsx +63 -18
  166. package/rating/item.tsx +141 -26
  167. package/select/index.tsx +6 -2
  168. package/spin/icon.tsx +1 -1
  169. package/table/Body/index.tsx +1 -1
  170. package/table/_story/v2/FixedVirtualizedEmpty.tsx +76 -0
  171. package/table/_story/v2/index.js +2 -1
  172. package/tabs/index.tsx +1 -0
  173. package/tabs/interface.ts +1 -0
  174. package/tag/index.tsx +2 -3
  175. package/tag/interface.ts +1 -0
  176. package/tagInput/index.tsx +8 -4
  177. package/timePicker/TimeInput.tsx +5 -3
  178. package/timePicker/TimePicker.tsx +2 -0
  179. package/tooltip/index.tsx +7 -2
  180. package/tree/index.tsx +3 -1
  181. package/tree/treeNode.tsx +9 -12
  182. package/treeSelect/index.tsx +4 -1
  183. package/upload/_story/upload.stories.tsx +9 -6
  184. package/yarn-error.log +0 -26235
@@ -1,8 +1,10 @@
1
1
  import React from 'react';
2
+ import { TooltipProps } from '../tooltip/index';
2
3
 
3
4
  export interface DropdownContextType {
4
5
  level?: number;
5
6
  showTick?: boolean;
7
+ trigger?: TooltipProps['trigger'];
6
8
  }
7
9
 
8
10
  const DropdownContext = React.createContext<DropdownContextType>({
@@ -25,6 +25,7 @@ export interface DropdownItemProps extends BaseProps {
25
25
  const prefixCls = css.PREFIX;
26
26
 
27
27
  class DropdownItem extends BaseComponent<DropdownItemProps> {
28
+
28
29
  static propTypes = {
29
30
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
30
31
  name: PropTypes.string,
@@ -93,7 +94,7 @@ class DropdownItem extends BaseComponent<DropdownItemProps> {
93
94
  );
94
95
  }
95
96
  return (
96
- <li role="menuitem" {...events} ref={ref => forwardRef(ref)} className={itemclass} style={style}>
97
+ <li role="menuitem" tabIndex={-1} aria-disabled={disabled} {...events} ref={ref => forwardRef(ref)} className={itemclass} style={style}>
97
98
  {tick}
98
99
  {iconContent}
99
100
  {children}
@@ -2,6 +2,8 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import classnames from 'classnames';
4
4
  import { cssClasses } from '@douyinfe/semi-foundation/dropdown/constants';
5
+ import Foundation from '@douyinfe/semi-foundation/dropdown/menuFoundation';
6
+ import DropdownContext from './context';
5
7
 
6
8
  import BaseComponent, { BaseProps } from '../_base/baseComponent';
7
9
 
@@ -15,10 +17,31 @@ class DropdownMenu extends BaseComponent<DropdownMenuProps> {
15
17
  style: PropTypes.object,
16
18
  };
17
19
 
20
+ static contextType = DropdownContext;
21
+
22
+ menuRef: React.RefObject<HTMLUListElement>
23
+
24
+ constructor(props: DropdownMenuProps) {
25
+ super(props);
26
+
27
+ this.menuRef = React.createRef();
28
+ this.foundation = new Foundation(this.adapter);
29
+ }
30
+
31
+ get adapter() {
32
+ return {
33
+ ...super.adapter,
34
+ };
35
+ }
36
+
37
+ componentDidMount() {
38
+ this.foundation.autoFocus(this.menuRef.current);
39
+ }
40
+
18
41
  render() {
19
42
  const { children, className, style, ...rest } = this.props;
20
43
  return (
21
- <ul role="menu" aria-orientation="vertical" {...rest} className={classnames(`${prefixCls}-menu`, className)} style={style}>
44
+ <ul role="menu" aria-orientation="vertical" ref={this.menuRef} {...rest} className={classnames(`${prefixCls}-menu`, className)} style={style} onKeyDown={e => this.foundation.onMenuKeydown(e)}>
22
45
  {children}
23
46
  </ul>
24
47
  );
@@ -58,6 +58,8 @@ export interface DropdownProps extends TooltipProps {
58
58
  onVisibleChange?: (visible: boolean) => void;
59
59
  rePosKey?: string | number;
60
60
  showTick?: boolean;
61
+ closeOnEsc?: TooltipProps['closeOnEsc'];
62
+ onEscKeyDown?: TooltipProps['onEscKeyDown'];
61
63
  }
62
64
 
63
65
  interface DropdownState {
@@ -106,6 +108,8 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
106
108
  position: 'bottom',
107
109
  mouseLeaveDelay: strings.DEFAULT_LEAVE_DELAY,
108
110
  showTick: false,
111
+ closeOnEsc: true,
112
+ onEscKeyDown: noop,
109
113
  };
110
114
 
111
115
  constructor(props: DropdownProps) {
@@ -131,10 +135,10 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
131
135
  handleVisibleChange = (visible: boolean) => this.foundation.handleVisibleChange(visible);
132
136
 
133
137
  renderContent() {
134
- const { render, menu, contentClassName, style, showTick, prefixCls } = this.props;
138
+ const { render, menu, contentClassName, style, showTick, prefixCls, trigger } = this.props;
135
139
  const className = classnames(prefixCls, contentClassName);
136
140
  const { level = 0 } = this.context;
137
- const contextValue = { showTick, level: level + 1 };
141
+ const contextValue = { showTick, level: level + 1, trigger };
138
142
  let content = null;
139
143
  if (React.isValidElement(render)) {
140
144
  content = render;
@@ -233,6 +237,7 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
233
237
  trigger={trigger}
234
238
  onVisibleChange={this.handleVisibleChange}
235
239
  showArrow={false}
240
+ returnFocusOnClose={true}
236
241
  {...attr}
237
242
  >
238
243
  {React.isValidElement(children) ?
@@ -240,6 +245,9 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
240
245
  className: classnames(get(children, 'props.className'), {
241
246
  [`${prefixCls}-showing`]: popVisible,
242
247
  }),
248
+ 'aria-haspopup': true,
249
+ 'aria-expanded': popVisible,
250
+ onKeyDown: e => this.foundation.handleKeyDown(e)
243
251
  }) :
244
252
  children}
245
253
  </Tooltip>
@@ -1,6 +1,6 @@
1
1
  import React, { FunctionComponent } from 'react';
2
2
  import { storiesOf } from '@storybook/react';
3
- import { Form, useFormState, useFormApi, withField, Input, Button } from '../../index';
3
+ import { Form, useFormState, useFormApi, withField, Input, Button, Upload } from '../../index';
4
4
  import { values } from 'lodash';
5
5
  const stories = storiesOf('Form', module);
6
6
 
@@ -64,40 +64,44 @@ const htmlInput = (props: any) => {
64
64
  const FieldB = withField(Input);
65
65
  const FieldA = withField(htmlInput, { valueKey: 'value', onKeyChangeFnName: 'onChange', valuePath: 'target.value' });
66
66
 
67
- const Fields: FunctionComponent<FormFCChild> = ({ formState, values, formApi }) => (
67
+ const Fields: FunctionComponent<FormFCChild> = ({ formState, values, formApi }) => {
68
+ const ref = React.useRef();
69
+ return (
68
70
  <>
69
- <Form.Rating field='test' className='fe' count={2} />
71
+ <Form.Rating field='test' className='fe' count={2} ref={ref} />
70
72
 
71
- <Form.Input field='test' />
73
+ <Form.Input field='test' ref={ref} />
72
74
  <Input size='default' showClear insetLabel />
73
75
  <FieldB insetLabel placeholder='fe' fieldClassName='fefe' field='custom' />
74
76
 
75
77
  <Button onClick={() => formApi.setValue('fieldA', 'fe')}>set</Button>
76
- <Form.Select field='test'>
78
+ <Form.Select field='test' ref={ref}>
77
79
  <Form.Select.Option value="f1"></Form.Select.Option>
78
80
  <Form.Select.Option value="f2"></Form.Select.Option>
79
81
  </Form.Select>
80
- <Form.Input field="UserName" label="用户名"/>
81
- <Form.TextArea field="textarea" onKeyDown={(v: any) => console.log(v)} />
82
+ <Form.Input field="UserName" label="用户名" ref={ref} />
83
+ <Form.TextArea field="textarea" onKeyDown={(v: any) => console.log(v)} ref={ref} />
82
84
  <Form.Input field="Password" label="密码" />
83
- <Form.InputNumber field="number" />
85
+ <Form.InputNumber field="number" ref={ref} />
84
86
  <Form.Rating field="rating" />
85
- <Form.Switch field="switch" checkedText="on" uncheckedText="off" />
87
+ <Form.Switch field="switch" checkedText="on" uncheckedText="off" ref={ref} />
86
88
 
87
89
  <Form.Cascader
88
90
  placeholder="请选择所在地区"
89
91
  field="area"
92
+ ref={ref}
90
93
  label={{ text: '123', required: true, extra: 123 }}
91
94
  treeData={treeData}
92
95
  ></Form.Cascader>
93
- <Form.TimePicker field="time" minuteStep={2} />
96
+ <Form.TimePicker field="time" minuteStep={2} ref={ref} />
94
97
  <Form.AutoComplete field="fe" />
95
98
 
96
- <Form.TreeSelect field="treeSelect" treeData={treeData} />
97
- <Form.Slider field="slider" />
98
- <Form.DatePicker field="datepicker" />
99
+ <Form.TreeSelect field="treeSelect" treeData={treeData} ref={ref} />
100
+ <Form.Slider field="slider" ref={ref} />
101
+ <Form.DatePicker field="datepicker" ref={ref} />
99
102
  <Form.CheckboxGroup
100
103
  field="type"
104
+ ref={ref}
101
105
  label="申请类型(CheckboxGroup)"
102
106
  initValue={['user', 'admin']}
103
107
  rules={[{ required: true }]}
@@ -109,6 +113,7 @@ const Fields: FunctionComponent<FormFCChild> = ({ formState, values, formApi })
109
113
  </Form.CheckboxGroup>
110
114
  <Form.RadioGroup
111
115
  field="radio"
116
+ ref={ref}
112
117
  label="是否独占资源(Radio)"
113
118
  rules={[{ type: 'boolean' }, { required: true, message: '必须选择是否独占 ' }]}
114
119
  >
@@ -122,11 +127,13 @@ const Fields: FunctionComponent<FormFCChild> = ({ formState, values, formApi })
122
127
  <Form.ErrorMessage error="errorText" />
123
128
  <FieldB field="custom" />
124
129
  <FieldA field="cuB" />
125
- <Form.Upload fileName='semi' action='https://test.com' field='file' />
130
+ <Form.TagInput field='tagInput' ref={ref} ></Form.TagInput>
131
+ <Form.Upload ref={ref} fileName='semi' action='https://test.com' field='file' />
126
132
  <Form.Slot />
127
133
  <code style={{ marginTop: 30 }}>{JSON.stringify(formState)}</code>
128
134
  </>
129
- );
135
+ )
136
+ };
130
137
 
131
138
  stories.add('Form', () => <Form>{Fields}</Form>);
132
139
 
@@ -138,14 +145,21 @@ interface IProps {
138
145
  interface IState {
139
146
  visible: boolean;
140
147
  }
148
+
149
+ interface FData {
150
+ test: boolean;
151
+ test2: boolean;
152
+ test3: string;
153
+ // [x: string]: unknown;
154
+ }
141
155
  class Demo extends React.Component<IProps, IState> {
142
156
  constructor(props:any) {
143
157
  super(props);
144
158
  this.state = { visible: false};
145
159
  }
146
160
 
147
- getFormApi(formApi: FormApi) {
148
-
161
+ getFormApi(formApi: FormApi<FData>) {
162
+ formApi.getValue()
149
163
  }
150
164
 
151
165
  render() {
@@ -153,6 +167,7 @@ class Demo extends React.Component<IProps, IState> {
153
167
  return (
154
168
  <>
155
169
  <Form getFormApi={this.getFormApi}>
170
+
156
171
  </Form>
157
172
  </>
158
173
  );
@@ -28,7 +28,7 @@ const prefix = cssClasses.PREFIX;
28
28
 
29
29
  function withField<
30
30
  C extends React.ElementType,
31
- T extends Subtract<React.ComponentProps<C>, CommonexcludeType> & CommonFieldProps,
31
+ T extends Subtract<React.ComponentProps<C>, CommonexcludeType> & CommonFieldProps & React.RefAttributes<any>,
32
32
  R extends React.ComponentType<T>
33
33
  >(Component: C, opts?: WithFieldOption): R {
34
34
  let SemiField = (props: any, ref: React.MutableRefObject<any> | ((instance: any) => void)) => {
package/form/interface.ts CHANGED
@@ -84,7 +84,7 @@ export interface SelectStatic {
84
84
  OptGroup: typeof OptGroup;
85
85
  }
86
86
 
87
- export class Field<P> extends React.Component<Subtract<P & CommonFieldProps, CommonexcludeType>> {}
87
+ export class Field<P> extends React.Component<Subtract<P & CommonFieldProps, CommonexcludeType> & React.RefAttributes<any>> {}
88
88
  export let FormSelectType: React.ComponentType<Subtract<SelectProps & CommonFieldProps, CommonexcludeType>> & SelectStatic;
89
89
  export let FormCheckboxType: React.ComponentType<Subtract<CommonFieldProps, RadioCheckboxExcludeProps> & CheckboxProps & RCIncludeType>;
90
90
  export let FormRadioType: React.ComponentType<Subtract<CommonFieldProps, RadioCheckboxExcludeProps> & RadioProps & RCIncludeType>;
@@ -3,6 +3,7 @@ import Icon from '../../icons/index';
3
3
  import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
4
4
  import GraphemeSplitter from 'grapheme-splitter';
5
5
  import { isString, isFunction } from 'lodash';
6
+ import { InputGroup, InputNumber } from '../../index';
6
7
 
7
8
  function getValueLength(str) {
8
9
  if (isString(str)) {
@@ -251,4 +252,34 @@ describe('Input', () => {
251
252
  expect(truncateValue(value, length, fc)).toBe(result);
252
253
  }
253
254
  })
255
+
256
+ it('input group', () => {
257
+ const groupFocus = sinon.spy(() => {
258
+ console.log('group focus');
259
+ });
260
+ const groupBlur = sinon.spy(() => {
261
+ console.log('group focus');
262
+ });
263
+ const inputFocus = sinon.spy(() => {
264
+ console.log('input focus');
265
+ });
266
+ const inputBlur = sinon.spy(() => {
267
+ console.log('input blur');
268
+ });
269
+ const inputGroup = mount(
270
+ <InputGroup disabled={true} onFocus={groupFocus} onBlur={groupBlur}>
271
+ <Input disabled={false} onFocus={inputFocus} onBlur={inputBlur} placeholder="Name" style={{ width: 100 }} />
272
+ <InputNumber placeholder="Score" style={{ width: 140 }} />
273
+ </InputGroup>
274
+ );
275
+
276
+ inputGroup.find('input').at(0).simulate('focus');
277
+ expect(inputFocus.called).toBe(true);
278
+ expect(groupFocus.called).toBe(true);
279
+ inputGroup.find('input').at(0).simulate('blur');
280
+ expect(inputBlur.called).toBe(true);
281
+ expect(groupBlur.called).toBe(true);
282
+ expect(inputGroup.find('input').at(0).instance().disabled).toBe(false);
283
+ expect(inputGroup.find('input').at(1).instance().disabled).toBe(true);
284
+ })
254
285
  });
@@ -22,7 +22,8 @@ import {
22
22
  Switch,
23
23
  Form,
24
24
  Space,
25
- Radio
25
+ Radio,
26
+ InputNumber
26
27
  } from '../../index';
27
28
  import './input.scss';
28
29
  import RTLWrapper from '../../configProvider/_story/RTLDirection/RTLWrapper';
@@ -936,3 +937,25 @@ export const InputA11y = () => {
936
937
  );
937
938
  }
938
939
  InputA11y.storyName = "input a11y";
940
+
941
+ export const FixInputGroup = () => {
942
+ const groupFocus = () => {
943
+ console.log('group focus');
944
+ }
945
+ const groupBlur = () => {
946
+ console.log('group blur');
947
+ }
948
+ const inputFocus = () => {
949
+ console.log('input focus');
950
+ }
951
+ const inputBlur = () => {
952
+ console.log('input blur');
953
+ }
954
+
955
+ return (
956
+ <InputGroup disabled={true} onFocus={groupFocus} onBlur={groupBlur}>
957
+ <Input disabled={false} onFocus={inputFocus} onBlur={inputBlur} placeholder="Name" style={{ width: 100 }} />
958
+ <InputNumber placeholder="Score" style={{ width: 140 }} />
959
+ </InputGroup>
960
+ );
961
+ }
package/input/index.tsx CHANGED
@@ -64,6 +64,7 @@ export interface InputProps extends
64
64
  inputStyle?: React.CSSProperties;
65
65
  getValueLength?: (value: string) => number;
66
66
  forwardRef?: ((instance: any) => void) | React.MutableRefObject<any> | null;
67
+ preventScroll?: boolean;
67
68
  }
68
69
 
69
70
  export interface InputState {
@@ -117,6 +118,7 @@ class Input extends BaseComponent<InputProps, InputState> {
117
118
  insetLabelId: PropTypes.string,
118
119
  inputStyle: PropTypes.object,
119
120
  getValueLength: PropTypes.func,
121
+ preventScroll: PropTypes.bool,
120
122
  };
121
123
 
122
124
  static defaultProps = {
@@ -124,7 +126,6 @@ class Input extends BaseComponent<InputProps, InputState> {
124
126
  addonAfter: '',
125
127
  prefix: '',
126
128
  suffix: '',
127
- disabled: false,
128
129
  readonly: false,
129
130
  type: 'text',
130
131
  showClear: false,
@@ -174,9 +175,10 @@ class Input extends BaseComponent<InputProps, InputState> {
174
175
  setValue: (value: string) => this.setState({ value }),
175
176
  setEyeClosed: (value: boolean) => this.setState({ eyeClosed: value }),
176
177
  toggleFocusing: (isFocus: boolean) => {
178
+ const { preventScroll } = this.props;
177
179
  const input = this.inputRef && this.inputRef.current;
178
180
  if (isFocus) {
179
- input && input.focus();
181
+ input && input.focus({ preventScroll });
180
182
  } else {
181
183
  input && input.blur();
182
184
  }
@@ -424,6 +426,7 @@ class Input extends BaseComponent<InputProps, InputState> {
424
426
  forwardRef,
425
427
  maxLength,
426
428
  getValueLength,
429
+ preventScroll,
427
430
  ...rest
428
431
  } = this.props;
429
432
  const { value, paddingLeft, isFocus, minLength: stateMinLength } = this.state;
@@ -7,7 +7,7 @@ import BaseComponent from '../_base/baseComponent';
7
7
  import Label, { LabelProps } from '../form/label';
8
8
 
9
9
  import { noop } from '@douyinfe/semi-foundation/utils/function';
10
- import { isFunction } from 'lodash';
10
+ import { get, isFunction } from 'lodash';
11
11
 
12
12
  const prefixCls = cssClasses.PREFIX;
13
13
  const sizeSet = strings.SIZE;
@@ -84,7 +84,7 @@ export default class inputGroup extends BaseComponent<InputGroupProps, InputGrou
84
84
  }
85
85
 
86
86
  render() {
87
- const { size, style, className, children, label, onBlur: groupOnBlur, onFocus: groupOnFocus, ...rest } = this.props;
87
+ const { size, style, className, children, label, onBlur: groupOnBlur, onFocus: groupOnFocus, disabled: groupDisabled, ...rest } = this.props;
88
88
  const groupCls = cls(
89
89
  `${prefixCls}-group`,
90
90
  {
@@ -96,10 +96,11 @@ export default class inputGroup extends BaseComponent<InputGroupProps, InputGrou
96
96
  if (children) {
97
97
  inner = (Array.isArray(children) ? children : [children]).map((item, index) => {
98
98
  if (item) {
99
- const { onBlur: itemOnBlur, onFocus: itemOnFocus } = (item as any).props;
100
- const onBlur = isFunction(itemOnBlur) ? itemOnBlur : groupOnBlur;
101
- const onFocus = isFunction(itemOnFocus) ? itemOnFocus : groupOnFocus;
102
- return React.cloneElement(item as any, { key: index, size, onBlur, onFocus, ...rest });
99
+ const { onBlur: itemOnBlur, onFocus: itemOnFocus, disabled: itemDisabled } = (item as any).props;
100
+ const onBlur = isFunction(itemOnBlur) && get(itemOnBlur, 'name') !== 'noop' ? itemOnBlur : groupOnBlur;
101
+ const onFocus = isFunction(itemOnFocus) && get(itemOnFocus, 'name') !== 'noop' ? itemOnFocus : groupOnFocus;
102
+ const disabled = typeof itemDisabled === 'boolean' ? itemDisabled : groupDisabled;
103
+ return React.cloneElement(item as any, { key: index, ...rest, size, onBlur, onFocus, disabled });
103
104
  }
104
105
  return null;
105
106
  });
@@ -1,3 +1,4 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
1
2
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
3
  /* eslint-disable no-unused-vars */
3
4
  /* eslint-disable max-depth */
@@ -54,6 +55,7 @@ export interface InputNumberProps extends InputProps {
54
55
  onUpClick?: (value: string, e: React.MouseEvent<HTMLButtonElement>) => void;
55
56
  }
56
57
 
58
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
57
59
  export interface InputNumberState extends BaseInputNumberState {}
58
60
 
59
61
  class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
@@ -82,6 +84,7 @@ class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
82
84
  prefixCls: PropTypes.string,
83
85
  pressInterval: PropTypes.number,
84
86
  pressTimeout: PropTypes.number,
87
+ preventScroll: PropTypes.bool,
85
88
  shiftStep: PropTypes.number,
86
89
  step: PropTypes.number,
87
90
  style: PropTypes.object,
@@ -96,7 +99,6 @@ class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
96
99
  };
97
100
 
98
101
  static defaultProps: InputNumberProps = {
99
- disabled: false,
100
102
  forwardedRef: noop,
101
103
  innerButtons: false,
102
104
  keepFocus: false,
@@ -246,7 +248,7 @@ class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
246
248
  }
247
249
 
248
250
  componentDidUpdate(prevProps: InputNumberProps) {
249
- const { value } = this.props;
251
+ const { value, preventScroll } = this.props;
250
252
  const { focusing } = this.state;
251
253
  let newValue;
252
254
  /**
@@ -338,7 +340,7 @@ class InputNumber extends BaseComponent<InputNumberProps, InputNumberState> {
338
340
 
339
341
  if (this.props.keepFocus && this.state.focusing) {
340
342
  if (document.activeElement !== this.inputNode) {
341
- this.inputNode.focus();
343
+ this.inputNode.focus({ preventScroll });
342
344
  }
343
345
  }
344
346
  }
@@ -143,7 +143,6 @@ declare class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<Au
143
143
  position: "bottomLeft";
144
144
  data: [];
145
145
  showClear: boolean;
146
- disabled: boolean;
147
146
  size: "default";
148
147
  onFocus: (...args: any[]) => void;
149
148
  onSearch: (...args: any[]) => void;
@@ -424,7 +424,6 @@ AutoComplete.defaultProps = {
424
424
  position: 'bottomLeft',
425
425
  data: [],
426
426
  showClear: false,
427
- disabled: false,
428
427
  size: 'default',
429
428
  onFocus: _noop2.default,
430
429
  onSearch: _noop2.default,
@@ -131,6 +131,7 @@ declare class Cascader extends BaseComponent<CascaderProps, CascaderState> {
131
131
  disableStrictly: PropTypes.Requireable<boolean>;
132
132
  leafOnly: PropTypes.Requireable<boolean>;
133
133
  enableLeafClick: PropTypes.Requireable<boolean>;
134
+ preventScroll: PropTypes.Requireable<boolean>;
134
135
  };
135
136
  static defaultProps: {
136
137
  leafOnly: boolean;
@@ -142,7 +143,6 @@ declare class Cascader extends BaseComponent<CascaderProps, CascaderState> {
142
143
  showClear: boolean;
143
144
  autoClearSearchValue: boolean;
144
145
  changeOnSelect: boolean;
145
- disabled: boolean;
146
146
  disableStrictly: boolean;
147
147
  autoMergeValue: boolean;
148
148
  multiple: boolean;
@@ -611,7 +611,8 @@ class Cascader extends _baseComponent.default {
611
611
  loadingKeys: new _set.default(),
612
612
 
613
613
  /* Mark whether this rendering has triggered asynchronous loading of data */
614
- loading: false
614
+ loading: false,
615
+ showInput: false
615
616
  };
616
617
  this.options = {};
617
618
  this.isEmpty = false;
@@ -638,9 +639,15 @@ class Cascader extends _baseComponent.default {
638
639
  });
639
640
  },
640
641
  focusInput: () => {
642
+ const {
643
+ preventScroll
644
+ } = this.props;
645
+
641
646
  if (this.inputRef && this.inputRef.current) {
642
647
  // TODO: check the reason
643
- this.inputRef.current.focus();
648
+ this.inputRef.current.focus({
649
+ preventScroll
650
+ });
644
651
  }
645
652
  }
646
653
  };
@@ -751,7 +758,19 @@ class Cascader extends _baseComponent.default {
751
758
  });
752
759
  },
753
760
  notifyOnExceed: data => this.props.onExceed(data),
754
- notifyClear: () => this.props.onClear()
761
+ notifyClear: () => this.props.onClear(),
762
+ toggleInputShow: (showInput, cb) => {
763
+ this.setState({
764
+ showInput
765
+ }, () => {
766
+ cb();
767
+ });
768
+ },
769
+ updateFocusState: isFocus => {
770
+ this.setState({
771
+ isFocus
772
+ });
773
+ }
755
774
  });
756
775
  }
757
776
 
@@ -922,21 +941,29 @@ class Cascader extends _baseComponent.default {
922
941
  const inputcls = (0, _classnames.default)("".concat(prefixcls, "-input"));
923
942
  const {
924
943
  inputValue,
925
- inputPlaceHolder
944
+ inputPlaceHolder,
945
+ showInput
926
946
  } = this.state;
927
947
  const inputProps = {
928
948
  disabled,
929
949
  value: inputValue,
930
950
  className: inputcls,
931
- onChange: this.handleInputChange,
932
- placeholder: inputPlaceHolder
951
+ onChange: this.handleInputChange
933
952
  };
934
953
  const wrappercls = (0, _classnames.default)({
935
954
  ["".concat(prefixcls, "-search-wrapper")]: true
936
955
  });
956
+ const displayText = this.renderDisplayText();
957
+ const spanCls = (0, _classnames.default)({
958
+ ["".concat(prefixcls, "-selection-placeholder")]: !displayText,
959
+ ["".concat(prefixcls, "-selection-text-hide")]: showInput && inputValue,
960
+ ["".concat(prefixcls, "-selection-text-inactive")]: showInput && !inputValue
961
+ });
937
962
  return /*#__PURE__*/_react.default.createElement("div", {
938
963
  className: wrappercls
939
- }, /*#__PURE__*/_react.default.createElement(_index.default, (0, _assign.default)({
964
+ }, /*#__PURE__*/_react.default.createElement("span", {
965
+ className: spanCls
966
+ }, displayText ? displayText : inputPlaceHolder), showInput && /*#__PURE__*/_react.default.createElement(_index.default, (0, _assign.default)({
940
967
  ref: this.inputRef,
941
968
  size: size
942
969
  }, inputProps)));
@@ -1053,7 +1080,8 @@ Cascader.propTypes = {
1053
1080
  loadedKeys: _propTypes.default.array,
1054
1081
  disableStrictly: _propTypes.default.bool,
1055
1082
  leafOnly: _propTypes.default.bool,
1056
- enableLeafClick: _propTypes.default.bool
1083
+ enableLeafClick: _propTypes.default.bool,
1084
+ preventScroll: _propTypes.default.bool
1057
1085
  };
1058
1086
  Cascader.defaultProps = {
1059
1087
  leafOnly: false,
@@ -1065,7 +1093,6 @@ Cascader.defaultProps = {
1065
1093
  showClear: false,
1066
1094
  autoClearSearchValue: true,
1067
1095
  changeOnSelect: false,
1068
- disabled: false,
1069
1096
  disableStrictly: false,
1070
1097
  autoMergeValue: true,
1071
1098
  multiple: false,
@@ -54,6 +54,7 @@ declare class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
54
54
  index: PropTypes.Requireable<number>;
55
55
  'aria-label': PropTypes.Requireable<string>;
56
56
  tabIndex: PropTypes.Requireable<number>;
57
+ preventScroll: PropTypes.Requireable<boolean>;
57
58
  };
58
59
  static defaultProps: {
59
60
  defaultChecked: boolean;
@@ -270,7 +270,8 @@ Checkbox.propTypes = {
270
270
  extra: _propTypes.default.node,
271
271
  index: _propTypes.default.number,
272
272
  'aria-label': _propTypes.default.string,
273
- tabIndex: _propTypes.default.number
273
+ tabIndex: _propTypes.default.number,
274
+ preventScroll: _propTypes.default.bool
274
275
  };
275
276
  Checkbox.defaultProps = {
276
277
  defaultChecked: false,
@@ -19,6 +19,7 @@ export interface CheckboxInnerProps {
19
19
  focusInner?: boolean;
20
20
  onInputFocus?: (e: any) => void;
21
21
  onInputBlur?: (e: any) => void;
22
+ preventScroll?: boolean;
22
23
  }
23
24
  declare class CheckboxInner extends PureComponent<CheckboxInnerProps> {
24
25
  static contextType: React.Context<import("./context").CheckboxContextType>;
@@ -40,6 +41,7 @@ declare class CheckboxInner extends PureComponent<CheckboxInnerProps> {
40
41
  focusInner: PropTypes.Requireable<boolean>;
41
42
  onInputFocus: PropTypes.Requireable<(...args: any[]) => any>;
42
43
  onInputBlur: PropTypes.Requireable<(...args: any[]) => any>;
44
+ preventScroll: PropTypes.Requireable<boolean>;
43
45
  };
44
46
  static defaultProps: {
45
47
  onChange: (...args: any[]) => void;
@@ -41,7 +41,12 @@ class CheckboxInner extends _react.PureComponent {
41
41
  }
42
42
 
43
43
  focus() {
44
- this.inputEntity.focus();
44
+ const {
45
+ preventScroll
46
+ } = this.props;
47
+ this.inputEntity.focus({
48
+ preventScroll
49
+ });
45
50
  }
46
51
 
47
52
  render() {
@@ -119,7 +124,8 @@ CheckboxInner.propTypes = {
119
124
  extraId: _propTypes.default.string,
120
125
  focusInner: _propTypes.default.bool,
121
126
  onInputFocus: _propTypes.default.func,
122
- onInputBlur: _propTypes.default.func
127
+ onInputBlur: _propTypes.default.func,
128
+ preventScroll: _propTypes.default.bool
123
129
  };
124
130
  CheckboxInner.defaultProps = {
125
131
  onChange: _noop2.default