@trycourier/react-designer 0.6.0 → 0.8.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.
- package/README.md +7 -5
- package/dist/cjs/index.js +70 -58
- package/dist/cjs/index.js.map +4 -4
- package/dist/cjs/styles.css +1473 -486
- package/dist/components/BrandEditor/Editor/BrandFooter/BrandFooter.d.ts +3 -1
- package/dist/components/Providers/TemplateProvider.d.ts +9 -0
- package/dist/components/Providers/store.d.ts +11 -0
- package/dist/components/TemplateEditor/Channels/Email/Email.d.ts +12 -2
- package/dist/components/TemplateEditor/Channels/Email/EmailLayout.d.ts +3 -1
- package/dist/components/TemplateEditor/Channels/Inbox/Inbox.d.ts +3 -0
- package/dist/components/TemplateEditor/Channels/Inbox/InboxLayout.d.ts +1 -1
- package/dist/components/TemplateEditor/Channels/Inbox/SideBar/useInboxButtonSync.d.ts +27 -0
- package/dist/components/TemplateEditor/Channels/MSTeams/MSTeamsLayout.d.ts +1 -1
- package/dist/components/TemplateEditor/Channels/Push/PushLayout.d.ts +1 -1
- package/dist/components/TemplateEditor/Channels/SMS/SMSLayout.d.ts +1 -1
- package/dist/components/TemplateEditor/Channels/Slack/SlackLayout.d.ts +1 -1
- package/dist/components/TemplateEditor/Layout/Layout.d.ts +1 -0
- package/dist/components/TemplateEditor/TemplateEditor.d.ts +19 -0
- package/dist/components/TemplateEditor/VariableViewModeSync.d.ts +3 -0
- package/dist/components/TemplateEditor/hooks/index.d.ts +1 -0
- package/dist/components/TemplateEditor/hooks/useEmailBackgroundColors.d.ts +9 -0
- package/dist/components/TemplateEditor/hooks/useEmailFontFamily.d.ts +10 -0
- package/dist/components/TemplateEditor/hooks/useFonts.d.ts +4 -0
- package/dist/components/TemplateEditor/hooks/useGoogleFontLoader.d.ts +5 -0
- package/dist/components/TemplateEditor/index.d.ts +1 -0
- package/dist/components/TemplateEditor/store.d.ts +20 -0
- package/dist/components/TranslationEditor/TranslationEditor.d.ts +17 -0
- package/dist/components/TranslationEditor/index.d.ts +1 -0
- package/dist/components/extensions/Blockquote/Blockquote.d.ts +4 -0
- package/dist/components/extensions/Button/Button.types.d.ts +10 -6
- package/dist/components/extensions/Button/inboxButtonStyle.d.ts +65 -0
- package/dist/components/extensions/ButtonRow/ButtonRow.types.d.ts +4 -0
- package/dist/components/extensions/Color/Color.d.ts +14 -0
- package/dist/components/extensions/ColumnCell/ColumnCell.types.d.ts +32 -0
- package/dist/components/extensions/{CustomCode/CustomCodeForm.d.ts → ColumnCell/ColumnCellForm.d.ts} +2 -2
- package/dist/components/extensions/ColumnCell/index.d.ts +2 -0
- package/dist/components/extensions/HTML/HTML.d.ts +11 -0
- package/dist/components/extensions/{CustomCode/CustomCode.types.d.ts → HTML/HTML.types.d.ts} +2 -2
- package/dist/components/extensions/HTML/HTMLComponent.d.ts +9 -0
- package/dist/components/extensions/HTML/HTMLForm.d.ts +9 -0
- package/dist/components/extensions/HTML/index.d.ts +6 -0
- package/dist/components/extensions/ImageBlock/components/ImageBlockView.d.ts +1 -3
- package/dist/components/extensions/Link/LinkBubble.d.ts +1 -0
- package/dist/components/extensions/List/List.types.d.ts +5 -0
- package/dist/components/extensions/MessagingChannelPaste/MessagingChannelPaste.d.ts +11 -0
- package/dist/components/extensions/MessagingChannelPaste/index.d.ts +2 -0
- package/dist/components/extensions/Variable/Variable.d.ts +5 -0
- package/dist/components/extensions/index.d.ts +3 -2
- package/dist/components/extensions/shared/conditionalAttribute.d.ts +19 -0
- package/dist/components/hooks/useVariables.d.ts +12 -7
- package/dist/components/ui/Blocks/HTMLBlock/HTMLBlock.d.ts +3 -0
- package/dist/components/ui/Blocks/HTMLBlock/index.d.ts +1 -0
- package/dist/components/ui/Blocks/index.d.ts +1 -1
- package/dist/components/ui/Conditions/ConditionGroupRow.d.ts +12 -0
- package/dist/components/ui/Conditions/ConditionRow.d.ts +11 -0
- package/dist/components/ui/Conditions/Conditions.d.ts +9 -0
- package/dist/components/ui/Conditions/ConditionsSection.d.ts +18 -0
- package/dist/components/ui/Conditions/index.d.ts +3 -0
- package/dist/components/ui/Conditions/useConditions.d.ts +13 -0
- package/dist/components/ui/ContentIcon/ContentIcon.d.ts +1 -1
- package/dist/components/ui/MainLayout/MainLayout.d.ts +1 -0
- package/dist/components/ui/TextMenu/components/ContentTypePicker.d.ts +1 -1
- package/dist/components/ui/TextMenu/components/TextColorButton.d.ts +6 -0
- package/dist/components/ui/TextMenu/config.d.ts +1 -0
- package/dist/components/ui/TextMenu/hooks/useTextmenuCommands.d.ts +2 -0
- package/dist/components/ui/TextMenu/hooks/useTextmenuStates.d.ts +2 -0
- package/dist/components/ui/Tooltip/types.d.ts +1 -1
- package/dist/components/ui/VariableEditor/VariableChipBase.d.ts +10 -0
- package/dist/components/ui/VariableEditor/VariableInput.d.ts +18 -0
- package/dist/components/ui-kit/Button/Button.d.ts +2 -2
- package/dist/components/ui-kit/FontSelect/FontSelect.d.ts +9 -0
- package/dist/components/ui-kit/FontSelect/index.d.ts +1 -0
- package/dist/components/ui-kit/Form/Form.d.ts +2 -1
- package/dist/components/ui-kit/InputColor/ColorPicker.d.ts +2 -1
- package/dist/components/ui-kit/InputColor/InputColor.d.ts +4 -1
- package/dist/components/ui-kit/PrefixInput/PrefixInput.d.ts +30 -0
- package/dist/components/ui-kit/PrefixInput/index.d.ts +2 -0
- package/dist/components/ui-kit/index.d.ts +2 -0
- package/dist/components/utils/resolveDataPath.d.ts +13 -0
- package/dist/components/utils/validateVariableName.d.ts +5 -2
- package/dist/esm/index.js +70 -58
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/styles.css +1473 -486
- package/dist/hooks/useLocalization.d.ts +30 -0
- package/dist/index.d.ts +18 -4
- package/dist/lib/constants/block-defaults.d.ts +43 -0
- package/dist/lib/constants/email-editor-tiptap-styles.d.ts +62 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/utils/brandColors.d.ts +15 -0
- package/dist/lib/utils/extractTextFields.d.ts +60 -0
- package/dist/lib/utils/fontFamily.d.ts +23 -0
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/styles.css +1473 -486
- package/dist/types/conditions.types.d.ts +21 -0
- package/dist/types/elemental.types.d.ts +70 -4
- package/dist/types/font.types.d.ts +8 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/validation.types.d.ts +15 -3
- package/package.json +6 -1
- package/dist/components/extensions/CustomCode/CustomCode.d.ts +0 -11
- package/dist/components/extensions/CustomCode/CustomCodeComponent.d.ts +0 -9
- package/dist/components/extensions/CustomCode/index.d.ts +0 -6
- package/dist/components/ui/Blocks/CustomCodeBlock/CustomCodeBlock.d.ts +0 -3
- package/dist/components/ui/Blocks/CustomCodeBlock/index.d.ts +0 -1
- /package/dist/components/extensions/{CustomCode → HTML}/MonacoCodeEditor.d.ts +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ElementalConditionOperator = "equals" | "not_equals" | "greater_than" | "less_than" | "greater_than_or_equals" | "less_than_or_equals" | "contains" | "not_contains" | "is_empty" | "is_not_empty";
|
|
2
|
+
export interface ElementalCondition {
|
|
3
|
+
property: string;
|
|
4
|
+
operator: ElementalConditionOperator;
|
|
5
|
+
value?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ElementalConditionGroup {
|
|
8
|
+
conditions: ElementalCondition[];
|
|
9
|
+
logical_operator: "and" | "or";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Structured condition format for the Elemental `if` field.
|
|
13
|
+
* An array of condition groups, evaluated with OR logic between groups.
|
|
14
|
+
* Within each group, conditions are joined by the group's `logical_operator`.
|
|
15
|
+
*/
|
|
16
|
+
export type ElementalConditionExpression = ElementalConditionGroup[];
|
|
17
|
+
/** Union type for the `if` field: legacy string expression or structured conditions. */
|
|
18
|
+
export type ElementalIfCondition = string | ElementalConditionExpression;
|
|
19
|
+
/** Operators that don't require a value (unary checks). */
|
|
20
|
+
export declare const UNARY_OPERATORS: ElementalConditionOperator[];
|
|
21
|
+
export declare const OPERATOR_LABELS: Record<ElementalConditionOperator, string>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { ElementalConditionExpression } from "./conditions.types";
|
|
1
2
|
export type Align = "left" | "center" | "right" | "full";
|
|
2
3
|
export type IActionButtonStyle = "button" | "link";
|
|
3
|
-
export type TextStyle = "text" | "h1" | "h2" | "subtext";
|
|
4
|
+
export type TextStyle = "text" | "h1" | "h2" | "h3" | "subtext";
|
|
4
5
|
export interface IBorderConfig {
|
|
5
6
|
enabled?: boolean;
|
|
6
7
|
radius?: string;
|
|
@@ -17,7 +18,7 @@ export interface ElementalContent {
|
|
|
17
18
|
version: "2022-01-01";
|
|
18
19
|
elements: ElementalNode[];
|
|
19
20
|
}
|
|
20
|
-
export type ElementalNode = ElementalTextNode | ElementalMetaNode | ElementalChannelNode | ElementalImageNode | ElementalActionNode | ElementalDividerNode | ElementalGroupNode | ElementalQuoteNode | ElementalHtmlNode | ElementalCommentNode | ElementalTextContentNode | ElementalListNode | ElementalListItemNode;
|
|
21
|
+
export type ElementalNode = ElementalTextNode | ElementalMetaNode | ElementalChannelNode | ElementalImageNode | ElementalActionNode | ElementalDividerNode | ElementalGroupNode | ElementalColumnsNode | ElementalColumnNode | ElementalQuoteNode | ElementalHtmlNode | ElementalCommentNode | ElementalTextContentNode | ElementalListNode | ElementalListItemNode;
|
|
21
22
|
export interface ElementalListNode extends IsElementalNode {
|
|
22
23
|
type: "list";
|
|
23
24
|
list_type: "ordered" | "unordered";
|
|
@@ -32,6 +33,11 @@ export interface ElementalListItemNode extends IsElementalNode {
|
|
|
32
33
|
type: "list-item";
|
|
33
34
|
background_color?: string;
|
|
34
35
|
elements: (ElementalTextContentNode | ElementalListNode)[];
|
|
36
|
+
locales?: ElementalLocales<{
|
|
37
|
+
content?: string;
|
|
38
|
+
elements?: ElementalTextContentNode[];
|
|
39
|
+
_sourceHash?: string;
|
|
40
|
+
}>;
|
|
35
41
|
}
|
|
36
42
|
export type ElementalTextNode = ElementalTextNodeWithContent | ElementalTextNodeWithElements;
|
|
37
43
|
export interface ElementalTextNodeWithElements extends IsElementalTextNode {
|
|
@@ -56,6 +62,7 @@ export interface IsElementalTextNode extends IsElementalNode {
|
|
|
56
62
|
border?: IBorderConfig;
|
|
57
63
|
locales?: ElementalLocales<{
|
|
58
64
|
content?: string;
|
|
65
|
+
elements?: ElementalTextContentNode[];
|
|
59
66
|
}>;
|
|
60
67
|
}
|
|
61
68
|
export type ElementalTextContentNode = ElementalStringTextContent | ElementalLinkTextContent | ElementalImageTextContent;
|
|
@@ -99,6 +106,9 @@ export interface ElementalChannelNode extends IsElementalNode {
|
|
|
99
106
|
type: "channel";
|
|
100
107
|
channel: string;
|
|
101
108
|
elements?: ElementalNode[];
|
|
109
|
+
background_color?: string;
|
|
110
|
+
content_body_color?: string;
|
|
111
|
+
font_family?: string;
|
|
102
112
|
raw?: {
|
|
103
113
|
html?: string;
|
|
104
114
|
transformers?: string[];
|
|
@@ -192,6 +202,62 @@ export interface ElementalGroupNode extends IsElementalNode {
|
|
|
192
202
|
elements?: ElementalNode[];
|
|
193
203
|
}>;
|
|
194
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Represents a columns container node that arranges child column elements horizontally.
|
|
207
|
+
* Used to create multi-column layouts in email templates.
|
|
208
|
+
*/
|
|
209
|
+
export interface ElementalColumnsNode extends IsElementalNode {
|
|
210
|
+
/** Node type identifier */
|
|
211
|
+
type: "columns";
|
|
212
|
+
/** Array of column elements to be arranged horizontally */
|
|
213
|
+
elements: ElementalColumnNode[];
|
|
214
|
+
/** Background color for the columns container (e.g., "#ffffff", "transparent") */
|
|
215
|
+
background_color?: string;
|
|
216
|
+
/** Border color for the columns container (e.g., "#000000") */
|
|
217
|
+
border_color?: string;
|
|
218
|
+
/** Border radius for the columns container (e.g., "8px") */
|
|
219
|
+
border_radius?: string;
|
|
220
|
+
/** Border width for the columns container (e.g., "2px") */
|
|
221
|
+
border_width?: string;
|
|
222
|
+
/** Gap/spacing between columns (e.g., "10px") */
|
|
223
|
+
gap?: string;
|
|
224
|
+
/** Padding for the columns container (e.g., "10px 20px") */
|
|
225
|
+
padding?: string;
|
|
226
|
+
/** Vertical alignment of columns within the container */
|
|
227
|
+
vertical_align?: "top" | "middle" | "bottom";
|
|
228
|
+
/** Locale-specific overrides for elements */
|
|
229
|
+
locales?: ElementalLocales<{
|
|
230
|
+
elements?: ElementalColumnNode[];
|
|
231
|
+
}>;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Represents a single column within a columns container.
|
|
235
|
+
* Contains elements that will be stacked vertically within the column.
|
|
236
|
+
*/
|
|
237
|
+
export interface ElementalColumnNode extends IsElementalNode {
|
|
238
|
+
/** Node type identifier */
|
|
239
|
+
type: "column";
|
|
240
|
+
/** Array of elements to be stacked vertically within this column */
|
|
241
|
+
elements: ElementalNode[];
|
|
242
|
+
/** Background color for the column (e.g., "#ffffff", "transparent") */
|
|
243
|
+
background_color?: string;
|
|
244
|
+
/** Border color for the column (e.g., "#000000") */
|
|
245
|
+
border_color?: string;
|
|
246
|
+
/** Border radius for the column (e.g., "8px") */
|
|
247
|
+
border_radius?: string;
|
|
248
|
+
/** Border width for the column (e.g., "2px") */
|
|
249
|
+
border_width?: string;
|
|
250
|
+
/** Internal padding for the column content (e.g., "10px", "10px 20px") */
|
|
251
|
+
padding?: string;
|
|
252
|
+
/** Vertical alignment of content within this column */
|
|
253
|
+
vertical_align?: "top" | "middle" | "bottom";
|
|
254
|
+
/** Column width (e.g., "50%", "200px", "auto") */
|
|
255
|
+
width?: string;
|
|
256
|
+
/** Locale-specific overrides for elements */
|
|
257
|
+
locales?: ElementalLocales<{
|
|
258
|
+
elements?: ElementalNode[];
|
|
259
|
+
}>;
|
|
260
|
+
}
|
|
195
261
|
export interface ElementalQuoteNode extends IsElementalNode {
|
|
196
262
|
type: "quote";
|
|
197
263
|
content: string;
|
|
@@ -201,7 +267,7 @@ export interface ElementalQuoteNode extends IsElementalNode {
|
|
|
201
267
|
padding_horizontal?: number;
|
|
202
268
|
padding_vertical?: number;
|
|
203
269
|
background_color?: string;
|
|
204
|
-
text_style?: "text" | "h1" | "h2" | "subtext";
|
|
270
|
+
text_style?: "text" | "h1" | "h2" | "h3" | "subtext";
|
|
205
271
|
locales?: ElementalLocales<{
|
|
206
272
|
content?: string;
|
|
207
273
|
}>;
|
|
@@ -222,7 +288,7 @@ interface IsElementalNode {
|
|
|
222
288
|
type: string;
|
|
223
289
|
channels?: string[];
|
|
224
290
|
ref?: string;
|
|
225
|
-
if?: string;
|
|
291
|
+
if?: string | ElementalConditionExpression;
|
|
226
292
|
loop?: string;
|
|
227
293
|
data?: Record<string, unknown>;
|
|
228
294
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context about where a variable chip is positioned in the document tree.
|
|
3
|
+
* Passed to the validate function so consumers can make context-aware decisions.
|
|
4
|
+
*/
|
|
5
|
+
export interface VariableValidationContext {
|
|
6
|
+
/** Whether the variable is inside a list node that has a loop configured */
|
|
7
|
+
isInsideLoop: boolean;
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Configuration for custom variable validation in the editor.
|
|
3
11
|
* Allows consumers to restrict which variable names are allowed and
|
|
@@ -9,15 +17,19 @@ export interface VariableValidationConfig {
|
|
|
9
17
|
* (unless `overrideFormatValidation` is true).
|
|
10
18
|
*
|
|
11
19
|
* @param variableName - The variable name to validate (without curly braces)
|
|
20
|
+
* @param context - Positional context about where the variable chip lives
|
|
12
21
|
* @returns true if the variable is allowed, false otherwise
|
|
13
22
|
*
|
|
14
23
|
* @example
|
|
15
24
|
* ```tsx
|
|
16
|
-
* //
|
|
17
|
-
* validate: (name) =>
|
|
25
|
+
* // Allow $.item.* only inside loops
|
|
26
|
+
* validate: (name, ctx) => {
|
|
27
|
+
* if (name.startsWith('$.')) return ctx?.isInsideLoop ?? false;
|
|
28
|
+
* return allowedPrefixes.some(p => name.startsWith(p));
|
|
29
|
+
* }
|
|
18
30
|
* ```
|
|
19
31
|
*/
|
|
20
|
-
validate?: (variableName: string) => boolean;
|
|
32
|
+
validate?: (variableName: string, context?: VariableValidationContext) => boolean;
|
|
21
33
|
/**
|
|
22
34
|
* Behavior when validation fails.
|
|
23
35
|
* - 'mark': Keep the chip with invalid styling (default, shows red styling)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trycourier/react-designer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "React-based rich text designer component",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -86,7 +86,9 @@
|
|
|
86
86
|
"@testing-library/jest-dom": "^6.0.0",
|
|
87
87
|
"@testing-library/react": "^14.0.0",
|
|
88
88
|
"@testing-library/user-event": "^14.0.0",
|
|
89
|
+
"@tiptap/extension-text-style": "^2.11.5",
|
|
89
90
|
"@types/node": "^20.0.0",
|
|
91
|
+
"@types/pngjs": "^6.0.5",
|
|
90
92
|
"@types/react": "^18.2.0",
|
|
91
93
|
"@types/react-dom": "^18.0.0",
|
|
92
94
|
"@vitejs/plugin-react": "^4.0.0",
|
|
@@ -98,6 +100,8 @@
|
|
|
98
100
|
"esbuild-style-plugin": "^1.6.3",
|
|
99
101
|
"jsdom": "^22.1.0",
|
|
100
102
|
"nyc": "^17.1.0",
|
|
103
|
+
"pixelmatch": "^7.1.0",
|
|
104
|
+
"pngjs": "^7.0.0",
|
|
101
105
|
"postcss": "^8.4.49",
|
|
102
106
|
"postcss-import": "^16.1.0",
|
|
103
107
|
"postcss-nested": "^7.0.2",
|
|
@@ -152,6 +156,7 @@
|
|
|
152
156
|
"test:coverage:watch": "vitest --coverage",
|
|
153
157
|
"test:e2e": "playwright test --workers=4",
|
|
154
158
|
"test:e2e:fullcycle": "playwright test --config=playwright.fullcycle.config.ts",
|
|
159
|
+
"test:e2e:fullcycle:update-snapshots": "playwright test --config=playwright.fullcycle.config.ts --update-snapshots",
|
|
155
160
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
|
156
161
|
"analyze": "node build.js --analyze",
|
|
157
162
|
"release": "node scripts/publish.js",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Node } from "@tiptap/core";
|
|
2
|
-
import type { CustomCodeProps } from "./CustomCode.types";
|
|
3
|
-
declare module "@tiptap/core" {
|
|
4
|
-
interface Commands<ReturnType> {
|
|
5
|
-
customCode: {
|
|
6
|
-
setCustomCode: (props: Partial<CustomCodeProps>) => ReturnType;
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
export declare const defaultCustomCodeProps: CustomCodeProps;
|
|
11
|
-
export declare const CustomCode: Node<any, any>;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type NodeViewProps } from "@tiptap/react";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import type { CustomCodeProps } from "./CustomCode.types";
|
|
4
|
-
export declare const CustomCodeComponent: React.FC<CustomCodeProps & {
|
|
5
|
-
nodeKey?: string;
|
|
6
|
-
selected?: boolean;
|
|
7
|
-
updateAttributes?: (attrs: Partial<CustomCodeProps>) => void;
|
|
8
|
-
}>;
|
|
9
|
-
export declare const CustomCodeComponentNode: (props: NodeViewProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { CustomCode, defaultCustomCodeProps } from "./CustomCode";
|
|
2
|
-
export { CustomCodeComponent, CustomCodeComponentNode } from "./CustomCodeComponent";
|
|
3
|
-
export { MonacoCodeEditor } from "./MonacoCodeEditor";
|
|
4
|
-
export { CustomCodeForm } from "./CustomCodeForm";
|
|
5
|
-
export type { CustomCodeProps } from "./CustomCode.types";
|
|
6
|
-
export { customCodeSchema } from "./CustomCode.types";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./CustomCodeBlock";
|
|
File without changes
|