@transferwise/components 46.160.5 → 46.160.6

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 (93) hide show
  1. package/build/ExpressiveMoneyInput/AmountInput/AmountInput.js +2 -0
  2. package/build/ExpressiveMoneyInput/AmountInput/AmountInput.js.map +1 -1
  3. package/build/ExpressiveMoneyInput/AmountInput/AmountInput.mjs +2 -0
  4. package/build/ExpressiveMoneyInput/AmountInput/AmountInput.mjs.map +1 -1
  5. package/build/ExpressiveMoneyInput/hooks/useInputStyle.js +1 -1
  6. package/build/ExpressiveMoneyInput/hooks/useInputStyle.js.map +1 -1
  7. package/build/ExpressiveMoneyInput/hooks/useInputStyle.mjs +1 -1
  8. package/build/ExpressiveMoneyInput/hooks/useInputStyle.mjs.map +1 -1
  9. package/build/Inputs/Input/Input.js +1 -0
  10. package/build/Inputs/Input/Input.js.map +1 -1
  11. package/build/Inputs/Input/Input.mjs +1 -0
  12. package/build/Inputs/Input/Input.mjs.map +1 -1
  13. package/build/Inputs/TextArea/TextArea.js +1 -0
  14. package/build/Inputs/TextArea/TextArea.js.map +1 -1
  15. package/build/Inputs/TextArea/TextArea.mjs +1 -0
  16. package/build/Inputs/TextArea/TextArea.mjs.map +1 -1
  17. package/build/MoneyInput/MoneyInput.js +1 -0
  18. package/build/MoneyInput/MoneyInput.js.map +1 -1
  19. package/build/MoneyInput/MoneyInput.mjs +1 -0
  20. package/build/MoneyInput/MoneyInput.mjs.map +1 -1
  21. package/build/PhoneNumberInput/PhoneNumberInput.js +3 -2
  22. package/build/PhoneNumberInput/PhoneNumberInput.js.map +1 -1
  23. package/build/PhoneNumberInput/PhoneNumberInput.messages.js +3 -0
  24. package/build/PhoneNumberInput/PhoneNumberInput.messages.js.map +1 -1
  25. package/build/PhoneNumberInput/PhoneNumberInput.messages.mjs +3 -0
  26. package/build/PhoneNumberInput/PhoneNumberInput.messages.mjs.map +1 -1
  27. package/build/PhoneNumberInput/PhoneNumberInput.mjs +3 -2
  28. package/build/PhoneNumberInput/PhoneNumberInput.mjs.map +1 -1
  29. package/build/Typeahead/TypeaheadInput/TypeaheadInput.js +50 -20
  30. package/build/Typeahead/TypeaheadInput/TypeaheadInput.js.map +1 -1
  31. package/build/Typeahead/TypeaheadInput/TypeaheadInput.mjs +50 -20
  32. package/build/Typeahead/TypeaheadInput/TypeaheadInput.mjs.map +1 -1
  33. package/build/i18n/en.json +1 -0
  34. package/build/i18n/en.json.js +1 -0
  35. package/build/i18n/en.json.js.map +1 -1
  36. package/build/i18n/en.json.mjs +1 -0
  37. package/build/i18n/en.json.mjs.map +1 -1
  38. package/build/main.css +51 -1
  39. package/build/styles/ExpressiveMoneyInput/AmountInput/AmountInput.css +6 -0
  40. package/build/styles/ExpressiveMoneyInput/ExpressiveMoneyInput.css +6 -0
  41. package/build/styles/Inputs/Input/Input.css +19 -0
  42. package/build/styles/Inputs/TextArea/TextArea.css +16 -1
  43. package/build/styles/MoneyInput/MoneyInput.css +3 -0
  44. package/build/styles/PhoneNumberInput/PhoneNumberInput.css +7 -0
  45. package/build/styles/main.css +51 -1
  46. package/build/types/ExpressiveMoneyInput/AmountInput/AmountInput.d.ts.map +1 -1
  47. package/build/types/ExpressiveMoneyInput/hooks/useInputStyle.d.ts.map +1 -1
  48. package/build/types/Inputs/Input/Input.d.ts.map +1 -1
  49. package/build/types/Inputs/TextArea/TextArea.d.ts.map +1 -1
  50. package/build/types/MoneyInput/MoneyInput.d.ts.map +1 -1
  51. package/build/types/PhoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  52. package/build/types/PhoneNumberInput/PhoneNumberInput.messages.d.ts +5 -0
  53. package/build/types/PhoneNumberInput/PhoneNumberInput.messages.d.ts.map +1 -1
  54. package/build/types/Typeahead/TypeaheadInput/TypeaheadInput.d.ts +1 -1
  55. package/build/types/Typeahead/TypeaheadInput/TypeaheadInput.d.ts.map +1 -1
  56. package/build/types/test-utils/index.d.ts +2 -0
  57. package/build/types/test-utils/index.d.ts.map +1 -1
  58. package/package.json +1 -1
  59. package/src/ExpressiveMoneyInput/AmountInput/AmountInput.css +6 -0
  60. package/src/ExpressiveMoneyInput/AmountInput/AmountInput.less +7 -0
  61. package/src/ExpressiveMoneyInput/AmountInput/AmountInput.tsx +2 -1
  62. package/src/ExpressiveMoneyInput/ExpressiveMoneyInput.css +6 -0
  63. package/src/ExpressiveMoneyInput/hooks/useInputStyle.ts +1 -2
  64. package/src/Field/_stories/Field.test.story.tsx +27 -0
  65. package/src/Inputs/Input/Input.css +19 -0
  66. package/src/Inputs/Input/Input.less +16 -0
  67. package/src/Inputs/Input/Input.tsx +1 -0
  68. package/src/Inputs/{_stories → InputGroup/_stories}/InputGroup.story.tsx +9 -9
  69. package/src/Inputs/InputGroup/_stories/InputGroup.test.story.tsx +80 -0
  70. package/src/Inputs/{_stories → SearchInput/_stories}/SearchInput.story.tsx +4 -4
  71. package/src/Inputs/SearchInput/_stories/SearchInput.test.story.tsx +38 -0
  72. package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +31 -19
  73. package/src/Inputs/TextArea/TextArea.css +16 -1
  74. package/src/Inputs/TextArea/TextArea.less +6 -1
  75. package/src/Inputs/TextArea/TextArea.tsx +1 -0
  76. package/src/Inputs/{_stories → TextArea/_stories}/TextArea.story.tsx +4 -4
  77. package/src/Inputs/{_stories → TextArea/_stories}/TextArea.test.story.tsx +50 -26
  78. package/src/MoneyInput/MoneyInput.css +3 -0
  79. package/src/MoneyInput/MoneyInput.less +6 -0
  80. package/src/MoneyInput/MoneyInput.tsx +1 -0
  81. package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +14 -10
  82. package/src/PhoneNumberInput/PhoneNumberInput.css +7 -0
  83. package/src/PhoneNumberInput/PhoneNumberInput.less +13 -0
  84. package/src/PhoneNumberInput/PhoneNumberInput.messages.ts +5 -0
  85. package/src/PhoneNumberInput/PhoneNumberInput.tsx +3 -2
  86. package/src/PhoneNumberInput/_stories/PhoneNumberInput.rtl.test.story.tsx +15 -7
  87. package/src/TextareaWithDisplayFormat/_stories/TextareaWithDisplayFormat.test.story.tsx +49 -34
  88. package/src/Typeahead/TypeaheadInput/TypeaheadInput.tsx +31 -20
  89. package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +90 -57
  90. package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +8 -1
  91. package/src/main.css +51 -1
  92. package/src/Inputs/_stories/InputGroup.test.story.tsx +0 -69
  93. package/src/Inputs/_stories/SearchInput.test.story.tsx +0 -32
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { userEvent, within } from 'storybook/test';
3
3
  import { Flag } from '@wise/art';
4
4
 
5
- import { withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
5
+ import { useRtlDiffI18n, withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
6
6
  import { SelectInput, SelectInputOptionContent } from '..';
7
7
 
8
8
  export default {
@@ -108,28 +108,40 @@ const groupedItems = [
108
108
  ];
109
109
 
110
110
  export const OpenDropdown: Story = {
111
- render: () => (
112
- <SelectInput
113
- size="lg"
114
- filterable
115
- filterPlaceholder="Type a currency / country"
116
- placeholder="Select currency"
117
- defaultValue={rtlCurrencies[0]}
118
- items={groupedItems}
119
- renderValue={(currency, withinTrigger) => (
120
- <SelectInputOptionContent
121
- title={currency.code}
122
- note={withinTrigger ? undefined : currency.name}
123
- icon={<Flag code={currency.code} intrinsicSize={24} />}
124
- />
125
- )}
126
- />
127
- ),
111
+ render: () => {
112
+ const i18n = useRtlDiffI18n();
113
+ return (
114
+ <SelectInput
115
+ size="lg"
116
+ filterable
117
+ filterPlaceholder={i18n.filterPlaceholder}
118
+ placeholder="Select currency"
119
+ defaultValue={rtlCurrencies[0]}
120
+ items={groupedItems}
121
+ renderValue={(currency, withinTrigger) => (
122
+ <SelectInputOptionContent
123
+ title={currency.code}
124
+ note={withinTrigger ? undefined : currency.name}
125
+ icon={<Flag code={currency.code} intrinsicSize={24} />}
126
+ />
127
+ )}
128
+ />
129
+ );
130
+ },
128
131
  play: async ({ canvasElement }) => {
129
132
  const canvas = within(canvasElement);
130
133
  const trigger = canvas.queryByRole('combobox');
131
134
  if (!trigger) return;
132
135
  await userEvent.click(trigger);
133
136
  },
134
- ...withRTLDiff({ renderAs: 'iframe', width: '80%' }),
137
+ ...withRTLDiff({
138
+ renderAs: 'iframe',
139
+ width: '80%',
140
+ i18n: {
141
+ filterPlaceholder: {
142
+ ltr: 'Type a currency / country',
143
+ rtl: 'اكتب عملة / دولة',
144
+ },
145
+ },
146
+ }),
135
147
  };
@@ -154,7 +154,22 @@
154
154
  color: #768e9c;
155
155
  color: var(--color-content-tertiary);
156
156
  }
157
- .np-text-area::placeholder {
157
+ .np-text-area:-moz-placeholder {
158
158
  color: #768e9c;
159
159
  color: var(--color-content-tertiary);
160
160
  }
161
+ .np-text-area::placeholder,
162
+ .np-text-area:placeholder-shown {
163
+ color: #768e9c;
164
+ color: var(--color-content-tertiary);
165
+ }
166
+ [dir="rtl"] .np-text-area::-moz-placeholder {
167
+ direction: rtl !important;
168
+ }
169
+ [dir="rtl"] .np-text-area:-moz-placeholder {
170
+ direction: rtl !important;
171
+ }
172
+ [dir="rtl"] .np-text-area::placeholder,
173
+ [dir="rtl"] .np-text-area:placeholder-shown {
174
+ direction: rtl !important;
175
+ }
@@ -7,7 +7,12 @@
7
7
  overscroll-behavior: none;
8
8
  border-radius: var(--radius-small) !important;
9
9
 
10
- &::placeholder {
10
+ &::placeholder,
11
+ &:placeholder-shown{
11
12
  color: var(--color-content-tertiary);
13
+
14
+ [dir="rtl"] & {
15
+ direction: rtl !important;
16
+ }
12
17
  }
13
18
  }
@@ -25,6 +25,7 @@ export const TextArea = forwardRef(function TextArea(
25
25
  return (
26
26
  <textarea
27
27
  ref={reference}
28
+ dir="auto"
28
29
  className={clsx(className, inputClassNameBase(), 'np-text-area')}
29
30
  maxLength={maxLength}
30
31
  {...inputAttributes}
@@ -4,10 +4,10 @@ import { Meta, StoryObj } from '@storybook/react-webpack5';
4
4
  import {
5
5
  createSandboxStory,
6
6
  globalScope,
7
- } from '../../../.storybook/components/sandbox/SandboxEditor';
8
- import Field from '../../Field';
9
- import { Sentiment } from '../../common';
10
- import { TextArea } from '../TextArea/TextArea';
7
+ } from '../../../../.storybook/components/sandbox/SandboxEditor';
8
+ import Field from '../../../Field';
9
+ import { Sentiment } from '../../../common';
10
+ import { TextArea } from '../TextArea';
11
11
 
12
12
  /**
13
13
  * TextArea must be the only input with `maxLength` inside a given Field.
@@ -2,10 +2,10 @@ import { useState } from 'react';
2
2
  import { userEvent, within } from 'storybook/test';
3
3
  import { Meta, StoryObj } from '@storybook/react-webpack5';
4
4
 
5
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
6
- import Field from '../../Field';
7
- import { Sentiment } from '../../common';
8
- import { TextArea } from '../TextArea/TextArea';
5
+ import { useRtlDiffI18n, withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
6
+ import Field from '../../../Field';
7
+ import { Sentiment } from '../../../common';
8
+ import { TextArea } from '../TextArea';
9
9
 
10
10
  const meta: Meta<typeof TextArea> = {
11
11
  title: 'Forms/TextArea/Tests',
@@ -144,26 +144,50 @@ export const CJKTypingBlocked: Story = {
144
144
  };
145
145
 
146
146
  export const RTLDiff: Story = {
147
- render: () => (
148
- <>
149
- <Field label="Message" required={false}>
150
- <TextArea placeholder="Type something..." />
151
- </Field>
152
- <Field label="Message" required={false}>
153
- <TextArea value="This is some entered text content in the textarea field." readOnly />
154
- </Field>
155
- <Field
156
- label="Message"
157
- required={false}
158
- sentiment={Sentiment.NEGATIVE}
159
- message="This field has an error message"
160
- >
161
- <TextArea value="Invalid input text" readOnly />
162
- </Field>
163
- <Field label="Message with character count" required={false}>
164
- <TextArea maxLength={200} value="Text with a character counter displayed below." readOnly />
165
- </Field>
166
- </>
167
- ),
168
- ...withRTLDiff(),
147
+ render: () => {
148
+ const i18n = useRtlDiffI18n();
149
+
150
+ return (
151
+ <>
152
+ <Field label="Localised placeholder">
153
+ <TextArea placeholder={i18n.placeholder} />
154
+ </Field>
155
+ <Field label="Localised value">
156
+ <TextArea value={i18n.value_ar} readOnly />
157
+ </Field>
158
+ <Field label="LTR value">
159
+ <TextArea value={i18n.value_en} readOnly />
160
+ </Field>
161
+ <Field label="Message" sentiment={Sentiment.NEGATIVE} message={i18n.errorMessage}>
162
+ <TextArea value={i18n.invalidInputText} readOnly />
163
+ </Field>
164
+ <Field label="Message with character count">
165
+ <TextArea maxLength={200} value={i18n.characterCounter} readOnly />
166
+ </Field>
167
+ </>
168
+ );
169
+ },
170
+ ...withRTLDiff({
171
+ width: 'stretch',
172
+ i18n: {
173
+ placeholder: { ltr: 'Translated placeholder...', rtl: 'نص بديل مترجم...' },
174
+ value_en: {
175
+ ltr: 'This is LTR text content in the RTL textarea field, showing the input adapting to the content rather than page setting.',
176
+ rtl: 'This is LTR text content in the RTL textarea field, showing the input adapting to the content rather than page setting.',
177
+ },
178
+ value_ar: {
179
+ ltr: 'This is some entered text content in the textarea field.',
180
+ rtl: 'هذا هو بعض المحتوى النصي المدخل في حقل منطقة النص.',
181
+ },
182
+ errorMessage: {
183
+ ltr: 'This field has an error message',
184
+ rtl: 'هذا الحقل يحتوي على رسالة خطأ',
185
+ },
186
+ invalidInputText: { ltr: 'Invalid input text', rtl: 'نص الإدخال غير صالح' },
187
+ characterCounter: {
188
+ ltr: 'Text with a character counter displayed below.',
189
+ rtl: 'نص مع عداد أحرف معروض أدناه.',
190
+ },
191
+ },
192
+ }),
169
193
  };
@@ -10,6 +10,9 @@
10
10
  font-weight: 600;
11
11
  font-weight: var(--font-weight-semi-bold);
12
12
  }
13
+ [dir="rtl"] .tw-money-input .money-input__number-input {
14
+ text-align: end;
15
+ }
13
16
  .tw-money-input .money-input-currency-flag {
14
17
  display: flex;
15
18
  align-items: center;
@@ -11,6 +11,12 @@
11
11
  }
12
12
  }
13
13
 
14
+ .money-input__number-input{
15
+ [dir="rtl"] & {
16
+ text-align: end;
17
+ }
18
+ }
19
+
14
20
  .money-input-currency-flag {
15
21
  display: flex;
16
22
  align-items: center;
@@ -367,6 +367,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
367
367
  locale: this.state.locale,
368
368
  decimals: this.props.decimals,
369
369
  })}
370
+ className="money-input__number-input"
370
371
  autoComplete="off"
371
372
  aria-describedby={selectedCurrencyElementId}
372
373
  onKeyDown={this.handleKeyDown}
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { userEvent, within } from 'storybook/test';
3
3
 
4
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
5
  import Field from '../../Field/Field';
6
6
  import MoneyInput from '..';
7
7
 
@@ -70,19 +70,23 @@ export const TriggerVariants: Story = {
70
70
  };
71
71
 
72
72
  export const OpenDropdown: Story = {
73
- render: () => (
74
- <MoneyInput
75
- {...sharedProps}
76
- size="lg"
77
- currencies={multipleCurrencies}
78
- selectedCurrency={eurCurrency}
79
- />
80
- ),
73
+ render: () => {
74
+ const i18n = useRtlDiffI18n();
75
+ return (
76
+ <MoneyInput
77
+ {...sharedProps}
78
+ size="lg"
79
+ currencies={multipleCurrencies}
80
+ selectedCurrency={eurCurrency}
81
+ searchPlaceholder={i18n.searchPlaceholder}
82
+ />
83
+ );
84
+ },
81
85
  play: async ({ canvasElement }) => {
82
86
  const canvas = within(canvasElement);
83
87
  const trigger = canvas.queryByRole('combobox');
84
88
  if (!trigger) return;
85
89
  await userEvent.click(trigger);
86
90
  },
87
- ...withRTLDiff({ renderAs: 'iframe', width: '40%' }),
91
+ ...withRTLDiff({ renderAs: 'iframe', width: '40%', i18n: { searchPlaceholder: { ltr: 'Search currencies or countries', rtl: 'ابحث عن العملات أو الدول' } } }),
88
92
  };
@@ -5,6 +5,9 @@
5
5
  margin-inline-start: 12px;
6
6
  margin-inline-start: var(--size-12);
7
7
  }
8
+ [dir="rtl"] .tw-telephone__number-input-field {
9
+ text-align: end;
10
+ }
8
11
  .tw-telephone__country-select {
9
12
  flex-basis: 120px;
10
13
  flex-shrink: 0;
@@ -12,6 +15,10 @@
12
15
  .tw-telephone__country-select .np-input-group {
13
16
  inline-size: 100%;
14
17
  }
18
+ [dir="rtl"] .tw-telephone__country-select .np-select-input-content {
19
+ text-align: end;
20
+ direction: ltr;
21
+ }
15
22
  .tw-telephone__country-select--with-input-group-addon-start .np-button-input {
16
23
  padding-inline-start: 48px;
17
24
  padding-inline-start: var(--size-48);
@@ -6,6 +6,12 @@
6
6
  .tw-telephone__number-input {
7
7
  margin-left: var(--size-12);
8
8
  }
9
+
10
+ &__number-input-field{
11
+ [dir="rtl"] & {
12
+ text-align: end;
13
+ }
14
+ }
9
15
  }
10
16
 
11
17
  .tw-telephone__country-select {
@@ -15,6 +21,13 @@
15
21
  .np-input-group {
16
22
  width: 100%;
17
23
  }
24
+
25
+ .np-select-input-content{
26
+ [dir="rtl"] & {
27
+ text-align: end;
28
+ direction: ltr;
29
+ }
30
+ }
18
31
  }
19
32
 
20
33
  .tw-telephone__country-select--with-input-group-addon-start {
@@ -13,4 +13,9 @@ export default defineMessages({
13
13
  id: 'neptune.PhoneNumberInput.phoneNumberLabel',
14
14
  defaultMessage: 'Phone number',
15
15
  },
16
+ phoneNumberPrefix: {
17
+ id: 'neptune.PhoneNumberInput.phoneNumberPrefix',
18
+ defaultMessage: 'Prefix',
19
+ description: 'phone number prefix / country code',
20
+ },
16
21
  });
@@ -59,7 +59,7 @@ const PhoneNumberInput = ({
59
59
  onFocus,
60
60
  onBlur,
61
61
  countryCode,
62
- searchPlaceholder = 'Prefix',
62
+ searchPlaceholder,
63
63
  size = Size.MEDIUM,
64
64
  placeholder,
65
65
  selectProps = defaultSelectProps,
@@ -232,7 +232,7 @@ const PhoneNumberInput = ({
232
232
  />
233
233
  )}
234
234
  filterable
235
- filterPlaceholder={searchPlaceholder}
235
+ filterPlaceholder={searchPlaceholder ?? formatMessage(messages.phoneNumberPrefix)}
236
236
  disabled={disabled}
237
237
  size={size}
238
238
  id={ids.countryCode.select}
@@ -261,6 +261,7 @@ const PhoneNumberInput = ({
261
261
  <div className={`input-group input-group-${size} ${disabled ? 'disabled' : ''}`}>
262
262
  <Input
263
263
  ref={phoneNumberInputRef}
264
+ className="tw-telephone__number-input-field"
264
265
  id={ids.phoneNumber.input}
265
266
  autoComplete="tel-national"
266
267
  name="phoneNumber"
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { userEvent, within } from 'storybook/test';
3
3
 
4
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
5
  import Field from '../../Field/Field';
6
6
  import PhoneNumberInput from '..';
7
7
 
@@ -37,16 +37,24 @@ export const Sizes: Story = {
37
37
  };
38
38
 
39
39
  export const DropdownOpen: Story = {
40
- render: () => (
41
- <Field label="Phone number">
42
- <PhoneNumberInput onChange={() => {}} />
43
- </Field>
44
- ),
40
+ render: () => {
41
+ const i18n = useRtlDiffI18n();
42
+
43
+ return (
44
+ <Field label="Phone number">
45
+ <PhoneNumberInput searchPlaceholder={i18n.searchPlaceholder} onChange={() => {}} />
46
+ </Field>
47
+ );
48
+ },
45
49
  play: async ({ canvasElement }) => {
46
50
  const canvas = within(canvasElement);
47
51
  const trigger = canvas.queryByRole('combobox');
48
52
  if (!trigger) return;
49
53
  await userEvent.click(trigger);
50
54
  },
51
- ...withRTLDiff({ renderAs: 'iframe', hAlign: 'center' }),
55
+ ...withRTLDiff({
56
+ renderAs: 'iframe',
57
+ hAlign: 'center',
58
+ i18n: { searchPlaceholder: { ltr: 'Country code', rtl: 'رمز الدولة' } },
59
+ }),
52
60
  };
@@ -1,8 +1,8 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
- import TextareaWithDisplayFormat from '..';
3
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
4
  import Field from '../../Field/Field';
5
+ import TextareaWithDisplayFormat from '..';
6
6
 
7
7
  export default {
8
8
  component: TextareaWithDisplayFormat,
@@ -13,36 +13,51 @@ export default {
13
13
  type Story = StoryObj<typeof TextareaWithDisplayFormat>;
14
14
 
15
15
  export const RTLDiff: Story = {
16
- render: () => (
17
- <>
18
- <Field id="card-code" label="Gift card code">
19
- <TextareaWithDisplayFormat
20
- id="card-code"
21
- value="1234567890123456"
22
- maxLength={16}
23
- displayPattern="**** - **** - ****"
24
- onChange={() => {}}
25
- />
26
- </Field>
27
- <Field id="iban" label="IBAN">
28
- <TextareaWithDisplayFormat
29
- id="iban"
30
- value="GB29NWBK60161331926819"
31
- maxLength={22}
32
- displayPattern="** **** **** **** **** **"
33
- onChange={() => {}}
34
- />
35
- </Field>
36
- <Field id="empty" label="Empty with placeholder">
37
- <TextareaWithDisplayFormat
38
- id="empty"
39
- value=""
40
- displayPattern="**** - **** - ****"
41
- placeholder="Enter code"
42
- onChange={() => {}}
43
- />
44
- </Field>
45
- </>
46
- ),
47
- ...withRTLDiff(),
16
+ render: () => {
17
+ const i18n = useRtlDiffI18n();
18
+
19
+ return (
20
+ <>
21
+ <Field id="empty" label="Empty with placeholder">
22
+ <TextareaWithDisplayFormat
23
+ id="empty"
24
+ value=""
25
+ displayPattern="**** - **** - ****"
26
+ placeholder={i18n.placeholder}
27
+ onChange={() => {}}
28
+ />
29
+ </Field>
30
+ <Field id="card-code" label="Localised pattern">
31
+ <TextareaWithDisplayFormat
32
+ id="card-code"
33
+ value={i18n.value}
34
+ maxLength={16}
35
+ displayPattern="**** - **** - ****"
36
+ onChange={() => {}}
37
+ />
38
+ </Field>
39
+ <Field id="iban" label="IBAN (not localised)">
40
+ <TextareaWithDisplayFormat
41
+ id="iban"
42
+ value="GB29NWBK60161331926819"
43
+ maxLength={22}
44
+ displayPattern="** **** **** **** **** **"
45
+ onChange={() => {}}
46
+ />
47
+ </Field>
48
+ </>
49
+ );
50
+ },
51
+ ...withRTLDiff({
52
+ i18n: {
53
+ value: {
54
+ ltr: 'XKQMRTBWJNFL',
55
+ rtl: 'خكقمرتبوجنفل',
56
+ },
57
+ placeholder: {
58
+ ltr: 'Enter code',
59
+ rtl: 'أدخل الرمز',
60
+ },
61
+ },
62
+ }),
48
63
  };
@@ -6,6 +6,8 @@ import { Component, createRef, ReactNode } from 'react';
6
6
 
7
7
  import { Input } from '../../Inputs/Input/Input';
8
8
  import { TypeaheadOption, TypeaheadProps } from '../Typeahead';
9
+ import { Direction } from '../../common';
10
+ import { DirectionContext } from '../../Provider/Direction';
9
11
 
10
12
  const DEFAULT_INPUT_MIN_WIDTH = 10;
11
13
 
@@ -67,7 +69,7 @@ export default class TypeaheadInput<T> extends Component<
67
69
  });
68
70
  };
69
71
 
70
- renderInput = () => {
72
+ renderInput = (isRTL: boolean) => {
71
73
  const {
72
74
  typeaheadId,
73
75
  autoFocus,
@@ -90,6 +92,7 @@ export default class TypeaheadInput<T> extends Component<
90
92
  return (
91
93
  <Input
92
94
  ref={this.inputRef}
95
+ dir={isRTL ? 'rtl' : 'auto'}
93
96
  className={clsx(multiple && 'typeahead__input')}
94
97
  name={name}
95
98
  id={`input-${typeaheadId}`}
@@ -116,26 +119,34 @@ export default class TypeaheadInput<T> extends Component<
116
119
  render() {
117
120
  const { multiple, selected, value, maxHeight, renderChip } = this.props;
118
121
 
119
- return multiple ? (
120
- <div
121
- className="form-control typeahead__input-container"
122
- style={{ maxHeight }}
123
- onClick={() => {
124
- this.inputRef.current?.focus();
125
- }}
126
- >
127
- <div className="typeahead__input-wrapper">
128
- {selected && selected.map((chip, idx) => renderChip(chip, idx))}
122
+ return (
123
+ <DirectionContext.Consumer>
124
+ {(direction) => {
125
+ const isRTL = direction === Direction.RTL;
129
126
 
130
- {this.renderInput()}
131
- <div className="typeahead__input-aligner" />
132
- </div>
133
- <div ref={this.sizerRef} className="sizer form-control typeahead__input">
134
- {value}
135
- </div>
136
- </div>
137
- ) : (
138
- this.renderInput()
127
+ return multiple ? (
128
+ <div
129
+ className="form-control typeahead__input-container"
130
+ style={{ maxHeight }}
131
+ onClick={() => {
132
+ this.inputRef.current?.focus();
133
+ }}
134
+ >
135
+ <div className="typeahead__input-wrapper">
136
+ {selected && selected.map((chip, idx) => renderChip(chip, idx))}
137
+
138
+ {this.renderInput(isRTL)}
139
+ <div className="typeahead__input-aligner" />
140
+ </div>
141
+ <div ref={this.sizerRef} className="sizer form-control typeahead__input">
142
+ {value}
143
+ </div>
144
+ </div>
145
+ ) : (
146
+ this.renderInput(isRTL)
147
+ );
148
+ }}
149
+ </DirectionContext.Consumer>
139
150
  );
140
151
  }
141
152
  }