@squiz/formatted-text-editor 1.21.1-alpha.7 → 1.22.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.
Files changed (121) hide show
  1. package/demo/App.tsx +52 -10
  2. package/demo/index.scss +11 -10
  3. package/jest.config.ts +0 -2
  4. package/lib/Editor/Editor.js +45 -7
  5. package/lib/Editor/EditorContext.d.ts +15 -0
  6. package/lib/Editor/EditorContext.js +15 -0
  7. package/lib/EditorToolbar/FloatingToolbar.js +11 -5
  8. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +9 -8
  9. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +91 -23
  10. package/lib/EditorToolbar/Tools/Image/ImageButton.d.ts +4 -1
  11. package/lib/EditorToolbar/Tools/Image/ImageButton.js +22 -14
  12. package/lib/EditorToolbar/Tools/Image/ImageModal.js +9 -5
  13. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +14 -5
  14. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +66 -14
  15. package/lib/EditorToolbar/Tools/Link/LinkButton.js +21 -13
  16. package/lib/EditorToolbar/Tools/Link/LinkModal.js +12 -5
  17. package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +1 -8
  18. package/lib/Extensions/CommandsExtension/CommandsExtension.d.ts +20 -0
  19. package/lib/Extensions/CommandsExtension/CommandsExtension.js +52 -0
  20. package/lib/Extensions/Extensions.d.ts +12 -5
  21. package/lib/Extensions/Extensions.js +42 -20
  22. package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +17 -0
  23. package/lib/Extensions/ImageExtension/AssetImageExtension.js +92 -0
  24. package/lib/Extensions/ImageExtension/ImageExtension.d.ts +4 -0
  25. package/lib/Extensions/ImageExtension/ImageExtension.js +11 -0
  26. package/lib/Extensions/LinkExtension/AssetLinkExtension.d.ts +26 -0
  27. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +102 -0
  28. package/lib/Extensions/LinkExtension/LinkExtension.d.ts +19 -12
  29. package/lib/Extensions/LinkExtension/LinkExtension.js +56 -66
  30. package/lib/Extensions/LinkExtension/common.d.ts +7 -0
  31. package/lib/Extensions/LinkExtension/common.js +14 -0
  32. package/lib/Extensions/PreformattedExtension/PreformattedExtension.d.ts +1 -1
  33. package/lib/Extensions/PreformattedExtension/PreformattedExtension.js +6 -2
  34. package/lib/hooks/index.d.ts +1 -0
  35. package/lib/hooks/index.js +1 -0
  36. package/lib/hooks/useExpandedSelection.d.ts +23 -0
  37. package/lib/hooks/useExpandedSelection.js +37 -0
  38. package/lib/index.css +58 -23
  39. package/lib/index.d.ts +5 -2
  40. package/lib/index.js +9 -3
  41. package/lib/types.d.ts +3 -0
  42. package/lib/types.js +2 -0
  43. package/lib/ui/Button/Button.d.ts +2 -1
  44. package/lib/ui/Button/Button.js +4 -5
  45. package/lib/ui/Fields/Input/Input.d.ts +1 -0
  46. package/lib/ui/Fields/Input/Input.js +9 -3
  47. package/lib/ui/Modal/Modal.js +5 -3
  48. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.d.ts +9 -0
  49. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +174 -0
  50. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.d.ts +9 -0
  51. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +138 -0
  52. package/lib/utils/resolveMatrixAssetUrl.d.ts +1 -0
  53. package/lib/utils/resolveMatrixAssetUrl.js +10 -0
  54. package/lib/utils/undefinedIfEmpty.d.ts +1 -0
  55. package/lib/utils/undefinedIfEmpty.js +7 -0
  56. package/package.json +10 -4
  57. package/src/Editor/Editor.spec.tsx +78 -18
  58. package/src/Editor/Editor.tsx +28 -9
  59. package/src/Editor/EditorContext.spec.tsx +26 -0
  60. package/src/Editor/EditorContext.ts +26 -0
  61. package/src/Editor/_editor.scss +20 -4
  62. package/src/EditorToolbar/FloatingToolbar.spec.tsx +26 -7
  63. package/src/EditorToolbar/FloatingToolbar.tsx +15 -6
  64. package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +81 -6
  65. package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +167 -47
  66. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +250 -2
  67. package/src/EditorToolbar/Tools/Image/ImageButton.tsx +29 -16
  68. package/src/EditorToolbar/Tools/Image/ImageModal.spec.tsx +59 -20
  69. package/src/EditorToolbar/Tools/Image/ImageModal.tsx +12 -10
  70. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +37 -9
  71. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +96 -26
  72. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +137 -26
  73. package/src/EditorToolbar/Tools/Link/LinkButton.tsx +28 -19
  74. package/src/EditorToolbar/Tools/Link/LinkModal.tsx +13 -6
  75. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +27 -26
  76. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +2 -10
  77. package/src/EditorToolbar/Tools/Undo/UndoButton.spec.tsx +22 -1
  78. package/src/EditorToolbar/_floating-toolbar.scss +4 -5
  79. package/src/EditorToolbar/_toolbar.scss +1 -1
  80. package/src/Extensions/CommandsExtension/CommandsExtension.ts +54 -0
  81. package/src/Extensions/Extensions.ts +42 -18
  82. package/src/Extensions/ImageExtension/AssetImageExtension.spec.ts +76 -0
  83. package/src/Extensions/ImageExtension/AssetImageExtension.ts +111 -0
  84. package/src/Extensions/ImageExtension/ImageExtension.ts +17 -1
  85. package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +104 -0
  86. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +128 -0
  87. package/src/Extensions/LinkExtension/LinkExtension.spec.ts +68 -0
  88. package/src/Extensions/LinkExtension/LinkExtension.ts +71 -85
  89. package/src/Extensions/LinkExtension/common.ts +10 -0
  90. package/src/Extensions/PreformattedExtension/PreformattedExtension.spec.ts +41 -0
  91. package/src/Extensions/PreformattedExtension/PreformattedExtension.ts +6 -2
  92. package/src/hooks/index.ts +1 -0
  93. package/src/hooks/useExpandedSelection.ts +44 -0
  94. package/src/index.ts +5 -2
  95. package/src/types.ts +5 -0
  96. package/src/ui/Button/Button.tsx +10 -6
  97. package/src/ui/Button/_button.scss +1 -1
  98. package/src/ui/Fields/Input/Input.spec.tsx +7 -1
  99. package/src/ui/Fields/Input/Input.tsx +23 -4
  100. package/src/ui/Modal/Modal.spec.tsx +15 -0
  101. package/src/ui/Modal/Modal.tsx +8 -4
  102. package/src/ui/ToolbarDropdown/_toolbar-dropdown.scss +1 -1
  103. package/src/ui/_forms.scss +14 -0
  104. package/src/utils/converters/mocks/squizNodeJson.mock.ts +271 -0
  105. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +480 -0
  106. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +212 -0
  107. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +341 -0
  108. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +159 -0
  109. package/src/utils/resolveMatrixAssetUrl.spec.ts +26 -0
  110. package/src/utils/resolveMatrixAssetUrl.ts +7 -0
  111. package/src/utils/undefinedIfEmpty.spec.ts +12 -0
  112. package/src/utils/undefinedIfEmpty.ts +3 -0
  113. package/tailwind.config.cjs +3 -0
  114. package/tests/renderWithEditor.tsx +28 -15
  115. package/tsconfig.json +1 -1
  116. package/lib/FormattedTextEditor.d.ts +0 -2
  117. package/lib/FormattedTextEditor.js +0 -7
  118. package/src/Editor/Editor.mock.tsx +0 -43
  119. package/src/FormattedTextEditor.spec.tsx +0 -10
  120. package/src/FormattedTextEditor.tsx +0 -3
  121. /package/tests/{select.tsx → select.ts} +0 -0
@@ -1,16 +1,23 @@
1
- import { ApplySchemaAttributes, MarkExtensionSpec, MarkSpecOverride } from 'remirror';
2
- import { KeyBindingProps } from '@remirror/core';
3
- import { CommandFunction } from '@remirror/pm';
4
- import { LinkAttributes as RemirrorLinkAttributes, LinkExtension as RemirrorLinkExtension } from 'remirror/extensions';
5
- export type UpdateLinkOptions = LinkAttributes & {
6
- text: string;
7
- };
8
- export type LinkAttributes = RemirrorLinkAttributes & {
1
+ import { ApplySchemaAttributes, FromToProps, MarkExtensionSpec, MarkSpecOverride } from 'remirror';
2
+ import { CommandFunction, MarkExtension } from '@remirror/core';
3
+ import { LinkTarget } from './common';
4
+ export type LinkAttributes = {
5
+ href: string;
9
6
  title?: string;
7
+ target: LinkTarget;
8
+ };
9
+ export type LinkOptions = {
10
+ defaultTarget?: LinkTarget;
11
+ supportedTargets?: LinkTarget[];
12
+ };
13
+ export type UpdateLinkProps = {
14
+ text: string;
15
+ attrs: Partial<LinkAttributes>;
16
+ range: FromToProps;
10
17
  };
11
- export declare class LinkExtension extends RemirrorLinkExtension {
18
+ export declare class LinkExtension extends MarkExtension<LinkOptions> {
19
+ get name(): string;
12
20
  createMarkSpec(extra: ApplySchemaAttributes, override: MarkSpecOverride): MarkExtensionSpec;
13
- shortcut({ tr }: KeyBindingProps): boolean;
14
- selectLink(): CommandFunction;
15
- updateLink(options: UpdateLinkOptions): CommandFunction;
21
+ updateLink({ text, attrs, range }: UpdateLinkProps): CommandFunction;
22
+ removeLink(): CommandFunction;
16
23
  }
@@ -1,18 +1,31 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
2
8
  Object.defineProperty(exports, "__esModule", { value: true });
3
9
  exports.LinkExtension = void 0;
4
10
  const remirror_1 = require("remirror");
5
11
  const core_1 = require("@remirror/core");
6
- const extensions_1 = require("remirror/extensions");
7
- class LinkExtension extends extensions_1.LinkExtension {
12
+ const common_1 = require("./common");
13
+ const CommandsExtension_1 = require("../CommandsExtension/CommandsExtension");
14
+ const Extensions_1 = require("../Extensions");
15
+ let LinkExtension = class LinkExtension extends core_1.MarkExtension {
16
+ get name() {
17
+ return Extensions_1.MarkName.Link;
18
+ }
8
19
  createMarkSpec(extra, override) {
9
- const spec = super.createMarkSpec(extra, override);
10
20
  return {
11
- ...spec,
12
- excludes: undefined,
21
+ inclusive: false,
22
+ excludes: Extensions_1.MarkName.AssetLink,
23
+ ...override,
13
24
  attrs: {
14
- ...spec.attrs,
25
+ ...extra.defaults(),
26
+ href: {},
15
27
  title: { default: undefined },
28
+ target: { default: this.options.defaultTarget },
16
29
  },
17
30
  parseDOM: [
18
31
  {
@@ -23,75 +36,52 @@ class LinkExtension extends extensions_1.LinkExtension {
23
36
  }
24
37
  return {
25
38
  ...extra.parse(node),
26
- auto: false,
27
39
  href: node.getAttribute('href'),
28
- target: node.getAttribute('target'),
29
40
  title: node.getAttribute('title'),
41
+ target: (0, common_1.validateTarget)(node.getAttribute('target'), this.options.supportedTargets, this.options.defaultTarget),
30
42
  };
31
43
  },
32
44
  },
33
45
  ],
46
+ toDOM: (node) => {
47
+ const { target, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
48
+ const rel = 'noopener noreferrer nofollow';
49
+ const attrs = {
50
+ ...extra.dom(node),
51
+ ...rest,
52
+ rel,
53
+ target: (0, common_1.validateTarget)(target, this.options.supportedTargets, this.options.defaultTarget),
54
+ };
55
+ return ['a', attrs, 0];
56
+ },
34
57
  };
35
58
  }
36
- shortcut({ tr }) {
37
- // override parent implementation to allow a link to be inserted without requiring a text selection first.
38
- const { from, to, $from } = tr.selection;
39
- const mark = (0, core_1.getMarkRange)($from, this.type);
40
- const selectedText = tr.doc.textBetween(from, to);
41
- this.options.onShortcut({
42
- activeLink: mark ? { attrs: mark.mark.attrs, from: mark.from, to: mark.to } : undefined,
43
- selectedText,
44
- from,
45
- to,
59
+ updateLink({ text, attrs, range }) {
60
+ return this.store.getExtension(CommandsExtension_1.CommandsExtension).updateMark({
61
+ attrs,
62
+ text,
63
+ range,
64
+ mark: this.type,
65
+ removeMark: !attrs.href,
46
66
  });
47
- return true;
48
67
  }
49
- selectLink() {
50
- // parent implementation selects only the link text, this mimics closer to Google Docs where
51
- // the select text is widened to include the link but retains non-link selected text as well.
52
- return (props) => {
53
- const { tr } = props;
54
- const ranges = (0, remirror_1.getMarkRanges)(tr.selection, this.type);
55
- if (ranges.length === 0) {
56
- return false;
57
- }
58
- // work out the start position of the first link and end position of the last link in the selection.
59
- const from = Math.min(tr.selection.from, ...ranges.map((range) => range.from));
60
- const to = Math.max(tr.selection.to, ...ranges.map((range) => range.to));
61
- // don't need to widen the selection, return early.
62
- if (tr.selection.from === from && tr.selection.to === to) {
63
- return false;
64
- }
65
- // widen the selection to make sure the full link is included.
66
- this.store.commands.selectText.original({ from, to })(props);
67
- return true;
68
- };
69
- }
70
- updateLink(options) {
71
- const { text, ...attrs } = options;
72
- return (props) => {
73
- const { tr, dispatch, view } = props;
74
- const range = { from: tr.selection.from, to: tr.selection.to };
75
- const selectedText = tr.doc.textBetween(range.from, range.to);
76
- if (text !== selectedText) {
77
- // update the text in the editor if it was updated, update the range to cover the length of the new text.
78
- tr.insertText(text);
79
- range.to = range.from + text.length;
80
- }
81
- // apply the link, or remove it if no URL was provided.
82
- if (attrs.href.length > 0) {
83
- tr.addMark(range.from, range.to, this.type.create(attrs));
84
- }
85
- else {
86
- tr.removeMark(range.from, range.to, this.type);
87
- }
88
- // move the cursor to the end of the link and re-focus the editor.
89
- tr.setSelection((0, core_1.getTextSelection)({ from: range.to, to: range.to }, tr.doc));
90
- // apply the transaction.
91
- dispatch?.(tr);
92
- view?.focus();
93
- return true;
94
- };
68
+ removeLink() {
69
+ return (0, core_1.removeMark)({ type: this.type });
95
70
  }
96
- }
71
+ };
72
+ __decorate([
73
+ (0, core_1.command)()
74
+ ], LinkExtension.prototype, "updateLink", null);
75
+ __decorate([
76
+ (0, core_1.command)()
77
+ ], LinkExtension.prototype, "removeLink", null);
78
+ LinkExtension = __decorate([
79
+ (0, core_1.extension)({
80
+ defaultOptions: {
81
+ defaultTarget: common_1.LinkTarget.Self,
82
+ supportedTargets: [common_1.LinkTarget.Self, common_1.LinkTarget.Blank],
83
+ },
84
+ defaultPriority: remirror_1.ExtensionPriority.Medium,
85
+ })
86
+ ], LinkExtension);
97
87
  exports.LinkExtension = LinkExtension;
@@ -0,0 +1,7 @@
1
+ export declare enum LinkTarget {
2
+ Self = "_self",
3
+ Blank = "_blank",
4
+ Parent = "_parent",
5
+ Top = "_top"
6
+ }
7
+ export declare const validateTarget: (target: unknown, supportedTargets: LinkTarget[], defaultTarget: LinkTarget) => LinkTarget;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateTarget = exports.LinkTarget = void 0;
4
+ var LinkTarget;
5
+ (function (LinkTarget) {
6
+ LinkTarget["Self"] = "_self";
7
+ LinkTarget["Blank"] = "_blank";
8
+ LinkTarget["Parent"] = "_parent";
9
+ LinkTarget["Top"] = "_top";
10
+ })(LinkTarget = exports.LinkTarget || (exports.LinkTarget = {}));
11
+ const validateTarget = (target, supportedTargets, defaultTarget) => {
12
+ return supportedTargets.includes(target) ? target : defaultTarget;
13
+ };
14
+ exports.validateTarget = validateTarget;
@@ -1,7 +1,7 @@
1
1
  import { ApplySchemaAttributes, CommandFunction, NodeExtension, NodeExtensionSpec, NodeSpecOverride } from '@remirror/core';
2
2
  export declare class PreformattedExtension extends NodeExtension {
3
3
  get name(): "preformatted";
4
- createTags(): ("formattingNode" | "block" | "textBlock")[];
4
+ createTags(): ("block" | "formattingNode" | "textBlock")[];
5
5
  createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec;
6
6
  /**
7
7
  * Toggle the <pre> for the current block.
@@ -24,9 +24,13 @@ let PreformattedExtension = class PreformattedExtension extends core_1.NodeExten
24
24
  attrs: {
25
25
  ...extra.defaults(),
26
26
  },
27
- parseDOM: [...(override.parseDOM ?? [])],
27
+ parseDOM: [
28
+ {
29
+ tag: 'pre',
30
+ },
31
+ ],
28
32
  toDOM: (node) => {
29
- return [`pre`, extra.dom(node), 0];
33
+ return ['pre', extra.dom(node), 0];
30
34
  },
31
35
  };
32
36
  }
@@ -1 +1,2 @@
1
1
  export * from './useExtensionNames';
2
+ export * from './useExpandedSelection';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./useExtensionNames"), exports);
18
+ __exportStar(require("./useExpandedSelection"), exports);
@@ -0,0 +1,23 @@
1
+ import { Selection } from '@remirror/core';
2
+ import { Mark, MarkType } from 'remirror';
3
+ export type ExpandedSelection = {
4
+ selection: Selection;
5
+ marks: Mark[];
6
+ };
7
+ /**
8
+ * Returns a single range that is either:
9
+ * 1. The current selection if the current selection does not contain any of the indicated marks.
10
+ * 2. An expanded version of the current selection if the range contains any of the indicated marks.
11
+ *
12
+ * For example, given the content:
13
+ *
14
+ * <strong>Bold</strong> regular <u>underline</u> <u>more underline</u>
15
+ *
16
+ * If the marks passed in are 'bold' and 'underline' and the text "old regular under" is selected
17
+ * the returned range will be "Bold regular underline".
18
+ *
19
+ * @param {(MarkType|string)[]} markTypes
20
+ *
21
+ * @return {ExpandedSelection}
22
+ */
23
+ export declare const useExpandedSelection: (markTypes: (MarkType | string)[]) => ExpandedSelection;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useExpandedSelection = void 0;
4
+ const remirror_1 = require("remirror");
5
+ const react_1 = require("@remirror/react");
6
+ /**
7
+ * Returns a single range that is either:
8
+ * 1. The current selection if the current selection does not contain any of the indicated marks.
9
+ * 2. An expanded version of the current selection if the range contains any of the indicated marks.
10
+ *
11
+ * For example, given the content:
12
+ *
13
+ * <strong>Bold</strong> regular <u>underline</u> <u>more underline</u>
14
+ *
15
+ * If the marks passed in are 'bold' and 'underline' and the text "old regular under" is selected
16
+ * the returned range will be "Bold regular underline".
17
+ *
18
+ * @param {(MarkType|string)[]} markTypes
19
+ *
20
+ * @return {ExpandedSelection}
21
+ */
22
+ const useExpandedSelection = (markTypes) => {
23
+ const { doc, selection } = (0, react_1.useEditorState)();
24
+ const ranges = [];
25
+ markTypes.forEach((markType) => {
26
+ ranges.push(...(0, remirror_1.getMarkRanges)(selection, markType));
27
+ });
28
+ if (ranges.length === 0) {
29
+ return { selection, marks: [] };
30
+ }
31
+ // work out the start position of the first link and end position of the last link in the selection.
32
+ const from = Math.min(selection.from, ...ranges.map((range) => range.from));
33
+ const to = Math.max(selection.to, ...ranges.map((range) => range.to));
34
+ const marks = ranges.map((range) => range.mark);
35
+ return { selection: (0, remirror_1.getTextSelection)({ from, to }, doc), marks };
36
+ };
37
+ exports.useExpandedSelection = useExpandedSelection;
package/lib/index.css CHANGED
@@ -388,6 +388,10 @@
388
388
  margin-top: 1.5rem !important;
389
389
  margin-bottom: 1.5rem !important;
390
390
  }
391
+ .squiz-fte-scope .my-auto {
392
+ margin-top: auto !important;
393
+ margin-bottom: auto !important;
394
+ }
391
395
  .squiz-fte-scope .-mr-3 {
392
396
  margin-right: -0.75rem !important;
393
397
  }
@@ -444,9 +448,6 @@
444
448
  .squiz-fte-scope .flex-row {
445
449
  flex-direction: row !important;
446
450
  }
447
- .squiz-fte-scope .items-end {
448
- align-items: flex-end !important;
449
- }
450
451
  .squiz-fte-scope .items-center {
451
452
  align-items: center !important;
452
453
  }
@@ -662,10 +663,24 @@
662
663
  .squiz-fte-scope .squiz-fte-form-control:active {
663
664
  box-shadow: none;
664
665
  }
666
+ .squiz-fte-scope .squiz-fte-invalid-form-field .squiz-fte-form-control {
667
+ --tw-border-opacity: 1;
668
+ border-color: rgb(215 35 33 / var(--tw-border-opacity));
669
+ background-repeat: no-repeat;
670
+ padding-right: 2rem;
671
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0ibm9uZSIvPjxnIGNsYXNzPSJjdXJyZW50TGF5ZXIiPjxwYXRoIGQ9Ik00LjQ3IDIxaDE1LjA2YzEuNTQgMCAyLjUtMS42NyAxLjczLTNMMTMuNzMgNC45OWMtLjc3LTEuMzMtMi42OS0xLjMzLTMuNDYgMEwyLjc0IDE4Yy0uNzcgMS4zMy4xOSAzIDEuNzMgM3pNMTIgMTRjLS41NSAwLTEtLjQ1LTEtMXYtMmMwLS41NS40NS0xIDEtMXMxIC40NSAxIDF2MmMwIC41NS0uNDUgMS0xIDF6bTEgNGgtMnYtMmgydjJ6IiBjbGFzcz0ic2VsZWN0ZWQiIGZpbGw9IiNkNzIzMjEiLz48L2c+PC9zdmc+);
672
+ background-position: top 0.25rem right 0.25rem;
673
+ background-size: 1.5rem;
674
+ }
675
+ .squiz-fte-scope .squiz-fte-form-error {
676
+ --tw-text-opacity: 1;
677
+ color: rgb(215 35 33 / var(--tw-text-opacity));
678
+ font-size: 13px;
679
+ line-height: 1.23;
680
+ padding-top: 0.25rem;
681
+ }
665
682
  .squiz-fte-scope .formatted-text-editor {
666
683
  font-family: "Open Sans" !important;
667
- }
668
- .squiz-fte-scope .formatted-text-editor.editor-wrapper {
669
684
  border-radius: 4px;
670
685
  border-width: 2px;
671
686
  border-style: solid;
@@ -692,6 +707,7 @@
692
707
  var(--tw-ring-shadow, 0 0 #0000),
693
708
  var(--tw-shadow);
694
709
  overflow: auto;
710
+ min-height: 15vh;
695
711
  }
696
712
  .squiz-fte-scope .formatted-text-editor .remirror-editor:active,
697
713
  .squiz-fte-scope .formatted-text-editor .remirror-editor:focus {
@@ -700,6 +716,14 @@
700
716
  .squiz-fte-scope .formatted-text-editor .remirror-editor p {
701
717
  display: block;
702
718
  }
719
+ .squiz-fte-scope .formatted-text-editor--is-disabled .remirror-editor {
720
+ cursor: not-allowed;
721
+ --tw-bg-opacity: 1;
722
+ background-color: rgb(224 224 224 / var(--tw-bg-opacity));
723
+ }
724
+ .squiz-fte-scope .formatted-text-editor--is-disabled .remirror-is-empty:first-of-type::before {
725
+ display: none;
726
+ }
703
727
  .squiz-fte-scope .formatted-text-editor .remirror-is-empty:first-of-type::before {
704
728
  position: absolute;
705
729
  pointer-events: none;
@@ -709,7 +733,17 @@
709
733
  --tw-text-opacity: 1;
710
734
  color: rgb(148 148 148 / var(--tw-text-opacity));
711
735
  }
712
- .squiz-fte-scope .editor-toolbar {
736
+ .squiz-fte-scope .formatted-text-editor .ProseMirror-selectednode {
737
+ border-width: 2px;
738
+ border-style: solid;
739
+ --tw-border-opacity: 1;
740
+ border-color: rgb(7 116 210 / var(--tw-border-opacity));
741
+ }
742
+ .squiz-fte-scope .formatted-text-editor img {
743
+ display: inline;
744
+ }
745
+ .squiz-fte-scope .editor-toolbar,
746
+ .squiz-fte-scope__floating-popover {
713
747
  border-bottom-width: 2px;
714
748
  border-style: solid;
715
749
  --tw-border-opacity: 1;
@@ -720,10 +754,12 @@
720
754
  display: flex;
721
755
  justify-items: center;
722
756
  }
723
- .squiz-fte-scope .editor-toolbar > *:not(:first-child, .editor-divider) {
757
+ .squiz-fte-scope .editor-toolbar > *:not(:first-child, .editor-divider),
758
+ .squiz-fte-scope .squiz-fte-scope__floating-popover > *:not(:first-child, .editor-divider) {
724
759
  margin: 0 0 0 2px;
725
760
  }
726
- .squiz-fte-scope .editor-toolbar .editor-divider {
761
+ .squiz-fte-scope .editor-toolbar .editor-divider,
762
+ .squiz-fte-scope .squiz-fte-scope__floating-popover .editor-divider {
727
763
  margin-top: -0.25rem;
728
764
  margin-bottom: -0.25rem;
729
765
  margin-left: 0.25rem;
@@ -732,10 +768,13 @@
732
768
  margin-right: 2px;
733
769
  height: auto;
734
770
  }
735
- .squiz-fte-scope .editor-toolbar .squiz-fte-btn {
771
+ .squiz-fte-scope .editor-toolbar .squiz-fte-btn,
772
+ .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-btn {
736
773
  padding: 0.25rem;
774
+ font-weight: 700;
737
775
  }
738
- .squiz-fte-scope .editor-toolbar .squiz-fte-btn ~ .squiz-fte-btn {
776
+ .squiz-fte-scope .editor-toolbar .squiz-fte-btn ~ .squiz-fte-btn,
777
+ .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-btn ~ .squiz-fte-btn {
739
778
  margin-left: 2px;
740
779
  }
741
780
  .squiz-fte-scope__floating-popover {
@@ -754,17 +793,15 @@
754
793
  var(--tw-ring-shadow, 0 0 #0000),
755
794
  var(--tw-shadow);
756
795
  }
757
- .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-btn {
758
- padding: 0.25rem;
759
- }
760
- .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-btn ~ .squiz-fte-btn {
761
- margin-left: 2px;
796
+ .squiz-fte-scope .squiz-fte-scope__floating-popover .editor-divider {
797
+ margin-top: 0px;
798
+ margin-bottom: 0px;
762
799
  }
763
800
  .squiz-fte-scope .squiz-fte-btn {
764
801
  border-radius: 4px;
765
802
  --tw-bg-opacity: 1;
766
803
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
767
- font-weight: 400;
804
+ font-weight: 700;
768
805
  --tw-text-opacity: 1;
769
806
  color: rgb(112 112 112 / var(--tw-text-opacity));
770
807
  transition-property: all;
@@ -807,6 +844,7 @@
807
844
  .squiz-fte-scope .toolbar-dropdown__button {
808
845
  display: flex;
809
846
  align-items: center;
847
+ border-radius: 4px;
810
848
  font-family:
811
849
  Open Sans,
812
850
  Arial,
@@ -923,15 +961,12 @@
923
961
  font-size: 0.875rem;
924
962
  font-weight: 700;
925
963
  }
926
- .squiz-fte-scope .editor-toolbar .squiz-fte-modal-footer__button {
927
- padding: 0.25rem;
928
- }
929
- .squiz-fte-scope .editor-toolbar .squiz-fte-modal-footer__button ~ .squiz-fte-btn {
930
- margin-left: 2px;
931
- }
964
+ .squiz-fte-scope .editor-toolbar .squiz-fte-modal-footer__button,
932
965
  .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-modal-footer__button {
933
966
  padding: 0.25rem;
967
+ font-weight: 700;
934
968
  }
969
+ .squiz-fte-scope .editor-toolbar .squiz-fte-modal-footer__button ~ .squiz-fte-btn,
935
970
  .squiz-fte-scope .squiz-fte-scope__floating-popover .squiz-fte-modal-footer__button ~ .squiz-fte-btn {
936
971
  margin-left: 2px;
937
972
  }
@@ -939,7 +974,7 @@
939
974
  border-radius: 4px;
940
975
  --tw-bg-opacity: 1;
941
976
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
942
- font-weight: 400;
977
+ font-weight: 700;
943
978
  --tw-text-opacity: 1;
944
979
  color: rgb(112 112 112 / var(--tw-text-opacity));
945
980
  transition-property: all;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
- import FormattedTextEditor from './FormattedTextEditor';
2
- export { FormattedTextEditor };
1
+ import Editor from './Editor/Editor';
2
+ import { EditorContext } from './Editor/EditorContext';
3
+ import { remirrorNodeToSquizNode } from './utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode';
4
+ import { squizNodeToRemirrorNode } from './utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode';
5
+ export { Editor, EditorContext, remirrorNodeToSquizNode, squizNodeToRemirrorNode };
package/lib/index.js CHANGED
@@ -3,6 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FormattedTextEditor = void 0;
7
- const FormattedTextEditor_1 = __importDefault(require("./FormattedTextEditor"));
8
- exports.FormattedTextEditor = FormattedTextEditor_1.default;
6
+ exports.squizNodeToRemirrorNode = exports.remirrorNodeToSquizNode = exports.EditorContext = exports.Editor = void 0;
7
+ const Editor_1 = __importDefault(require("./Editor/Editor"));
8
+ exports.Editor = Editor_1.default;
9
+ const EditorContext_1 = require("./Editor/EditorContext");
10
+ Object.defineProperty(exports, "EditorContext", { enumerable: true, get: function () { return EditorContext_1.EditorContext; } });
11
+ const remirrorNodeToSquizNode_1 = require("./utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode");
12
+ Object.defineProperty(exports, "remirrorNodeToSquizNode", { enumerable: true, get: function () { return remirrorNodeToSquizNode_1.remirrorNodeToSquizNode; } });
13
+ const squizNodeToRemirrorNode_1 = require("./utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode");
14
+ Object.defineProperty(exports, "squizNodeToRemirrorNode", { enumerable: true, get: function () { return squizNodeToRemirrorNode_1.squizNodeToRemirrorNode; } });
package/lib/types.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export type DeepPartial<T> = T extends Record<string, unknown> ? {
2
+ [P in keyof T]?: DeepPartial<T[P]>;
3
+ } : T;
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -6,6 +6,7 @@ type ButtonProps = {
6
6
  label: string;
7
7
  text?: string;
8
8
  icon?: ReactElement;
9
+ className?: string;
9
10
  };
10
- declare const Button: ({ handleOnClick, isDisabled, isActive, label, text, icon }: ButtonProps) => JSX.Element;
11
+ declare const Button: ({ handleOnClick, isDisabled, isActive, label, text, icon, className }: ButtonProps) => JSX.Element;
11
12
  export default Button;
@@ -5,10 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const clsx_1 = __importDefault(require("clsx"));
8
- const Button = ({ handleOnClick, isDisabled, isActive, label, text, icon }) => {
9
- return (react_1.default.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: (0, clsx_1.default)('squiz-fte-btn', isActive && 'squiz-fte-btn--is-active', icon && ' squiz-fte-btn--is-icon') },
10
- react_1.default.createElement(react_1.default.Fragment, null,
11
- text && react_1.default.createElement("span", null, text),
12
- icon && icon)));
8
+ const Button = ({ handleOnClick, isDisabled, isActive, label, text, icon, className }) => {
9
+ return (react_1.default.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: (0, clsx_1.default)('squiz-fte-btn', isActive && 'squiz-fte-btn--is-active', icon && ' squiz-fte-btn--is-icon', className) },
10
+ text && react_1.default.createElement("span", null, text),
11
+ icon && icon));
13
12
  };
14
13
  exports.default = Button;
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  export declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & {
3
3
  label?: string | undefined;
4
+ error?: string | undefined;
4
5
  } & React.RefAttributes<HTMLInputElement>>;
@@ -22,12 +22,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  exports.Input = void 0;
27
30
  const react_1 = __importStar(require("react"));
28
- const InputInternal = ({ name, label, type = 'text', ...rest }, ref) => {
29
- return (react_1.default.createElement(react_1.default.Fragment, null,
31
+ const clsx_1 = __importDefault(require("clsx"));
32
+ const InputInternal = ({ name, label, type = 'text', error, required, ...rest }, ref) => {
33
+ return (react_1.default.createElement("div", { className: (0, clsx_1.default)(error && 'squiz-fte-invalid-form-field') },
30
34
  label && (react_1.default.createElement("label", { htmlFor: name, className: "squiz-fte-form-label" }, label)),
31
- react_1.default.createElement("input", { ref: ref, id: name, name: name, type: type, className: "squiz-fte-form-control", ...rest })));
35
+ required && (react_1.default.createElement("span", { className: "text-gray-600", "aria-label": "Required field" }, "*")),
36
+ react_1.default.createElement("input", { ref: ref, id: name, name: name, type: type, "aria-invalid": !!error, className: "squiz-fte-form-control", ...rest }),
37
+ error && react_1.default.createElement("div", { className: "squiz-fte-form-error" }, error)));
32
38
  };
33
39
  exports.Input = (0, react_1.forwardRef)(InputInternal);
@@ -30,7 +30,9 @@ const react_1 = __importStar(require("react"));
30
30
  const react_dom_1 = require("react-dom");
31
31
  const CloseRounded_1 = __importDefault(require("@mui/icons-material/CloseRounded"));
32
32
  const base_1 = require("@mui/base");
33
+ const clsx_1 = __importDefault(require("clsx"));
33
34
  const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
35
+ const content = (0, react_1.useRef)(null);
34
36
  const container = (0, react_1.useMemo)(() => {
35
37
  const element = document.createElement('div');
36
38
  element.classList.add('squiz-fte-scope');
@@ -51,7 +53,7 @@ const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
51
53
  }, []);
52
54
  // add/remove the modal container from the DOM and focus on the first input
53
55
  (0, react_1.useEffect)(() => {
54
- const firstInput = container.querySelector('input:not([type=hidden])');
56
+ const firstInput = content.current?.querySelector('input:not([type=hidden]), button');
55
57
  document.body.appendChild(container);
56
58
  firstInput?.focus();
57
59
  return () => {
@@ -60,14 +62,14 @@ const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
60
62
  }, [container]);
61
63
  return (0, react_dom_1.createPortal)(react_1.default.createElement(react_1.default.Fragment, null,
62
64
  react_1.default.createElement(base_1.FocusTrap, { open: true },
63
- react_1.default.createElement("div", { ref: ref, className: `squiz-fte-modal-wrapper ${className ? className : ''}`, tabIndex: -1 },
65
+ react_1.default.createElement("div", { ref: ref, className: (0, clsx_1.default)('squiz-fte-modal-wrapper', className), tabIndex: -1 },
64
66
  react_1.default.createElement("div", { className: "w-modal-sm my-6 mx-auto" },
65
67
  react_1.default.createElement("div", { className: "squiz-fte-modal" },
66
68
  react_1.default.createElement("div", { className: "squiz-fte-modal-header p-6 pb-2" },
67
69
  react_1.default.createElement("h2", { className: "font-semibold text-gray-900 text-heading-2" }, title),
68
70
  react_1.default.createElement("button", { type: "button", className: "ml-auto -mr-3 -mt-3 bg-transparent border-0 text-gray-600 font-semibold outline-none focus:outline-none hover:text-color-gray-800", onClick: onCancel, "aria-label": "Close" },
69
71
  react_1.default.createElement(CloseRounded_1.default, null))),
70
- react_1.default.createElement("div", { className: "squiz-fte-modal-content" }, children),
72
+ react_1.default.createElement("div", { className: "squiz-fte-modal-content", ref: content }, children),
71
73
  react_1.default.createElement("div", { className: "squiz-fte-modal-footer p-6 pt-3" },
72
74
  react_1.default.createElement("button", { className: "squiz-fte-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300", type: "button", onClick: onCancel, "aria-label": "Cancel" }, "Cancel"),
73
75
  onSubmit && (react_1.default.createElement("button", { className: "squiz-fte-modal-footer__button bg-blue-300 text-white hover:bg-blue-400", type: "button", onClick: onSubmit, "aria-label": "Apply" }, "Apply"))))))),
@@ -0,0 +1,9 @@
1
+ import { ProsemirrorNode } from 'remirror';
2
+ import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
3
+ export declare const resolveNodeTag: (node: ProsemirrorNode) => string;
4
+ /**
5
+ * Converts Remirror node JSON structure to Squiz component JSON structure.
6
+ * @param {ProsemirrorNode} node Remirror node to convert to component.
7
+ * @returns {FormattedText} The converted Squiz component JSON.
8
+ */
9
+ export declare const remirrorNodeToSquizNode: (node: ProsemirrorNode) => FormattedTextModels.v1.FormattedText;