@gm-pc/react 1.27.5-beta.0 → 1.28.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.
- package/package.json +3 -3
- package/src/component/loading/types.ts +1 -1
- package/src/component/more_select/base.tsx +240 -113
- package/src/component/more_select/more_select.tsx +4 -0
- package/src/component/more_select/stories.tsx +92 -0
- package/src/component/more_select/style.less +2 -14
- package/src/component/more_select/types.ts +22 -5
- package/src/component/pagination/left.tsx +11 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gm-pc/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0-beta.0",
|
|
4
4
|
"description": "观麦前端基础组件库",
|
|
5
5
|
"author": "liyatang <liyatang@qq.com>",
|
|
6
6
|
"homepage": "https://github.com/gmfe/gm-pc#readme",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@gm-common/hooks": "^2.10.0",
|
|
26
26
|
"@gm-common/tool": "^2.10.0",
|
|
27
|
-
"@gm-pc/locales": "^1.
|
|
27
|
+
"@gm-pc/locales": "^1.28.0-beta.0",
|
|
28
28
|
"big.js": "^6.0.1",
|
|
29
29
|
"classnames": "^2.2.5",
|
|
30
30
|
"lodash": "^4.17.19",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"react-router-dom": "^5.2.0",
|
|
49
49
|
"react-window": "^1.8.5"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "107461a0dd5c644e10482ed5f3ed8638fee436cc"
|
|
52
52
|
}
|
|
@@ -20,13 +20,16 @@ import { getLocale } from '@gm-pc/locales'
|
|
|
20
20
|
import { ListBase } from '../list'
|
|
21
21
|
import { findDOMNode } from 'react-dom'
|
|
22
22
|
import { ConfigConsumer, ConfigProvider, ConfigProviderProps } from '../config_provider'
|
|
23
|
+
import { Checkbox, Switch } from '@gm-pc/react'
|
|
23
24
|
|
|
24
25
|
interface MoreSelectBaseState {
|
|
25
|
-
searchValue: string
|
|
26
|
+
searchValue: string
|
|
26
27
|
loading: boolean
|
|
27
28
|
/* keyboard 默认第一个位置 */
|
|
28
29
|
willActiveIndex: number | null
|
|
29
|
-
|
|
30
|
+
isCheckedAll: boolean
|
|
31
|
+
isFilterDelete: boolean
|
|
32
|
+
displayCount: number
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
// @todo keydown item disabled
|
|
@@ -39,10 +42,12 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
39
42
|
static renderListFilterPinYin = renderListFilterPinYin
|
|
40
43
|
|
|
41
44
|
readonly state: MoreSelectBaseState = {
|
|
42
|
-
searchValue:
|
|
45
|
+
searchValue: '',
|
|
43
46
|
loading: false,
|
|
44
47
|
willActiveIndex: this.props.isKeyboard ? 0 : null,
|
|
45
|
-
|
|
48
|
+
isCheckedAll: false,
|
|
49
|
+
isFilterDelete: false,
|
|
50
|
+
displayCount: 0,
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
private _isUnmounted = false
|
|
@@ -50,6 +55,7 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
50
55
|
private _selectionRef = createRef<HTMLDivElement>()
|
|
51
56
|
private _popoverRef = createRef<Popover>()
|
|
52
57
|
private _inputRef = createRef<HTMLInputElement>()
|
|
58
|
+
private _resizeObserver: ResizeObserver | null = null
|
|
53
59
|
|
|
54
60
|
private _filterData: MoreSelectGroupDataItem<V>[] | undefined
|
|
55
61
|
|
|
@@ -64,8 +70,44 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
componentDidMount() {
|
|
74
|
+
const { maxTagCount } = this.props
|
|
75
|
+
if (maxTagCount === 'responsive' && this._selectionRef.current) {
|
|
76
|
+
// HACK: 首次计算
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
if (this._selectionRef.current) {
|
|
79
|
+
const { width } = this._selectionRef.current.getBoundingClientRect()
|
|
80
|
+
const omittedTagWidth = 50 // for "+N..."
|
|
81
|
+
const availableWidth = width - omittedTagWidth
|
|
82
|
+
const newDisplayCount = Math.floor(availableWidth / 80)
|
|
83
|
+
if (this.state.displayCount !== newDisplayCount) {
|
|
84
|
+
this.setState({ displayCount: newDisplayCount > 0 ? newDisplayCount : 0 })
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, 0)
|
|
88
|
+
|
|
89
|
+
this._resizeObserver = new ResizeObserver((entries) => {
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
const { width } = entry.contentRect
|
|
92
|
+
// Estimate item width, let's say 80px.
|
|
93
|
+
const omittedTagWidth = 50 // for "+N..."
|
|
94
|
+
const availableWidth = width - omittedTagWidth
|
|
95
|
+
const newDisplayCount = Math.floor(availableWidth / 80)
|
|
96
|
+
|
|
97
|
+
if (this.state.displayCount !== newDisplayCount) {
|
|
98
|
+
this.setState({ displayCount: newDisplayCount > 0 ? newDisplayCount : 0 })
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
this._resizeObserver.observe(this._selectionRef.current)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
67
106
|
componentWillUnmount() {
|
|
68
|
-
this._isUnmounted =
|
|
107
|
+
this._isUnmounted = true
|
|
108
|
+
if (this._resizeObserver) {
|
|
109
|
+
this._resizeObserver.disconnect()
|
|
110
|
+
}
|
|
69
111
|
}
|
|
70
112
|
|
|
71
113
|
public apiDoFocus = (): void => {
|
|
@@ -135,10 +177,6 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
135
177
|
const searchValue = event.target.value
|
|
136
178
|
this.setState({ searchValue })
|
|
137
179
|
this._debounceDoSearch(searchValue)
|
|
138
|
-
if (this.props.isSameAntd) {
|
|
139
|
-
// eslint-disable-next-line no-unused-expressions
|
|
140
|
-
this._popoverRef.current?.apiDoSetActive(true)
|
|
141
|
-
}
|
|
142
180
|
setTimeout(() => {
|
|
143
181
|
// eslint-disable-next-line no-unused-expressions
|
|
144
182
|
isInitSearch && this._inputRef.current?.select()
|
|
@@ -172,7 +210,7 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
172
210
|
onSelect(willSelected)
|
|
173
211
|
}
|
|
174
212
|
|
|
175
|
-
private _handlePopupKeyDown = (event: KeyboardEvent): void => {
|
|
213
|
+
private _handlePopupKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
176
214
|
const { onKeyDown } = this.props
|
|
177
215
|
let willActiveIndex = this.state.willActiveIndex as number
|
|
178
216
|
if (!onKeyDown) {
|
|
@@ -238,19 +276,81 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
238
276
|
)
|
|
239
277
|
}
|
|
240
278
|
|
|
241
|
-
|
|
242
|
-
const {
|
|
243
|
-
|
|
279
|
+
renderBottom = () => {
|
|
280
|
+
const {
|
|
281
|
+
selected = [],
|
|
282
|
+
isShowDeletedSwitch = true,
|
|
283
|
+
isShowCheckedAll = true,
|
|
284
|
+
} = this.props
|
|
285
|
+
const { isCheckedAll, isFilterDelete } = this.state
|
|
286
|
+
const flatFilterData = this._getFlatFilterData()
|
|
287
|
+
|
|
288
|
+
// 根据过滤状态决定是否过滤已删除商品
|
|
289
|
+
const availableData = isFilterDelete
|
|
290
|
+
? flatFilterData.filter((item) => !item.deleted)
|
|
291
|
+
: flatFilterData
|
|
292
|
+
|
|
293
|
+
// 检查是否所有可用数据都被选中
|
|
294
|
+
const allSelected =
|
|
295
|
+
availableData.length > 0 &&
|
|
296
|
+
availableData.every((item) =>
|
|
297
|
+
selected.some((selectedItem) => selectedItem.value === item.value)
|
|
298
|
+
)
|
|
299
|
+
|
|
244
300
|
return (
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
301
|
+
<Flex
|
|
302
|
+
justifyBetween
|
|
303
|
+
className='tw-p-[8px]'
|
|
304
|
+
alignCenter
|
|
305
|
+
style={{ borderTop: '1px solid #aeaeae' }}
|
|
306
|
+
>
|
|
307
|
+
{isShowCheckedAll && (
|
|
308
|
+
<Checkbox
|
|
309
|
+
checked={allSelected}
|
|
310
|
+
onChange={(e) => {
|
|
311
|
+
const isChecked = e.target.checked
|
|
312
|
+
this.setState({
|
|
313
|
+
isCheckedAll: isChecked,
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
if (isChecked) {
|
|
317
|
+
// 全选当前过滤后的可用数据
|
|
318
|
+
const valuesToSelect = availableData.map((item) => item.value)
|
|
319
|
+
this._handleSelect(valuesToSelect)
|
|
320
|
+
} else {
|
|
321
|
+
// 取消全选
|
|
322
|
+
this._handleSelect([])
|
|
323
|
+
}
|
|
324
|
+
}}
|
|
325
|
+
>
|
|
326
|
+
全选
|
|
327
|
+
</Checkbox>
|
|
328
|
+
)}
|
|
329
|
+
{isShowDeletedSwitch && (
|
|
330
|
+
<Flex alignCenter>
|
|
331
|
+
<Flex row>
|
|
332
|
+
<Switch
|
|
333
|
+
style={{ width: 48 }}
|
|
334
|
+
checked={isFilterDelete}
|
|
335
|
+
onChange={(open) => {
|
|
336
|
+
this.setState({
|
|
337
|
+
isFilterDelete: open,
|
|
338
|
+
})
|
|
339
|
+
if (isCheckedAll) {
|
|
340
|
+
const newAvailableData = open
|
|
341
|
+
? flatFilterData.filter((item) => !item.deleted)
|
|
342
|
+
: flatFilterData
|
|
343
|
+
|
|
344
|
+
const valuesToSelect = newAvailableData.map((item) => item.value)
|
|
345
|
+
this._handleSelect(valuesToSelect)
|
|
346
|
+
}
|
|
347
|
+
}}
|
|
348
|
+
/>
|
|
349
|
+
</Flex>
|
|
350
|
+
<span className='gm-margin-left-5'>过滤已删除商品</span>
|
|
351
|
+
</Flex>
|
|
352
|
+
)}
|
|
353
|
+
</Flex>
|
|
254
354
|
)
|
|
255
355
|
}
|
|
256
356
|
|
|
@@ -260,20 +360,40 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
260
360
|
multiple,
|
|
261
361
|
isGroupList,
|
|
262
362
|
renderListItem,
|
|
363
|
+
searchPlaceholder,
|
|
263
364
|
listHeight,
|
|
264
365
|
popupClassName,
|
|
265
366
|
renderCustomizedBottom,
|
|
266
|
-
|
|
367
|
+
isRenderDefaultBottom = false,
|
|
267
368
|
} = this.props
|
|
268
|
-
const { loading, willActiveIndex } = this.state
|
|
269
|
-
|
|
369
|
+
const { loading, searchValue, willActiveIndex, isFilterDelete } = this.state
|
|
370
|
+
let filterData = this._getFilterData()
|
|
371
|
+
|
|
372
|
+
// 如果开启了过滤已删除商品功能,需要过滤掉已删除的商品
|
|
373
|
+
if (isFilterDelete) {
|
|
374
|
+
filterData = filterData
|
|
375
|
+
.map((group) => ({
|
|
376
|
+
...group,
|
|
377
|
+
children: group.children.filter((item) => !item.deleted),
|
|
378
|
+
}))
|
|
379
|
+
.filter((group) => group.children.length > 0)
|
|
380
|
+
}
|
|
381
|
+
|
|
270
382
|
return (
|
|
271
383
|
<ConfigProvider {...config}>
|
|
272
384
|
<div
|
|
273
385
|
className={classNames('gm-more-select-popup', popupClassName)}
|
|
274
386
|
onKeyDown={this._handlePopupKeyDown}
|
|
275
387
|
>
|
|
276
|
-
|
|
388
|
+
<div className='gm-more-select-popup-input'>
|
|
389
|
+
<Input
|
|
390
|
+
ref={this._inputRef}
|
|
391
|
+
autoFocus
|
|
392
|
+
value={searchValue}
|
|
393
|
+
onChange={this._handleChange}
|
|
394
|
+
placeholder={searchPlaceholder}
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
277
397
|
<div style={{ height: listHeight }}>
|
|
278
398
|
{loading && (
|
|
279
399
|
<Flex alignCenter justifyCenter className='gm-bg gm-padding-5'>
|
|
@@ -298,8 +418,11 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
298
418
|
</div>
|
|
299
419
|
{!loading &&
|
|
300
420
|
!!filterData.length &&
|
|
301
|
-
renderCustomizedBottom
|
|
302
|
-
|
|
421
|
+
(renderCustomizedBottom
|
|
422
|
+
? renderCustomizedBottom(this._popoverRef, this.renderBottom)
|
|
423
|
+
: isRenderDefaultBottom
|
|
424
|
+
? this.renderBottom()
|
|
425
|
+
: null)}
|
|
303
426
|
</div>
|
|
304
427
|
</ConfigProvider>
|
|
305
428
|
)
|
|
@@ -313,16 +436,7 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
313
436
|
}
|
|
314
437
|
|
|
315
438
|
private _handlePopoverVisibleChange = (active: boolean) => {
|
|
316
|
-
if (this.props.
|
|
317
|
-
this.setState({
|
|
318
|
-
isOpen: active,
|
|
319
|
-
})
|
|
320
|
-
if (!this.props.multiple && !active) {
|
|
321
|
-
this.setState({ searchValue: undefined })
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (active && this.props.searchOnActive && !this.props.isSameAntd) {
|
|
439
|
+
if (active && this.props.searchOnActive) {
|
|
326
440
|
const searchValue = localStorage.getItem('_GM-PC_MORESELECT_SEARCHVALUE')
|
|
327
441
|
if (searchValue) {
|
|
328
442
|
this.setState({ searchValue })
|
|
@@ -348,10 +462,90 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
348
462
|
style,
|
|
349
463
|
popoverType,
|
|
350
464
|
children,
|
|
351
|
-
|
|
352
|
-
|
|
465
|
+
maxTagCount,
|
|
466
|
+
maxTagPlaceholder,
|
|
467
|
+
isRenderDefaultBottom = false,
|
|
353
468
|
} = this.props
|
|
354
|
-
|
|
469
|
+
|
|
470
|
+
// 处理 maxTagCount 逻辑
|
|
471
|
+
const renderSelectedItems = () => {
|
|
472
|
+
if (!multiple || !maxTagCount || selected.length === 0) {
|
|
473
|
+
return selected.map((item) => (
|
|
474
|
+
<Flex key={item.value as any} className='gm-more-select-selected-item'>
|
|
475
|
+
<Popover
|
|
476
|
+
disabled={!this.props.isKeyboard}
|
|
477
|
+
type='hover'
|
|
478
|
+
popup={<div className='gm-padding-10'>{item.text}</div>}
|
|
479
|
+
>
|
|
480
|
+
<Flex flex column>
|
|
481
|
+
{renderSelected!(item)}
|
|
482
|
+
</Flex>
|
|
483
|
+
</Popover>
|
|
484
|
+
{multiple ? (
|
|
485
|
+
<SVGRemove
|
|
486
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
487
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
488
|
+
/>
|
|
489
|
+
) : (
|
|
490
|
+
!disabledClose && ( // 是否不限时清除按钮,仅单选可用
|
|
491
|
+
<SVGCloseCircle
|
|
492
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
493
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
494
|
+
/>
|
|
495
|
+
)
|
|
496
|
+
)}
|
|
497
|
+
</Flex>
|
|
498
|
+
))
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// 处理 maxTagCount 逻辑
|
|
502
|
+
const isResponsive = maxTagCount === 'responsive'
|
|
503
|
+
let displayCount: number
|
|
504
|
+
|
|
505
|
+
if (isResponsive) {
|
|
506
|
+
displayCount = this.state.displayCount
|
|
507
|
+
} else {
|
|
508
|
+
displayCount = maxTagCount as number
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const itemsToShow = selected.slice(0, displayCount)
|
|
512
|
+
const omittedItems = selected.slice(displayCount)
|
|
513
|
+
const omittedCount = selected.length - displayCount
|
|
514
|
+
|
|
515
|
+
return (
|
|
516
|
+
<>
|
|
517
|
+
{itemsToShow.map((item) => (
|
|
518
|
+
<Flex key={item.value as any} className='gm-more-select-selected-item'>
|
|
519
|
+
<Popover
|
|
520
|
+
disabled={!this.props.isKeyboard}
|
|
521
|
+
type='hover'
|
|
522
|
+
popup={<div className='gm-padding-10'>{item.text}</div>}
|
|
523
|
+
>
|
|
524
|
+
<Flex flex column>
|
|
525
|
+
{renderSelected!(item)}
|
|
526
|
+
</Flex>
|
|
527
|
+
</Popover>
|
|
528
|
+
<SVGRemove
|
|
529
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
530
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
531
|
+
/>
|
|
532
|
+
</Flex>
|
|
533
|
+
))}
|
|
534
|
+
{omittedCount > 0 && (
|
|
535
|
+
<Flex
|
|
536
|
+
key='omitted'
|
|
537
|
+
className='gm-more-select-selected-item gm-more-select-omitted-item'
|
|
538
|
+
>
|
|
539
|
+
{maxTagPlaceholder ? (
|
|
540
|
+
maxTagPlaceholder(omittedItems, omittedCount)
|
|
541
|
+
) : (
|
|
542
|
+
<span className='gm-more-select-omitted-count'>+{omittedCount}...</span>
|
|
543
|
+
)}
|
|
544
|
+
</Flex>
|
|
545
|
+
)}
|
|
546
|
+
</>
|
|
547
|
+
)
|
|
548
|
+
}
|
|
355
549
|
|
|
356
550
|
return (
|
|
357
551
|
<ConfigConsumer>
|
|
@@ -367,15 +561,13 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
367
561
|
},
|
|
368
562
|
className
|
|
369
563
|
)}
|
|
370
|
-
style={style}
|
|
564
|
+
style={style as any}
|
|
371
565
|
>
|
|
372
566
|
<Popover
|
|
373
567
|
ref={this._popoverRef}
|
|
374
568
|
type={popoverType}
|
|
375
569
|
popup={() => this._renderList(config)}
|
|
376
|
-
disabled={
|
|
377
|
-
disabled || (!isSameAntd ? false : this.state.searchValue === undefined)
|
|
378
|
-
}
|
|
570
|
+
disabled={disabled}
|
|
379
571
|
isInPopup={isInPopup}
|
|
380
572
|
onVisibleChange={this._handlePopoverVisibleChange}
|
|
381
573
|
>
|
|
@@ -384,78 +576,13 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
384
576
|
ref={this._selectionRef}
|
|
385
577
|
tabIndex={0}
|
|
386
578
|
wrap
|
|
387
|
-
className=
|
|
388
|
-
'gm-more-select-selected': true,
|
|
389
|
-
'gm-more-select-selected-antd': isSameAntd,
|
|
390
|
-
})}
|
|
579
|
+
className='gm-more-select-selected'
|
|
391
580
|
>
|
|
392
581
|
{selected.length !== 0 ? (
|
|
393
|
-
|
|
394
|
-
<Flex
|
|
395
|
-
key={item.value as any}
|
|
396
|
-
className='gm-more-select-selected-item'
|
|
397
|
-
alignCenter
|
|
398
|
-
>
|
|
399
|
-
<Popover
|
|
400
|
-
disabled={!this.props.isKeyboard}
|
|
401
|
-
type='hover'
|
|
402
|
-
popup={<div className='gm-padding-10'>{item.text}</div>}
|
|
403
|
-
>
|
|
404
|
-
<Flex flex column>
|
|
405
|
-
{isSameAntd ? (
|
|
406
|
-
<div className='gm-more-select-popup-input'>
|
|
407
|
-
<Input
|
|
408
|
-
ref={this._inputRef}
|
|
409
|
-
value={
|
|
410
|
-
!this.state.isOpen
|
|
411
|
-
? renderSelected!(item)
|
|
412
|
-
: searchValue
|
|
413
|
-
}
|
|
414
|
-
onChange={this._handleChange}
|
|
415
|
-
placeholder={searchPlaceholder}
|
|
416
|
-
className='gm-more-select-popup-input-no-border'
|
|
417
|
-
/>
|
|
418
|
-
</div>
|
|
419
|
-
) : (
|
|
420
|
-
renderSelected!(item)
|
|
421
|
-
)}
|
|
422
|
-
</Flex>
|
|
423
|
-
</Popover>
|
|
424
|
-
{multiple ? (
|
|
425
|
-
<SVGRemove
|
|
426
|
-
className='gm-cursor gm-more-select-clear-btn'
|
|
427
|
-
onClick={
|
|
428
|
-
disabled ? _.noop : this._handleClear.bind(this, item)
|
|
429
|
-
}
|
|
430
|
-
/>
|
|
431
|
-
) : (
|
|
432
|
-
!disabledClose && ( // 是否不限时清除按钮,仅单选可用
|
|
433
|
-
<SVGCloseCircle
|
|
434
|
-
onClick={
|
|
435
|
-
disabled ? _.noop : this._handleClear.bind(this, item)
|
|
436
|
-
}
|
|
437
|
-
className='gm-cursor gm-more-select-clear-btn'
|
|
438
|
-
/>
|
|
439
|
-
)
|
|
440
|
-
)}
|
|
441
|
-
</Flex>
|
|
442
|
-
))
|
|
582
|
+
renderSelectedItems()
|
|
443
583
|
) : (
|
|
444
584
|
// 加多个 避免对齐问题,有文本才有对齐
|
|
445
|
-
|
|
446
|
-
{isSameAntd ? (
|
|
447
|
-
<Input
|
|
448
|
-
ref={this._inputRef}
|
|
449
|
-
value={searchValue}
|
|
450
|
-
onChange={this._handleChange}
|
|
451
|
-
placeholder={searchPlaceholder}
|
|
452
|
-
className='gm-more-select-popup-input-no-border'
|
|
453
|
-
/>
|
|
454
|
-
) : (
|
|
455
|
-
<div className='gm-text-placeholder'>{placeholder} </div>
|
|
456
|
-
)}
|
|
457
|
-
</>
|
|
458
|
-
//
|
|
585
|
+
<div className='gm-text-placeholder'>{placeholder} </div>
|
|
459
586
|
)}
|
|
460
587
|
</Flex>
|
|
461
588
|
)}
|
|
@@ -85,6 +85,8 @@ class MoreSelect<V = any> extends Component<MoreSelectProps<V>> {
|
|
|
85
85
|
onSearch,
|
|
86
86
|
onClick,
|
|
87
87
|
renderListFilter,
|
|
88
|
+
maxTagCount,
|
|
89
|
+
maxTagPlaceholder,
|
|
88
90
|
...rest
|
|
89
91
|
} = this.props
|
|
90
92
|
let tempSelect = selected as MoreSelectDataItem<V>[]
|
|
@@ -129,6 +131,8 @@ class MoreSelect<V = any> extends Component<MoreSelectProps<V>> {
|
|
|
129
131
|
isGroupList={isGroupList}
|
|
130
132
|
onSearch={onSearch && this._handleSearch}
|
|
131
133
|
renderListFilter={renderListFilter && this._renderListFilter}
|
|
134
|
+
maxTagCount={maxTagCount}
|
|
135
|
+
maxTagPlaceholder={maxTagPlaceholder}
|
|
132
136
|
/>
|
|
133
137
|
)
|
|
134
138
|
}
|
|
@@ -318,6 +318,98 @@ export const ComMoreSelectWithIsGroupListMultiple = () => (
|
|
|
318
318
|
/>
|
|
319
319
|
)
|
|
320
320
|
|
|
321
|
+
export const ComMoreSelectWithMaxTagCount = () => {
|
|
322
|
+
// 创建一个包含多个选项的数据集
|
|
323
|
+
const manyOptions = [
|
|
324
|
+
{ value: 1, text: '选项1' },
|
|
325
|
+
{ value: 2, text: '选项2' },
|
|
326
|
+
{ value: 3, text: '选项3' },
|
|
327
|
+
{ value: 4, text: '选项4' },
|
|
328
|
+
{ value: 5, text: '选项5' },
|
|
329
|
+
{ value: 6, text: '选项6' },
|
|
330
|
+
{ value: 7, text: '选项7' },
|
|
331
|
+
{ value: 8, text: '选项8' },
|
|
332
|
+
]
|
|
333
|
+
|
|
334
|
+
// 预选多个选项
|
|
335
|
+
const preSelected = manyOptions.slice(0, 6)
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<div style={{ width: '300px' }}>
|
|
339
|
+
<h3>maxTagCount 示例</h3>
|
|
340
|
+
|
|
341
|
+
<div style={{ marginBottom: '20px' }}>
|
|
342
|
+
<h4>不使用 maxTagCount(显示所有选项)</h4>
|
|
343
|
+
<MoreSelect<number>
|
|
344
|
+
multiple
|
|
345
|
+
data={manyOptions}
|
|
346
|
+
selected={preSelected}
|
|
347
|
+
onSelect={(selected) => {
|
|
348
|
+
console.log('不限制显示数量:', selected)
|
|
349
|
+
}}
|
|
350
|
+
/>
|
|
351
|
+
</div>
|
|
352
|
+
|
|
353
|
+
<div style={{ marginBottom: '20px' }}>
|
|
354
|
+
<h4>maxTagCount={2}(最多显示2个选项)</h4>
|
|
355
|
+
<MoreSelect<number>
|
|
356
|
+
multiple
|
|
357
|
+
maxTagCount={2}
|
|
358
|
+
data={manyOptions}
|
|
359
|
+
selected={preSelected}
|
|
360
|
+
onSelect={(selected) => {
|
|
361
|
+
console.log('最多显示2个:', selected)
|
|
362
|
+
}}
|
|
363
|
+
/>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<div style={{ marginBottom: '20px' }}>
|
|
367
|
+
<h4>maxTagCount={3}(最多显示3个选项)</h4>
|
|
368
|
+
<MoreSelect<number>
|
|
369
|
+
multiple
|
|
370
|
+
maxTagCount={3}
|
|
371
|
+
data={manyOptions}
|
|
372
|
+
selected={preSelected}
|
|
373
|
+
onSelect={(selected) => {
|
|
374
|
+
console.log('最多显示3个:', selected)
|
|
375
|
+
}}
|
|
376
|
+
/>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<div style={{ marginBottom: '20px' }}>
|
|
380
|
+
<h4>maxTagCount=responsive(响应式模式)</h4>
|
|
381
|
+
<MoreSelect<number>
|
|
382
|
+
multiple
|
|
383
|
+
maxTagCount='responsive'
|
|
384
|
+
data={manyOptions}
|
|
385
|
+
selected={preSelected}
|
|
386
|
+
onSelect={(selected) => {
|
|
387
|
+
console.log('响应式模式:', selected)
|
|
388
|
+
}}
|
|
389
|
+
/>
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
<div style={{ marginBottom: '20px' }}>
|
|
393
|
+
<h4>自定义 maxTagPlaceholder</h4>
|
|
394
|
+
<MoreSelect<number>
|
|
395
|
+
multiple
|
|
396
|
+
maxTagCount={2}
|
|
397
|
+
maxTagPlaceholder={(omittedValues, omittedCount) => (
|
|
398
|
+
<span style={{ color: '#1890ff', fontWeight: 'bold' }}>
|
|
399
|
+
还有{omittedCount}项未显示
|
|
400
|
+
</span>
|
|
401
|
+
)}
|
|
402
|
+
data={manyOptions}
|
|
403
|
+
selected={preSelected}
|
|
404
|
+
onSelect={(selected) => {
|
|
405
|
+
console.log('自定义占位符:', selected)
|
|
406
|
+
}}
|
|
407
|
+
/>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
)
|
|
411
|
+
}
|
|
412
|
+
|
|
321
413
|
export default {
|
|
322
414
|
title: '表单/MoreSelect',
|
|
323
415
|
}
|
|
@@ -14,15 +14,10 @@
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
.gm-more-select-selected-antd {
|
|
18
|
-
padding: 0 12px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
17
|
.gm-more-select-clear-btn {
|
|
22
18
|
position: absolute;
|
|
23
|
-
right:
|
|
24
|
-
top:
|
|
25
|
-
transform: translateY(-50%);
|
|
19
|
+
right: 5px;
|
|
20
|
+
top: 7px;
|
|
26
21
|
cursor: pointer;
|
|
27
22
|
color: var(--gm-color-desc);
|
|
28
23
|
}
|
|
@@ -75,10 +70,3 @@
|
|
|
75
70
|
}
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
|
-
|
|
79
|
-
.gm-more-select-popup-input-no-border {
|
|
80
|
-
border: none !important;
|
|
81
|
-
border-radius: 0 !important;
|
|
82
|
-
padding: 0 !important;
|
|
83
|
-
box-shadow: none !important;
|
|
84
|
-
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { Popover } from '@gm-pc/react'
|
|
2
1
|
import { CSSProperties, ReactNode, KeyboardEvent } from 'react'
|
|
2
|
+
import { Popover } from '../popover'
|
|
3
3
|
|
|
4
4
|
/** 普通的数据格式 */
|
|
5
5
|
interface MoreSelectDataItem<V extends string | number = string> {
|
|
6
6
|
value: V
|
|
7
7
|
text: string
|
|
8
8
|
disabled?: boolean
|
|
9
|
+
/** 是否已删除 */
|
|
10
|
+
deleted?: boolean
|
|
9
11
|
[key: string]: any
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -36,10 +38,13 @@ interface MoreSelectCommonProps<V extends string | number = string> {
|
|
|
36
38
|
renderListItem?(value: MoreSelectDataItem<V>, index: number): ReactNode
|
|
37
39
|
|
|
38
40
|
/** 自定义popup底部渲染 */
|
|
39
|
-
renderCustomizedBottom?(
|
|
41
|
+
renderCustomizedBottom?(
|
|
42
|
+
ref: React.RefObject<Popover>,
|
|
43
|
+
defaultBottom: () => ReactNode
|
|
44
|
+
): ReactNode
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
|
-
*
|
|
47
|
+
* 自定义"空状态"渲染
|
|
43
48
|
*
|
|
44
49
|
* 若函数返回 undefined 则使用默认的空状态
|
|
45
50
|
*/
|
|
@@ -60,6 +65,14 @@ interface MoreSelectCommonProps<V extends string | number = string> {
|
|
|
60
65
|
/** 目前为了 keyboard */
|
|
61
66
|
isKeyboard?: boolean
|
|
62
67
|
onKeyDown?(event: KeyboardEvent): void
|
|
68
|
+
|
|
69
|
+
/** 最多显示的选中项数量,超出部分会折叠 */
|
|
70
|
+
maxTagCount?: number | 'responsive'
|
|
71
|
+
/** 自定义超出 maxTagCount 时显示的内容 */
|
|
72
|
+
maxTagPlaceholder?: (
|
|
73
|
+
omittedValues: MoreSelectDataItem<V>[],
|
|
74
|
+
omittedCount: number
|
|
75
|
+
) => ReactNode
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
interface MoreSelectBaseProps<V extends string | number = string>
|
|
@@ -80,8 +93,12 @@ interface MoreSelectBaseProps<V extends string | number = string>
|
|
|
80
93
|
): MoreSelectGroupDataItem<V>[]
|
|
81
94
|
/** 是否在active的时候搜索,订单业务相关,searchValue放在localstorage */
|
|
82
95
|
searchOnActive?: boolean
|
|
83
|
-
/**
|
|
84
|
-
|
|
96
|
+
/** 是否展示全选以及过滤已删除商品 */
|
|
97
|
+
isRenderDefaultBottom?: boolean
|
|
98
|
+
/** 是否展示已删除商品 */
|
|
99
|
+
isShowDeletedSwitch?: boolean
|
|
100
|
+
/** 是否展示全选 */
|
|
101
|
+
isShowCheckedAll?: boolean
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
type MoreSelectData<V extends string | number = string> =
|
|
@@ -6,13 +6,17 @@ import _ from 'lodash'
|
|
|
6
6
|
import { getLocale } from '@gm-pc/locales'
|
|
7
7
|
|
|
8
8
|
function getLimitData(limit: number, pageSizeOptions?: string[]) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{ value:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
let limitData = []
|
|
10
|
+
if (pageSizeOptions) {
|
|
11
|
+
limitData = pageSizeOptions.map((v) => ({ value: Number(v), text: v }))
|
|
12
|
+
} else {
|
|
13
|
+
limitData = [
|
|
14
|
+
{ value: limit, text: limit + '' },
|
|
15
|
+
{ value: 10, text: '10' },
|
|
16
|
+
{ value: 20, text: '20' },
|
|
17
|
+
{ value: 50, text: '50' },
|
|
18
|
+
]
|
|
19
|
+
}
|
|
16
20
|
|
|
17
21
|
return _.orderBy(
|
|
18
22
|
_.uniqBy(limitData, (v) => v.value),
|