@k-int/stripes-kint-components 5.9.0 → 5.10.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.
- package/CHANGELOG.md +7 -0
- package/es/lib/Typedown/Typedown.js +12 -2
- package/es/lib/hooks/typedownHooks/useTypedown.js +15 -2
- package/package.json +1 -1
- package/src/lib/FormModal/README.md +91 -0
- package/src/lib/Typedown/README.md +21 -19
- package/src/lib/Typedown/Typedown.js +16 -3
- package/src/lib/hooks/typedownHooks/useTypedown.js +17 -3
- package/src/lib/utils/README.md +126 -56
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [5.10.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.9.0...v5.10.0) (2025-02-04)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Typedown delay ([c736865](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/c736865cec8f4b5cbe2ad473393452fd7ec34dc8))
|
|
7
|
+
|
|
1
8
|
# [5.9.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.8.3...v5.9.0) (2025-01-31)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -22,8 +22,11 @@ const Typedown = _ref => {
|
|
|
22
22
|
className,
|
|
23
23
|
dataOptions,
|
|
24
24
|
displayClearItem = true,
|
|
25
|
+
displayValueWhileOpen = true,
|
|
25
26
|
endOfList,
|
|
26
27
|
id,
|
|
28
|
+
initialOpenDelay = 800,
|
|
29
|
+
// Initial opening delay of 800ms (handles any stripes animations)
|
|
27
30
|
input,
|
|
28
31
|
isSelected,
|
|
29
32
|
filterPath,
|
|
@@ -89,7 +92,9 @@ const Typedown = _ref => {
|
|
|
89
92
|
resizeRef,
|
|
90
93
|
searchWidth
|
|
91
94
|
}
|
|
92
|
-
} = (0, _typedownHooks.useTypedown)(input.name
|
|
95
|
+
} = (0, _typedownHooks.useTypedown)(input.name, {
|
|
96
|
+
timeout: initialOpenDelay
|
|
97
|
+
});
|
|
93
98
|
const renderItem = (0, _react.useCallback)(function (option) {
|
|
94
99
|
let optionIsSelected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
95
100
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
@@ -157,6 +162,9 @@ const Typedown = _ref => {
|
|
|
157
162
|
})
|
|
158
163
|
});
|
|
159
164
|
};
|
|
165
|
+
const displayValue = (0, _react.useMemo)(() => {
|
|
166
|
+
return !!selectedUniqueId && (!open || displayValueWhileOpen);
|
|
167
|
+
}, [displayValueWhileOpen, open, selectedUniqueId]);
|
|
160
168
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
161
169
|
ref: resizeRef,
|
|
162
170
|
className: (0, _classnames.default)(_TypeDown.default.typedown, className),
|
|
@@ -185,7 +193,7 @@ const Typedown = _ref => {
|
|
|
185
193
|
overlayRef: overlayRef,
|
|
186
194
|
portal: portal,
|
|
187
195
|
children: dropDown()
|
|
188
|
-
}, "typedown-menu-toggle"),
|
|
196
|
+
}, "typedown-menu-toggle"), displayValue && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
189
197
|
className: (0, _classnames.default)(_TypeDown.default.selectedDisplay),
|
|
190
198
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
191
199
|
className: _TypeDown.default.selectedItem,
|
|
@@ -202,9 +210,11 @@ Typedown.propTypes = {
|
|
|
202
210
|
className: _propTypes.default.string,
|
|
203
211
|
dataOptions: _propTypes.default.arrayOf(_propTypes.default.object),
|
|
204
212
|
displayClearItem: _propTypes.default.bool,
|
|
213
|
+
displayValueWhileOpen: _propTypes.default.bool,
|
|
205
214
|
endOfList: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node, _propTypes.default.element]),
|
|
206
215
|
filterPath: _propTypes.default.string,
|
|
207
216
|
id: _propTypes.default.string,
|
|
217
|
+
initialOpenDelay: _propTypes.default.number,
|
|
208
218
|
input: _propTypes.default.object,
|
|
209
219
|
isSelected: _propTypes.default.func,
|
|
210
220
|
label: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.element]),
|
|
@@ -11,7 +11,10 @@ var _eventCodes = require("../../constants/eventCodes");
|
|
|
11
11
|
var _selectorSafe = _interopRequireDefault(require("../../utils/selectorSafe"));
|
|
12
12
|
var _useTypedownToggle = _interopRequireDefault(require("./useTypedownToggle"));
|
|
13
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
-
const useTypedown = name
|
|
14
|
+
const useTypedown = function (name) {
|
|
15
|
+
let {
|
|
16
|
+
timeout = 800
|
|
17
|
+
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
15
18
|
// SEARCHFIELD COMPONENT
|
|
16
19
|
const searchFieldComponent = document.getElementById(`typedown-searchField-${(0, _selectorSafe.default)(name)}`);
|
|
17
20
|
|
|
@@ -101,6 +104,16 @@ const useTypedown = name => {
|
|
|
101
104
|
const {
|
|
102
105
|
open
|
|
103
106
|
} = (0, _useTypedownToggle.default)(name);
|
|
107
|
+
const [useOpen, setUseOpen] = (0, _react.useState)(false);
|
|
108
|
+
(0, _react.useEffect)(() => {
|
|
109
|
+
// Use setTimeout to update the message after 2000 milliseconds (2 seconds)
|
|
110
|
+
const timeoutId = setTimeout(() => {
|
|
111
|
+
setUseOpen(true);
|
|
112
|
+
}, timeout); // Wait 0.8 seconds for open prop to get used
|
|
113
|
+
|
|
114
|
+
// Cleanup function to clear the timeout if the component unmounts
|
|
115
|
+
return () => clearTimeout(timeoutId);
|
|
116
|
+
}, [timeout]);
|
|
104
117
|
|
|
105
118
|
// RESIZE STUFF
|
|
106
119
|
const {
|
|
@@ -123,7 +136,7 @@ const useTypedown = name => {
|
|
|
123
136
|
searchFieldKeyDownHandler
|
|
124
137
|
},
|
|
125
138
|
variables: {
|
|
126
|
-
open,
|
|
139
|
+
open: useOpen ? open : false,
|
|
127
140
|
portal,
|
|
128
141
|
resizeRef,
|
|
129
142
|
searchWidth
|
package/package.json
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
## FormModal Component
|
|
2
|
+
|
|
3
|
+
The `FormModal` component provides a simple way to create a modal dialog with a form. It combines the `Modal` component from `@folio/stripes/components` with the `Form` component from `react-final-form`, handling form submission, validation, and modal interactions.
|
|
4
|
+
|
|
5
|
+
### Basic Usage
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
import FormModal from '@k-int/stripes-kint-components';
|
|
10
|
+
import { Field } from 'react-final-form';
|
|
11
|
+
import { TextField } from '@folio/stripes/components';
|
|
12
|
+
|
|
13
|
+
const MyFormModal = () => {
|
|
14
|
+
const [open, setOpen] = useState(false);
|
|
15
|
+
|
|
16
|
+
const onSubmit = (values) => {
|
|
17
|
+
// Handle form submission
|
|
18
|
+
console.log(values);
|
|
19
|
+
setOpen(false); // Close the modal after submission
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
<Button onClick={() => setOpen(true)}>Open Modal</Button> {/* Button to open the modal */}
|
|
25
|
+
<FormModal
|
|
26
|
+
modalProps={{ open, onClose: () => setOpen(false) }}
|
|
27
|
+
onSubmit={onSubmit}
|
|
28
|
+
>
|
|
29
|
+
<Field
|
|
30
|
+
name="name"
|
|
31
|
+
component={TextField}
|
|
32
|
+
label="Name"
|
|
33
|
+
/>
|
|
34
|
+
</FormModal>
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Props
|
|
41
|
+
|
|
42
|
+
| Name | Type | Description | Default | Required |
|
|
43
|
+
|---|---|---|---|---|
|
|
44
|
+
| children | node/func | The content of the modal, typically form fields. | | ✓ |
|
|
45
|
+
| intlKey | string | The key to use for internationalization messages. | | ✕ |
|
|
46
|
+
| intlNS | string | The namespace to use for internationalization messages. | | ✕ |
|
|
47
|
+
| labelOverrides | object | An object to override the default labels for buttons. | `{}` | ✕ |
|
|
48
|
+
| modalProps | object | Props to pass to the underlying `Modal` component. Should include `open` and `onClose`. | | ✓ |
|
|
49
|
+
| onError | func | A function to handle errors that occur during form submission. This function will receive the error object as a parameter. | | ✕ |
|
|
50
|
+
| onSubmit | func | A function to handle form submission. | | ✓ |
|
|
51
|
+
| onSuccess | func | A function to handle successful form submission. This function will receive the submitted values as a parameter. | | ✕ |
|
|
52
|
+
|...formProps | object | Any other props will be passed to the underlying `Form` component from `react-final-form`. | | ✕ |
|
|
53
|
+
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
* **Integrated form handling:** The component integrates seamlessly with `react-final-form`, providing access to form state and helper functions within the `footer` and `children` props.
|
|
57
|
+
* **Customizable footer:** The `modalProps.footer` prop allows for customization of the modal footer. It receives an object with the following properties:
|
|
58
|
+
* `formState`: The current state of the form.
|
|
59
|
+
* `handleSubmit`: A function to handle form submission and close the modal.
|
|
60
|
+
* `handleClose`: A function to close the modal.
|
|
61
|
+
* `handleSubmitNoRestart`: **(DEPRECATED)** Use `handleSubmitRaw` instead.
|
|
62
|
+
* `handleSubmitRaw`: A function to handle form submission without closing the modal or clearing the form.
|
|
63
|
+
* **Error and success handling:** The `onError` and `onSuccess` props allow for custom handling of asynchronous form submission errors and successes.
|
|
64
|
+
* **Internationalization:** The component supports internationalization using the `intlKey` and `intlNS` props.
|
|
65
|
+
* **Label overrides:** The `labelOverrides` prop allows for overriding the default button labels.
|
|
66
|
+
|
|
67
|
+
### Example with Custom Footer
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
<FormModal
|
|
71
|
+
modalProps={{
|
|
72
|
+
open: true,
|
|
73
|
+
onClose: () => { /*... */ },
|
|
74
|
+
footer: ({ handleSubmit, handleClose }) => (
|
|
75
|
+
<ModalFooter>
|
|
76
|
+
<Button
|
|
77
|
+
buttonStyle="primary"
|
|
78
|
+
onClick={handleSubmit}
|
|
79
|
+
type="submit"
|
|
80
|
+
>
|
|
81
|
+
Save
|
|
82
|
+
</Button>
|
|
83
|
+
<Button onClick={handleClose}>Cancel</Button>
|
|
84
|
+
</ModalFooter>
|
|
85
|
+
)
|
|
86
|
+
}}
|
|
87
|
+
onSubmit={() => { /*... */ }}
|
|
88
|
+
>
|
|
89
|
+
{/*... form content... */}
|
|
90
|
+
</FormModal>
|
|
91
|
+
```
|
|
@@ -24,22 +24,24 @@ import Typedown from '@k-int/stripes-kint-components';
|
|
|
24
24
|
|
|
25
25
|
### Props
|
|
26
26
|
|
|
27
|
-
| Name
|
|
28
|
-
|
|
29
|
-
| className
|
|
30
|
-
| dataOptions
|
|
31
|
-
| displayClearItem
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
27
|
+
| Name | Type | Description | Default | Required |
|
|
28
|
+
|--------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|---|
|
|
29
|
+
| className | string | CSS class name to apply to the component's outer div. | | ✕ |
|
|
30
|
+
| dataOptions | array | An array of objects representing the dropdown options. Each object should have a property (specified by `uniqueIdentificationPath`) that serves as a unique identifier. | | ✓ |
|
|
31
|
+
| displayClearItem | bool | Whether to display a clear icon when an item is selected. | `true` | ✕ |
|
|
32
|
+
| displayValueWhileOpen | bool | Whether or not to display the "value" underneath the typedown search while the dropdown is open. Defaults to true to avoid size changing onClick. | `true` | ✕ |
|
|
33
|
+
| endOfList | node/func | Component or function to render when the dropdown list is empty. Defaults to `<EndOfList />` from `@folio/stripes/components`. | `<EndOfList />` | ✕ |
|
|
34
|
+
| filterPath | string | Path to the property in `dataOptions` objects to use for filtering. If not provided, filtering is done on the property specified by `uniqueIdentificationPath`. | | ✕ |
|
|
35
|
+
| id | string | Id to apply to the component's outer div. | | ✕ |
|
|
36
|
+
| initialTimeoutDelay | number | Delay applied to `open` occurring on first render. Set to 800ms to avoid any stripes animations, such as being the first element focused in an opening modal. | 800 | ✕ |
|
|
37
|
+
| input | object | An object containing the input props typically provided by a form library like `react-final-form` or `redux-form`. Should include `name`, `value`, and `onChange`. | | ✓ |
|
|
38
|
+
| isSelected | func | A function `(inputValue, dataOption)` that determines if a given `dataOption` is currently selected. Useful when selected values are complex objects. If not provided, selection is determined by comparing the value of the `uniqueIdentificationPath` property of the `input.value` and the `dataOption`. | | ✕ |
|
|
39
|
+
| label | string/element | Label for the input field. | | ✕ |
|
|
40
|
+
| meta | object | Meta information about the field, typically provided by a form library. Useful for displaying error messages etc. | | ✕ |
|
|
41
|
+
| onChange | func | A callback function `(value)` that is called when a value is selected from the dropdown. This is in addition to the `input.onChange` provided. | | ✕ |
|
|
42
|
+
| onType | func | A callback function `(event)` that is called when the user types in the search field. Allows for custom filtering or data fetching based on user input. | | ✕ |
|
|
43
|
+
| renderFooter | func | A function `(displayData, currentlyTyped, exactMatch)` that renders a footer below the dropdown list. Receives the currently filtered `displayData`, what the user has typed, and whether it is an exact match. | | ✕ |
|
|
44
|
+
| renderListItem | func | A function `(option, currentlyTyped, exactMatch, optionIsSelected)` that renders each item in the dropdown list. Receives the current option, what the user has typed, whether there is an exact match, and if the option is selected. If not provided, the value of the `uniqueIdentificationPath` property of the option is displayed. | | ✕ |
|
|
45
|
+
| required | bool | Whether the input is required. | | ✕ |
|
|
46
|
+
| selectedStyles | string | CSS class name to apply to the selected item display. | | ✕ |
|
|
47
|
+
| uniqueIdentificationPath | string | Path to the property in `dataOptions` objects that serves as a unique identifier for each option and is used to determine if an option is selected. | `'id'` | ✕ |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
4
|
|
|
@@ -16,8 +16,10 @@ const Typedown = ({
|
|
|
16
16
|
className,
|
|
17
17
|
dataOptions,
|
|
18
18
|
displayClearItem = true,
|
|
19
|
+
displayValueWhileOpen = true,
|
|
19
20
|
endOfList,
|
|
20
21
|
id,
|
|
22
|
+
initialOpenDelay = 800, // Initial opening delay of 800ms (handles any stripes animations)
|
|
21
23
|
input,
|
|
22
24
|
isSelected,
|
|
23
25
|
filterPath,
|
|
@@ -85,7 +87,12 @@ const Typedown = ({
|
|
|
85
87
|
resizeRef,
|
|
86
88
|
searchWidth
|
|
87
89
|
}
|
|
88
|
-
} = useTypedown(
|
|
90
|
+
} = useTypedown(
|
|
91
|
+
input.name,
|
|
92
|
+
{
|
|
93
|
+
timeout: initialOpenDelay
|
|
94
|
+
}
|
|
95
|
+
);
|
|
89
96
|
|
|
90
97
|
const renderItem = useCallback((option, optionIsSelected = false) => (
|
|
91
98
|
<div
|
|
@@ -197,6 +204,10 @@ const Typedown = ({
|
|
|
197
204
|
);
|
|
198
205
|
};
|
|
199
206
|
|
|
207
|
+
const displayValue = useMemo(() => {
|
|
208
|
+
return !!selectedUniqueId && (!open || displayValueWhileOpen);
|
|
209
|
+
}, [displayValueWhileOpen, open, selectedUniqueId]);
|
|
210
|
+
|
|
200
211
|
return (
|
|
201
212
|
<div
|
|
202
213
|
ref={resizeRef}
|
|
@@ -229,7 +240,7 @@ const Typedown = ({
|
|
|
229
240
|
>
|
|
230
241
|
{dropDown()}
|
|
231
242
|
</Popper>
|
|
232
|
-
{
|
|
243
|
+
{displayValue &&
|
|
233
244
|
<div
|
|
234
245
|
className={classnames(
|
|
235
246
|
css.selectedDisplay
|
|
@@ -257,6 +268,7 @@ Typedown.propTypes = {
|
|
|
257
268
|
className: PropTypes.string,
|
|
258
269
|
dataOptions: PropTypes.arrayOf(PropTypes.object),
|
|
259
270
|
displayClearItem: PropTypes.bool,
|
|
271
|
+
displayValueWhileOpen: PropTypes.bool,
|
|
260
272
|
endOfList: PropTypes.oneOfType([
|
|
261
273
|
PropTypes.func,
|
|
262
274
|
PropTypes.node,
|
|
@@ -264,6 +276,7 @@ Typedown.propTypes = {
|
|
|
264
276
|
]),
|
|
265
277
|
filterPath: PropTypes.string,
|
|
266
278
|
id: PropTypes.string,
|
|
279
|
+
initialOpenDelay: PropTypes.number,
|
|
267
280
|
input: PropTypes.object,
|
|
268
281
|
isSelected: PropTypes.func,
|
|
269
282
|
label: PropTypes.oneOfType([
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRef } from 'react';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useResizeDetector } from 'react-resize-detector';
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -18,7 +18,10 @@ import selectorSafe from '../../utils/selectorSafe';
|
|
|
18
18
|
|
|
19
19
|
import useTypedownToggle from './useTypedownToggle';
|
|
20
20
|
|
|
21
|
-
const useTypedown = (
|
|
21
|
+
const useTypedown = (
|
|
22
|
+
name,
|
|
23
|
+
{ timeout = 800 } = {}
|
|
24
|
+
) => {
|
|
22
25
|
// SEARCHFIELD COMPONENT
|
|
23
26
|
const searchFieldComponent = document.getElementById(`typedown-searchField-${selectorSafe(name)}`);
|
|
24
27
|
|
|
@@ -114,6 +117,17 @@ const useTypedown = (name) => {
|
|
|
114
117
|
|
|
115
118
|
// SET UP VARIABLES
|
|
116
119
|
const { open } = useTypedownToggle(name);
|
|
120
|
+
const [useOpen, setUseOpen] = useState(false);
|
|
121
|
+
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
// Use setTimeout to update the message after 2000 milliseconds (2 seconds)
|
|
124
|
+
const timeoutId = setTimeout(() => {
|
|
125
|
+
setUseOpen(true);
|
|
126
|
+
}, timeout); // Wait 0.8 seconds for open prop to get used
|
|
127
|
+
|
|
128
|
+
// Cleanup function to clear the timeout if the component unmounts
|
|
129
|
+
return () => clearTimeout(timeoutId);
|
|
130
|
+
}, [timeout]);
|
|
117
131
|
|
|
118
132
|
// RESIZE STUFF
|
|
119
133
|
const { width: searchWidth, ref: resizeRef } = useResizeDetector();
|
|
@@ -134,7 +148,7 @@ const useTypedown = (name) => {
|
|
|
134
148
|
searchFieldKeyDownHandler
|
|
135
149
|
},
|
|
136
150
|
variables: {
|
|
137
|
-
open,
|
|
151
|
+
open: useOpen ? open : false,
|
|
138
152
|
portal,
|
|
139
153
|
resizeRef,
|
|
140
154
|
searchWidth
|
package/src/lib/utils/README.md
CHANGED
|
@@ -1,73 +1,143 @@
|
|
|
1
|
-
#
|
|
2
|
-
A collection of useful util functions
|
|
1
|
+
# Utility Functions
|
|
3
2
|
|
|
4
3
|
## generateKiwtQuery
|
|
5
|
-
A util function for generating a "KIWT" (K-Int Web-Toolkit) style backend query from a SASQ query object
|
|
6
|
-
### Basic usage
|
|
7
|
-
```
|
|
8
|
-
import { generateKiwtQuery } from '@k-int/stripes-kint-components'
|
|
9
|
-
...
|
|
10
|
-
const nsValues = {
|
|
11
|
-
query: 'test',
|
|
12
|
-
filters: 'requestStatus.completed,journalVolume.test1,startDate.startDate>=2021-10-28'
|
|
13
|
-
}
|
|
14
4
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
The `generateKiwtQuery` function generates a URL query string in "KIWT" (K-Int Web Toolkit) style from a SASQ (Search and Sort Query) object. It handles search terms, filters, sorting, and other parameters, making it easy to construct complex query strings for backend APIs.
|
|
6
|
+
|
|
7
|
+
### Basic Usage
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
import { generateKiwtQuery } from '@k-int/stripes-kint-components';
|
|
11
|
+
|
|
12
|
+
const nsValues = {
|
|
13
|
+
query: 'test',
|
|
14
|
+
filters: 'requestStatus.completed,journalVolume.test1,startDate.startDate>=2021-10-28',
|
|
15
|
+
sort: '-title' // Example of sorting by title in descending order
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const options = {
|
|
19
|
+
searchKey: 'request.name',
|
|
20
|
+
filterKeys: {
|
|
21
|
+
requestStatus: 'requestStatus.value',
|
|
22
|
+
journalVolume: 'journalVolume'
|
|
23
|
+
},
|
|
24
|
+
sortKeys: {
|
|
25
|
+
title: 'item.title' // Example of mapping 'title' to 'item.title' for sorting
|
|
21
26
|
}
|
|
27
|
+
};
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
const queryString = generateKiwtQuery(options, nsValues);
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
// queryString will be:
|
|
32
|
+
//?match=request.name&term=test&filters=requestStatus.value==completed&filters=journalVolume==test1&filters=startDate%3E=2021-10-28&sort=item.title;desc&stats=true
|
|
27
33
|
```
|
|
28
34
|
|
|
29
35
|
### Props
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
|
|
37
|
+
| Name | Type | Description | Default | Required |
|
|
38
|
+
|---|---|---|---|---|
|
|
39
|
+
| options | object | An object with keys: `searchKey`, `filterKeys`, `sortKeys`, and `stats`, which maps the incoming `nsValues` object to a KIWT query. You can also pass arbitrary `key`/`value` pairs to append `key==value` onto the query. | | ✓ |
|
|
40
|
+
| nsValues | object | An object containing the query parameters. Can contain `query`, `filters`, and `sort`, as well as any other arbitrary parameters. | | ✓ |
|
|
41
|
+
| encode | boolean | A boolean indicating whether to URL-encode the values. | `true` | ✕ |
|
|
35
42
|
|
|
36
43
|
## generateKiwtQueryParams
|
|
37
|
-
A util function for generating an array of "KIWT" (K-Int Web-Toolkit) style backend query parameters from a SASQ query object
|
|
38
|
-
### Basic usage
|
|
39
|
-
```
|
|
40
|
-
import { generateKiwtQueryParams } from '@k-int/stripes-kint-components'
|
|
41
|
-
...
|
|
42
|
-
const nsValues = {
|
|
43
|
-
query: 'test',
|
|
44
|
-
filters: 'requestStatus.completed,journalVolume.test1,startDate.startDate>=2021-10-28'
|
|
45
|
-
}
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
The `generateKiwtQueryParams` function is similar to `generateKiwtQuery`, but instead of returning a string, it returns an array of query parameters. This can be useful for more advanced use cases where you need to manipulate the parameters before constructing the final query string.
|
|
46
|
+
|
|
47
|
+
### Basic Usage
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import { generateKiwtQueryParams } from '@k-int/stripes-kint-components';
|
|
51
|
+
|
|
52
|
+
const nsValues = {
|
|
53
|
+
query: 'test',
|
|
54
|
+
filters: 'requestStatus.completed,journalVolume.test1,startDate.startDate>=2021-10-28'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const options = {
|
|
58
|
+
searchKey: 'request.name',
|
|
59
|
+
filterKeys: {
|
|
60
|
+
requestStatus: 'requestStatus.value',
|
|
61
|
+
journalVolume: 'journalVolume'
|
|
53
62
|
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const queryArray = generateKiwtQueryParams(options, nsValues);
|
|
54
66
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
]
|
|
65
|
-
...
|
|
67
|
+
// queryArray will be:
|
|
68
|
+
// [
|
|
69
|
+
// "match=request.name",
|
|
70
|
+
// "term=test",
|
|
71
|
+
// "filters=requestStatus.value==completed",
|
|
72
|
+
// "filters=journalVolume==test1",
|
|
73
|
+
// "filters=startDate%3E=2021-10-28",
|
|
74
|
+
// "stats=true"
|
|
75
|
+
// ]
|
|
66
76
|
```
|
|
67
77
|
|
|
68
78
|
### Props
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
|
|
80
|
+
| Name | Type | Description | Default | Required |
|
|
81
|
+
|---|---|---|---|---|
|
|
82
|
+
| options | object | An object with keys: `searchKey`, `filterKeys`, `sortKeys`, and `stats`, which maps the incoming `nsValues` object to a KIWT query array. You can also pass arbitrary `key`/`value` pairs to append `key==value` onto the query. | | ✓ |
|
|
83
|
+
| nsValues | object | An object containing the query parameters. Can contain `query`, `filters`, and `sort`, as well as any other arbitrary parameters. | | ✓ |
|
|
84
|
+
| encode | boolean | A boolean indicating whether to URL-encode the values. | `true` | ✕ |
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
### Options Parameter Structure
|
|
88
|
+
|
|
89
|
+
The `options` parameter is a powerful tool for customizing the query string generation. It has the following key elements:
|
|
90
|
+
|
|
91
|
+
* **Search:**
|
|
92
|
+
* `searchKey`: Specifies the field to search on. If using SASQ, the corresponding value in `nsValues.query` will be used as the search term. Otherwise, you can directly specify the search term using the `term` key in `options`.
|
|
93
|
+
* **Filters:** See the "Filters Object Structure" section below for details.
|
|
94
|
+
* **Sorting:**
|
|
95
|
+
* `sortKeys`: An object mapping sort field names from `nsValues.sort` to their corresponding backend keys.
|
|
96
|
+
* `sort`: An array of sort objects. Each object can have `path` (field to sort on) and `direction` (`asc` or `desc`).
|
|
97
|
+
* **Statistics:**
|
|
98
|
+
* `stats`: A boolean value indicating whether to include the `stats=true` parameter.
|
|
99
|
+
* **Other parameters:** Any other key-value pairs in the `options` object will be directly added as query parameters.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Filters Object Structure
|
|
103
|
+
|
|
104
|
+
The `filters` option in the `options` parameter allows you to define complex filter expressions using an array of filter objects. Each filter object can have the following properties:
|
|
105
|
+
|
|
106
|
+
* **path:** The path to the field to filter on (e.g., `item.title`).
|
|
107
|
+
* **comparator:** *(Optional)* The comparator to use for the filter (e.g., `==`, `!=`, `>`, `<`). Defaults to `==`.
|
|
108
|
+
* **value:** A single value to filter on.
|
|
109
|
+
* **values:** An array of values to filter on. If present, this property takes precedence over `value`, and an `OR` condition is implied between the values.
|
|
110
|
+
* **groupValues:** An object defining nested filter groups with `AND` or `OR` logic. This property allows for building complex nested filters. See the explanation below.
|
|
111
|
+
|
|
112
|
+
#### Nested Filter Groups (`groupValues`)
|
|
113
|
+
|
|
114
|
+
The `groupValues` property enables the creation of nested filter expressions with `AND` and `OR` logic. It is an object with either `AND` or `OR` properties (or both, with `AND` taking precedence). The value of these properties should be an array of filter objects, allowing for recursive nesting.
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
// Example: (status==active AND type==local) OR (status==pending)
|
|
118
|
+
const filters = [
|
|
119
|
+
{
|
|
120
|
+
groupValues: {
|
|
121
|
+
OR: [
|
|
122
|
+
{
|
|
123
|
+
groupValues: {
|
|
124
|
+
AND: [
|
|
125
|
+
{ path: 'item.status', value: 'active' },
|
|
126
|
+
{ path: 'item.type', value: 'local' },
|
|
127
|
+
],
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{ path: 'item.status', value: 'pending' },
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This structure allows you to express complex filter logic in a clear and organized way.
|
|
138
|
+
|
|
139
|
+
### Key Takeaways
|
|
140
|
+
|
|
141
|
+
* `generateKiwtQuery` provides a flexible way to construct URL query strings for backend APIs, especially when working with Stripes SASQ.
|
|
142
|
+
* The `options` parameter offers fine-grained control over the query generation process, allowing for complex filtering, sorting, and other customizations.
|
|
143
|
+
* `generateKiwtQueryParams` is useful for advanced use cases where you need to manipulate the parameters before constructing the final query string.
|