@squiz/formatted-text-editor 1.12.0-alpha.40 → 1.12.0-alpha.43

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 (43) hide show
  1. package/jest.config.ts +2 -0
  2. package/lib/EditorToolbar/EditorToolbar.js +3 -1
  3. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +3 -0
  4. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +29 -0
  5. package/lib/EditorToolbar/Tools/Link/LinkButton.d.ts +7 -0
  6. package/lib/EditorToolbar/Tools/Link/LinkButton.js +8 -0
  7. package/lib/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.d.ts +3 -0
  8. package/lib/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.js +12 -0
  9. package/lib/index.css +401 -3744
  10. package/lib/ui/Inputs/Select/Select.d.ts +12 -0
  11. package/lib/ui/Inputs/Select/Select.js +19 -0
  12. package/lib/ui/Inputs/Text/TextInput.d.ts +8 -0
  13. package/lib/ui/Inputs/Text/TextInput.js +6 -0
  14. package/lib/ui/Modal/Modal.d.ts +9 -0
  15. package/lib/ui/Modal/Modal.js +30 -0
  16. package/lib/ui/ToolbarButton/ToolbarButton.js +1 -1
  17. package/package.json +10 -7
  18. package/src/Editor/_editor.scss +16 -9
  19. package/src/EditorToolbar/EditorToolbar.tsx +2 -0
  20. package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +1 -1
  21. package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +1 -1
  22. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +21 -0
  23. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +41 -0
  24. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +26 -0
  25. package/src/EditorToolbar/Tools/Link/LinkButton.tsx +25 -0
  26. package/src/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.spec.tsx +41 -0
  27. package/src/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.tsx +21 -0
  28. package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +1 -1
  29. package/src/EditorToolbar/_editor-toolbar.scss +1 -1
  30. package/src/index.scss +5 -2
  31. package/src/ui/DropdownButton/_dropdown-button.scss +3 -2
  32. package/src/ui/Inputs/Select/Select.spec.tsx +24 -0
  33. package/src/ui/Inputs/Select/Select.tsx +67 -0
  34. package/src/ui/Inputs/Text/TextInput.spec.tsx +43 -0
  35. package/src/ui/Inputs/Text/TextInput.tsx +20 -0
  36. package/src/ui/Modal/Modal.spec.tsx +75 -0
  37. package/src/ui/Modal/Modal.tsx +70 -0
  38. package/src/ui/Modal/_modal.scss +24 -0
  39. package/src/ui/ToolbarButton/ToolbarButton.tsx +1 -1
  40. package/src/ui/ToolbarButton/_toolbar-button.scss +5 -25
  41. package/src/ui/_buttons.scss +19 -0
  42. package/src/ui/_forms.scss +16 -0
  43. package/tailwind.config.cjs +23 -0
@@ -0,0 +1,75 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import React from 'react';
4
+ import Modal from './Modal';
5
+
6
+ describe('Modal', () => {
7
+ const mockOnCancel = jest.fn();
8
+ const mockOnSubmit = jest.fn();
9
+
10
+ const ModalComponent = () => {
11
+ return (
12
+ <Modal onCancel={mockOnCancel}>
13
+ <div>I am a child in the modal</div>
14
+ </Modal>
15
+ );
16
+ };
17
+
18
+ it('Renders the modal title', () => {
19
+ render(<ModalComponent />);
20
+ // Check that the modal heading displays
21
+ const modalHeading = screen.getByRole('heading', {
22
+ name: /Link/i,
23
+ });
24
+ expect(modalHeading).toBeInTheDocument();
25
+ });
26
+
27
+ it('Renders the child', () => {
28
+ render(<ModalComponent />);
29
+ // Check that the modal heading displays
30
+ const modalChild = screen.getByText(/I am a child in the modal/i);
31
+ expect(modalChild).toBeInTheDocument();
32
+ });
33
+
34
+ it('Renders the cancel button', () => {
35
+ render(<ModalComponent />);
36
+ // Check that the cancel button renders
37
+ const cancelButton = screen.getByRole('button', { name: 'Cancel' });
38
+ expect(cancelButton).toBeInTheDocument();
39
+ // check that firing the cancel button fires the cancel function
40
+ fireEvent.click(cancelButton);
41
+ expect(mockOnCancel).toHaveBeenCalled();
42
+ });
43
+
44
+ it('Does not render the submit button if there is no submit function supplied', () => {
45
+ render(<ModalComponent />);
46
+ // Check that the submit button does not render
47
+ const submitButton = screen.queryByRole('button', { name: 'Apply' });
48
+ expect(submitButton).not.toBeInTheDocument();
49
+ });
50
+
51
+ it('Renders the submit button if there is a submit function supplied', () => {
52
+ render(
53
+ <Modal onCancel={mockOnCancel} onSubmit={mockOnSubmit}>
54
+ <div>I am a child in the modal</div>
55
+ </Modal>,
56
+ );
57
+ // Check that the submit button renders
58
+ const submitButton = screen.getByRole('button', { name: 'Apply' });
59
+ expect(submitButton).toBeInTheDocument();
60
+ });
61
+
62
+ it('Checks that the submit function fires if you click on the submit button', () => {
63
+ render(
64
+ <Modal onCancel={mockOnCancel} onSubmit={mockOnSubmit}>
65
+ <div>I am a child in the modal</div>
66
+ </Modal>,
67
+ );
68
+ // Check that the submit button renders
69
+ const submitButton = screen.getByRole('button', { name: 'Apply' });
70
+ expect(submitButton).toBeInTheDocument();
71
+ // check that firing the submit button fires the submit function
72
+ fireEvent.click(submitButton);
73
+ expect(mockOnSubmit).toHaveBeenCalled();
74
+ });
75
+ });
@@ -0,0 +1,70 @@
1
+ import React, { ReactElement, useEffect } from 'react';
2
+ import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
3
+
4
+ type ModalProps = {
5
+ children: ReactElement;
6
+ onCancel: () => void;
7
+ onSubmit?: () => void;
8
+ className?: string;
9
+ };
10
+
11
+ const Modal = ({ children, onCancel, onSubmit, className }: ModalProps): ReactElement => {
12
+ const keydown = (e: { key: string }) => {
13
+ if (e.key === 'Escape') {
14
+ onCancel();
15
+ }
16
+ if (e.key === 'Enter') {
17
+ onSubmit && onSubmit();
18
+ }
19
+ };
20
+
21
+ useEffect(() => {
22
+ window.addEventListener('keydown', keydown);
23
+ return () => window.removeEventListener('keydown', keydown);
24
+ }, []);
25
+
26
+ return (
27
+ <>
28
+ <div className={`sds-modal-wrapper ${className ? className : ''}`}>
29
+ <div className="w-modal-sm my-6 mx-auto">
30
+ <div className="sds-modal">
31
+ <div className="sds-modal-header p-6 pb-2">
32
+ <h2 className="font-semibold text-gray-900 text-heading-2">Link</h2>
33
+ <button
34
+ 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"
35
+ onClick={onCancel}
36
+ aria-label="Close"
37
+ >
38
+ <CloseRoundedIcon />
39
+ </button>
40
+ </div>
41
+ <div className="sds-modal-content">{children}</div>
42
+ <div className="sds-modal-footer p-6 pt-3">
43
+ <button
44
+ className="sds-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300"
45
+ type="button"
46
+ onClick={onCancel}
47
+ aria-label="Cancel"
48
+ >
49
+ Cancel
50
+ </button>
51
+ {onSubmit && (
52
+ <button
53
+ className="sds-modal-footer__button bg-blue-300 text-white hover:bg-blue-400"
54
+ type="button"
55
+ onClick={onSubmit}
56
+ aria-label="Apply"
57
+ >
58
+ Apply
59
+ </button>
60
+ )}
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ <div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
66
+ </>
67
+ );
68
+ };
69
+
70
+ export default Modal;
@@ -0,0 +1,24 @@
1
+ .sds-modal {
2
+ @apply border-0 rounded shadow-lg flex flex-col w-full bg-white font-base;
3
+ border-radius: 8px;
4
+
5
+ &-wrapper {
6
+ @apply justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none;
7
+ }
8
+
9
+ &-header {
10
+ @apply flex items-start justify-between;
11
+ }
12
+
13
+ &-content {
14
+ @apply relative px-6 flex-auto;
15
+ }
16
+
17
+ &-footer {
18
+ @apply flex items-center justify-end rounded-b;
19
+
20
+ &__button {
21
+ @apply sds-btn text-md font-bold;
22
+ }
23
+ }
24
+ }
@@ -16,7 +16,7 @@ const ToolbarButton = ({ handleOnClick, isDisabled, isActive, icon, label }: Too
16
16
  type="button"
17
17
  onClick={handleOnClick}
18
18
  disabled={isDisabled}
19
- className={`btn toolbar-button ${isActive ? 'is-active' : ''}`}
19
+ className={`sds-btn toolbar-button ${isActive ? 'is-active' : ''}`}
20
20
  >
21
21
  {icon}
22
22
  </button>
@@ -1,28 +1,3 @@
1
- .btn {
2
- @apply font-normal rounded;
3
- display: flex;
4
- align-items: center;
5
- text-align: center;
6
- white-space: nowrap;
7
- vertical-align: middle;
8
- touch-action: manipulation;
9
- cursor: pointer;
10
- background-image: none;
11
- border: 1px solid transparent;
12
-
13
- &:active,
14
- &:hover,
15
- &:focus {
16
- background-color: rgba(black, 0.04);
17
- }
18
-
19
- &.disabled,
20
- &[disabled] {
21
- cursor: not-allowed;
22
- @apply opacity-50;
23
- }
24
- }
25
-
26
1
  .toolbar-button {
27
2
  @apply bg-white text-gray-600 p-1;
28
3
 
@@ -30,6 +5,11 @@
30
5
  margin-left: 2px;
31
6
  }
32
7
 
8
+ &:hover,
9
+ &:focus {
10
+ background-color: rgba(black, 0.04);
11
+ }
12
+
33
13
  &.is-active,
34
14
  &:active {
35
15
  @apply text-blue-300 bg-blue-100;
@@ -0,0 +1,19 @@
1
+ .sds-btn {
2
+ @apply font-normal rounded ease-linear transition-all duration-150;
3
+ display: flex;
4
+ align-items: center;
5
+ text-align: center;
6
+ white-space: nowrap;
7
+ vertical-align: middle;
8
+ touch-action: manipulation;
9
+ cursor: pointer;
10
+ background-image: none;
11
+ border: 1px solid transparent;
12
+ padding: 6px 12px;
13
+
14
+ &.disabled,
15
+ &[disabled] {
16
+ cursor: not-allowed;
17
+ @apply opacity-50;
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ .sds {
2
+ &-form-group {
3
+ @apply flex flex-col;
4
+ }
5
+ &-form-label {
6
+ @apply mb-1 text-md font-semibold text-gray-600;
7
+ }
8
+ &-form-control {
9
+ padding: 6px 12px;
10
+ @apply placeholder-slate-300 text-gray-800 relative bg-white rounded text-md border-2 border-gray-300 outline-0 focus:outline-0 focus:border-blue-300 w-full;
11
+ &:focus,
12
+ &:active {
13
+ box-shadow: none;
14
+ }
15
+ }
16
+ }
@@ -21,6 +21,14 @@ module.exports = {
21
21
  lg: '1rem',
22
22
  md: '0.875rem',
23
23
  sm: '0.8125rem',
24
+ base: '1rem',
25
+ 'heading-1': ['1.625rem', '2rem'],
26
+ 'heading-2': ['1.25rem', '1.5rem'],
27
+ 'heading-3': ['1.125rem', '1.375rem'],
28
+ 'heading-4': ['1rem', '1.25rem'],
29
+ },
30
+ fontFamily: {
31
+ base: 'Open Sans, Arial, sans-serif',
24
32
  },
25
33
  boxShadow: {
26
34
  outline: '0 0 0 1px rgba(0,0,0,0.10)',
@@ -31,6 +39,12 @@ module.exports = {
31
39
  inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
32
40
  none: 'none',
33
41
  },
42
+ width: {
43
+ 'modal-sm': '25rem',
44
+ 'modal-md': '37.5rem',
45
+ 'modal-lg': '50rem',
46
+ 'modal-xl': '62.5rem',
47
+ },
34
48
  spacing: {
35
49
  1: '0.25rem', // 4px
36
50
  2: '0.5rem', // 8px
@@ -44,13 +58,22 @@ module.exports = {
44
58
  },
45
59
  colors: {
46
60
  gray: {
61
+ 50: '#F7F7F7',
62
+ 100: '#F5F5F5',
47
63
  200: '#ededed',
48
64
  300: '#e0e0e0',
65
+ 400: '#BABABA',
66
+ 500: '#949494',
49
67
  600: '#707070',
68
+ 700: '#4F4F4F',
69
+ 800: '#3D3D3D',
70
+ 900: '#2B2B2B',
50
71
  },
51
72
  blue: {
52
73
  100: '#e6f1fa',
74
+ 200: '#8FC0EB',
53
75
  300: '#0774d2',
76
+ 400: '#044985',
54
77
  },
55
78
  orange: {
56
79
  100: '#dadbe9',