Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(blade): Trigger native select events in dropdown/ file upload / Date picker [FC-3151] #2408

Merged
merged 30 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
03cb1bb
chore: trigger native events
tewarig Nov 6, 2024
48182f7
chore: trigger native events
tewarig Nov 6, 2024
0c355c1
fix: fireNativeEvents in case of dropdown
tewarig Nov 7, 2024
90d7063
chore: remove extra code
tewarig Nov 7, 2024
7f537a3
chore: change value of fireNative events to unknown
tewarig Nov 7, 2024
d75fa17
chore: remove fireNativeEvent from autocompelte
tewarig Nov 7, 2024
5d16744
chore: remove add fireNative event on remove , dissmiss
tewarig Nov 7, 2024
45b43f9
chore: remove logs
tewarig Nov 7, 2024
b683440
chore: code clean up
tewarig Nov 7, 2024
f66ef5f
chore: minor change
tewarig Nov 7, 2024
6440afd
chore: minor changes
tewarig Nov 7, 2024
497aff1
chore: fix type
tewarig Nov 7, 2024
bf6083f
chore: fire native event is not supported on react-native
tewarig Nov 8, 2024
4a5abdc
chore: change fire native event
tewarig Nov 8, 2024
2a8975f
chore: review change useFireNativeEvent
tewarig Nov 10, 2024
c4887f6
feat: added fireNativeEvent test
tewarig Nov 11, 2024
9295b8d
chore: test for fireNativeEvent react native
tewarig Nov 11, 2024
92235e5
Merge branch 'master' of https://github.com/razorpay/blade into fix/t…
tewarig Nov 11, 2024
7a6cfa9
chore: update fireNativeEvent error
tewarig Nov 11, 2024
f023d4c
chore: add tests in AutoComplete
tewarig Nov 11, 2024
42b8c3d
feat: add test for fire naitve event in DatePicker
tewarig Nov 11, 2024
5e517b3
feat: added test case for FileUpload
tewarig Nov 11, 2024
d139e26
chore: sync with main
tewarig Nov 14, 2024
500e30f
fix: failing build
tewarig Nov 14, 2024
2e3b148
chore: update snap
tewarig Nov 14, 2024
277c1b9
chore: add fixes to fireNativeEvent
tewarig Nov 14, 2024
a7657a4
Merge branch 'master' of https://github.com/razorpay/blade into fix/t…
tewarig Nov 15, 2024
d6947b0
chore: change throwBladeError to logger
tewarig Nov 15, 2024
f0d49f5
chore: fix errors
tewarig Nov 15, 2024
82104ef
chore: increase timeout
tewarig Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type { StyledPropsBlade } from '~components/Box/styledProps';
import { getStyledProps } from '~components/Box/styledProps';
import { metaAttribute, MetaConstants } from '~utils/metaAttribute';
import { componentZIndices } from '~utils/componentZIndices';
import { fireNativeEvent } from '~utils/fireNativeEvent';

const DatePicker = <Type extends DateSelectionType = 'single'>({
selectionType,
Expand Down Expand Up @@ -71,6 +72,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
const isSingle = _selectionType === 'single';
const [_, forceRerender] = React.useReducer((x: number) => x + 1, 0);
const [selectedPreset, setSelectedPreset] = React.useState<DatesRangeValue | null>(null);
const referenceRef = React.useRef<HTMLButtonElement>(null);

const [_picker, setPicker] = useControllableState<PickerType>({
defaultValue: defaultPicker,
Expand All @@ -97,6 +99,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
defaultValue,
onChange: (date) => {
onChange?.(date as never);
fireNativeEvent(referenceRef, ['input']);
if (isSingle) return;
// sync selected preset with value
setSelectedPreset(date as DatesRangeValue);
Expand Down Expand Up @@ -124,6 +127,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
const handleApply = (): void => {
if (isSingle) {
onChange?.(controlledValue);
fireNativeEvent(referenceRef, ['change']);
setOldValue(controlledValue);
onApply?.(controlledValue);
close();
Expand All @@ -132,6 +136,7 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({
// only apply if both dates are selected
if (hasBothDatesSelected) {
onChange?.(controlledValue);
fireNativeEvent(referenceRef, ['change']);
setOldValue(controlledValue);
onApply?.(controlledValue);
close();
Expand All @@ -140,14 +145,14 @@ const DatePicker = <Type extends DateSelectionType = 'single'>({

const handleCancel = (): void => {
setControlledValue(oldValue);
fireNativeEvent(referenceRef, ['change']);
setPickedDate(null);
close();
};

const isMobile = useIsMobile();
const defaultInitialFocusRef = React.useRef<HTMLButtonElement>(null);
const titleId = useId('datepicker-title');
const referenceRef = React.useRef<HTMLButtonElement>(null);
const {
context,
refs,
Expand Down
2 changes: 2 additions & 0 deletions packages/blade/src/components/Dropdown/useDropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { dropdownComponentIds } from './dropdownComponentIds';
import type { FormInputHandleOnKeyDownEvent } from '~components/Form/FormTypes';
import { isReactNative } from '~utils';
import type { ContainerElementType } from '~utils/types';
import { fireNativeEvent } from '~utils/fireNativeEvent';

// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = (): void => {};
Expand Down Expand Up @@ -355,6 +356,7 @@ const useDropdown = (): UseDropdownReturnValue => {

const optionValues = options.map((option) => option.value);
ensureScrollVisiblity(updatedIndex, rest.actionListItemRef.current, optionValues);
fireNativeEvent(rest.actionListItemRef as React.RefObject<HTMLElement>, ['change', 'input']);
};

/**
Expand Down
5 changes: 5 additions & 0 deletions packages/blade/src/components/FileUpload/FileUpload.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { makeAccessible } from '~utils/makeAccessible';
import { formHintLeftLabelMarginLeft } from '~components/Input/BaseInput/baseInputTokens';
import { useMergeRefs } from '~utils/useMergeRefs';
import { useControllableState } from '~utils/useControllable';
import { fireNativeEvent } from '~utils/fireNativeEvent';

const _FileUpload: React.ForwardRefRenderFunction<BladeElementRef, FileUploadProps> = (
{
Expand Down Expand Up @@ -158,6 +159,7 @@ const _FileUpload: React.ForwardRefRenderFunction<BladeElementRef, FileUploadPro
if (!hasValidationErrors) {
handleFilesChange(droppedFiles);
onDrop?.({ name, fileList: allFiles });
fireNativeEvent(inputRef, ['change', 'input']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the normal DOM inputs if we actually fire both of these or not. I think they do but still confirm once.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checked for <input type="file" /> they do fire both change and input .

}
};

Expand Down Expand Up @@ -307,6 +309,7 @@ const _FileUpload: React.ForwardRefRenderFunction<BladeElementRef, FileUploadPro
const newFiles = selectedFiles.filter(({ id }) => id !== selectedFiles[0].id);
setSelectedFiles(() => newFiles);
onRemove?.({ file: selectedFiles[0] });
fireNativeEvent(inputRef, ['change', 'input']);
}}
onReupload={() => {
const newFiles = selectedFiles.filter(({ id }) => id !== selectedFiles[0].id);
Expand Down Expand Up @@ -368,6 +371,7 @@ const _FileUpload: React.ForwardRefRenderFunction<BladeElementRef, FileUploadPro
const newFiles = selectedFiles.filter(({ id }) => id !== file.id);
setSelectedFiles(() => newFiles);
onRemove?.({ file });
fireNativeEvent(inputRef, ['change', 'input']);
}}
onReupload={() => {
const newFiles = selectedFiles.filter(({ id }) => id !== file.id);
Expand All @@ -386,6 +390,7 @@ const _FileUpload: React.ForwardRefRenderFunction<BladeElementRef, FileUploadPro
const newFiles = selectedFiles.filter(({ id }) => id !== file.id);
setSelectedFiles(() => newFiles);
onDismiss?.({ file });
fireNativeEvent(inputRef, ['change', 'input']);
}}
onPreview={onPreview}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ const useAutoComplete = ({
}
props.onChange?.({ name: props.name, values });
};

return {
onSelectionChange,
onTriggerKeydown,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { BaseInput } from '../BaseInput';
import type { BaseInputProps } from '../BaseInput';
import { InputChevronIcon } from './InputChevronIcon';
import type { BaseDropdownInputTriggerProps } from './types';
import type { BaseDropdownInputTriggerProps, useControlledDropdownInputProps } from './types';
import isEmpty from '~utils/lodashButBetter/isEmpty';
import { useDropdown } from '~components/Dropdown/useDropdown';
import { isReactNative } from '~utils';
Expand All @@ -18,19 +18,9 @@ import {
validationStateToInputTrailingIconMap,
} from '~components/Table/tokens';
import { useTableEditableCell } from '~components/Table/TableEditableCellContext';
import { fireNativeEvent } from '~utils/fireNativeEvent';

const useControlledDropdownInput = (
props: Pick<
BaseDropdownInputTriggerProps,
| 'onChange'
| 'name'
| 'value'
| 'defaultValue'
| 'onInputValueChange'
| 'syncInputValueWithSelection'
| 'isSelectInput'
>,
): void => {
const useControlledDropdownInput = (props: useControlledDropdownInputProps): void => {
const isFirstRender = useFirstRender();
const {
changeCallbackTriggerer,
Expand Down Expand Up @@ -116,6 +106,7 @@ const useControlledDropdownInput = (
name: props.name,
values: getValuesArrayFromIndices(),
});
fireNativeEvent(props.triggererRef, ['change', 'input']);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [changeCallbackTriggerer]);
Expand Down Expand Up @@ -176,6 +167,7 @@ const _BaseDropdownInputTrigger = (
defaultValue: props.defaultValue,
syncInputValueWithSelection: props.syncInputValueWithSelection,
isSelectInput: props.isSelectInput,
triggererRef,
tewarig marked this conversation as resolved.
Show resolved Hide resolved
});

const getValue = (): string | undefined => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ export type BaseDropdownInputTriggerProps = Omit<
onTriggerClick: BaseInputProps['onClick'];
};

export type useControlledDropdownInputProps = Pick<
BaseDropdownInputTriggerProps,
| 'onChange'
| 'name'
| 'value'
| 'defaultValue'
| 'onInputValueChange'
| 'syncInputValueWithSelection'
| 'isSelectInput'
> & {
triggererRef: React.RefObject<HTMLElement>;
};

export type SelectInputProps = DropdownInputTriggersProps;

export type AutoCompleteProps = DropdownInputTriggersCommonProps & {
Expand Down
30 changes: 30 additions & 0 deletions packages/blade/src/utils/fireNativeEvent/fireNativeEvent.web.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Fires native events on a given HTML element reference.
*
* @param ref - A React ref object pointing to an HTML element or null.
* @param eventTypes - An array of event types to be dispatched. Supported event types are 'change' and 'input'.
*
* @remarks
* This function creates and dispatches native events of the specified types on the element referenced by `ref`.
* If `ref` is null, a warning is logged to the console.
*
* @example
* ```typescript
* const inputRef = React.createRef<HTMLInputElement>();
* fireNativeEvent(inputRef, ['change', 'input']);
* ```
*/

export const fireNativeEvent = (
ref: React.RefObject<HTMLElement> | null,
eventTypes: Array<'change' | 'input'>,
): void => {
if (ref) {
eventTypes.forEach((eventType) => {
const event = new Event(eventType, { bubbles: true });
ref.current?.dispatchEvent(event);
});
} else {
console.warn('ref is not defined');
}
tewarig marked this conversation as resolved.
Show resolved Hide resolved
};
1 change: 1 addition & 0 deletions packages/blade/src/utils/fireNativeEvent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './fireNativeEvent.web';
tewarig marked this conversation as resolved.
Show resolved Hide resolved
Loading