@dhis2-ui/select 10.10.0-alpha.3 → 10.10.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.
Files changed (26) hide show
  1. package/README.md +1 -1
  2. package/build/cjs/locales/en_US/translations.json +9 -0
  3. package/build/cjs/locales/fr/translations.json +2 -2
  4. package/build/cjs/locales/hi_IN/translations.json +7 -0
  5. package/build/cjs/locales/index.js +54 -50
  6. package/build/cjs/locales/zh/translations.json +3 -1
  7. package/build/cjs/locales/zh_CN/translations.json +1 -1
  8. package/build/cjs/simple-single-select/__stories__/WithServerSideFilteringDemo.js +236 -0
  9. package/build/cjs/simple-single-select/__stories__/WithSimpleFilteringDemo.js +62 -0
  10. package/build/cjs/simple-single-select/__stories__/simple-single-select-server-side-filtering/CustomDataProvider.js +94 -0
  11. package/build/cjs/simple-single-select/__stories__/simple-single-select-server-side-filtering/dataElements.js +3118 -0
  12. package/build/cjs/simple-single-select/__stories__/simple-single-select-server-side-filtering/index.js +12 -0
  13. package/build/cjs/simple-single-select/simple-single-select.prod.stories.js +14 -0
  14. package/build/es/locales/en_US/translations.json +9 -0
  15. package/build/es/locales/fr/translations.json +2 -2
  16. package/build/es/locales/hi_IN/translations.json +7 -0
  17. package/build/es/locales/index.js +4 -0
  18. package/build/es/locales/zh/translations.json +3 -1
  19. package/build/es/locales/zh_CN/translations.json +1 -1
  20. package/build/es/simple-single-select/__stories__/WithServerSideFilteringDemo.js +228 -0
  21. package/build/es/simple-single-select/__stories__/WithSimpleFilteringDemo.js +53 -0
  22. package/build/es/simple-single-select/__stories__/simple-single-select-server-side-filtering/CustomDataProvider.js +86 -0
  23. package/build/es/simple-single-select/__stories__/simple-single-select-server-side-filtering/dataElements.js +3112 -0
  24. package/build/es/simple-single-select/__stories__/simple-single-select-server-side-filtering/index.js +1 -0
  25. package/build/es/simple-single-select/simple-single-select.prod.stories.js +3 -1
  26. package/package.json +15 -15
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "CustomDataProvider", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _CustomDataProvider.CustomDataProvider;
10
+ }
11
+ });
12
+ var _CustomDataProvider = require("./CustomDataProvider.js");
@@ -183,6 +183,18 @@ Object.defineProperty(exports, "WithSelectionAndDisabled", {
183
183
  return _WithSelectionAndDisabled.WithSelectionAndDisabled;
184
184
  }
185
185
  });
186
+ Object.defineProperty(exports, "WithServerSideFilteringDemo", {
187
+ enumerable: true,
188
+ get: function () {
189
+ return _WithServerSideFilteringDemo.WithServerSideFilteringDemo;
190
+ }
191
+ });
192
+ Object.defineProperty(exports, "WithSimpleFilteringDemo", {
193
+ enumerable: true,
194
+ get: function () {
195
+ return _WithSimpleFilteringDemo.WithSimpleFilteringDemo;
196
+ }
197
+ });
186
198
  Object.defineProperty(exports, "WithoutOptionsAndLoading", {
187
199
  enumerable: true,
188
200
  get: function () {
@@ -229,6 +241,8 @@ var _DefaultPosition = require("./__stories__/DefaultPosition.js");
229
241
  var _FlippedPosition = require("./__stories__/FlippedPosition.js");
230
242
  var _ShiftedIntoView = require("./__stories__/ShiftedIntoView.js");
231
243
  var _WithMultipleSelectsAndScrollableParent = require("./__stories__/WithMultipleSelectsAndScrollableParent.js");
244
+ var _WithSimpleFilteringDemo = require("./__stories__/WithSimpleFilteringDemo.js");
245
+ var _WithServerSideFilteringDemo = require("./__stories__/WithServerSideFilteringDemo.js");
232
246
  var _default = exports.default = {
233
247
  title: 'Simple Single Select',
234
248
  component: _simpleSingleSelect.SimpleSingleSelect
@@ -0,0 +1,9 @@
1
+ {
2
+ "Clear": "साफ़ करें",
3
+ "No data found": "",
4
+ "Type to filter options": "",
5
+ "Loading options": "",
6
+ "No options found": "",
7
+ "Search options": "",
8
+ "{{clearText}}": ""
9
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "Clear": "Effacer",
3
3
  "No data found": "Aucune valeur trouvée",
4
- "Type to filter options": "",
4
+ "Type to filter options": "Tapez pour filtrer les options",
5
5
  "Loading options": "Chargement des options",
6
- "No options found": ""
6
+ "No options found": "Pas d'options trouvées"
7
7
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "Clear": "साफ़ करें",
3
+ "No data found": "",
4
+ "Type to filter options": "",
5
+ "Loading options": "",
6
+ "No options found": ""
7
+ }
@@ -13,9 +13,11 @@ import ckbTranslations from './ckb/translations.json';
13
13
  import csTranslations from './cs/translations.json';
14
14
  import daTranslations from './da/translations.json';
15
15
  import enTranslations from './en/translations.json';
16
+ import en_USTranslations from './en_US/translations.json';
16
17
  import esTranslations from './es/translations.json';
17
18
  import es_419Translations from './es_419/translations.json';
18
19
  import frTranslations from './fr/translations.json';
20
+ import hi_INTranslations from './hi_IN/translations.json';
19
21
  import idTranslations from './id/translations.json';
20
22
  import kmTranslations from './km/translations.json';
21
23
  import loTranslations from './lo/translations.json';
@@ -45,9 +47,11 @@ i18n.addResources('ckb', namespace, ckbTranslations);
45
47
  i18n.addResources('cs', namespace, csTranslations);
46
48
  i18n.addResources('da', namespace, daTranslations);
47
49
  i18n.addResources('en', namespace, enTranslations);
50
+ i18n.addResources('en_US', namespace, en_USTranslations);
48
51
  i18n.addResources('es', namespace, esTranslations);
49
52
  i18n.addResources('es_419', namespace, es_419Translations);
50
53
  i18n.addResources('fr', namespace, frTranslations);
54
+ i18n.addResources('hi_IN', namespace, hi_INTranslations);
51
55
  i18n.addResources('id', namespace, idTranslations);
52
56
  i18n.addResources('km', namespace, kmTranslations);
53
57
  i18n.addResources('lo', namespace, loTranslations);
@@ -3,5 +3,7 @@
3
3
  "No data found": "没有发现数据",
4
4
  "Type to filter options": "键入过滤选项",
5
5
  "Loading options": "加载选项",
6
- "No options found": "没有找到选项"
6
+ "No options found": "没有找到选项",
7
+ "Search options": "搜索选项",
8
+ "{{clearText}}": "{{clearText}}"
7
9
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "Clear": "清除",
3
3
  "No data found": "没有数据被找到",
4
- "Type to filter options": "",
4
+ "Type to filter options": "键入过滤选项",
5
5
  "Loading options": "",
6
6
  "No options found": ""
7
7
  }
@@ -0,0 +1,228 @@
1
+ import { useDataEngine, useDataQuery } from '@dhis2/app-runtime';
2
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
3
+ import { SimpleSingleSelect } from '../simple-single-select.js';
4
+ import { CustomDataProvider } from './simple-single-select-server-side-filtering/index.js';
5
+ function dataElementToOption(_ref) {
6
+ let {
7
+ id,
8
+ displayName
9
+ } = _ref;
10
+ return {
11
+ value: id,
12
+ label: displayName
13
+ };
14
+ }
15
+ function useLoadDataElementQuery(options) {
16
+ return useDataQuery({
17
+ result: {
18
+ resource: 'dataElements',
19
+ id: _ref2 => {
20
+ let {
21
+ id
22
+ } = _ref2;
23
+ return id;
24
+ }
25
+ }
26
+ }, {
27
+ ...options,
28
+ lazy: true
29
+ });
30
+ }
31
+ function useLoadDataElementsQuery(options) {
32
+ return useDataQuery({
33
+ result: {
34
+ resource: 'dataElements',
35
+ params: _ref3 => {
36
+ let {
37
+ page
38
+ } = _ref3;
39
+ return {
40
+ page,
41
+ pageSize: 10
42
+ };
43
+ }
44
+ }
45
+ }, options);
46
+ }
47
+ function useLoadFilteredDataElementsQuery(customOptions) {
48
+ const engine = useDataEngine();
49
+ const timeout = useRef(null);
50
+ const abortController = useRef();
51
+ const [loading, setLoading] = useState(false);
52
+ const [error, setError] = useState(null);
53
+ const refetch = useCallback(_ref4 => {
54
+ let {
55
+ searchTerm,
56
+ page
57
+ } = _ref4;
58
+ if (timeout.current) {
59
+ var _abortController$curr;
60
+ clearTimeout(timeout.current);
61
+ (_abortController$curr = abortController.current) === null || _abortController$curr === void 0 ? void 0 : _abortController$curr.abort();
62
+ }
63
+ return new Promise((resolve, reject) => {
64
+ timeout.current = setTimeout(async () => {
65
+ try {
66
+ abortController.current = new AbortController();
67
+ setLoading(true);
68
+ const query = {
69
+ result: {
70
+ resource: 'dataElements',
71
+ params: {
72
+ filter: [`displayName:ilike:${searchTerm}`],
73
+ pageSize: 10,
74
+ page
75
+ }
76
+ }
77
+ };
78
+ const options = {
79
+ ...customOptions,
80
+ signal: abortController.current.signal
81
+ };
82
+ try {
83
+ const result = await engine.query(query, options);
84
+ resolve(result);
85
+ } catch (e) {
86
+ setError(e);
87
+ }
88
+ abortController.current = null;
89
+ timeout.current = null;
90
+ setLoading(false);
91
+ } catch (e) {
92
+ reject(e);
93
+ }
94
+ }, 200);
95
+ });
96
+ }, [abortController, engine, customOptions]);
97
+ return {
98
+ loading,
99
+ error,
100
+ refetch
101
+ };
102
+ }
103
+ function ServerSideFilteringSelect() {
104
+ const [initializedSelectedLabel, setInitializedSelectedLabel] = useState(false);
105
+ const [selectedOption, setSelectedOption] = useState({
106
+ value: 'fbfJHSPpUQD',
107
+ label: 'Loading...'
108
+ });
109
+ const [loadedOptions, setLoadedOptions] = useState([]);
110
+ const [defaultPager, setDefaultPager] = useState({
111
+ page: 0,
112
+ pageSize: -1,
113
+ total: -1,
114
+ pageCount: -1
115
+ });
116
+ const [searchTerm, _setSearchTerm] = useState('');
117
+ const [filteredOptions, setFilteredOptions] = useState([]);
118
+ const [filterPager, setFilterPager] = useState({
119
+ page: 0,
120
+ pageSize: -1,
121
+ total: -1,
122
+ pageCount: -1
123
+ });
124
+ const loadDataElementQuery = useLoadDataElementQuery({
125
+ onComplete: data => {
126
+ setSelectedOption(dataElementToOption(data.result.dataElements));
127
+ setInitializedSelectedLabel(true); // Done AFTER setting the option's label!
128
+ },
129
+ onError: () => {
130
+ setSelectedOption(option => ({
131
+ ...option,
132
+ label: option.value
133
+ }));
134
+ setInitializedSelectedLabel(true); // Done AFTER setting the option's label!
135
+ }
136
+ });
137
+ const loadDataElementsQuery = useLoadDataElementsQuery({
138
+ onComplete: _ref5 => {
139
+ let {
140
+ result
141
+ } = _ref5;
142
+ setDefaultPager(result.pager);
143
+ setLoadedOptions(prevLoadedOptions => [...prevLoadedOptions, ...result.dataElements.map(dataElementToOption)]);
144
+ },
145
+ onError: () => {
146
+ setDefaultPager(prevPager => ({
147
+ ...prevPager,
148
+ pageCount: prevPager.page,
149
+ total: loadedOptions.length
150
+ }));
151
+ }
152
+ });
153
+ const loadFilteredDataElementsQuery = useLoadFilteredDataElementsQuery({
154
+ onComplete: _ref6 => {
155
+ let {
156
+ result
157
+ } = _ref6;
158
+ setFilterPager(result.pager);
159
+ setFilteredOptions(prevFilteredOptions => {
160
+ const newOptions = result.dataElements.map(dataElementToOption);
161
+ return result.pager.page === 1 ? newOptions : [...prevFilteredOptions, ...newOptions];
162
+ });
163
+ },
164
+ onError: () => {
165
+ setFilterPager(prevPager => ({
166
+ ...prevPager,
167
+ pageCount: prevPager.page,
168
+ total: filteredOptions.length
169
+ }));
170
+ }
171
+ });
172
+ const loadingOptions = loadDataElementsQuery.loading || loadFilteredDataElementsQuery.loading;
173
+ const options = searchTerm ? filteredOptions : loadedOptions;
174
+ const setSearchTerm = useCallback(nextSearchTerm => {
175
+ _setSearchTerm(nextSearchTerm);
176
+ if (nextSearchTerm.trim()) {
177
+ loadFilteredDataElementsQuery.refetch({
178
+ page: 1,
179
+ searchTerm: nextSearchTerm
180
+ });
181
+ }
182
+ }, [loadFilteredDataElementsQuery.refetch]);
183
+ const loadNextPage = useCallback(() => {
184
+ const pager = searchTerm ? filterPager : defaultPager;
185
+ if (pager.page === pager.pageCount || loadingOptions) {
186
+ return;
187
+ }
188
+ if (searchTerm) {
189
+ loadFilteredDataElementsQuery.refetch({
190
+ page: pager.page + 1,
191
+ searchTerm
192
+ });
193
+ } else {
194
+ loadDataElementsQuery.refetch({
195
+ page: pager.page + 1
196
+ });
197
+ }
198
+ }, [filterPager, defaultPager, searchTerm, loadingOptions, loadFilteredDataElementsQuery.refetch, loadDataElementsQuery.refetch]);
199
+ useEffect(() => {
200
+ if (selectedOption !== null && selectedOption !== void 0 && selectedOption.value) {
201
+ loadDataElementQuery.refetch({
202
+ id: selectedOption.value
203
+ });
204
+ } else {
205
+ setInitializedSelectedLabel(true);
206
+ }
207
+ },
208
+ // Needs to run on initial render only!
209
+ // eslint-disable-next-line react-hooks/exhaustive-deps
210
+ []);
211
+ return /*#__PURE__*/React.createElement(SimpleSingleSelect, {
212
+ name: "demo",
213
+ disabled: !initializedSelectedLabel,
214
+ loading: loadingOptions,
215
+ options: options,
216
+ selected: selectedOption,
217
+ filterable: true,
218
+ filterValue: searchTerm,
219
+ filterPlaceholder: "search for 'ART' or 'ANC'",
220
+ onFilterChange: setSearchTerm,
221
+ noMatchText: "No options were found",
222
+ empty: "Please use the search input to find data elements",
223
+ onChange: setSelectedOption,
224
+ onEndReached: loadNextPage
225
+ });
226
+ }
227
+ const Wrapper = () => /*#__PURE__*/React.createElement(CustomDataProvider, null, /*#__PURE__*/React.createElement(ServerSideFilteringSelect, null));
228
+ export { Wrapper as WithServerSideFilteringDemo };
@@ -0,0 +1,53 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { SimpleSingleSelect } from '../simple-single-select.js';
3
+ const options = [{
4
+ label: 'No selection',
5
+ value: ''
6
+ }, {
7
+ label: 'ANC 1st visit',
8
+ value: 'anc_1st_visit'
9
+ }, {
10
+ label: 'ANC 2nd visit',
11
+ value: 'anc_2nd_visit'
12
+ }, {
13
+ label: 'ARI treated follow-up',
14
+ value: 'ari_treated_follow-up'
15
+ }, {
16
+ label: 'ARI treated with new',
17
+ value: 'ari_treated_with_new'
18
+ }];
19
+ function filterOptions(options, searchTerm) {
20
+ // If there is no search term, we want to return all options
21
+ if (!searchTerm) {
22
+ return options;
23
+ }
24
+
25
+ // We're transform both the label and the search term to
26
+ // lower-case strings so the search is case-insensitive
27
+ return options.filter(_ref => {
28
+ let {
29
+ label
30
+ } = _ref;
31
+ return label.toLowerCase().startsWith(searchTerm.toLowerCase());
32
+ });
33
+ }
34
+ export const WithSimpleFilteringDemo = () => {
35
+ // Handle actual value changes
36
+ const [selected, setSelected] = useState({
37
+ value: '',
38
+ label: 'No selection'
39
+ });
40
+
41
+ // Handle filtering
42
+ const [searchTerm, setSearchTerm] = useState('');
43
+ const filteredOptions = useMemo(() => filterOptions(options, searchTerm), [searchTerm]);
44
+ return /*#__PURE__*/React.createElement(SimpleSingleSelect, {
45
+ filterable: true,
46
+ filterValue: searchTerm,
47
+ idPrefix: "simple",
48
+ options: filteredOptions,
49
+ selected: selected,
50
+ onChange: setSelected,
51
+ onFilterChange: setSearchTerm
52
+ });
53
+ };
@@ -0,0 +1,86 @@
1
+ /* eslint-disable react/prop-types */
2
+ import { CustomDataProvider } from '@dhis2/app-runtime';
3
+ import React from 'react';
4
+ import { dataElements as allDataElements } from './dataElements.js';
5
+ function randomBetween(min, max) {
6
+ return Math.floor(Math.random() * (max - min + 1) + min);
7
+ }
8
+ const fakeNetworkDelay = _ref => {
9
+ let {
10
+ pager,
11
+ dataElements,
12
+ signal
13
+ } = _ref;
14
+ const delay = randomBetween(750, 1550);
15
+ const response = {
16
+ dataElements
17
+ };
18
+ if (pager) {
19
+ response.pager = pager;
20
+ }
21
+ return new Promise((resolve, reject) => {
22
+ const onAbort = () => {
23
+ clearTimeout(timeout);
24
+ reject('Aborted');
25
+ };
26
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort);
27
+ const timeout = setTimeout(() => {
28
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
29
+ resolve(response);
30
+ }, delay);
31
+ });
32
+ };
33
+ const Provider = _ref2 => {
34
+ let {
35
+ children
36
+ } = _ref2;
37
+ const data = {
38
+ dataElements: (_, _ref3, _ref4) => {
39
+ let {
40
+ id,
41
+ params = {}
42
+ } = _ref3;
43
+ let {
44
+ signal
45
+ } = _ref4;
46
+ if (id) {
47
+ const dataElement = allDataElements.find(curDE => id === curDE.id);
48
+ return fakeNetworkDelay({
49
+ dataElements: dataElement,
50
+ signal
51
+ });
52
+ }
53
+
54
+ // Only this specific filter is supported by this server-mock
55
+ const searchTerm = params.filter ? params.filter[0].split(':')[2] : '';
56
+ const filteredDataElements = searchTerm ? allDataElements.filter(_ref5 => {
57
+ let {
58
+ displayName
59
+ } = _ref5;
60
+ return displayName.startsWith(searchTerm);
61
+ }) : allDataElements;
62
+ const page = params.page || 1;
63
+ const total = filteredDataElements.length;
64
+ const pageSize = params.pageSize || 50;
65
+ const pageCount = Math.ceil(total / pageSize);
66
+ const pager = {
67
+ page,
68
+ total,
69
+ pageSize,
70
+ pageCount
71
+ };
72
+ const start = (page - 1) * pageSize;
73
+ const end = start + pageSize;
74
+ const dataElements = filteredDataElements.slice(start, end);
75
+ return fakeNetworkDelay({
76
+ pager,
77
+ dataElements,
78
+ signal
79
+ });
80
+ }
81
+ };
82
+ return /*#__PURE__*/React.createElement(CustomDataProvider, {
83
+ data: data
84
+ }, children);
85
+ };
86
+ export { Provider as CustomDataProvider };