@gm-pc/react 1.27.5-beta.0 → 1.28.0-beta.1
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 +236 -113
- package/src/component/more_select/more_select.tsx +10 -0
- package/src/component/more_select/stories.tsx +92 -0
- package/src/component/more_select/style.less +4 -12
- package/src/component/more_select/types.ts +33 -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.1",
|
|
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.1",
|
|
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": "994ee00d0f8515ba21e8522f0e66f717bc0859d9"
|
|
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: true,
|
|
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,42 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
componentDidMount() {
|
|
74
|
+
const { maxTagCount, tagItemWidth = 80, omittedTagWidth = 45 } = 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 availableWidth = width - omittedTagWidth
|
|
81
|
+
const newDisplayCount = Math.floor(availableWidth / tagItemWidth)
|
|
82
|
+
if (this.state.displayCount !== newDisplayCount) {
|
|
83
|
+
this.setState({ displayCount: newDisplayCount > 0 ? newDisplayCount : 0 })
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}, 0)
|
|
87
|
+
|
|
88
|
+
this._resizeObserver = new ResizeObserver((entries) => {
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const { width } = entry.contentRect
|
|
91
|
+
// Estimate item width, let's say 80px.
|
|
92
|
+
const availableWidth = width - omittedTagWidth
|
|
93
|
+
const newDisplayCount = Math.floor(availableWidth / tagItemWidth)
|
|
94
|
+
|
|
95
|
+
if (this.state.displayCount !== newDisplayCount) {
|
|
96
|
+
this.setState({ displayCount: newDisplayCount })
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
this._resizeObserver.observe(this._selectionRef.current)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
67
104
|
componentWillUnmount() {
|
|
68
|
-
this._isUnmounted =
|
|
105
|
+
this._isUnmounted = true
|
|
106
|
+
if (this._resizeObserver) {
|
|
107
|
+
this._resizeObserver.disconnect()
|
|
108
|
+
}
|
|
69
109
|
}
|
|
70
110
|
|
|
71
111
|
public apiDoFocus = (): void => {
|
|
@@ -135,10 +175,6 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
135
175
|
const searchValue = event.target.value
|
|
136
176
|
this.setState({ searchValue })
|
|
137
177
|
this._debounceDoSearch(searchValue)
|
|
138
|
-
if (this.props.isSameAntd) {
|
|
139
|
-
// eslint-disable-next-line no-unused-expressions
|
|
140
|
-
this._popoverRef.current?.apiDoSetActive(true)
|
|
141
|
-
}
|
|
142
178
|
setTimeout(() => {
|
|
143
179
|
// eslint-disable-next-line no-unused-expressions
|
|
144
180
|
isInitSearch && this._inputRef.current?.select()
|
|
@@ -172,7 +208,7 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
172
208
|
onSelect(willSelected)
|
|
173
209
|
}
|
|
174
210
|
|
|
175
|
-
private _handlePopupKeyDown = (event: KeyboardEvent): void => {
|
|
211
|
+
private _handlePopupKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
176
212
|
const { onKeyDown } = this.props
|
|
177
213
|
let willActiveIndex = this.state.willActiveIndex as number
|
|
178
214
|
if (!onKeyDown) {
|
|
@@ -238,19 +274,80 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
238
274
|
)
|
|
239
275
|
}
|
|
240
276
|
|
|
241
|
-
|
|
242
|
-
const {
|
|
243
|
-
|
|
277
|
+
renderBottom = () => {
|
|
278
|
+
const {
|
|
279
|
+
selected = [],
|
|
280
|
+
isShowDeletedSwitch = true,
|
|
281
|
+
isShowCheckedAll = true,
|
|
282
|
+
} = this.props
|
|
283
|
+
const { isCheckedAll, isFilterDelete } = this.state
|
|
284
|
+
const flatFilterData = this._getFlatFilterData()
|
|
285
|
+
|
|
286
|
+
// 根据过滤状态决定是否过滤已删除商品
|
|
287
|
+
const availableData = isFilterDelete
|
|
288
|
+
? flatFilterData.filter((item) => !item.deleted)
|
|
289
|
+
: flatFilterData
|
|
290
|
+
|
|
291
|
+
// 检查是否所有可用数据都被选中
|
|
292
|
+
const allSelected =
|
|
293
|
+
availableData.length > 0 &&
|
|
294
|
+
availableData.every((item) =>
|
|
295
|
+
selected.some((selectedItem) => selectedItem.value === item.value)
|
|
296
|
+
)
|
|
297
|
+
|
|
244
298
|
return (
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
299
|
+
<Flex
|
|
300
|
+
justifyBetween
|
|
301
|
+
className='tw-p-[8px] gm-more-select-default-bottom'
|
|
302
|
+
alignCenter
|
|
303
|
+
>
|
|
304
|
+
{isShowCheckedAll && (
|
|
305
|
+
<Checkbox
|
|
306
|
+
checked={allSelected}
|
|
307
|
+
onChange={(e) => {
|
|
308
|
+
const isChecked = e.target.checked
|
|
309
|
+
this.setState({
|
|
310
|
+
isCheckedAll: isChecked,
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
if (isChecked) {
|
|
314
|
+
// 全选当前过滤后的可用数据
|
|
315
|
+
const valuesToSelect = availableData.map((item) => item.value)
|
|
316
|
+
this._handleSelect(valuesToSelect)
|
|
317
|
+
} else {
|
|
318
|
+
// 取消全选
|
|
319
|
+
this._handleSelect([])
|
|
320
|
+
}
|
|
321
|
+
}}
|
|
322
|
+
>
|
|
323
|
+
全选({availableData.length})
|
|
324
|
+
</Checkbox>
|
|
325
|
+
)}
|
|
326
|
+
{isShowDeletedSwitch && (
|
|
327
|
+
<Flex alignCenter>
|
|
328
|
+
<Flex row>
|
|
329
|
+
<Switch
|
|
330
|
+
style={{ width: 48 }}
|
|
331
|
+
checked={isFilterDelete}
|
|
332
|
+
onChange={(open) => {
|
|
333
|
+
this.setState({
|
|
334
|
+
isFilterDelete: open,
|
|
335
|
+
})
|
|
336
|
+
if (isCheckedAll) {
|
|
337
|
+
const newAvailableData = open
|
|
338
|
+
? flatFilterData.filter((item) => !item.deleted)
|
|
339
|
+
: flatFilterData
|
|
340
|
+
|
|
341
|
+
const valuesToSelect = newAvailableData.map((item) => item.value)
|
|
342
|
+
this._handleSelect(valuesToSelect)
|
|
343
|
+
}
|
|
344
|
+
}}
|
|
345
|
+
/>
|
|
346
|
+
</Flex>
|
|
347
|
+
<span className='gm-margin-left-5'>过滤已删除商品</span>
|
|
348
|
+
</Flex>
|
|
349
|
+
)}
|
|
350
|
+
</Flex>
|
|
254
351
|
)
|
|
255
352
|
}
|
|
256
353
|
|
|
@@ -260,20 +357,40 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
260
357
|
multiple,
|
|
261
358
|
isGroupList,
|
|
262
359
|
renderListItem,
|
|
360
|
+
searchPlaceholder,
|
|
263
361
|
listHeight,
|
|
264
362
|
popupClassName,
|
|
265
363
|
renderCustomizedBottom,
|
|
266
|
-
|
|
364
|
+
isRenderDefaultBottom = false,
|
|
267
365
|
} = this.props
|
|
268
|
-
const { loading, willActiveIndex } = this.state
|
|
269
|
-
|
|
366
|
+
const { loading, searchValue, willActiveIndex, isFilterDelete } = this.state
|
|
367
|
+
let filterData = this._getFilterData()
|
|
368
|
+
|
|
369
|
+
// 如果开启了过滤已删除商品功能,需要过滤掉已删除的商品
|
|
370
|
+
if (isFilterDelete) {
|
|
371
|
+
filterData = filterData
|
|
372
|
+
.map((group) => ({
|
|
373
|
+
...group,
|
|
374
|
+
children: group.children.filter((item) => !item.deleted),
|
|
375
|
+
}))
|
|
376
|
+
.filter((group) => group.children.length > 0)
|
|
377
|
+
}
|
|
378
|
+
|
|
270
379
|
return (
|
|
271
380
|
<ConfigProvider {...config}>
|
|
272
381
|
<div
|
|
273
382
|
className={classNames('gm-more-select-popup', popupClassName)}
|
|
274
383
|
onKeyDown={this._handlePopupKeyDown}
|
|
275
384
|
>
|
|
276
|
-
|
|
385
|
+
<div className='gm-more-select-popup-input'>
|
|
386
|
+
<Input
|
|
387
|
+
ref={this._inputRef}
|
|
388
|
+
autoFocus
|
|
389
|
+
value={searchValue}
|
|
390
|
+
onChange={this._handleChange}
|
|
391
|
+
placeholder={searchPlaceholder}
|
|
392
|
+
/>
|
|
393
|
+
</div>
|
|
277
394
|
<div style={{ height: listHeight }}>
|
|
278
395
|
{loading && (
|
|
279
396
|
<Flex alignCenter justifyCenter className='gm-bg gm-padding-5'>
|
|
@@ -298,8 +415,11 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
298
415
|
</div>
|
|
299
416
|
{!loading &&
|
|
300
417
|
!!filterData.length &&
|
|
301
|
-
renderCustomizedBottom
|
|
302
|
-
|
|
418
|
+
(renderCustomizedBottom
|
|
419
|
+
? renderCustomizedBottom(this._popoverRef, this.renderBottom)
|
|
420
|
+
: isRenderDefaultBottom
|
|
421
|
+
? this.renderBottom()
|
|
422
|
+
: null)}
|
|
303
423
|
</div>
|
|
304
424
|
</ConfigProvider>
|
|
305
425
|
)
|
|
@@ -313,16 +433,7 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
313
433
|
}
|
|
314
434
|
|
|
315
435
|
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) {
|
|
436
|
+
if (active && this.props.searchOnActive) {
|
|
326
437
|
const searchValue = localStorage.getItem('_GM-PC_MORESELECT_SEARCHVALUE')
|
|
327
438
|
if (searchValue) {
|
|
328
439
|
this.setState({ searchValue })
|
|
@@ -348,10 +459,89 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
348
459
|
style,
|
|
349
460
|
popoverType,
|
|
350
461
|
children,
|
|
351
|
-
|
|
352
|
-
|
|
462
|
+
maxTagCount,
|
|
463
|
+
maxTagPlaceholder,
|
|
353
464
|
} = this.props
|
|
354
|
-
|
|
465
|
+
|
|
466
|
+
// 处理 maxTagCount 逻辑
|
|
467
|
+
const renderSelectedItems = () => {
|
|
468
|
+
if (!multiple || !maxTagCount || selected.length === 0) {
|
|
469
|
+
return selected.map((item) => (
|
|
470
|
+
<Flex key={item.value as any} className='gm-more-select-selected-item'>
|
|
471
|
+
<Popover
|
|
472
|
+
disabled={!this.props.isKeyboard}
|
|
473
|
+
type='hover'
|
|
474
|
+
popup={<div className='gm-padding-10'>{item.text}</div>}
|
|
475
|
+
>
|
|
476
|
+
<Flex flex column>
|
|
477
|
+
{renderSelected!(item)}
|
|
478
|
+
</Flex>
|
|
479
|
+
</Popover>
|
|
480
|
+
{multiple ? (
|
|
481
|
+
<SVGRemove
|
|
482
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
483
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
484
|
+
/>
|
|
485
|
+
) : (
|
|
486
|
+
!disabledClose && ( // 是否不限时清除按钮,仅单选可用
|
|
487
|
+
<SVGCloseCircle
|
|
488
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
489
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
490
|
+
/>
|
|
491
|
+
)
|
|
492
|
+
)}
|
|
493
|
+
</Flex>
|
|
494
|
+
))
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 处理 maxTagCount 逻辑
|
|
498
|
+
const isResponsive = maxTagCount === 'responsive'
|
|
499
|
+
let displayCount: number
|
|
500
|
+
|
|
501
|
+
if (isResponsive) {
|
|
502
|
+
displayCount = this.state.displayCount
|
|
503
|
+
} else {
|
|
504
|
+
displayCount = maxTagCount as number
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const itemsToShow = selected.slice(0, displayCount)
|
|
508
|
+
const omittedItems = selected.slice(displayCount)
|
|
509
|
+
const omittedCount = selected.length - displayCount
|
|
510
|
+
|
|
511
|
+
return (
|
|
512
|
+
<>
|
|
513
|
+
{itemsToShow.map((item) => (
|
|
514
|
+
<Flex key={item.value as any} className='gm-more-select-selected-item'>
|
|
515
|
+
<Popover
|
|
516
|
+
disabled={!this.props.isKeyboard}
|
|
517
|
+
type='hover'
|
|
518
|
+
popup={<div className='gm-padding-10'>{item.text}</div>}
|
|
519
|
+
>
|
|
520
|
+
<Flex flex column>
|
|
521
|
+
{renderSelected!(item)}
|
|
522
|
+
</Flex>
|
|
523
|
+
</Popover>
|
|
524
|
+
<SVGRemove
|
|
525
|
+
className='gm-cursor gm-more-select-clear-btn'
|
|
526
|
+
onClick={disabled ? _.noop : this._handleClear.bind(this, item)}
|
|
527
|
+
/>
|
|
528
|
+
</Flex>
|
|
529
|
+
))}
|
|
530
|
+
{omittedCount > 0 && (
|
|
531
|
+
<Flex
|
|
532
|
+
key='omitted'
|
|
533
|
+
className='gm-more-select-selected-item gm-more-select-omitted-item'
|
|
534
|
+
>
|
|
535
|
+
{maxTagPlaceholder ? (
|
|
536
|
+
maxTagPlaceholder(omittedItems, omittedCount)
|
|
537
|
+
) : (
|
|
538
|
+
<span className='gm-more-select-omitted-count'>+{omittedCount}...</span>
|
|
539
|
+
)}
|
|
540
|
+
</Flex>
|
|
541
|
+
)}
|
|
542
|
+
</>
|
|
543
|
+
)
|
|
544
|
+
}
|
|
355
545
|
|
|
356
546
|
return (
|
|
357
547
|
<ConfigConsumer>
|
|
@@ -367,15 +557,13 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
367
557
|
},
|
|
368
558
|
className
|
|
369
559
|
)}
|
|
370
|
-
style={style}
|
|
560
|
+
style={style as any}
|
|
371
561
|
>
|
|
372
562
|
<Popover
|
|
373
563
|
ref={this._popoverRef}
|
|
374
564
|
type={popoverType}
|
|
375
565
|
popup={() => this._renderList(config)}
|
|
376
|
-
disabled={
|
|
377
|
-
disabled || (!isSameAntd ? false : this.state.searchValue === undefined)
|
|
378
|
-
}
|
|
566
|
+
disabled={disabled}
|
|
379
567
|
isInPopup={isInPopup}
|
|
380
568
|
onVisibleChange={this._handlePopoverVisibleChange}
|
|
381
569
|
>
|
|
@@ -384,78 +572,13 @@ class MoreSelectBase<V extends string | number = string> extends Component<
|
|
|
384
572
|
ref={this._selectionRef}
|
|
385
573
|
tabIndex={0}
|
|
386
574
|
wrap
|
|
387
|
-
className=
|
|
388
|
-
'gm-more-select-selected': true,
|
|
389
|
-
'gm-more-select-selected-antd': isSameAntd,
|
|
390
|
-
})}
|
|
575
|
+
className='gm-more-select-selected'
|
|
391
576
|
>
|
|
392
577
|
{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
|
-
))
|
|
578
|
+
renderSelectedItems()
|
|
443
579
|
) : (
|
|
444
580
|
// 加多个 避免对齐问题,有文本才有对齐
|
|
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
|
-
//
|
|
581
|
+
<div className='gm-text-placeholder'>{placeholder} </div>
|
|
459
582
|
)}
|
|
460
583
|
</Flex>
|
|
461
584
|
)}
|
|
@@ -12,6 +12,12 @@ class MoreSelect<V = any> extends Component<MoreSelectProps<V>> {
|
|
|
12
12
|
renderListFilterType: 'default',
|
|
13
13
|
popoverType: 'focus',
|
|
14
14
|
onKeyDown: _.noop,
|
|
15
|
+
/** 是否展示全选以及过滤已删除商品 */
|
|
16
|
+
isRenderDefaultBottom: false,
|
|
17
|
+
/** 是否展示已删除商品 */
|
|
18
|
+
isShowDeletedSwitch: true,
|
|
19
|
+
/** 是否展示全选 */
|
|
20
|
+
isShowCheckedAll: true,
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
private _moreSelectBaseRef = createRef<MoreSelectBase>()
|
|
@@ -85,6 +91,8 @@ class MoreSelect<V = any> extends Component<MoreSelectProps<V>> {
|
|
|
85
91
|
onSearch,
|
|
86
92
|
onClick,
|
|
87
93
|
renderListFilter,
|
|
94
|
+
maxTagCount,
|
|
95
|
+
maxTagPlaceholder,
|
|
88
96
|
...rest
|
|
89
97
|
} = this.props
|
|
90
98
|
let tempSelect = selected as MoreSelectDataItem<V>[]
|
|
@@ -129,6 +137,8 @@ class MoreSelect<V = any> extends Component<MoreSelectProps<V>> {
|
|
|
129
137
|
isGroupList={isGroupList}
|
|
130
138
|
onSearch={onSearch && this._handleSearch}
|
|
131
139
|
renderListFilter={renderListFilter && this._renderListFilter}
|
|
140
|
+
maxTagCount={maxTagCount}
|
|
141
|
+
maxTagPlaceholder={maxTagPlaceholder}
|
|
132
142
|
/>
|
|
133
143
|
)
|
|
134
144
|
}
|
|
@@ -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
|
}
|
|
@@ -76,9 +71,6 @@
|
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
|
|
79
|
-
.gm-more-select-
|
|
80
|
-
border:
|
|
81
|
-
border-radius: 0 !important;
|
|
82
|
-
padding: 0 !important;
|
|
83
|
-
box-shadow: none !important;
|
|
74
|
+
.gm-more-select-default-bottom {
|
|
75
|
+
border-top: 1px solid var(--gm-color-border);
|
|
84
76
|
}
|
|
@@ -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,25 @@ 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
|
|
76
|
+
|
|
77
|
+
/** 是否展示全选以及过滤已删除商品 */
|
|
78
|
+
isRenderDefaultBottom?: boolean
|
|
79
|
+
/** 是否展示已删除商品 */
|
|
80
|
+
isShowDeletedSwitch?: boolean
|
|
81
|
+
/** 是否展示全选 */
|
|
82
|
+
isShowCheckedAll?: boolean
|
|
83
|
+
/** 当设置 maxTagCount 的时候的宽度, 根据这个去计算显示内容 */
|
|
84
|
+
tagItemWidth?: number
|
|
85
|
+
/** +N 显示的宽度 */
|
|
86
|
+
omittedTagWidth?: number
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
interface MoreSelectBaseProps<V extends string | number = string>
|
|
@@ -80,8 +104,12 @@ interface MoreSelectBaseProps<V extends string | number = string>
|
|
|
80
104
|
): MoreSelectGroupDataItem<V>[]
|
|
81
105
|
/** 是否在active的时候搜索,订单业务相关,searchValue放在localstorage */
|
|
82
106
|
searchOnActive?: boolean
|
|
83
|
-
/**
|
|
84
|
-
|
|
107
|
+
/** 是否展示全选以及过滤已删除商品 */
|
|
108
|
+
isRenderDefaultBottom?: boolean
|
|
109
|
+
/** 是否展示已删除商品 */
|
|
110
|
+
isShowDeletedSwitch?: boolean
|
|
111
|
+
/** 是否展示全选 */
|
|
112
|
+
isShowCheckedAll?: boolean
|
|
85
113
|
}
|
|
86
114
|
|
|
87
115
|
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),
|