@blocklet/list 0.10.32 → 0.10.34

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/lib/libs/utils.js CHANGED
@@ -4,24 +4,17 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.urlStringify = exports.toColorRgb = exports.replaceTranslate = exports.removeUndefined = exports.isMobileScreen = exports.getStoreDetail = exports.getSortOptions = exports.getPrices = exports.getCurrentPage = exports.getCategoryOptions = exports.formatLogoPath = exports.formatError = exports.filterBlockletByPrice = exports.debounced = void 0;
7
-
8
7
  var _urlJoin = _interopRequireDefault(require("url-join"));
9
-
10
8
  var _cloneDeep = _interopRequireDefault(require("lodash/cloneDeep"));
11
-
12
9
  var _color = _interopRequireDefault(require("color"));
13
-
14
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
-
16
11
  const isFreeBlocklet = blocklet => {
17
12
  if (!blocklet.payment) {
18
13
  return true;
19
14
  }
20
-
21
15
  const priceList = (blocklet.payment.price || []).map(x => x.value || 0);
22
16
  return priceList.every(x => x === 0);
23
17
  };
24
-
25
18
  const getSortOptions = t => {
26
19
  return [{
27
20
  name: t('sort.popularity'),
@@ -37,9 +30,7 @@ const getSortOptions = t => {
37
30
  value: 'nameDesc'
38
31
  }];
39
32
  };
40
-
41
33
  exports.getSortOptions = getSortOptions;
42
-
43
34
  const getPrices = t => {
44
35
  return [{
45
36
  name: t('blocklet.free'),
@@ -49,9 +40,7 @@ const getPrices = t => {
49
40
  value: 'payment'
50
41
  }];
51
42
  };
52
-
53
43
  exports.getPrices = getPrices;
54
-
55
44
  const getCategoryOptions = function getCategoryOptions() {
56
45
  let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
57
46
  let locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en';
@@ -60,66 +49,50 @@ const getCategoryOptions = function getCategoryOptions() {
60
49
  value: item._id
61
50
  }));
62
51
  };
52
+
63
53
  /**
64
54
  * 根据 是否付费 过滤 blocklet list
65
55
  * @param {*} list
66
56
  * @param {*} price
67
57
  * @returns
68
58
  */
69
-
70
-
71
59
  exports.getCategoryOptions = getCategoryOptions;
72
-
73
60
  const filterBlockletByPrice = function filterBlockletByPrice() {
74
61
  let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
75
62
  let price = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
76
63
  let result = list;
77
64
  if (!price) return result;
78
-
79
65
  if (price === 'free') {
80
66
  result = list.filter(blocklet => isFreeBlocklet(blocklet));
81
67
  } else {
82
68
  result = list.filter(blocklet => !isFreeBlocklet(blocklet));
83
69
  }
84
-
85
70
  return result;
86
71
  };
87
-
88
72
  exports.filterBlockletByPrice = filterBlockletByPrice;
89
-
90
73
  const formatError = error => {
91
74
  if (Array.isArray(error.errors)) {
92
75
  return error.errors.map(x => x.message).join('\n');
93
76
  }
94
-
95
77
  return error.message;
96
78
  };
97
-
98
79
  exports.formatError = formatError;
99
-
100
80
  const getStoreDetail = (storeUrl, blocklet) => {
101
81
  return (0, _urlJoin.default)(storeUrl, "/blocklets/".concat(blocklet.did));
102
82
  };
103
-
104
83
  exports.getStoreDetail = getStoreDetail;
105
-
106
84
  const formatLogoPath = function formatLogoPath(did, asset) {
107
85
  let target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'assets';
108
-
109
86
  if (asset.startsWith(target)) {
110
87
  return asset;
111
88
  }
112
-
113
89
  return "".concat(target, "/").concat(did, "/").concat(asset);
114
90
  };
115
-
116
91
  exports.formatLogoPath = formatLogoPath;
117
-
118
- const replaceTranslate = (template, data) => // eslint-disable-next-line no-prototype-builtins
92
+ const replaceTranslate = (template, data) =>
93
+ // eslint-disable-next-line no-prototype-builtins
119
94
  template.replace(/{(\w*)}/g, (m, key) => data.hasOwnProperty(key) ? data[key] : '');
120
-
121
95
  exports.replaceTranslate = replaceTranslate;
122
-
123
96
  const removeUndefined = obj => {
124
97
  const clone = (0, _cloneDeep.default)(obj);
125
98
  Object.keys(clone).forEach(key => {
@@ -129,56 +102,42 @@ const removeUndefined = obj => {
129
102
  });
130
103
  return clone;
131
104
  };
132
-
133
105
  exports.removeUndefined = removeUndefined;
134
-
135
106
  const urlStringify = obj => {
136
107
  if (!obj) {
137
108
  throw new Error('obj is required in urlStringify ');
138
109
  }
139
-
140
110
  return new URLSearchParams(removeUndefined(obj)).toString();
141
111
  };
142
-
143
112
  exports.urlStringify = urlStringify;
144
-
145
113
  const isMobileScreen = () => {
146
114
  return window.innerWidth <= 600;
147
115
  };
148
-
149
116
  exports.isMobileScreen = isMobileScreen;
150
-
151
117
  const getCurrentPage = (length, pageSize) => {
152
118
  const page = (length + pageSize) / pageSize;
153
119
  if (page > 1) return page.toFixed();
154
120
  return 1;
155
121
  };
156
-
157
122
  exports.getCurrentPage = getCurrentPage;
158
-
159
123
  const toColorRgb = colorStr => {
160
124
  const color = (0, _color.default)(colorStr);
161
125
  return color.rgb().object();
162
126
  };
163
-
164
127
  exports.toColorRgb = toColorRgb;
165
-
166
128
  function debouncePromise(fn, time) {
167
129
  let timerId;
168
130
  return function debounced() {
169
131
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
170
132
  args[_key] = arguments[_key];
171
133
  }
172
-
173
134
  if (timerId) {
174
135
  clearTimeout(timerId);
175
136
  }
176
-
177
137
  return new Promise(resolve => {
178
138
  timerId = setTimeout(() => resolve(fn(...args)), time);
179
139
  });
180
140
  };
181
141
  }
182
-
183
142
  const debounced = debouncePromise(items => Promise.resolve(items), 300);
184
143
  exports.debounced = debounced;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/list",
3
- "version": "0.10.32",
3
+ "version": "0.10.34",
4
4
  "description": "Common ux components of blocklet",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -42,12 +42,11 @@
42
42
  "dependencies": {
43
43
  "@algolia/autocomplete-js": "^1.7.1",
44
44
  "@algolia/autocomplete-theme-classic": "^1.7.1",
45
- "@arcblock/ux": "^2.4.49",
45
+ "@arcblock/ux": "^2.4.52",
46
46
  "@emotion/react": "^11.10.0",
47
47
  "@emotion/styled": "^11.10.0",
48
48
  "@mui/icons-material": "^5.8.4",
49
49
  "ahooks": "^3.7.0",
50
- "algoliasearch": "^4.14.2",
51
50
  "axios": "^0.27.2",
52
51
  "color": "^4.2.3",
53
52
  "flat": "^5.0.2",
@@ -71,5 +70,5 @@
71
70
  "eslint": "^8.22.0",
72
71
  "prettier": "^2.7.1"
73
72
  },
74
- "gitHead": "175ef1a333106105733fe3ac8d222a54fac91b8a"
73
+ "gitHead": "a937d5fcacee474b9f024440587a94975f8c0361"
75
74
  }
package/src/base.js CHANGED
@@ -11,6 +11,7 @@ import { CustomChip, FilterIcon } from './components/filter';
11
11
  import { getSortOptions } from './libs/utils';
12
12
  import BlockletList from './components/list';
13
13
  import Aside from './components/aside';
14
+ import BaseSearch from './components/base-search';
14
15
  import Autocomplete from './components/autocomplete';
15
16
 
16
17
  function ListBase() {
@@ -27,6 +28,7 @@ function ListBase() {
27
28
  getCategoryLocale,
28
29
  priceOptions,
29
30
  wrapChildren,
31
+ baseSearch,
30
32
  } = useFilterContext();
31
33
  const sortOptions = getSortOptions(t);
32
34
  const sortLocale = sortOptions.find((f) => f.value === filters.sortBy)?.name || t('sort.sort');
@@ -40,7 +42,12 @@ function ListBase() {
40
42
  <StyledMin>
41
43
  <FilterContainer>
42
44
  <Box className="filter-bar" display="flex" alignItems="center">
43
- <Autocomplete onSelect={handleSearchSelect} wrapChildren={wrapChildren} />
45
+ {/* see: https://github.com/blocklet/blocklet-store/pull/852 */}
46
+ {baseSearch ? (
47
+ <BaseSearch className="bl-search-container" placeholder={t('common.searchStore')} />
48
+ ) : (
49
+ <Autocomplete onSelect={handleSearchSelect} wrapChildren={wrapChildren} />
50
+ )}
44
51
  <Box mt={0} ml="16px" className="filter-container">
45
52
  <Hidden mdUp>
46
53
  {/* 小屏幕下类别 */}
@@ -0,0 +1,93 @@
1
+ import { useEffect, useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import SearchIcon from '@mui/icons-material/Search';
4
+ import CloseIcon from '@mui/icons-material/Close';
5
+ import { OutlinedInput, InputAdornment } from '@mui/material';
6
+ import { useDebounceFn } from 'ahooks';
7
+ import styled from '@emotion/styled';
8
+
9
+ import { useFilterContext } from '../contexts/filter';
10
+
11
+ function BaseSearch({ placeholder, ...rest }) {
12
+ const { filters, handleKeyword } = useFilterContext();
13
+ const [searchStr, setSearchStr] = useState(filters.keyword || '');
14
+
15
+ const debouncedSearch = useDebounceFn(handleKeyword, { wait: 300 });
16
+ const handleChange = (event) => {
17
+ const { value } = event.target;
18
+ setSearchStr(value);
19
+ debouncedSearch.run(value);
20
+ };
21
+ const handleClose = () => {
22
+ setSearchStr('');
23
+ handleKeyword();
24
+ };
25
+ useEffect(() => {
26
+ setSearchStr(filters.keyword || '');
27
+ }, [filters.keyword]);
28
+
29
+ return (
30
+ <StyledSearch
31
+ inputProps={{
32
+ 'data-cy': 'search-blocklet',
33
+ }}
34
+ startAdornment={
35
+ <InputAdornment position="start">
36
+ <StyledSearchIcon />
37
+ </InputAdornment>
38
+ }
39
+ onChange={handleChange}
40
+ placeholder={placeholder}
41
+ value={searchStr}
42
+ title={placeholder}
43
+ data-cy="search"
44
+ endAdornment={
45
+ searchStr && (
46
+ <InputAdornment position="end">
47
+ <StyledCloseIcon data-cy="search-delete" onClick={handleClose} />
48
+ </InputAdornment>
49
+ )
50
+ }
51
+ {...rest}
52
+ />
53
+ );
54
+ }
55
+ BaseSearch.propTypes = {
56
+ placeholder: PropTypes.string,
57
+ };
58
+ BaseSearch.defaultProps = {
59
+ placeholder: 'Type to search...',
60
+ };
61
+ const StyledSearch = styled(OutlinedInput)`
62
+ background-color: ${(props) => props.theme.palette.grey[50]};
63
+ font-size: 14px;
64
+ border-radius: 6px;
65
+ .MuiInputBase-input {
66
+ padding: 8px 0 8px 10px;
67
+ }
68
+ .MuiOutlinedInput-notchedOutline {
69
+ border: none;
70
+ }
71
+ .Mui-focused {
72
+ background-color: #f6f6f6;
73
+ .MuiInputBase-input::placeholder {
74
+ color: transparent;
75
+ }
76
+ }
77
+ `;
78
+
79
+ const StyledSearchIcon = styled(SearchIcon)`
80
+ color: ${(props) => props.theme.palette.grey[500]};
81
+ font-size: 28px;
82
+ @media (max-width: ${(props) => props.theme.breakpoints.values.md}px) {
83
+ font-size: 24px;
84
+ }
85
+ `;
86
+
87
+ const StyledCloseIcon = styled(CloseIcon)`
88
+ color: ${(props) => props.theme.palette.grey[500]};
89
+ font-size: 16px;
90
+ cursor: pointer;
91
+ `;
92
+
93
+ export default BaseSearch;
@@ -21,6 +21,7 @@ function FilterProvider({
21
21
  onSearchSelect,
22
22
  extraFilter,
23
23
  wrapChildren,
24
+ baseSearch,
24
25
  }) {
25
26
  const storeApi = useMemo(() => {
26
27
  return axios.create({
@@ -118,6 +119,7 @@ function FilterProvider({
118
119
  categoryOptions,
119
120
  priceOptions,
120
121
  storeApi,
122
+ baseSearch,
121
123
  hasNextPage: blockletsState.list.length < blockletsState.total,
122
124
  handleSort: (sort) => {
123
125
  const changeData = {
@@ -16,6 +16,7 @@ const propTypes = {
16
16
  onFilterChange: PropTypes.func,
17
17
  onSearchSelect: PropTypes.func,
18
18
  locale: PropTypes.oneOf(['zh', 'en']),
19
+ baseSearch: PropTypes.bool,
19
20
  };
20
21
 
21
22
  const defaultProps = {
@@ -27,6 +28,7 @@ const defaultProps = {
27
28
  },
28
29
  wrapChildren: (children) => children,
29
30
  extraFilter: (list) => list,
31
+ baseSearch: false,
30
32
  };
31
33
 
32
34
  export { propTypes, defaultProps };