@griddo/ax 10.4.7 → 10.4.9

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 (45) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/components/Browser/Browser.test.tsx +4 -4
  3. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +39 -7
  4. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +8 -8
  5. package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +28 -16
  6. package/src/components/Browser/index.tsx +5 -5
  7. package/src/components/BulkSelectionOptions/style.tsx +1 -0
  8. package/src/components/ConfigPanel/Header/index.tsx +8 -4
  9. package/src/components/Fields/AsyncCheckGroup/style.tsx +3 -0
  10. package/src/components/Fields/CheckField/index.tsx +4 -1
  11. package/src/components/Fields/CheckField/style.tsx +19 -3
  12. package/src/components/Fields/CheckGroup/index.tsx +3 -2
  13. package/src/components/Fields/CheckGroup/style.tsx +3 -0
  14. package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/index.tsx +47 -0
  15. package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/style.tsx +44 -0
  16. package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx +31 -12
  17. package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +153 -59
  18. package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +1 -1
  19. package/src/components/Fields/ComponentArray/helpers.tsx +45 -4
  20. package/src/components/Fields/ComponentContainer/EmptyContainer/index.tsx +2 -2
  21. package/src/components/Fields/ComponentContainer/index.tsx +68 -33
  22. package/src/components/Fields/ComponentContainer/style.tsx +78 -11
  23. package/src/components/Fields/ReferenceField/Context/index.tsx +1 -1
  24. package/src/components/MainWrapper/AppBar/atoms.tsx +5 -8
  25. package/src/components/SideModal/SideModalOption/index.tsx +5 -3
  26. package/src/containers/Navigation/Defaults/actions.tsx +86 -55
  27. package/src/containers/Navigation/Defaults/interfaces.tsx +2 -2
  28. package/src/containers/Navigation/Defaults/reducer.tsx +3 -3
  29. package/src/containers/PageEditor/actions.tsx +142 -109
  30. package/src/containers/PageEditor/interfaces.tsx +1 -1
  31. package/src/containers/PageEditor/reducer.tsx +2 -2
  32. package/src/containers/PageEditor/utils.tsx +1 -1
  33. package/src/containers/Settings/DataPacks/actions.tsx +7 -2
  34. package/src/forms/elements.tsx +20 -14
  35. package/src/hooks/bulk.tsx +57 -2
  36. package/src/hooks/iframe.ts +5 -5
  37. package/src/modules/Content/index.tsx +10 -1
  38. package/src/modules/FramePreview/index.tsx +4 -4
  39. package/src/modules/GlobalEditor/Editor/index.tsx +6 -6
  40. package/src/modules/GlobalEditor/PageBrowser/index.tsx +2 -2
  41. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +6 -6
  42. package/src/modules/PageEditor/Editor/index.tsx +7 -7
  43. package/src/modules/PageEditor/PageBrowser/index.tsx +2 -2
  44. package/src/modules/Users/UserForm/index.tsx +52 -34
  45. package/src/types/index.tsx +1 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "10.4.7",
4
+ "version": "10.4.9",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Carlos Torres <carlos.torres@secuoyas.com>",
@@ -231,5 +231,5 @@
231
231
  "publishConfig": {
232
232
  "access": "public"
233
233
  },
234
- "gitHead": "0280c78de79a2b1f534c9aaaf16e6bb72bd5b652"
234
+ "gitHead": "798ce16f44f99f35c4eb372b04e54f8a1f433469"
235
235
  }
@@ -146,10 +146,10 @@ describe("Browser component rendering", () => {
146
146
  defaultProps.isPreview = false;
147
147
  defaultProps.showIframe = false;
148
148
  const deleteModuleActionMock = defaultProps.actions?.deleteModuleAction as jest.MockedFunction<
149
- (editorID: number) => void
149
+ (editorID: number[]) => void
150
150
  >;
151
151
  const duplicateModuleActionMock = defaultProps.actions?.duplicateModuleAction as jest.MockedFunction<
152
- (editorID: number) => Promise<number>
152
+ (editorID: number[]) => number
153
153
  >;
154
154
  const setSelectedContentActionMock = defaultProps.actions?.setSelectedContentAction as jest.MockedFunction<
155
155
  () => void
@@ -172,10 +172,10 @@ describe("Browser component rendering", () => {
172
172
  defaultProps.isPreview = true;
173
173
  defaultProps.showIframe = true;
174
174
  const deleteModuleActionMock = defaultProps.actions?.deleteModuleAction as jest.MockedFunction<
175
- (editorID: number) => void
175
+ (editorID: number[]) => void
176
176
  >;
177
177
  const duplicateModuleActionMock = defaultProps.actions?.duplicateModuleAction as jest.MockedFunction<
178
- (editorID: number) => Promise<number>
178
+ (editorID: number[]) => number
179
179
  >;
180
180
  const setSelectedContentActionMock = defaultProps.actions?.setSelectedContentAction as jest.MockedFunction<
181
181
  () => void
@@ -23,7 +23,7 @@ otherMixableModule.editorID = 2;
23
23
  otherMixableModule.component = "HeroCard";
24
24
  otherMixableModule.title = "Hero Section";
25
25
  otherMixableModule.modules = [];
26
- mixableProps.field = { type: "components" };
26
+ mixableProps.field = { type: "components", title: "", key: "elements" };
27
27
  const testModule = {
28
28
  value: {
29
29
  editorID: 1,
@@ -59,7 +59,7 @@ describe("ComponentArraySelector component rendering", () => {
59
59
  otherMixableModule.title = "Hero Section";
60
60
  otherMixableModule.modules = [];
61
61
  mixableProps.value = [mixableModule, otherMixableModule];
62
- mixableProps.field = { contentType: "modules" };
62
+ mixableProps.field = { contentType: "modules", title: "", key: "elements", type: "" };
63
63
  mixableProps.objKey = "elements";
64
64
  mixableProps.disabled = false;
65
65
  mixableProps.maxItems = 10;
@@ -68,6 +68,12 @@ describe("ComponentArraySelector component rendering", () => {
68
68
  addComponentAction: jest.fn(),
69
69
  deleteModuleAction: jest.fn(),
70
70
  replaceElementsInCollectionAction: jest.fn(),
71
+ duplicateModuleAction: jest.fn(),
72
+ copyModuleAction: jest.fn(),
73
+ moveModuleAction: jest.fn(),
74
+ pasteModuleAction: jest.fn(),
75
+ setNotificationAction: jest.fn(),
76
+ replaceModuleAction: jest.fn(),
71
77
  };
72
78
 
73
79
  render(
@@ -122,6 +128,7 @@ describe("ComponentArraySelector component rendering", () => {
122
128
  mixableProps.field = {
123
129
  contentType: "modules",
124
130
  key: "mainContent",
131
+ title: "", type: ""
125
132
  };
126
133
  mixableProps.objKey = "elements";
127
134
  mixableProps.disabled = false;
@@ -131,6 +138,12 @@ describe("ComponentArraySelector component rendering", () => {
131
138
  addComponentAction: jest.fn(),
132
139
  deleteModuleAction: jest.fn(),
133
140
  replaceElementsInCollectionAction: jest.fn(),
141
+ duplicateModuleAction: jest.fn(),
142
+ copyModuleAction: jest.fn(),
143
+ moveModuleAction: jest.fn(),
144
+ pasteModuleAction: jest.fn(),
145
+ setNotificationAction: jest.fn(),
146
+ replaceModuleAction: jest.fn(),
134
147
  };
135
148
  mixableProps.template = { component: "BasicTemplate" };
136
149
  mixableProps.availableDataPacks = [
@@ -197,8 +210,9 @@ describe("ComponentArraySelector component rendering", () => {
197
210
  ];
198
211
  const actualDate = new Date();
199
212
  mixableProps.moduleCopy = {
200
- date: actualDate.toISOString(),
201
- element: {
213
+ date: actualDate,
214
+ elements: [{
215
+ editorID: 1,
202
216
  component: "ArticlesDistributor",
203
217
  anchorID: null,
204
218
  verticalSpacing: "medium",
@@ -224,7 +238,7 @@ describe("ComponentArraySelector component rendering", () => {
224
238
  editorID: 40,
225
239
  parentEditorID: 39,
226
240
  },
227
- },
241
+ }],
228
242
  };
229
243
  mixableProps.mandatory = true;
230
244
 
@@ -245,7 +259,7 @@ describe("ComponentArraySelector component events trigger", () => {
245
259
  otherMixableModule.title = "Hero Section";
246
260
  otherMixableModule.modules = [];
247
261
  mixableProps.value = [mixableModule, otherMixableModule];
248
- mixableProps.field = { contentType: "modules" };
262
+ mixableProps.field = { contentType: "modules", title: "", key: "elements", type: "" };
249
263
  mixableProps.objKey = "elements";
250
264
  mixableProps.disabled = false;
251
265
  mixableProps.maxItems = 10;
@@ -254,6 +268,12 @@ describe("ComponentArraySelector component events trigger", () => {
254
268
  addComponentAction: jest.fn(),
255
269
  deleteModuleAction: jest.fn(),
256
270
  replaceElementsInCollectionAction: jest.fn(),
271
+ duplicateModuleAction: jest.fn(),
272
+ copyModuleAction: jest.fn(),
273
+ moveModuleAction: jest.fn(),
274
+ pasteModuleAction: jest.fn(),
275
+ setNotificationAction: jest.fn(),
276
+ replaceModuleAction: jest.fn(),
257
277
  };
258
278
 
259
279
  render(
@@ -276,11 +296,23 @@ describe("ComponentArraySelector component events trigger", () => {
276
296
  otherMixableModule.component = "HeroCard";
277
297
  otherMixableModule.title = "Hero Section";
278
298
  otherMixableModule.modules = [];
279
- mixableProps.field = { type: "components" };
299
+ mixableProps.field = { type: "components", title: "", key: "elements" };
280
300
  mixableProps.value = [mixableModule];
281
301
  mixableProps.activatedModules = ["HeroSection"];
282
302
  mixableProps.whiteList = [];
283
303
  mixableProps.moduleCopy = null;
304
+ mixableProps.actions = {
305
+ addModuleAction: jest.fn(),
306
+ addComponentAction: jest.fn(),
307
+ deleteModuleAction: jest.fn(),
308
+ replaceElementsInCollectionAction: jest.fn(),
309
+ duplicateModuleAction: jest.fn(),
310
+ copyModuleAction: jest.fn(),
311
+ moveModuleAction: jest.fn(),
312
+ pasteModuleAction: jest.fn(),
313
+ setNotificationAction: jest.fn(),
314
+ replaceModuleAction: jest.fn(),
315
+ };
284
316
 
285
317
  render(
286
318
  <ThemeProvider theme={parseTheme(globalTheme)}>
@@ -6,7 +6,7 @@ import { ThemeProvider } from "styled-components";
6
6
  import { parseTheme } from "@ax/helpers";
7
7
  import "@testing-library/jest-dom";
8
8
  import globalTheme from "@ax/themes/theme.json";
9
- import { INotification } from "@ax/types";
9
+ import { IModule, INotification } from "@ax/types";
10
10
  import { render, screen, cleanup, fireEvent, act } from "@testing-library/react";
11
11
  import { mock } from "jest-mock-extended";
12
12
 
@@ -22,7 +22,7 @@ jest.mock("react-router-dom", () => ({
22
22
  const defaultProps = mock<IPasteModuleProps>();
23
23
 
24
24
  const mockedFunction = defaultProps.pasteModule as jest.MockedFunction<
25
- (editorID: number, key: string) => Promise<{ error?: INotification }>
25
+ (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>
26
26
  >;
27
27
  const mockedNotification = defaultProps.setNotification as jest.MockedFunction<(notification: INotification) => void>;
28
28
  defaultProps.editorID = 1;
@@ -65,8 +65,8 @@ describe("ComponentArraySelector trigger events", () => {
65
65
  await act(async () => {
66
66
  fireEvent.click(iconButton);
67
67
  });
68
- await expect(mockedFunction).toHaveBeenCalled();
69
- await expect(mockedFunction(1, "")).resolves.toEqual({
68
+ expect(mockedFunction).toHaveBeenCalled();
69
+ await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({
70
70
  error: {
71
71
  type: "warning",
72
72
  text: "This is a warning",
@@ -90,8 +90,8 @@ describe("ComponentArraySelector trigger events", () => {
90
90
  await act(async () => {
91
91
  fireEvent.click(iconButton);
92
92
  });
93
- await expect(mockedFunction).toHaveBeenCalled();
94
- await expect(mockedFunction(1, "")).resolves.toEqual({});
93
+ expect(mockedFunction).toHaveBeenCalled();
94
+ await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({});
95
95
  expect(screen.getByTestId("toast-message")).toHaveTextContent("Module pasted from clipboard");
96
96
  });
97
97
 
@@ -109,8 +109,8 @@ describe("ComponentArraySelector trigger events", () => {
109
109
  await act(async () => {
110
110
  fireEvent.click(iconButton);
111
111
  });
112
- await expect(mockedFunction).toHaveBeenCalled();
113
- await expect(mockedFunction(1, "")).resolves.toEqual({ error: undefined });
112
+ expect(mockedFunction).toHaveBeenCalled();
113
+ await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({ error: undefined });
114
114
  expect(screen.getByTestId("toast-message")).toHaveTextContent("Module pasted from clipboard");
115
115
  });
116
116
  });
@@ -61,10 +61,11 @@ describe("ComponentContainer component rendering", () => {
61
61
  defaultProps.value = {};
62
62
  defaultProps.actionReplace = jest.fn();
63
63
  defaultProps.actions = {
64
+ addComponentAction: jest.fn(),
64
65
  deleteModuleAction: jest.fn(),
65
- moveModuleAction: jest.fn(),
66
- duplicateModuleAction: jest.fn,
66
+ duplicateModuleAction: jest.fn(),
67
67
  copyModuleAction: jest.fn(),
68
+ replaceModuleAction: jest.fn(),
68
69
  };
69
70
  defaultProps.canDuplicate = true;
70
71
  defaultProps.canReplace = true;
@@ -147,10 +148,11 @@ describe("ComponentContainer component rendering", () => {
147
148
  defaultProps.value = {};
148
149
  defaultProps.actionReplace = jest.fn();
149
150
  defaultProps.actions = {
151
+ addComponentAction: jest.fn(),
150
152
  deleteModuleAction: jest.fn(),
151
- moveModuleAction: jest.fn(),
152
- duplicateModuleAction: jest.fn,
153
+ duplicateModuleAction: jest.fn(),
153
154
  copyModuleAction: jest.fn(),
155
+ replaceModuleAction: jest.fn(),
154
156
  };
155
157
  defaultProps.canDuplicate = true;
156
158
  defaultProps.canReplace = true;
@@ -190,7 +192,11 @@ describe("ComponentContainer component rendering", () => {
190
192
  parentEditorID: 4,
191
193
  };
192
194
  defaultProps.actions = {
195
+ addComponentAction: jest.fn(),
193
196
  deleteModuleAction: jest.fn(),
197
+ duplicateModuleAction: jest.fn(),
198
+ copyModuleAction: jest.fn(),
199
+ replaceModuleAction: jest.fn(),
194
200
  };
195
201
  defaultProps.parentKey = "title";
196
202
  defaultProps.objKey = "content";
@@ -307,10 +313,11 @@ describe("ComponentContainer component rendering", () => {
307
313
  };
308
314
  defaultProps.actionReplace = jest.fn();
309
315
  defaultProps.actions = {
316
+ addComponentAction: jest.fn(),
310
317
  deleteModuleAction: jest.fn(),
311
- moveModuleAction: jest.fn(),
312
- duplicateModuleAction: jest.fn,
318
+ duplicateModuleAction: jest.fn(),
313
319
  copyModuleAction: jest.fn(),
320
+ replaceModuleAction: jest.fn(),
314
321
  };
315
322
  defaultProps.canDuplicate = true;
316
323
  defaultProps.canReplace = true;
@@ -345,10 +352,11 @@ describe("ComponentContainer component rendering", () => {
345
352
  };
346
353
  defaultProps.actionReplace = jest.fn();
347
354
  defaultProps.actions = {
355
+ addComponentAction: jest.fn(),
348
356
  deleteModuleAction: jest.fn(),
349
- moveModuleAction: jest.fn(),
350
- duplicateModuleAction: jest.fn,
357
+ duplicateModuleAction: jest.fn(),
351
358
  copyModuleAction: jest.fn(),
359
+ replaceModuleAction: jest.fn(),
352
360
  };
353
361
  defaultProps.canDuplicate = true;
354
362
  defaultProps.canReplace = true;
@@ -392,10 +400,11 @@ test("should render the FloatingMenu with options when click Component Container
392
400
  };
393
401
  defaultProps.actionReplace = jest.fn();
394
402
  defaultProps.actions = {
403
+ addComponentAction: jest.fn(),
395
404
  deleteModuleAction: jest.fn(),
396
- moveModuleAction: jest.fn(),
397
- duplicateModuleAction: jest.fn,
405
+ duplicateModuleAction: jest.fn(),
398
406
  copyModuleAction: jest.fn(),
407
+ replaceModuleAction: jest.fn(),
399
408
  };
400
409
  defaultProps.canDuplicate = true;
401
410
  defaultProps.canReplace = true;
@@ -440,10 +449,11 @@ test("should render the SideModal with options when click the replace action", a
440
449
  };
441
450
  defaultProps.actionReplace = jest.fn();
442
451
  defaultProps.actions = {
452
+ addComponentAction: jest.fn(),
443
453
  deleteModuleAction: jest.fn(),
444
- moveModuleAction: jest.fn(),
445
- duplicateModuleAction: jest.fn,
454
+ duplicateModuleAction: jest.fn(),
446
455
  copyModuleAction: jest.fn(),
456
+ replaceModuleAction: jest.fn(),
447
457
  };
448
458
  defaultProps.canDuplicate = true;
449
459
  defaultProps.canReplace = true;
@@ -496,10 +506,11 @@ test("should not render the drag handle if arrays length is lower than two", asy
496
506
  };
497
507
  defaultProps.actionReplace = jest.fn();
498
508
  defaultProps.actions = {
509
+ addComponentAction: jest.fn(),
499
510
  deleteModuleAction: jest.fn(),
500
- moveModuleAction: jest.fn(),
501
- duplicateModuleAction: jest.fn,
511
+ duplicateModuleAction: jest.fn(),
502
512
  copyModuleAction: jest.fn(),
513
+ replaceModuleAction: jest.fn(),
503
514
  };
504
515
  defaultProps.canDuplicate = true;
505
516
  defaultProps.canReplace = true;
@@ -537,10 +548,11 @@ test("should render the drag handle if arrays length is greater than two", async
537
548
  };
538
549
  defaultProps.actionReplace = jest.fn();
539
550
  defaultProps.actions = {
551
+ addComponentAction: jest.fn(),
540
552
  deleteModuleAction: jest.fn(),
541
- moveModuleAction: jest.fn(),
542
- duplicateModuleAction: jest.fn,
553
+ duplicateModuleAction: jest.fn(),
543
554
  copyModuleAction: jest.fn(),
555
+ replaceModuleAction: jest.fn(),
544
556
  };
545
557
  defaultProps.canDuplicate = true;
546
558
  defaultProps.canReplace = true;
@@ -91,11 +91,11 @@ const Browser = (props: IBrowserProps): JSX.Element => {
91
91
 
92
92
  const deleteModuleSelected = (editorID: number) => {
93
93
  actions?.setSelectedContentAction(0);
94
- actions?.deleteModuleAction(editorID);
94
+ actions?.deleteModuleAction([editorID]);
95
95
  };
96
96
 
97
- const duplicateModuleSelected = async (editorID: number) => {
98
- const duplicatedEditorID = await actions?.duplicateModuleAction(editorID);
97
+ const duplicateModuleSelected = (editorID: number) => {
98
+ const duplicatedEditorID = actions?.duplicateModuleAction([editorID]);
99
99
  actions?.setSelectedContentAction(duplicatedEditorID);
100
100
  };
101
101
 
@@ -191,8 +191,8 @@ export interface IBrowserProps {
191
191
  browserRef?: React.RefObject<HTMLDivElement>;
192
192
  actions?: {
193
193
  setSelectedContentAction: any;
194
- deleteModuleAction(editorID: number): void;
195
- duplicateModuleAction(editorID: number): Promise<number>;
194
+ deleteModuleAction(editorID: number[]): void;
195
+ duplicateModuleAction(editorID: number[]): number;
196
196
  };
197
197
  }
198
198
 
@@ -12,6 +12,7 @@ const BulkHeader = styled.div<{ isScrolling?: boolean }>`
12
12
  const BulkActionsWrapper = styled.div`
13
13
  display: flex;
14
14
  width: 100%;
15
+ align-items: center;
15
16
  `;
16
17
 
17
18
  const BulkActions = styled.div`
@@ -20,16 +20,16 @@ const Header = (props: IHeaderProps) => {
20
20
 
21
21
  const removeItem = () => {
22
22
  setSelectedContent(parentID);
23
- deleteModuleAction(editorID);
23
+ deleteModuleAction([editorID]);
24
24
  };
25
25
 
26
26
  const duplicateItem = () => {
27
- duplicateModuleAction(editorID);
27
+ duplicateModuleAction([editorID]);
28
28
  setSelectedContent(parentID);
29
29
  };
30
30
 
31
31
  const copyItem = () => {
32
- const isCopied = copyModuleAction(editorID);
32
+ const isCopied = copyModuleAction([editorID]);
33
33
  isCopied && toggleToast();
34
34
  };
35
35
 
@@ -71,7 +71,11 @@ const Header = (props: IHeaderProps) => {
71
71
 
72
72
  export interface IHeaderProps {
73
73
  schema: any;
74
- actions: any;
74
+ actions: {
75
+ deleteModuleAction: (editorID: number[], key?: string) => void;
76
+ duplicateModuleAction: (editorID: number[], key?: string) => number;
77
+ copyModuleAction: (editorID: number[]) => boolean;
78
+ };
75
79
  breadcrumb: IBreadcrumbItem[];
76
80
  selectedParent: any;
77
81
  activatedModules: string[];
@@ -6,4 +6,7 @@ export const FieldGroup = styled.div<{ full?: boolean }>`
6
6
  max-height: ${(p) => (p.full ? "auto" : `calc(${p.theme.spacing.l} * 3)`)};
7
7
  overflow: auto;
8
8
  margin-bottom: ${(p) => p.theme.spacing.xxs};
9
+ & > div {
10
+ margin-bottom: ${p => p.theme.spacing.xxs}
11
+ }
9
12
  `;
@@ -17,6 +17,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
17
17
  icon,
18
18
  className,
19
19
  inversed = false,
20
+ light = false,
20
21
  } = props;
21
22
 
22
23
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -28,7 +29,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
28
29
 
29
30
  return (
30
31
  <S.Wrapper className={className}>
31
- <S.Label data-testid="check-field-label" disabled={disabled} inversed={inversed}>
32
+ <S.Label data-testid="check-field-label" disabled={disabled} inversed={inversed} hasText={!!title}>
32
33
  {icon ? (
33
34
  <S.IconLabelWrapper data-testid="check-field-icon-label">
34
35
  <S.IconWrapper>
@@ -55,6 +56,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
55
56
  error={error}
56
57
  indeterminate={indeterminate}
57
58
  inversed={inversed}
59
+ className={light ? "light" : ""}
58
60
  />
59
61
  </S.Label>
60
62
  </S.Wrapper>
@@ -73,6 +75,7 @@ export interface ICheckFieldProps {
73
75
  icon?: string;
74
76
  inversed?: boolean;
75
77
  className?: string;
78
+ light?: boolean;
76
79
  }
77
80
 
78
81
  export default CheckField;
@@ -2,12 +2,11 @@ import styled from "styled-components";
2
2
 
3
3
  const Wrapper = styled.div``;
4
4
 
5
- const Label = styled.label<{ disabled: boolean | undefined; inversed: boolean }>`
5
+ const Label = styled.label<{ disabled: boolean | undefined; inversed: boolean; hasText: boolean }>`
6
6
  ${(p) => p.theme.textStyle.fieldContent};
7
- display: block;
8
7
  position: relative;
8
+ display: ${(p) => (p.hasText ? "block" : "inline")};
9
9
  padding-left: calc(${(p) => p.theme.spacing.s} + ${(p) => p.theme.spacing.xs});
10
- margin-bottom: ${(p) => p.theme.spacing.xs};
11
10
  cursor: pointer;
12
11
  user-select: none;
13
12
  color: ${(p) =>
@@ -60,6 +59,23 @@ const CheckMark = styled.span<{
60
59
  border-width: ${(p) => (p.indeterminate ? "0 2px 0 0" : "0 2px 2px 0")};
61
60
  transform: ${(p) => (p.indeterminate ? "rotate(90deg)" : "rotate(45deg)")};
62
61
  }
62
+
63
+ &.light {
64
+ border-color: ${(p) =>
65
+ p.error
66
+ ? p.theme.color.error
67
+ : p.checked || p.indeterminate
68
+ ? p.theme.color.interactive01
69
+ : p.theme.color.textLowEmphasis};
70
+ &:hover {
71
+ border-color: ${(p) =>
72
+ p.error
73
+ ? p.theme.color.error
74
+ : p.checked || p.indeterminate
75
+ ? p.theme.color.interactive01
76
+ : p.theme.color.interactiveInactive};
77
+ }
78
+ }
63
79
  `;
64
80
 
65
81
  const Input = styled.input`
@@ -24,9 +24,10 @@ const CheckGroup = (props: ICheckGroupProps): JSX.Element => {
24
24
 
25
25
  if (selectAllOption) {
26
26
  const valueArrayNoAll = valueArray.filter((item: string | number) => item !== selectAllOption);
27
-
27
+ const uniqueOption = options && options.length === 2;
28
28
  const isAllSelected =
29
- newValue.value === selectAllOption || (options && valueArrayNoAll.length === options.length - 1);
29
+ newValue.value === selectAllOption ||
30
+ (options && valueArrayNoAll.length === options.length - 1 && !uniqueOption);
30
31
 
31
32
  valueArray = isAllSelected ? [selectAllOption] : valueArrayNoAll;
32
33
  }
@@ -4,4 +4,7 @@ export const FieldGroup = styled.div`
4
4
  width: 100%;
5
5
  max-width: calc(${p => p.theme.spacing.xl} * 5);
6
6
  overflow: auto;
7
+ & > div {
8
+ margin-bottom: ${p => p.theme.spacing.xxs}
9
+ }
7
10
  `;
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import { CheckField, Icon, IconAction } from "@ax/components";
3
+ import { IBulkAction } from "@ax/types";
4
+
5
+ import * as S from "./style";
6
+
7
+ const BulkHeader = (props: IProps): JSX.Element => {
8
+ const { checkState, selectItems, totalItems, actions, toggleBulk } = props;
9
+
10
+ const handleClick = () => toggleBulk();
11
+
12
+ return (
13
+ <S.Wrapper>
14
+ <S.CloseWrapper onClick={handleClick}>
15
+ <Icon name="close" size="16" />
16
+ </S.CloseWrapper>
17
+ <S.SelectAllCheckField>
18
+ <CheckField
19
+ key="selectAll"
20
+ name="selectAll"
21
+ value="selectAll"
22
+ onChange={selectItems}
23
+ checked={checkState.isAllSelected}
24
+ indeterminate={checkState.indeterminate}
25
+ disabled={false}
26
+ error={false}
27
+ />
28
+ </S.SelectAllCheckField>
29
+ <S.Counter>{totalItems} selected</S.Counter>
30
+ <S.BulkActions>
31
+ {actions.map((item: IBulkAction) => (
32
+ <IconAction key={item.text} icon={item.icon || ""} onClick={item.action} size="s" />
33
+ ))}
34
+ </S.BulkActions>
35
+ </S.Wrapper>
36
+ );
37
+ };
38
+
39
+ interface IProps {
40
+ checkState: any;
41
+ selectItems: () => void;
42
+ totalItems: number;
43
+ toggleBulk: () => void;
44
+ actions: IBulkAction[];
45
+ }
46
+
47
+ export default BulkHeader;
@@ -0,0 +1,44 @@
1
+ import styled from "styled-components";
2
+
3
+ const Wrapper = styled.div`
4
+ display: flex;
5
+ background-color: ${(p) => p.theme.color.uiBackground03};
6
+ width: 236px;
7
+ height: 32px;
8
+ margin-top: ${(p) => p.theme.spacing.xxs};
9
+ border-radius: ${(p) => p.theme.radii.s};
10
+ align-items: center;
11
+ padding: ${(p) => `0 ${p.theme.spacing.xs}`};
12
+ `;
13
+
14
+ const SelectAllCheckField = styled.div`
15
+ margin-left: ${(p) => p.theme.spacing.xxs};
16
+ width: ${(p) => p.theme.spacing.s};
17
+ `;
18
+
19
+ const CloseWrapper = styled.div`
20
+ width: ${(p) => p.theme.spacing.s};
21
+ height: ${(p) => p.theme.spacing.s};
22
+ cursor: pointer;
23
+ svg {
24
+ path {
25
+ fill: ${(p) => p.theme.color.iconMediumEmphasis};
26
+ }
27
+ }
28
+ `;
29
+
30
+ const Counter = styled.div`
31
+ ${(p) => p.theme.textStyle.uiS};
32
+ color: ${(p) => p.theme.color.textMediumEmphasis};
33
+ margin-left: ${(p) => p.theme.spacing.xs};
34
+ `;
35
+
36
+ const BulkActions = styled.div`
37
+ display: flex;
38
+ margin-left: auto;
39
+ button {
40
+ margin-left: ${(p) => p.theme.spacing.xxs};
41
+ }
42
+ `;
43
+
44
+ export { Wrapper, CloseWrapper, SelectAllCheckField, Counter, BulkActions };
@@ -2,23 +2,24 @@ import React, { memo } from "react";
2
2
 
3
3
  import { useToast } from "@ax/hooks";
4
4
  import { Tooltip, IconAction, Toast } from "@ax/components";
5
- import { INotification } from "@ax/types";
5
+ import { IModule, INotification } from "@ax/types";
6
6
 
7
7
  const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
8
- const { pasteModule, setNotification, setHistoryPush, editorID, isModuleCopyUnavailable, arrayKey } = props;
8
+ const {
9
+ pasteModule,
10
+ setNotification,
11
+ setHistoryPush,
12
+ editorID,
13
+ isModuleCopyUnavailable,
14
+ arrayKey,
15
+ modulesToPaste,
16
+ slots,
17
+ } = props;
9
18
 
10
19
  const { isVisible, toggleToast, setIsVisible } = useToast();
11
20
 
12
21
  const handlePasteModule = async () => {
13
- if (!isModuleCopyUnavailable) {
14
- const pasteResult = await pasteModule(editorID, arrayKey);
15
- if (pasteResult.error) {
16
- const { type, text } = pasteResult.error;
17
- setNotification && setNotification({ type, text });
18
- } else {
19
- toggleToast();
20
- }
21
- } else {
22
+ if (isModuleCopyUnavailable) {
22
23
  const notification: INotification = {
23
24
  type: "error",
24
25
  text: "You are trying to paste a module that is part of a disabled content type package. To copy it, you must first activate it.",
@@ -27,6 +28,22 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
27
28
  };
28
29
  setNotification && setNotification(notification);
29
30
  }
31
+
32
+ if (slots && modulesToPaste.length > slots) {
33
+ const notification: INotification = {
34
+ type: "error",
35
+ text: "Unable to paste modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
36
+ };
37
+ setNotification && setNotification(notification);
38
+ } else {
39
+ const pasteResult = await pasteModule(editorID, arrayKey, modulesToPaste);
40
+ if (pasteResult?.error) {
41
+ const { type, text } = pasteResult.error;
42
+ setNotification && setNotification({ type, text });
43
+ } else {
44
+ toggleToast();
45
+ }
46
+ }
30
47
  };
31
48
 
32
49
  return (
@@ -40,12 +57,14 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
40
57
  };
41
58
 
42
59
  export interface IPasteModuleProps {
43
- pasteModule: (editorID: number, key: string) => Promise<{ error?: INotification }>;
60
+ pasteModule: (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>;
44
61
  setNotification?: (notification: INotification) => void;
45
62
  setHistoryPush?: (path: string, isEditor: boolean) => void;
46
63
  editorID: number;
47
64
  isModuleCopyUnavailable: boolean;
48
65
  arrayKey: string;
66
+ modulesToPaste: IModule[];
67
+ slots: number | null;
49
68
  }
50
69
 
51
70
  export default memo(PasteModuleButton);