@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.
- package/jest.config.ts +2 -0
- package/lib/EditorToolbar/EditorToolbar.js +3 -1
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +3 -0
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +29 -0
- package/lib/EditorToolbar/Tools/Link/LinkButton.d.ts +7 -0
- package/lib/EditorToolbar/Tools/Link/LinkButton.js +8 -0
- package/lib/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.d.ts +3 -0
- package/lib/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.js +12 -0
- package/lib/index.css +401 -3744
- package/lib/ui/Inputs/Select/Select.d.ts +12 -0
- package/lib/ui/Inputs/Select/Select.js +19 -0
- package/lib/ui/Inputs/Text/TextInput.d.ts +8 -0
- package/lib/ui/Inputs/Text/TextInput.js +6 -0
- package/lib/ui/Modal/Modal.d.ts +9 -0
- package/lib/ui/Modal/Modal.js +30 -0
- package/lib/ui/ToolbarButton/ToolbarButton.js +1 -1
- package/package.json +10 -7
- package/src/Editor/_editor.scss +16 -9
- package/src/EditorToolbar/EditorToolbar.tsx +2 -0
- package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +21 -0
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +41 -0
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +26 -0
- package/src/EditorToolbar/Tools/Link/LinkButton.tsx +25 -0
- package/src/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.spec.tsx +41 -0
- package/src/EditorToolbar/Tools/Link/Trigger/TriggerLinkModal.tsx +21 -0
- package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +1 -1
- package/src/EditorToolbar/_editor-toolbar.scss +1 -1
- package/src/index.scss +5 -2
- package/src/ui/DropdownButton/_dropdown-button.scss +3 -2
- package/src/ui/Inputs/Select/Select.spec.tsx +24 -0
- package/src/ui/Inputs/Select/Select.tsx +67 -0
- package/src/ui/Inputs/Text/TextInput.spec.tsx +43 -0
- package/src/ui/Inputs/Text/TextInput.tsx +20 -0
- package/src/ui/Modal/Modal.spec.tsx +75 -0
- package/src/ui/Modal/Modal.tsx +70 -0
- package/src/ui/Modal/_modal.scss +24 -0
- package/src/ui/ToolbarButton/ToolbarButton.tsx +1 -1
- package/src/ui/ToolbarButton/_toolbar-button.scss +5 -25
- package/src/ui/_buttons.scss +19 -0
- package/src/ui/_forms.scss +16 -0
- 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
|
+
}
|
package/tailwind.config.cjs
CHANGED
@@ -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',
|