@evoke-platform/ui-components 1.11.0-dev.0 → 1.11.0-dev.2

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.
@@ -118,7 +118,7 @@ const Select = (props) => {
118
118
  setValue(e.target.value);
119
119
  setInputValue(e.target.value);
120
120
  onChange && onChange(property.id, e.target.value, property);
121
- }, size: 'small', onFocus: () => setIsOtherFocused(true), onBlur: (e) => {
121
+ }, size: 'small', onFocus: () => setIsOtherFocused(true), onBlur: async (e) => {
122
122
  // If another radio button is focused, change the value to that radio button's value.
123
123
  const targetElement = e.nativeEvent.relatedTarget;
124
124
  if (targetElement?.defaultValue && targetElement.name === `radioGroup-${id}`) {
@@ -128,6 +128,13 @@ const Select = (props) => {
128
128
  onChange && onChange(property.id, e.target.value, property);
129
129
  }
130
130
  setIsOtherFocused(false);
131
+ // Trigger autosave when the custom value field loses focus
132
+ try {
133
+ await onAutosave?.(id);
134
+ }
135
+ catch (error) {
136
+ console.error('Autosave failed:', error);
137
+ }
131
138
  } })))))),
132
139
  onChange && !readOnly && value && (React.createElement(Box, { sx: {
133
140
  ':hover': { cursor: 'pointer' },
@@ -2,6 +2,7 @@ import { render, screen } from '@testing-library/react';
2
2
  import { userEvent } from '@testing-library/user-event';
3
3
  import React from 'react';
4
4
  import { describe, expect, it, vi } from 'vitest';
5
+ import { FormContext } from '../../FormV2/components/FormContext';
5
6
  import Select from './Select';
6
7
  describe('Single select', () => {
7
8
  // Right now an object property is required for this to function, but eventually this should go
@@ -61,6 +62,27 @@ describe('Single select', () => {
61
62
  await user.click(customOption);
62
63
  expect(onChangeMock).toBeCalledWith('selectOptions', expect.objectContaining({ label: 'Add "custom option"', value: 'custom option' }), choiceProperty);
63
64
  });
65
+ it('triggers autosave when entering a custom value in dropdown combobox', async () => {
66
+ const user = userEvent.setup();
67
+ const onChangeMock = vi.fn((name, value, property) => { });
68
+ const onAutosaveMock = vi.fn();
69
+ const options = ['option 1', 'option 2', 'option 3'];
70
+ render(React.createElement(FormContext.Provider, { value: {
71
+ fetchedOptions: {},
72
+ setFetchedOptions: () => { },
73
+ onAutosave: onAutosaveMock,
74
+ width: 1200,
75
+ } },
76
+ React.createElement(Select, { id: "testSelect", property: choiceProperty, selectOptions: options, onChange: onChangeMock, isCombobox: true })));
77
+ const input = screen.getByRole('combobox');
78
+ await user.click(input);
79
+ await user.type(input, 'custom option');
80
+ // Select the custom option from dropdown
81
+ const customOption = await screen.findByRole('option', { name: 'Add "custom option"' });
82
+ await user.click(customOption);
83
+ // Verify autosave was triggered
84
+ expect(onAutosaveMock).toHaveBeenCalledWith('testSelect');
85
+ });
64
86
  });
65
87
  describe('Multi select', () => {
66
88
  // Right now an object property is required for this to function, but eventually this should go
@@ -122,6 +144,34 @@ describe('Multi select', () => {
122
144
  expect(onChangeMock).toBeCalledTimes(2);
123
145
  expect(onChangeMock).lastCalledWith('multiSelect', ['custom option 1', 'option 1'], multiChoiceProperty);
124
146
  });
147
+ it('triggers autosave when entering custom values in multiselect combobox', async () => {
148
+ const user = userEvent.setup();
149
+ const onChangeMock = vi.fn((name, value, property) => { });
150
+ const onAutosaveMock = vi.fn();
151
+ const options = ['option 1', 'option 2', 'option 3'];
152
+ render(React.createElement(FormContext.Provider, { value: {
153
+ fetchedOptions: {},
154
+ setFetchedOptions: () => { },
155
+ onAutosave: onAutosaveMock,
156
+ width: 1200,
157
+ } },
158
+ React.createElement(Select, { id: "multiSelect", property: multiChoiceProperty, selectOptions: options, onChange: onChangeMock, isCombobox: true })));
159
+ const input = screen.getByRole('combobox');
160
+ await user.click(input);
161
+ await user.type(input, 'custom option 1');
162
+ // Select the first custom option
163
+ const customOption1 = await screen.findByRole('option', { name: 'Add "custom option 1"' });
164
+ await user.click(customOption1);
165
+ // Verify autosave was triggered for first custom value
166
+ expect(onAutosaveMock).toHaveBeenCalledWith('multiSelect');
167
+ onAutosaveMock.mockClear();
168
+ // Add a second custom option
169
+ await user.type(input, 'custom option 2');
170
+ const customOption2 = await screen.findByRole('option', { name: 'Add "custom option 2"' });
171
+ await user.click(customOption2);
172
+ // Verify autosave was triggered for second custom value
173
+ expect(onAutosaveMock).toHaveBeenCalledWith('multiSelect');
174
+ });
125
175
  });
126
176
  describe('Radio Single select', () => {
127
177
  const choiceProperty = {
@@ -166,4 +216,55 @@ describe('Radio Single select', () => {
166
216
  await user.type(otherTextField, 'custom option');
167
217
  expect(onChangeMock).toBeCalledWith('selectOptions', expect.stringContaining('custom option'), choiceProperty);
168
218
  });
219
+ it('triggers autosave when a custom value is entered', async () => {
220
+ const user = userEvent.setup();
221
+ const onChangeMock = vi.fn((name, value, property) => { });
222
+ const onAutosaveMock = vi.fn();
223
+ const options = ['option 1', 'option 2', 'option 3'];
224
+ render(React.createElement(FormContext.Provider, { value: {
225
+ fetchedOptions: {},
226
+ setFetchedOptions: () => { },
227
+ onAutosave: onAutosaveMock,
228
+ width: 1200,
229
+ } },
230
+ React.createElement(Select, { id: "testSelect", property: choiceProperty, selectOptions: options, displayOption: 'radioButton', sortBy: 'ASC', onChange: onChangeMock, isCombobox: true })));
231
+ // Select the "Other" radio option
232
+ await user.click(screen.getByRole('radio', { name: 'Other' }));
233
+ const otherTextField = await screen.findByRole('textbox', { name: 'Other' });
234
+ // Type a custom value
235
+ await user.type(otherTextField, 'custom option');
236
+ // Blur the text field by clicking elsewhere
237
+ await user.tab();
238
+ // Verify autosave was triggered
239
+ expect(onAutosaveMock).toHaveBeenCalledWith('testSelect');
240
+ });
241
+ it('triggers autosave when clearing the custom value', async () => {
242
+ const user = userEvent.setup();
243
+ const onChangeMock = vi.fn((name, value, property) => { });
244
+ const onAutosaveMock = vi.fn();
245
+ const options = ['option 1', 'option 2', 'option 3'];
246
+ render(React.createElement(FormContext.Provider, { value: {
247
+ fetchedOptions: {},
248
+ setFetchedOptions: () => { },
249
+ onAutosave: onAutosaveMock,
250
+ width: 1200,
251
+ } },
252
+ React.createElement(Select, { id: "testSelect", property: choiceProperty, selectOptions: options, displayOption: 'radioButton', sortBy: 'ASC', onChange: onChangeMock, isCombobox: true })));
253
+ // Select the "Other" radio option and enter a custom value
254
+ await user.click(await screen.findByRole('radio', { name: 'Other' }));
255
+ const otherTextField = await screen.findByRole('textbox', { name: 'Other' });
256
+ await user.type(otherTextField, 'custom option');
257
+ // Blur to set the value and trigger the first autosave
258
+ await user.tab();
259
+ // Clear the mock to isolate the clear action
260
+ onAutosaveMock.mockClear();
261
+ onChangeMock.mockClear();
262
+ // Click the clear button (now visible since value is set)
263
+ const clearButton = await screen.findByRole('button', { name: 'Clear' });
264
+ await user.click(clearButton);
265
+ // Verify onChange was called with empty value
266
+ expect(onChangeMock).toHaveBeenCalledWith('selectOptions', '');
267
+ // Verify autosave was triggered after clearing
268
+ expect(onAutosaveMock).toHaveBeenCalledWith('testSelect');
269
+ });
169
270
  });
@@ -11,7 +11,7 @@ import { getDefaultPages, getPrefixedUrl, transformToWhere } from '../../utils';
11
11
  import RelatedObjectInstance from './RelatedObjectInstance';
12
12
  const ObjectPropertyInput = (props) => {
13
13
  const { id, fieldDefinition, readOnly, error, mode, displayOption, filter, defaultValueCriteria, sortBy, orderBy, isModal, initialValue, viewLayout, hasDescription, createActionId, formId, relatedObjectId, } = props;
14
- const { fetchedOptions, setFetchedOptions, parameters, fieldHeight, handleChange: handleChangeObjectField, onAutosave: onAutosave, instance, } = useFormContext();
14
+ const { fetchedOptions, setFetchedOptions, fieldHeight, handleChange: handleChangeObjectField, onAutosave: onAutosave, instance, } = useFormContext();
15
15
  const { defaultPages, findDefaultPageSlugFor } = useApp();
16
16
  const [selectedInstance, setSelectedInstance] = useState(initialValue || undefined);
17
17
  const [openCreateDialog, setOpenCreateDialog] = useState(false);
@@ -205,8 +205,8 @@ const ObjectPropertyInput = (props) => {
205
205
  }, [relatedObjectId, fetchedOptions, id]);
206
206
  useEffect(() => {
207
207
  (async () => {
208
- if (parameters && fetchedOptions[`${id}NavigationSlug`] === undefined) {
209
- const pages = await getDefaultPages(parameters, defaultPages, findDefaultPageSlugFor);
208
+ if (fetchedOptions[`${id}NavigationSlug`] === undefined) {
209
+ const pages = await getDefaultPages([{ ...fieldDefinition, objectId: relatedObjectId }], defaultPages, findDefaultPageSlugFor);
210
210
  if (relatedObjectId && pages[relatedObjectId]) {
211
211
  setNavigationSlug(pages[relatedObjectId]);
212
212
  setFetchedOptions({
@@ -221,7 +221,7 @@ const ObjectPropertyInput = (props) => {
221
221
  }
222
222
  }
223
223
  })();
224
- }, [parameters, defaultPages, findDefaultPageSlugFor, relatedObjectId, fetchedOptions]);
224
+ }, [id, fieldDefinition, defaultPages, findDefaultPageSlugFor, relatedObjectId, fetchedOptions]);
225
225
  const handleClose = () => {
226
226
  setOpenCreateDialog(false);
227
227
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evoke-platform/ui-components",
3
- "version": "1.11.0-dev.0",
3
+ "version": "1.11.0-dev.2",
4
4
  "description": "",
5
5
  "main": "dist/published/index.js",
6
6
  "module": "dist/published/index.js",