@transferwise/components 46.160.2 → 46.160.4

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 (58) hide show
  1. package/build/FlowNavigation/FlowNavigation.js +6 -4
  2. package/build/FlowNavigation/FlowNavigation.js.map +1 -1
  3. package/build/FlowNavigation/FlowNavigation.mjs +6 -4
  4. package/build/FlowNavigation/FlowNavigation.mjs.map +1 -1
  5. package/build/Inputs/SelectInput/Options/SelectInputOptions.js +33 -5
  6. package/build/Inputs/SelectInput/Options/SelectInputOptions.js.map +1 -1
  7. package/build/Inputs/SelectInput/Options/SelectInputOptions.mjs +34 -6
  8. package/build/Inputs/SelectInput/Options/SelectInputOptions.mjs.map +1 -1
  9. package/build/Inputs/SelectInput/SelectInput.js +28 -4
  10. package/build/Inputs/SelectInput/SelectInput.js.map +1 -1
  11. package/build/Inputs/SelectInput/SelectInput.mjs +29 -5
  12. package/build/Inputs/SelectInput/SelectInput.mjs.map +1 -1
  13. package/build/Inputs/SelectInput/SelectInput.utils.js +0 -2
  14. package/build/Inputs/SelectInput/SelectInput.utils.js.map +1 -1
  15. package/build/Inputs/SelectInput/SelectInput.utils.mjs +1 -2
  16. package/build/Inputs/SelectInput/SelectInput.utils.mjs.map +1 -1
  17. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js +5 -1
  18. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js.map +1 -1
  19. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs +5 -1
  20. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs.map +1 -1
  21. package/build/Inputs/SelectInput/constants.js +8 -0
  22. package/build/Inputs/SelectInput/constants.js.map +1 -0
  23. package/build/Inputs/SelectInput/constants.mjs +5 -0
  24. package/build/Inputs/SelectInput/constants.mjs.map +1 -0
  25. package/build/Inputs/SelectInput/hooks/useTypeahead.js +57 -0
  26. package/build/Inputs/SelectInput/hooks/useTypeahead.js.map +1 -0
  27. package/build/Inputs/SelectInput/hooks/useTypeahead.mjs +54 -0
  28. package/build/Inputs/SelectInput/hooks/useTypeahead.mjs.map +1 -0
  29. package/build/i18n/ja.json +1 -1
  30. package/build/i18n/ja.json.js +1 -1
  31. package/build/i18n/ja.json.mjs +1 -1
  32. package/build/main.css +10 -0
  33. package/build/styles/FlowNavigation/FlowNavigation.css +10 -0
  34. package/build/styles/main.css +10 -0
  35. package/build/types/FlowNavigation/FlowNavigation.d.ts.map +1 -1
  36. package/build/types/Inputs/SelectInput/Options/SelectInputOptions.d.ts +3 -1
  37. package/build/types/Inputs/SelectInput/Options/SelectInputOptions.d.ts.map +1 -1
  38. package/build/types/Inputs/SelectInput/SelectInput.d.ts.map +1 -1
  39. package/build/types/Inputs/SelectInput/SelectInput.utils.d.ts +0 -1
  40. package/build/types/Inputs/SelectInput/SelectInput.utils.d.ts.map +1 -1
  41. package/build/types/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.d.ts.map +1 -1
  42. package/build/types/Inputs/SelectInput/constants.d.ts +3 -0
  43. package/build/types/Inputs/SelectInput/constants.d.ts.map +1 -0
  44. package/build/types/Inputs/SelectInput/hooks/useTypeahead.d.ts +8 -0
  45. package/build/types/Inputs/SelectInput/hooks/useTypeahead.d.ts.map +1 -0
  46. package/package.json +2 -2
  47. package/src/FlowNavigation/FlowNavigation.css +10 -0
  48. package/src/FlowNavigation/FlowNavigation.less +11 -0
  49. package/src/FlowNavigation/FlowNavigation.tsx +6 -4
  50. package/src/Inputs/SelectInput/Options/SelectInputOptions.tsx +36 -6
  51. package/src/Inputs/SelectInput/SelectInput.test.tsx +143 -0
  52. package/src/Inputs/SelectInput/SelectInput.tsx +31 -5
  53. package/src/Inputs/SelectInput/SelectInput.utils.ts +0 -2
  54. package/src/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.tsx +3 -0
  55. package/src/Inputs/SelectInput/constants.ts +3 -0
  56. package/src/Inputs/SelectInput/hooks/useTypeahead.ts +82 -0
  57. package/src/i18n/ja.json +1 -1
  58. package/src/main.css +10 -0
@@ -1,11 +1,13 @@
1
1
  import { CrossCircle } from '@transferwise/icons';
2
2
  import { ListboxOptions } from '@headlessui/react';
3
3
  import { clsx } from 'clsx';
4
- import { useEffect, useId, useMemo, useRef, useState } from 'react';
4
+ import { useDeferredValue, useEffect, useId, useMemo, useRef, useState } from 'react';
5
5
  import { useIntl } from 'react-intl';
6
6
  import { Virtualizer, type VirtualizerHandle } from 'virtua';
7
7
 
8
8
  import { SearchInput } from '../../SearchInput/SearchInput';
9
+ import { MAX_ITEMS_WITHOUT_VIRTUALIZATION } from '../constants';
10
+ import { useTypeahead } from '../hooks/useTypeahead';
9
11
  import {
10
12
  SelectInputItemsCountContext,
11
13
  SelectInputItemPositionContext,
@@ -13,7 +15,6 @@ import {
13
15
  import {
14
16
  dedupeSelectInputItems,
15
17
  filterSelectInputItems,
16
- MAX_ITEMS_WITHOUT_VIRTUALIZATION,
17
18
  searchableString,
18
19
  selectInputOptionItemIncludesNeedle,
19
20
  sortSelectInputItems,
@@ -42,7 +43,9 @@ export interface SelectInputOptionsProps<T = string> extends Pick<
42
43
  searchInputRef: React.MutableRefObject<HTMLInputElement | null>;
43
44
  listboxRef: React.MutableRefObject<HTMLDivElement | null>;
44
45
  filterQuery: string;
46
+ initialTypeaheadKey?: string | null;
45
47
  onFilterChange: (query: string) => void;
48
+ onInitialTypeaheadHandled?: () => void;
46
49
  listBoxLabel?: string;
47
50
  listBoxLabelledBy?: string;
48
51
  autocomplete?: string;
@@ -67,7 +70,9 @@ export function SelectInputOptions<T = string>({
67
70
  searchInputRef,
68
71
  listboxRef,
69
72
  filterQuery,
73
+ initialTypeaheadKey,
70
74
  onFilterChange,
75
+ onInitialTypeaheadHandled,
71
76
  listBoxLabel,
72
77
  listBoxLabelledBy,
73
78
  autocomplete,
@@ -78,13 +83,37 @@ export function SelectInputOptions<T = string>({
78
83
  const virtualiserHandlerRef = useRef<VirtualizerHandle>(null);
79
84
  const controllerRef = filterable ? searchInputRef : listboxRef;
80
85
  const initialRenderRef = useRef(true);
86
+ const deferredFilterQuery = useDeferredValue(filterQuery);
87
+ const handleTypeahead = useTypeahead({
88
+ disabled: filterable,
89
+ onMatch: onInitialTypeaheadHandled,
90
+ });
91
+
92
+ useEffect(() => {
93
+ if (filterable || initialTypeaheadKey == null) {
94
+ return;
95
+ }
96
+
97
+ const animationFrame = requestAnimationFrame(() => {
98
+ if (listboxRef.current == null) {
99
+ return;
100
+ }
101
+
102
+ listboxRef.current.focus({ preventScroll: true });
103
+ listboxRef.current.dispatchEvent(
104
+ new KeyboardEvent('keydown', { key: initialTypeaheadKey, bubbles: true }),
105
+ );
106
+ });
107
+
108
+ return () => cancelAnimationFrame(animationFrame);
109
+ }, [filterable, initialTypeaheadKey, listboxRef]);
81
110
 
82
111
  const needle = useMemo(() => {
83
112
  if (filterable) {
84
- return filterQuery ? searchableString(filterQuery) : null;
113
+ return deferredFilterQuery ? searchableString(deferredFilterQuery) : null;
85
114
  }
86
115
  return undefined;
87
- }, [filterQuery, filterable]);
116
+ }, [deferredFilterQuery, filterable]);
88
117
  useEffect(() => {
89
118
  if (needle) {
90
119
  // Ensure having an active option while filtering.
@@ -151,7 +180,7 @@ export function SelectInputOptions<T = string>({
151
180
  return item;
152
181
  });
153
182
 
154
- return sortSelectInputItems(filtered, sortFilteredOptions, filterQuery);
183
+ return sortSelectInputItems(filtered, sortFilteredOptions, deferredFilterQuery);
155
184
  }
156
185
 
157
186
  return filterSelectInputItems(dedupedItems, (item) =>
@@ -284,7 +313,7 @@ export function SelectInputOptions<T = string>({
284
313
  shape="rectangle"
285
314
  placeholder={filterPlaceholder}
286
315
  aria-label={filterPlaceholder}
287
- defaultValue={filterQuery}
316
+ value={filterQuery}
288
317
  aria-autocomplete="list"
289
318
  aria-expanded
290
319
  aria-controls={listboxId}
@@ -352,6 +381,7 @@ export function SelectInputOptions<T = string>({
352
381
  aria-labelledby={listBoxLabelledBy}
353
382
  tabIndex={0}
354
383
  className="np-select-input-listbox"
384
+ onKeyDownCapture={handleTypeahead}
355
385
  >
356
386
  {!virtualized ? (
357
387
  filteredItems.map((_, index) => getItemNode(index))
@@ -34,6 +34,20 @@ describe('SelectInput', () => {
34
34
  expect(screen.getByText('Currency')).toBeInTheDocument();
35
35
  });
36
36
 
37
+ it('explicitly includes the trigger in the sequential keyboard focus order', () => {
38
+ render(
39
+ <SelectInput
40
+ placeholder="Currency"
41
+ items={[
42
+ { type: 'option', value: 'USD' },
43
+ { type: 'option', value: 'EUR' },
44
+ ]}
45
+ />,
46
+ );
47
+
48
+ expect(screen.getByRole('combobox')).toHaveAttribute('tabindex', '0');
49
+ });
50
+
37
51
  it('renders footer', async () => {
38
52
  render(
39
53
  <SelectInput
@@ -221,6 +235,135 @@ describe('SelectInput', () => {
221
235
  expect(trigger).toHaveTextContent('EUR');
222
236
  });
223
237
 
238
+ it('starts filtering when typing on the focused trigger', async () => {
239
+ const handleFilterChange = jest.fn();
240
+
241
+ render(
242
+ <SelectInput
243
+ items={[
244
+ { type: 'option', value: 'January' },
245
+ { type: 'option', value: 'February' },
246
+ { type: 'option', value: 'March' },
247
+ ]}
248
+ filterable
249
+ onFilterChange={handleFilterChange}
250
+ />,
251
+ );
252
+
253
+ const trigger = screen.getByRole('combobox');
254
+ await userEvent.tab();
255
+ expect(trigger).toHaveFocus();
256
+ await userEvent.keyboard('f');
257
+
258
+ const searchInput = screen.getByRole('combobox', { expanded: true });
259
+ expect(searchInput).toHaveFocus();
260
+ expect(searchInput).toHaveValue('f');
261
+ expect(handleFilterChange).toHaveBeenLastCalledWith({
262
+ query: 'f',
263
+ queryNormalized: 'f',
264
+ });
265
+ expect(screen.getByRole('option', { name: 'February' })).toBeInTheDocument();
266
+ expect(screen.queryByRole('option', { name: 'January' })).not.toBeInTheDocument();
267
+ });
268
+
269
+ it('starts typeahead when typing on the focused trigger', async () => {
270
+ render(
271
+ <SelectInput
272
+ items={[
273
+ { type: 'option', value: 'Frost' },
274
+ { type: 'option', value: 'February' },
275
+ { type: 'option', value: 'March' },
276
+ ]}
277
+ />,
278
+ );
279
+
280
+ const trigger = screen.getByRole('combobox');
281
+ await userEvent.tab();
282
+ expect(trigger).toHaveFocus();
283
+ await userEvent.keyboard('f');
284
+
285
+ const listbox = screen.getByRole('listbox');
286
+ const frost = within(listbox).getByRole('option', { name: 'Frost' });
287
+ const february = within(listbox).getByRole('option', { name: 'February' });
288
+ await waitFor(() => {
289
+ expect(listbox).toHaveFocus();
290
+ });
291
+ await waitFor(() => {
292
+ expect(frost).toHaveClass('np-select-input-option-container--active');
293
+ });
294
+
295
+ await userEvent.keyboard('e');
296
+ await waitFor(() => {
297
+ expect(february).toHaveClass('np-select-input-option-container--active');
298
+ });
299
+
300
+ await userEvent.keyboard('{ArrowDown}');
301
+ expect(within(listbox).getByRole('option', { name: 'March' })).toHaveClass(
302
+ 'np-select-input-option-container--active',
303
+ );
304
+ });
305
+
306
+ it('continues typeahead across spaces after the query starts', async () => {
307
+ render(
308
+ <SelectInput
309
+ items={[
310
+ { type: 'option', value: 'New Zealand' },
311
+ { type: 'option', value: 'New York' },
312
+ { type: 'option', value: 'Yorkshire' },
313
+ ]}
314
+ />,
315
+ );
316
+
317
+ await userEvent.tab();
318
+ await userEvent.keyboard('n');
319
+
320
+ const listbox = screen.getByRole('listbox');
321
+ await waitFor(() => {
322
+ expect(listbox).toHaveFocus();
323
+ });
324
+
325
+ await userEvent.keyboard('ew y');
326
+
327
+ await waitFor(() => {
328
+ expect(within(listbox).getByRole('option', { name: 'New York' })).toHaveClass(
329
+ 'np-select-input-option-container--active',
330
+ );
331
+ });
332
+ });
333
+
334
+ it.each([
335
+ ['filterable', true],
336
+ ['non-filterable', false],
337
+ ])('supports arrow navigation after opening a %s select with Enter', async (_, filterable) => {
338
+ render(
339
+ <SelectInput
340
+ items={[
341
+ { type: 'option', value: 'GBP' },
342
+ { type: 'option', value: 'EUR' },
343
+ { type: 'option', value: 'USD' },
344
+ ]}
345
+ filterable={filterable}
346
+ />,
347
+ );
348
+
349
+ const trigger = screen.getByRole('combobox');
350
+ await userEvent.tab();
351
+ expect(trigger).toHaveFocus();
352
+ await userEvent.keyboard('{Enter}');
353
+
354
+ const controller = filterable
355
+ ? screen.getByRole('combobox', { expanded: true })
356
+ : screen.getByRole('listbox');
357
+ await waitFor(() => {
358
+ expect(controller).toHaveFocus();
359
+ });
360
+
361
+ await userEvent.keyboard('{ArrowDown}');
362
+ expect(screen.getByRole('option', { name: 'EUR' })).toHaveClass(
363
+ 'np-select-input-option-container--active',
364
+ );
365
+ });
366
+
224
367
  it('clears filter query on close', async () => {
225
368
  const handleFilterChange = jest.fn();
226
369
 
@@ -1,5 +1,5 @@
1
1
  import mergeProps from 'merge-props';
2
- import { useCallback, useEffect, useRef, useState, useDeferredValue } from 'react';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { Listbox as ListboxBase } from '@headlessui/react';
4
4
  import { Breakpoint } from '@transferwise/neptune-tokens';
5
5
  import { useScreenSize } from '../../common/hooks/useScreenSize';
@@ -10,6 +10,7 @@ import { SelectInputBottomSheet } from './BottomSheet';
10
10
  import { SelectInputPopover } from './Popover';
11
11
  import { SelectInputOptions } from './Options';
12
12
  import { DefaultRenderTrigger } from './DefaultRenderTrigger';
13
+ import { isTypingKey } from './hooks/useTypeahead';
13
14
 
14
15
  import {
15
16
  SelectInputOptionContentWithinTriggerContext,
@@ -74,7 +75,6 @@ export function SelectInput<T = string, M extends boolean = false>({
74
75
  }, [open]);
75
76
 
76
77
  const [filterQuery, _setFilterQuery] = useState('');
77
- const deferredFilterQuery = useDeferredValue(filterQuery);
78
78
  const previousFilterQueryRef = useRef(filterQuery);
79
79
 
80
80
  const setFilterQuery = useCallback(
@@ -94,6 +94,7 @@ export function SelectInput<T = string, M extends boolean = false>({
94
94
  const internalTriggerRef = useRef<HTMLButtonElement | null>(null);
95
95
  const searchInputRef = useRef<HTMLInputElement>(null);
96
96
  const listboxRef = useRef<HTMLDivElement>(null);
97
+ const [initialTypeaheadKey, setInitialTypeaheadKey] = useState<string | null>(null);
97
98
  const controllerRef = filterable ? searchInputRef : listboxRef;
98
99
 
99
100
  const screenSm = useScreenSize(Breakpoint.SMALL);
@@ -175,13 +176,33 @@ export function SelectInput<T = string, M extends boolean = false>({
175
176
  setOpen((prev) => !prev);
176
177
  },
177
178
  onKeyDown: (event: React.KeyboardEvent) => {
179
+ if (event.key === 'Enter') {
180
+ event.preventDefault();
181
+ event.currentTarget.dispatchEvent(
182
+ new KeyboardEvent('keydown', { key: ' ', bubbles: true }),
183
+ );
184
+ return;
185
+ }
186
+
187
+ if (!open && isTypingKey(event)) {
188
+ event.preventDefault();
189
+
190
+ if (filterable) {
191
+ setFilterQuery(event.key);
192
+ } else {
193
+ setInitialTypeaheadKey(event.key);
194
+ }
195
+
196
+ (event.currentTarget as HTMLButtonElement).click();
197
+ return;
198
+ }
199
+
178
200
  if (
179
201
  event.key === ' ' ||
180
- event.key === 'Enter' ||
181
202
  event.key === 'ArrowDown' ||
182
203
  event.key === 'ArrowUp'
183
204
  ) {
184
- setOpen((prev) => !prev);
205
+ setOpen(true);
185
206
  }
186
207
  },
187
208
  },
@@ -225,6 +246,7 @@ export function SelectInput<T = string, M extends boolean = false>({
225
246
  setOpen(false);
226
247
  }}
227
248
  onCloseEnd={() => {
249
+ setInitialTypeaheadKey(null);
228
250
  setFilterQuery('');
229
251
  }}
230
252
  >
@@ -240,10 +262,14 @@ export function SelectInput<T = string, M extends boolean = false>({
240
262
  sortFilteredOptions={sortFilteredOptions}
241
263
  searchInputRef={searchInputRef}
242
264
  listboxRef={listboxRef}
243
- filterQuery={deferredFilterQuery}
265
+ filterQuery={filterQuery}
266
+ initialTypeaheadKey={initialTypeaheadKey}
244
267
  autocomplete={autocomplete}
245
268
  name={name}
246
269
  onFilterChange={setFilterQuery}
270
+ onInitialTypeaheadHandled={() => {
271
+ setInitialTypeaheadKey(null);
272
+ }}
247
273
  onAutocompleteSelect={(matchedValue) => {
248
274
  onChange?.(matchedValue as M extends true ? T[] : T);
249
275
  if (!multiple) {
@@ -1,7 +1,5 @@
1
1
  import { SelectInputItem, SelectInputOptionItem } from './SelectInput.types';
2
2
 
3
- export const MAX_ITEMS_WITHOUT_VIRTUALIZATION = 50;
4
-
5
3
  /**
6
4
  * Converts a string to a normalized, searchable format by:
7
5
  * - Trimming whitespace
@@ -29,6 +29,9 @@ export function SelectInputTriggerButton<T extends SelectInputTriggerButtonEleme
29
29
  ref={ref}
30
30
  as={PolymorphicWithOverrides}
31
31
  role="combobox"
32
+ // Safari can omit buttons from sequential keyboard navigation unless their
33
+ // focus order is explicit. Zero keeps the trigger in the natural tab order.
34
+ tabIndex={0}
32
35
  __overrides={{ as, size, ...interactionProps }}
33
36
  {...mergeProps({ onClick, onKeyDown }, restProps)}
34
37
  />
@@ -0,0 +1,3 @@
1
+ export const MAX_ITEMS_WITHOUT_VIRTUALIZATION = 50;
2
+
3
+ export const TYPEAHEAD_QUERY_RESET_TIMEOUT_MS = 350;
@@ -0,0 +1,82 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+
3
+ import { TYPEAHEAD_QUERY_RESET_TIMEOUT_MS } from '../constants';
4
+ import { searchableString } from '../SelectInput.utils';
5
+
6
+ const resetsTypeaheadQuery = (key: string) =>
7
+ key === 'ArrowDown' ||
8
+ key === 'ArrowUp' ||
9
+ key === 'Home' ||
10
+ key === 'End' ||
11
+ key === 'PageDown' ||
12
+ key === 'PageUp';
13
+
14
+ export const isTypingKey = (event: React.KeyboardEvent, query = '') =>
15
+ !event.metaKey &&
16
+ !event.ctrlKey &&
17
+ !event.nativeEvent.isComposing &&
18
+ /^.$/u.test(event.key) &&
19
+ (event.key !== ' ' || query !== '');
20
+
21
+ interface UseTypeaheadParams {
22
+ disabled?: boolean;
23
+ onMatch?: () => void;
24
+ }
25
+
26
+ export function useTypeahead({ disabled = false, onMatch }: UseTypeaheadParams = {}) {
27
+ const queryRef = useRef('');
28
+ const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
29
+
30
+ const resetQuery = useCallback(() => {
31
+ queryRef.current = '';
32
+ if (timeoutRef.current != null) {
33
+ clearTimeout(timeoutRef.current);
34
+ timeoutRef.current = null;
35
+ }
36
+ }, []);
37
+
38
+ useEffect(() => resetQuery, [resetQuery]);
39
+
40
+ return useCallback(
41
+ (event: React.KeyboardEvent<HTMLDivElement>) => {
42
+ if (disabled || !isTypingKey(event, queryRef.current)) {
43
+ if (resetsTypeaheadQuery(event.key)) {
44
+ resetQuery();
45
+ }
46
+ return;
47
+ }
48
+
49
+ event.preventDefault();
50
+ event.stopPropagation();
51
+
52
+ queryRef.current += event.key;
53
+ const needle = searchableString(queryRef.current);
54
+
55
+ if (timeoutRef.current != null) {
56
+ clearTimeout(timeoutRef.current);
57
+ }
58
+ timeoutRef.current = setTimeout(resetQuery, TYPEAHEAD_QUERY_RESET_TIMEOUT_MS);
59
+
60
+ const options = Array.from(
61
+ event.currentTarget.querySelectorAll<HTMLElement>(
62
+ '[role="option"]:not([aria-disabled="true"])',
63
+ ),
64
+ );
65
+ const optionLabels = options.map((option) => searchableString(option.textContent ?? ''));
66
+ const matchingIndex = optionLabels.findIndex((label) => label.startsWith(needle));
67
+ const closestIndex =
68
+ matchingIndex === -1
69
+ ? optionLabels.findIndex((label) => label.includes(needle))
70
+ : matchingIndex;
71
+
72
+ if (closestIndex === -1) {
73
+ return;
74
+ }
75
+
76
+ options[closestIndex].focus({ preventScroll: true });
77
+ event.currentTarget.focus({ preventScroll: true });
78
+ onMatch?.();
79
+ },
80
+ [disabled, onMatch, resetQuery],
81
+ );
82
+ }
package/src/i18n/ja.json CHANGED
@@ -50,7 +50,7 @@
50
50
  "neptune.Table.loaded": "テーブルデータが読み込まれました",
51
51
  "neptune.Table.loading": "テーブルデータを読み込み中です",
52
52
  "neptune.Table.refreshPage": "ページを更新する",
53
- "neptune.Typeahead.suggestionsLabel": "Suggestions",
53
+ "neptune.Typeahead.suggestionsLabel": "提案",
54
54
  "neptune.Upload.csButtonText": "別のファイルをアップロードしますか?",
55
55
  "neptune.Upload.csFailureText": "アップロードに失敗しました。もう一度やり直してください。",
56
56
  "neptune.Upload.csSuccessText": "アップロードが完了しました。",
package/src/main.css CHANGED
@@ -22323,6 +22323,16 @@ button.np-option {
22323
22323
  min-block-size: 128px;
22324
22324
  }
22325
22325
  }
22326
+ .np-flow-navigation--no-steps {
22327
+ block-size: 80px;
22328
+ min-block-size: 80px;
22329
+ }
22330
+ @media (min-width: 320.02px) {
22331
+ .np-flow-navigation--no-steps {
22332
+ block-size: 80px;
22333
+ min-block-size: 80px;
22334
+ }
22335
+ }
22326
22336
  .np-flow-navigation--border-bottom {
22327
22337
  border-block-end: 1px solid rgba(0,0,0,0.10196);
22328
22338
  border-block-end: 1px solid #0000001a;