@king-design/intact 3.6.0-beta.0 → 3.6.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 (171) hide show
  1. package/components/.DS_Store +0 -0
  2. package/components/cascader/index.spec.ts +7 -6
  3. package/components/datepicker/basepicker.ts +26 -314
  4. package/components/datepicker/calendar.ts +3 -1
  5. package/components/datepicker/calendar.vdt +5 -2
  6. package/components/datepicker/dayjs.ts +2 -16
  7. package/components/datepicker/demos/multiple.md +5 -0
  8. package/components/datepicker/demos/yearMonth.md +2 -8
  9. package/components/datepicker/helpers.ts +5 -7
  10. package/components/datepicker/index.md +1 -2
  11. package/components/datepicker/index.spec.ts +551 -139
  12. package/components/datepicker/index.ts +16 -33
  13. package/components/datepicker/index.vdt +41 -35
  14. package/components/datepicker/shortcuts.ts +1 -1
  15. package/components/datepicker/styles.ts +27 -18
  16. package/components/datepicker/useConfirm.ts +82 -0
  17. package/components/datepicker/useDisabled.ts +29 -31
  18. package/components/datepicker/useFormats.ts +8 -4
  19. package/components/datepicker/useHighlight.ts +81 -0
  20. package/components/datepicker/useKeyboards.ts +2 -1
  21. package/components/datepicker/useMergeRange.ts +12 -12
  22. package/components/datepicker/useMonths.ts +6 -3
  23. package/components/datepicker/usePanel.ts +19 -19
  24. package/components/datepicker/useShowDate.ts +21 -41
  25. package/components/datepicker/useStatus.ts +34 -15
  26. package/components/datepicker/useValue.ts +43 -72
  27. package/components/datepicker/useValueBase.ts +309 -0
  28. package/components/datepicker/useWeeks.ts +1 -1
  29. package/components/datepicker/useYears.ts +7 -3
  30. package/components/descriptions/.DS_Store +0 -0
  31. package/components/dropdown/dropdown.ts +5 -4
  32. package/components/dropdown/index.md +1 -0
  33. package/components/dropdown/item.ts +1 -1
  34. package/components/dropdown/useKeyboard.ts +0 -1
  35. package/components/input/index.spec.ts +42 -0
  36. package/components/input/index.ts +8 -0
  37. package/components/input/index.vdt +3 -4
  38. package/components/input/useAutoWidth.ts +19 -1
  39. package/components/menu/.DS_Store +0 -0
  40. package/components/menu/demos/.DS_Store +0 -0
  41. package/components/scrollSelect/useMouseEvents.ts +5 -4
  42. package/components/select/base.ts +3 -2
  43. package/components/select/base.vdt +2 -1
  44. package/components/select/demos/creatable.md +2 -2
  45. package/components/select/index.md +1 -1
  46. package/components/select/index.spec.ts +107 -34
  47. package/components/select/option.ts +2 -1
  48. package/components/select/select.ts +1 -0
  49. package/components/select/styles.ts +3 -1
  50. package/components/select/useInput.ts +5 -9
  51. package/components/table/.DS_Store +0 -0
  52. package/components/table/index.spec.ts +69 -1
  53. package/components/table/useStickyHeader.ts +1 -1
  54. package/components/timepicker/index.spec.ts +145 -27
  55. package/components/timepicker/panelPicker.ts +10 -4
  56. package/components/timepicker/panelPicker.vdt +3 -5
  57. package/components/timepicker/styles.ts +1 -0
  58. package/components/timepicker/useConfirm.ts +33 -0
  59. package/components/timepicker/useDefaultValue.ts +30 -0
  60. package/components/timepicker/useDisabled.ts +17 -4
  61. package/components/timepicker/useFormats.ts +1 -1
  62. package/components/timepicker/useValue.ts +22 -19
  63. package/components/tour/.DS_Store +0 -0
  64. package/components/tour/index.spec.ts +1 -1
  65. package/components/virtualList/.DS_Store +0 -0
  66. package/components/virtualList/demos/.DS_Store +0 -0
  67. package/es/components/cascader/index.spec.js +18 -19
  68. package/es/components/datepicker/basepicker.d.ts +6 -27
  69. package/es/components/datepicker/basepicker.js +23 -268
  70. package/es/components/datepicker/calendar.d.ts +4 -2
  71. package/es/components/datepicker/dayjs.d.ts +2 -13
  72. package/es/components/datepicker/helpers.d.ts +3 -2
  73. package/es/components/datepicker/helpers.js +2 -3
  74. package/es/components/datepicker/index.d.ts +21 -29
  75. package/es/components/datepicker/index.js +22 -32
  76. package/es/components/datepicker/index.spec.js +1333 -578
  77. package/es/components/datepicker/index.vdt.js +39 -38
  78. package/es/components/datepicker/shortcuts.d.ts +1 -1
  79. package/es/components/datepicker/styles.d.ts +7 -2
  80. package/es/components/datepicker/styles.js +10 -15
  81. package/es/components/datepicker/useConfirm.d.ts +6 -0
  82. package/es/components/datepicker/useConfirm.js +65 -0
  83. package/es/components/datepicker/useDisabled.d.ts +5 -3
  84. package/es/components/datepicker/useDisabled.js +22 -27
  85. package/es/components/datepicker/useFormats.d.ts +2 -2
  86. package/es/components/datepicker/useFormats.js +6 -2
  87. package/es/components/datepicker/useHighlight.d.ts +14 -0
  88. package/es/components/datepicker/useHighlight.js +60 -0
  89. package/es/components/datepicker/useKeyboards.js +2 -1
  90. package/es/components/datepicker/useMergeRange.d.ts +1 -1
  91. package/es/components/datepicker/useMergeRange.js +11 -16
  92. package/es/components/datepicker/useMonths.js +5 -3
  93. package/es/components/datepicker/usePanel.d.ts +1 -10
  94. package/es/components/datepicker/usePanel.js +19 -32
  95. package/es/components/datepicker/useShowDate.d.ts +1 -1
  96. package/es/components/datepicker/useShowDate.js +15 -40
  97. package/es/components/datepicker/useStatus.js +33 -16
  98. package/es/components/datepicker/useValue.d.ts +11 -6
  99. package/es/components/datepicker/useValue.js +49 -69
  100. package/es/components/datepicker/useValueBase.d.ts +28 -0
  101. package/es/components/datepicker/useValueBase.js +277 -0
  102. package/es/components/datepicker/useYears.js +6 -3
  103. package/es/components/dropdown/dropdown.d.ts +1 -0
  104. package/es/components/dropdown/dropdown.js +7 -4
  105. package/es/components/input/index.d.ts +2 -0
  106. package/es/components/input/index.js +6 -0
  107. package/es/components/input/index.spec.js +45 -0
  108. package/es/components/input/index.vdt.js +4 -3
  109. package/es/components/input/useAutoWidth.d.ts +2 -0
  110. package/es/components/input/useAutoWidth.js +19 -1
  111. package/es/components/scrollSelect/useMouseEvents.js +5 -4
  112. package/es/components/select/base.d.ts +1 -1
  113. package/es/components/select/base.js +3 -2
  114. package/es/components/select/base.vdt.js +4 -3
  115. package/es/components/select/index.spec.js +158 -84
  116. package/es/components/select/option.js +2 -1
  117. package/es/components/select/select.js +2 -1
  118. package/es/components/select/styles.d.ts +79 -0
  119. package/es/components/select/styles.js +1 -0
  120. package/es/components/select/useInput.d.ts +1 -1
  121. package/es/components/select/useInput.js +4 -4
  122. package/es/components/table/index.spec.js +84 -6
  123. package/es/components/table/useStickyHeader.js +1 -1
  124. package/es/components/timepicker/index.spec.js +298 -128
  125. package/es/components/timepicker/panelPicker.d.ts +21 -16
  126. package/es/components/timepicker/panelPicker.js +7 -4
  127. package/es/components/timepicker/panelPicker.vdt.js +5 -9
  128. package/es/components/timepicker/selectPicker.d.ts +4 -3
  129. package/es/components/timepicker/styles.js +1 -1
  130. package/es/components/timepicker/useConfirm.d.ts +6 -0
  131. package/es/components/timepicker/useConfirm.js +19 -0
  132. package/es/components/timepicker/useDefaultValue.d.ts +4 -0
  133. package/es/components/timepicker/useDefaultValue.js +27 -0
  134. package/es/components/timepicker/useDisabled.d.ts +6 -3
  135. package/es/components/timepicker/useDisabled.js +13 -4
  136. package/es/components/timepicker/useFormats.d.ts +1 -1
  137. package/es/components/timepicker/useValue.d.ts +13 -8
  138. package/es/components/timepicker/useValue.js +14 -15
  139. package/es/components/tour/index.spec.js +1 -1
  140. package/es/index.d.ts +2 -2
  141. package/es/index.js +2 -2
  142. package/es/site/data/components/datepicker/demos/multiple/index.d.ts +1 -0
  143. package/es/site/data/components/datepicker/demos/multiple/index.js +2 -1
  144. package/es/site/data/components/datepicker/demos/multiple/react.d.ts +1 -0
  145. package/es/site/data/components/datepicker/demos/multiple/react.js +13 -2
  146. package/es/site/data/components/datepicker/demos/yearMonth/index.d.ts +0 -2
  147. package/es/site/data/components/datepicker/demos/yearMonth/index.js +1 -3
  148. package/es/site/data/components/datepicker/demos/yearMonth/react.d.ts +0 -2
  149. package/es/site/data/components/datepicker/demos/yearMonth/react.js +1 -21
  150. package/es/site/data/components/select/demos/creatable/react.js +2 -2
  151. package/es/site/data/components/select/demos/searchable/index.js +1 -1
  152. package/es/site/data/components/select/demos/searchable/react.js +1 -1
  153. package/es/site/data/components/tour/demos/customText/index.d.ts +19 -6
  154. package/es/site/data/components/tour/demos/customText/index.js +18 -17
  155. package/es/site/data/components/tour/demos/customText/react.d.ts +20 -6
  156. package/es/site/data/components/tour/demos/customText/react.js +31 -27
  157. package/index.ts +2 -2
  158. package/package.json +2 -2
  159. package/styles/.DS_Store +0 -0
  160. package/components/datepicker/demos/nowrap.md +0 -35
  161. package/components/datepicker/usePosition.ts +0 -169
  162. package/es/components/datepicker/usePosition.d.ts +0 -10
  163. package/es/components/datepicker/usePosition.js +0 -166
  164. package/es/site/data/components/datepicker/demos/nowrap/index.d.ts +0 -10
  165. package/es/site/data/components/datepicker/demos/nowrap/index.js +0 -19
  166. package/es/site/data/components/datepicker/demos/nowrap/react.d.ts +0 -10
  167. package/es/site/data/components/datepicker/demos/nowrap/react.js +0 -49
  168. package/es/site/data/components/tour/demos/customButtons/index.d.ts +0 -33
  169. package/es/site/data/components/tour/demos/customButtons/index.js +0 -55
  170. package/es/site/data/components/tour/demos/customButtons/react.d.ts +0 -33
  171. package/es/site/data/components/tour/demos/customButtons/react.js +0 -99
@@ -0,0 +1,309 @@
1
+ import {useInstance, Component, TypeDefs} from 'intact';
2
+ import {useState, watchState, State} from '../../hooks/useState';
3
+ import dayjs, {Dayjs, OpUnitType, QUnitType} from './dayjs';
4
+ import {findValueIndex} from './helpers';
5
+ import type {useFormats} from './useFormats';
6
+ import type {useDisabled} from './useDisabled';
7
+ import {isEqualArray, last, bind} from '../utils';
8
+ import {PanelFlags, usePanel} from './usePanel';
9
+ import type {BasePicker, BasePickerProps} from './basepicker';
10
+
11
+ export type Value = string | Date | number | Dayjs;
12
+
13
+ export type StateValueRange = [Dayjs] | [Dayjs, Dayjs];
14
+ export type StateValueItem = Dayjs | StateValueRange;
15
+ export type StateValue = StateValueItem[]
16
+
17
+ export type StringValue = string | string[] | [string, string] | [string, string][]
18
+ export type DayjsValueRange = [Dayjs, Dayjs]
19
+ export type DayjsValueItem = Dayjs | DayjsValueRange
20
+ export type DayjsValue = DayjsValueItem[]
21
+
22
+ export function useValueBase(
23
+ {
24
+ createDateByValueFormat,
25
+ createDateByShowFormat,
26
+ getShowString,
27
+ getValueString,
28
+ }: ReturnType<typeof useFormats>,
29
+ {isDisabled, minDate}: ReturnType<typeof useDisabled>,
30
+ panel: ReturnType<typeof usePanel>,
31
+ shouldUpdateValue: (v: StateValueItem) => boolean,
32
+ updateValueOnInput: (v: DayjsValueItem) => void,
33
+ getEqualType: () => OpUnitType | QUnitType,
34
+ updateStateValue: (v: DayjsValue, value: State<StateValue>) => void,
35
+ ) {
36
+ // Normalize the value to multipe values, no matter it's multipe or not
37
+ const value = useState<StateValue>([]);
38
+ const instance = useInstance() as BasePicker<BasePickerProps<Value>>;
39
+ let dayjsValue: DayjsValue = [];
40
+
41
+ instance.watch('value', (newValue, oldValue) => {
42
+ if (isEqualArray(newValue, oldValue)) return;
43
+ dayjsValue = convertToDayjs(newValue);
44
+ updateStateValue(dayjsValue, value);
45
+ // should update keywords
46
+ instance.resetKeywords();
47
+ });
48
+
49
+ watchState(value, (value) => {
50
+ // silently update the keywords to display the currently selected value
51
+ instance.resetKeywords(true);
52
+ /**
53
+ * the position may changed after the input break line in multipe mode
54
+ * use Macro task instead of nextTick, because it has too many Micro tasks
55
+ */
56
+ setTimeout(() => {
57
+ instance.position();
58
+ });
59
+ });
60
+ instance.on('hide', () => {
61
+ // reset the value after hiding
62
+ value.set(dayjsValue.slice(0));
63
+ });
64
+
65
+ watchState(instance.input.keywords, v => {
66
+ const {range, multiple} = instance.get();
67
+ if (!multiple && v === '') return instance.set('value', null);
68
+
69
+ if (range) {
70
+ const [start, end] = v.split(/\s*~\s*/).map(s => s.trim());
71
+ if (start && end) {
72
+ const startDate = createDateByShowFormat(start);
73
+ if (!isValidDate(startDate)) {
74
+ return;
75
+ }
76
+ const endDate = createDateByShowFormat(end);
77
+ if (!isValidDate(endDate)) {
78
+ return;
79
+ }
80
+ if (endDate.isAfter(startDate)) {
81
+ updateValueOnInput([startDate, endDate]);
82
+ } else {
83
+ updateValueOnInput([endDate, startDate]);
84
+ }
85
+ }
86
+ } else {
87
+ const date = createDateByShowFormat(v);
88
+ if (isValidDate(date)) {
89
+ updateValueOnInput(date);
90
+ }
91
+ }
92
+ });
93
+
94
+ function convertToDayjs(v: BasePickerProps<Value>['value']): DayjsValue {
95
+ if (!v || Array.isArray(v) && !v.length) return [];
96
+ const {multiple} = instance.get();
97
+ if (!multiple) {
98
+ v = [v] as any;
99
+ }
100
+ return (v as (Value | [Value, Value])[]).map(value => {
101
+ if (Array.isArray(value)) {
102
+ // range
103
+ return value.map(createDateByValueFormat);
104
+ }
105
+ return createDateByValueFormat(value);
106
+ }) as DayjsValue;
107
+ }
108
+
109
+ function convertToValueString(v: DayjsValue): StringValue | null {
110
+ const results = v.map(value => {
111
+ if (Array.isArray(value)) {
112
+ return value.map(getValueString);
113
+ }
114
+ return getValueString(value);
115
+ });
116
+
117
+ if (!instance.get('multiple')) {
118
+ return results[0] || null;
119
+ }
120
+ return results as StringValue;
121
+ }
122
+
123
+ function format(): string | string[] {
124
+ const { multiple } = instance.get();
125
+ let labelValue = value.value;
126
+ if (multiple) {
127
+ labelValue = dayjsValue;
128
+ }
129
+ const results = labelValue.map(formatSingleValue);
130
+
131
+ if (!instance.get('multiple')) {
132
+ return results[0];
133
+ }
134
+ return results;
135
+ }
136
+
137
+ function formatSingleValue(value: StateValueItem) {
138
+ if (Array.isArray(value)) {
139
+ if (value.length === 1) {
140
+ return getShowString(value[0]) + ' ~';
141
+ }
142
+ return value.map(getShowString).join(' ~ ');
143
+ }
144
+ return getShowString(value);
145
+ }
146
+
147
+ function setSingleDate(v: StateValueItem, fromInput: boolean) {
148
+ value.set([v]);
149
+ if (fromInput || shouldUpdateValue(v)) {
150
+ updateValue();
151
+ }
152
+ }
153
+
154
+ function addMultipeDate(v: StateValueItem, fromInput: boolean) {
155
+ const {range} = instance.get();
156
+ let _value = value.value as StateValueItem[];
157
+ _value = !_value ? [] : _value.slice();
158
+
159
+ if (range && (v as StateValueRange).length === 2) {
160
+ // pop the last value firstly, if it only has the start date
161
+ const lastValue = last(_value);
162
+ if (lastValue && (lastValue as StateValueRange).length < 2) {
163
+ _value.pop();
164
+ }
165
+ }
166
+
167
+ if (_value.length > dayjsValue.length) {
168
+ // remove the temporary value added by selecting time directly
169
+ _value.pop();
170
+ }
171
+
172
+ let _shouldUpdateValue = true;
173
+ if (fromInput || shouldUpdateValue(v)) {
174
+ // if select the date/year/month, then toggle the value.
175
+ // if from input, treat the value as the final value
176
+ const index = findValueIndex(_value, v, getEqualType());
177
+ if (index > -1) {
178
+ _value.splice(index, 1);
179
+ } else {
180
+ _value.push(v);
181
+ }
182
+ } else {
183
+ // select the datetime, only push the value,
184
+ // and unique the array on click confirm button
185
+ _value.push(v);
186
+ _shouldUpdateValue = false;
187
+ }
188
+
189
+ value.set(_value);
190
+
191
+ if (_shouldUpdateValue) {
192
+ updateValue();
193
+ }
194
+ }
195
+
196
+ function setValue(v: StateValueItem, fromInput: boolean) {
197
+ const multiple = instance.get('multiple');
198
+ if (multiple) {
199
+ addMultipeDate(v, fromInput);
200
+ } else {
201
+ setSingleDate(v, fromInput);
202
+ }
203
+ }
204
+
205
+ function updateValue() {
206
+ const _value = value.value as DayjsValue;
207
+ const { range } = instance.get();
208
+ if (range) {
209
+ // only fix the last value, since the others are already fixed
210
+ const lastValue = last(_value) as DayjsValueRange;
211
+ if (lastValue) {
212
+ lastValue.sort((a, b) => a.isAfter(b) ? 1 : -1);
213
+ }
214
+ }
215
+
216
+ const valueStr = convertToValueString(_value);
217
+ instance.set('value', valueStr);
218
+ instance.resetKeywords();
219
+ }
220
+
221
+ // TODO
222
+ function setMoment() {
223
+ const now = dayjs();
224
+ setValue(now, true);
225
+ instance.hide();
226
+ }
227
+
228
+ function unique() {
229
+ const _value = value.value;
230
+ const map: Record<string, true> = {};
231
+ const results: StateValue = [];
232
+ _value.forEach(value => {
233
+ let key: string;
234
+ if (Array.isArray(value)) {
235
+ key = (value as DayjsValueRange).map(getValueString).join(' ~ ');
236
+ } else {
237
+ key = getValueString(value);
238
+ }
239
+ if (!map[key]) {
240
+ map[key] = true;
241
+ results.push(value);
242
+ }
243
+ });
244
+
245
+ value.set(results);
246
+ }
247
+
248
+ function isValidDate(date: Dayjs) {
249
+ return date.isValid() && !isDisabled(date, getEqualType());
250
+ }
251
+
252
+ function onChangeTime(date: Dayjs, flag: PanelFlags) {
253
+ const {range, multiple} = instance.get();
254
+ const values = value.value.slice();
255
+ // maybe we select time directly
256
+ let lastIndex = Math.max(values.length - 1, 0);
257
+ if (allValuesUpdatedInMultipleMode()) {
258
+ // need add new value, if all value.value has updated to dayjsValue
259
+ lastIndex = values.length;
260
+ }
261
+ let _value: StateValueItem = date;
262
+
263
+ if (range) {
264
+ _value = (values as DayjsValueRange[])[lastIndex];
265
+ if (_value) {
266
+ _value = _value.slice() as DayjsValueRange;
267
+ } else {
268
+ _value = [] as unknown as DayjsValueRange;
269
+ }
270
+ _value[flag] = date;
271
+ instance.trigger('selecting', _value, false);
272
+ }
273
+
274
+ values[lastIndex] = _value;
275
+ value.set(values);
276
+ }
277
+
278
+ function getTimeValue(flag: PanelFlags): Dayjs | null | undefined {
279
+ const _value = value.value;
280
+ if (!_value.length) return null;
281
+
282
+ const {range, min} = instance.get();
283
+ const lastValue = last(_value);
284
+ return range ? (lastValue as StateValueRange)[flag] : lastValue as Dayjs;
285
+ }
286
+
287
+ function getDayjsValue() {
288
+ return dayjsValue;
289
+ }
290
+
291
+ function allValuesUpdatedInMultipleMode() {
292
+ return instance.get('multiple') && value.value.length === dayjsValue.length;
293
+ }
294
+
295
+ return {
296
+ value,
297
+ format,
298
+ formatSingleValue,
299
+ onChangeTime,
300
+ getTimeValue,
301
+ setValue,
302
+ convertToDayjs,
303
+ getDayjsValue,
304
+ unique,
305
+ setMoment,
306
+ updateValue,
307
+ allValuesUpdatedInMultipleMode,
308
+ };
309
+ }
@@ -39,7 +39,7 @@ export function useWeeks(
39
39
  isDisabled: status.isDisabled(day),
40
40
  isHover: day.isSame(focusDate.value, 'week'),
41
41
  isInRange: !isFirstOrLastDay && status.isActive(day, 'week')
42
- });
42
+ });
43
43
  }
44
44
  // 每周的数据,包括周数和7天的信息
45
45
  weeks.push({week: weekNumber, days});
@@ -55,10 +55,14 @@ export function useYears(
55
55
 
56
56
  function onClick(date: Dayjs) {
57
57
  showDate.set(date);
58
- if (instance.datepicker.get('type') !== 'year') {
59
- instance.type.set('month');
60
- } else {
58
+ const datepickerType = instance.datepicker.get('type');
59
+
60
+ if (datepickerType === 'year') {
61
61
  instance.triggerChange(date);
62
+ } else if (datepickerType === 'quarter') {
63
+ instance.type.set('quarter');
64
+ } else {
65
+ instance.type.set('month');
62
66
  }
63
67
  }
64
68
 
@@ -15,7 +15,6 @@ import {bind, isTextChildren, getRestProps} from '../utils';
15
15
  import {EMPTY_OBJ, isFunction, noop} from 'intact-shared';
16
16
  import {Options, position, Feedback} from '../position';
17
17
  import {cx} from '@emotion/css';
18
- import {DropdownMenu} from './menu';
19
18
  import {useDocumentClick, containsOrEqual} from '../../hooks/useDocumentClick';
20
19
  import {Portal, PortalProps} from '../portal';
21
20
  import {useShowHideEvents} from '../../hooks/useShowHideEvents';
@@ -40,6 +39,7 @@ export interface DropdownProps {
40
39
  collison?: Position['collision']
41
40
  of?: 'self' | 'parent' | Event
42
41
  container?: PortalProps['container']
42
+ alwaysShowOnClick?: boolean
43
43
  }
44
44
 
45
45
  export interface DropdownEvents {
@@ -64,6 +64,7 @@ const typeDefs: Required<TypeDefs<DropdownProps>> = {
64
64
  of: ['self', 'parent', typeof Event === 'undefined' ? undefined : Event],
65
65
  container: [String, Function],
66
66
  collison: ['none', 'fit', 'flip', 'flipfit', Array],
67
+ alwaysShowOnClick: Boolean,
67
68
  };
68
69
 
69
70
  const defaults = (): Partial<DropdownProps> => ({
@@ -266,15 +267,15 @@ function useDocumentClickForDropdown(dropdown: Dropdown) {
266
267
  // case 2: if right click on a trigger and its trigger type is contextmenu, ignore it
267
268
  // case 3: if click on a trigger and its trigger type is focus, do nothing
268
269
  // case 3: if click on sub-dropdown, we should also show the parent dropdown, so ignore it
269
- const trigger = dropdown.get('trigger');
270
+ const { trigger, alwaysShowOnClick }= dropdown.get();
270
271
  if (trigger === 'focus') return;
271
272
 
272
273
  const isHover = trigger === 'hover';
273
- if (isHover || trigger === 'contextmenu') {
274
+ if (isHover || trigger === 'contextmenu' || alwaysShowOnClick) {
274
275
  const triggerDom = findDomFromVNode(dropdown.$lastInput!, true) as Element;
275
276
  const target = e.target as Element;
276
277
  if (containsOrEqual(triggerDom, target)) {
277
- if (isHover) return;
278
+ if (isHover || alwaysShowOnClick) return;
278
279
  if (!isHover && e.type === 'contextmenu') return;
279
280
  }
280
281
  }
@@ -17,6 +17,7 @@ sidebar: doc
17
17
  | position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
18
18
  | of | 弹出菜单的位置是相对当前触发元素,还是触发元素所在的菜单元素,这在嵌套菜单中可能会用到,可以使所有子菜单保持统一的对齐方式,例如:级联选择(Cascader)组件 | `"self"` &#124; `"parent"` &#124; `Event` | `"self"` |
19
19
  | container | 指定弹出菜单追加的位置,默认:`Dialog`类型的组件会追加到`Dialog`中,其他会追加到`body`中。你可以传入函数返回一个DOM用来作为插入的容器,或者传入字符串用来给`querySelector`进行查询 | `Container` | `undefined` |
20
+ | alwaysShowOnClick | 不管什么触发方式,重复点击触发器,都不隐藏弹层 | `boolean` | `false` |
20
21
 
21
22
  ```ts
22
23
  type Position = {
@@ -3,7 +3,7 @@ import template from './item.vdt';
3
3
  import {bind} from '../utils';
4
4
  import {useItemKeyboard, MenuKeyboardMethods} from './useKeyboard';
5
5
  import {Dropdown, DROPDOWN} from './dropdown';
6
- import {DropdownMenu, DROPDOWN_MENU} from './menu';
6
+ import {type DropdownMenu, DROPDOWN_MENU} from './menu';
7
7
  import {IgnoreClickEvent} from '../../hooks/useDocumentClick';
8
8
  import { Dropdown as ExportDropdown, DropdownMenu as ExportDropdownMenu } from '.';
9
9
  import { useConfigContext } from '../config';
@@ -20,7 +20,6 @@ import {useKeyboard} from '../../hooks/useKeyboard';
20
20
  import {useState} from '../../hooks/useState';
21
21
  import {eachChildren, isComponentVNode} from '../utils';
22
22
  import {DropdownItem} from './item';
23
- import {isStringOrNumber} from 'intact-shared';
24
23
  // can not import DropdownMenu from index.ts, otherwise it will cause circle reference
25
24
  // import {DropdownMenu} from './';
26
25
  import {DropdownMenu} from './menu';
@@ -177,4 +177,46 @@ describe('Input', () => {
177
177
  await wait(50);
178
178
  expect(input.offsetWidth).to.gt(16);
179
179
  });
180
+
181
+ it('should handle textarea resize correctly', async () => {
182
+ class ResizeDemo extends Component {
183
+ static template = `
184
+ const {Input} = this;
185
+ <div>
186
+ <Input type="textarea" resize="none" placeholder="resize none" />
187
+ <Input type="textarea" resize="vertical" placeholder="resize vertical" />
188
+ <Input type="textarea" resize="none" rows="auto" placeholder="resize none with auto rows" />
189
+ </div>
190
+ `;
191
+ private Input = Input;
192
+ }
193
+
194
+ const [instance, element] = mount(ResizeDemo as any);
195
+
196
+ const inputElements = element.querySelectorAll('.k-input');
197
+
198
+ // should have k-resize-none class
199
+ const resizeNoneElement = inputElements[0];
200
+ expect(resizeNoneElement.classList.contains('k-resize-none')).to.be.true;
201
+ expect(resizeNoneElement.classList.contains('k-resize-vertical')).to.be.false;
202
+
203
+ const resizeVerticalElement = inputElements[1];
204
+ expect(resizeVerticalElement.classList.contains('k-resize-vertical')).to.be.true;
205
+ expect(resizeVerticalElement.classList.contains('k-resize-none')).to.be.false;
206
+
207
+ // resize="none" with rows="auto" (should have k-resize-none class)
208
+ const resizeNoneAutoElement = inputElements[2];
209
+ expect(resizeNoneAutoElement.classList.contains('k-resize-none')).to.be.true;
210
+
211
+ // Test CSS computed styles to ensure resize is applied correctly
212
+ const textareas = element.querySelectorAll('.k-textarea');
213
+ const textarea1 = textareas[0] as HTMLTextAreaElement;
214
+ const textarea2 = textareas[1] as HTMLTextAreaElement;
215
+
216
+ const computedStyle1 = getComputedStyle(textarea1);
217
+ const computedStyle2 = getComputedStyle(textarea2);
218
+
219
+ expect(computedStyle1.resize).to.eql('none');
220
+ expect(computedStyle2.resize).to.eql('vertical');
221
+ });
180
222
  });
@@ -157,6 +157,14 @@ export class Input<V extends Value = Value> extends Component<InputProps<V>, Inp
157
157
  selectValue(this.inputRef.value!);
158
158
  }
159
159
 
160
+ getStringWidth(str: string) {
161
+ return this.autoWidth.getStringWidth(str);
162
+ }
163
+
164
+ getSelectionStart() {
165
+ return this.inputRef.value!.selectionStart;
166
+ }
167
+
160
168
  @bind
161
169
  private clear(e: MouseEvent) {
162
170
  this.set<string>('value', '');
@@ -41,8 +41,7 @@ const classNameObj = {
41
41
  [`${k}-flat`]: flat,
42
42
  [`${k}-type-textarea`]: type === 'textarea',
43
43
  [`${k}-focus`]: isFocus.value,
44
- [`${k}-resize-${resize}`]: type === 'textarea' && isNotAutoRows,
45
- [`${k}-resize-none`]: type === 'textarea' && !isNotAutoRows,
44
+ [`${k}-resize-${isNotAutoRows ? resize : 'none'}`]: type === 'textarea',
46
45
  [className]: className,
47
46
  [makeStyles(k)]: true,
48
47
  }
@@ -54,7 +53,7 @@ const {
54
53
  showIcon: showPasswordIcon,
55
54
  } = this.showPassword;
56
55
 
57
- const {fakeRef, width: {value: fakeWidth}} = this.autoWidth;
56
+ const {fakeRef, width: {value: fakeWidth}, forceShowFake} = this.autoWidth;
58
57
  const height = this.autoRows;
59
58
 
60
59
  const inputValue = frozenOnInput && inputing ? originalValue : value;
@@ -142,7 +141,7 @@ if (hasInputValue) {
142
141
  </span>
143
142
  <b:suffix />
144
143
  </div>
145
- <div class={`${k}-input-fake`} v-if={autoWidth}>
144
+ <div class={`${k}-input-fake`} v-if={autoWidth || forceShowFake.value}>
146
145
  <pre ref={fakeRef}>{!hasValue ? (hasInputValue || !defaultValue ? placeholder : defaultValue) : inputValue}</pre>
147
146
  </div>
148
147
  </div>
@@ -6,6 +6,7 @@ export function useAutoWidth() {
6
6
  const instance = useInstance() as Input;
7
7
  const fakeRef = createRef<HTMLDivElement>();
8
8
  const width = useState<number>(0);
9
+ const forceShowFake = useState(false);
9
10
 
10
11
  instance.watch('value', adjustWidth, {inited: true, presented: true});
11
12
  instance.watch('placeholder', adjustWidth, {inited: true, presented: true});
@@ -23,7 +24,24 @@ export function useAutoWidth() {
23
24
  }
24
25
  }
25
26
 
26
- return {fakeRef, width};
27
+ function getStringWidth(str: string) {
28
+ forceShowFake.set(true);
29
+ return new Promise<number>((resolve) => {
30
+ nextTick(() => {
31
+ const fakeElem = fakeRef.value!;
32
+ const textNode = fakeElem.firstChild!;
33
+ const oldStr = textNode.nodeValue;
34
+ textNode.nodeValue = str;
35
+
36
+ resolve(fakeElem.offsetWidth);
37
+
38
+ textNode.nodeValue = oldStr;
39
+ forceShowFake.set(false);
40
+ });
41
+ });
42
+ }
43
+
44
+ return {fakeRef, width, forceShowFake, getStringWidth};
27
45
  }
28
46
 
29
47
  function isVisible(elem: HTMLDivElement | null) {
Binary file
Binary file
@@ -18,6 +18,7 @@ export function useMouseEvents(
18
18
  let y: number;
19
19
  let itemHeight: number;
20
20
  let deltaY: number;
21
+ let wheelDeltaY: number = 0;
21
22
  const {start, dragging} = useDraggable({
22
23
  onStart(e: MouseEvent) {
23
24
  dragged = false;
@@ -67,15 +68,15 @@ export function useMouseEvents(
67
68
  itemHeight = getItemHeight();
68
69
 
69
70
  const threshold = itemHeight * 0.6;
70
- deltaY = (deltaY || 0) + e.deltaY;
71
+ wheelDeltaY += e.deltaY;
71
72
 
72
- if (Math.abs(deltaY) >= threshold) {
73
- if (deltaY > 0) {
73
+ if (Math.abs(wheelDeltaY) >= threshold) {
74
+ if (wheelDeltaY > 0) {
74
75
  setByRelativeIndex(1, null, true);
75
76
  } else {
76
77
  setByRelativeIndex(-1, null, true);
77
78
  }
78
- deltaY = 0;
79
+ wheelDeltaY = 0;
79
80
  }
80
81
  }
81
82
 
@@ -142,8 +142,9 @@ export abstract class BaseSelect<
142
142
  this.set('show', false);
143
143
  }
144
144
 
145
- public resetKeywords(keywords: State<string>) {
146
- keywords.set('');
145
+ @bind
146
+ public resetKeywords() {
147
+ this.input.keywords.set('');
147
148
  }
148
149
 
149
150
  protected hasValue() {
@@ -66,6 +66,7 @@ const filterInput = <Input v-if={filterable}
66
66
  container={container}
67
67
  v-model="show"
68
68
  position={position}
69
+ alwaysShowOnClick={$props.alwaysShowOnClick}
69
70
  >
70
71
  <div {...getRestProps(this)}
71
72
  class={classNameObj}
@@ -74,6 +75,7 @@ const filterInput = <Input v-if={filterable}
74
75
  ev-focusout={onFocusout}
75
76
  style={!isNullOrUndefined(width) ? addStyle(style, {width: `${width}px`}) : style}
76
77
  ref={triggerRef}
78
+ ev-click={$props.onClick}
77
79
  >
78
80
  <div class={`${k}-select-prefix`} v-if={$blocks.prefix}>
79
81
  <b:prefix />
@@ -95,7 +97,6 @@ const filterInput = <Input v-if={filterable}
95
97
  readonly={!show}
96
98
  waveDisabled={true}
97
99
  flat={flat}
98
- ev-click={$props.onClick}
99
100
  />
100
101
  <div class={`${k}-select-placeholder c-ellipsis`}
101
102
  v-else-if={!filterable && !hasValue}
@@ -31,7 +31,7 @@ import {Select, Option} from 'kpc';
31
31
  </Select>
32
32
  Days: {JSON.stringify(this.get('days'))}
33
33
  <br /><br />
34
- <Select v-model="dayWithKeywords" filterable multiple creatable keepKeywords style="margin-right: 10px">
34
+ <Select v-model="dayWithKeywords" filterable multiple creatable keepKeywords={false} style="margin-right: 10px">
35
35
  <Option value="Monday">星期一</Option>
36
36
  <Option value="Tuesday">星期二</Option>
37
37
  <Option value="Wednesday">星期三</Option>
@@ -40,7 +40,7 @@ import {Select, Option} from 'kpc';
40
40
  <Option value="Saturday">星期六</Option>
41
41
  <Option value="Sunday">星期天</Option>
42
42
  </Select>
43
- Day with keepKeywords: {JSON.stringify(this.get('dayWithKeywords'))}
43
+ Day with keepKeywords=false: {JSON.stringify(this.get('dayWithKeywords'))}
44
44
  </div>
45
45
  ```
46
46
 
@@ -31,7 +31,7 @@ sidebar: doc
31
31
  | labelMap | 建立值`value`到展示标签`label`的映射,可以在`value`不在`Option`集合中时,依然能够正确展示相应的`label` | `Map<any, string>` | `new Map()` |
32
32
  | card | 是否展示`card`模式 | `boolean` | `false` |
33
33
  | autoDisableArrow | 是否在没有更多可选项时,给箭头一个`disabled`状态来提示用户 | `boolean` | `false` |
34
- | keepKeywords | 是否在选中选项后保留搜索关键字,配合`filterable`使用 | `boolean` | `false` |
34
+ | keepKeywords | 是否在选中选项后保留搜索关键字,配合`filterable`使用 | `boolean` | `true` |
35
35
  | show | 是否展示菜单项 | `boolean` | `false` |
36
36
  | position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
37
37
  | flat | 是否展示扁平样式 | `boolean` | `false` |