@kne/react-filter 0.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.
@@ -0,0 +1,688 @@
1
+ import React, { createContext, useContext, useState, useRef, useEffect, cloneElement } from 'react';
2
+ import { Space, Tag, message, Button, Tooltip, InputNumber, Input, Select, Checkbox, Divider, Row, Col } from 'antd';
3
+ import { createCitySelect, apis, RemoteData, DisplayCity } from '@kne/react-city-select';
4
+ import get from 'lodash/get';
5
+ import isFunction from 'lodash/isFunction';
6
+ import isEqual from 'lodash/isEqual';
7
+ import useClickOutSide from '@kne/use-click-outside';
8
+ import classnames from 'classnames';
9
+ import isNumber from 'lodash/isNumber';
10
+
11
+ function _extends() {
12
+ _extends = Object.assign || function (target) {
13
+ for (var i = 1; i < arguments.length; i++) {
14
+ var source = arguments[i];
15
+
16
+ for (var key in source) {
17
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
18
+ target[key] = source[key];
19
+ }
20
+ }
21
+ }
22
+
23
+ return target;
24
+ };
25
+
26
+ return _extends.apply(this, arguments);
27
+ }
28
+
29
+ function _objectWithoutPropertiesLoose(source, excluded) {
30
+ if (source == null) return {};
31
+ var target = {};
32
+ var sourceKeys = Object.keys(source);
33
+ var key, i;
34
+
35
+ for (i = 0; i < sourceKeys.length; i++) {
36
+ key = sourceKeys[i];
37
+ if (excluded.indexOf(key) >= 0) continue;
38
+ target[key] = source[key];
39
+ }
40
+
41
+ return target;
42
+ }
43
+
44
+ const context$1 = createContext({});
45
+ const {
46
+ Consumer,
47
+ Provider: Provider$1
48
+ } = context$1;
49
+ const useConsumer = () => useContext(context$1);
50
+
51
+ const _excluded$5 = ["label"];
52
+
53
+ const FilterItem = ({
54
+ label,
55
+ children
56
+ }) => {
57
+ return /*#__PURE__*/React.createElement(Space, null, /*#__PURE__*/React.createElement("div", {
58
+ className: "react-filter-item-label"
59
+ }, label, ":"), /*#__PURE__*/React.createElement("div", {
60
+ className: "react-filter-item-children"
61
+ }, children));
62
+ };
63
+
64
+ const withFilterItem = WrappedComponent => _ref => {
65
+ let {
66
+ label
67
+ } = _ref,
68
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$5);
69
+
70
+ return /*#__PURE__*/React.createElement(FilterItem, {
71
+ label: label
72
+ }, /*#__PURE__*/React.createElement(WrappedComponent, props));
73
+ };
74
+
75
+ const _excluded$4 = ["value", "label"];
76
+ const {
77
+ CheckableTag
78
+ } = Tag;
79
+ const context = createContext({});
80
+ const {
81
+ Provider
82
+ } = context;
83
+
84
+ const List = ({
85
+ label,
86
+ name,
87
+ size,
88
+ children,
89
+ options,
90
+ more
91
+ }) => {
92
+ const {
93
+ value,
94
+ onChange
95
+ } = useConsumer();
96
+
97
+ const currentValue = (() => {
98
+ const originValue = get(value, name);
99
+
100
+ if (size === 1) {
101
+ return originValue !== void 0 ? [originValue] : [];
102
+ } else {
103
+ return originValue || [];
104
+ }
105
+ })();
106
+
107
+ const changeHandler = value => {
108
+ if (size === 1) {
109
+ return onChange(name, value[0]);
110
+ } else {
111
+ return onChange(name, value);
112
+ }
113
+ };
114
+
115
+ const createCheckedChangeHandler = value => checked => {
116
+ if (checked) {
117
+ let newList = currentValue.slice(0);
118
+
119
+ if (currentValue.length < size) {
120
+ newList.push(value);
121
+ }
122
+
123
+ if (currentValue.length === size && size === 1) {
124
+ newList = [value];
125
+ }
126
+
127
+ if (currentValue.length >= size && size > 1) {
128
+ message.error(`最多选择${size}个`);
129
+ return;
130
+ }
131
+
132
+ changeHandler(newList);
133
+ } else {
134
+ const newList = currentValue.slice(0);
135
+ newList.splice(currentValue.indexOf(value), 1);
136
+ changeHandler(newList);
137
+ }
138
+ };
139
+
140
+ const computedChildren = (() => {
141
+ if (Array.isArray(options)) {
142
+ return options.map(({
143
+ label,
144
+ value
145
+ }) => /*#__PURE__*/React.createElement(List.Item, {
146
+ key: value,
147
+ value: value,
148
+ label: label
149
+ }));
150
+ }
151
+
152
+ if (isFunction(children)) {
153
+ return children({
154
+ value: currentValue,
155
+ onChange: changeHandler
156
+ });
157
+ }
158
+
159
+ return children;
160
+ })();
161
+
162
+ return /*#__PURE__*/React.createElement(FilterItem, {
163
+ label: label
164
+ }, /*#__PURE__*/React.createElement(Provider, {
165
+ value: {
166
+ currentValue,
167
+ createCheckedChangeHandler
168
+ }
169
+ }, computedChildren, more ? (() => {
170
+ if (isFunction(more)) {
171
+ return more({
172
+ name,
173
+ size,
174
+ label,
175
+ value: currentValue,
176
+ onChange: changeHandler
177
+ });
178
+ }
179
+
180
+ const {
181
+ children,
182
+ onClick
183
+ } = more;
184
+ return /*#__PURE__*/React.createElement(List.Item, _extends({}, more, {
185
+ onClick: e => {
186
+ onClick({
187
+ name,
188
+ label,
189
+ value: currentValue,
190
+ onChange: changeHandler
191
+ }, e);
192
+ },
193
+ label: children || "其他"
194
+ }));
195
+ })() : null));
196
+ };
197
+
198
+ List.Item = _ref => {
199
+ let {
200
+ value,
201
+ label
202
+ } = _ref,
203
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$4);
204
+
205
+ const {
206
+ currentValue,
207
+ createCheckedChangeHandler
208
+ } = useContext(context);
209
+ const itemProps = {};
210
+
211
+ if (value !== void 0) {
212
+ itemProps.checked = currentValue.findIndex(item => isEqual(item.value, value)) > -1;
213
+ itemProps.onChange = createCheckedChangeHandler({
214
+ label,
215
+ value
216
+ });
217
+ }
218
+
219
+ return /*#__PURE__*/React.createElement(CheckableTag, _extends({}, props, itemProps), label);
220
+ };
221
+
222
+ List.defaultProps = {
223
+ size: 2
224
+ };
225
+
226
+ const {
227
+ Item
228
+ } = List;
229
+
230
+ const City = ({
231
+ label,
232
+ name,
233
+ size
234
+ }) => {
235
+ return /*#__PURE__*/React.createElement(List, {
236
+ label: label,
237
+ name: name,
238
+ size: size,
239
+ more: {
240
+ children: "其他",
241
+ onClick: ({
242
+ value,
243
+ onChange
244
+ }) => {
245
+ createCitySelect({
246
+ size,
247
+ defaultValue: value.map(({
248
+ value
249
+ }) => value),
250
+ onChange: value => {
251
+ Promise.all(value.map(id => apis.getCity(id).then(({
252
+ city
253
+ }) => ({
254
+ label: city.name,
255
+ value: city.code
256
+ })))).then(value => onChange(value));
257
+ }
258
+ });
259
+ }
260
+ }
261
+ }, ({
262
+ value: currentValue
263
+ }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RemoteData, {
264
+ loader: apis.getChinaHotCities
265
+ }, data => {
266
+ const otherList = currentValue.filter(({
267
+ value: code
268
+ }) => !data.find(item => item.code === code));
269
+ let extraLength = 0;
270
+ data.forEach((item, index) => {
271
+ if (currentValue.findIndex(({
272
+ value
273
+ }) => value === item.code) > -1 && index >= data.length - otherList.length) {
274
+ extraLength += 1;
275
+ }
276
+ });
277
+ return /*#__PURE__*/React.createElement(React.Fragment, null, otherList.map(({
278
+ value: code
279
+ }) => {
280
+ return /*#__PURE__*/React.createElement(DisplayCity, {
281
+ id: code,
282
+ key: code
283
+ }, ({
284
+ city: item
285
+ }) => {
286
+ return /*#__PURE__*/React.createElement(Item, {
287
+ value: code,
288
+ label: item.name
289
+ });
290
+ });
291
+ }), data.filter((item, index) => currentValue.findIndex(({
292
+ value
293
+ }) => value === item.code) > -1 || index < data.length - otherList.length - extraLength).map(item => /*#__PURE__*/React.createElement(Item, {
294
+ key: item.code,
295
+ value: item.code,
296
+ label: item.name
297
+ })));
298
+ })));
299
+ };
300
+
301
+ const SearchButton = ({
302
+ name,
303
+ size,
304
+ template,
305
+ children,
306
+ defaultValue,
307
+ defaultActive,
308
+ onSearch,
309
+ onBeforeSearch,
310
+ onActiveChange,
311
+ buttonText
312
+ }) => {
313
+ const {
314
+ value: aValue,
315
+ onChange
316
+ } = useConsumer();
317
+ const currentValue = aValue[name];
318
+ const [value, setValue] = useState(defaultValue || get(currentValue, "value"));
319
+ const [active, setActive] = useState(defaultActive);
320
+
321
+ const withTemplate = value => ({
322
+ value,
323
+ label: isFunction(template) ? template(value) : value.toString()
324
+ });
325
+
326
+ const ref = useClickOutSide(() => {
327
+ if (!active) {
328
+ return;
329
+ }
330
+
331
+ setValue(get(currentValue, "value"));
332
+ setActive(false);
333
+ });
334
+ const activeChangeRef = useRef(onActiveChange);
335
+ activeChangeRef.current = onActiveChange;
336
+ useEffect(() => {
337
+ activeChangeRef.current && activeChangeRef.current(active);
338
+ }, [active]);
339
+ return /*#__PURE__*/React.createElement("div", {
340
+ className: classnames("react-filter-search-button", {
341
+ "is-active": active
342
+ }),
343
+ ref: ref
344
+ }, /*#__PURE__*/React.createElement("div", {
345
+ className: "inner"
346
+ }, /*#__PURE__*/React.createElement("div", null, children({
347
+ value,
348
+ setValue,
349
+ setActive
350
+ })), active ? /*#__PURE__*/React.createElement(Button, {
351
+ className: "react-filter-search-confirm",
352
+ size: "small",
353
+ type: "primary",
354
+ onClick: e => {
355
+ e.stopPropagation();
356
+
357
+ if (onBeforeSearch && onBeforeSearch(value) === false) {
358
+ return;
359
+ }
360
+
361
+ onChange(name, Number.isInteger(size) && size > 1 ? [withTemplate(value)] : withTemplate(value));
362
+ setActive(false);
363
+ onSearch && onSearch({
364
+ value
365
+ });
366
+ }
367
+ }, buttonText) : null));
368
+ };
369
+
370
+ SearchButton.defaultProps = {
371
+ defaultActive: false,
372
+ buttonText: "确定"
373
+ };
374
+
375
+ const RangeInner = ({
376
+ name,
377
+ size,
378
+ defaultActive,
379
+ template,
380
+ onSearch,
381
+ onActiveChange,
382
+ startProps,
383
+ endProps
384
+ }) => {
385
+ const [error, setError] = useState(null);
386
+
387
+ const check = value => {
388
+ setError(null);
389
+
390
+ if (!Array.isArray(value)) {
391
+ return false;
392
+ }
393
+
394
+ if (value[0] === null && value[1] === null) {
395
+ setError("最大值和最小值不能同时为空");
396
+ return false;
397
+ }
398
+
399
+ if (isNumber(value[1]) && value[0] > value[1]) {
400
+ setError("最大值不能小于最小值");
401
+ return false;
402
+ }
403
+
404
+ return true;
405
+ };
406
+
407
+ return /*#__PURE__*/React.createElement(SearchButton, {
408
+ size: size,
409
+ template: template,
410
+ defaultActive: defaultActive,
411
+ name: name,
412
+ onSearch: onSearch,
413
+ onBeforeSearch: value => {
414
+ return check(value);
415
+ },
416
+ onActiveChange: active => {
417
+ if (!active) {
418
+ setError(null);
419
+ }
420
+
421
+ onActiveChange && onActiveChange(active);
422
+ }
423
+ }, ({
424
+ value,
425
+ setValue,
426
+ setActive
427
+ }) => /*#__PURE__*/React.createElement(Tooltip, {
428
+ visible: !!error,
429
+ title: error,
430
+ placement: "bottomRight"
431
+ }, /*#__PURE__*/React.createElement(Space, {
432
+ size: "small"
433
+ }, /*#__PURE__*/React.createElement(InputNumber, _extends({
434
+ size: "small"
435
+ }, startProps, {
436
+ value: get(value, 0),
437
+ onChange: inputValue => {
438
+ const target = [inputValue, get(value, 1)];
439
+ check(target);
440
+ setValue(target);
441
+ },
442
+ onFocus: () => {
443
+ setActive(true);
444
+ }
445
+ })), "~", /*#__PURE__*/React.createElement(InputNumber, _extends({
446
+ size: "small"
447
+ }, endProps, {
448
+ value: get(value, 1),
449
+ onChange: inputValue => {
450
+ const target = [get(value, 0), inputValue];
451
+ check(target);
452
+ setValue(target);
453
+ },
454
+ onFocus: () => {
455
+ setActive(true);
456
+ }
457
+ })))));
458
+ };
459
+ const Range = withFilterItem(RangeInner);
460
+
461
+ const _excluded$3 = ["name", "label", "template", "defaultActive", "onSearch", "onActiveChange"];
462
+ const TextInner = _ref => {
463
+ let {
464
+ name,
465
+ template,
466
+ defaultActive,
467
+ onSearch,
468
+ onActiveChange
469
+ } = _ref,
470
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$3);
471
+
472
+ return /*#__PURE__*/React.createElement(SearchButton, {
473
+ defaultActive: defaultActive,
474
+ template: template,
475
+ name: name,
476
+ onSearch: onSearch,
477
+ onActiveChange: active => {
478
+ onActiveChange && onActiveChange(active);
479
+ }
480
+ }, ({
481
+ value,
482
+ setValue,
483
+ setActive
484
+ }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Input, _extends({
485
+ size: "small"
486
+ }, props, {
487
+ value: value,
488
+ onChange: e => {
489
+ setValue(e.target.value);
490
+ },
491
+ onFocus: () => {
492
+ setActive(true);
493
+ }
494
+ }))));
495
+ };
496
+ const Text = withFilterItem(TextInner);
497
+
498
+ const _excluded$2 = ["name"];
499
+ const SelectorInner = _ref => {
500
+ let {
501
+ name
502
+ } = _ref,
503
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$2);
504
+
505
+ const {
506
+ value: aValue,
507
+ onChange
508
+ } = useConsumer();
509
+ const currentValue = aValue[name];
510
+ return /*#__PURE__*/React.createElement(Select, _extends({}, props, {
511
+ style: {
512
+ minWidth: "150px"
513
+ },
514
+ size: "small",
515
+ value: currentValue,
516
+ onChange: (value, item) => {
517
+ onChange(name, item);
518
+ }
519
+ }));
520
+ };
521
+ const Selector = withFilterItem(SelectorInner);
522
+
523
+ const _excluded$1 = ["name", "label"];
524
+
525
+ const Check = _ref => {
526
+ let {
527
+ name,
528
+ label
529
+ } = _ref,
530
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$1);
531
+
532
+ const {
533
+ value: aValue,
534
+ onChange
535
+ } = useConsumer();
536
+ const currentValue = aValue[name];
537
+ return /*#__PURE__*/React.createElement(Checkbox, _extends({}, props, {
538
+ size: "small",
539
+ checked: currentValue,
540
+ onChange: e => {
541
+ onChange(name, e.target.checked ? {
542
+ value: true,
543
+ label
544
+ } : null);
545
+ }
546
+ }), label);
547
+ };
548
+
549
+ const _excluded = ["name", "value", "children"],
550
+ _excluded2 = ["type"];
551
+ const withMoreExtraButton = WrappedComponent => _ref => {
552
+ let {
553
+ name,
554
+ children
555
+ } = _ref,
556
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
557
+
558
+ const [isEdit, setIsEdit] = useState(false);
559
+ return isEdit ? /*#__PURE__*/React.createElement(WrappedComponent, _extends({
560
+ defaultActive: true
561
+ }, props, {
562
+ name: name,
563
+ onActiveChange: active => {
564
+ if (active === false) {
565
+ setIsEdit(false);
566
+ }
567
+ }
568
+ })) : /*#__PURE__*/React.createElement(List.Item, {
569
+ onClick: e => {
570
+ e.stopPropagation();
571
+ setIsEdit(true);
572
+ },
573
+ label: children || "其他"
574
+ });
575
+ };
576
+ const RangeButton = withMoreExtraButton(RangeInner);
577
+ const TextButton = withMoreExtraButton(TextInner);
578
+ const SelectorButton = withMoreExtraButton(SelectorInner);
579
+ const createExtraButton = _ref2 => {
580
+ let {
581
+ type
582
+ } = _ref2,
583
+ props = _objectWithoutPropertiesLoose(_ref2, _excluded2);
584
+
585
+ return innerProps => {
586
+ const mapping = {
587
+ range: RangeButton,
588
+ text: TextButton,
589
+ selector: SelectorButton
590
+ };
591
+ const ExtraButtonComponent = mapping[type];
592
+
593
+ if (!ExtraButtonComponent) {
594
+ return null;
595
+ }
596
+
597
+ return /*#__PURE__*/React.createElement(ExtraButtonComponent, _extends({}, props, innerProps));
598
+ };
599
+ };
600
+
601
+ const Filter = ({
602
+ displayLine,
603
+ list,
604
+ value,
605
+ onChange
606
+ }) => {
607
+ const [display, setDisplay] = useState(false);
608
+ const basicList = list.slice(0, displayLine),
609
+ moreList = list.slice(displayLine);
610
+
611
+ const renderList = list => list.map((item, index) => {
612
+ return /*#__PURE__*/React.createElement(Space, {
613
+ key: index
614
+ }, item.map((item, index) => cloneElement(item, {
615
+ key: index
616
+ })));
617
+ });
618
+
619
+ const changeHandler = (name, item) => {
620
+ const target = Object.assign({}, value, {
621
+ [name]: item
622
+ });
623
+ Object.keys(target).forEach(key => {
624
+ const item = target[key];
625
+
626
+ if (item === void 0 || item === null) {
627
+ delete target[key];
628
+ }
629
+
630
+ if (Array.isArray(item) && item.length === 0) {
631
+ delete target[key];
632
+ }
633
+ });
634
+ onChange(target);
635
+ };
636
+
637
+ return /*#__PURE__*/React.createElement(Provider$1, {
638
+ value: {
639
+ value,
640
+ onChange: changeHandler
641
+ }
642
+ }, /*#__PURE__*/React.createElement(Space, {
643
+ className: "space-full",
644
+ direction: "vertical"
645
+ }, /*#__PURE__*/React.createElement(FilterItem, {
646
+ label: "\u7B5B\u9009\u9879"
647
+ }, Object.keys(value).map(key => {
648
+ const item = value[key];
649
+ if (!item) return null;
650
+ if (Array.isArray(item) && item.length === 0) return null;
651
+ return /*#__PURE__*/React.createElement(Tag, {
652
+ key: key,
653
+ closable: true,
654
+ onClose: () => {
655
+ changeHandler(key, null);
656
+ }
657
+ }, Array.isArray(item) ? item.map(({
658
+ label
659
+ }) => label).join(",") : item.label);
660
+ })), renderList(basicList), display ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, {
661
+ className: "react-filter-divider"
662
+ }), renderList(moreList)) : null, /*#__PURE__*/React.createElement(Row, {
663
+ justify: "end"
664
+ }, /*#__PURE__*/React.createElement(Col, null, /*#__PURE__*/React.createElement(Button, {
665
+ type: "link",
666
+ onClick: () => {
667
+ setDisplay(display => !display);
668
+ }
669
+ }, display ? "收起更多条件" : "展开更多")))));
670
+ };
671
+
672
+ Filter.type = {
673
+ City,
674
+ List,
675
+ Range,
676
+ Text,
677
+ Selector,
678
+ Check
679
+ };
680
+ Filter.defaultProps = {
681
+ displayLine: 2,
682
+ list: [[]],
683
+ value: {},
684
+ onChange: () => {}
685
+ };
686
+
687
+ export { FilterItem, SearchButton, createExtraButton, Filter as default, withFilterItem, withMoreExtraButton };
688
+ //# sourceMappingURL=index.modern.js.map