Skip to content

Commit

Permalink
fix(new-hope): edit select native ui component in combobox
Browse files Browse the repository at this point in the history
  • Loading branch information
iljs committed Nov 21, 2024
1 parent 2b6cea9 commit 63a293b
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 5,682 deletions.
1 change: 0 additions & 1 deletion packages/plasma-b2c/api/plasma-b2c.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ import { CellTextboxLabel } from '@salutejs/plasma-new-hope/styled-components';
import { CellTextboxSubtitle } from '@salutejs/plasma-new-hope/styled-components';
import { CellTextboxTitle } from '@salutejs/plasma-new-hope/styled-components';
import { ChangeEvent } from 'react';
import { ChangeEventHandler } from 'react';
import { ChangeInstanceCallback } from '@salutejs/plasma-new-hope/types/components/DatePicker/RangeDate/RangeDate.types';
import { CheckboxProps as CheckboxProps_2 } from '@salutejs/plasma-new-hope/types/components/Checkbox/Checkbox.types';
import { ChipGroupProps } from '@salutejs/plasma-new-hope/types/components/ChipGroup/ChipGroup.types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import type { ItemContext, ComboboxProps } from './Combobox.types';
import { base as viewCSS } from './variations/_view/base';
import { base as sizeCSS } from './variations/_size/base';
import type { ItemOptionTransformed } from './ui/Inner/ui/Item/Item.types';
import { Form } from './ui/Form/Form';
import { SelectNative } from './ui/SelectNative/SelectNative';

export const Context = createContext<ItemContext>({} as ItemContext);

Expand All @@ -45,7 +45,7 @@ export const Context = createContext<ItemContext>({} as ItemContext);
*/

export const comboboxRoot = (Root: RootProps<HTMLInputElement, Omit<ComboboxProps, 'items'>>) =>
forwardRef<HTMLInputElement | HTMLSelectElement, ComboboxProps>((props, ref) => {
forwardRef<HTMLInputElement, ComboboxProps>((props, ref) => {
const {
name,
multiple,
Expand Down Expand Up @@ -79,6 +79,7 @@ export const comboboxRoot = (Root: RootProps<HTMLInputElement, Omit<ComboboxProp
renderValue,
...rest
} = props;

const transformedItems = useMemo(() => initialItemsTransform(items || []), [items]);

// Создаем структуры для быстрой работы с деревом
Expand Down Expand Up @@ -139,21 +140,23 @@ export const comboboxRoot = (Root: RootProps<HTMLInputElement, Omit<ComboboxProp
}
}, floatingPopoverRef);

// Эта функция срабатывает при изменении Combobox и
// при изменении нативного Select для формы (срабатывает только после изменения internalValue и рендера).
const onChange = (newValue: string | Array<string> | ChangeEvent<HTMLSelectElement> | null) => {
// Условие для отправки изменений наружу
if (outerOnChange) {
if (!name && !multiple && typeof newValue === 'string') {
outerOnChange(newValue as string & string[] & ChangeEvent<HTMLSelectElement>);
}

if (!name && multiple && Array.isArray(newValue)) {
outerOnChange(newValue as string & string[] & ChangeEvent<HTMLSelectElement>);
// Условие для отправки если комбобокс используется без формы.
if (!name && (typeof newValue === 'string' || Array.isArray(newValue))) {
outerOnChange(newValue as any);
}

// Условие для отправки если комбобокс используется с формой.
if (name && typeof newValue === 'object' && !Array.isArray(newValue)) {
outerOnChange(newValue as string & string[] & ChangeEvent<HTMLSelectElement>);
outerOnChange(newValue as any);
}
}

// Условие для изменения внутреннего значения (только если newValue строка или массив строк).
if (typeof newValue === 'string' || Array.isArray(newValue)) {
setInternalValue(newValue);
}
Expand Down Expand Up @@ -348,14 +351,21 @@ export const comboboxRoot = (Root: RootProps<HTMLInputElement, Omit<ComboboxProp
}, [defaultValue]);

return (
<Root size={size} view={view} labelPlacement={labelPlacement} disabled={disabled} readOnly={readOnly}>
<Root
size={size}
view={view}
labelPlacement={labelPlacement}
disabled={disabled}
readOnly={readOnly}
name={name}
>
{name && (
<Form
<SelectNative
name={name}
value={internalValue}
multiple={multiple}
onChange={onChange}
ref={ref as ForwardedRef<HTMLSelectElement>}
ref={ref as ForwardedRef<HTMLInputElement>}
/>
)}
<div>
Expand Down Expand Up @@ -432,6 +442,7 @@ export const comboboxRoot = (Root: RootProps<HTMLInputElement, Omit<ComboboxProp
labelPlacement={labelPlacement}
disabled={disabled}
readOnly={readOnly}
name={name}
>
<Ul
role="tree"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,57 +22,51 @@ type Placement =
| 'left-end';

type IsMultiselect<T extends ItemOption = ItemOption> =
| {
name?: never;
multiple?: false;
value?: string;
defaultValue?: never;
onChange?: (value: string) => void;
/**
* Если включено - будет выведено общее количество выбранных элементов вместо перечисления.
* @default false
*/
isTargetAmount?: never | false;
/**
* Ручная настройка количества выбранных элементов. Только при isTargetAmount === true.
* @default undefined
*/
targetAmount?: never;
renderValue?: never;
}
| {
multiple: true;
value?: Array<string>;
defaultValue?: never;
onChange?: (value: Array<string>) => void;
isTargetAmount?: true;
targetAmount?: number;
/**
* Callback для кастомной настройки значения в селекте.
*/
renderValue?: (item: T) => string;
name?: never;
}
| {
multiple: true;
value?: string[];
defaultValue?: string[];
onChange?: ChangeEventHandler;
isTargetAmount?: never | false;
targetAmount?: never;
renderValue?: never;
name: string;
}
| {
multiple?: false;
value?: string;
defaultValue?: string;
onChange?: ChangeEventHandler;
isTargetAmount?: never | false;
targetAmount?: never;
renderValue?: never;
name: string;
};
| ({ name: never; defaultValue: never } & (
| {
multiple?: false;
value?: string;
onChange?: (value: string) => void;
/**
* Если включено - будет выведено общее количество выбранных элементов вместо перечисления.
* @default false
*/
isTargetAmount?: never | false;
/**
* Ручная настройка количества выбранных элементов. Только при isTargetAmount === true.
* @default undefined
*/
targetAmount?: never;
/**
* Callback для кастомной настройки значения в селекте.
*/
renderValue?: never;
}
| {
multiple: true;
value?: string[];
onChange?: (value: string[]) => void;
isTargetAmount?: true;
targetAmount?: number;
renderValue?: (item: T) => string;
}
))
| ({ name: string; defaultValue?: string; onChange?: ChangeEventHandler } & (
| {
multiple?: false;
value?: string;
isTargetAmount?: never | false;
targetAmount?: never;
renderValue?: never;
}
| {
multiple: true;
value?: string[];
isTargetAmount?: true;
targetAmount?: number;
renderValue?: (item: T) => string;
}
));

type ViewStateProps =
| {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import React, { ChangeEvent, forwardRef, useEffect, useRef } from 'react';
import { useForkRef } from '@salutejs/plasma-core';

import { createEvent } from '../../../../../utils/syntheticEvent';
import { createEvent } from '../../../../../utils';
import { ComboboxProps } from '../../Combobox.types';

import { SelectHidden } from './Form.styles';
import { SelectHidden } from './SelectNative.styles';

type Props = Pick<ComboboxProps, 'name' | 'value' | 'multiple'> & {
onChange: (value: ChangeEvent<HTMLSelectElement> | null) => void;
};

export const Form = forwardRef<HTMLSelectElement, Props>(({ name, multiple, value, onChange }, ref) => {
export const SelectNative = forwardRef<HTMLInputElement, Props>(({ name, multiple, value, onChange }, ref) => {
const values = (multiple ? value : [value]) as string[];
const selectRef = useRef<HTMLSelectElement | null>(null);
const forkRef = useForkRef(selectRef, ref);
const selectRef = useRef<HTMLSelectElement>(null);
const forkRef = useForkRef(selectRef, ref as any);

useEffect(() => {
const event = createEvent(selectRef);
onChange && onChange(event);
if (onChange) {
onChange(event);
}
}, [values]);

return (
<>
<SelectHidden ref={forkRef} multiple={multiple} name={name} hidden value={multiple ? values : values[0]}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const createEvent = <T extends HTMLSelectElement | HTMLInputElement | HTM
return null;
};

export const createSyntheticEvent = <T extends Element, E extends Event>(event: E): React.SyntheticEvent<T, E> => {
const createSyntheticEvent = <T extends Element, E extends Event>(event: E): React.SyntheticEvent<T, E> => {
let isDefaultPrevented = false;
let isPropagationStopped = false;
const preventDefault = () => {
Expand Down
1 change: 1 addition & 0 deletions packages/plasma-new-hope/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { IS_REACT_18, safeUseId } from './react';
export { isNumber } from './isNumber';
export { mergeRefs, setRefList } from './setRefList';
export { isEmpty } from './isEmpty';
export { createEvent } from './createEvent';
export * as constants from './constants';
export * from './getPopoverPlacement';
export { noop } from './noop';
Expand Down
1 change: 0 additions & 1 deletion packages/plasma-web/api/plasma-web.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ import { CellTextboxLabel } from '@salutejs/plasma-new-hope/styled-components';
import { CellTextboxSubtitle } from '@salutejs/plasma-new-hope/styled-components';
import { CellTextboxTitle } from '@salutejs/plasma-new-hope/styled-components';
import { ChangeEvent } from 'react';
import { ChangeEventHandler } from 'react';
import { ChangeInstanceCallback } from '@salutejs/plasma-new-hope/types/components/DatePicker/RangeDate/RangeDate.types';
import { CheckboxProps as CheckboxProps_2 } from '@salutejs/plasma-new-hope/types/components/Checkbox/Checkbox.types';
import { ChipGroupProps } from '@salutejs/plasma-new-hope/types/components/ChipGroup/ChipGroup.types';
Expand Down
Loading

0 comments on commit 63a293b

Please sign in to comment.