@king-design/intact 2.0.17-beta.0 → 2.1.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 (147) hide show
  1. package/components/cascader/index.md +18 -0
  2. package/components/cascader/index.spec.ts +56 -0
  3. package/components/cascader/index.ts +35 -12
  4. package/components/cascader/index.vdt +9 -8
  5. package/components/cascader/useFields.ts +22 -0
  6. package/components/cascader/useFilterable.ts +23 -8
  7. package/components/cascader/useLabel.ts +7 -4
  8. package/components/cascader/useLoad.ts +4 -2
  9. package/components/code/demos/basic.md +1 -1
  10. package/components/colorpicker/index.md +16 -0
  11. package/components/colorpicker/index.ts +4 -0
  12. package/components/colorpicker/index.vdt +3 -2
  13. package/components/datepicker/index.md +11 -0
  14. package/components/dialog/index.spec.ts +2 -2
  15. package/components/dropdown/dropdown.ts +0 -1
  16. package/components/dropdown/item.ts +3 -2
  17. package/components/dropdown/usePosition.ts +9 -1
  18. package/components/editable/index.ts +17 -3
  19. package/components/editable/index.vdt +1 -0
  20. package/components/input/demos/autoRows.md +44 -0
  21. package/components/input/demos/password.md +12 -0
  22. package/components/input/demos/textarea.md +2 -2
  23. package/components/input/index.md +1 -0
  24. package/components/input/index.spec.ts +97 -1
  25. package/components/input/index.ts +17 -3
  26. package/components/input/index.vdt +29 -6
  27. package/components/input/styles.ts +18 -1
  28. package/components/input/useAutoRows.ts +65 -0
  29. package/components/input/useAutoWidth.ts +12 -3
  30. package/components/input/useShowPassword.ts +27 -0
  31. package/components/pagination/index.spec.ts +1 -1
  32. package/components/pagination/index.ts +1 -2
  33. package/components/portal.ts +4 -4
  34. package/components/position.ts +5 -1
  35. package/components/select/base.ts +3 -1
  36. package/components/select/base.vdt +2 -0
  37. package/components/select/index.md +11 -1
  38. package/components/table/cell.ts +4 -5
  39. package/components/table/demos/hideHeader.md +33 -0
  40. package/components/table/demos/pagination.md +53 -0
  41. package/components/table/index.md +22 -0
  42. package/components/table/index.spec.ts +73 -1
  43. package/components/table/row.ts +3 -3
  44. package/components/table/styles.ts +5 -0
  45. package/components/table/table.ts +29 -4
  46. package/components/table/table.vdt +21 -3
  47. package/components/table/useChecked.ts +21 -6
  48. package/components/table/useDisableRow.ts +3 -2
  49. package/components/table/useDraggable.ts +11 -8
  50. package/components/table/useGroup.ts +2 -0
  51. package/components/table/useMerge.ts +6 -3
  52. package/components/table/usePagination.ts +71 -0
  53. package/components/table/useRestRowStatus.ts +4 -1
  54. package/components/table/useTree.ts +4 -3
  55. package/components/timepicker/index.md +11 -0
  56. package/components/tooltip/demos/trigger.md +1 -1
  57. package/components/tooltip/index.md +1 -1
  58. package/components/tooltip/index.spec.ts +8 -5
  59. package/components/treeSelect/index.md +9 -0
  60. package/es/components/cascader/index.d.ts +22 -11
  61. package/es/components/cascader/index.js +9 -12
  62. package/es/components/cascader/index.spec.js +81 -0
  63. package/es/components/cascader/index.vdt.js +10 -8
  64. package/es/components/cascader/useFields.d.ts +2 -0
  65. package/es/components/cascader/useFields.js +18 -0
  66. package/es/components/cascader/useFilterable.d.ts +2 -1
  67. package/es/components/cascader/useFilterable.js +17 -6
  68. package/es/components/cascader/useLabel.d.ts +2 -1
  69. package/es/components/cascader/useLabel.js +4 -4
  70. package/es/components/cascader/useLoad.d.ts +2 -1
  71. package/es/components/cascader/useLoad.js +9 -7
  72. package/es/components/colorpicker/index.d.ts +2 -0
  73. package/es/components/colorpicker/index.js +7 -2
  74. package/es/components/colorpicker/index.vdt.js +3 -6
  75. package/es/components/dialog/index.spec.js +2 -2
  76. package/es/components/dropdown/dropdown.js +0 -1
  77. package/es/components/dropdown/item.js +3 -3
  78. package/es/components/dropdown/usePosition.js +8 -1
  79. package/es/components/editable/index.d.ts +1 -0
  80. package/es/components/editable/index.js +20 -6
  81. package/es/components/editable/index.vdt.js +2 -1
  82. package/es/components/input/index.d.ts +10 -2
  83. package/es/components/input/index.js +10 -3
  84. package/es/components/input/index.spec.js +169 -1
  85. package/es/components/input/index.vdt.js +26 -7
  86. package/es/components/input/styles.js +8 -3
  87. package/es/components/input/useAutoRows.d.ts +2 -0
  88. package/es/components/input/useAutoRows.js +79 -0
  89. package/es/components/input/useAutoWidth.js +13 -3
  90. package/es/components/input/useShowPassword.d.ts +7 -0
  91. package/es/components/input/useShowPassword.js +31 -0
  92. package/es/components/pagination/index.js +1 -3
  93. package/es/components/pagination/index.spec.js +2 -4
  94. package/es/components/portal.d.ts +6 -2
  95. package/es/components/portal.js +4 -3
  96. package/es/components/position.js +2 -1
  97. package/es/components/select/base.d.ts +2 -1
  98. package/es/components/select/base.js +3 -1
  99. package/es/components/select/base.vdt.js +3 -1
  100. package/es/components/table/cell.js +1 -6
  101. package/es/components/table/index.spec.js +130 -19
  102. package/es/components/table/row.d.ts +1 -1
  103. package/es/components/table/row.js +2 -1
  104. package/es/components/table/styles.js +1 -1
  105. package/es/components/table/table.d.ts +15 -0
  106. package/es/components/table/table.js +16 -7
  107. package/es/components/table/table.vdt.js +20 -6
  108. package/es/components/table/useChecked.d.ts +3 -2
  109. package/es/components/table/useChecked.js +23 -12
  110. package/es/components/table/useDisableRow.d.ts +2 -1
  111. package/es/components/table/useDisableRow.js +4 -4
  112. package/es/components/table/useDraggable.d.ts +3 -2
  113. package/es/components/table/useDraggable.js +11 -8
  114. package/es/components/table/useGroup.js +3 -0
  115. package/es/components/table/useMerge.d.ts +2 -1
  116. package/es/components/table/useMerge.js +5 -4
  117. package/es/components/table/usePagination.d.ts +8 -0
  118. package/es/components/table/usePagination.js +81 -0
  119. package/es/components/table/useTree.d.ts +2 -1
  120. package/es/components/table/useTree.js +3 -4
  121. package/es/components/tooltip/index.spec.js +9 -10
  122. package/es/index.d.ts +3 -3
  123. package/es/index.js +3 -3
  124. package/es/packages/kpc-react/__tests__/components/cascader.spec.d.ts +1 -0
  125. package/es/packages/kpc-react/__tests__/components/cascader.spec.js +79 -0
  126. package/es/site/data/components/dialog/demos/basic/react.js +4 -1
  127. package/es/site/data/components/input/demos/autoRows/index.d.ts +9 -0
  128. package/es/site/data/components/input/demos/autoRows/index.js +24 -0
  129. package/es/site/data/components/input/demos/autoRows/react.d.ts +8 -0
  130. package/es/site/data/components/input/demos/autoRows/react.js +62 -0
  131. package/es/site/data/components/input/demos/password/index.d.ts +5 -0
  132. package/es/site/data/components/input/demos/password/index.js +17 -0
  133. package/es/site/data/components/input/demos/password/react.d.ts +5 -0
  134. package/es/site/data/components/input/demos/password/react.js +41 -0
  135. package/es/site/data/components/input/demos/textarea/react.js +4 -2
  136. package/es/site/data/components/table/demos/hideHeader/index.d.ts +12 -0
  137. package/es/site/data/components/table/demos/hideHeader/index.js +30 -0
  138. package/es/site/data/components/table/demos/hideHeader/react.d.ts +11 -0
  139. package/es/site/data/components/table/demos/hideHeader/react.js +60 -0
  140. package/es/site/data/components/table/demos/pagination/index.d.ts +12 -0
  141. package/es/site/data/components/table/demos/pagination/index.js +35 -0
  142. package/es/site/data/components/table/demos/pagination/react.d.ts +16 -0
  143. package/es/site/data/components/table/demos/pagination/react.js +65 -0
  144. package/es/styles/fonts/ionicons.js +1 -1
  145. package/index.ts +3 -3
  146. package/package.json +4 -4
  147. package/styles/fonts/ionicons.ts +0 -1
@@ -27,6 +27,7 @@ sidebar: doc
27
27
  | stackClearIcon | 是否将清空按钮覆盖在`suffix`按钮上展示来节省空间 | `boolean` | `false` |
28
28
  | frozenOnInput | 是否在输入的过程中冻结`value`更新到视图 | `boolean` | `false` |
29
29
  | inline | 是否展示内联模式 | `boolean` | `flase` |
30
+ | resize | 指定textarea输入框拖动调整大小的方向,默认只能垂直方向调整 | `"none"` | `"vertical"` | `"horizontal"` | `"both"`' | `"vertical"` |
30
31
 
31
32
  ## Search
32
33
 
@@ -1,7 +1,12 @@
1
1
  import BasicDemo from '~/components/input/demos/basic';
2
- import {mount, unmount, dispatchEvent, wait} from '../../test/utils';
2
+ import {mount, unmount, dispatchEvent, wait, getElement} from '../../test/utils';
3
3
  import SearchDemo from '~/components/input/demos/search';
4
4
  import FrozenDemo from '~/components/input/demos/frozen';
5
+ import AutoRowsDemo from '~/components/input/demos/autoRows';
6
+ import PasswordDemo from '~/components/input/demos/password';
7
+ import {Input} from './';
8
+ import {Dialog} from '../dialog';
9
+ import { Component } from 'intact';
5
10
 
6
11
  describe('Input', () => {
7
12
  afterEach(() => {unmount()});
@@ -70,4 +75,95 @@ describe('Input', () => {
70
75
  await wait();
71
76
  expect(input2.value).to.eql('#112233');
72
77
  });
78
+
79
+ it('should auto expand or shrink textarea', async () => {
80
+ const [instance, element] = mount(AutoRowsDemo);
81
+ const [textarea1, textarea2] = element.querySelectorAll('textarea');
82
+ // const lineHeight = parseInt(getComputedStyle(textarea1).lineHeight);
83
+
84
+ instance.set<string>('value1', 'a\nb');
85
+ await wait();
86
+ expect(textarea1.style.height).to.eql('50px');
87
+
88
+ instance.set<string>('value1', 'a');
89
+ await wait();
90
+ expect(textarea1.style.height).to.eql('32px');
91
+
92
+ instance.set<string>('value2', 'a');
93
+ await wait();
94
+ expect(textarea2.style.height).to.eql('68px');
95
+
96
+ instance.set<string>('value2', 'a\nb\nc')
97
+ await wait();
98
+ expect(textarea2.style.height).to.eql('68px');
99
+
100
+ instance.set<string>('value2', 'a\nb\nc\nd')
101
+ await wait();
102
+ expect(textarea2.style.height).to.eql('86px');
103
+
104
+ instance.set<string>('value2', 'a\nb\nc\nd\ne\nf\ng\nh')
105
+ await wait();
106
+ expect(textarea2.style.height).to.eql('104px');
107
+ });
108
+
109
+ it('should show or hide password', async () => {
110
+ const [instance, element] = mount(PasswordDemo);
111
+ const input = element.querySelector<HTMLInputElement>('input')!;
112
+ const icon = element.querySelector<HTMLElement>('.k-icon')!;
113
+ const inputInstance = instance.refs.__demo as Input;
114
+
115
+ icon.click();
116
+ await wait();
117
+ expect(input.type).to.eql('text');
118
+ expect(element.innerHTML).to.matchSnapshot();
119
+
120
+ icon.click();
121
+ await wait();
122
+ expect(input.type).to.eql('password');
123
+ expect(element.innerHTML).to.matchSnapshot();
124
+
125
+ // simulate receive type
126
+ inputInstance.$props.type = 'number';
127
+ (inputInstance as any).trigger('$receive:type', 'number');
128
+ await wait();
129
+ expect(input.type).to.eql('number');
130
+ expect(icon.parentElement!.parentElement).to.eql(null);
131
+ expect(element.innerHTML).to.matchSnapshot();
132
+
133
+ // simulate receive showPassword
134
+ inputInstance.$props.type = 'password';
135
+ inputInstance.$props.showPassword = false;
136
+ (inputInstance as any).trigger('$receive:type', 'password');
137
+ (inputInstance as any).trigger('$receive:showPassword', false);
138
+ await wait();
139
+ expect(input.type).to.eql('password');
140
+ expect(element.querySelector<HTMLElement>('.k-icon')).to.eql(null);
141
+ expect(element.innerHTML).to.matchSnapshot();
142
+ });
143
+
144
+ it('should set width when dialog show and input mounted', async () => {
145
+ class Demo extends Component<{show: boolean}> {
146
+ static template = `
147
+ var Dialog = this.Dialog;
148
+ var Input = this.Input;
149
+ <Dialog value={this.get('show')}>
150
+ <Input autoWidth placeholder="test" v-if={this.get('show')} />
151
+ </Dialog>
152
+ `;
153
+ static defaults() {
154
+ return {
155
+ show: false,
156
+ };
157
+ }
158
+ private Dialog = Dialog;
159
+ private Input = Input;
160
+ }
161
+
162
+ const [instance] = mount(Demo);
163
+ instance.set('show', true);
164
+ await wait(50);
165
+ const dialog = getElement('.k-dialog')!;
166
+ const width = parseInt(dialog.querySelector<HTMLInputElement>('.k-input-inner')!.style.width);
167
+ expect(width).to.gt(1);
168
+ });
73
169
  });
@@ -6,9 +6,11 @@ import {isNullOrUndefined, EMPTY_OBJ} from 'intact-shared';
6
6
  import {useAutoWidth} from './useAutoWidth';
7
7
  import {useFrozen} from './useFrozen';
8
8
  import {CommonInputHTMLAttributes, Events} from '../types';
9
+ import {useAutoRows} from './useAutoRows';
10
+ import { useShowPassword } from './useShowPassword';
9
11
  export * from './search';
10
12
 
11
- type HTMLInputTypes =
13
+ export type HTMLInputTypes =
12
14
  | 'textarea' // for textarea
13
15
  | 'button'
14
16
  | 'checkbox'
@@ -56,7 +58,7 @@ export interface InputProps<V extends Value = Value> extends InputHTMLAttributes
56
58
  clearable?: boolean
57
59
  disabled?: boolean
58
60
  size?: Sizes
59
- rows?: string | number
61
+ rows?: string | number | 'auto' | AutoRows
60
62
  autoWidth?: boolean
61
63
  fluid?: boolean
62
64
  width?: number | string
@@ -64,8 +66,15 @@ export interface InputProps<V extends Value = Value> extends InputHTMLAttributes
64
66
  frozenOnInput?: boolean
65
67
  inline?: boolean
66
68
  waveDisabled?: boolean
69
+ resize?: 'none' | 'vertical' | 'horizontal' | 'both'
70
+ showPassword?: boolean
67
71
  }
68
72
 
73
+ export type AutoRows = {
74
+ min?: number
75
+ max?: number
76
+ }
77
+
69
78
  export interface InputEvents {
70
79
  clear: [MouseEvent]
71
80
  focus: [FocusEvent]
@@ -89,7 +98,7 @@ const typeDefs: Required<TypeDefs<Omit<InputProps, keyof InputHTMLAttributes>>>
89
98
  clearable: Boolean,
90
99
  disabled: Boolean,
91
100
  size: sizes,
92
- rows: [String, Number],
101
+ rows: [String, Number, 'auto', Object],
93
102
  autoWidth: Boolean,
94
103
  fluid: Boolean,
95
104
  width: [Number, String],
@@ -97,12 +106,15 @@ const typeDefs: Required<TypeDefs<Omit<InputProps, keyof InputHTMLAttributes>>>
97
106
  frozenOnInput: Boolean,
98
107
  inline: Boolean,
99
108
  waveDisabled: Boolean,
109
+ resize: ['none', 'vertical', 'horizontal', 'both'],
110
+ showPassword: Boolean,
100
111
  }
101
112
 
102
113
  const defaults = (): Partial<InputProps> => ({
103
114
  type: 'text', // text | textarea
104
115
  size: 'default',
105
116
  rows: 2,
117
+ resize: 'vertical',
106
118
  });
107
119
 
108
120
  const events: Events<InputEvents> = {
@@ -121,6 +133,8 @@ export class Input<V extends Value = Value> extends Component<InputProps<V>, Inp
121
133
  private inputRef = createRef<HTMLInputElement>();
122
134
  private autoWidth = useAutoWidth();
123
135
  private frozen = useFrozen();
136
+ private autoRows = useAutoRows(this.inputRef);
137
+ private showPassword = useShowPassword();
124
138
 
125
139
  focus() {
126
140
  this.inputRef.value!.focus();
@@ -1,7 +1,7 @@
1
1
  import {Icon} from '../icon';
2
2
  import {addStyle, isTextBlock, getRestProps} from '../utils';
3
3
  import {makeStyles} from './styles';
4
- import {noop, isNullOrUndefined} from 'intact-shared';
4
+ import {noop, isNullOrUndefined, isStringOrNumber} from 'intact-shared';
5
5
  import {Wave} from '../wave';
6
6
  import {context as ErrorContext} from '../form/useError';
7
7
 
@@ -9,7 +9,7 @@ const {
9
9
  className, style, type, value, defaultValue, placeholder,
10
10
  clearable, disabled, size, rows, autoWidth, fluid,
11
11
  width, stackClearIcon, frozenOnInput, readonly, inline,
12
- waveDisabled,
12
+ waveDisabled, resize,
13
13
 
14
14
  'ev-click': click,
15
15
  'ev-mounseenter': mouseenter,
@@ -24,6 +24,8 @@ const {
24
24
  startInput, onInput, endInput
25
25
  } = this.frozen;
26
26
 
27
+ const isNotAutoRows = isStringOrNumber(rows) && rows !== 'auto';
28
+
27
29
  const classNameObj = {
28
30
  'k-input': true,
29
31
  [`k-${size}`]: size !== 'default',
@@ -36,11 +38,21 @@ const classNameObj = {
36
38
  'k-fluid': fluid,
37
39
  'k-stack-clear': stackClearIcon,
38
40
  'k-inline': inline,
41
+ [`k-resize-${resize}`]: type === 'textarea' && isNotAutoRows,
42
+ [`k-resize-none`]: type === 'textarea' && !isNotAutoRows,
39
43
  [className]: className,
40
44
  [makeStyles()]: true,
41
45
  }
42
46
 
47
+ const {
48
+ isShow: isShowPassword,
49
+ toggleShow: toggleShowPassword,
50
+ type: showPasswordType,
51
+ showIcon: showPasswordIcon,
52
+ } = this.showPassword;
53
+
43
54
  const {fakeRef, width: {value: fakeWidth}} = this.autoWidth;
55
+ const height = this.autoRows;
44
56
 
45
57
  const inputValue = frozenOnInput && inputing ? originalValue : value;
46
58
  const hasInputValue = !isNullOrUndefined(inputValue);
@@ -55,7 +67,7 @@ const inputProps = {
55
67
  placeholder,
56
68
  disabled,
57
69
  ref: this.inputRef,
58
- style: autoWidth ? {width: fakeWidth + 'px'} : undefined,
70
+ style: autoWidth && fakeWidth ? {width: fakeWidth + 'px'} : undefined,
59
71
  };
60
72
  // if we pass value to input element, the input is controlled and the
61
73
  // defaultValue does not work
@@ -90,14 +102,25 @@ if (hasInputValue) {
90
102
  <input v-if={type !== 'textarea'}
91
103
  {...inputProps}
92
104
  class="k-input-inner"
93
- type={type}
105
+ type={showPasswordType.value}
94
106
  />
95
107
  <textarea v-else
96
108
  {...inputProps}
97
109
  class="k-input-inner k-textarea"
98
- rows={rows}
110
+ rows={isNotAutoRows ? rows : 1}
111
+ style={height.value ? addStyle(inputProps.style, { height: height.value + 'px' }) : inputProps.style}
99
112
  ></textarea>
100
- <div class="k-input-suffix" v-if={$blocks.suffix || clearable && !disabled}>
113
+ <div class="k-input-suffix" v-if={$blocks.suffix || clearable && !disabled || showPasswordIcon.value}>
114
+ <template v-if={showPasswordIcon.value}>
115
+ <Icon hoverable
116
+ class={{
117
+ "k-input-show-password": true,
118
+ "ion-eye-disabled": !isShowPassword.value,
119
+ "ion-eye": isShowPassword.value,
120
+ }}
121
+ ev-click={toggleShowPassword}
122
+ />{' '}
123
+ </template>
101
124
  <Icon v-if={clearable && !disabled}
102
125
  class={{
103
126
  "k-input-clear ion-ios-close": true,
@@ -2,6 +2,7 @@ import {css} from '@emotion/css';
2
2
  import {theme, setDefault} from '../../styles/theme';
3
3
  import {deepDefaults, sizes, Sizes} from '../../styles/utils';
4
4
  import '../../styles/global';
5
+ import {Input} from './';
5
6
 
6
7
  const defaults = deepDefaults(
7
8
  {
@@ -24,7 +25,7 @@ const defaults = deepDefaults(
24
25
  clearIconGap: '3px',
25
26
 
26
27
  // textarea
27
- get textareaPadding() { return `5px ${input.paddingGap}` },
28
+ get textareaPadding() { return `6px ${input.paddingGap}` },
28
29
 
29
30
  // group
30
31
  get groupBgColor() { return theme.color.bg },
@@ -129,6 +130,11 @@ export function makeStyles() {
129
130
  pointer-events: all;
130
131
  }
131
132
 
133
+ // show password
134
+ .k-input-show-password {
135
+ color: ${input.clearIconColor};
136
+ }
137
+
132
138
  // stack clear icon
133
139
  &.k-stack-clear {
134
140
  .k-input-clear {
@@ -282,6 +288,15 @@ export function makeStyles() {
282
288
  line-height: 1.5;
283
289
  vertical-align: top;
284
290
  }
291
+ ${(Input.typeDefs.resize as string[]).map(type => {
292
+ return css`
293
+ &.k-resize-${type} {
294
+ .k-textarea {
295
+ resize: ${type};
296
+ }
297
+ }
298
+ `
299
+ })}
285
300
 
286
301
  // fake dom for get value's width
287
302
  .k-input-fake {
@@ -292,7 +307,9 @@ export function makeStyles() {
292
307
  }
293
308
  &.k-auto-width {
294
309
  width: auto;
310
+ max-width: 100%;
295
311
  .k-input-inner {
312
+ max-width: 100%;
296
313
  box-sizing: content-box;
297
314
  }
298
315
  }
@@ -0,0 +1,65 @@
1
+ import {useInstance, createRef, onMounted, RefObject, watch} from 'intact';
2
+ import type {Input} from './';
3
+ import {useState} from '../../hooks/useState';
4
+ import { isObject } from 'intact-shared';
5
+
6
+ export function useAutoRows(inputRef: RefObject<HTMLInputElement>) {
7
+ const instance = useInstance() as Input;
8
+ const height = useState<number>(0);
9
+
10
+ let lineHeight: number;
11
+ let paddingTop: number;
12
+ let paddingBottom: number;
13
+ let isBorderBox: boolean;
14
+
15
+ function getStyles() {
16
+ if (instance.get('type') === 'textarea') {
17
+ const styles = getComputedStyle(inputRef.value!);
18
+
19
+ lineHeight = parseInt(styles.lineHeight);
20
+ paddingTop = parseInt(styles.paddingTop);
21
+ paddingBottom = parseInt(styles.paddingBottom);
22
+ isBorderBox = styles.boxSizing === 'border-box';
23
+ }
24
+ }
25
+
26
+ onMounted(getStyles);
27
+ instance.watch('type', getStyles, { presented: true });
28
+
29
+ instance.watch('value', adjust, {inited: true, presented: true});
30
+ instance.watch('placeholder', adjust, {inited: true, presented: true});
31
+ instance.watch('rows', adjust, {inited: true, presented: true});
32
+ onMounted(adjust);
33
+
34
+ function adjust() {
35
+ const { rows, type } = instance.get();
36
+ if (type === 'textarea' && (rows === 'auto' || isObject(rows))) {
37
+ const textarea = inputRef.value!;
38
+ const originheight = textarea.style.height;
39
+ // we shuold remove height before get scrollHeight,
40
+ // otherwise we cannot shrink the height when we remove the text
41
+ textarea.style.height = '';
42
+ const scrollHeight = textarea.scrollHeight;
43
+ const lines = (scrollHeight - paddingTop - paddingBottom) / lineHeight;
44
+ textarea.style.height = originheight;
45
+
46
+ let actualLines = lines;
47
+ if (rows !== 'auto') {
48
+ const { min, max } = rows;
49
+ if (min && lines <= min) {
50
+ actualLines = min;
51
+ }
52
+ if (max && lines >= max) {
53
+ actualLines = max;
54
+ }
55
+ }
56
+ height.set(lineHeight * actualLines + (isBorderBox ? paddingTop + paddingBottom + 2 /* border */ : 0));
57
+
58
+ return;
59
+ }
60
+
61
+ height.set(0);
62
+ }
63
+
64
+ return height;
65
+ }
@@ -1,4 +1,4 @@
1
- import {useInstance, createRef, onMounted} from 'intact';
1
+ import {useInstance, createRef, onMounted, nextTick} from 'intact';
2
2
  import type {Input} from './';
3
3
  import {useState} from '../../hooks/useState';
4
4
 
@@ -13,10 +13,19 @@ export function useAutoWidth() {
13
13
 
14
14
  function adjustWidth() {
15
15
  if (instance.get('autoWidth')) {
16
- const _width = fakeRef.value!.offsetWidth || 1;
17
- width.set(_width);
16
+ nextTick(() => {
17
+ const fakeElem = fakeRef.value;
18
+ if (isVisible(fakeElem)) {
19
+ const _width = fakeElem!.offsetWidth || 1;
20
+ width.set(_width);
21
+ }
22
+ });
18
23
  }
19
24
  }
20
25
 
21
26
  return {fakeRef, width};
22
27
  }
28
+
29
+ function isVisible(elem: HTMLDivElement | null) {
30
+ return elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
31
+ }
@@ -0,0 +1,27 @@
1
+ import {useInstance, createRef, onMounted, RefObject, watch} from 'intact';
2
+ import type {Input, HTMLInputTypes} from './';
3
+ import {useState} from '../../hooks/useState';
4
+ import { useReceive } from '../../hooks/useReceive';
5
+
6
+ export function useShowPassword() {
7
+ const instance = useInstance() as Input;
8
+ const isShow = useState(false);
9
+ const type = useState<HTMLInputTypes | undefined>(undefined);
10
+ const showIcon = useState(false);
11
+
12
+ instance.on('$receive:type', (_type) => {
13
+ type.set(_type);
14
+ });
15
+
16
+ useReceive<Input>(['type', 'showPassword'], () => {
17
+ const { showPassword, type } = instance.get();
18
+ showIcon.set(type === 'password' && !!showPassword);
19
+ });
20
+
21
+ function toggleShow() {
22
+ isShow.set(!isShow.value);
23
+ type.set(isShow.value ? 'text' : 'password');
24
+ }
25
+
26
+ return { isShow, type, toggleShow, showIcon };
27
+ }
@@ -5,7 +5,7 @@ import DisableDemo from '~/components/pagination/demos/disable';
5
5
  import {mount, unmount, dispatchEvent, wait} from '../../test/utils';
6
6
 
7
7
  describe('Pagination', () => {
8
- afterEach(() => unmount());
8
+ // afterEach(() => unmount());
9
9
 
10
10
  it('basic test', async () => {
11
11
  const [instance, element] = mount(BasicDemo);
@@ -100,8 +100,7 @@ export class Pagination extends Component<PaginationProps, PaginationEvents> {
100
100
 
101
101
  if (page > totalPages) {
102
102
  page = totalPages;
103
- }
104
- if (page < 1) {
103
+ } else if (page < 1) {
105
104
  page = 1;
106
105
  }
107
106
 
@@ -46,7 +46,7 @@ export class Portal<T extends PortalProps = PortalProps> extends Component<T> {
46
46
  nextVNode: VNodeComponentClass<this>,
47
47
  parentDom: Element,
48
48
  anchor: IntactDom | null,
49
- mountedQueue: Function[]
49
+ mountedQueue: Function[] & { priority?: Function[] } // in React, it has priority property to add some prior functions
50
50
  ) {
51
51
  /**
52
52
  * In React, we cannot render real elements in mountedQueue.
@@ -56,7 +56,7 @@ export class Portal<T extends PortalProps = PortalProps> extends Component<T> {
56
56
  const nextProps = nextVNode.props!;
57
57
  const fakeContainer = document.createDocumentFragment();
58
58
 
59
- mountedQueue.push(() => {
59
+ (mountedQueue.priority || mountedQueue).push(() => {
60
60
  const parentDom = this.$lastInput!.dom!.parentElement!;
61
61
  this.initContainer(nextProps.container, parentDom, anchor);
62
62
  this.container!.appendChild(fakeContainer);
@@ -79,7 +79,7 @@ export class Portal<T extends PortalProps = PortalProps> extends Component<T> {
79
79
  nextVNode: VNodeComponentClass<this>,
80
80
  parentDom: Element,
81
81
  anchor: IntactDom | null,
82
- mountedQueue: Function[],
82
+ mountedQueue: Function[] & { priority?: Function[] },
83
83
  force: boolean,
84
84
  ) {
85
85
  // update container if it has changed
@@ -121,7 +121,7 @@ export class Portal<T extends PortalProps = PortalProps> extends Component<T> {
121
121
 
122
122
  if (!this.container) {
123
123
  // in react, sometimes $update will be called before mountedQueue in $render
124
- mountedQueue.push(update);
124
+ (mountedQueue.priority || mountedQueue).push(update);
125
125
  } else {
126
126
  update();
127
127
  }
@@ -1,3 +1,5 @@
1
+ import { isArray } from 'intact-shared';
2
+
1
3
  export type Options = {
2
4
  of?: Window | HTMLElement | Document | MouseEvent
3
5
  at?: string | [string, string]
@@ -265,7 +267,9 @@ export default function position(elem: HTMLElement, options: Options) {
265
267
  } = getDimensions(target);
266
268
  const basePosition = Object.assign({}, targetOffset);
267
269
  // don't detect collison if the target is not in viewport
268
- const collision = isInViewport(targetRect) ? (options.collision as string || 'flip').split(' ') : ['none', 'none'];
270
+ const collision = isInViewport(targetRect)
271
+ ? (!isArray(options.collision) ? (options.collision || 'flip').split(' ') : options.collision)
272
+ : ['none', 'none'];
269
273
  const offsets = {} as {my: [string, string], at: [string, string]};
270
274
  const within = getWithinInfo(options.within);
271
275
  const scrollInfo = getScrollInfo(within);
@@ -12,7 +12,7 @@ import {SELECT} from './constants';
12
12
  import type {Input} from '../input';
13
13
  import {useShowHideEvents} from '../../hooks/useShowHideEvents';
14
14
  import {bind} from '../utils';
15
- import {Dropdown} from '../dropdown';
15
+ import {Dropdown, DropdownProps} from '../dropdown';
16
16
  import {State} from '../../hooks/useState';
17
17
  import {useInput} from './useInput';
18
18
  import {Container} from '../portal';
@@ -36,6 +36,7 @@ export interface BaseSelectProps<V, Multipe extends boolean = boolean, Attach =
36
36
  container?: Container
37
37
  width?: string | number
38
38
  show?: boolean
39
+ position?: DropdownProps['position']
39
40
  }
40
41
 
41
42
  export interface BaseSelectEvents {
@@ -68,6 +69,7 @@ const typeDefs: Required<TypeDefs<BaseSelectProps<any>>> = {
68
69
  container: [Function, String],
69
70
  width: [String, Number],
70
71
  show: Boolean,
72
+ position: Dropdown.typeDefs.position,
71
73
  };
72
74
 
73
75
  const defaults = (): Partial<BaseSelectProps<any>> => ({
@@ -15,6 +15,7 @@ const {
15
15
  clearable, filterable,
16
16
  className, container,
17
17
  inline, style, width, show,
18
+ position,
18
19
  } = this.get();
19
20
 
20
21
  const classNameObj = {
@@ -43,6 +44,7 @@ const {onFocusout, triggerRef} = this.focusout;
43
44
  disabled={disabled}
44
45
  container={container}
45
46
  v-model="show"
47
+ position={position}
46
48
  >
47
49
  <div {...getRestProps(this)}
48
50
  class={classNameObj}
@@ -32,8 +32,18 @@ sidebar: doc
32
32
  | card | 是否展示`card`模式 | `boolean` | `false` |
33
33
  | autoDisableArrow | 是否在没有更多可选项时,给箭头一个`disabled`状态来提示用户 | `boolean` | `false` |
34
34
  | show | 是否展示菜单项 | `boolean` | `false` |
35
+ | position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
35
36
 
36
37
  ```ts
38
+ type Position = {
39
+ my?: string | [string, string]
40
+ at?: string | [string, string]
41
+ collision?: Collision | [Collision, Collision]
42
+ collisionDirection?: ['left'] | ['top'] | ['left', 'top']
43
+ }
44
+
45
+ type Collision = 'fit' | 'flip' | 'flipfit' | 'none'
46
+
37
47
  export type Container = string | ((parentDom: Element, anchor: Node | null) => Element)
38
48
  ```
39
49
 
@@ -60,7 +70,7 @@ export type Container = string | ((parentDom: Element, anchor: Node | null) => E
60
70
  | --- | --- | --- |
61
71
  | value | 自定义选择结果的展示 | `([value: any, label: Children]) => Children` |
62
72
  | values | 自定义多选的选择结果的展示 | `([values: any[], labels: Children[]]) => Children` |
63
- | prefix | 自定义输入款前面展示的内容 | - |
73
+ | prefix | 自定义输入框前面展示的内容 | - |
64
74
  | suffix | 自定义输入框后面展示的内容 | - |
65
75
  | menu | 自定义整个菜单的内容 | - |
66
76
 
@@ -35,11 +35,10 @@ export class TableCell extends Component<TableCellProps> {
35
35
 
36
36
  let isSame = true;
37
37
  for (const key in lastProps) {
38
- if (lastProps[key] !== nextProps[key]) {
39
- isSame = false;
40
- break;
41
- }
42
- if (key === 'props' && nextProps.props.$blocks) {
38
+ if (
39
+ lastProps[key] !== nextProps[key] ||
40
+ key === 'props' && nextProps.props.$blocks
41
+ ) {
43
42
  isSame = false;
44
43
  break;
45
44
  }
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: 隐藏表头
3
+ order: 29
4
+ ---
5
+
6
+ 添加`hideHeader`属性,即可隐藏表头
7
+
8
+ ```vdt
9
+ import {Table, TableColumn, Switch} from 'kpc';
10
+
11
+ <div>
12
+ <p>hideHeader: <Switch v-model="hideHeader" /></p>
13
+ <Table data={this.get('data')} resizable hideHeader={this.get('hideHeader')}>
14
+ <TableColumn key="a" title="Title 1" />
15
+ <TableColumn key="b" title="Title 2" />
16
+ </Table>
17
+ </div>
18
+ ```
19
+
20
+ ```ts
21
+ export default class extends Component {
22
+ static template = template;
23
+ static defaults() {
24
+ return {
25
+ data: [
26
+ {a: 'Cell 1-1', b: 'Cell 1-2'},
27
+ {a: 'Cell 2-1', b: 'Cell 2-2'}
28
+ ],
29
+ hideHeader: true,
30
+ };
31
+ }
32
+ }
33
+ ```