@squiz/formatted-text-editor 2.0.1-rc.2 → 2.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 37094f9: Added content tools dropdown & context to FTE
8
+
9
+ ## 2.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 6838083: Updated repo package-lock.json to consume shared resource browsers with bumped versions with correct peer dependencies to be consumed by both Matrix and Page Builder
14
+
3
15
  ## 2.0.0
4
16
 
5
17
  ### Major Changes
@@ -9,6 +9,7 @@ import { EditorContext } from '../src';
9
9
  import resources from './resources.json';
10
10
  import sources from './sources.json';
11
11
  import { ResolveNodeType } from '../src/types';
12
+ import { AiServiceProvider } from '@squiz/dxp-ai-client-react';
12
13
 
13
14
  export type AppContextProps = PropsWithChildren;
14
15
  export const AppContext = ({ children }: AppContextProps) => (
@@ -45,26 +46,48 @@ export const AppContext = ({ children }: AppContextProps) => (
45
46
  ],
46
47
  }}
47
48
  >
48
- <EditorContext.Provider
49
- value={{
50
- matrix: {
51
- matrixDomain: 'https://matrix-domain.squiz.net',
49
+ <AiServiceProvider
50
+ clientConfig={{
51
+ // We are using a simple Express proxy here for testing locally in FTE
52
+ // You can find this proxy here: https://gitlab.squiz.net/tgrob/dxp-ai-client-proxy
53
+ baseUrl: 'http://localhost:7777',
54
+ baseApiParams: {
55
+ headers: {
56
+ // You will need to create an API key to test this in FTE, details can be found here:
57
+ // https://squizgroup.atlassian.net/wiki/spaces/PRODUCT/pages/2895119377/FEaaS+Playbook+Configuring+a+Matrix+instance+for+the+Component+Service#Create-an-API-key
58
+ 'x-api-key': '',
59
+ },
52
60
  },
53
- resolveNodeToUrl: (node: ResolveNodeType): Promise<string> => {
54
- const nodeResource = node.matrixAssetId;
55
- const flattenResources = (resources: unknown[]) => {
56
- return [
57
- ...resources,
58
- ...resources.flatMap((resource) => ('_children' in resource ? flattenResources(resource._children) : [])),
59
- ];
60
- };
61
-
62
- const resource = flattenResources(resources).find((resource) => resource.id === nodeResource);
63
- return Promise.resolve(resource.url || '');
61
+ customFetch: async (input, init) => {
62
+ const response = await fetch(input, init);
63
+ return response;
64
64
  },
65
65
  }}
66
+ tags={['tag1']}
66
67
  >
67
- {children}
68
- </EditorContext.Provider>
68
+ <EditorContext.Provider
69
+ value={{
70
+ matrix: {
71
+ matrixDomain: 'https://matrix-domain.squiz.net',
72
+ },
73
+ resolveNodeToUrl: (node: ResolveNodeType): Promise<string> => {
74
+ const nodeResource = node.matrixAssetId;
75
+ const flattenResources = (resources: unknown[]) => {
76
+ return [
77
+ ...resources,
78
+ ...resources.flatMap((resource) =>
79
+ '_children' in resource ? flattenResources(resource._children) : [],
80
+ ),
81
+ ];
82
+ };
83
+
84
+ const resource = flattenResources(resources).find((resource) => resource.id === nodeResource);
85
+ return Promise.resolve(resource.url || '');
86
+ },
87
+ }}
88
+ >
89
+ {children}
90
+ </EditorContext.Provider>
91
+ </AiServiceProvider>
69
92
  </ResourceBrowserContextProvider>
70
93
  );
package/jest.config.ts CHANGED
@@ -23,5 +23,5 @@ export default {
23
23
  '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css|scss)$':
24
24
  '<rootDir>/file-transformer.js',
25
25
  },
26
- setupFilesAfterEnv: ['<rootDir>/jest.bootstrap.ts'],
26
+ setupFilesAfterEnv: ['<rootDir>/jest.bootstrap.ts', '<rootDir>/jest.setup.ts'],
27
27
  };
package/jest.setup.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { useAiService } from '@squiz/dxp-ai-client-react';
2
+
3
+ // Mock the module
4
+ jest.mock('@squiz/dxp-ai-client-react', () => ({
5
+ useAiService: jest.fn(),
6
+ }));
7
+
8
+ // Cast useAiService to a Jest mock
9
+ const mockedUseAiService = useAiService as jest.MockedFunction<typeof useAiService>;
10
+
11
+ beforeEach(() => {
12
+ // Provide the mock implementation before each test
13
+ mockedUseAiService.mockReturnValue({
14
+ contentTools: [],
15
+ } as any);
16
+ });
@@ -21,6 +21,7 @@ const ClearFormattingButton_1 = __importDefault(require("./Tools/ClearFormatting
21
21
  const ListButtons_1 = __importDefault(require("./Tools/Lists/ListButtons"));
22
22
  const HorizontalLineButton_1 = __importDefault(require("./Tools/HorizontalLine/HorizontalLineButton"));
23
23
  const TableButton_1 = __importDefault(require("./Tools/Table/TableButton"));
24
+ const ContentToolsDropdown_1 = __importDefault(require("./Tools/ContentTools/ContentToolsDropdown"));
24
25
  const hooks_1 = require("../hooks");
25
26
  const Toolbar = ({ isVisible, enableTableTool }) => {
26
27
  const extensionNames = (0, hooks_1.useExtensionNames)();
@@ -42,6 +43,7 @@ const Toolbar = ({ isVisible, enableTableTool }) => {
42
43
  react_1.default.createElement(RemoveLinkButton_1.default, null))),
43
44
  extensionNames.image && react_1.default.createElement(ImageButton_1.default, null),
44
45
  extensionNames.clearFormatting && react_1.default.createElement(ClearFormattingButton_1.default, null),
45
- enableTableTool && extensionNames.table && react_1.default.createElement(TableButton_1.default, null))));
46
+ enableTableTool && extensionNames.table && react_1.default.createElement(TableButton_1.default, null),
47
+ react_1.default.createElement(ContentToolsDropdown_1.default, null))));
46
48
  };
47
49
  exports.Toolbar = Toolbar;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const ContentToolsDropdown: () => React.JSX.Element | null;
3
+ export default ContentToolsDropdown;
@@ -0,0 +1,35 @@
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
+ const react_1 = __importDefault(require("react"));
7
+ const AiIcon_1 = require("../../../Icons/AiIcon");
8
+ const sds_1 = require("@squiz/sds");
9
+ const dxp_ai_client_react_1 = require("@squiz/dxp-ai-client-react");
10
+ const react_2 = require("@remirror/react");
11
+ const ContentToolsDropdown = () => {
12
+ const { contentTools } = (0, dxp_ai_client_react_1.useAiService)();
13
+ const dropdownItems = contentTools.map((item) => ({
14
+ items: [
15
+ {
16
+ action: () => alert(JSON.stringify(item, null, 2)),
17
+ key: item.id,
18
+ label: react_1.default.createElement("span", null, item.name),
19
+ },
20
+ ],
21
+ key: item.id,
22
+ }));
23
+ // No content tools to show, don't show dropdown at all
24
+ if (contentTools.length === 0) {
25
+ return null;
26
+ }
27
+ return (react_1.default.createElement(react_1.default.Fragment, null,
28
+ react_1.default.createElement(react_2.VerticalDivider, null),
29
+ react_1.default.createElement(sds_1.Dropdown, { title: "Content tools", "aria-label": "Content tools", buttonProps: {
30
+ format: sds_1.BUTTON_FORMAT_TRANSPARENT,
31
+ icon: AiIcon_1.ICON_AI,
32
+ theme: sds_1.BUTTON_THEME_DEFAULT,
33
+ }, className: "content-tools-dropdown", dropdownPosition: sds_1.DROPDOWN_POSITION_RIGHT, heading: 'Rewrite to...', sections: dropdownItems })));
34
+ };
35
+ exports.default = ContentToolsDropdown;
@@ -5,7 +5,6 @@ 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 react_2 = require("@remirror/react");
8
- const react_components_1 = require("@remirror/react-components");
9
8
  const Button_1 = __importDefault(require("../../../ui/Button/Button"));
10
9
  const TableViewRounded_1 = __importDefault(require("@mui/icons-material/TableViewRounded"));
11
10
  const TableButton = () => {
@@ -16,7 +15,6 @@ const TableButton = () => {
16
15
  createTable({ rowsCount: 4, columnsCount: 3, withHeaderRow: false });
17
16
  };
18
17
  return (react_1.default.createElement(react_1.default.Fragment, null,
19
- react_1.default.createElement(Button_1.default, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.table(), icon: react_1.default.createElement(TableViewRounded_1.default, null), label: "Insert table" }),
20
- react_1.default.createElement(react_components_1.VerticalDivider, null)));
18
+ react_1.default.createElement(Button_1.default, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.table(), icon: react_1.default.createElement(TableViewRounded_1.default, null), label: "Insert table" })));
21
19
  };
22
20
  exports.default = TableButton;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const ICON_AI: React.JSX.Element;
@@ -0,0 +1,60 @@
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.ICON_AI = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ exports.ICON_AI = (react_1.default.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
9
+ react_1.default.createElement("g", { id: "sq-AI-icon", clipPath: "url(#clip0_3060_44545)" },
10
+ react_1.default.createElement("g", { id: "circle", filter: "url(#filter0_dd_3060_44545)" },
11
+ react_1.default.createElement("rect", { x: "2", y: "2", width: "20", height: "20", rx: "10", fill: "url(#paint0_linear_3060_44545)" }),
12
+ react_1.default.createElement("rect", { x: "1.5", y: "1.5", width: "21", height: "21", rx: "10.5", stroke: "white" })),
13
+ react_1.default.createElement("g", { id: "Vector", filter: "url(#filter1_d_3060_44545)" },
14
+ react_1.default.createElement("path", { d: "M11.2084 9.79157L10.1219 7.39977C9.88269 6.86674 9.11731 6.86674 8.87813 7.39977L7.79157 9.79157L5.39977 10.8781C4.86674 11.1241 4.86674 11.8827 5.39977 12.1219L7.79157 13.2084L8.87813 15.6002C9.12415 16.1333 9.88269 16.1333 10.1219 15.6002L11.2084 13.2084L13.6002 12.1219C14.1333 11.8759 14.1333 11.1173 13.6002 10.8781L11.2084 9.79157Z", fill: "white" })),
15
+ react_1.default.createElement("g", { id: "Vector_2", opacity: "0.8", filter: "url(#filter2_d_3060_44545)" },
16
+ react_1.default.createElement("path", { d: "M17.4491 10.4491L16.8493 11.7779C16.7126 12.074 16.2874 12.074 16.1507 11.7779L15.5509 10.4415L14.2221 9.84169C13.926 9.70501 13.926 9.2874 14.2221 9.15072L15.5585 8.55087L16.1583 7.2221C16.295 6.92597 16.7126 6.92597 16.8493 7.2221L17.4491 8.55847L18.7779 9.15831C19.074 9.29499 19.074 9.7126 18.7779 9.84928L17.4491 10.4491Z", fill: "white" })),
17
+ react_1.default.createElement("g", { id: "Ellipse 55", opacity: "0.8", filter: "url(#filter3_d_3060_44545)" },
18
+ react_1.default.createElement("circle", { cx: "14.5", cy: "16.5", r: "1.5", fill: "white" }))),
19
+ react_1.default.createElement("defs", null,
20
+ react_1.default.createElement("filter", { id: "filter0_dd_3060_44545", x: "0", y: "0", width: "24", height: "24", filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB" },
21
+ react_1.default.createElement("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
22
+ react_1.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
23
+ react_1.default.createElement("feOffset", { dx: "1", dy: "1" }),
24
+ react_1.default.createElement("feComposite", { in2: "hardAlpha", operator: "out" }),
25
+ react_1.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0.2 0 0 0 0 0.709941 0 0 0 0 1 0 0 0 0.64 0" }),
26
+ react_1.default.createElement("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1_dropShadow_3060_44545" }),
27
+ react_1.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
28
+ react_1.default.createElement("feOffset", { dx: "-1", dy: "-1" }),
29
+ react_1.default.createElement("feComposite", { in2: "hardAlpha", operator: "out" }),
30
+ react_1.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0.96 0 0 0 0 0.76 0 0 0 0 0.48 0 0 0 0.64 0" }),
31
+ react_1.default.createElement("feBlend", { mode: "normal", in2: "effect1_dropShadow_3060_44545", result: "effect2_dropShadow_3060_44545" }),
32
+ react_1.default.createElement("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect2_dropShadow_3060_44545", result: "shape" })),
33
+ react_1.default.createElement("filter", { id: "filter1_d_3060_44545", x: "5", y: "7", width: "9", height: "10", filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB" },
34
+ react_1.default.createElement("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
35
+ react_1.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
36
+ react_1.default.createElement("feOffset", { dy: "1" }),
37
+ react_1.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.16 0" }),
38
+ react_1.default.createElement("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1_dropShadow_3060_44545" }),
39
+ react_1.default.createElement("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect1_dropShadow_3060_44545", result: "shape" })),
40
+ react_1.default.createElement("filter", { id: "filter2_d_3060_44545", x: "14", y: "7", width: "5", height: "6.30682", filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB" },
41
+ react_1.default.createElement("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
42
+ react_1.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
43
+ react_1.default.createElement("feOffset", { dy: "1.30682" }),
44
+ react_1.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.16 0" }),
45
+ react_1.default.createElement("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1_dropShadow_3060_44545" }),
46
+ react_1.default.createElement("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect1_dropShadow_3060_44545", result: "shape" })),
47
+ react_1.default.createElement("filter", { id: "filter3_d_3060_44545", x: "13", y: "15", width: "3", height: "4.32373", filterUnits: "userSpaceOnUse", colorInterpolationFilters: "sRGB" },
48
+ react_1.default.createElement("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
49
+ react_1.default.createElement("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
50
+ react_1.default.createElement("feOffset", { dy: "1.32373" }),
51
+ react_1.default.createElement("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.16 0" }),
52
+ react_1.default.createElement("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1_dropShadow_3060_44545" }),
53
+ react_1.default.createElement("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect1_dropShadow_3060_44545", result: "shape" })),
54
+ react_1.default.createElement("linearGradient", { id: "paint0_linear_3060_44545", x1: "6.54545", y1: "3.81818", x2: "17", y2: "20.1818", gradientUnits: "userSpaceOnUse" },
55
+ react_1.default.createElement("stop", { stopColor: "#F5D6AB" }),
56
+ react_1.default.createElement("stop", { offset: "0.251162", stopColor: "#F895A7" }),
57
+ react_1.default.createElement("stop", { offset: "0.585", stopColor: "#77A1F1" }),
58
+ react_1.default.createElement("stop", { offset: "0.861262", stopColor: "#68C8FF" })),
59
+ react_1.default.createElement("clipPath", { id: "clip0_3060_44545" },
60
+ react_1.default.createElement("rect", { width: "24", height: "24", fill: "white" })))));