@k-int/stripes-kint-components 1.5.0 → 2.0.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/es/index.js +80 -25
  3. package/es/lib/ActionList/ActionList.js +92 -33
  4. package/es/lib/ActionList/ActionListFieldArray.js +202 -104
  5. package/es/lib/ActionList/index.js +7 -3
  6. package/es/lib/CustomProperties/Config/CustomPropertiesLookup.js +198 -0
  7. package/es/lib/CustomProperties/Config/CustomPropertiesSettings.js +321 -0
  8. package/es/lib/CustomProperties/Config/CustomPropertiesView.js +166 -0
  9. package/es/lib/CustomProperties/Config/CustomPropertyForm.js +357 -0
  10. package/es/lib/CustomProperties/Config/index.js +41 -0
  11. package/es/lib/EditableRefdataList/EditableRefdataList.js +69 -24
  12. package/es/lib/EditableRefdataList/index.js +7 -3
  13. package/es/lib/EditableSettingsList/EditableSettingsList.js +90 -0
  14. package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.js +90 -0
  15. package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.test.js +181 -0
  16. package/es/lib/{Settings → EditableSettingsList/SettingField}/EditSettingValue.js +72 -9
  17. package/es/lib/EditableSettingsList/SettingField/EditSettingValue.test.js +447 -0
  18. package/es/lib/{Settings → EditableSettingsList/SettingField}/RenderSettingValue.js +45 -7
  19. package/es/lib/EditableSettingsList/SettingField/RenderSettingValue.test.js +495 -0
  20. package/es/lib/EditableSettingsList/SettingField/SettingField.js +187 -0
  21. package/es/lib/EditableSettingsList/SettingField/SettingField.test.js +180 -0
  22. package/es/lib/EditableSettingsList/SettingField/index.js +35 -0
  23. package/es/lib/EditableSettingsList/index.js +35 -0
  24. package/es/lib/FormModal/FormModal.js +126 -0
  25. package/es/lib/FormModal/index.js +19 -0
  26. package/es/lib/NoResultsMessage/NoResultsMessage.js +65 -32
  27. package/es/lib/NoResultsMessage/index.js +7 -3
  28. package/es/lib/QueryTypedown/QueryTypedown.js +48 -9
  29. package/es/lib/QueryTypedown/index.js +6 -2
  30. package/es/lib/RefdataButtons/RefdataButtons.js +143 -0
  31. package/es/lib/RefdataButtons/index.js +19 -0
  32. package/es/lib/SASQLookupComponent/SASQLookupComponent.js +194 -140
  33. package/es/lib/SASQLookupComponent/index.js +6 -2
  34. package/es/lib/SASQRoute/SASQRoute.js +55 -18
  35. package/es/lib/SASQRoute/index.js +6 -2
  36. package/es/lib/SASQViewComponent/SASQViewComponent.js +50 -11
  37. package/es/lib/SASQViewComponent/index.js +6 -2
  38. package/es/lib/SearchField/SearchField.js +48 -13
  39. package/es/lib/SearchField/index.js +6 -2
  40. package/es/lib/SettingPage/SettingPage.js +99 -0
  41. package/es/lib/SettingPage/SettingPagePane.js +83 -0
  42. package/es/lib/SettingPage/index.js +27 -0
  43. package/es/lib/Typedown/Typedown.js +174 -99
  44. package/es/lib/Typedown/index.js +6 -2
  45. package/es/lib/constants/customProperties.js +60 -0
  46. package/es/lib/constants/eventCodes.js +31 -1
  47. package/es/lib/contexts/SettingsContext.js +41 -0
  48. package/es/lib/contexts/index.js +19 -0
  49. package/es/lib/hooks/index.js +44 -10
  50. package/es/lib/hooks/settingsHooks/index.js +27 -0
  51. package/es/lib/hooks/settingsHooks/useSettingSection.js +74 -0
  52. package/es/lib/hooks/settingsHooks/useSettings.js +175 -0
  53. package/es/lib/hooks/typedownHooks/index.js +8 -28
  54. package/es/lib/hooks/typedownHooks/useTypedown.js +129 -12
  55. package/es/lib/hooks/typedownHooks/useTypedownData.js +35 -2
  56. package/es/lib/hooks/typedownHooks/useTypedownToggle.js +39 -6
  57. package/es/lib/hooks/useActiveElement.js +33 -2
  58. package/es/lib/hooks/useCustomProperties.js +112 -0
  59. package/es/lib/hooks/useHelperApp.js +44 -11
  60. package/es/lib/hooks/useKiwtFieldArray.js +37 -4
  61. package/es/lib/hooks/useKiwtSASQuery.js +43 -9
  62. package/es/lib/hooks/useLocalStorageState.js +37 -4
  63. package/es/lib/hooks/useMutateCustomProperties.js +143 -0
  64. package/es/lib/hooks/useMutateRefdataValue.js +42 -9
  65. package/es/lib/hooks/useQIndex.js +42 -9
  66. package/es/lib/hooks/useRefdata.js +43 -16
  67. package/es/lib/hooks/useTemplates.js +36 -3
  68. package/es/lib/utils/buildUrl.js +43 -10
  69. package/es/lib/utils/generateKiwtQuery.js +33 -4
  70. package/es/lib/utils/generateKiwtQueryParams.js +31 -2
  71. package/es/lib/utils/index.js +41 -5
  72. package/es/lib/utils/refdataOptions.js +43 -0
  73. package/es/lib/utils/renderHelpText.js +109 -0
  74. package/es/lib/utils/selectorSafe.js +31 -2
  75. package/es/lib/utils/sortByLabel.js +55 -0
  76. package/es/lib/utils/toCamelCase.js +48 -0
  77. package/jest.config.js +15 -1
  78. package/package.json +19 -10
  79. package/src/index.js +25 -10
  80. package/src/lib/ActionList/ActionList.js +32 -22
  81. package/src/lib/ActionList/ActionListFieldArray.js +56 -10
  82. package/src/lib/ActionList/README.md +5 -1
  83. package/src/lib/ActionList/index.js +1 -1
  84. package/src/lib/CustomProperties/Config/CustomPropertiesLookup.js +111 -0
  85. package/src/lib/CustomProperties/Config/CustomPropertiesSettings.js +237 -0
  86. package/src/lib/CustomProperties/Config/CustomPropertiesView.js +150 -0
  87. package/src/lib/CustomProperties/Config/CustomPropertyForm.js +295 -0
  88. package/src/lib/CustomProperties/Config/index.js +4 -0
  89. package/src/lib/EditableRefdataList/EditableRefdataList.js +10 -5
  90. package/src/lib/EditableRefdataList/index.js +1 -1
  91. package/src/lib/{Settings → EditableSettingsList}/EditableSettingsList.js +0 -0
  92. package/src/lib/{Settings → EditableSettingsList}/EditableSettingsListFieldArray.js +2 -2
  93. package/src/lib/EditableSettingsList/EditableSettingsListFieldArray.test.js +111 -0
  94. package/src/lib/{Settings → EditableSettingsList/SettingField}/EditSettingValue.js +24 -1
  95. package/src/lib/EditableSettingsList/SettingField/EditSettingValue.test.js +379 -0
  96. package/src/lib/{Settings → EditableSettingsList/SettingField}/RenderSettingValue.js +2 -1
  97. package/src/lib/EditableSettingsList/SettingField/RenderSettingValue.test.js +368 -0
  98. package/src/lib/{Settings → EditableSettingsList/SettingField}/SettingField.js +7 -7
  99. package/src/lib/EditableSettingsList/SettingField/SettingField.test.js +80 -0
  100. package/src/lib/EditableSettingsList/SettingField/index.js +3 -0
  101. package/src/lib/EditableSettingsList/index.js +3 -0
  102. package/src/lib/FormModal/FormModal.js +71 -0
  103. package/src/lib/FormModal/index.js +1 -0
  104. package/src/lib/NoResultsMessage/NoResultsMessage.js +2 -2
  105. package/src/lib/NoResultsMessage/index.js +1 -1
  106. package/src/lib/{Settings → RefdataButtons}/RefdataButtons.js +1 -1
  107. package/src/lib/RefdataButtons/index.js +1 -0
  108. package/src/lib/SASQLookupComponent/SASQLookupComponent.js +7 -1
  109. package/src/lib/{Settings → SettingPage}/SettingPage.js +5 -5
  110. package/src/lib/{Settings → SettingPage}/SettingPagePane.js +12 -2
  111. package/src/lib/SettingPage/index.js +2 -0
  112. package/src/lib/Typedown/Typedown.js +52 -9
  113. package/src/lib/constants/customProperties.js +9 -0
  114. package/src/lib/{Settings → contexts}/SettingsContext.js +1 -1
  115. package/src/lib/contexts/index.js +2 -0
  116. package/src/lib/hooks/index.js +3 -0
  117. package/src/lib/hooks/settingsHooks/index.js +2 -0
  118. package/src/lib/{Settings → hooks/settingsHooks}/useSettingSection.js +0 -0
  119. package/src/lib/{Settings → hooks/settingsHooks}/useSettings.js +14 -6
  120. package/src/lib/hooks/typedownHooks/index.js +0 -3
  121. package/src/lib/hooks/typedownHooks/useTypedown.js +93 -11
  122. package/src/lib/hooks/useCustomProperties.js +73 -0
  123. package/src/lib/hooks/useMutateCustomProperties.js +62 -0
  124. package/src/lib/hooks/useRefdata.js +2 -8
  125. package/src/lib/utils/index.js +7 -0
  126. package/src/lib/utils/refdataOptions.js +7 -0
  127. package/src/lib/{Settings/utils → utils}/renderHelpText.js +1 -1
  128. package/src/lib/{Settings/utils → utils}/sortByLabel.js +1 -1
  129. package/src/lib/{Settings/utils → utils}/toCamelCase.js +0 -0
  130. package/test/helpers/index.js +1 -0
  131. package/test/helpers/translationsProperties.js +40 -0
  132. package/test/jest/helpers/KintHarness.js +36 -0
  133. package/test/jest/helpers/index.js +2 -0
  134. package/test/jest/helpers/renderWithKintHarness.js +15 -0
  135. package/test/jest/jest-transformer.js +4 -0
  136. package/test/jest/setupTests.js +1 -0
  137. package/translations/stripes-kint-components/en.json +48 -1
  138. package/yarn-error.log +14118 -0
  139. package/babelOptions.js +0 -30
  140. package/es/lib/Settings/EditableSettingsList.js +0 -57
  141. package/es/lib/Settings/EditableSettingsListFieldArray.js +0 -59
  142. package/es/lib/Settings/RefdataButtons.js +0 -100
  143. package/es/lib/Settings/SettingField.js +0 -144
  144. package/es/lib/Settings/SettingPage.js +0 -64
  145. package/es/lib/Settings/SettingPagePane.js +0 -43
  146. package/es/lib/Settings/SettingsContext.js +0 -18
  147. package/es/lib/Settings/index.js +0 -71
  148. package/es/lib/Settings/useSettingSection.js +0 -41
  149. package/es/lib/Settings/useSettings.js +0 -126
  150. package/es/lib/Settings/utils/index.js +0 -31
  151. package/es/lib/Settings/utils/renderHelpText.js +0 -57
  152. package/es/lib/Settings/utils/sortByLabel.js +0 -26
  153. package/es/lib/Settings/utils/toCamelCase.js +0 -19
  154. package/es/lib/TypeDown/TypeDown.js +0 -209
  155. package/es/lib/TypeDown/index.js +0 -15
  156. package/es/lib/hooks/typedownHooks/useTypedownFooter.js +0 -47
  157. package/es/lib/hooks/typedownHooks/useTypedownList.js +0 -45
  158. package/es/lib/hooks/typedownHooks/useTypedownSearchField.js +0 -47
  159. package/es/lib/utils/getFocusableElements.js +0 -132
  160. package/src/lib/Settings/index.js +0 -8
  161. package/src/lib/Settings/utils/index.js +0 -3
  162. package/src/lib/TypeDown/README.md +0 -1
  163. package/src/lib/TypeDown/TypeDown.js +0 -226
  164. package/src/lib/TypeDown/index.js +0 -1
  165. package/src/lib/hooks/typedownHooks/useTypedownFooter.js +0 -43
  166. package/src/lib/hooks/typedownHooks/useTypedownList.js +0 -36
  167. package/src/lib/hooks/typedownHooks/useTypedownSearchField.js +0 -39
  168. package/src/lib/utils/getFocusableElements.js +0 -99
@@ -0,0 +1,2 @@
1
+ export { default as SettingPagePane } from './SettingPagePane';
2
+ export { default as SettingPage } from './SettingPage';
@@ -4,7 +4,7 @@ import classnames from 'classnames';
4
4
 
5
5
  import get from 'lodash/get';
6
6
 
7
- import { EndOfList, IconButton, Popper } from '@folio/stripes/components';
7
+ import { EndOfList, IconButton, Label, Popper } from '@folio/stripes/components';
8
8
 
9
9
  // eslint-disable-next-line import/no-extraneous-dependencies
10
10
  import { interactionStyles } from '@folio/stripes-components/lib/sharedStyles/interactionStyles.css';
@@ -17,19 +17,29 @@ import selectorSafe from '../utils/selectorSafe';
17
17
 
18
18
  const Typedown = ({
19
19
  dataOptions,
20
+ endOfList,
21
+ id,
20
22
  input,
23
+ isSelected,
21
24
  filterPath,
25
+ label,
22
26
  meta,
23
27
  onChange,
24
28
  onType,
25
29
  renderFooter = null,
26
30
  renderListItem = null,
31
+ required,
27
32
  uniqueIdentificationPath = 'id'
28
33
  }) => {
29
34
  const selectedUniqueId = get(input.value, uniqueIdentificationPath);
30
35
 
31
36
  // Display data needs to be in line with data options but also able to react to default handleType
32
37
  const [displayData, setDisplayData] = useState(dataOptions);
38
+
39
+ // keep track of what we've typed and whether we've typed an exact match or not
40
+ const [currentlyTyped, setCurrentlyTyped] = useState('');
41
+ const [exactMatch, setExactMatch] = useState(false);
42
+
33
43
  useEffect(() => {
34
44
  setDisplayData(dataOptions);
35
45
  }, [dataOptions]);
@@ -46,6 +56,14 @@ const Typedown = ({
46
56
  } else {
47
57
  setDisplayData(dataOptions);
48
58
  }
59
+
60
+ setCurrentlyTyped(e.target.value);
61
+
62
+ if (displayData.length === 1 && get(displayData[0], filterPath) === e.target.value) {
63
+ setExactMatch(true);
64
+ } else {
65
+ setExactMatch(false);
66
+ }
49
67
  };
50
68
 
51
69
  // Hook to set up all the essentials
@@ -74,11 +92,11 @@ const Typedown = ({
74
92
  className={css.listItem}
75
93
  >
76
94
  {renderListItem ?
77
- renderListItem(option) :
95
+ renderListItem(option, currentlyTyped, exactMatch) :
78
96
  get(option, uniqueIdentificationPath)
79
97
  }
80
98
  </div>
81
- ), [renderListItem, uniqueIdentificationPath]);
99
+ ), [currentlyTyped, exactMatch, renderListItem, uniqueIdentificationPath]);
82
100
 
83
101
  const handleChange = useCallback(value => {
84
102
  input.onChange(value);
@@ -101,7 +119,7 @@ const Typedown = ({
101
119
  id="typedown-list"
102
120
  >
103
121
  {displayData?.length ? displayData?.map((d, index) => {
104
- const isSelected = get(input.value, uniqueIdentificationPath) === get(d, uniqueIdentificationPath);
122
+ const isSelectedEval = isSelected ? isSelected(input.value, d) : get(input.value, uniqueIdentificationPath) === get(d, uniqueIdentificationPath);
105
123
  return (
106
124
  <button
107
125
  key={`typedown-button-[${index}]`}
@@ -110,7 +128,7 @@ const Typedown = ({
110
128
  css.fullWidth,
111
129
  css.menuButton
112
130
  )}
113
- data-selected={isSelected}
131
+ data-selected={isSelectedEval}
114
132
  id={`typedown-button-[${index}]`}
115
133
  onClick={() => {
116
134
  handleChange(d);
@@ -123,27 +141,30 @@ const Typedown = ({
123
141
  </button>
124
142
  );
125
143
  }) :
126
- // TODO test this
127
- <EndOfList />
144
+ endOfList || <EndOfList />
128
145
  }
129
146
  </div>
130
147
  {renderFooter &&
131
148
  <div
132
149
  ref={footerRef}
133
150
  className={css.footer}
134
- id="typedown-footer"
151
+ id={`typedown-footer-${selectorSafe(input.name)}`}
135
152
  >
136
- {renderFooter()}
153
+ {renderFooter(displayData, currentlyTyped, exactMatch)}
137
154
  </div>
138
155
  }
139
156
  </div>
140
157
  );
141
158
  }, [
159
+ currentlyTyped,
142
160
  displayData,
161
+ endOfList,
162
+ exactMatch,
143
163
  footerRef,
144
164
  handleChange,
145
165
  handleNextFocus,
146
166
  input,
167
+ isSelected,
147
168
  listKeyDownHandler,
148
169
  listRef,
149
170
  renderFooter,
@@ -174,6 +195,15 @@ const Typedown = ({
174
195
  <div
175
196
  ref={resizeRef}
176
197
  >
198
+ {label &&
199
+ <Label
200
+ htmlFor={id}
201
+ id={`${id}-label`}
202
+ required={required}
203
+ >
204
+ {label}
205
+ </Label>
206
+ }
177
207
  {renderSearchField()}
178
208
  <Popper
179
209
  key="typedown-menu-toggle"
@@ -222,12 +252,25 @@ const Typedown = ({
222
252
 
223
253
  Typedown.propTypes = {
224
254
  dataOptions: PropTypes.arrayOf(PropTypes.object),
255
+ endOfList: PropTypes.oneOfType([
256
+ PropTypes.func,
257
+ PropTypes.node,
258
+ PropTypes.element
259
+ ]),
260
+ filterPath: PropTypes.string,
261
+ id: PropTypes.string,
225
262
  input: PropTypes.object,
263
+ isSelected: PropTypes.func,
264
+ label: PropTypes.oneOfType([
265
+ PropTypes.string,
266
+ PropTypes.element
267
+ ]),
226
268
  meta: PropTypes.object,
227
269
  onChange: PropTypes.func,
228
270
  onType: PropTypes.func,
229
271
  renderFooter: PropTypes.func,
230
272
  renderListItem: PropTypes.func,
273
+ required: PropTypes.bool,
231
274
  uniqueIdentificationPath: PropTypes.string
232
275
  };
233
276
 
@@ -0,0 +1,9 @@
1
+ export const TYPE_CLASS_PREFIX = 'com.k_int.web.toolkit.custprops.types.CustomProperty';
2
+ export const BLOB_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyBlob';
3
+ export const BOOLEAN_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyBoolean';
4
+ export const CONTAINER_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyContainer';
5
+ export const DECIMAL_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyDecimal';
6
+ export const INTEGER_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyInteger';
7
+ export const REFDATA_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyRefdata';
8
+ export const REFDATA_DEFINITION_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyRefdataDefinition';
9
+ export const TEXT_CLASS_NAME = 'com.k_int.web.toolkit.custprops.types.CustomPropertyText';
@@ -1,4 +1,4 @@
1
- import React, { createContext } from 'react';
1
+ import { createContext } from 'react';
2
2
 
3
3
  const SettingsContext = createContext();
4
4
  export default SettingsContext;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { default as SettingsContext } from './SettingsContext';
@@ -6,4 +6,7 @@ export { default as useKiwtSASQuery } from './useKiwtSASQuery';
6
6
  export { default as useHelperApp } from './useHelperApp';
7
7
  export { default as useLocalStorageState } from './useLocalStorageState';
8
8
  export { default as useQIndex } from './useQIndex';
9
+ export { useSettings, useSettingSection } from './settingsHooks';
9
10
  export { default as useKiwtFieldArray } from './useKiwtFieldArray';
11
+ export { default as useCustomProperties } from './useCustomProperties';
12
+ export { default as useMutateCustomProperties } from './useMutateCustomProperties';
@@ -0,0 +1,2 @@
1
+ export { default as useSettings } from './useSettings';
2
+ export { default as useSettingSection } from './useSettingSection';
@@ -1,15 +1,16 @@
1
1
  import React, { useContext } from 'react';
2
+ import PropTypes from 'prop-types';
3
+
2
4
  import { useQuery } from 'react-query';
3
5
  import { FormattedMessage, useIntl } from 'react-intl';
4
6
  import { useOkapiKy } from '@folio/stripes/core';
5
7
 
6
8
  import { Settings } from '@folio/stripes/smart-components';
7
9
 
8
- import SettingPage from './SettingPage';
9
- import SettingPagePane from './SettingPagePane';
10
- import SettingsContext from './SettingsContext';
10
+ import { SettingPage, SettingPagePane } from '../../SettingPage';
11
+ import { SettingsContext } from '../../contexts';
11
12
 
12
- import { sortByLabel, toCamelCase } from './utils';
13
+ import { sortByLabel, toCamelCase } from '../../utils';
13
14
 
14
15
  const useSettings = ({
15
16
  dynamicPageExclusions,
@@ -21,7 +22,7 @@ const useSettings = ({
21
22
  }) => {
22
23
  const ky = useOkapiKy();
23
24
  const intl = useIntl();
24
- const extraPathItems = dynamicPageExclusions.map(dpe => `filters=section!=${dpe}`)
25
+ const extraPathItems = dynamicPageExclusions.map(dpe => `filters=section!=${dpe}`);
25
26
  extraPathItems.push('max=500');
26
27
 
27
28
  const { data: appSettings = [], isLoading } = useQuery(
@@ -50,7 +51,7 @@ const useSettings = ({
50
51
  );
51
52
  });
52
53
 
53
- const pageList = persistentPages.concat(dynamic).sort(sortByLabel)
54
+ const pageList = persistentPages.concat(dynamic).sort(sortByLabel);
54
55
 
55
56
  const SettingsContextProvider = ({ children }) => {
56
57
  return (
@@ -67,6 +68,13 @@ const useSettings = ({
67
68
  );
68
69
  };
69
70
 
71
+ SettingsContextProvider.propTypes = {
72
+ children: PropTypes.oneOfType([
73
+ PropTypes.func,
74
+ PropTypes.node
75
+ ])
76
+ };
77
+
70
78
  const SettingsComponent = (props) => {
71
79
  const settingsData = useContext(SettingsContext);
72
80
 
@@ -1,6 +1,3 @@
1
1
  export { default as useTypedown } from './useTypedown';
2
- export { default as useTypedownFooter } from './useTypedownFooter';
3
- export { default as useTypedownList } from './useTypedownList';
4
- export { default as useTypedownSearchField } from './useTypedownSearchField';
5
2
  export { default as useTypedownToggle } from './useTypedownToggle';
6
3
  export { default as useTypedownData } from './useTypedownData';
@@ -1,19 +1,22 @@
1
1
  import { useRef } from 'react';
2
2
  import { useResizeDetector } from 'react-resize-detector';
3
3
 
4
- // TODO swap to stripes-components export once available (Will need <= peer dep bump)
5
4
  import {
5
+ getFirstFocusable,
6
+ getLastFocusable,
6
7
  getNextFocusable,
7
- } from '../../utils/getFocusableElements';
8
+ getPreviousFocusable,
9
+ } from '@folio/stripes/components';
10
+
11
+ import {
12
+ DOWN_ARROW,
13
+ TAB,
14
+ UP_ARROW
15
+ } from '../../constants/eventCodes';
8
16
 
9
17
  import selectorSafe from '../../utils/selectorSafe';
10
18
 
11
- import {
12
- useTypedownToggle,
13
- useTypedownFooter,
14
- useTypedownSearchField,
15
- useTypedownList
16
- } from '.';
19
+ import useTypedownToggle from './useTypedownToggle';
17
20
 
18
21
  const useTypedown = (name) => {
19
22
  // SEARCHFIELD COMPONENT
@@ -23,11 +26,90 @@ const useTypedown = (name) => {
23
26
  const listRef = useRef();
24
27
  const triggerRef = useRef();
25
28
  const overlayRef = useRef();
26
- const footerRef = useTypedownFooter(searchFieldComponent);
29
+ const footerRef = useRef();
30
+
31
+ const footer = document.getElementById(`typedown-footer-${selectorSafe(name)}`);
32
+ // Add an event listener to the footer, so that we can control tab behaviour between footer elements
33
+
34
+ if (footer && footer.getAttribute('hasListener') !== 'true') {
35
+ footer.addEventListener('keydown', e => {
36
+ // We want special behaviour on tab
37
+ if (e.code === TAB) {
38
+ // Prevent the default behaviour
39
+ e.preventDefault();
40
+ const focusFunc = e.shiftKey ? getPreviousFocusable : getNextFocusable;
41
+ const elem = focusFunc(footerRef.current, true, true, false, true);
42
+
43
+ if (elem) {
44
+ // Focus on next focusable element
45
+ elem.focus();
46
+ } else if (e.shiftKey) {
47
+ // We are at the beginning of the list, refocus on search bar
48
+ searchFieldComponent.focus();
49
+ } else {
50
+ // We are at the end of the list, move onto next focusable element in page
51
+ getNextFocusable(searchFieldComponent, false).focus();
52
+ }
53
+ }
54
+ });
55
+
56
+ footer.setAttribute('hasListener', 'true');
57
+ }
27
58
 
28
59
  // SET UP HANDLERS
29
- const searchFieldKeyDownHandler = useTypedownSearchField(listRef, footerRef, searchFieldComponent);
30
- const listKeyDownHandler = useTypedownList(listRef, footerRef, searchFieldComponent);
60
+ const searchFieldKeyDownHandler = e => {
61
+ if (e.code === UP_ARROW) {
62
+ const elem = getLastFocusable(listRef.current, true, true);
63
+ if (elem) {
64
+ elem.focus();
65
+ }
66
+ }
67
+
68
+ if (e.code === DOWN_ARROW) {
69
+ const elem = getFirstFocusable(listRef.current, true, true);
70
+ if (elem) {
71
+ elem.focus();
72
+ }
73
+ }
74
+
75
+ // Tab key (But not while shifting)
76
+ if (e.code === TAB && !e.shiftKey) {
77
+ e.preventDefault();
78
+ // If we have focusable elements in the footer, then focus on them, else unfocus searchbar
79
+ const elem = getNextFocusable(footerRef.current, true, true, true, true);
80
+ if (elem) {
81
+ elem.focus();
82
+ } else {
83
+ getNextFocusable(searchFieldComponent, false).focus();
84
+ }
85
+ }
86
+ };
87
+
88
+ const listKeyDownHandler = e => {
89
+ if (e.code === DOWN_ARROW) {
90
+ const elem = getNextFocusable(listRef.current, true, true);
91
+ elem.focus();
92
+ }
93
+
94
+ if (e.code === UP_ARROW) {
95
+ const elem = getPreviousFocusable(listRef.current, true, true);
96
+ elem.focus();
97
+ }
98
+
99
+ if (e.code === TAB) {
100
+ e.preventDefault();
101
+ let elem;
102
+ if (!e.shiftKey && !footerRef.current) {
103
+ elem = getNextFocusable(searchFieldComponent, false);
104
+ } else if (!e.shiftKey) {
105
+ elem = getNextFocusable(footerRef.current, true, true, true, true);
106
+ } else {
107
+ elem = searchFieldComponent;
108
+ }
109
+ elem.focus();
110
+ }
111
+ };
112
+
31
113
  const handleNextFocus = () => getNextFocusable(searchFieldComponent, false).focus();
32
114
 
33
115
  // SET UP VARIABLES
@@ -0,0 +1,73 @@
1
+ import PropTypes from 'prop-types';
2
+
3
+ import { useQuery } from 'react-query';
4
+ import { useOkapiKy } from '@folio/stripes/core';
5
+
6
+ import { generateKiwtQuery } from '../utils';
7
+
8
+ const useCustomProperties = ({
9
+ endpoint,
10
+ ctx,
11
+ nsValues = {
12
+ sort: 'id'
13
+ },
14
+ options = {
15
+ searchKey: 'label,name,description',
16
+ filterKeys: {
17
+ ContextKey: 'ctx'
18
+ },
19
+ stats: false,
20
+ max: 100
21
+ },
22
+ queryParams,
23
+ returnQueryObject = false,
24
+ }) => {
25
+ const ky = useOkapiKy();
26
+
27
+ // Allow passing of 'false' for isNull
28
+ if (Array.isArray(ctx)) {
29
+ // If we have an array, append a context filter for each ctx given
30
+ nsValues.filters = ctx.map(c => {
31
+ if (c === 'isNull') {
32
+ return 'ContextWithoutKey.ctx isNull';
33
+ } else {
34
+ return `ContextKey.${c}`;
35
+ }
36
+ }).join(',');
37
+ } else if (ctx === 'isNull') { // isNull is a special case
38
+ nsValues.filters = 'ContextWithoutKey.ctx isNull';
39
+ } else if (ctx) {
40
+ // If we just have a string, append a single ctx filter
41
+ nsValues.filters = `ContextKey.${ctx}`;
42
+ } else {
43
+ nsValues.filters = null;
44
+ }
45
+
46
+ const query = generateKiwtQuery(options, nsValues);
47
+ const path = `${endpoint}${query}`;
48
+
49
+ const queryObject = useQuery(
50
+ ['stripes-kint-components', 'useCustomProperties', 'custprops', ctx, path],
51
+ () => ky(path).json(),
52
+ queryParams
53
+ );
54
+
55
+ if (returnQueryObject) {
56
+ return queryObject || {};
57
+ }
58
+
59
+ const { data: custprops } = queryObject;
60
+ return custprops || [];
61
+ };
62
+
63
+ useCustomProperties.propTypes = {
64
+ endpoint: PropTypes.string,
65
+ ctx: PropTypes.oneOfType([
66
+ PropTypes.string,
67
+ PropTypes.arrayOf(PropTypes.string)
68
+ ]),
69
+ queryParams: PropTypes.object,
70
+ returnQueryObject: PropTypes.bool
71
+ };
72
+
73
+ export default useCustomProperties;
@@ -0,0 +1,62 @@
1
+ import { useMutation } from 'react-query';
2
+
3
+ import { useOkapiKy } from '@folio/stripes/core';
4
+
5
+ const useMutateCustomProperties = ({
6
+ afterQueryCalls,
7
+ endpoint,
8
+ id,
9
+ queryParams,
10
+ returnQueryObject = {
11
+ post: false,
12
+ put: false,
13
+ delete: false
14
+ }
15
+ }) => {
16
+ const returnObj = {};
17
+
18
+ const ky = useOkapiKy();
19
+
20
+ const deleteQueryObject = useMutation(
21
+ ['stripes-kint-components', 'useMutateCustomProperties', 'delete', id],
22
+ async () => ky.delete(`${endpoint}/${id}`).json()
23
+ .then(afterQueryCalls?.delete),
24
+ queryParams?.delete
25
+ );
26
+
27
+ const putQueryObject = useMutation(
28
+ ['stripes-kint-components', 'useMutateCustomProperties', 'put', id],
29
+ async (data) => ky.put(`${endpoint}/${id}`, { json: data }).json()
30
+ .then(afterQueryCalls?.put),
31
+ queryParams?.put
32
+ );
33
+
34
+ const postQueryObject = useMutation(
35
+ ['stripes-kint-components', 'useMutateCustomProperties', 'post'],
36
+ async (data) => ky.post(`${endpoint}`, { json: data }).json()
37
+ .then(afterQueryCalls?.post),
38
+ queryParams?.post
39
+ );
40
+
41
+ if (returnQueryObject?.delete) {
42
+ returnObj.delete = deleteQueryObject;
43
+ } else {
44
+ returnObj.delete = deleteQueryObject.mutateAsync;
45
+ }
46
+
47
+ if (returnQueryObject?.put) {
48
+ returnObj.put = putQueryObject;
49
+ } else {
50
+ returnObj.put = putQueryObject.mutateAsync;
51
+ }
52
+
53
+ if (returnQueryObject?.post) {
54
+ returnObj.post = postQueryObject;
55
+ } else {
56
+ returnObj.post = postQueryObject.mutateAsync;
57
+ }
58
+
59
+ return returnObj;
60
+ };
61
+
62
+ export default useMutateCustomProperties;
@@ -4,20 +4,14 @@ import PropTypes from 'prop-types';
4
4
  import { useQuery } from 'react-query';
5
5
  import { useOkapiKy } from '@folio/stripes/core';
6
6
 
7
- import { generateKiwtQuery } from '../utils';
7
+ import { generateKiwtQuery, refdataOptions } from '../utils';
8
8
 
9
9
  const useRefdata = ({
10
10
  endpoint,
11
11
  desc,
12
+ options = refdataOptions,
12
13
  queryParams,
13
14
  returnQueryObject = false,
14
- options = {
15
- filterKeys: {
16
- DescKey: 'desc'
17
- },
18
- stats: false,
19
- max: 100
20
- }
21
15
  }) => {
22
16
  const ky = useOkapiKy();
23
17
 
@@ -3,3 +3,10 @@ export { default as generateKiwtQueryParams } from './generateKiwtQueryParams';
3
3
  export { default as selectorSafe } from './selectorSafe';
4
4
 
5
5
  export { default as buildUrl } from './buildUrl';
6
+
7
+ export { default as refdataOptions } from './refdataOptions';
8
+
9
+ // Settings utils
10
+ export { default as renderHelpText } from './renderHelpText';
11
+ export { default as sortByLabel } from './sortByLabel';
12
+ export { default as toCamelCase } from './toCamelCase'; // I hate that this exists
@@ -0,0 +1,7 @@
1
+ export default {
2
+ filterKeys: {
3
+ DescKey: 'desc'
4
+ },
5
+ stats: false,
6
+ max: 100
7
+ };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { FormattedMessage } from 'react-intl';
3
- import css from '../../../../styles/renderHelpText.css';
3
+ import css from '../../../styles/renderHelpText.css';
4
4
 
5
5
  const renderHelpText = (id) => {
6
6
  return (
@@ -12,4 +12,4 @@ const sortByLabel = (a, b) => {
12
12
  return 0;
13
13
  };
14
14
 
15
- export default sortByLabel;
15
+ export default sortByLabel;
File without changes
@@ -0,0 +1 @@
1
+ export { default } from './translationsProperties';
@@ -0,0 +1,40 @@
1
+ import translations from '../../translations/stripes-kint-components/en';
2
+
3
+ const translationsProperties = [
4
+ {
5
+ prefix: 'stripes-kint-components',
6
+ translations,
7
+ },
8
+ /* Don't think we're using any of the below rn */
9
+ {
10
+ prefix: 'stripes-core',
11
+ translations: {
12
+ 'label.missingRequiredField': 'Please fill this in to continue',
13
+ 'button.save': 'Save',
14
+ }
15
+ },
16
+ {
17
+ prefix: 'stripes-components',
18
+ translations: {
19
+ 'saveAndClose': 'Save and close',
20
+ 'cancel': 'Cancel',
21
+ 'paneMenuActionsToggleLabel': 'Actions',
22
+ 'collapseAll': 'Collapse all',
23
+ 'button.edit': 'Edit'
24
+ },
25
+ },
26
+ {
27
+ prefix: 'stripes-smart-components',
28
+ translations: {
29
+ 'permissionError': 'Sorry - your permissions do not allow access to this page.',
30
+ 'searchAndFilter': 'Search and filter',
31
+ 'hideSearchPane': 'Hide search pane',
32
+ 'search': 'Search',
33
+ 'resetAll': 'Reset all',
34
+ 'searchResultsCountHeader': '"{count, number} {count, plural, one {record found} other {records found}}"',
35
+ 'new': 'New'
36
+ },
37
+ }
38
+ ];
39
+
40
+ export default translationsProperties;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Harness } from '@folio/stripes-erm-components/test/jest/helpers';
4
+
5
+ import { SettingsContext } from '../../../src/lib/contexts';
6
+ import translationsProperties from '../../helpers';
7
+
8
+
9
+ export default function KintHarness({
10
+ children,
11
+ settingsValues = {
12
+ intlKey: 'stripes-kint-components',
13
+ refdataEndpoint: 'path/to/refdata',
14
+ settingEndpoint: 'path/to/settings',
15
+ templateEndpoint: 'path/to/templates'
16
+ },
17
+ translations = translationsProperties,
18
+ ...harnessProps
19
+ }) {
20
+ return (
21
+ <SettingsContext.Provider value={settingsValues}>
22
+ <Harness
23
+ translations={translations}
24
+ {...harnessProps}
25
+ >
26
+ {children}
27
+ </Harness>
28
+ </SettingsContext.Provider>
29
+ );
30
+ }
31
+
32
+ KintHarness.propTypes = {
33
+ children: PropTypes.node,
34
+ settingsValues: PropTypes.object,
35
+ translations: PropTypes.object
36
+ };
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { default as renderWithKintHarness } from './renderWithKintHarness';