@k-int/stripes-kint-components 5.18.0 → 5.19.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 (73) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/es/index.js +8 -0
  3. package/es/lib/SASQLookupComponent/SASQLookupComponent.js +5 -1
  4. package/es/lib/SearchKeyControl/SearchKeyControl.js +95 -0
  5. package/es/lib/SearchKeyControl/SearchKeyControl.test.js +177 -0
  6. package/es/lib/SearchKeyControl/index.js +13 -0
  7. package/es/lib/hooks/__mocks__/index.js +2 -2
  8. package/es/lib/hooks/index.js +33 -21
  9. package/es/lib/hooks/intlHooks/index.js +27 -0
  10. package/es/lib/hooks/intlHooks/useIntlKey/index.js +13 -0
  11. package/es/lib/hooks/{useIntlKey.js → intlHooks/useIntlKey/useIntlKey.js} +1 -1
  12. package/es/lib/hooks/intlHooks/useIntlKeyStore/index.js +13 -0
  13. package/es/lib/hooks/intlHooks/useKintIntl/index.js +13 -0
  14. package/es/lib/hooks/{useKintIntl.js → intlHooks/useKintIntl/useKintIntl.js} +1 -1
  15. package/es/lib/hooks/useInvalidateRefdata/index.js +13 -0
  16. package/es/lib/hooks/{useInvalidateRefdata.js → useInvalidateRefdata/useInvalidateRefdata.js} +1 -1
  17. package/es/lib/hooks/useMutateCustomProperties/index.js +13 -0
  18. package/es/lib/hooks/{useMutateCustomProperties.js → useMutateCustomProperties/useMutateCustomProperties.js} +1 -1
  19. package/es/lib/hooks/useMutateGeneric/index.js +13 -0
  20. package/es/lib/hooks/useMutateRefdataCategory/index.js +13 -0
  21. package/es/lib/hooks/{useMutateRefdataCategory.js → useMutateRefdataCategory/useMutateRefdataCategory.js} +2 -2
  22. package/es/lib/hooks/useMutateRefdataValue/index.js +13 -0
  23. package/es/lib/hooks/{useMutateRefdataValue.js → useMutateRefdataValue/useMutateRefdataValue.js} +2 -2
  24. package/es/lib/utils/refdataQueryKey/index.js +13 -0
  25. package/package.json +1 -1
  26. package/src/index.js +4 -0
  27. package/src/lib/NumberField/README.md +134 -0
  28. package/src/lib/SASQLookupComponent/README.md +172 -0
  29. package/src/lib/SASQLookupComponent/SASQLookupComponent.js +6 -1
  30. package/src/lib/SASQLookupComponent/TableBody/README.md +113 -0
  31. package/src/lib/SASQRoute/README.md +49 -18
  32. package/src/lib/SASQViewComponent/README.md +132 -0
  33. package/src/lib/SearchKeyControl/README.md +70 -0
  34. package/src/lib/SearchKeyControl/SearchKeyControl.js +98 -0
  35. package/src/lib/SearchKeyControl/SearchKeyControl.test.js +165 -0
  36. package/src/lib/SearchKeyControl/index.js +1 -0
  37. package/src/lib/hooks/README.md +26 -121
  38. package/src/lib/hooks/__mocks__/index.js +2 -2
  39. package/src/lib/hooks/index.js +2 -3
  40. package/src/lib/hooks/intlHooks/README.md +31 -0
  41. package/src/lib/hooks/intlHooks/index.js +3 -0
  42. package/src/lib/hooks/intlHooks/useIntlKey/README.md +23 -0
  43. package/src/lib/hooks/intlHooks/useIntlKey/index.js +1 -0
  44. package/src/lib/hooks/{useIntlKey.js → intlHooks/useIntlKey/useIntlKey.js} +1 -1
  45. package/src/lib/hooks/intlHooks/useIntlKeyStore/README.md +32 -0
  46. package/src/lib/hooks/intlHooks/useIntlKeyStore/index.js +1 -0
  47. package/src/lib/hooks/intlHooks/useKintIntl/README.md +42 -0
  48. package/src/lib/hooks/intlHooks/useKintIntl/index.js +1 -0
  49. package/src/lib/hooks/{useKintIntl.js → intlHooks/useKintIntl/useKintIntl.js} +1 -1
  50. package/src/lib/hooks/useInvalidateRefdata/README.md +72 -0
  51. package/src/lib/hooks/useInvalidateRefdata/index.js +1 -0
  52. package/src/lib/hooks/{useInvalidateRefdata.js → useInvalidateRefdata/useInvalidateRefdata.js} +1 -1
  53. package/src/lib/hooks/useMutateCustomProperties/README.md +88 -0
  54. package/src/lib/hooks/useMutateCustomProperties/index.js +1 -0
  55. package/src/lib/hooks/{useMutateCustomProperties.js → useMutateCustomProperties/useMutateCustomProperties.js} +1 -1
  56. package/src/lib/hooks/useMutateGeneric/README.md +187 -0
  57. package/src/lib/hooks/useMutateGeneric/index.js +1 -0
  58. package/src/lib/hooks/useMutateRefdataCategory/README.md +85 -0
  59. package/src/lib/hooks/useMutateRefdataCategory/index.js +1 -0
  60. package/src/lib/hooks/{useMutateRefdataCategory.js → useMutateRefdataCategory/useMutateRefdataCategory.js} +2 -2
  61. package/src/lib/hooks/useMutateRefdataValue/README.md +154 -0
  62. package/src/lib/hooks/useMutateRefdataValue/index.js +1 -0
  63. package/src/lib/hooks/{useMutateRefdataValue.js → useMutateRefdataValue/useMutateRefdataValue.js} +2 -2
  64. package/src/lib/settingsHooks/useAppSettings/README.md +24 -0
  65. package/src/lib/utils/refdataQueryKey/README.md +38 -0
  66. package/src/lib/utils/refdataQueryKey/index.js +1 -0
  67. package/styles/SearchKeyControl.css +14 -0
  68. /package/es/lib/hooks/{useIntlKeyStore.js → intlHooks/useIntlKeyStore/useIntlKeyStore.js} +0 -0
  69. /package/es/lib/hooks/{useMutateGeneric.js → useMutateGeneric/useMutateGeneric.js} +0 -0
  70. /package/es/lib/utils/{refdataQueryKey.js → refdataQueryKey/refdataQueryKey.js} +0 -0
  71. /package/src/lib/hooks/{useIntlKeyStore.js → intlHooks/useIntlKeyStore/useIntlKeyStore.js} +0 -0
  72. /package/src/lib/hooks/{useMutateGeneric.js → useMutateGeneric/useMutateGeneric.js} +0 -0
  73. /package/src/lib/utils/{refdataQueryKey.js → refdataQueryKey/refdataQueryKey.js} +0 -0
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "default", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _refdataQueryKey.default;
10
+ }
11
+ });
12
+ var _refdataQueryKey = _interopRequireDefault(require("./refdataQueryKey"));
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-int/stripes-kint-components",
3
- "version": "5.18.0",
3
+ "version": "5.19.0",
4
4
  "description": "Stripes Component library for K-Int specific applications",
5
5
  "sideEffects": [
6
6
  "*.css"
package/src/index.js CHANGED
@@ -42,6 +42,10 @@ export {
42
42
  default as SearchField
43
43
  } from './lib/SearchField';
44
44
 
45
+ export {
46
+ default as SearchKeyControl
47
+ } from './lib/SearchKeyControl';
48
+
45
49
  // SASQRoute
46
50
  export {
47
51
  default as SASQRoute
@@ -0,0 +1,134 @@
1
+ # NumberField
2
+
3
+ A controlled input component designed for numeric values, providing parsing, validation, and seamless integration with form libraries like React Final Form. **NumberField** ensures that user input is always treated as a numeric value (or empty string) while maintaining compatibility with browser-native number input validation.
4
+
5
+ ## Features
6
+
7
+ - **Controlled/Uncontrolled Support:** Works as a controlled component (via `value`) or within form libraries (via `input`).
8
+ - **Automatic Parsing:** Converts user input to a numeric value (float) or empty string.
9
+ - **Form Integration:** Compatible with React Final Form's `Field` component.
10
+ - **Dual Input Handling:** Uses a visible `TextField` for user interaction and a hidden input for form state management.
11
+ - **Validation:** Leverages HTML5 `type="number"` validation with fallback to numeric parsing.
12
+
13
+ ## Basic Usage
14
+
15
+ ### Standalone (Controlled)
16
+
17
+ ```jsx
18
+ import { useState } from 'react';
19
+ import { NumberField } from '@k-int/stripes-kint-components';
20
+
21
+ const AgeInput = () => {
22
+ const [age, setAge] = useState('');
23
+
24
+ return (
25
+ <NumberField
26
+ label="Enter your age"
27
+ value={age}
28
+ onChange={(e, value) => setAge(value)}
29
+ aria-label="Age input"
30
+ />
31
+ );
32
+ };
33
+
34
+ export default AgeInput;
35
+ ```
36
+
37
+ ### With React Final Form
38
+
39
+ ```jsx
40
+ import { Field } from 'react-final-form';
41
+ import { NumberField } from '@k-int/stripes-kint-components';
42
+
43
+ const FormAgeField = () => (
44
+ <Field
45
+ name="age"
46
+ render={({ input }) => (
47
+ <NumberField
48
+ label="Age"
49
+ input={input}
50
+ aria-label="Form age input"
51
+ />
52
+ )}
53
+ />
54
+ );
55
+
56
+ export default FormAgeField;
57
+ ```
58
+
59
+ ## Props
60
+
61
+ | Prop | Type | Required | Description |
62
+ |-------------|------------|----------|--------------------------------------------------------------------------------------------------------------|
63
+ | `input` | `object` | ✕ | Form library input object (e.g., from React Final Form). Must contain `name`, `onChange`, and `value`. |
64
+ | `value` | `number` | ✕ | Controlled value (use either `input` or `value`, not both). |
65
+ | `onChange` | `function` | ✕ | Custom change handler: `(event: React.ChangeEvent, value: number | '') => void`. |
66
+ | `onBlur` | `function` | ✕ | Custom blur handler: `(event: React.FocusEvent) => void`. |
67
+ | ...TextFieldProps | `any` | ✕ | All other props passed to underlying [TextField](https://stripes.github.io/stripes-components/TextField). |
68
+
69
+ ## Behavior Details
70
+
71
+ ### Input Handling
72
+ - **User Input:** Directly manipulates a visible `TextField`
73
+ - **Value Parsing:**
74
+ ```js
75
+ const parsedValue = parseFloat(userInput);
76
+ // Returns number or NaN
77
+ ```
78
+ - **Form State:** Maintains a hidden `<input>` that always contains:
79
+ - Valid number (as float)
80
+ - Empty string (for invalid/empty input)
81
+
82
+ ### Value Propagation
83
+ 1. User types "12.5" ➔ `handleUserChange`:
84
+ ```js
85
+ parsedValue = 12.5
86
+ setNumValue(12.5) // Updates visible field
87
+ changeField(12.5) // Updates hidden input
88
+ ```
89
+ 2. Hidden input's `onChange`:
90
+ ```js
91
+ input.onChange(12.5) // Propagates to form library
92
+ passedOnChange(12.5) // Notifies custom handler
93
+ ```
94
+
95
+ ## Integration Notes
96
+
97
+ ### Form Library Requirements
98
+ When using with React Final Form:
99
+ ```jsx
100
+ <Field
101
+ name="quantity"
102
+ parse={v => v === '' ? undefined : Number(v)} // Convert empty string to undefined
103
+ render={({ input }) => (
104
+ <NumberField
105
+ input={input}
106
+ label="Quantity"
107
+ />
108
+ )}
109
+ />
110
+ ```
111
+
112
+ ### Styling/Validation
113
+ - Inherits all styling capabilities from `@folio/stripes-components/TextField`
114
+ - Browser-native number validation shown via:
115
+ ```jsx
116
+ <NumberField
117
+ type="number"
118
+ min={0}
119
+ max={100}
120
+ step={0.1}
121
+ />
122
+ ```
123
+
124
+ ## Error Handling
125
+ Implement custom error states through form library integrations or wrapper components:
126
+ ```jsx
127
+ const ErrorProneField = ({ meta, ...props }) => (
128
+ <NumberField
129
+ {...props}
130
+ error={meta.touched && meta.error}
131
+ aria-label="Error-prone field"
132
+ />
133
+ );
134
+ ```
@@ -0,0 +1,172 @@
1
+ # SASQLookupComponent
2
+
3
+ A highly configurable component that renders a lookup view for displaying data in a multi-pane layout. **SASQLookupComponent** combines a search and sort query (SASQ) interface, a filter pane, and a main content pane into a unified view. It leverages components from `@folio/stripes/smart-components` and `@folio/stripes/components` to provide a persistent paneset layout with integrated search, filtering, and pagination.
4
+
5
+ > **Note:** Detailed documentation for sub-components (such as **SearchAndSortQuery**, **PersistedPaneset**, **CollapseFilterPaneButton**, and **ExpandFilterPaneButton**) is available separately. **SASQLookupComponent** is designed to work seamlessly with these components while allowing for significant customization via its props.
6
+
7
+ ## Basic Usage
8
+
9
+ Below is an example demonstrating how to use **SASQLookupComponent**. In this example, the component is configured with custom fetch parameters, filtering behavior, and a custom table body for rendering results. The component automatically manages query state, pagination, and filter pane visibility.
10
+
11
+ ```jsx
12
+ import { FormattedMessage } from 'react-intl';
13
+ import { SASQLookupComponent } from '@k-int/stripes-kint-components';
14
+ import CustomFilter from './CustomFilter';
15
+ import CustomTableBody from './CustomTableBody';
16
+
17
+ const MyLookupView = () => {
18
+ const fetchParameters = {
19
+ endpoint: '/api/my-items',
20
+ SASQ_MAP: {
21
+ searchKey: 'name',
22
+ perPage: 25,
23
+ // Additional SASQ configuration
24
+ }
25
+ };
26
+
27
+ return (
28
+ <SASQLookupComponent
29
+ id="my-lookup"
30
+ path="/my-lookup"
31
+ fetchParameters={fetchParameters}
32
+ FilterComponent={CustomFilter}
33
+ RenderBody={CustomTableBody}
34
+ intlKey="myLookup"
35
+ intlNS="myApp"
36
+ labelOverrides={{ foundValues: 'Items Found' }}
37
+ resultColumns={[
38
+ { propertyPath: 'name', label: <FormattedMessage id="myApp.item.name" /> },
39
+ { propertyPath: 'status', label: <FormattedMessage id="myApp.item.status" /> }
40
+ ]}
41
+ searchFieldAriaLabel="Search items"
42
+ >
43
+ {/* Optionally, additional children can be rendered */}
44
+ </SASQLookupComponent>
45
+ );
46
+ };
47
+
48
+ export default MyLookupView;
49
+ ```
50
+
51
+ In this example, **SASQLookupComponent**:
52
+
53
+ - Uses `fetchParameters` to configure data fetching.
54
+ - Provides a custom filter interface via `FilterComponent`.
55
+ - Renders results using a custom table body (or defaults to an internal **TableBody**).
56
+ - Manages pagination and query state via hooks like `usePrevNextPagination` and `useKiwtSASQuery`.
57
+
58
+ ## Props
59
+
60
+ | Name | Type | Description | Default | Required |
61
+ |---------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|----------|
62
+ | `id` | `string` | A unique identifier for the lookup instance. Used to generate unique keys for query state, persistent paneset, and filter pane visibility in local storage. | | ✓ |
63
+ | `fetchParameters` | `object` | An object that defines the endpoints and SASQ configuration used for fetching data. It must include:<br><br>• **endpoint:** The URL used to fetch the main data set.<br>• **SASQ_MAP:** An object containing settings for search, filter, pagination (e.g., `searchKey`, `perPage`, etc.). Additional keys (such as `itemEndpoint`) can also be provided if needed. | `{}` | ✓ |
64
+ | `FilterComponent` | `func` or `node` | A custom component used to render additional filtering options in the filter pane. This component receives props for managing active filters, search state, and resetting filters. | `() => null` | ✕ |
65
+ | `FilterPaneHeaderComponent` | `func` or `node` | A component rendered at the top of the filter pane. Use this to customize the header area of the filter pane. | `() => null` | ✕ |
66
+ | `filterPaneProps` | `object` | Additional props to be passed to the filter pane. These props can customize the appearance and behavior of the filter pane (such as first or last menu elements). | `{}` | ✕ |
67
+ | `intlKey` | `string` | A base internationalization key used by the internal `useKintIntl` hook to resolve localized messages (e.g., for labels or pane titles). | | ✕ |
68
+ | `intlNS` | `string` | An internationalization namespace used by the internal `useKintIntl` hook. | | ✕ |
69
+ | `labelOverrides` | `object` | An object for overriding default labels, such as the text for displaying the count of found values. | `{}` | ✕ |
70
+ | `lookupQueryNamespaceGenerator` | `func` | A function that generates a query namespace (an array) for `react-query` based on provided parameters such as `currentPage`, `namespace`, `id`, `query`, etc. This ensures that queries are uniquely identified. | See default implementation in source code | ✕ |
71
+ | `mainPaneProps` | `object` | Additional props to be passed to the main pane containing the lookup results. This can include custom menu elements or styling. | `{}` | ✕ |
72
+ | `mclProps` | `object` | Custom properties to be passed to the underlying Multi-Column List (MCL) component. These properties are merged with pagination props derived from `usePrevNextPagination`. | `{}` | ✕ |
73
+ | `noSearchField` | `bool` | When set to `true`, the search field is not rendered in the filter pane. Use this if you want to disable search input. | `false` | ✕ |
74
+ | `persistedPanesetProps` | `object` | Additional props to be passed to the **PersistedPaneset** component, which manages the persistent layout of the filter and main panes. | `{}` | ✕ |
75
+ | `queryParameterGenerator` | `func` | A function that takes the SASQ_MAP configuration and current query values to generate an array of query parameters for the fetch call. Defaults to `generateKiwtQuery`. | `generateKiwtQuery` | ✕ |
76
+ | `RenderBody` | `func` or `node` | A component used to render the body of the main pane (typically a table). If not provided, the internal **TableBody** component is used. | `TableBody` | ✕ |
77
+ | `rowNavigation` | `bool` | Flag to enable or disable row navigation. When enabled, clicking on a row triggers navigation to a detailed view. | `true` | ✕ |
78
+ | `sasqProps` | `object` | Additional props to override or extend the default SASQ query behavior. These props can include custom query values, setters, or getters. | | ✕ |
79
+ | `searchableIndexes` | `arrayOf(object)` | An array of objects defining the options for the search index selection component (`SearchKeyControl`), rendered below the search field. Each object typically has `value` and `label` keys. If empty or omitted, the qindex checkboxes are not shown. | `[]` | ✕ |
80
+ | `searchFieldAriaLabel` | `string` | Accessibility label for the search field. | | ✕ |
81
+ | `searchFieldProps` | `object` | Additional props to be passed to the **SearchField** component for customizing its behavior or styling. | | ✕ |
82
+ | `children` | `node`, `func` | Optional children to be rendered below the main pane. These are rendered within the **PersistedPaneset** container. | | ✕ |
83
+ Below is an additional section for **SASQLookupComponent** documentation that describes the available functionality on the component's ref along with a worked example.
84
+
85
+
86
+ ## Exposed Ref Functionality
87
+
88
+ **SASQLookupComponent** uses `forwardRef` and `useImperativeHandle` to expose specific properties to parent components. This allows external components to access certain internal states and query-related information directly. The ref object includes the following properties:
89
+
90
+ - **`lookupQueryProps`**:
91
+ An object containing:
92
+ - **`data`**: The latest data fetched by the component.
93
+ - Additional query-related properties returned from `useQuery` (such as loading state, error, etc.).
94
+
95
+ - **`queryParams`**:
96
+ The array of query parameters generated by the component, based on the provided SASQ configuration and current query state. This reflects the current filters, pagination, and search criteria used for the data fetch.
97
+
98
+ In general is is recommended not to use this functionality, as it represents an antipattern in React to pass information back up to the parents. Instead the implementing developer should try to replace the inner rendered components and do their logic there with the passed information.
99
+
100
+
101
+ ### Worked Example
102
+
103
+ Below is a sample usage demonstrating how to access the exposed ref properties:
104
+
105
+ ```jsx
106
+ import { useRef, useEffect } from 'react';
107
+ import { SASQLookupComponent } from '@k-int/stripes-kint-components';
108
+
109
+ const LookupWithRefExample = () => {
110
+ // Create a ref to access SASQLookupComponent's exposed methods and properties
111
+ const lookupRef = useRef();
112
+
113
+ useEffect(() => {
114
+ // When the component mounts or updates, you can access the lookupQueryProps and queryParams
115
+ if (lookupRef.current) {
116
+ const { lookupQueryProps, queryParams } = lookupRef.current;
117
+ console.log('Fetched data:', lookupQueryProps.data);
118
+ console.log('Current query parameters:', queryParams);
119
+
120
+ // Example: Check if data is loaded and then trigger some side-effect
121
+ if (!lookupQueryProps.isLoading && lookupQueryProps.data) {
122
+ // Perform an action with the fetched data
123
+ console.log('Data is ready for processing');
124
+ }
125
+ }
126
+ }, []);
127
+
128
+ const fetchParameters = {
129
+ endpoint: '/api/my-items',
130
+ SASQ_MAP: {
131
+ searchKey: 'name',
132
+ perPage: 25
133
+ }
134
+ };
135
+
136
+ return (
137
+ <SASQLookupComponent
138
+ id="my-lookup"
139
+ path="/my-lookup"
140
+ fetchParameters={fetchParameters}
141
+ intlKey="myLookup"
142
+ intlNS="myApp"
143
+ ref={lookupRef} // Attach the ref here
144
+ searchableIndexes={[
145
+ { key: 'name' },
146
+ { key: 'description' }
147
+ ]} // Provide options for search key selection
148
+ />
149
+ );
150
+ };
151
+
152
+ export default LookupWithRefExample;
153
+ ```
154
+
155
+ ## How It Works
156
+
157
+ 1. **Query and Pagination Management:**
158
+ + The component leverages hooks such as `usePrevNextPagination` (for page state), `useKiwtSASQuery` (for search/filter/sort state), and `useQuery` (from `react-query` for data fetching). The query parameters string is generated using the provided `queryParameterGenerator` function based on the `WorkspaceParameters.SASQ_MAP` and the current state from the hooks.
159
+ 2. **Filter Pane & Main Pane Layout:**
160
+ - **Filter Pane:**
161
+ + Rendered conditionally based on local storage state (`filterPaneVisible`), it contains a search section (SearchField, SearchKeyControl if `searchableIndexes` are provided, Submit/Reset buttons - unless `noSearchField` is true) and custom filtering options provided via `FilterComponent` and `FilterPaneHeaderComponent`. Buttons for collapsing the pane are included.
162
+ - **Main Pane:**
163
+ + Displays the fetched data using the `RenderBody` component (defaulting to `TableBody`). It integrates pagination controls (via `mclProps` passed to `RenderBody`) and displays record counts in the header. An expand button is shown if the filter pane is collapsed.
164
+ 3. **Persistent Layout:**
165
+ The component wraps its content in a **PersistedPaneset** which maintains pane states (such as sizes and visibility) across sessions.
166
+
167
+ 4. **Customization and Extensibility:**
168
+ Through various props, consumers can inject custom components (`FilterComponent`, `FilterPaneHeaderComponent`, `RenderBody`), override query generation (`queryParameterGenerator`, `lookupQueryNamespaceGenerator`), configure data fetching (`WorkspaceParameters`), pass props down to underlying components (`filterPaneProps`, `mainPaneProps`, `mclProps`, `persistedPanesetProps`, `searchFieldProps`), tweak SASQ behavior (`sasqProps`), and adjust UI elements (`noSearchField`, `labelOverrides`, `searchableIndexes`).
169
+ 5. **Ref Forwarding:**
170
+ Using `forwardRef` and `useImperativeHandle`, the component exposes certain query properties and generated query parameters to parent components.
171
+
172
+ This design enables **SASQLookupComponent** to serve as a robust and flexible foundation for building data lookup views with advanced filtering, search, and pagination functionalities.
@@ -28,6 +28,7 @@ import { generateKiwtQuery } from '../utils';
28
28
  import { useKintIntl, useKiwtSASQuery, useLocalStorageState, usePrevNextPagination } from '../hooks';
29
29
 
30
30
  import TableBody from './TableBody';
31
+ import SearchKeyControl from '../SearchKeyControl';
31
32
 
32
33
  const SASQLookupComponent = forwardRef((props, ref) => {
33
34
  const {
@@ -59,8 +60,9 @@ const SASQLookupComponent = forwardRef((props, ref) => {
59
60
  RenderBody,
60
61
  rowNavigation = true, // Default navigation onRowClick
61
62
  sasqProps,
63
+ searchableIndexes,
62
64
  searchFieldAriaLabel,
63
- searchFieldProps,
65
+ searchFieldProps = {},
64
66
  } = props;
65
67
  const kintIntl = useKintIntl(passedIntlKey, passedIntlNS);
66
68
  const [count, setCount] = useState(0);
@@ -236,6 +238,9 @@ const SASQLookupComponent = forwardRef((props, ref) => {
236
238
  value={searchValue.query}
237
239
  {...searchFieldProps}
238
240
  />
241
+ {searchableIndexes.length > 0 && (
242
+ <SearchKeyControl options={searchableIndexes} />
243
+ )}
239
244
  <Button
240
245
  buttonStyle="primary"
241
246
  disabled={!searchValue.query}
@@ -0,0 +1,113 @@
1
+ # SASQTableBody
2
+
3
+ A component that renders a Multi-Column List (MCL) for displaying tabular data with integrated sorting, row navigation, and infinite scrolling. **SASQTableBody** is designed to work within lookup workflows (like **SASQLookupComponent**) but can be used independently. It handles rendering of data, empty states, and integrates with pagination via a `fetchNextPage` callback.
4
+
5
+ ## Basic Usage
6
+
7
+ Below is an example demonstrating how to use **SASQTableBody** with required props. Additional props are commented for context:
8
+
9
+ ```jsx
10
+ import { useState } from 'react';
11
+ import { SASQTableBody } from '@k-int/stripes-kint-components';
12
+
13
+ const MyTableView = () => {
14
+ const [data] = useState({
15
+ totalRecords: 2,
16
+ results: [
17
+ { id: '1', name: 'Item One', status: 'Active' },
18
+ { id: '2', name: 'Item Two', status: 'Inactive' }
19
+ ]
20
+ });
21
+
22
+ const query = { sort: 'name' }; // Used for sorting and empty state messages
23
+ const resultColumns = [
24
+ { propertyPath: 'name', label: 'Name' },
25
+ { propertyPath: 'status', label: 'Status' }
26
+ ];
27
+
28
+ const fetchNextPage = ({ pageParam }) => {
29
+ console.log('Fetching page:', pageParam);
30
+ // Implement pagination logic here
31
+ };
32
+
33
+ return (
34
+ <SASQTableBody
35
+ data={data}
36
+ query={query}
37
+ path="/my-items" // Base path for row navigation
38
+ resultColumns={resultColumns}
39
+ fetchNextPage={fetchNextPage}
40
+ // mclProps={{ formatter: { name: (item) => <strong>{item.name}</strong> } }}
41
+ // rowNavigation={false}
42
+ />
43
+ );
44
+ };
45
+
46
+ export default MyTableView;
47
+ ```
48
+
49
+ ### Explanation
50
+
51
+ - **data:**
52
+ Contains `results` (array of items) and `totalRecords` (total items for pagination).
53
+ - **query:**
54
+ Provides current search/sort state. Must include `sort` and `query` if applicable.
55
+ - **path:**
56
+ Base URL path for constructing row navigation links (e.g., `/my-items/1`).
57
+ - **resultColumns:**
58
+ Defines table columns via `propertyPath` (data key) and `label` (header text).
59
+ - **fetchNextPage:**
60
+ Called when more data is needed (e.g., scrolling to the bottom).
61
+
62
+ ## Props
63
+
64
+ | Prop | Type | Required | Description |
65
+ |---------------------|--------------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
66
+ | `data` | `{ totalRecords: number, results: object[] }` | ✓ | Data to display. `results` contains the items, `totalRecords` sets pagination bounds. |
67
+ | `query` | `object` | ✓ | Current query state (e.g., `{ sort: 'name', query: 'search term' }`). Used for sorting and empty state messages. |
68
+ | `path` | `string` | ✓ | Base path for row URLs. Each row links to `{path}/{rowData.id}`. |
69
+ | `resultColumns` | `Array<{ propertyPath: string, label: string }>` | ✓ | Columns to render. `propertyPath` accesses the data field, `label` sets the header. |
70
+ | `fetchNextPage` | `({ pageParam: number }) => void` | ✓ | Callback to load more data. `pageParam` indicates the next page index. |
71
+ | `mclProps` | `object` | ✕ | Props passed to the underlying [MultiColumnList](https://github.com/folio-org/stripes-components/tree/master/lib/MultiColumnList). Example: `formatter`, `id`. |
72
+ | `rowNavigation` | `boolean` | ✕ | Enables navigation to detail views on row click. Default: `true`. |
73
+ | `filterPaneVisible` | `boolean` | ✕ | Toggles filter pane visibility in `NoResultsMessage`. |
74
+ | `toggleFilterPane` | `() => void` | ✕ | Callback to toggle filter pane. Used in `NoResultsMessage`. |
75
+ | `intlKey` | `string` | ✕ | Base key for internationalizing labels. See `useKintIntl`. |
76
+ | `intlNS` | `string` | ✕ | Namespace for internationalization. See `useKintIntl`. |
77
+ | `labelOverrides` | `object` | ✕ | Overrides default labels (e.g., `{ noResultsFound: 'No items' }`). |
78
+ | `match` | `object` | ✕ | React Router `match` object. Used to highlight the selected row via URL `id` param. |
79
+ | `isLoading` | `boolean` | ✕ | Shows loading state in `NoResultsMessage`. |
80
+ | `isError` | `boolean` | ✕ | Shows error state in `NoResultsMessage`. |
81
+ | `error` | `object` | ✕ | Error object displayed in `NoResultsMessage`. |
82
+
83
+ ## Key Features
84
+
85
+ 1. **Row Navigation:**
86
+ When `rowNavigation={true}` (default), clicking a row navigates to `{path}/{rowData.id}`. Uses `react-router` internally.
87
+
88
+ 2. **Sorting:**
89
+ Column headers trigger `onSort`, updating the `query.sort` value. The current sort is derived from `query.sort`.
90
+
91
+ 3. **Infinite Scroll:**
92
+ `fetchNextPage` is called automatically as the user scrolls. Can alternatively use with pagination logic (e.g., `usePrevNextPagination` props passed to mclProps).
93
+
94
+ 4. **Custom Formatters:**
95
+ Pass a `formatter` in `mclProps` to customize cell rendering. Each formatter receives the row data and a `defaultRowUrl`:
96
+ ```jsx
97
+ mclProps={{
98
+ formatter: {
99
+ name: (item) => <Link to={item.defaultRowUrl}>{item.name}</Link>
100
+ }
101
+ }}
102
+ ```
103
+
104
+ 5. **Empty States:**
105
+ `NoResultsMessage` handles loading, errors, and no-results states.
106
+
107
+ ## Integration Notes
108
+
109
+ - **Parent Components:**
110
+ Designed to work within **SASQLookupComponent** (as its default `RenderBody`), but can be used standalone.
111
+
112
+ - **Routing:**
113
+ Must be rendered within a `react-router` context for navigation to work.
@@ -1,33 +1,38 @@
1
1
  # SASQRoute
2
- A component designed to speed up the basic 3-pane layout setup process, SASQRoute is an all in one Routing, SASQ and MCL setup
2
+
3
+ A component designed to accelerate the setup of a basic 3-pane layout by combining routing, SASQ (Search And Sort Query), and Multi-Column List (MCL) configuration in one place. **SASQRoute** simplifies the process of configuring lookup and view components by automatically setting up the required routes and passing down fetch parameters and custom components.
4
+
5
+ > **Note:** Although **SASQRoute** is intended to work with the default sub-components—**SASQLookupComponent** and **SASQViewComponent**—you can override them via props. Refer to the documentation for those sub-components for further details.
3
6
 
4
7
  ## Basic Usage
5
- ```
6
- import React from 'react';
8
+
9
+ Below is an example of how to set up **SASQRoute**. In this example, it configures a route that manages both a lookup view and an individual item view within a 3-pane layout. The lookup component renders an MCL with the given `resultColumns`, and clicking on a row navigates to the view route that renders the specified `ViewComponent`.
10
+
11
+ ```jsx
7
12
  import { FormattedMessage } from 'react-intl';
8
13
 
9
14
  import { SASQRoute } from '@k-int/stripes-kint-components';
10
15
  import ActionItem from '../components/ActionItem';
11
16
 
12
17
  const ActionedRoute = ({ path }) => {
13
-
14
18
  const fetchParameters = {
15
19
  endpoint: "remote-sync/feedback/done",
16
20
  itemEndpoint: "remote-sync/feedback",
17
21
  SASQ_MAP: {
18
22
  searchKey: 'description',
19
23
  filterKeys: {
24
+ // Additional filter configuration if required
20
25
  }
21
26
  }
22
27
  };
23
28
 
24
29
  const resultColumns = [
25
- { propertyPath: "selected", label: " " },
26
- { propertyPath:"description", label: <FormattedMessage id="ui-remote-sync.prop.feedback.description" /> },
27
- { propertyPath:"status", label: <FormattedMessage id="ui-remote-sync.prop.feedback.status" /> },
28
- { propertyPath:"correlationId", label: <FormattedMessage id="ui-remote-sync.prop.feedback.correlationId" /> },
29
- { propertyPath:"caseIndicator", label: <FormattedMessage id="ui-remote-sync.prop.feedback.caseIndicator" /> }
30
- ];
30
+ { propertyPath: "selected", label: " " },
31
+ { propertyPath: "description", label: <FormattedMessage id="ui-remote-sync.prop.feedback.description" /> },
32
+ { propertyPath: "status", label: <FormattedMessage id="ui-remote-sync.prop.feedback.status" /> },
33
+ { propertyPath: "correlationId", label: <FormattedMessage id="ui-remote-sync.prop.feedback.correlationId" /> },
34
+ { propertyPath: "caseIndicator", label: <FormattedMessage id="ui-remote-sync.prop.feedback.caseIndicator" /> }
35
+ ];
31
36
 
32
37
  return (
33
38
  <SASQRoute
@@ -41,15 +46,41 @@ const ActionedRoute = ({ path }) => {
41
46
  };
42
47
  ```
43
48
 
44
- NOTE - The following prop list is incomplete
49
+ In this example, **SASQRoute**:
50
+ - Configures lookup behavior via `fetchParameters` and the associated `SASQ_MAP`.
51
+ - Uses `resultColumns` to define the columns for the MCL rendered by the lookup component.
52
+ - Sets up routes under the provided `path` for both the lookup and view panes.
53
+ - Renders the `ActionItem` component when an individual row is selected.
54
+
45
55
  ## Props
46
56
 
47
- Name | Type | Description | default | required
48
- --- | --- | --- | --- | ---
49
- fetchParameters | object | An object containing the parameters needed to make the fetches necessary for both the table and the view components. `endpoint` contains the main fetch endpoint, which regularly will be used for both fetching all data, and also for fetching an individual item (It is assumed that this endpoint will have `/{id}` appended to it.) If `itemEndpoint` is provided that will be used instead (this will also have `/{:id}` appended to it). `SASQ_MAP` is an object of the shape taken by `generateKiwtQuery` | | ✓ |
50
- id | string | A unique identifier for this route. IMPORTANT that this is unique, as it drives paneset logic | | ✓ |
51
- path | string | The main path for this route. In the above example the path is `remote-sync/actioned`. This component will set up the main 3 pane layout under this path, and also the view pane route under `remote-sync/actioned/:id` | | ✓ |
52
- resultColumns | array | An array containing objects with a `propertyPath` and `label`. These will be used to drive the MCL columns. | | ✓ |
53
- ViewComponent | Element | The component to render on clicking a row entry. | | ✓ |
57
+ | Name | Type | Description | Default | Required |
58
+ |-----------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|----------|
59
+ | `fetchParameters` | `object` | An object containing the parameters needed for data fetching for both the lookup and view components. This should include:<br><br>• **endpoint:** The main fetch endpoint for retrieving all data. The endpoint is typically used for both list and individual item fetches (appending `/{id}` to the endpoint for individual items).<br><br>• **itemEndpoint (optional):** An alternative endpoint for fetching a single item.<br><br>• **SASQ_MAP:** An object defining search and filter configuration. See `generateKiwtQuery` for details. | | |
60
+ | `id` | `string` | A unique identifier for this route. This identifier is important as it drives pane set logic and must be unique within the application. | | |
61
+ | `path` | `string` | The base path for this route. **SASQRoute** will set up a 3-pane layout under this path and automatically configure the view route under `{path}/:id`. | | ✓ |
62
+ | `resultColumns` | `array` | An array of objects where each object defines a column for the Multi-Column List (MCL) rendered by the lookup component. Each object should contain a `propertyPath` and a `label`. These columns drive the display of data in the list view. | | ✓ |
63
+ | `ViewComponent` | `element` (or `func`) | The component to render when a row in the lookup list is selected. This component is displayed in the view pane for showing detailed information about a selected item. | | |
64
+ | `children` | `node`, `element`, or `func` | Optional additional child elements to render within the lookup component. These are rendered inside the **SASQLookupComponent**. | | ✕ |
65
+ | `getPathLookup` | `func` | A function to determine the route for the lookup pane. Defaults to appending `/:id?` to the base `path`. Use this prop to customize the lookup route if needed. | `(path) => ${path}/:id?` | ✕ |
66
+ | `getPathView` | `func` | A function to determine the route for the view pane. Defaults to appending `/:id` to the base `path`. Use this prop to customize the view route if needed. | `(path) => ${path}/:id` | ✕ |
67
+ | `SASQLookupComponent` | `element` or `func` | The component to be used for the lookup view. Defaults to the built-in **SASQLookupComponent**. Override this prop to provide a custom lookup component. | `SASQLookupComponent` | ✕ |
68
+ | `SASQViewComponent` | `element` or `func` | The component to be used for the view pane. Defaults to the built-in **SASQViewComponent**. Override this prop to provide a custom view component. | `SASQViewComponent` | ✕ |
69
+ | `...props` | `object` | Additional props will be passed down to both the lookup and view components. Use these to further customize behavior or appearance as needed. | | ✕ |
70
+
71
+ ## How It Works
72
+
73
+ 1. **Configuration of SASQ_MAP:**
74
+ The component extracts and updates the `SASQ_MAP` from `fetchParameters`. If `perPage` is not defined, it defaults to 25. Additionally, it ensures that `stats` is set to `true` before reassigning the object back to `fetchParameters`.
75
+
76
+ 2. **Routing Setup:**
77
+ - The **lookup route** is configured using the `getPathLookup` function (defaulting to appending `/:id?` to the base `path`). The lookup component (default **SASQLookupComponent**) renders the main Multi-Column List.
78
+ - Nested within the lookup route is a **view route** configured using the `getPathView` function (defaulting to appending `/:id`). This route renders the view component (default **SASQViewComponent**), which in turn displays the detailed view of a selected item via the passed `ViewComponent`.
79
+
80
+ 3. **Forwarding Refs:**
81
+ The component uses `forwardRef` and `useImperativeHandle` to combine the refs of both the lookup and view components, allowing parent components to access methods or properties exposed by these sub-components.
54
82
 
83
+ 4. **Customizability:**
84
+ By overriding default sub-components (`SASQLookupComponent` and `SASQViewComponent`), and by providing custom functions for route paths (`getPathLookup` and `getPathView`), developers can tailor the routing and display behavior to match specific application needs.
55
85
 
86
+ This comprehensive setup provided by **SASQRoute** allows for a rapid configuration of complex layouts involving data lookup and detailed views, reducing boilerplate and ensuring consistency across the application.