@transferwise/components 0.0.0-experimental-4658255 → 0.0.0-experimental-07a2614

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.
@@ -3524,6 +3524,13 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
3524
3524
  padding-inline-start: 8px;
3525
3525
  padding-inline-start: var(--size-8);
3526
3526
  }
3527
+ .wds-select-input-scroll-freeze {
3528
+ scroll-behavior: unset !important;
3529
+ height: 100vh;
3530
+ }
3531
+ .wds-select-input-scroll-freeze body {
3532
+ height: 100vh;
3533
+ }
3527
3534
  .np-bottom-sheet-v2-container {
3528
3535
  position: relative;
3529
3536
  z-index: 1060;
@@ -3537,6 +3544,8 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
3537
3544
  transition-property: opacity;
3538
3545
  transition-timing-function: ease-out;
3539
3546
  transition-duration: 300ms;
3547
+ will-change: transform;
3548
+ min-height: 100vh;
3540
3549
  }
3541
3550
  .np-bottom-sheet-v2-backdrop--closed {
3542
3551
  opacity: 0;
@@ -3544,7 +3553,7 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
3544
3553
  .np-bottom-sheet-v2 {
3545
3554
  position: fixed;
3546
3555
  inset: 0px;
3547
- bottom: env(keyboard-inset-height, 0px);
3556
+ bottom: env(safe-area-inset-bottom, 0);
3548
3557
  margin-left: 8px;
3549
3558
  margin-left: var(--size-8);
3550
3559
  margin-right: 8px;
@@ -3554,18 +3563,21 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
3554
3563
  display: flex;
3555
3564
  flex-direction: column;
3556
3565
  justify-content: flex-end;
3566
+ height: calc(100vh - 64px - 40px);
3567
+ height: calc(100vh - var(--size-64) - 40px);
3557
3568
  }
3558
3569
  .np-bottom-sheet-v2-content {
3559
3570
  display: flex;
3560
3571
  flex-direction: column;
3561
3572
  overflow: auto;
3562
- border-top-left-radius: 32px;
3563
- /* TODO: Tokenize */
3564
- border-top-right-radius: 32px;
3565
- /* TODO: Tokenize */
3573
+ border-radius: 32px;
3574
+ border-radius: var(--size-32);
3575
+ margin-bottom: 8px;
3576
+ margin-bottom: var(--size-8);
3566
3577
  background-color: #ffffff;
3567
3578
  background-color: var(--color-background-elevated);
3568
3579
  box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
3580
+ will-change: transform;
3569
3581
  }
3570
3582
  .np-bottom-sheet-v2-content:focus {
3571
3583
  outline: none;
@@ -32,25 +32,6 @@ export interface SelectInputProps<T = string, M extends boolean = false> {
32
32
  multiple?: M;
33
33
  placeholder?: string;
34
34
  items: readonly SelectInputItem<NonNullable<T>>[];
35
- /**
36
- * Enables browser autocomplete integration through the search input.
37
- * Accepts standard HTML autocomplete values (e.g., "country-name", "address-level1").
38
- *
39
- * Requires `filterable={true}` to enable the search input.
40
- *
41
- * @example
42
- * <SelectInput
43
- * name="country"
44
- * autocomplete="country-name"
45
- * filterable={true}
46
- * items={[{
47
- * type: 'option',
48
- * value: 'GB',
49
- * filterMatchers: ['United Kingdom', 'UK']
50
- * }]}
51
- * />
52
- */
53
- autocomplete?: string;
54
35
  defaultValue?: M extends true ? readonly T[] : T;
55
36
  value?: M extends true ? readonly T[] : T;
56
37
  compareValues?: (keyof NonNullable<T> & string) | ((a: T | undefined, b: T | undefined) => boolean);
@@ -86,7 +67,7 @@ export interface SelectInputProps<T = string, M extends boolean = false> {
86
67
  onClose?: () => void;
87
68
  onClear?: () => void;
88
69
  }
89
- export declare function SelectInput<T = string, M extends boolean = false>({ id: idProp, parentId, name, multiple, placeholder, autocomplete, items, defaultValue, value: controlledValue, compareValues, renderValue, renderFooter, renderTrigger, filterable, filterPlaceholder, disabled, size, className, UNSAFE_triggerButtonProps, triggerRef: externalTriggerRef, onFilterChange, onChange, onOpen, onClose, onClear, }: SelectInputProps<T, M>): import("react").JSX.Element;
70
+ export declare function SelectInput<T = string, M extends boolean = false>({ id: idProp, parentId, name, multiple, placeholder, items, defaultValue, value: controlledValue, compareValues, renderValue, renderFooter, renderTrigger, filterable, filterPlaceholder, disabled, size, className, UNSAFE_triggerButtonProps, triggerRef: externalTriggerRef, onFilterChange, onChange, onOpen, onClose, onClear, }: SelectInputProps<T, M>): import("react").JSX.Element;
90
71
  type SelectInputTriggerButtonElementType = 'button' | React.ComponentType;
91
72
  export type SelectInputTriggerButtonProps<T extends SelectInputTriggerButtonElementType = 'button'> = Merge<React.ComponentPropsWithoutRef<T>, {
92
73
  as?: T;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.d.ts","sourceRoot":"","sources":["../../../src/inputs/SelectInput.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectInput.d.ts","sourceRoot":"","sources":["../../../src/inputs/SelectInput.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"_BottomSheet.d.ts","sourceRoot":"","sources":["../../../src/inputs/_BottomSheet.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,mBAAmB,EAAE,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;YACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,aAAa,EACb,KAAK,EACL,eAAe,EACf,OAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,gBAAgB,+BA6FlB"}
1
+ {"version":3,"file":"_BottomSheet.d.ts","sourceRoot":"","sources":["../../../src/inputs/_BottomSheet.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,mBAAmB,EAAE,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;YACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAeD,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,aAAa,EACb,KAAK,EACL,eAAe,EACf,OAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,gBAAgB,+BAiGlB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-4658255",
3
+ "version": "0.0.0-experimental-07a2614",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -102,8 +102,8 @@
102
102
  "@floating-ui/react": "^0.27.16",
103
103
  "@headlessui/react": "^1.7.19",
104
104
  "@popperjs/core": "^2.11.8",
105
- "@react-aria/focus": "^3.21.0",
106
- "@react-aria/overlays": "^3.28.0",
105
+ "@react-aria/focus": "^3.21.1",
106
+ "@react-aria/overlays": "^3.29.1",
107
107
  "@react-spring/web": "~10.0.1",
108
108
  "@transferwise/formatting": "^2.13.4",
109
109
  "@transferwise/neptune-validation": "^3.3.1",
@@ -0,0 +1,94 @@
1
+ import { useState } from 'react';
2
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { userEvent, within } from 'storybook/test';
4
+ import { lorem100, lorem500 } from '../../test-utils';
5
+ import { Typography } from '../propsValues/typography';
6
+ import Alert from '../../alert';
7
+ import Body from '../../body';
8
+ import Button from '../../button';
9
+ import Title from '../../title';
10
+ import BottomSheet from './BottomSheet';
11
+
12
+ const wait = async (duration = 500) =>
13
+ new Promise<void>((resolve) => {
14
+ setTimeout(resolve, duration);
15
+ });
16
+
17
+ export default {
18
+ component: BottomSheet,
19
+ title: 'Dialogs/BottomSheet/tests',
20
+ tags: ['!autodocs'],
21
+ args: {
22
+ open: false,
23
+ },
24
+ } satisfies Meta<typeof BottomSheet>;
25
+
26
+ type Story = StoryObj<typeof BottomSheet>;
27
+
28
+ /**
29
+ * This test ensures that when the SelectInput is used within a scrollable page,
30
+ * opening the dropdown does not cause any unwanted scrolling or layout shifts.
31
+ * Expected preview should start with green bar at the top, with yellow section
32
+ * not in the viewport.
33
+ *
34
+ * NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
35
+ */
36
+ export const SmoothScrollReset: Story = {
37
+ args: {
38
+ children: (
39
+ <>
40
+ <Title type={Typography.TITLE_SECTION}>Observe the document</Title>
41
+ <Alert className="m-t-2" type="warning">
42
+ Once the <code>BottomSheet</code> opens, the document underneath should be static and
43
+ should not scroll.
44
+ </Alert>
45
+ <Body as="p">{lorem100}</Body>
46
+ <Body as="p">{lorem100}</Body>
47
+ </>
48
+ ),
49
+ },
50
+ decorators: [
51
+ (Story) => (
52
+ <>
53
+ <style>{'html { scroll-behavior: smooth; }'}</style>
54
+ <div style={{ maxWidth: 500 }}>
55
+ <Body>
56
+ <p>{lorem100}</p>
57
+ <p>{lorem100}</p>
58
+ </Body>
59
+ <Story />
60
+ <Body as="p" className="m-t-5 disabled">
61
+ {lorem500}
62
+ </Body>
63
+ </div>
64
+ </>
65
+ ),
66
+ ],
67
+ parameters: {
68
+ chromatic: {
69
+ disableSnapshot: true,
70
+ },
71
+ },
72
+ play: async ({ canvasElement }) => {
73
+ document.documentElement.scrollTop = 400;
74
+ await wait(500);
75
+ const canvas = within(canvasElement);
76
+ await userEvent.click(canvas.getByRole('button'));
77
+ },
78
+ render: ({ open, ...args }) => {
79
+ const [isOpen, setIsOpen] = useState(false);
80
+
81
+ return (
82
+ <div>
83
+ <Button onClick={() => setIsOpen(true)}>Open BottomSheet</Button>
84
+ <BottomSheet
85
+ {...args}
86
+ open={isOpen}
87
+ onClose={() => {
88
+ setIsOpen(false);
89
+ }}
90
+ />
91
+ </div>
92
+ );
93
+ },
94
+ };
@@ -1,3 +1,10 @@
1
+ .wds-select-input-scroll-freeze {
2
+ scroll-behavior: unset !important;
3
+ height: 100vh;
4
+ }
5
+ .wds-select-input-scroll-freeze body {
6
+ height: 100vh;
7
+ }
1
8
  .np-bottom-sheet-v2-container {
2
9
  position: relative;
3
10
  z-index: 1060;
@@ -11,6 +18,8 @@
11
18
  transition-property: opacity;
12
19
  transition-timing-function: ease-out;
13
20
  transition-duration: 300ms;
21
+ will-change: transform;
22
+ min-height: 100vh;
14
23
  }
15
24
  .np-bottom-sheet-v2-backdrop--closed {
16
25
  opacity: 0;
@@ -18,7 +27,7 @@
18
27
  .np-bottom-sheet-v2 {
19
28
  position: fixed;
20
29
  inset: 0px;
21
- bottom: env(keyboard-inset-height, 0px);
30
+ bottom: env(safe-area-inset-bottom, 0);
22
31
  margin-left: 8px;
23
32
  margin-left: var(--size-8);
24
33
  margin-right: 8px;
@@ -28,18 +37,21 @@
28
37
  display: flex;
29
38
  flex-direction: column;
30
39
  justify-content: flex-end;
40
+ height: calc(100vh - 64px - 40px);
41
+ height: calc(100vh - var(--size-64) - 40px);
31
42
  }
32
43
  .np-bottom-sheet-v2-content {
33
44
  display: flex;
34
45
  flex-direction: column;
35
46
  overflow: auto;
36
- border-top-left-radius: 32px;
37
- /* TODO: Tokenize */
38
- border-top-right-radius: 32px;
39
- /* TODO: Tokenize */
47
+ border-radius: 32px;
48
+ border-radius: var(--size-32);
49
+ margin-bottom: 8px;
50
+ margin-bottom: var(--size-8);
40
51
  background-color: #ffffff;
41
52
  background-color: var(--color-background-elevated);
42
53
  box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
54
+ will-change: transform;
43
55
  }
44
56
  .np-bottom-sheet-v2-content:focus {
45
57
  outline: none;
@@ -3,13 +3,21 @@ import { userEvent } from '@testing-library/user-event';
3
3
 
4
4
  import { render, mockMatchMedia, mockResizeObserver } from '../test-utils';
5
5
 
6
+ import { useScreenSize } from '../common/hooks/useScreenSize';
6
7
  import { SelectInput, type SelectInputOptionItem, type SelectInputProps } from './SelectInput';
7
8
  import { Field } from '../field/Field';
8
9
 
9
10
  mockMatchMedia();
10
11
  mockResizeObserver();
12
+ jest.mock('../common/hooks/useScreenSize');
11
13
 
12
14
  describe('SelectInput', () => {
15
+ beforeEach(() => {
16
+ (useScreenSize as jest.Mock).mockReturnValue(true);
17
+ });
18
+
19
+ afterEach(jest.clearAllMocks);
20
+
13
21
  it('renders placeholder', () => {
14
22
  render(
15
23
  <SelectInput
@@ -309,4 +317,29 @@ describe('SelectInput', () => {
309
317
  expect(listBox).not.toHaveAttribute('aria-labelledby');
310
318
  });
311
319
  });
320
+
321
+ describe('smooth scroll reset', () => {
322
+ const options: SelectInputOptionItem[] = [
323
+ { type: 'option', value: 'Banana' },
324
+ { type: 'option', value: 'Orange' },
325
+ { type: 'option', value: 'Olive' },
326
+ ];
327
+
328
+ beforeEach(() => {
329
+ (useScreenSize as jest.Mock).mockReturnValue(false);
330
+ });
331
+
332
+ afterEach(jest.clearAllMocks);
333
+
334
+ it('toggles scroll-resetting class', async () => {
335
+ render(<SelectInput items={options} />);
336
+ expect(document.documentElement).not.toHaveClass('wds-select-input-scroll-freeze');
337
+
338
+ await userEvent.click(screen.getByRole('combobox'));
339
+ expect(document.documentElement).toHaveClass('wds-select-input-scroll-freeze');
340
+
341
+ await userEvent.click(document.documentElement);
342
+ expect(document.documentElement).not.toHaveClass('wds-select-input-scroll-freeze');
343
+ });
344
+ });
312
345
  });
@@ -516,97 +516,3 @@ export const WithinModal: Story<Currency> = {
516
516
  },
517
517
  ],
518
518
  };
519
-
520
- interface Country {
521
- code: string;
522
- name: string;
523
- }
524
-
525
- const countries: Country[] = [
526
- { code: 'US', name: 'United States' },
527
- { code: 'GB', name: 'United Kingdom' },
528
- { code: 'CA', name: 'Canada' },
529
- { code: 'AU', name: 'Australia' },
530
- { code: 'DE', name: 'Germany' },
531
- { code: 'FR', name: 'France' },
532
- { code: 'JP', name: 'Japan' },
533
- { code: 'BR', name: 'Brazil' },
534
- { code: 'IN', name: 'India' },
535
- { code: 'CN', name: 'China' },
536
- { code: 'IT', name: 'Italy' },
537
- { code: 'ES', name: 'Spain' },
538
- { code: 'NL', name: 'Netherlands' },
539
- { code: 'CH', name: 'Switzerland' },
540
- { code: 'SE', name: 'Sweden' },
541
- ];
542
-
543
- function countryOption(country: Country) {
544
- return {
545
- type: 'option',
546
- value: country.code,
547
- filterMatchers: [country.code, country.name],
548
- } satisfies SelectInputItem;
549
- }
550
-
551
- export const WithAutocomplete: Story<string> = {
552
- args: {
553
- name: 'country',
554
- autocomplete: 'country-name',
555
- placeholder: 'Select your country',
556
- items: countries.map(countryOption),
557
- renderValue: (countryCode, withinTrigger) => {
558
- const country = countries.find((c) => c.code === countryCode);
559
- return (
560
- <SelectInputOptionContent
561
- title={withinTrigger ? countryCode : country?.name || countryCode}
562
- note={withinTrigger ? undefined : countryCode}
563
- icon={<Flag code={countryCode} intrinsicSize={24} />}
564
- />
565
- );
566
- },
567
- filterable: true,
568
- filterPlaceholder: 'Type a country name',
569
- size: 'lg',
570
- },
571
- render: function Render({ onChange, onClear, ...args }) {
572
- const [selectedCountry, setSelectedCountry] = useState<string | undefined>(undefined);
573
-
574
- return (
575
- <div>
576
- <form
577
- method="post"
578
- onSubmit={(e) => {
579
- e.preventDefault();
580
- console.log(
581
- `Form submitted with country: ${selectedCountry}. This saves data for browser autocomplete!`,
582
- );
583
- }}
584
- >
585
- <div>
586
- <label htmlFor="country-select" className="block text-sm font-medium mb-2">
587
- Country Selection with Autocomplete:
588
- </label>
589
- <SelectInput
590
- {...args}
591
- id="country-select"
592
- value={selectedCountry}
593
- onChange={(country) => {
594
- setSelectedCountry(country);
595
- onChange?.(country);
596
- console.log('Country selected via SelectInput:', country);
597
- }}
598
- onClear={() => {
599
- setSelectedCountry(undefined);
600
- onClear?.();
601
- }}
602
- />
603
- </div>
604
-
605
- <Button type="submit" v2 className="m-t-2" data-testid="submit-btn">
606
- Submit Form
607
- </Button>
608
- </form>
609
- </div>
610
- );
611
- },
612
- };
@@ -0,0 +1,83 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { fn, type Mock, userEvent, within } from 'storybook/test';
3
+ import { allModes } from '../../.storybook/modes';
4
+ import { lorem5, lorem500 } from '../test-utils';
5
+ import { Field } from '../field/Field';
6
+ import Body from '../body';
7
+ import { SelectInput, type SelectInputProps } from './SelectInput';
8
+
9
+ const meta = {
10
+ title: 'Forms/SelectInput/tests',
11
+ component: SelectInput,
12
+ args: {
13
+ onFilterChange: fn() satisfies Mock,
14
+ onChange: fn() satisfies Mock,
15
+ onClose: fn() satisfies Mock,
16
+ onOpen: fn() satisfies Mock,
17
+ },
18
+ tags: ['!autodocs'],
19
+ } satisfies Meta<typeof SelectInput>;
20
+ export default meta;
21
+
22
+ type Story<T, M extends boolean = false> = StoryObj<SelectInputProps<T, M>>;
23
+
24
+ const wait = async (duration = 500) =>
25
+ new Promise<void>((resolve) => {
26
+ setTimeout(resolve, duration);
27
+ });
28
+
29
+ /**
30
+ * This test ensures that when the SelectInput is used within a scrollable page,
31
+ * opening the dropdown does not cause any unwanted scrolling or layout shifts.
32
+ * Expected preview should start with green bar at the top, with yellow section
33
+ * not in the viewport.
34
+ *
35
+ * NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
36
+ */
37
+ export const SmoothScrollReset: Story<string> = {
38
+ args: {
39
+ items: Array.from({ length: 15 }).map((_, id) => ({
40
+ type: 'option',
41
+ value: `option ${id + 1}`,
42
+ })),
43
+ placeholder: 'Select option',
44
+ },
45
+ decorators: [
46
+ (Story) => (
47
+ <>
48
+ <style>{`html { scroll-behavior: smooth; }`}</style>
49
+ <div>
50
+ <div
51
+ className="d-flex align-items-center justify-content-center"
52
+ style={{
53
+ backgroundColor: 'var(--color-bright-yellow)',
54
+ height: 400,
55
+ }}
56
+ >
57
+ This block should not be in the viewport.
58
+ </div>
59
+ <div style={{ height: 10, backgroundColor: 'var(--color-bright-green)' }} />
60
+ <Field id="el1" label={lorem5}>
61
+ <Story />
62
+ </Field>
63
+ <Body as="p">{lorem500}</Body>
64
+ </div>
65
+ </>
66
+ ),
67
+ ],
68
+ play: async ({ canvasElement }) => {
69
+ document.documentElement.scrollTop = 400;
70
+ await wait();
71
+ const canvas = within(canvasElement);
72
+ const triggerButton = canvas.getByRole('combobox');
73
+ await userEvent.click(triggerButton);
74
+ },
75
+ globals: {
76
+ viewport: { value: allModes.largeMobile.viewport, isRotated: false },
77
+ },
78
+ parameters: {
79
+ chromatic: {
80
+ disableSnapshot: true,
81
+ },
82
+ },
83
+ };
@@ -155,25 +155,6 @@ export interface SelectInputProps<T = string, M extends boolean = false> {
155
155
  multiple?: M;
156
156
  placeholder?: string;
157
157
  items: readonly SelectInputItem<NonNullable<T>>[];
158
- /**
159
- * Enables browser autocomplete integration through the search input.
160
- * Accepts standard HTML autocomplete values (e.g., "country-name", "address-level1").
161
- *
162
- * Requires `filterable={true}` to enable the search input.
163
- *
164
- * @example
165
- * <SelectInput
166
- * name="country"
167
- * autocomplete="country-name"
168
- * filterable={true}
169
- * items={[{
170
- * type: 'option',
171
- * value: 'GB',
172
- * filterMatchers: ['United Kingdom', 'UK']
173
- * }]}
174
- * />
175
- */
176
- autocomplete?: string;
177
158
  defaultValue?: M extends true ? readonly T[] : T;
178
159
  value?: M extends true ? readonly T[] : T;
179
160
  compareValues?:
@@ -276,7 +257,6 @@ export function SelectInput<T = string, M extends boolean = false>({
276
257
  name,
277
258
  multiple,
278
259
  placeholder,
279
- autocomplete,
280
260
  items,
281
261
  defaultValue,
282
262
  value: controlledValue,
@@ -477,15 +457,7 @@ export function SelectInput<T = string, M extends boolean = false>({
477
457
  searchInputRef={searchInputRef}
478
458
  listboxRef={listboxRef}
479
459
  filterQuery={deferredFilterQuery}
480
- autocomplete={autocomplete}
481
- name={name}
482
460
  onFilterChange={setFilterQuery}
483
- onAutocompleteSelect={(matchedValue) => {
484
- onChange?.(matchedValue as M extends true ? T[] : T);
485
- if (!multiple) {
486
- setOpen(false);
487
- }
488
- }}
489
461
  {...getListBoxLabelProps()}
490
462
  />
491
463
  </OptionsOverlay>
@@ -593,9 +565,6 @@ interface SelectInputOptionsProps<T = string>
593
565
  onFilterChange: (query: string) => void;
594
566
  listBoxLabel?: string;
595
567
  listBoxLabelledBy?: string;
596
- autocomplete?: string;
597
- name?: string;
598
- onAutocompleteSelect?: (value: T) => void;
599
568
  }
600
569
 
601
570
  function SelectInputOptions<T = string>({
@@ -612,9 +581,6 @@ function SelectInputOptions<T = string>({
612
581
  onFilterChange,
613
582
  listBoxLabel,
614
583
  listBoxLabelledBy,
615
- autocomplete,
616
- name,
617
- onAutocompleteSelect,
618
584
  }: SelectInputOptionsProps<T>) {
619
585
  const intl = useIntl();
620
586
  const virtualiserHandlerRef = useRef<VirtualizerHandle>(null);
@@ -698,35 +664,6 @@ function SelectInputOptions<T = string>({
698
664
  );
699
665
  };
700
666
 
701
- const findMatchingItem = (autocompleteValue: string): T | null => {
702
- const flatOptions = items
703
- .flatMap((item) =>
704
- item.type === 'group' ? item.options : item.type === 'option' ? [item] : [],
705
- )
706
- .filter(
707
- (item): item is SelectInputOptionItem<NonNullable<T>> =>
708
- item.type === 'option' && item.value != null,
709
- );
710
-
711
- const exactMatch = flatOptions.find(
712
- (option) =>
713
- String(option.value) === autocompleteValue ||
714
- option.filterMatchers?.some((matcher) => matcher === autocompleteValue),
715
- );
716
-
717
- if (exactMatch) {
718
- return exactMatch.value;
719
- }
720
-
721
- const fuzzyMatch = flatOptions.find((option) =>
722
- option.filterMatchers?.some((matcher) =>
723
- matcher.toLowerCase().includes(autocompleteValue.toLowerCase()),
724
- ),
725
- );
726
-
727
- return fuzzyMatch ? fuzzyMatch.value : null;
728
- };
729
-
730
667
  return (
731
668
  <ListboxBase.Options
732
669
  as={SelectInputOptionsContainer}
@@ -747,8 +684,6 @@ function SelectInputOptions<T = string>({
747
684
  <SearchInput
748
685
  ref={searchInputRef}
749
686
  id={id}
750
- name={name}
751
- autoComplete={autocomplete}
752
687
  role="combobox"
753
688
  shape="rectangle"
754
689
  placeholder={filterPlaceholder}
@@ -768,26 +703,8 @@ function SelectInputOptions<T = string>({
768
703
  onChange={(event) => {
769
704
  // Free up resources and ensure not to go out of bounds when the
770
705
  // resulting item count is less than before
771
- const inputValue = event.currentTarget.value;
772
-
773
- // Free up resources and ensure not to go out of bounds
774
706
  setMountedIndexes([]);
775
- onFilterChange(inputValue);
776
- }}
777
- onInput={(event) => {
778
- const inputValue = event.currentTarget.value;
779
- const inputElement = event.currentTarget;
780
-
781
- if (autocomplete && onAutocompleteSelect && inputValue) {
782
- setTimeout(() => {
783
- if (inputElement.value === inputValue && inputValue.length > 2) {
784
- const matchedValue = findMatchingItem(inputValue);
785
- if (matchedValue !== null) {
786
- onAutocompleteSelect(matchedValue);
787
- }
788
- }
789
- }, 50);
790
- }
707
+ onFilterChange(event.currentTarget.value);
791
708
  }}
792
709
  />
793
710
  </div>