@k-int/stripes-kint-components 5.17.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.
- package/CHANGELOG.md +20 -0
- package/LICENSE +1 -1
- package/es/index.js +32 -12
- package/es/lib/EditableSettingsList/EditableSettingsList.js +4 -3
- package/es/lib/EditableSettingsList/EditableSettingsListFieldArray/EditableSettingsListFieldArray.js +110 -0
- package/es/lib/EditableSettingsList/{EditableSettingsListFieldArray.test.js → EditableSettingsListFieldArray/EditableSettingsListFieldArray.test.js} +3 -4
- package/es/lib/EditableSettingsList/EditableSettingsListFieldArray/index.js +13 -0
- package/es/lib/EditableSettingsList/SettingField/{EditSettingValue.js → EditSettingValue/EditSettingValue.js} +2 -2
- package/es/lib/EditableSettingsList/SettingField/{EditSettingValue.test.js → EditSettingValue/EditSettingValue.test.js} +2 -3
- package/es/lib/EditableSettingsList/SettingField/EditSettingValue/index.js +13 -0
- package/es/lib/EditableSettingsList/SettingField/{RenderSettingValue.js → RenderSettingValue/RenderSettingValue.js} +1 -1
- package/es/lib/EditableSettingsList/SettingField/{RenderSettingValue.test.js → RenderSettingValue/RenderSettingValue.test.js} +2 -2
- package/es/lib/EditableSettingsList/SettingField/RenderSettingValue/index.js +13 -0
- package/es/lib/EditableSettingsList/SettingField/SettingField.js +5 -5
- package/es/lib/EditableSettingsList/SettingField/SettingField.test.js +54 -44
- package/es/lib/EditableSettingsList/index.js +12 -0
- package/es/lib/SASQLookupComponent/SASQLookupComponent.js +5 -1
- package/es/lib/SearchKeyControl/SearchKeyControl.js +95 -0
- package/es/lib/SearchKeyControl/SearchKeyControl.test.js +177 -0
- package/es/lib/SearchKeyControl/index.js +13 -0
- package/es/lib/SettingPage/SettingPage.js +3 -1
- package/es/lib/SettingPage/{SettingPagePane.js → SettingPagePane/SettingPagePane.js} +2 -2
- package/es/lib/SettingPage/SettingPagePane/index.js +13 -0
- package/es/lib/hooks/__mocks__/index.js +2 -2
- package/es/lib/hooks/index.js +33 -21
- package/es/lib/hooks/intlHooks/index.js +27 -0
- package/es/lib/hooks/intlHooks/useIntlKey/index.js +13 -0
- package/es/lib/hooks/{useIntlKey.js → intlHooks/useIntlKey/useIntlKey.js} +1 -1
- package/es/lib/hooks/intlHooks/useIntlKeyStore/index.js +13 -0
- package/es/lib/hooks/intlHooks/useKintIntl/index.js +13 -0
- package/es/lib/hooks/{useKintIntl.js → intlHooks/useKintIntl/useKintIntl.js} +1 -1
- package/es/lib/hooks/useInvalidateRefdata/index.js +13 -0
- package/es/lib/hooks/{useInvalidateRefdata.js → useInvalidateRefdata/useInvalidateRefdata.js} +1 -1
- package/es/lib/hooks/useMutateCustomProperties/index.js +13 -0
- package/es/lib/hooks/{useMutateCustomProperties.js → useMutateCustomProperties/useMutateCustomProperties.js} +1 -1
- package/es/lib/hooks/useMutateGeneric/index.js +13 -0
- package/es/lib/hooks/useMutateRefdataCategory/index.js +13 -0
- package/es/lib/hooks/{useMutateRefdataCategory.js → useMutateRefdataCategory/useMutateRefdataCategory.js} +2 -2
- package/es/lib/hooks/useMutateRefdataValue/index.js +13 -0
- package/es/lib/hooks/{useMutateRefdataValue.js → useMutateRefdataValue/useMutateRefdataValue.js} +2 -2
- package/es/lib/settingsHooks/useAppSettings/index.js +13 -0
- package/es/lib/settingsHooks/{useAppSettings.js → useAppSettings/useAppSettings.js} +1 -1
- package/es/lib/settingsHooks/useSettingSection/index.js +13 -0
- package/es/lib/settingsHooks/{useSettingSection.js → useSettingSection/useSettingSection.js} +1 -1
- package/es/lib/settingsHooks/useSettings/index.js +13 -0
- package/es/lib/settingsHooks/{useSettings.js → useSettings/useSettings.js} +10 -9
- package/es/lib/utils/refdataQueryKey/index.js +13 -0
- package/package.json +1 -1
- package/src/index.js +8 -3
- package/src/lib/ActionList/README.md +18 -18
- package/src/lib/EditableSettingsList/EditableSettingsList.js +3 -2
- package/src/lib/EditableSettingsList/EditableSettingsListFieldArray/EditableSettingsListFieldArray.js +118 -0
- package/src/lib/EditableSettingsList/{EditableSettingsListFieldArray.test.js → EditableSettingsListFieldArray/EditableSettingsListFieldArray.test.js} +3 -5
- package/src/lib/EditableSettingsList/EditableSettingsListFieldArray/README.md +68 -0
- package/src/lib/EditableSettingsList/EditableSettingsListFieldArray/index.js +1 -0
- package/src/lib/EditableSettingsList/README.md +74 -0
- package/src/lib/EditableSettingsList/SettingField/{EditSettingValue.js → EditSettingValue/EditSettingValue.js} +2 -2
- package/src/lib/EditableSettingsList/SettingField/{EditSettingValue.test.js → EditSettingValue/EditSettingValue.test.js} +2 -5
- package/src/lib/EditableSettingsList/SettingField/EditSettingValue/README.md +63 -0
- package/src/lib/EditableSettingsList/SettingField/EditSettingValue/index.js +1 -0
- package/src/lib/EditableSettingsList/SettingField/README.md +61 -0
- package/src/lib/EditableSettingsList/SettingField/{RenderSettingValue.js → RenderSettingValue/RenderSettingValue.js} +1 -1
- package/src/lib/EditableSettingsList/SettingField/{RenderSettingValue.test.js → RenderSettingValue/RenderSettingValue.test.js} +2 -2
- package/src/lib/EditableSettingsList/SettingField/RenderSettingValue/index.js +1 -0
- package/src/lib/EditableSettingsList/SettingField/SettingField.js +5 -3
- package/src/lib/EditableSettingsList/SettingField/SettingField.test.js +65 -44
- package/src/lib/EditableSettingsList/index.js +1 -1
- package/src/lib/NumberField/README.md +134 -0
- package/src/lib/SASQLookupComponent/README.md +172 -0
- package/src/lib/SASQLookupComponent/SASQLookupComponent.js +6 -1
- package/src/lib/SASQLookupComponent/TableBody/README.md +113 -0
- package/src/lib/SASQRoute/README.md +49 -18
- package/src/lib/SASQViewComponent/README.md +132 -0
- package/src/lib/SearchKeyControl/README.md +70 -0
- package/src/lib/SearchKeyControl/SearchKeyControl.js +98 -0
- package/src/lib/SearchKeyControl/SearchKeyControl.test.js +165 -0
- package/src/lib/SearchKeyControl/index.js +1 -0
- package/src/lib/SettingPage/README.md +66 -0
- package/src/lib/SettingPage/SettingPage.js +3 -1
- package/src/lib/SettingPage/SettingPagePane/README.md +31 -0
- package/src/lib/SettingPage/{SettingPagePane.js → SettingPagePane/SettingPagePane.js} +2 -2
- package/src/lib/SettingPage/SettingPagePane/index.js +1 -0
- package/src/lib/hooks/README.md +26 -121
- package/src/lib/hooks/__mocks__/index.js +2 -2
- package/src/lib/hooks/index.js +2 -3
- package/src/lib/hooks/intlHooks/README.md +31 -0
- package/src/lib/hooks/intlHooks/index.js +3 -0
- package/src/lib/hooks/intlHooks/useIntlKey/README.md +23 -0
- package/src/lib/hooks/intlHooks/useIntlKey/index.js +1 -0
- package/src/lib/hooks/{useIntlKey.js → intlHooks/useIntlKey/useIntlKey.js} +1 -1
- package/src/lib/hooks/intlHooks/useIntlKeyStore/README.md +32 -0
- package/src/lib/hooks/intlHooks/useIntlKeyStore/index.js +1 -0
- package/src/lib/hooks/intlHooks/useKintIntl/README.md +42 -0
- package/src/lib/hooks/intlHooks/useKintIntl/index.js +1 -0
- package/src/lib/hooks/{useKintIntl.js → intlHooks/useKintIntl/useKintIntl.js} +1 -1
- package/src/lib/hooks/useInvalidateRefdata/README.md +72 -0
- package/src/lib/hooks/useInvalidateRefdata/index.js +1 -0
- package/src/lib/hooks/{useInvalidateRefdata.js → useInvalidateRefdata/useInvalidateRefdata.js} +1 -1
- package/src/lib/hooks/useMutateCustomProperties/README.md +88 -0
- package/src/lib/hooks/useMutateCustomProperties/index.js +1 -0
- package/src/lib/hooks/{useMutateCustomProperties.js → useMutateCustomProperties/useMutateCustomProperties.js} +1 -1
- package/src/lib/hooks/useMutateGeneric/README.md +187 -0
- package/src/lib/hooks/useMutateGeneric/index.js +1 -0
- package/src/lib/hooks/useMutateRefdataCategory/README.md +85 -0
- package/src/lib/hooks/useMutateRefdataCategory/index.js +1 -0
- package/src/lib/hooks/{useMutateRefdataCategory.js → useMutateRefdataCategory/useMutateRefdataCategory.js} +2 -2
- package/src/lib/hooks/useMutateRefdataValue/README.md +154 -0
- package/src/lib/hooks/useMutateRefdataValue/index.js +1 -0
- package/src/lib/hooks/{useMutateRefdataValue.js → useMutateRefdataValue/useMutateRefdataValue.js} +2 -2
- package/src/lib/settingsHooks/useAppSettings/README.md +24 -0
- package/src/lib/settingsHooks/useAppSettings/index.js +1 -0
- package/src/lib/settingsHooks/{useAppSettings.js → useAppSettings/useAppSettings.js} +1 -1
- package/src/lib/settingsHooks/useSettingSection/README.md +54 -0
- package/src/lib/settingsHooks/useSettingSection/index.js +1 -0
- package/src/lib/settingsHooks/{useSettingSection.js → useSettingSection/useSettingSection.js} +1 -1
- package/src/lib/settingsHooks/useSettings/README.md +84 -0
- package/src/lib/settingsHooks/useSettings/index.js +1 -0
- package/src/lib/settingsHooks/{useSettings.js → useSettings/useSettings.js} +10 -7
- package/src/lib/utils/refdataQueryKey/README.md +38 -0
- package/src/lib/utils/refdataQueryKey/index.js +1 -0
- package/styles/SearchKeyControl.css +14 -0
- package/es/lib/EditableSettingsList/EditableSettingsListFieldArray.js +0 -57
- package/src/lib/EditableSettingsList/EditableSettingsListFieldArray.js +0 -58
- /package/es/lib/hooks/{useIntlKeyStore.js → intlHooks/useIntlKeyStore/useIntlKeyStore.js} +0 -0
- /package/es/lib/hooks/{useMutateGeneric.js → useMutateGeneric/useMutateGeneric.js} +0 -0
- /package/es/lib/utils/{refdataQueryKey.js → refdataQueryKey/refdataQueryKey.js} +0 -0
- /package/src/lib/hooks/{useIntlKeyStore.js → intlHooks/useIntlKeyStore/useIntlKeyStore.js} +0 -0
- /package/src/lib/hooks/{useMutateGeneric.js → useMutateGeneric/useMutateGeneric.js} +0 -0
- /package/src/lib/utils/{refdataQueryKey.js → refdataQueryKey/refdataQueryKey.js} +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
|
|
4
|
+
import { renderWithIntl, Checkbox } from '@folio/stripes-erm-testing';
|
|
5
|
+
|
|
6
|
+
import SearchKeyControl from './SearchKeyControl';
|
|
7
|
+
|
|
8
|
+
const mockUseQIndex = jest.fn();
|
|
9
|
+
|
|
10
|
+
jest.mock('../hooks', () => ({
|
|
11
|
+
...jest.requireActual('../hooks'),
|
|
12
|
+
useQIndex: () => mockUseQIndex()
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe('SearchKeyControl', () => {
|
|
16
|
+
describe('without initial qIndex', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
mockUseQIndex.mockImplementation(() => {
|
|
19
|
+
return useState();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
renderWithIntl(
|
|
23
|
+
<SearchKeyControl
|
|
24
|
+
options={[
|
|
25
|
+
{
|
|
26
|
+
label: 'Opt 1',
|
|
27
|
+
key: 'opt1'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: 'Opt 2',
|
|
31
|
+
key: 'opt2'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'Opt 3',
|
|
35
|
+
key: 'opt3'
|
|
36
|
+
}
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('renders all Checkboxes', async () => {
|
|
43
|
+
await Checkbox('Opt 1').exists();
|
|
44
|
+
await Checkbox('Opt 2').exists();
|
|
45
|
+
await Checkbox('Opt 3').exists();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('all Checkboxes have expected initial "checked" value', async () => {
|
|
49
|
+
await Checkbox('Opt 1').has({ checked: false });
|
|
50
|
+
await Checkbox('Opt 2').has({ checked: false });
|
|
51
|
+
await Checkbox('Opt 3').has({ checked: false });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('clicking Opt 2', () => {
|
|
55
|
+
beforeEach(async () => {
|
|
56
|
+
await waitFor(async () => {
|
|
57
|
+
await Checkbox('Opt 2').click();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('all Checkboxes have expected "checked" value', async () => {
|
|
62
|
+
await Checkbox('Opt 1').has({ checked: false });
|
|
63
|
+
await Checkbox('Opt 2').has({ checked: true });
|
|
64
|
+
await Checkbox('Opt 3').has({ checked: false });
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('clicking Opt 1 and Opt 2', () => {
|
|
69
|
+
beforeEach(async () => {
|
|
70
|
+
await waitFor(async () => {
|
|
71
|
+
await Checkbox('Opt 1').click();
|
|
72
|
+
await Checkbox('Opt 2').click();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('all Checkboxes have expected "checked" value', async () => {
|
|
77
|
+
await Checkbox('Opt 1').has({ checked: true });
|
|
78
|
+
await Checkbox('Opt 2').has({ checked: true });
|
|
79
|
+
await Checkbox('Opt 3').has({ checked: false });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('with initial qIndex', () => {
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
mockUseQIndex.mockImplementation(() => {
|
|
87
|
+
return useState('opt1,opt3');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
renderWithIntl(
|
|
91
|
+
<SearchKeyControl
|
|
92
|
+
options={[
|
|
93
|
+
{
|
|
94
|
+
label: 'Opt 1',
|
|
95
|
+
key: 'opt1'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: 'Opt 2',
|
|
99
|
+
key: 'opt2'
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: 'Opt 3',
|
|
103
|
+
key: 'opt3'
|
|
104
|
+
}
|
|
105
|
+
]}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('renders all Checkboxes', async () => {
|
|
111
|
+
await Checkbox('Opt 1').exists();
|
|
112
|
+
await Checkbox('Opt 2').exists();
|
|
113
|
+
await Checkbox('Opt 3').exists();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('all Checkboxes have expected initial "checked" value', async () => {
|
|
117
|
+
await Checkbox('Opt 1').has({ checked: true });
|
|
118
|
+
await Checkbox('Opt 2').has({ checked: false });
|
|
119
|
+
await Checkbox('Opt 3').has({ checked: true });
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('clicking Opt 2', () => {
|
|
123
|
+
beforeEach(async () => {
|
|
124
|
+
await waitFor(async () => {
|
|
125
|
+
await Checkbox('Opt 2').click();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('all Checkboxes have expected "checked" value', async () => {
|
|
130
|
+
await Checkbox('Opt 1').has({ checked: true });
|
|
131
|
+
await Checkbox('Opt 2').has({ checked: true });
|
|
132
|
+
await Checkbox('Opt 3').has({ checked: true });
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('clicking Opt 1 and Opt 2', () => {
|
|
137
|
+
beforeEach(async () => {
|
|
138
|
+
await waitFor(async () => {
|
|
139
|
+
await Checkbox('Opt 1').click();
|
|
140
|
+
await Checkbox('Opt 2').click();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('all Checkboxes have expected "checked" value', async () => {
|
|
145
|
+
await Checkbox('Opt 1').has({ checked: false });
|
|
146
|
+
await Checkbox('Opt 2').has({ checked: true });
|
|
147
|
+
await Checkbox('Opt 3').has({ checked: true });
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe('clicking Opt 3', () => {
|
|
152
|
+
beforeEach(async () => {
|
|
153
|
+
await waitFor(async () => {
|
|
154
|
+
await Checkbox('Opt 3').click();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('all Checkboxes have expected "checked" value', async () => {
|
|
159
|
+
await Checkbox('Opt 1').has({ checked: true });
|
|
160
|
+
await Checkbox('Opt 2').has({ checked: false });
|
|
161
|
+
await Checkbox('Opt 3').has({ checked: false });
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './SearchKeyControl';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SettingPage
|
|
2
|
+
|
|
3
|
+
A container component that simplifies the process of displaying and editing a section of application settings. It leverages the `EditableSettingsList` component to handle the rendering and editing of individual settings within that section. `SettingPage` fetches the relevant settings data for a given `sectionName` using a custom hook and manages the submission of changes.
|
|
4
|
+
|
|
5
|
+
This component acts as a higher-level abstraction, taking care of data fetching and preparing the necessary props for `EditableSettingsList`. It utilizes the `SettingsContext` to access the settings API endpoint and the `useSettingSection` hook to retrieve and handle the settings for a specific section.
|
|
6
|
+
|
|
7
|
+
## Basic Usage
|
|
8
|
+
|
|
9
|
+
Import the component and provide the `sectionName` to identify the settings section you want to display and manage.
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
const GeneralSettingsPage = () => {
|
|
13
|
+
return (
|
|
14
|
+
<div>
|
|
15
|
+
<h2>General Application Settings</h2>
|
|
16
|
+
<SettingPage sectionName="general" />
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
In this example, `SettingPage` will fetch the settings associated with the "general" section and render them in an editable list using `EditableSettingsList`.
|
|
23
|
+
|
|
24
|
+
You can also customize the editing capabilities, internationalization keys, and labels.
|
|
25
|
+
|
|
26
|
+
```jsx
|
|
27
|
+
const AdvancedSettingsPage = () => {
|
|
28
|
+
return (
|
|
29
|
+
<div>
|
|
30
|
+
<h2>Advanced Configuration</h2>
|
|
31
|
+
<SettingPage
|
|
32
|
+
sectionName="advanced"
|
|
33
|
+
allowEdit={false} // Disable editing for this section
|
|
34
|
+
intlKey="advancedSettings"
|
|
35
|
+
intlNS="myApp"
|
|
36
|
+
labelOverrides={{
|
|
37
|
+
'timeoutDuration': 'Session Timeout (in seconds)'
|
|
38
|
+
}}
|
|
39
|
+
render={({ fields: { name }, index }) => (
|
|
40
|
+
<div key={index}>
|
|
41
|
+
{/* Custom rendering for each setting field */}
|
|
42
|
+
<label htmlFor={`${name}[${index}].value`}>{name}</label>
|
|
43
|
+
<input type="text" id={`${name}[${index}].value`} {...fields.field(`${name}[${index}]`, 'value')} />
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Note:**
|
|
53
|
+
* This component relies on the `SettingsContext` being available in the component tree to access the `settingEndpoint`.
|
|
54
|
+
* It also depends on the `useSettingSection` custom hook to handle data fetching and submission logic for the specified `sectionName`.
|
|
55
|
+
* The `render` prop allows for complete customization of how the individual settings are rendered within the `EditableSettingsList`.
|
|
56
|
+
|
|
57
|
+
## Props
|
|
58
|
+
|
|
59
|
+
| Name | Type | Description | default | required |
|
|
60
|
+
|------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------|
|
|
61
|
+
| `allowEdit` | `boolean` | A flag to globally enable or disable editing for all settings within this section. This prop is passed directly to the underlying `EditableSettingsList` component. | `true` | ✕ |
|
|
62
|
+
| `intlKey` | `string` | A base internationalization key to be used for generating labels within the `EditableSettingsList` and its child components. If provided, it's passed down to `EditableSettingsList`. | `undefined` | ✕ |
|
|
63
|
+
| `intlNS` | `string` | An internationalization namespace used for resolving labels within the `EditableSettingsList` and its child components. If provided, it's passed down to `EditableSettingsList`. | `undefined` | ✕ |
|
|
64
|
+
| `labelOverrides` | `object` | An object containing key-value pairs where the keys are setting identifiers (e.g., `setting.key`) and the values are custom labels to override the default labels generated by `EditableSettingsList`. This prop is passed directly to `EditableSettingsList`. | `{}` | ✕ |
|
|
65
|
+
| `sectionName` | `string` | The unique name of the settings section to be displayed and managed. This prop is crucial as it's used by the `useSettingSection` hook to fetch the relevant settings data from the API. | `undefined` | ✓ |
|
|
66
|
+
| `render` | `func` | A render prop that receives the `fields` object from `react-final-form-arrays` (within `EditableSettingsList`) and allows for complete custom rendering of each setting row. This prop is passed directly to `EditableSettingsList`. See the `EditableSettingsList` documentation for more details on the props passed to this render function and how to use it. | `undefined` | ✕ |
|
|
@@ -11,7 +11,8 @@ const SettingPage = ({
|
|
|
11
11
|
intlKey: passedIntlKey,
|
|
12
12
|
intlNS: passedIntlNS,
|
|
13
13
|
labelOverrides = {},
|
|
14
|
-
sectionName
|
|
14
|
+
sectionName,
|
|
15
|
+
render
|
|
15
16
|
}) => {
|
|
16
17
|
const { settingEndpoint } = useContext(SettingsContext);
|
|
17
18
|
|
|
@@ -29,6 +30,7 @@ const SettingPage = ({
|
|
|
29
30
|
labelOverrides={labelOverrides}
|
|
30
31
|
onSave={handleSubmit}
|
|
31
32
|
onSubmit={handleSubmit}
|
|
33
|
+
render={render}
|
|
32
34
|
settingSection={sectionName}
|
|
33
35
|
/>
|
|
34
36
|
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# SettingPagePane
|
|
2
|
+
|
|
3
|
+
A presentational component that wraps its children within a styled pane dedicated to a settings section. **SettingPagePane** is most commonly used to wrap a **SettingsPage** component, which handles the logic for fetching and managing settings data. However, it is not strictly required to wrap a **SettingsPage**—any valid React content can be used as children.
|
|
4
|
+
|
|
5
|
+
This component leverages the `Pane` component from `@folio/stripes/components` to provide a consistent layout and styling for different settings pages. Additionally, it integrates internationalization by using the `useKintIntl` hook along with the `toCamelCase` utility to generate a pane title based on the provided `sectionName`.
|
|
6
|
+
|
|
7
|
+
## Basic Usage
|
|
8
|
+
|
|
9
|
+
Wrap your settings-related content inside **SettingPagePane**. It is common to use this component as a wrapper for **SettingsPage**; however, you can also use it to contain any other content.
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
import SettingsPage from './SettingsPage';
|
|
13
|
+
|
|
14
|
+
const GeneralSettings = () => (
|
|
15
|
+
<SettingPagePane sectionName="general">
|
|
16
|
+
{/* In typical usage, SettingsPage is rendered inside SettingPagePane */}
|
|
17
|
+
<SettingsPage sectionName="general" />
|
|
18
|
+
</SettingPagePane>
|
|
19
|
+
);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
In this example, **SettingPagePane** creates a pane with an ID of `settings-general` and a title generated by converting `"general"` to camel case and resolving the corresponding internationalized message. If no message is found, it defaults to using `"general"`.
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
| Name | Type | Description | Default | Required |
|
|
27
|
+
|--------------|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|----------|
|
|
28
|
+
| `sectionName`| `string` | The unique name of the settings section. This prop is used to generate the pane’s identifier and to lookup the internationalized title for the pane header. | `undefined` | ✓ |
|
|
29
|
+
| `intlKey` | `string` | A base internationalization key used by the `useKintIntl` hook to find the correct localized message for the pane title. | `undefined` | ✕ |
|
|
30
|
+
| `intlNS` | `string` | An internationalization namespace for resolving labels within the pane title. | `undefined` | ✕ |
|
|
31
|
+
| `children` | `node` or `func` | The content to be rendered within the pane. Typically, this is a **SettingsPage** component, but it can be any valid React node. | `undefined` | ✕ |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
|
|
3
3
|
import { Pane } from '@folio/stripes/components';
|
|
4
|
-
import { toCamelCase } from '
|
|
5
|
-
import { useKintIntl } from '
|
|
4
|
+
import { toCamelCase } from '../../utils';
|
|
5
|
+
import { useKintIntl } from '../../hooks';
|
|
6
6
|
|
|
7
7
|
const SettingPagePane = ({
|
|
8
8
|
children,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './SettingPagePane';
|
package/src/lib/hooks/README.md
CHANGED
|
@@ -15,85 +15,14 @@ const data = useRefdata({
|
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
### Props
|
|
18
|
-
Name
|
|
19
|
-
|
|
20
|
-
endpoint
|
|
21
|
-
desc
|
|
22
|
-
queryParams
|
|
23
|
-
returnQueryObject | bool
|
|
24
|
-
options
|
|
18
|
+
| Name | Type | Description | default | required |
|
|
19
|
+
|-------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|----------|
|
|
20
|
+
| endpoint | string | The endpoint to fetch refdataValues from | | ✓ |
|
|
21
|
+
| desc | string | The refdataCategory (usually of the form `DomainClass.Field`) | | ✕ |
|
|
22
|
+
| queryParams | object | A set of queryParameters to hand to react-query's `useQuery` | | ✕ |
|
|
23
|
+
| returnQueryObject | bool | A switch to return the entirety of the queryObject from useQuery. If `false`, the data will be destructured, if `true` the return will be the full object returned by react-query's `useQuery` | false | ✕ |
|
|
24
|
+
| options | object | An object of the shape SASQ_MAP (See generateKiwtQuery) to pass to the generateKiwtQuery inside. Any passed desc "d" will be passed as a filter `DescKey.${d}`, with DescKey acting as FilterName, assuming `filterKeys: { DescKey: "desc" }` in options, so `desc==${d}` is passed directly to the backend. | `{filterKeys: {DescKey: "desc" }, stats: false, max: 100}` | ✕ |
|
|
25
25
|
|
|
26
|
-
## useMutateRefdataValue
|
|
27
|
-
A hook for mutations (Create/Delete/Edit) of refdataValues.
|
|
28
|
-
|
|
29
|
-
### Basic Usage
|
|
30
|
-
```javascript
|
|
31
|
-
import { useMutateRefdataValue } from '@k-int/stripes-kint-components'
|
|
32
|
-
...
|
|
33
|
-
const { delete } = useMutateRefdataValue({
|
|
34
|
-
endpoint: 'oa/refdata',
|
|
35
|
-
id: '1234-abcd-5678',
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Props
|
|
40
|
-
Name | Type | Description | default | required
|
|
41
|
-
--- | --- | --- | --- | ---
|
|
42
|
-
afterQueryCalls | object | An object of the form `{delete: func1, put: func2}` where `func1`/`func2` are functions to be called after the `delete`/`put`. This is for ease of use, you can alternatively manually use a `.then()` on the functions returned from this hook. | | ✓ |
|
|
43
|
-
catchQueryCalls | object | An object of the form `{delete: func1, put: func2}` where `func1`/`func2` are functions to be called with a HTTPError object when the `delete`/`put` calls fail. This is for ease of use, you can alternatively manually use a `.catch()` on the functions returned from this hook. | | ✕ |
|
|
44
|
-
endpoint | string | The refdata endpoint | | ✕ |
|
|
45
|
-
id | string | The id of the refdata whose values are to be mutated | | ✕ |
|
|
46
|
-
queryParams | object | An object of the form `{delete: obj1, put: obj2}`, where `obj1`/`obj2` are set of queryParameters to hand to react-query's `useMutation` for the delete/put operations respectively | | ✕ |
|
|
47
|
-
returnQueryObject | object | An object of the form `{delete: bool1, put: bool2}` containing switches to return the entirety of the queryObject from useMutation for `delete` and `put` respectively. If `false`, the mutateAsync function will be destructured, if `true` the return will be the full object returned by react-query's `useMutation` | {put: false, delete: false} | ✕ |
|
|
48
|
-
|
|
49
|
-
### Example
|
|
50
|
-
```javascript
|
|
51
|
-
...
|
|
52
|
-
const { delete, put } = useMutateRefdataValue({
|
|
53
|
-
afterQueryCalls: {
|
|
54
|
-
delete: json => setContentData(json?.values ?? []),
|
|
55
|
-
put: json => setContentData(json?.values ?? [])
|
|
56
|
-
},
|
|
57
|
-
endpoint: 'oa/refdata',
|
|
58
|
-
id: refdata?.id,
|
|
59
|
-
queryParams: {
|
|
60
|
-
delete: {
|
|
61
|
-
enabled: !!refdata
|
|
62
|
-
},
|
|
63
|
-
put: {
|
|
64
|
-
enabled: !!refdata
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
...
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
This block will destructure two `mutateAsync` functions, `delete` and `put`. After a call to either of them the `json` returned will be used in a function call `setContentData`.
|
|
72
|
-
|
|
73
|
-
The calls will only be enabled if `refdata` is truthy.
|
|
74
|
-
|
|
75
|
-
`put` will return a function `put(data)` and will make a `put` call to add the `data` to the values of the given refdata id. In practice this means calling `put` as follows:
|
|
76
|
-
```javascript
|
|
77
|
-
put({
|
|
78
|
-
value: 'testValue'
|
|
79
|
-
label: 'testLabel'
|
|
80
|
-
})
|
|
81
|
-
```
|
|
82
|
-
for a new refdataValue, or
|
|
83
|
-
```javascript
|
|
84
|
-
put({
|
|
85
|
-
id: <id of the refdataValue to edit>
|
|
86
|
-
value: 'testValue2'
|
|
87
|
-
label: 'testLabel 2'
|
|
88
|
-
})
|
|
89
|
-
```
|
|
90
|
-
to edit an existing value.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
`delete` will return a function `delete(data)` and will make a `put` call to glue `_delete: true` to the given value. In practice this means calling `delete` as follows:
|
|
94
|
-
```javascript
|
|
95
|
-
delete(<ID of refdata value to remove>)
|
|
96
|
-
```
|
|
97
26
|
|
|
98
27
|
## useActiveElement
|
|
99
28
|
A hook which returns the currently focused element in the document, `active`, as well as a function `hasParent`.
|
|
@@ -145,9 +74,9 @@ return (
|
|
|
145
74
|
```
|
|
146
75
|
|
|
147
76
|
### Props
|
|
148
|
-
Name
|
|
149
|
-
|
|
150
|
-
helpers | object | An object of the form `{helperKey1: Component1, helperKey2: Component1}` where `Component1`/`Component1` are components to be rendered when the url contains query `helper=helperKey1` or `helper=helperKey2` respectively |
|
|
77
|
+
| Name | Type | Description | default | required |
|
|
78
|
+
|---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|----------|
|
|
79
|
+
| helpers | object | An object of the form `{helperKey1: Component1, helperKey2: Component1}` where `Component1`/`Component1` are components to be rendered when the url contains query `helper=helperKey1` or `helper=helperKey2` respectively | | ✓ |
|
|
151
80
|
|
|
152
81
|
## useKiwtSASQuery
|
|
153
82
|
A hook which sets up a basic queryGetter and querySetter for use with SASQ, as well as setting up the query object itself. Will often be used with the `generateKiwtQuery` function from `utils`.
|
|
@@ -285,34 +214,10 @@ export default Test
|
|
|
285
214
|
```
|
|
286
215
|
|
|
287
216
|
### Props
|
|
288
|
-
Name
|
|
289
|
-
|
|
290
|
-
name
|
|
291
|
-
submitWholeDeletedObject | bool
|
|
292
|
-
|
|
293
|
-
## useAppSettings
|
|
294
|
-
A hook for fetching AppSetting values
|
|
295
|
-
### Basic usage
|
|
296
|
-
```javascript
|
|
297
|
-
import { useAppSettings } from '@k-int/stripes-kint-components'
|
|
298
|
-
...
|
|
299
|
-
const data = useAppSettings({
|
|
300
|
-
endpoint: 'oa/settings/appSettings'
|
|
301
|
-
});
|
|
302
|
-
...
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
This will return a list of AppSettings. If a `keyName` is passed, this will instead return a single AppSetting object.
|
|
306
|
-
|
|
307
|
-
### Props
|
|
308
|
-
Name | Type | Description | default | required
|
|
309
|
-
--- | --- | --- | --- | ---
|
|
310
|
-
endpoint | string | The endpoint to fetch AppSettings from | | ✓ |
|
|
311
|
-
sectionName | string | A string representing a section of AppSettings to filter on | | ✕ |
|
|
312
|
-
keyName | string | A string representing an individual key of an AppSettings to filter on. The presence of this prop will change the output shape from Array to Object. It is not strictly necessary to use `keyName` in conjunction with `sectionName`, but keys are not guaranteed to be unique between sections. In addition it may marginally improve performance to use both, even if a key is unique, so it is recommended. | | ✕ |
|
|
313
|
-
queryParams | object | A set of queryParameters to hand to react-query's `useQuery` | | ✕ |
|
|
314
|
-
returnQueryObject | bool | A switch to return the entirety of the queryObject from useQuery. If `false`, the data will be destructured, if `true` the return will be the full object returned by react-query's `useQuery` | false | ✕ |
|
|
315
|
-
options | object | An object of the shape SASQ_MAP (See generateKiwtQuery) to pass to the generateKiwtQuery inside. The default | `{perPage: 100, stats: false, filters: [{path: 'section', value: sectionName }, {path: 'key', value: keyName }]}` | ✕ |
|
|
217
|
+
| Name | Type | Description | default | required |
|
|
218
|
+
|--------------------------|--------|---------------------------------------------------------------------------------------------------------|---------|----------|
|
|
219
|
+
| name | String | The name of the fieldArray, used to hook into the final form state for that field. | | ✓ |
|
|
220
|
+
| submitWholeDeletedObject | bool | a boolean flag to ensure that a deleted object is sent whole to the backend, rather than just as an id. | false | ✕ |
|
|
316
221
|
|
|
317
222
|
## useMutateGeneric
|
|
318
223
|
|
|
@@ -336,15 +241,15 @@ updateObject({ id: 456, name: 'Updated Object' }) // Updates the object with id
|
|
|
336
241
|
|
|
337
242
|
### Props
|
|
338
243
|
|
|
339
|
-
| Name
|
|
340
|
-
|
|
341
|
-
| afterQueryCalls
|
|
342
|
-
| catchQueryCalls
|
|
343
|
-
| endpoint
|
|
344
|
-
| endpointMutators
|
|
345
|
-
| payloadMutators
|
|
346
|
-
| promiseReturns
|
|
347
|
-
| queryKey
|
|
348
|
-
| queryKeyMutators
|
|
349
|
-
| queryParams
|
|
350
|
-
| returnQueryObject | object | An object of the form `{ delete: bool1, post: bool2, put: bool3 }` containing switches to return the entire query object from `useMutation` for each operation. If `false` (the default), the `mutateAsync` function will be returned; if `true`, the full object (including `mutate`, `isLoading`, `error`, etc.) will be returned.
|
|
244
|
+
| Name | Type | Description | Default | Required |
|
|
245
|
+
|-------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|----------|
|
|
246
|
+
| afterQueryCalls | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(responseData)`, `func2(responseData)`, and `func3(responseData)` are functions to be called *after* the corresponding mutation is successful. `responseData` is the data returned by the API call. | `{}` | ✕ |
|
|
247
|
+
| catchQueryCalls | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(error)`, `func2(error)`, and `func3(error)` are functions to be called *if* the corresponding mutation fails. `error` is the HTTPError object. | `{}` | ✕ |
|
|
248
|
+
| endpoint | string | The base endpoint for the API calls. | | ✓ |
|
|
249
|
+
| endpointMutators | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(id)`, `func2()`, and `func3(data)` are functions that modify the endpoint for each operation. Defaults to appending the id for `delete` and `put`, and using the base endpoint for `post`. | `{ delete: (id) => "${endpoint}/${id}", post: () => endpoint, put: (data) => "${endpoint}/${data.id}" }` | ✕ |
|
|
250
|
+
| payloadMutators | object | An object of the form `{ post: func1, put: func2 }` where `func1(data)` and `func2(data)` are functions that modify the payload for the `post` and `put` operations. Defaults to wrapping the data in a `json` object. | `{ post: (data) => ({ json: data }), put: (data) => ({ json: data }) }` | ✕ |
|
|
251
|
+
| promiseReturns | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(id, ky)`, `func2(data, ky)`, and `func3(data, ky)` are functions that define the promise return for each operation. Allows full control over the `ky` call. `id` is the id for delete, `data` is the data being sent for post/put, and `ky` is the `ky` instance. | `{ delete: (id, ky) => ky.delete(...).json(), post: (data, ky) => ky.post(...).json(), put: (data, ky) => ky.put(...).json() }` | ✕ |
|
|
252
|
+
| queryKey | array | The query key to be used with `react-query`. **Must be an array.** | `[]` | ✓ |
|
|
253
|
+
| queryKeyMutators | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1()`, `func2()`, and `func3()` are functions that return the query key for each mutation. | `{ delete: () => [...queryKey, 'delete'], post: () => [...queryKey, 'create'], put: () => [...queryKey, 'edit'] }` | ✕ |
|
|
254
|
+
| queryParams | object | An object of the form `{ delete: obj1, post: obj2, put: obj3 }` where `obj1`, `obj2`, and `obj3` are the query parameters for each operation. | `{}` | ✕ |
|
|
255
|
+
| returnQueryObject | object | An object of the form `{ delete: bool1, post: bool2, put: bool3 }` containing switches to return the entire query object from `useMutation` for each operation. If `false` (the default), the `mutateAsync` function will be returned; if `true`, the full object (including `mutate`, `isLoading`, `error`, etc.) will be returned. | `{ delete: false, post: false, put: false }` | ✕ |
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import refdata from '../../../../test/jest/refdata';
|
|
2
2
|
import customProperties from '../../../../test/jest/customProperties';
|
|
3
3
|
|
|
4
|
-
import useKintIntl from '../useKintIntl';
|
|
4
|
+
import useKintIntl from '../intlHooks/useKintIntl';
|
|
5
5
|
|
|
6
6
|
/* EXAMPLE Grab actual hooks for anything not mocked here */
|
|
7
7
|
const hooks = jest.requireActual('../index');
|
|
8
8
|
|
|
9
9
|
// We have to do this up here too so that our passed useKintIntl
|
|
10
10
|
// ALSO has a mocked useIntlKeyStore... I think anyway
|
|
11
|
-
jest.mock('../useIntlKeyStore', () => () => () => 'ui-test-implementor');
|
|
11
|
+
jest.mock('../intlHooks/useIntlKeyStore', () => () => () => 'ui-test-implementor');
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
14
14
|
...hooks,
|
package/src/lib/hooks/index.js
CHANGED
|
@@ -8,9 +8,6 @@ export { default as useQIndex } from './useQIndex';
|
|
|
8
8
|
export { default as useKiwtFieldArray } from './useKiwtFieldArray';
|
|
9
9
|
export { default as useCustomProperties } from './useCustomProperties';
|
|
10
10
|
export { default as useInvalidateRefdata } from './useInvalidateRefdata';
|
|
11
|
-
export { default as useKintIntl } from './useKintIntl';
|
|
12
|
-
export { default as useIntlKeyStore } from './useIntlKeyStore';
|
|
13
|
-
export { default as useIntlKey } from './useIntlKey';
|
|
14
11
|
export { default as useSASQQueryMeta } from './useSASQQueryMeta';
|
|
15
12
|
export { default as useModConfigEntries } from './useModConfigEntries';
|
|
16
13
|
export { default as useActionListRef } from './useActionListRef';
|
|
@@ -22,3 +19,5 @@ export { default as useMutateCustomProperties } from './useMutateCustomPropertie
|
|
|
22
19
|
export { default as useMutateModConfigEntry } from './useMutateModConfigEntry';
|
|
23
20
|
|
|
24
21
|
export { default as usePrevNextPagination } from './usePrevNextPagination';
|
|
22
|
+
|
|
23
|
+
export * from './intlHooks';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Internationalization (intl) Hooks
|
|
2
|
+
|
|
3
|
+
This suite of hooks provides a standardized way to handle internationalization across components while respecting module boundaries. The system allows:
|
|
4
|
+
|
|
5
|
+
1. **Root Module Configuration** - Set default intl keys/namespaces at application root
|
|
6
|
+
2. **Component-Level Overrides** - Customize translations per-component via `intlKey`/`intlNS` props
|
|
7
|
+
3. **Automatic Key Resolution** - Components automatically find translations without hardcoded paths
|
|
8
|
+
|
|
9
|
+
## Key Components
|
|
10
|
+
|
|
11
|
+
1. **[useIntlKeyStore](./useIntlKeyStore/README.md)** - Global store for managing intl keys
|
|
12
|
+
2. **[useIntlKey](./useIntlKey/README.md)** - Hook for resolving intl keys
|
|
13
|
+
3. **[useKintIntl](./useKintIntl/README.md)** - Enhanced intl formatting hook
|
|
14
|
+
|
|
15
|
+
## Core Principles
|
|
16
|
+
|
|
17
|
+
- **No Library Translations** - Parent modules provide all translations
|
|
18
|
+
- **Explicit Key Management** - Required key configuration prevents silent failures
|
|
19
|
+
- **Namespace Isolation** - Prevents key collisions between modules
|
|
20
|
+
- **Override Support** - Components can bypass default keys when needed
|
|
21
|
+
|
|
22
|
+
## Implementation Benefits
|
|
23
|
+
|
|
24
|
+
- ✅ Avoids duplicated translation efforts
|
|
25
|
+
- ✅ Maintains Lokalise compatibility
|
|
26
|
+
- ✅ Enables component reuse across modules
|
|
27
|
+
- ✅ Provides clear error messaging for missing config
|
|
28
|
+
- ✅ Supports both simple and complex i18n scenarios
|
|
29
|
+
|
|
30
|
+
## Developer note
|
|
31
|
+
This clearly isn't an ideal solution, but it is the best one we could come up with at the time. Each module implementing kint-components can either set up a global key store telling kint-components where to look for their intl keys in general, or set this on a component by component case via the `intlKey` and `intlNS` props used throughout kint-components
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# useIntlKey
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Resolves internationalization keys with fallback logic.
|
|
5
|
+
|
|
6
|
+
## Resolution Order
|
|
7
|
+
1. Directly passed `intlKey` prop
|
|
8
|
+
2. Namespace lookup via `intlNS` prop
|
|
9
|
+
3. Default namespace from `useNamespace`
|
|
10
|
+
|
|
11
|
+
## Error Handling
|
|
12
|
+
Throws error if:
|
|
13
|
+
- No key passed directly
|
|
14
|
+
- No key found in registry
|
|
15
|
+
- Namespace not registered
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
```jsx
|
|
19
|
+
const Component = ({ intlKey, intlNS }) => {
|
|
20
|
+
const resolvedKey = useIntlKey(intlKey, intlNS);
|
|
21
|
+
// Uses resolved key for translations
|
|
22
|
+
};
|
|
23
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './useIntlKey';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# useIntlKeyStore
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Global state management for internationalization keys using Zustand.
|
|
5
|
+
|
|
6
|
+
## Key Features
|
|
7
|
+
- Namespace-key pair storage
|
|
8
|
+
- Automatic namespace resolution
|
|
9
|
+
- Hook-safe operations
|
|
10
|
+
|
|
11
|
+
## Initial Setup
|
|
12
|
+
```jsx
|
|
13
|
+
// App root component
|
|
14
|
+
import useIntlKeyStore from './useIntlKeyStore';
|
|
15
|
+
|
|
16
|
+
const App = () => {
|
|
17
|
+
const { addKey } = useIntlKeyStore();
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
addKey('moduleBaseKey', 'myModuleNamespace');
|
|
21
|
+
}, [addKey]);
|
|
22
|
+
|
|
23
|
+
return (...);
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Store Methods
|
|
28
|
+
| Method | Parameters | Description |
|
|
29
|
+
|--------------|---------------------|--------------------------------------|
|
|
30
|
+
| `addKey` | `(key, namespace)` | Registers namespace-key pair |
|
|
31
|
+
| `removeKey` | `(namespace)` | Removes namespace registration |
|
|
32
|
+
| `getKey` | `(namespace)` | Retrieves key for namespace |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './useIntlKeyStore';
|