@transferwise/components 0.0.0-experimental-47ae02a → 0.0.0-experimental-da6dbbf
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.
- package/build/index.js +940 -642
- package/build/index.js.map +1 -1
- package/build/index.mjs +930 -633
- package/build/index.mjs.map +1 -1
- package/build/main.css +135 -0
- package/build/styles/carousel/Carousel.css +135 -0
- package/build/styles/main.css +135 -0
- package/build/types/accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
- package/build/types/carousel/Carousel.d.ts +26 -0
- package/build/types/carousel/Carousel.d.ts.map +1 -0
- package/build/types/carousel/index.d.ts +3 -0
- package/build/types/carousel/index.d.ts.map +1 -0
- package/build/types/common/card/Card.d.ts +2 -2
- package/build/types/common/card/Card.d.ts.map +1 -1
- package/build/types/common/hooks/useMedia.d.ts.map +1 -1
- package/build/types/common/panel/Panel.d.ts.map +1 -1
- package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
- package/build/types/dimmer/Dimmer.d.ts +11 -1
- package/build/types/dimmer/Dimmer.d.ts.map +1 -1
- package/build/types/drawer/Drawer.d.ts +4 -4
- package/build/types/index.d.ts +4 -3
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts +1 -2
- package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/modal/Modal.d.ts.map +1 -1
- package/build/types/processIndicator/ProcessIndicator.d.ts +19 -36
- package/build/types/processIndicator/ProcessIndicator.d.ts.map +1 -1
- package/build/types/processIndicator/index.d.ts +2 -2
- package/build/types/processIndicator/index.d.ts.map +1 -1
- package/build/types/promoCard/PromoCard.d.ts +16 -5
- package/build/types/promoCard/PromoCard.d.ts.map +1 -1
- package/build/types/select/searchBox/SearchBox.d.ts +1 -1
- package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts +1 -2
- package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts.map +1 -1
- package/build/types/tooltip/Tooltip.d.ts +1 -1
- package/build/types/tooltip/Tooltip.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/withDisplayFormat/WithDisplayFormat.d.ts +14 -14
- package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
- package/package.json +11 -7
- package/src/accordion/AccordionItem/AccordionItem.tsx +4 -2
- package/src/avatarWrapper/AvatarWrapper.story.tsx +3 -1
- package/src/button/Button.tsx +1 -1
- package/src/carousel/Carousel.css +135 -0
- package/src/carousel/Carousel.less +133 -0
- package/src/carousel/Carousel.spec.tsx +221 -0
- package/src/carousel/Carousel.story.tsx +63 -0
- package/src/carousel/Carousel.tsx +345 -0
- package/src/carousel/index.ts +3 -0
- package/src/common/card/Card.tsx +51 -43
- package/src/common/hooks/useConditionalListener/useConditionalListener.spec.js +1 -1
- package/src/common/hooks/useHasIntersected/useHasIntersected.spec.js +3 -3
- package/src/common/hooks/useMedia.spec.ts +1 -1
- package/src/common/hooks/useMedia.ts +2 -1
- package/src/common/panel/Panel.tsx +92 -90
- package/src/common/responsivePanel/ResponsivePanel.tsx +38 -34
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +180 -0
- package/src/dateLookup/DateLookup.rtl.spec.tsx +5 -181
- package/src/dateLookup/DateLookup.testingLibrary.spec.js +124 -171
- package/src/drawer/Drawer.js +3 -3
- package/src/field/Field.tsx +3 -3
- package/src/index.ts +4 -3
- package/src/inputWithDisplayFormat/InputWithDisplayFormat.tsx +1 -2
- package/src/inputs/SelectInput.story.tsx +0 -1
- package/src/inputs/SelectInput.tsx +2 -10
- package/src/main.css +135 -0
- package/src/main.less +1 -0
- package/src/modal/Modal.tsx +2 -1
- package/src/processIndicator/ProcessIndicator.js +117 -0
- package/src/processIndicator/ProcessIndicator.spec.js +101 -0
- package/src/promoCard/PromoCard.story.tsx +2 -2
- package/src/promoCard/PromoCard.tsx +31 -9
- package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +1 -0
- package/src/snackbar/Snackbar.spec.js +1 -4
- package/src/tabs/Tabs.spec.js +27 -46
- package/src/test-utils/index.js +7 -5
- package/src/test-utils/jest.setup.js +3 -9
- package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.tsx +1 -2
- package/src/tooltip/Tooltip.tsx +46 -44
- package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +2 -2
- package/src/upload/Upload.spec.js +13 -34
- package/src/uploadInput/UploadInput.spec.tsx +23 -21
- package/src/uploadInput/uploadItem/UploadItem.tsx +3 -1
- package/src/withDisplayFormat/WithDisplayFormat.spec.js +32 -63
- package/src/withDisplayFormat/WithDisplayFormat.tsx +28 -28
- package/src/processIndicator/ProcessIndicator.rtl.spec.tsx +0 -45
- package/src/processIndicator/ProcessIndicator.tsx +0 -110
- /package/src/processIndicator/{index.ts → index.js} +0 -0
|
@@ -25,12 +25,12 @@ export type EventType =
|
|
|
25
25
|
| 'Delete'
|
|
26
26
|
| 'Initial';
|
|
27
27
|
|
|
28
|
-
interface WithDisplayFormatState
|
|
28
|
+
interface WithDisplayFormatState {
|
|
29
29
|
value: string;
|
|
30
30
|
historyNavigator: HistoryNavigator;
|
|
31
31
|
prevDisplayPattern: string;
|
|
32
32
|
triggerType: EventType;
|
|
33
|
-
triggerEvent: React.KeyboardEvent<
|
|
33
|
+
triggerEvent: React.KeyboardEvent<HTMLTextElement> | null;
|
|
34
34
|
pastedLength: number;
|
|
35
35
|
selectionStart: number;
|
|
36
36
|
selectionEnd: number;
|
|
@@ -38,7 +38,7 @@ interface WithDisplayFormatState<T extends HTMLTextElement> {
|
|
|
38
38
|
|
|
39
39
|
export interface WithDisplayFormatProps<T extends TextElementProps = TextElementProps>
|
|
40
40
|
extends Pick<
|
|
41
|
-
|
|
41
|
+
TextElementProps,
|
|
42
42
|
| 'className'
|
|
43
43
|
| 'disabled'
|
|
44
44
|
| 'id'
|
|
@@ -64,21 +64,19 @@ export interface WithDisplayFormatProps<T extends TextElementProps = TextElement
|
|
|
64
64
|
render: (renderProps: T) => JSX.Element;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
class WithDisplayFormat<
|
|
68
|
-
T
|
|
69
|
-
|
|
70
|
-
>
|
|
67
|
+
class WithDisplayFormat<T extends TextElementProps> extends Component<
|
|
68
|
+
WithDisplayFormatProps<T>,
|
|
69
|
+
WithDisplayFormatState
|
|
70
|
+
> {
|
|
71
71
|
declare props: WithDisplayFormatProps<T> &
|
|
72
|
-
Required<
|
|
73
|
-
Pick<WithDisplayFormatProps<T>, keyof (typeof WithDisplayFormat<T, U>)['defaultProps']>
|
|
74
|
-
>;
|
|
72
|
+
Required<Pick<WithDisplayFormatProps<T>, keyof typeof WithDisplayFormat.defaultProps>>;
|
|
75
73
|
static defaultProps = {
|
|
76
74
|
autoComplete: 'off',
|
|
77
75
|
displayPattern: '',
|
|
78
76
|
value: '',
|
|
79
|
-
}
|
|
77
|
+
};
|
|
80
78
|
|
|
81
|
-
constructor(props:
|
|
79
|
+
constructor(props: WithDisplayFormatProps) {
|
|
82
80
|
super(props);
|
|
83
81
|
const unformattedValue = unformatWithPattern(props.value ?? '', props.displayPattern);
|
|
84
82
|
this.state = {
|
|
@@ -94,8 +92,8 @@ class WithDisplayFormat<
|
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
static getDerivedStateFromProps(
|
|
97
|
-
{ displayPattern }:
|
|
98
|
-
{ prevDisplayPattern = displayPattern, value, historyNavigator }:
|
|
95
|
+
{ displayPattern }: WithDisplayFormatProps,
|
|
96
|
+
{ prevDisplayPattern = displayPattern, value, historyNavigator }: WithDisplayFormatState,
|
|
99
97
|
) {
|
|
100
98
|
if (prevDisplayPattern !== displayPattern) {
|
|
101
99
|
const unFormattedValue = unformatWithPattern(value, prevDisplayPattern);
|
|
@@ -139,9 +137,10 @@ class WithDisplayFormat<
|
|
|
139
137
|
return 'Backspace';
|
|
140
138
|
}
|
|
141
139
|
return triggerEvent.key;
|
|
140
|
+
} else {
|
|
141
|
+
// triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
|
|
142
|
+
return 'Paste';
|
|
142
143
|
}
|
|
143
|
-
// triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
|
|
144
|
-
return 'Paste';
|
|
145
144
|
};
|
|
146
145
|
|
|
147
146
|
resetEvent = () => {
|
|
@@ -152,7 +151,7 @@ class WithDisplayFormat<
|
|
|
152
151
|
});
|
|
153
152
|
};
|
|
154
153
|
|
|
155
|
-
detectUndoRedo = (event: React.KeyboardEvent<
|
|
154
|
+
detectUndoRedo = (event: React.KeyboardEvent<HTMLTextElement>) => {
|
|
156
155
|
const charCode = String.fromCharCode(event.which).toLowerCase();
|
|
157
156
|
if ((event.ctrlKey || event.metaKey) && charCode === 'z') {
|
|
158
157
|
return event.shiftKey ? 'Redo' : 'Undo';
|
|
@@ -160,7 +159,7 @@ class WithDisplayFormat<
|
|
|
160
159
|
return null;
|
|
161
160
|
};
|
|
162
161
|
|
|
163
|
-
handleOnKeyDown: React.KeyboardEventHandler<
|
|
162
|
+
handleOnKeyDown: React.KeyboardEventHandler<HTMLTextElement> = (event) => {
|
|
164
163
|
event.persist();
|
|
165
164
|
const { selectionStart, selectionEnd } = event.currentTarget;
|
|
166
165
|
const { historyNavigator } = this.state;
|
|
@@ -185,7 +184,7 @@ class WithDisplayFormat<
|
|
|
185
184
|
}
|
|
186
185
|
};
|
|
187
186
|
|
|
188
|
-
handleOnPaste: React.ClipboardEventHandler<
|
|
187
|
+
handleOnPaste: React.ClipboardEventHandler<HTMLTextElement> = (event) => {
|
|
189
188
|
const { displayPattern } = this.props;
|
|
190
189
|
const pastedLength = unformatWithPattern(
|
|
191
190
|
event.clipboardData.getData('Text'),
|
|
@@ -195,7 +194,7 @@ class WithDisplayFormat<
|
|
|
195
194
|
this.setState({ triggerType: 'Paste', pastedLength });
|
|
196
195
|
};
|
|
197
196
|
|
|
198
|
-
handleOnCut: React.ClipboardEventHandler<
|
|
197
|
+
handleOnCut: React.ClipboardEventHandler<HTMLTextElement> = () => {
|
|
199
198
|
this.setState({ triggerType: 'Cut' });
|
|
200
199
|
};
|
|
201
200
|
|
|
@@ -206,7 +205,7 @@ class WithDisplayFormat<
|
|
|
206
205
|
return !symbolsInPattern.includes(action);
|
|
207
206
|
};
|
|
208
207
|
|
|
209
|
-
handleOnChange: React.ChangeEventHandler<
|
|
208
|
+
handleOnChange: React.ChangeEventHandler<HTMLTextElement> = (event) => {
|
|
210
209
|
const { historyNavigator, triggerType } = this.state;
|
|
211
210
|
const { displayPattern, onChange } = this.props;
|
|
212
211
|
const { value } = event.target;
|
|
@@ -234,11 +233,11 @@ class WithDisplayFormat<
|
|
|
234
233
|
});
|
|
235
234
|
};
|
|
236
235
|
|
|
237
|
-
handleOnBlur: React.FocusEventHandler<
|
|
236
|
+
handleOnBlur: React.FocusEventHandler<HTMLTextElement> = (event) => {
|
|
238
237
|
this.props.onBlur?.(unformatWithPattern(event.target.value, this.props.displayPattern));
|
|
239
238
|
};
|
|
240
239
|
|
|
241
|
-
handleOnFocus: React.FocusEventHandler<
|
|
240
|
+
handleOnFocus: React.FocusEventHandler<HTMLTextElement> = (event) => {
|
|
242
241
|
const { displayPattern, onFocus } = this.props;
|
|
243
242
|
if (onFocus) {
|
|
244
243
|
this.handleOnChange(event);
|
|
@@ -274,7 +273,6 @@ class WithDisplayFormat<
|
|
|
274
273
|
handleCursorPositioning = (action: string) => {
|
|
275
274
|
const { displayPattern } = this.props;
|
|
276
275
|
const { triggerEvent, selectionStart, selectionEnd, pastedLength } = this.state;
|
|
277
|
-
const target = triggerEvent?.currentTarget;
|
|
278
276
|
|
|
279
277
|
const cursorPosition = getCursorPositionAfterKeystroke(
|
|
280
278
|
action,
|
|
@@ -285,7 +283,9 @@ class WithDisplayFormat<
|
|
|
285
283
|
);
|
|
286
284
|
|
|
287
285
|
setTimeout(() => {
|
|
288
|
-
|
|
286
|
+
if (triggerEvent) {
|
|
287
|
+
(triggerEvent.target as HTMLTextElement).setSelectionRange(cursorPosition, cursorPosition);
|
|
288
|
+
}
|
|
289
289
|
this.setState({ selectionStart: cursorPosition, selectionEnd: cursorPosition });
|
|
290
290
|
}, 0);
|
|
291
291
|
};
|
|
@@ -305,7 +305,7 @@ class WithDisplayFormat<
|
|
|
305
305
|
autoComplete,
|
|
306
306
|
} = this.props;
|
|
307
307
|
const { value } = this.state;
|
|
308
|
-
const renderProps = {
|
|
308
|
+
const renderProps: TextElementProps = {
|
|
309
309
|
inputMode,
|
|
310
310
|
className,
|
|
311
311
|
id,
|
|
@@ -324,8 +324,8 @@ class WithDisplayFormat<
|
|
|
324
324
|
onKeyDown: this.handleOnKeyDown,
|
|
325
325
|
onChange: this.handleOnChange,
|
|
326
326
|
onCut: this.handleOnCut,
|
|
327
|
-
}
|
|
328
|
-
return this.props.render(renderProps);
|
|
327
|
+
};
|
|
328
|
+
return this.props.render(renderProps as T);
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { act } from 'react';
|
|
2
|
-
|
|
3
|
-
import { render, screen } from '../test-utils';
|
|
4
|
-
import ProcessIndicator, { ProcessIndicatorProps } from './ProcessIndicator';
|
|
5
|
-
|
|
6
|
-
describe('ProcessIndicator', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
jest.useFakeTimers();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
await jest.runOnlyPendingTimersAsync();
|
|
13
|
-
jest.useRealTimers();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('supports transitioning between states', async () => {
|
|
17
|
-
const handleAnimationCompleted = jest.fn();
|
|
18
|
-
const initialProps = {
|
|
19
|
-
'data-testid': 'process-indicator',
|
|
20
|
-
onAnimationCompleted: handleAnimationCompleted,
|
|
21
|
-
} satisfies ProcessIndicatorProps;
|
|
22
|
-
const view = render(<ProcessIndicator {...initialProps} />);
|
|
23
|
-
|
|
24
|
-
expect(screen.getByTestId('process-indicator')).not.toHaveClass('process-success');
|
|
25
|
-
expect(screen.getByTestId('process-indicator')).not.toHaveClass('process-xl');
|
|
26
|
-
|
|
27
|
-
const updatedProps = {
|
|
28
|
-
status: 'succeeded',
|
|
29
|
-
size: 'xl',
|
|
30
|
-
} satisfies ProcessIndicatorProps;
|
|
31
|
-
view.rerender(<ProcessIndicator {...initialProps} {...updatedProps} />);
|
|
32
|
-
await act(async () => {
|
|
33
|
-
await jest.runOnlyPendingTimersAsync();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
expect(screen.getByTestId('process-indicator')).toHaveClass('process-success');
|
|
37
|
-
expect(screen.getByTestId('process-indicator')).toHaveClass('process-xl');
|
|
38
|
-
expect(handleAnimationCompleted).not.toHaveBeenCalled();
|
|
39
|
-
|
|
40
|
-
await jest.runOnlyPendingTimersAsync();
|
|
41
|
-
|
|
42
|
-
expect(handleAnimationCompleted).toHaveBeenCalledWith(updatedProps.status);
|
|
43
|
-
expect(handleAnimationCompleted).toHaveBeenCalledTimes(1);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import classNames from 'classnames';
|
|
2
|
-
import { Component } from 'react';
|
|
3
|
-
|
|
4
|
-
import { Status, Size } from '../common';
|
|
5
|
-
|
|
6
|
-
const radius = { xxs: 6, xs: 11, sm: 22, xl: 61 };
|
|
7
|
-
|
|
8
|
-
const ANIMATION_DURATION_IN_MS = 1500;
|
|
9
|
-
|
|
10
|
-
type ProcessIndicatorStatus =
|
|
11
|
-
`${Status.PROCESSING | Status.FAILED | Status.SUCCEEDED | Status.HIDDEN}`;
|
|
12
|
-
|
|
13
|
-
export interface ProcessIndicatorProps {
|
|
14
|
-
status?: ProcessIndicatorStatus;
|
|
15
|
-
size?: 'xxs' | `${Size.EXTRA_SMALL | Size.SMALL | Size.EXTRA_LARGE}`;
|
|
16
|
-
className?: string;
|
|
17
|
-
'data-testid'?: string;
|
|
18
|
-
onAnimationCompleted?: (status: ProcessIndicatorStatus) => void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
type ProcessIndicatorState = Required<Pick<ProcessIndicatorProps, 'status' | 'size'>>;
|
|
22
|
-
|
|
23
|
-
export default class ProcessIndicator extends Component<
|
|
24
|
-
ProcessIndicatorProps,
|
|
25
|
-
ProcessIndicatorState
|
|
26
|
-
> {
|
|
27
|
-
declare props: ProcessIndicatorProps &
|
|
28
|
-
Required<Pick<ProcessIndicatorProps, keyof typeof ProcessIndicator.defaultProps>>;
|
|
29
|
-
|
|
30
|
-
static defaultProps = {
|
|
31
|
-
status: 'processing',
|
|
32
|
-
size: 'sm',
|
|
33
|
-
} satisfies Partial<ProcessIndicatorProps>;
|
|
34
|
-
|
|
35
|
-
interval = 0;
|
|
36
|
-
timeout = 0;
|
|
37
|
-
|
|
38
|
-
constructor(props: ProcessIndicator['props']) {
|
|
39
|
-
super(props);
|
|
40
|
-
this.state = {
|
|
41
|
-
status: props.status,
|
|
42
|
-
size: props.size,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Create interval for animation duration (1500ms)
|
|
48
|
-
* Update state only at the end of every interval
|
|
49
|
-
* (end of animation loop) if props changed before end of animation
|
|
50
|
-
*/
|
|
51
|
-
componentDidMount() {
|
|
52
|
-
this.interval = window.setInterval(() => {
|
|
53
|
-
const { status: targetStatus, size: targetSize, onAnimationCompleted } = this.props;
|
|
54
|
-
const { status: currentStatus, size: currentSize } = this.state;
|
|
55
|
-
|
|
56
|
-
if (currentStatus !== targetStatus) {
|
|
57
|
-
this.setState({ status: targetStatus }, () => {
|
|
58
|
-
if (onAnimationCompleted) {
|
|
59
|
-
this.timeout = window.setTimeout(() => {
|
|
60
|
-
onAnimationCompleted(targetStatus);
|
|
61
|
-
}, ANIMATION_DURATION_IN_MS);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (currentSize !== targetSize) {
|
|
67
|
-
this.setState({ size: targetSize });
|
|
68
|
-
}
|
|
69
|
-
}, ANIMATION_DURATION_IN_MS);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Only trigger render if comopnent's state got
|
|
74
|
-
* updated from interval callback
|
|
75
|
-
*/
|
|
76
|
-
shouldComponentUpdate(nextProps: ProcessIndicator['props'], nextState: ProcessIndicatorState) {
|
|
77
|
-
const isSameStatus = nextProps.status === nextState.status;
|
|
78
|
-
const isSameSize = nextProps.size === nextState.size;
|
|
79
|
-
|
|
80
|
-
return isSameStatus && isSameSize;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Clear interval before destroying component
|
|
84
|
-
componentWillUnmount() {
|
|
85
|
-
window.clearInterval(this.interval);
|
|
86
|
-
window.clearTimeout(this.timeout);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
render() {
|
|
90
|
-
const { className, 'data-testid': dataTestId } = this.props;
|
|
91
|
-
const { size, status } = this.state;
|
|
92
|
-
const classes = classNames(`process process-${size}`, className, {
|
|
93
|
-
[`process-danger`]: status === Status.FAILED,
|
|
94
|
-
[`process-stopped`]: status === Status.HIDDEN,
|
|
95
|
-
[`process-success`]: status === Status.SUCCEEDED,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<span className={classes} data-testid={dataTestId}>
|
|
100
|
-
<span className="process-icon-container">
|
|
101
|
-
<span className="process-icon-horizontal" />
|
|
102
|
-
<span className="process-icon-vertical" />
|
|
103
|
-
</span>
|
|
104
|
-
<svg xmlns="http://www.w3.org/2000/svg">
|
|
105
|
-
<circle className="process-circle" cx="50%" cy="50%" r={radius[size]} fillOpacity="0.0" />
|
|
106
|
-
</svg>
|
|
107
|
-
</span>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
File without changes
|