@squiz/formatted-text-editor 1.33.1-alpha.3 → 1.33.1-alpha.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 (57) hide show
  1. package/demo/App.tsx +4 -24
  2. package/demo/AppContext.tsx +28 -0
  3. package/demo/index.scss +0 -2
  4. package/demo/main.tsx +2 -0
  5. package/demo/resources.json +28 -0
  6. package/demo/sources.json +23 -0
  7. package/lib/Editor/EditorContext.d.ts +0 -7
  8. package/lib/Editor/EditorContext.js +0 -2
  9. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +8 -19
  10. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +6 -38
  11. package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +1 -1
  12. package/lib/Extensions/Extensions.js +0 -2
  13. package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +0 -1
  14. package/lib/Extensions/ImageExtension/AssetImageExtension.js +1 -2
  15. package/lib/Extensions/LinkExtension/AssetLinkExtension.d.ts +0 -1
  16. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +1 -2
  17. package/lib/index.css +7 -2
  18. package/lib/types.d.ts +3 -3
  19. package/lib/ui/Fields/Checkbox/Checkbox.js +1 -1
  20. package/lib/ui/Fields/Input/Input.d.ts +2 -4
  21. package/lib/ui/Fields/Input/Input.js +3 -9
  22. package/lib/ui/Fields/InputContainer/InputContainer.d.ts +9 -0
  23. package/lib/ui/Fields/InputContainer/InputContainer.js +16 -0
  24. package/lib/ui/Fields/MatrixAsset/MatrixAsset.d.ts +17 -0
  25. package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +29 -0
  26. package/lib/utils/validation.d.ts +2 -1
  27. package/lib/utils/validation.js +8 -2
  28. package/package.json +4 -3
  29. package/src/Editor/Editor.spec.tsx +1 -1
  30. package/src/Editor/EditorContext.spec.tsx +11 -13
  31. package/src/Editor/EditorContext.ts +0 -11
  32. package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +27 -10
  33. package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +25 -29
  34. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +69 -43
  35. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +15 -5
  36. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +14 -20
  37. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +45 -29
  38. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +47 -4
  39. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +3 -2
  40. package/src/Extensions/Extensions.ts +0 -2
  41. package/src/Extensions/ImageExtension/AssetImageExtension.ts +1 -3
  42. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +1 -3
  43. package/src/types.ts +7 -5
  44. package/src/ui/Fields/Checkbox/Checkbox.tsx +1 -1
  45. package/src/ui/Fields/Input/Input.tsx +4 -18
  46. package/src/ui/Fields/InputContainer/InputContainer.spec.tsx +18 -0
  47. package/src/ui/Fields/InputContainer/InputContainer.tsx +29 -0
  48. package/src/ui/Fields/MatrixAsset/MatrixAsset.spec.tsx +103 -0
  49. package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +55 -0
  50. package/src/ui/_forms.scss +4 -2
  51. package/src/utils/validation.spec.ts +22 -0
  52. package/src/utils/validation.ts +9 -1
  53. package/tests/index.ts +2 -0
  54. package/tests/mockResourceBrowserContext.tsx +63 -0
  55. package/tests/renderWithContext.tsx +18 -0
  56. package/tests/renderWithEditor.tsx +18 -21
  57. package/vite.config.ts +8 -0
package/demo/App.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import React, { useState } from 'react';
2
- import { Editor, EditorContext, remirrorNodeToSquizNode, squizNodeToRemirrorNode } from '../src';
2
+ import { Editor, remirrorNodeToSquizNode, squizNodeToRemirrorNode } from '../src';
3
3
  import { RemirrorEventListener, Extension } from '@remirror/core';
4
4
  import ReactDiffViewer from 'react-diff-viewer-continued';
5
+ import { AppContext } from './AppContext';
5
6
 
6
7
  function App() {
7
8
  const [doc, setDoc] = useState('');
@@ -35,34 +36,13 @@ function App() {
35
36
  </div>
36
37
  <h1>Editor</h1>
37
38
  <div className="page-section">
38
- <EditorContext.Provider
39
- value={{
40
- matrix: {
41
- matrixDomain: 'https://matrix-domain.squiz.net',
42
- matrixIdentifier: 'matrix-api-identifier',
43
- resolveMatrixAsset: (assetId: string) => {
44
- return new Promise((resolve) => {
45
- setTimeout(() => {
46
- if (assetId.match(/invalid/i)) {
47
- resolve(null);
48
- } else {
49
- resolve({
50
- id: assetId,
51
- type: assetId.match(/(image)/i)?.[0] || 'unknown',
52
- });
53
- }
54
- }, 200);
55
- });
56
- },
57
- },
58
- }}
59
- >
39
+ <AppContext>
60
40
  <Editor
61
41
  editable={editable}
62
42
  content={`<p>Hello <a href="https://www.google.com"><strong>Mr Bean</strong></a>, nice to <a href="https://www.google.com">meet you</a>.<img src="https://media2.giphy.com/media/3o6ozsIxg5legYvggo/giphy.gif" height="150" width="200"/></p>`}
63
43
  onChange={handleEditorChange}
64
44
  />
65
- </EditorContext.Provider>
45
+ </AppContext>
66
46
  </div>
67
47
  <h1>Document</h1>
68
48
  <div className="page-section">
@@ -0,0 +1,28 @@
1
+ import React, { PropsWithChildren } from 'react';
2
+ import { ResourceBrowserContext, Source, Resource, ResourceReference } from '@squiz/resource-browser';
3
+ import { EditorContext } from '../src';
4
+ import resources from './resources.json';
5
+ import sources from './sources.json';
6
+
7
+ export type AppContextProps = PropsWithChildren;
8
+
9
+ export const AppContext = ({ children }: AppContextProps) => (
10
+ <ResourceBrowserContext.Provider
11
+ value={{
12
+ onRequestSources: (): Promise<Source> => Promise.resolve(sources),
13
+ onRequestChildren: (): Promise<Resource[]> => Promise.resolve(resources),
14
+ onRequestResource: (reference: ResourceReference): Promise<Resource | null> =>
15
+ Promise.resolve(resources.find((resource) => resource.id === reference.resource) || null),
16
+ }}
17
+ >
18
+ <EditorContext.Provider
19
+ value={{
20
+ matrix: {
21
+ matrixDomain: 'https://matrix-domain.squiz.net',
22
+ },
23
+ }}
24
+ >
25
+ {children}
26
+ </EditorContext.Provider>
27
+ </ResourceBrowserContext.Provider>
28
+ );
package/demo/index.scss CHANGED
@@ -1,5 +1,3 @@
1
- @import '../src/index.scss';
2
-
3
1
  body {
4
2
  font-family: 'Open Sans';
5
3
  }
package/demo/main.tsx CHANGED
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
2
  import ReactDOM from 'react-dom/client';
3
3
  import App from './App';
4
+ import '@squiz/resource-browser/lib/index.css';
5
+ import '../src/index.scss';
4
6
  import './index.scss';
5
7
 
6
8
  ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
@@ -0,0 +1,28 @@
1
+ [
2
+ {
3
+ "id": "1",
4
+ "type": {
5
+ "code": "image",
6
+ "name": "Image"
7
+ },
8
+ "status": {
9
+ "code": "live",
10
+ "name": "Live"
11
+ },
12
+ "name": "Example image",
13
+ "childCount": 0
14
+ },
15
+ {
16
+ "id": "2",
17
+ "type": {
18
+ "code": "page_standard",
19
+ "name": "Standard Page"
20
+ },
21
+ "status": {
22
+ "code": "live",
23
+ "name": "Live"
24
+ },
25
+ "name": "Example page",
26
+ "childCount": 0
27
+ }
28
+ ]
@@ -0,0 +1,23 @@
1
+ [
2
+ {
3
+ "id": "my-matrix-instance",
4
+ "name": "My Matrix instance",
5
+ "nodes": [
6
+ {
7
+ "id": "1",
8
+ "name": "My site",
9
+ "childCount": 100,
10
+ "url": "https://my-matrix.squiz.net/site",
11
+ "urls": [],
12
+ "type": {
13
+ "code": "site",
14
+ "name": "Site"
15
+ },
16
+ "status": {
17
+ "code": "live",
18
+ "name": "Live"
19
+ }
20
+ }
21
+ ]
22
+ }
23
+ ]
@@ -1,14 +1,7 @@
1
1
  import React from 'react';
2
- export type MatrixAsset = {
3
- id: string;
4
- type: string | 'image';
5
- };
6
- export type MatrixAssetResolver = (assetId: string) => Promise<MatrixAsset | null>;
7
2
  export type EditorContextOptions = {
8
3
  matrix: {
9
- matrixIdentifier: string;
10
4
  matrixDomain: string;
11
- resolveMatrixAsset: MatrixAssetResolver;
12
5
  };
13
6
  };
14
7
  export declare const defaultEditorContext: EditorContextOptions;
@@ -7,9 +7,7 @@ exports.EditorContext = exports.defaultEditorContext = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  exports.defaultEditorContext = {
9
9
  matrix: {
10
- matrixIdentifier: '',
11
10
  matrixDomain: '',
12
- resolveMatrixAsset: () => Promise.resolve(null),
13
11
  },
14
12
  };
15
13
  exports.EditorContext = react_1.default.createContext(exports.defaultEditorContext);
@@ -27,27 +27,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importStar(require("react"));
30
- const Input_1 = require("../../../../ui/Fields/Input/Input");
31
30
  const react_hook_form_1 = require("react-hook-form");
32
31
  const react_image_size_1 = require("react-image-size");
32
+ const clsx_1 = __importDefault(require("clsx"));
33
+ const Input_1 = require("../../../../ui/Fields/Input/Input");
33
34
  const Button_1 = __importDefault(require("../../../../ui/Button/Button"));
34
35
  const LinkOff_1 = __importDefault(require("@mui/icons-material/LinkOff"));
35
36
  const InsertLinkRounded_1 = __importDefault(require("@mui/icons-material/InsertLinkRounded"));
36
- const clsx_1 = __importDefault(require("clsx"));
37
37
  const Extensions_1 = require("../../../../Extensions/Extensions");
38
- const EditorContext_1 = require("../../../../Editor/EditorContext");
39
38
  const validation_1 = require("../../../../utils/validation");
40
39
  const Tabs_1 = require("../../../../ui/Tabs/Tabs");
40
+ const MatrixAsset_1 = require("../../../../ui/Fields/MatrixAsset/MatrixAsset");
41
41
  const imageTypeOptions = {
42
42
  [Extensions_1.NodeName.AssetImage]: { label: 'From source' },
43
43
  [Extensions_1.NodeName.Image]: { label: 'From URL' },
44
44
  };
45
45
  const ImageForm = ({ data, onSubmit }) => {
46
- const { register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
46
+ const { control, register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
47
47
  defaultValues: data,
48
48
  });
49
49
  const imageType = watch('imageType') || Extensions_1.NodeName.AssetImage;
50
- const context = (0, react_1.useContext)(EditorContext_1.EditorContext);
51
50
  const [aspectRatioFromWidth, setAspectRatioFromWidth] = (0, react_1.useState)(9 / 16);
52
51
  const [aspectRatioFromHeight, setAspectRatioFromHeight] = (0, react_1.useState)(16 / 9);
53
52
  const [aspectRatioLocked, setAspectRatioLocked] = (0, react_1.useState)(true);
@@ -136,19 +135,9 @@ const ImageForm = ({ data, onSubmit }) => {
136
135
  }) }))),
137
136
  react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
138
137
  react_1.default.createElement(Input_1.Input, { label: "Alternative description", error: errors?.image?.alt?.message, ...register('image.alt') })))),
139
- imageType === Extensions_1.NodeName.AssetImage && (react_1.default.createElement(react_1.default.Fragment, null,
140
- react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
141
- react_1.default.createElement(Input_1.Input, { label: "Asset ID", required: true, error: errors?.assetImage?.matrixAssetId?.message, ...register('assetImage.matrixAssetId', {
142
- required: 'Asset ID is required',
143
- validate: {
144
- isImage: async (assetId) => {
145
- const asset = await context.matrix.resolveMatrixAsset(assetId);
146
- if (asset?.type !== 'image') {
147
- return 'Asset ID is invalid or not an image';
148
- }
149
- },
150
- noEmptySpaces: validation_1.noEmptySpacesValidation,
151
- },
152
- }) }))))));
138
+ imageType === Extensions_1.NodeName.AssetImage && (react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
139
+ react_1.default.createElement(react_hook_form_1.Controller, { control: control, name: "assetImage", rules: {
140
+ validate: (0, validation_1.hasProperties)('An image must be selected', ['matrixIdentifier', 'matrixAssetId']),
141
+ }, render: ({ field: { onChange, value }, fieldState: { error } }) => (react_1.default.createElement(MatrixAsset_1.MatrixAsset, { modalTitle: "Insert image", allowedTypes: ['image'], value: value, onChange: onChange, error: error?.message })) })))));
153
142
  };
154
143
  exports.default = ImageForm;
@@ -1,49 +1,25 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
4
  };
28
5
  Object.defineProperty(exports, "__esModule", { value: true });
29
6
  exports.LinkForm = void 0;
30
- const react_1 = __importStar(require("react"));
7
+ const react_1 = __importDefault(require("react"));
31
8
  const clsx_1 = __importDefault(require("clsx"));
32
9
  const react_hook_form_1 = require("react-hook-form");
33
10
  const Input_1 = require("../../../../ui/Fields/Input/Input");
34
11
  const Checkbox_1 = require("../../../../ui/Fields/Checkbox/Checkbox");
35
12
  const common_1 = require("../../../../Extensions/LinkExtension/common");
36
- const EditorContext_1 = require("../../../../Editor/EditorContext");
37
13
  const Extensions_1 = require("../../../../Extensions/Extensions");
38
14
  const validation_1 = require("../../../../utils/validation");
39
15
  const Tabs_1 = require("../../../../ui/Tabs/Tabs");
16
+ const MatrixAsset_1 = require("../../../../ui/Fields/MatrixAsset/MatrixAsset");
40
17
  const linkTypeOptions = {
41
18
  [Extensions_1.MarkName.AssetLink]: { label: 'From source' },
42
19
  [Extensions_1.MarkName.Link]: { label: 'From URL' },
43
20
  };
44
21
  const LinkForm = ({ data, onSubmit }) => {
45
- const context = (0, react_1.useContext)(EditorContext_1.EditorContext);
46
- const { register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
22
+ const { control, register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
47
23
  defaultValues: data,
48
24
  });
49
25
  const linkType = watch('linkType') || Extensions_1.MarkName.AssetLink;
@@ -71,17 +47,9 @@ const LinkForm = ({ data, onSubmit }) => {
71
47
  react_1.default.createElement(Checkbox_1.Checkbox, { label: "Open link in new window", onChange: (value) => setValue('link.target', value), defaultChecked: data?.link?.target === common_1.LinkTarget.Blank, unchecked: common_1.LinkTarget.Self, checked: common_1.LinkTarget.Blank })))),
72
48
  linkType === Extensions_1.MarkName.AssetLink && (react_1.default.createElement(react_1.default.Fragment, null,
73
49
  react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
74
- react_1.default.createElement(Input_1.Input, { label: "Asset ID", required: true, error: errors?.assetLink?.matrixAssetId?.message, ...register('assetLink.matrixAssetId', {
75
- required: 'Asset ID is required',
76
- validate: {
77
- isValidAsset: async (assetId) => {
78
- if (assetId && !(await context.matrix.resolveMatrixAsset(assetId))) {
79
- return 'Invalid asset ID';
80
- }
81
- },
82
- noEmptySpaces: validation_1.noEmptySpacesValidation,
83
- },
84
- }) })),
50
+ react_1.default.createElement(react_hook_form_1.Controller, { control: control, name: "assetLink", rules: {
51
+ validate: (0, validation_1.hasProperties)('An asset must be selected', ['matrixIdentifier', 'matrixAssetId']),
52
+ }, render: ({ field: { onChange, value }, fieldState: { error } }) => (react_1.default.createElement(MatrixAsset_1.MatrixAsset, { modalTitle: "Insert link", value: value, onChange: onChange, error: error?.message })) })),
85
53
  react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
86
54
  react_1.default.createElement(Input_1.Input, { label: "Text", required: true, error: errors?.text?.message, ...register('text', {
87
55
  required: 'Text is required',
@@ -33,7 +33,7 @@ const LinkOff_1 = __importDefault(require("@mui/icons-material/LinkOff"));
33
33
  const RemoveLinkButton = ({ inPopover = false }) => {
34
34
  const chain = (0, react_2.useChainedCommands)();
35
35
  const active = (0, react_2.useActive)();
36
- const disabled = !active.link();
36
+ const disabled = !active.link() && !active.assetLink();
37
37
  const handleClick = () => {
38
38
  chain.removeLink().removeAssetLink().focus().run();
39
39
  };
@@ -34,12 +34,10 @@ const createExtensions = (context) => {
34
34
  new ImageExtension_1.ImageExtension(),
35
35
  new ImageExtension_1.ImageExtension({ preferPastedTextContent: false }),
36
36
  new AssetImageExtension_1.AssetImageExtension({
37
- matrixIdentifier: context.matrix.matrixIdentifier,
38
37
  matrixDomain: context.matrix.matrixDomain,
39
38
  }),
40
39
  new LinkExtension_1.LinkExtension(),
41
40
  new AssetLinkExtension_1.AssetLinkExtension({
42
- matrixIdentifier: context.matrix.matrixIdentifier,
43
41
  matrixDomain: context.matrix.matrixDomain,
44
42
  }),
45
43
  ];
@@ -1,7 +1,6 @@
1
1
  import { ApplySchemaAttributes, NodeExtension, NodeExtensionSpec, NodeSpecOverride, CommandFunction } from '@remirror/core';
2
2
  import { NodeName } from '../Extensions';
3
3
  export type AssetImageOptions = {
4
- matrixIdentifier?: string;
5
4
  matrixDomain?: string;
6
5
  };
7
6
  export type AssetImageAttributes = {
@@ -27,7 +27,7 @@ let AssetImageExtension = class AssetImageExtension extends core_1.NodeExtension
27
27
  attrs: {
28
28
  ...extra.defaults(),
29
29
  matrixAssetId: {},
30
- matrixIdentifier: { default: this.options.matrixIdentifier },
30
+ matrixIdentifier: {},
31
31
  matrixDomain: { default: this.options.matrixDomain },
32
32
  },
33
33
  parseDOM: [
@@ -83,7 +83,6 @@ __decorate([
83
83
  AssetImageExtension = __decorate([
84
84
  (0, core_1.extension)({
85
85
  defaultOptions: {
86
- matrixIdentifier: '',
87
86
  matrixDomain: '',
88
87
  },
89
88
  defaultPriority: core_1.ExtensionPriority.High,
@@ -8,7 +8,6 @@ export type AssetLinkAttributes = {
8
8
  target: LinkTarget;
9
9
  };
10
10
  export type AssetLinkOptions = {
11
- matrixIdentifier?: string;
12
11
  matrixDomain?: string;
13
12
  defaultTarget?: LinkTarget;
14
13
  supportedTargets?: LinkTarget[];
@@ -25,7 +25,7 @@ let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
25
25
  attrs: {
26
26
  ...extra.defaults(),
27
27
  matrixAssetId: {},
28
- matrixIdentifier: { default: this.options.matrixIdentifier },
28
+ matrixIdentifier: {},
29
29
  matrixDomain: { default: this.options.matrixDomain },
30
30
  target: { default: this.options.defaultTarget },
31
31
  },
@@ -91,7 +91,6 @@ __decorate([
91
91
  AssetLinkExtension = __decorate([
92
92
  (0, core_1.extension)({
93
93
  defaultOptions: {
94
- matrixIdentifier: '',
95
94
  matrixDomain: '',
96
95
  defaultTarget: common_1.LinkTarget.Self,
97
96
  supportedTargets: [common_1.LinkTarget.Self, common_1.LinkTarget.Blank],
package/lib/index.css CHANGED
@@ -630,6 +630,9 @@
630
630
  --tw-blur: blur(8px) !important;
631
631
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow) !important;
632
632
  }
633
+ .squiz-fte-scope .filter {
634
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow) !important;
635
+ }
633
636
  .squiz-fte-scope a {
634
637
  --tw-text-opacity: 1;
635
638
  color: rgb(7 116 210 / var(--tw-text-opacity));
@@ -683,6 +686,7 @@
683
686
  color: rgb(112 112 112 / var(--tw-text-opacity));
684
687
  }
685
688
  .squiz-fte-scope .squiz-fte-form-control {
689
+ height: 36px;
686
690
  padding: 6px 12px;
687
691
  position: relative;
688
692
  width: 100%;
@@ -716,13 +720,14 @@
716
720
  .squiz-fte-scope .squiz-fte-form-control:active {
717
721
  box-shadow: none;
718
722
  }
719
- .squiz-fte-scope .squiz-fte-invalid-form-field .squiz-fte-form-control {
723
+ .squiz-fte-scope .squiz-fte-invalid-form-field .squiz-fte-form-control,
724
+ .squiz-fte-scope .squiz-fte-invalid-form-field .resource-picker {
720
725
  --tw-border-opacity: 1;
721
726
  border-color: rgb(215 35 33 / var(--tw-border-opacity));
722
727
  background-repeat: no-repeat;
723
728
  padding-right: 2rem;
724
729
  background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0ibm9uZSIvPjxnIGNsYXNzPSJjdXJyZW50TGF5ZXIiPjxwYXRoIGQ9Ik00LjQ3IDIxaDE1LjA2YzEuNTQgMCAyLjUtMS42NyAxLjczLTNMMTMuNzMgNC45OWMtLjc3LTEuMzMtMi42OS0xLjMzLTMuNDYgMEwyLjc0IDE4Yy0uNzcgMS4zMy4xOSAzIDEuNzMgM3pNMTIgMTRjLS41NSAwLTEtLjQ1LTEtMXYtMmMwLS41NS40NS0xIDEtMXMxIC40NSAxIDF2MmMwIC41NS0uNDUgMS0xIDF6bTEgNGgtMnYtMmgydjJ6IiBjbGFzcz0ic2VsZWN0ZWQiIGZpbGw9IiNkNzIzMjEiLz48L2c+PC9zdmc+);
725
- background-position: top 0.25rem right 0.25rem;
730
+ background-position: center right 0.25rem;
726
731
  background-size: 1.5rem;
727
732
  }
728
733
  .squiz-fte-scope .squiz-fte-form-error {
package/lib/types.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type DeepPartial<T> = T extends Record<string, unknown> ? {
2
- [P in keyof T]?: DeepPartial<T[P]>;
3
- } : T;
1
+ export type DeepPartial<T> = {
2
+ [P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
3
+ };
@@ -42,6 +42,6 @@ const Checkbox = ({ label, onChange, defaultChecked = false, unchecked, checked,
42
42
  const toggleCheckbox = () => setToggled(!toggled);
43
43
  return (react_1.default.createElement("div", { className: "squiz-fte-checkbox" },
44
44
  react_1.default.createElement("button", { type: "button", role: "checkbox", "aria-label": label, "aria-checked": toggled, className: "checkbox", onClick: toggleCheckbox }, toggled && react_1.default.createElement(CheckRounded_1.default, null)),
45
- react_1.default.createElement("button", { type: "button", className: "label", onClick: toggleCheckbox }, label)));
45
+ react_1.default.createElement("button", { type: "button", className: "label", onClick: toggleCheckbox, tabIndex: -1 }, label)));
46
46
  };
47
47
  exports.Checkbox = Checkbox;
@@ -1,5 +1,3 @@
1
1
  import React from 'react';
2
- export declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & {
3
- label?: string | undefined;
4
- error?: string | undefined;
5
- } & React.RefAttributes<HTMLInputElement>>;
2
+ import { InputContainerProps } from '../InputContainer/InputContainer';
3
+ export declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & Omit<InputContainerProps, "children"> & React.RefAttributes<HTMLInputElement>>;
@@ -22,18 +22,12 @@ 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
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.Input = void 0;
30
27
  const react_1 = __importStar(require("react"));
31
- const clsx_1 = __importDefault(require("clsx"));
28
+ const InputContainer_1 = require("../InputContainer/InputContainer");
32
29
  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') },
34
- label && (react_1.default.createElement("label", { htmlFor: name, className: "squiz-fte-form-label" }, label)),
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)));
30
+ return (react_1.default.createElement(InputContainer_1.InputContainer, { name: name, label: label, error: error, required: required },
31
+ react_1.default.createElement("input", { ref: ref, id: name, name: name, type: type, "aria-invalid": !!error, className: "squiz-fte-form-control", ...rest })));
38
32
  };
39
33
  exports.Input = (0, react_1.forwardRef)(InputInternal);
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ export type InputContainerProps = {
3
+ name?: string;
4
+ label?: string;
5
+ error?: string;
6
+ required?: boolean;
7
+ children: ReactNode;
8
+ };
9
+ export declare const InputContainer: ({ name, label, error, required, children }: InputContainerProps) => JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.InputContainer = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const clsx_1 = __importDefault(require("clsx"));
9
+ const InputContainer = ({ name, label, error, required, children }) => {
10
+ return (react_1.default.createElement("div", { className: (0, clsx_1.default)(error && 'squiz-fte-invalid-form-field') },
11
+ label && (react_1.default.createElement("label", { htmlFor: name, className: "squiz-fte-form-label" }, label)),
12
+ label && required && (react_1.default.createElement("span", { className: "text-gray-600", "aria-label": "Required field" }, "*")),
13
+ children,
14
+ error && react_1.default.createElement("div", { className: "squiz-fte-form-error" }, error)));
15
+ };
16
+ exports.InputContainer = InputContainer;
@@ -0,0 +1,17 @@
1
+ import { InputContainerProps } from '../InputContainer/InputContainer';
2
+ type MatrixAssetValue = {
3
+ matrixIdentifier?: string;
4
+ matrixAssetId?: string;
5
+ };
6
+ export type MatrixAssetProps<T extends MatrixAssetValue> = Omit<InputContainerProps, 'children'> & {
7
+ modalTitle: string;
8
+ allowedTypes?: string[];
9
+ value?: T | null;
10
+ onChange: (value: {
11
+ target: {
12
+ value: T;
13
+ };
14
+ }) => void;
15
+ };
16
+ export declare const MatrixAsset: <T extends MatrixAssetValue>({ modalTitle, allowedTypes, value, onChange, ...props }: MatrixAssetProps<T>) => JSX.Element;
17
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MatrixAsset = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const resource_browser_1 = require("@squiz/resource-browser");
9
+ const InputContainer_1 = require("../InputContainer/InputContainer");
10
+ const MatrixAsset = ({ modalTitle, allowedTypes, value, onChange, ...props }) => {
11
+ return (react_1.default.createElement(InputContainer_1.InputContainer, { ...props },
12
+ react_1.default.createElement(resource_browser_1.ResourceBrowserInput, { modalTitle: modalTitle, allowedTypes: allowedTypes, value: value && value.matrixIdentifier && value.matrixAssetId
13
+ ? {
14
+ source: value.matrixIdentifier,
15
+ resource: value.matrixAssetId,
16
+ }
17
+ : null, onChange: (reference) => {
18
+ onChange({
19
+ target: {
20
+ value: {
21
+ ...value,
22
+ matrixIdentifier: reference?.source?.id,
23
+ matrixAssetId: reference?.resource?.id,
24
+ },
25
+ },
26
+ });
27
+ } })));
28
+ };
29
+ exports.MatrixAsset = MatrixAsset;
@@ -1,2 +1,3 @@
1
- export declare const noEmptySpacesValidation: (value: string | undefined) => Promise<"Empty space is not allowed" | undefined>;
1
+ export declare const noEmptySpacesValidation: (value: string | undefined) => "Empty space is not allowed" | undefined;
2
+ export declare const hasProperties: <T>(message: string, properties: (keyof T)[]) => (value: T) => string | undefined;
2
3
  export declare const regexDataURI: RegExp;
@@ -1,10 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.regexDataURI = exports.noEmptySpacesValidation = void 0;
4
- const noEmptySpacesValidation = async (value) => {
3
+ exports.regexDataURI = exports.hasProperties = exports.noEmptySpacesValidation = void 0;
4
+ const noEmptySpacesValidation = (value) => {
5
5
  if (value && !(value.trim().length > 0)) {
6
6
  return 'Empty space is not allowed';
7
7
  }
8
8
  };
9
9
  exports.noEmptySpacesValidation = noEmptySpacesValidation;
10
+ const hasProperties = (message, properties) => (value) => {
11
+ if (!value || properties.filter((property) => value[property]).length !== properties.length) {
12
+ return message;
13
+ }
14
+ };
15
+ exports.hasProperties = hasProperties;
10
16
  exports.regexDataURI = /^data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*)$/i;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/formatted-text-editor",
3
- "version": "1.33.1-alpha.3",
3
+ "version": "1.33.1-alpha.4",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "scripts": {
@@ -20,7 +20,8 @@
20
20
  "@headlessui/react": "1.7.11",
21
21
  "@mui/icons-material": "5.11.16",
22
22
  "@remirror/react": "2.0.25",
23
- "@squiz/dx-json-schema-lib": "1.21.1-alpha.2",
23
+ "@squiz/dx-json-schema-lib": "1.33.1-alpha.4",
24
+ "@squiz/resource-browser": "1.33.1-alpha.4",
24
25
  "clsx": "1.2.1",
25
26
  "react-hook-form": "7.43.2",
26
27
  "react-image-size": "2.0.0",
@@ -74,5 +75,5 @@
74
75
  "volta": {
75
76
  "node": "18.15.0"
76
77
  },
77
- "gitHead": "5189e21fcd9ad091397cacfa50765caf6138b034"
78
+ "gitHead": "00015ccc2b5c7761d3a62e8bbcdf88be15038877"
78
79
  }
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { act, fireEvent, render, screen } from '@testing-library/react';
3
3
  import Editor from './Editor';
4
4
  import '@testing-library/jest-dom';
5
- import { renderWithEditor } from '../../tests/renderWithEditor';
5
+ import { renderWithEditor } from '../../tests';
6
6
  import ImageButton from '../EditorToolbar/Tools/Image/ImageButton';
7
7
 
8
8
  describe('Formatted text editor', () => {