@snack-uikit/fields 0.14.2 → 0.15.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 (62) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +15 -14
  3. package/dist/components/FieldDecorator/Header.js +1 -1
  4. package/dist/components/FieldDecorator/styles.module.css +7 -1
  5. package/dist/components/FieldSelect/FieldSelect.d.ts +1 -7
  6. package/dist/components/FieldSelect/FieldSelect.js +9 -21
  7. package/dist/components/FieldSelect/FieldSelectMultiple.d.ts +17 -0
  8. package/dist/components/FieldSelect/FieldSelectMultiple.js +118 -0
  9. package/dist/components/FieldSelect/FieldSelectSingle.d.ts +9 -28
  10. package/dist/components/FieldSelect/FieldSelectSingle.js +69 -55
  11. package/dist/components/FieldSelect/hooks.d.ts +30 -0
  12. package/dist/components/FieldSelect/hooks.js +72 -0
  13. package/dist/components/FieldSelect/index.d.ts +2 -1
  14. package/dist/components/FieldSelect/index.js +1 -1
  15. package/dist/components/FieldSelect/styles.module.css +129 -27
  16. package/dist/components/FieldSelect/types.d.ts +42 -37
  17. package/dist/components/FieldSelect/utils.d.ts +19 -0
  18. package/dist/components/FieldSelect/utils.js +112 -0
  19. package/dist/helperComponents/FieldContainerPrivate/styles.module.css +30 -6
  20. package/package.json +5 -3
  21. package/src/components/FieldDecorator/Header.tsx +6 -1
  22. package/src/components/FieldDecorator/styles.module.scss +38 -30
  23. package/src/components/FieldSelect/FieldSelect.tsx +13 -21
  24. package/src/components/FieldSelect/FieldSelectMultiple.tsx +255 -0
  25. package/src/components/FieldSelect/FieldSelectSingle.tsx +159 -99
  26. package/src/components/FieldSelect/hooks.ts +125 -0
  27. package/src/components/FieldSelect/index.ts +12 -1
  28. package/src/components/FieldSelect/styles.module.scss +71 -31
  29. package/src/components/FieldSelect/types.ts +55 -40
  30. package/src/components/FieldSelect/utils.ts +163 -0
  31. package/src/helperComponents/FieldContainerPrivate/FieldContainerPrivate.tsx +2 -0
  32. package/src/helperComponents/FieldContainerPrivate/styles.module.scss +32 -11
  33. package/dist/components/FieldSelect/FieldSelectBase.d.ts +0 -31
  34. package/dist/components/FieldSelect/FieldSelectBase.js +0 -51
  35. package/dist/components/FieldSelect/FieldSelectMulti.d.ts +0 -37
  36. package/dist/components/FieldSelect/FieldSelectMulti.js +0 -89
  37. package/dist/components/FieldSelect/constants.d.ts +0 -7
  38. package/dist/components/FieldSelect/constants.js +0 -6
  39. package/dist/components/FieldSelect/helpers/getArrowIcon.d.ts +0 -8
  40. package/dist/components/FieldSelect/helpers/getArrowIcon.js +0 -8
  41. package/dist/components/FieldSelect/helpers/getDisplayedValue.d.ts +0 -10
  42. package/dist/components/FieldSelect/helpers/getDisplayedValue.js +0 -12
  43. package/dist/components/FieldSelect/helpers/index.d.ts +0 -2
  44. package/dist/components/FieldSelect/helpers/index.js +0 -2
  45. package/dist/components/FieldSelect/hooks/index.d.ts +0 -3
  46. package/dist/components/FieldSelect/hooks/index.js +0 -3
  47. package/dist/components/FieldSelect/hooks/useFilteredOptions.d.ts +0 -7
  48. package/dist/components/FieldSelect/hooks/useFilteredOptions.js +0 -6
  49. package/dist/components/FieldSelect/hooks/useList.d.ts +0 -37
  50. package/dist/components/FieldSelect/hooks/useList.js +0 -52
  51. package/dist/components/FieldSelect/hooks/useListNavigation.d.ts +0 -26
  52. package/dist/components/FieldSelect/hooks/useListNavigation.js +0 -48
  53. package/src/components/FieldSelect/FieldSelectBase.tsx +0 -222
  54. package/src/components/FieldSelect/FieldSelectMulti.tsx +0 -163
  55. package/src/components/FieldSelect/constants.ts +0 -9
  56. package/src/components/FieldSelect/helpers/getArrowIcon.ts +0 -9
  57. package/src/components/FieldSelect/helpers/getDisplayedValue.ts +0 -25
  58. package/src/components/FieldSelect/helpers/index.ts +0 -2
  59. package/src/components/FieldSelect/hooks/index.ts +0 -3
  60. package/src/components/FieldSelect/hooks/useFilteredOptions.ts +0 -23
  61. package/src/components/FieldSelect/hooks/useList.ts +0 -87
  62. package/src/components/FieldSelect/hooks/useListNavigation.ts +0 -81
@@ -1,133 +1,193 @@
1
- import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
1
+ import mergeRefs from 'merge-refs';
2
+ import { forwardRef, KeyboardEvent, KeyboardEventHandler, useEffect, useMemo, useRef, useState } from 'react';
2
3
  import { useUncontrolledProp } from 'uncontrollable';
3
4
 
4
- import { selectAll } from '@snack-uikit/input-private';
5
+ import { InputPrivate } from '@snack-uikit/input-private';
6
+ import { Droplist, SelectionSingleValueType, useFuzzySearch } from '@snack-uikit/list';
7
+ import { extractSupportProps } from '@snack-uikit/utils';
5
8
 
6
- import { DEFAULT_LOCALE, EMPTY_OPTION, SELECTION_MODE } from './constants';
7
- import { FieldSelectBase } from './FieldSelectBase';
8
- import { getDisplayedValue } from './helpers';
9
- import { useList } from './hooks';
10
- import { FieldSelectSingleProps, Option } from './types';
9
+ import { FieldContainerPrivate } from '../../helperComponents';
10
+ import { FieldDecorator } from '../FieldDecorator';
11
+ import { useButtons, useHandleOnKeyDown, useSearchInput } from './hooks';
12
+ import styles from './styles.module.scss';
13
+ import { FieldSelectSingleProps } from './types';
14
+ import { extractSelectedOptions, getArrowIcon, transformOptionsToItems } from './utils';
11
15
 
12
16
  export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleProps>(
13
17
  (
14
18
  {
15
- value: valueProp,
16
- onChange,
19
+ id,
20
+ name,
21
+ placeholder,
22
+ size = 's',
17
23
  options,
24
+ value: valueProp,
25
+ defaultValue,
26
+ onChange: onChangeProp,
27
+ loading,
18
28
  disabled = false,
19
29
  readonly = false,
20
30
  searchable = true,
31
+ showCopyButton = true,
32
+ showClearButton = true,
33
+ onKeyDown: onInputKeyDownProp,
34
+ label,
35
+ labelTooltip,
36
+ labelTooltipPlacement,
21
37
  required = false,
22
- locale = DEFAULT_LOCALE,
23
- open,
24
- onOpenChange,
25
- showCopyButton: showCopyButtonProp = true,
26
- showClearButton: showClearButtonProp = true,
38
+ hint,
39
+ showHintIcon,
40
+ validationState = 'default',
41
+ footer,
42
+ search,
43
+ autocomplete = false,
44
+ prefixIcon,
27
45
  ...rest
28
46
  },
29
47
  ref,
30
48
  ) => {
31
- const selectionMode = SELECTION_MODE.Single;
32
- const [value, setValue] = useUncontrolledProp(valueProp, '', onChange);
33
- const selected = useMemo(() => options.find(option => option.value === value) ?? EMPTY_OPTION, [options, value]);
34
- const displayedValue = getDisplayedValue({ selectionMode, selected });
35
- const [inputValue, setInputValue] = useState(selected.label);
36
- const showAdditionalButton = Boolean(value && !disabled);
37
- const isChecked = useCallback((option: Option) => selected.value === option.value, [selected.value]);
38
-
39
- const {
40
- isOpen,
41
- setIsOpen,
42
- localRef,
43
- extendedOptions,
44
- onInputKeyDown,
45
- onInputValueChange,
46
- onButtonKeyDown,
47
- clearButtonRef,
48
- copyButtonRef,
49
- showClearButton,
50
- showCopyButton,
51
- onDroplistFocusLeave,
52
- firstDroplistItemRefCallback,
53
- } = useList({
54
- open,
55
- onOpenChange,
56
- disabled,
49
+ const localRef = useRef<HTMLInputElement>(null);
50
+ const [open, setOpen] = useState<boolean>(false);
51
+ const [value, setValue] = useUncontrolledProp<string | number | undefined>(valueProp, defaultValue, onChangeProp);
52
+
53
+ const items = useMemo(() => transformOptionsToItems(options), [options]);
54
+ const selectedOption = useMemo(() => extractSelectedOptions(options, value), [options, value]);
55
+
56
+ const { inputValue, onInputValueChange, prevInputValue } = useSearchInput({
57
+ ...search,
58
+ defaultValue: String(selectedOption ?? ''),
59
+ });
60
+
61
+ useEffect(() => {
62
+ !open && onInputValueChange(String(selectedOption?.option ?? ''));
63
+ }, [onInputValueChange, open, selectedOption]);
64
+
65
+ useEffect(() => {
66
+ onInputValueChange(String(selectedOption?.option ?? ''));
67
+
68
+ prevInputValue.current = String(selectedOption?.option ?? '');
69
+ }, [prevInputValue, onInputValueChange, selectedOption]);
70
+
71
+ const onClear = () => {
72
+ setValue('');
73
+ onInputValueChange('');
74
+
75
+ localRef.current?.focus();
76
+ setOpen(true);
77
+ };
78
+
79
+ const { ArrowIcon, arrowIconSize } = getArrowIcon({ size, open });
80
+
81
+ const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
57
82
  readonly,
58
- inputValue,
59
- setInputValue,
60
- searchable,
61
- options,
62
- isChecked,
63
- showCopyButton: showCopyButtonProp,
64
- showClearButton: showClearButtonProp,
65
- showAdditionalButton,
83
+ size,
84
+ showClearButton: showClearButton && Boolean(value),
85
+ showCopyButton,
86
+ inputRef: localRef,
87
+ onClear,
88
+ valueToCopy: String(selectedOption?.option ?? ''),
89
+ });
90
+
91
+ const commonHandleOnKeyDown = useHandleOnKeyDown({
92
+ inputKeyDownNavigationHandler,
93
+ onInputKeyDownProp,
94
+ setOpen,
66
95
  });
67
96
 
68
- const handleOpenChange = (isOpen: boolean) => {
69
- if (isOpen) {
70
- searchable && selectAll(localRef.current);
71
- } else {
72
- setInputValue(displayedValue);
97
+ const handleOnKeyDown = (onKeyDown?: KeyboardEventHandler<HTMLElement>) => (e: KeyboardEvent<HTMLInputElement>) => {
98
+ if (!open && prevInputValue.current !== inputValue) {
99
+ setOpen(true);
73
100
  }
74
101
 
75
- setIsOpen(isOpen);
102
+ commonHandleOnKeyDown(onKeyDown)(e);
76
103
  };
77
104
 
78
- const handleClear = () => {
79
- setValue('');
80
- setInputValue('');
81
-
82
- if (required) {
83
- localRef.current?.focus();
84
- setIsOpen(true);
85
- } else {
86
- localRef.current?.blur();
87
- setIsOpen(false);
105
+ const handleSelectionChange = (newValue?: SelectionSingleValueType) => {
106
+ setValue(newValue);
107
+ localRef.current?.focus();
108
+
109
+ if (newValue) {
110
+ setOpen(false);
88
111
  }
89
112
  };
90
113
 
91
- const handleChange = (option: Option) => () => {
92
- setValue(option.value);
93
- setInputValue(option.label);
94
- setIsOpen(false);
95
- localRef.current?.focus();
114
+ const handleOpenChange = (open: boolean) => {
115
+ if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
116
+ setOpen(open);
117
+ }
96
118
  };
97
119
 
98
- useEffect(() => {
99
- setInputValue(selected.label);
100
- }, [selected]);
120
+ const fuzzySearch = useFuzzySearch(items);
121
+ const result = autocomplete ? items : fuzzySearch(prevInputValue.current !== inputValue ? inputValue : '');
101
122
 
102
123
  return (
103
- <FieldSelectBase
104
- {...rest}
105
- ref={ref}
106
- localRef={localRef}
107
- selectionMode={selectionMode}
108
- options={extendedOptions}
109
- selected={selected}
110
- disabled={disabled}
111
- readonly={readonly}
124
+ <FieldDecorator
125
+ {...extractSupportProps(rest)}
112
126
  required={required}
113
- searchable={searchable}
114
- onChange={handleChange}
115
- onClear={handleClear}
116
- valueToCopy={displayedValue}
117
- inputValue={searchable ? inputValue : displayedValue}
118
- onInputValueChange={onInputValueChange}
119
- onInputKeyDown={onInputKeyDown}
120
- clearButtonRef={clearButtonRef}
121
- copyButtonRef={copyButtonRef}
122
- onButtonKeyDown={onButtonKeyDown}
123
- open={isOpen}
124
- onOpenChange={handleOpenChange}
125
- locale={locale}
126
- showCopyButton={showCopyButton}
127
- showClearButton={showClearButton}
128
- onDroplistFocusLeave={onDroplistFocusLeave}
129
- firstDroplistItemRefCallback={firstDroplistItemRefCallback}
130
- />
127
+ readonly={readonly}
128
+ label={label}
129
+ labelTooltip={labelTooltip}
130
+ labelTooltipPlacement={labelTooltipPlacement}
131
+ labelFor={id}
132
+ hint={hint}
133
+ disabled={disabled}
134
+ showHintIcon={showHintIcon}
135
+ size={size}
136
+ validationState={validationState}
137
+ >
138
+ <Droplist
139
+ trigger='clickAndFocusVisible'
140
+ placement='bottom'
141
+ data-test-id='field-select__list'
142
+ items={result}
143
+ triggerElemRef={localRef}
144
+ scroll
145
+ marker
146
+ footer={footer}
147
+ selection={{
148
+ mode: 'single',
149
+ value: value,
150
+ onChange: handleSelectionChange,
151
+ }}
152
+ size={size}
153
+ open={open}
154
+ onOpenChange={handleOpenChange}
155
+ loading={loading}
156
+ >
157
+ {({ onKeyDown }) => (
158
+ <FieldContainerPrivate
159
+ className={styles.container}
160
+ validationState={validationState}
161
+ disabled={disabled}
162
+ readonly={readonly}
163
+ focused={open}
164
+ variant={'single-line-container'}
165
+ inputRef={localRef}
166
+ size={size}
167
+ prefix={prefixIcon}
168
+ >
169
+ <InputPrivate
170
+ id={id}
171
+ name={name}
172
+ type='text'
173
+ disabled={disabled}
174
+ placeholder={placeholder}
175
+ ref={mergeRefs(ref, localRef)}
176
+ onChange={searchable ? onInputValueChange : undefined}
177
+ value={inputValue}
178
+ readonly={!searchable || readonly}
179
+ data-test-id='field-select__input'
180
+ onKeyDown={handleOnKeyDown(onKeyDown)}
181
+ />
182
+
183
+ <div className={styles.postfix}>
184
+ {buttons}
185
+ <ArrowIcon size={arrowIconSize} className={styles.arrowIcon} />
186
+ </div>
187
+ </FieldContainerPrivate>
188
+ )}
189
+ </Droplist>
190
+ </FieldDecorator>
131
191
  );
132
192
  },
133
193
  );
@@ -0,0 +1,125 @@
1
+ import { KeyboardEvent, KeyboardEventHandler, RefObject, useCallback, useMemo, useRef } from 'react';
2
+ import { Handler, useUncontrolledProp } from 'uncontrollable';
3
+
4
+ import { useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
5
+ import { SelectionSingleValueType } from '@snack-uikit/list';
6
+ import { extractChildIds } from '@snack-uikit/list/dist/utils';
7
+
8
+ import { useCopyButton } from '../../hooks';
9
+ import { OptionProps, SearchState } from './types';
10
+ import { isAccordionOptionProps, isBaseOptionProps, isNextListOptionProps, transformOptionsToItems } from './utils';
11
+
12
+ type UseHandleOnKeyDownProps = {
13
+ inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
14
+ onInputKeyDownProp: KeyboardEventHandler<HTMLInputElement> | undefined;
15
+ setOpen(open: boolean): void;
16
+ };
17
+
18
+ export function useHandleOnKeyDown({
19
+ setOpen,
20
+ inputKeyDownNavigationHandler,
21
+ onInputKeyDownProp,
22
+ }: UseHandleOnKeyDownProps) {
23
+ return useCallback(
24
+ (onKeyDown?: KeyboardEventHandler<HTMLElement>) => (e: KeyboardEvent<HTMLInputElement>) => {
25
+ if (e.code === 'Space') {
26
+ e.stopPropagation();
27
+ } else {
28
+ onKeyDown?.(e);
29
+ }
30
+
31
+ if (e.code === 'ArrowUp') {
32
+ setOpen(false);
33
+ }
34
+
35
+ if (['ArrowUp', 'ArrowDown'].includes(e.key)) {
36
+ e.preventDefault();
37
+ }
38
+
39
+ if (e.key === 'Tab') {
40
+ setOpen(false);
41
+ }
42
+
43
+ inputKeyDownNavigationHandler(e);
44
+ onInputKeyDownProp?.(e);
45
+ },
46
+ [inputKeyDownNavigationHandler, onInputKeyDownProp, setOpen],
47
+ );
48
+ }
49
+
50
+ type UseButtonsProps = {
51
+ readonly: boolean;
52
+ showClearButton: boolean;
53
+ showCopyButton: boolean;
54
+ size: 's' | 'm' | 'l';
55
+ onClear(): void;
56
+ inputRef: RefObject<HTMLInputElement>;
57
+ valueToCopy?: string;
58
+ };
59
+
60
+ export function useButtons({
61
+ readonly,
62
+ showClearButton,
63
+ showCopyButton,
64
+ size,
65
+ onClear,
66
+ inputRef,
67
+ valueToCopy = '',
68
+ }: UseButtonsProps) {
69
+ const clearButtonRef = useRef<HTMLButtonElement>(null);
70
+ const copyButtonRef = useRef<HTMLButtonElement>(null);
71
+
72
+ const buttonsRefs: (Element | null)[] = [copyButtonRef.current, clearButtonRef.current];
73
+
74
+ const clearButtonSettings = useClearButton({
75
+ clearButtonRef,
76
+ showClearButton: !readonly && showClearButton,
77
+ size,
78
+ onClear,
79
+ });
80
+ const copyButtonSettings = useCopyButton({
81
+ copyButtonRef,
82
+ showCopyButton: readonly && showCopyButton,
83
+ size,
84
+ valueToCopy,
85
+ });
86
+ const { onInputKeyDown: inputKeyDownNavigationHandler, buttons } = useButtonNavigation({
87
+ inputRef,
88
+ buttons: useMemo(() => [clearButtonSettings, copyButtonSettings], [clearButtonSettings, copyButtonSettings]),
89
+ onButtonKeyDown: undefined,
90
+ readonly,
91
+ submitKeys: ['Enter', 'Space', 'Tab'],
92
+ });
93
+
94
+ return { buttons, inputKeyDownNavigationHandler, buttonsRefs };
95
+ }
96
+
97
+ export function useSearchInput({ value, onChange, defaultValue }: SearchState) {
98
+ const [inputValue, onInputValueChange] = useUncontrolledProp<string>(value, defaultValue ?? '', onChange);
99
+
100
+ const prevInputValue = useRef<string>(inputValue);
101
+
102
+ return { inputValue, onInputValueChange, prevInputValue };
103
+ }
104
+
105
+ export function useHandleDeleteItem(setValue: Handler) {
106
+ return useCallback(
107
+ (option?: OptionProps) => () => {
108
+ if (!option) {
109
+ return;
110
+ }
111
+
112
+ if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
113
+ const removeIds = extractChildIds({ items: transformOptionsToItems(option.options) }).concat(option.value);
114
+
115
+ setValue((value: SelectionSingleValueType[]) => value?.filter(v => !removeIds.includes(v ?? '')));
116
+ return;
117
+ }
118
+
119
+ if (isBaseOptionProps(option)) {
120
+ setValue((value: SelectionSingleValueType[]) => value?.filter(v => v !== option.value));
121
+ }
122
+ },
123
+ [setValue],
124
+ );
125
+ }
@@ -1 +1,12 @@
1
- export * from './FieldSelect';
1
+ export { FieldSelect } from './FieldSelect';
2
+
3
+ export type {
4
+ FieldSelectSingleProps,
5
+ FieldSelectMultipleProps,
6
+ FieldSelectProps,
7
+ OptionProps,
8
+ BaseOptionProps,
9
+ AccordionOptionProps,
10
+ NestListOptionProps,
11
+ GroupOptionProps,
12
+ } from './types';
@@ -6,52 +6,48 @@ $containerVariant: 'single-line-container';
6
6
  $icons-sizes: (
7
7
  's': $icon-xs,
8
8
  'm': $icon-s,
9
- 'l': $icon-s
9
+ 'l': $icon-s,
10
10
  );
11
11
 
12
+ $base-min-width: 4px;
13
+
12
14
  .triggerClassName {
13
15
  --offset: #{$space-drop-list-drop-offset};
14
-
15
- width: 100%;
16
- }
17
-
18
-
19
- .scrollContainerS {
20
- max-height: 256px;
21
- }
22
16
 
23
- .scrollContainerM {
24
- max-height: 320px;
17
+ width: 100%;
25
18
  }
26
19
 
27
- .scrollContainerL {
28
- max-height: 384px;
20
+ .contentWrapper {
21
+ display: flex;
22
+ flex-wrap: wrap;
23
+ width: 100%;
29
24
  }
30
25
 
31
- .displayValue {
32
- pointer-events: none;
26
+ .tagContainer {
27
+ /* stylelint-disable-next-line declaration-no-important */
28
+ height: auto !important;
33
29
 
34
- position: absolute;
35
- top: 0;
36
- left: 0;
37
-
38
- overflow: hidden;
39
- display: flex;
40
- align-items: center;
41
-
42
- box-sizing: border-box;
43
- height: 100%;
30
+ @each $size in $sizes {
31
+ &[data-size='#{$size}'] {
32
+ @include composite-var($fields, 'select-multiple', $size);
44
33
 
45
- background-color: inherit;
46
- border: none;
47
- outline: none;
34
+ .contentWrapper {
35
+ gap: simple-var($fields, 'select-multiple', $size, 'gap');
36
+ }
37
+ }
38
+ }
48
39
  }
49
40
 
50
41
  .container {
42
+ position: relative;
51
43
  flex: 1 1 0;
52
44
 
53
45
  @each $size in $sizes {
54
46
  &[data-size='#{$size}'] {
47
+ .inputPlug {
48
+ @include composite-var($theme-variables, 'sans', 'body', $size);
49
+ }
50
+
55
51
  .arrowIcon {
56
52
  width: simple-var($icons-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
57
53
  height: simple-var($icons-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
@@ -62,7 +58,11 @@ $icons-sizes: (
62
58
  .displayValue {
63
59
  $button-width: simple-var($icons-sizes, $size);
64
60
  $postfix-width: calc(var(#{$space-fields-postfix-gap}) + $button-width * 2);
65
- $margin-right: calc(#{simple-var($fields, $containerVariant, $size, 'padding-right')} + #{simple-var($fields, $containerVariant, $size, 'gap')} + #{$postfix-width});
61
+ $margin-right: calc(
62
+ #{simple-var($fields, $containerVariant, $size, 'padding-right')} +
63
+ #{simple-var($fields, $containerVariant, $size, 'gap')} +
64
+ #{$postfix-width}
65
+ );
66
66
 
67
67
  width: calc(100% - $margin-right);
68
68
  margin-right: $margin-right;
@@ -73,15 +73,55 @@ $icons-sizes: (
73
73
  }
74
74
  }
75
75
 
76
- &:hover, &:focus-within, &[data-focused] {
76
+ &:hover,
77
+ &:focus-within,
78
+ &[data-focused] {
77
79
  .arrowIcon {
78
80
  color: $sys-neutral-text-support;
79
81
  }
80
82
  }
81
83
 
82
- &[data-disabled], &[data-readonly] {
84
+ &[data-disabled],
85
+ &[data-readonly] {
83
86
  .arrowIcon {
84
87
  color: $sys-neutral-text-disabled;
85
88
  }
86
89
  }
87
90
  }
91
+
92
+ .inputPlug {
93
+ content: '';
94
+
95
+ position: absolute;
96
+ top: 0;
97
+ left: 0;
98
+
99
+ overflow: hidden;
100
+
101
+ width: fit-content;
102
+ max-width: 100%;
103
+ height: 0;
104
+ }
105
+
106
+ .inputWrapper {
107
+ position: relative;
108
+
109
+ display: inline-flex;
110
+ flex: 1;
111
+
112
+ min-width: $base-min-width;
113
+
114
+ color: transparent;
115
+
116
+ &[data-searchable='false'] {
117
+ width: 0;
118
+ min-width: 0;
119
+ max-width: 0;
120
+ }
121
+ }
122
+
123
+ .postfix {
124
+ display: inline-flex;
125
+ flex-shrink: 0;
126
+ gap: $space-fields-postfix-gap;
127
+ }