@squiz/formatted-text-editor 1.12.0-alpha.44 → 1.12.0-alpha.46

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 (52) hide show
  1. package/lib/EditorToolbar/EditorToolbar.js +1 -1
  2. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +5 -5
  3. package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.js +1 -1
  4. package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.js +2 -3
  5. package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.js +1 -1
  6. package/lib/FormattedTextEditor.js +3 -2
  7. package/lib/index.css +161 -459
  8. package/lib/ui/Inputs/Select/Select.js +1 -1
  9. package/lib/ui/Inputs/Text/TextInput.js +2 -2
  10. package/lib/ui/Modal/Modal.js +7 -7
  11. package/lib/ui/ToolbarButton/ToolbarButton.js +1 -1
  12. package/lib/ui/ToolbarDropdown/ToolbarDropdown.d.ts +0 -1
  13. package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +14 -6
  14. package/lib/ui/{DropdownButton/DropdownButton.js → ToolbarDropdownButton/ToolbarDropdownButton.js} +1 -1
  15. package/package.json +4 -4
  16. package/postcss.config.js +9 -1
  17. package/src/Editor/_editor.scss +1 -1
  18. package/src/EditorToolbar/EditorToolbar.tsx +1 -1
  19. package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +1 -1
  20. package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +1 -1
  21. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +1 -1
  22. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +5 -5
  23. package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.spec.tsx +39 -0
  24. package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.spec.tsx +39 -0
  25. package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.spec.tsx +39 -0
  26. package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.spec.tsx +39 -0
  27. package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.spec.tsx +56 -0
  28. package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.tsx +1 -1
  29. package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.spec.tsx +30 -0
  30. package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.tsx +2 -3
  31. package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.spec.tsx +47 -0
  32. package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.tsx +1 -1
  33. package/src/EditorToolbar/Tools/TextType/TextTypeDropdown.spec.tsx +51 -0
  34. package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +1 -1
  35. package/src/EditorToolbar/_editor-toolbar.scss +4 -2
  36. package/src/FormattedTextEditor.tsx +4 -2
  37. package/src/index.scss +2 -2
  38. package/src/ui/Inputs/Select/Select.tsx +1 -1
  39. package/src/ui/Inputs/Text/TextInput.tsx +2 -2
  40. package/src/ui/Modal/Modal.tsx +7 -7
  41. package/src/ui/Modal/_modal.scss +2 -2
  42. package/src/ui/ToolbarButton/ToolbarButton.tsx +1 -1
  43. package/src/ui/ToolbarDropdown/ToolbarDropdown.spec.tsx +78 -0
  44. package/src/ui/ToolbarDropdown/ToolbarDropdown.tsx +22 -12
  45. package/src/ui/ToolbarDropdown/_toolbar-dropdown.scss +25 -20
  46. package/src/ui/ToolbarDropdownButton/ToolbarDropdownButton.spec.tsx +48 -0
  47. package/src/ui/{DropdownButton/DropdownButton.tsx → ToolbarDropdownButton/ToolbarDropdownButton.tsx} +1 -0
  48. package/src/ui/{DropdownButton/_dropdown-button.scss → ToolbarDropdownButton/_toolbar-dropdown-button.scss} +7 -1
  49. package/src/ui/_buttons.scss +1 -1
  50. package/src/ui/_forms.scss +1 -1
  51. package/tailwind.config.cjs +2 -4
  52. /package/lib/ui/{DropdownButton/DropdownButton.d.ts → ToolbarDropdownButton/ToolbarDropdownButton.d.ts} +0 -0
@@ -3,8 +3,10 @@ import Editor from './Editor/Editor';
3
3
 
4
4
  const FormattedTextEditor = () => {
5
5
  return (
6
- <div className="remirror-theme formatted-text-editor editor-wrapper">
7
- <Editor />
6
+ <div className="squiz-fte-scope">
7
+ <div className="remirror-theme formatted-text-editor editor-wrapper">
8
+ <Editor />
9
+ </div>
8
10
  </div>
9
11
  );
10
12
  };
package/src/index.scss CHANGED
@@ -1,4 +1,4 @@
1
- /* Tailwind base */
1
+ /* Tailwind base styles, but scoped to the editor */
2
2
  @import 'tailwindcss/base';
3
3
  @import 'tailwindcss/components';
4
4
  @import 'tailwindcss/utilities';
@@ -13,6 +13,6 @@
13
13
 
14
14
  @import './ui/ToolbarButton/toolbar-button';
15
15
  @import './ui/ToolbarDropdown/toolbar-dropdown';
16
- @import './ui/DropdownButton/dropdown-button';
16
+ @import './ui/ToolbarDropdownButton/toolbar-dropdown-button';
17
17
 
18
18
  @import './ui/Modal/modal';
@@ -20,7 +20,7 @@ export const Select = ({ id, label, value, options }: SelectProps) => {
20
20
  return (
21
21
  <>
22
22
  {label && (
23
- <label htmlFor={id} className="sds-form-label">
23
+ <label htmlFor={id} className="squiz-fte-form-label">
24
24
  {label}
25
25
  </label>
26
26
  )}
@@ -10,11 +10,11 @@ export const TextInput = ({ id, label, value, ...rest }: TextInputProps) => {
10
10
  return (
11
11
  <>
12
12
  {label && (
13
- <label htmlFor={id} className="sds-form-label">
13
+ <label htmlFor={id} className="squiz-fte-form-label">
14
14
  {label}
15
15
  </label>
16
16
  )}
17
- <input name={id} id={id} type="text" className="sds-form-control" defaultValue={value} {...rest} />
17
+ <input name={id} id={id} type="text" className="squiz-fte-form-control" defaultValue={value} {...rest} />
18
18
  </>
19
19
  );
20
20
  };
@@ -25,10 +25,10 @@ const Modal = ({ children, onCancel, onSubmit, className }: ModalProps): ReactEl
25
25
 
26
26
  return (
27
27
  <>
28
- <div className={`sds-modal-wrapper ${className ? className : ''}`}>
28
+ <div className={`squiz-fte-modal-wrapper ${className ? className : ''}`}>
29
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">
30
+ <div className="squiz-fte-modal">
31
+ <div className="squiz-fte-modal-header p-6 pb-2">
32
32
  <h2 className="font-semibold text-gray-900 text-heading-2">Link</h2>
33
33
  <button
34
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"
@@ -38,10 +38,10 @@ const Modal = ({ children, onCancel, onSubmit, className }: ModalProps): ReactEl
38
38
  <CloseRoundedIcon />
39
39
  </button>
40
40
  </div>
41
- <div className="sds-modal-content">{children}</div>
42
- <div className="sds-modal-footer p-6 pt-3">
41
+ <div className="squiz-fte-modal-content">{children}</div>
42
+ <div className="squiz-fte-modal-footer p-6 pt-3">
43
43
  <button
44
- className="sds-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300"
44
+ className="squiz-fte-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300"
45
45
  type="button"
46
46
  onClick={onCancel}
47
47
  aria-label="Cancel"
@@ -50,7 +50,7 @@ const Modal = ({ children, onCancel, onSubmit, className }: ModalProps): ReactEl
50
50
  </button>
51
51
  {onSubmit && (
52
52
  <button
53
- className="sds-modal-footer__button bg-blue-300 text-white hover:bg-blue-400"
53
+ className="squiz-fte-modal-footer__button bg-blue-300 text-white hover:bg-blue-400"
54
54
  type="button"
55
55
  onClick={onSubmit}
56
56
  aria-label="Apply"
@@ -1,4 +1,4 @@
1
- .sds-modal {
1
+ .squiz-fte-modal {
2
2
  @apply border-0 rounded shadow-lg flex flex-col w-full bg-white font-base;
3
3
  border-radius: 8px;
4
4
 
@@ -18,7 +18,7 @@
18
18
  @apply flex items-center justify-end rounded-b;
19
19
 
20
20
  &__button {
21
- @apply sds-btn text-md font-bold;
21
+ @apply squiz-fte-btn text-md font-bold;
22
22
  }
23
23
  }
24
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={`sds-btn toolbar-button ${isActive ? 'is-active' : ''}`}
19
+ className={`squiz-fte-btn toolbar-button ${isActive ? 'is-active' : ''}`}
20
20
  >
21
21
  {icon}
22
22
  </button>
@@ -0,0 +1,78 @@
1
+ import '@testing-library/jest-dom';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
+ import React from 'react';
4
+ import ToolbarDropdown from './ToolbarDropdown';
5
+
6
+ describe('Toolbar dropdown', () => {
7
+ const ToolbarDropdownComponent = () => {
8
+ return (
9
+ <ToolbarDropdown label="Test dropdown">
10
+ <button>Test button</button>
11
+ <button>Test button 2</button>
12
+ </ToolbarDropdown>
13
+ );
14
+ };
15
+
16
+ it('Renders the dropdown button', () => {
17
+ render(<ToolbarDropdownComponent />);
18
+ // Check that the supplied label renders
19
+ const dropdownButton = screen.getByRole('button', { name: 'Test dropdown' });
20
+ expect(dropdownButton).toBeInTheDocument();
21
+ });
22
+
23
+ it('Renders the child elements for the dropdown', () => {
24
+ render(<ToolbarDropdownComponent />);
25
+ // Check that default value supplied renders
26
+ expect(screen.getByRole('button', { name: 'Test button' })).toBeInTheDocument();
27
+ expect(screen.getByRole('button', { name: 'Test button 2' })).toBeInTheDocument();
28
+ });
29
+
30
+ it('Renders the dropdown menu after clicking the dropdown button', () => {
31
+ const { baseElement } = render(<ToolbarDropdownComponent />);
32
+ expect(baseElement).toBeTruthy();
33
+
34
+ const dropdownButton = baseElement.querySelector('button#dropdownHoverButton') as HTMLButtonElement;
35
+ expect(dropdownButton).toBeTruthy();
36
+ fireEvent.click(dropdownButton);
37
+
38
+ const dropdownMenu = baseElement.querySelector('div.toolbar-dropdown__menu') as HTMLDivElement;
39
+ expect(dropdownMenu).toBeTruthy();
40
+ expect(dropdownMenu.classList).toContain('block');
41
+ });
42
+
43
+ it('Handles the onBlur call when focusing out of the menu', () => {
44
+ const { baseElement } = render(<ToolbarDropdownComponent />);
45
+ expect(baseElement).toBeTruthy();
46
+
47
+ const dropdownButton = baseElement.querySelector('button#dropdownHoverButton') as HTMLButtonElement;
48
+ expect(dropdownButton).toBeTruthy();
49
+ fireEvent.click(dropdownButton);
50
+
51
+ const dropdownMenu = baseElement.querySelector('div.toolbar-dropdown__menu') as HTMLDivElement;
52
+ expect(dropdownMenu).toBeTruthy();
53
+ expect(dropdownMenu.classList).toContain('block');
54
+
55
+ fireEvent.blur(dropdownMenu);
56
+
57
+ expect(dropdownMenu.classList).toContain('hidden');
58
+ });
59
+
60
+ it('Closes the dropdown menu after clicking a child element', () => {
61
+ const { baseElement } = render(<ToolbarDropdownComponent />);
62
+ expect(baseElement).toBeTruthy();
63
+
64
+ const dropdownButton = baseElement.querySelector('button#dropdownHoverButton') as HTMLButtonElement;
65
+ expect(dropdownButton).toBeTruthy();
66
+ fireEvent.click(dropdownButton);
67
+
68
+ const dropdownMenu = baseElement.querySelector('div.toolbar-dropdown__menu') as HTMLDivElement;
69
+ expect(dropdownMenu).toBeTruthy();
70
+ expect(dropdownMenu.classList).toContain('block');
71
+
72
+ const childElement = screen.getByRole('button', { name: 'Test button' });
73
+ expect(childElement).toBeTruthy();
74
+ fireEvent.click(childElement);
75
+
76
+ expect(dropdownMenu.classList).toContain('hidden');
77
+ });
78
+ });
@@ -1,6 +1,5 @@
1
- import React from 'react';
1
+ import React, { FocusEventHandler, useState } from 'react';
2
2
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
3
- import 'flowbite';
4
3
 
5
4
  type ToolbarDropdownProps = {
6
5
  children: JSX.Element | JSX.Element[];
@@ -8,24 +7,35 @@ type ToolbarDropdownProps = {
8
7
  };
9
8
 
10
9
  const ToolbarDropdown = ({ children, label }: ToolbarDropdownProps) => {
10
+ const [isOpen, setOpen] = useState<boolean>(false);
11
+
12
+ const handleDropDown = () => {
13
+ setOpen(!isOpen);
14
+ };
15
+
16
+ const handleBlur: FocusEventHandler<HTMLDivElement> = (event) => {
17
+ if (event.relatedTarget?.id !== 'dropdownMenuButton' && !event.target?.className.includes('is-active')) {
18
+ isOpen && handleDropDown();
19
+ }
20
+ };
21
+
11
22
  return (
12
- <>
13
- <button
14
- id="dropdownHoverButton"
15
- data-dropdown-toggle="dropdown"
16
- className="toolbar-dropdown__button"
17
- type="button"
18
- >
23
+ <div className="toolbar-dropdown" onBlur={handleBlur}>
24
+ <button id="dropdownHoverButton" className="toolbar-dropdown__button" onClick={handleDropDown}>
19
25
  <span className="toolbar-dropdown__label">{label}</span>
20
26
  <ExpandMoreIcon className="toolbar-dropdown__icon" aria-hidden="true" />
21
27
  </button>
28
+
22
29
  <div
23
30
  id="dropdown"
24
- className="toolbar-dropdown__menu z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow w-169 dark:bg-gray-700"
31
+ className={`toolbar-dropdown__menu z-10 ${isOpen ? 'block' : 'hidden'} bg-white divide-y w-169`}
25
32
  >
26
- <ul aria-labelledby="dropdownHoverButton">{children}</ul>
33
+ {/* eslint-disable-next-line */}
34
+ <ul aria-labelledby="dropdownHoverButton" onClick={handleDropDown}>
35
+ {children}
36
+ </ul>
27
37
  </div>
28
- </>
38
+ </div>
29
39
  );
30
40
  };
31
41
 
@@ -1,27 +1,32 @@
1
- .toolbar-dropdown__button {
2
- @apply font-base text-md font-semibold text-gray-600;
3
- align-self: center;
1
+ .toolbar-dropdown {
2
+ &__button {
3
+ @apply flex items-center font-base text-md font-semibold text-gray-600;
4
+ align-self: center;
4
5
 
5
- height: 2rem;
6
- padding-left: 0.5rem;
6
+ height: 2rem;
7
+ padding-left: 0.5rem;
7
8
 
8
- &:active,
9
- &:hover,
10
- &:focus {
11
- background-color: rgba(black, 0.04);
12
- }
9
+ &:active,
10
+ &:hover,
11
+ &:focus {
12
+ background-color: rgba(black, 0.04);
13
+ }
13
14
 
14
- .toolbar-dropdown__label {
15
- display: inline-flex;
16
- width: 7rem;
17
- }
15
+ .toolbar-dropdown__label {
16
+ display: inline-flex;
17
+ width: 7rem;
18
+ }
18
19
 
19
- .toolbar-dropdown__icon {
20
- width: 1rem;
21
- height: 1.5rem;
20
+ .toolbar-dropdown__icon {
21
+ width: 1rem;
22
+ height: 1.5rem;
23
+ }
22
24
  }
23
- }
24
25
 
25
- .toolbar-dropdown__menu {
26
- inset: 0rem auto auto 1rem !important;
26
+ &__menu {
27
+ @apply rounded shadow-sm border border-gray-300;
28
+
29
+ position: absolute;
30
+ margin-top: 0.75rem;
31
+ }
27
32
  }
@@ -0,0 +1,48 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render } from '@testing-library/react';
3
+ import React from 'react';
4
+ import ToolbarDropdownButton from './ToolbarDropdownButton';
5
+
6
+ describe('Toolbar dropdown', () => {
7
+ const handleSelect = jest.fn();
8
+
9
+ const ToolbarDropdownButtonComponent = () => {
10
+ return (
11
+ <ToolbarDropdownButton handleOnClick={handleSelect} isDisabled={false} isActive={true} label={'Test label'}>
12
+ <h1>Test heading 1</h1>
13
+ </ToolbarDropdownButton>
14
+ );
15
+ };
16
+
17
+ const EmptyToolbarDropdownButtonComponent = () => {
18
+ return (
19
+ <ToolbarDropdownButton handleOnClick={handleSelect} isDisabled={false} isActive={false} label={'Test label'} />
20
+ );
21
+ };
22
+
23
+ it('Renders the dropdown menu button', () => {
24
+ const { baseElement } = render(<ToolbarDropdownButtonComponent />);
25
+ expect(baseElement).toBeTruthy();
26
+
27
+ const buttonElement = baseElement.querySelector('button#dropdownMenuButton') as HTMLButtonElement;
28
+ expect(buttonElement).toBeTruthy();
29
+ expect(buttonElement.textContent).toBe('Test heading 1');
30
+ });
31
+
32
+ it('Renders the dropdown menu button active icon', () => {
33
+ const { baseElement } = render(<ToolbarDropdownButtonComponent />);
34
+ expect(baseElement).toBeTruthy();
35
+
36
+ const iconElement = baseElement.querySelector('svg.dropdown-button-icon') as SVGElement;
37
+ expect(iconElement).toBeTruthy();
38
+ });
39
+
40
+ it('Should render the label as button text if no children are provided', () => {
41
+ const { baseElement } = render(<EmptyToolbarDropdownButtonComponent />);
42
+ expect(baseElement).toBeTruthy();
43
+
44
+ const buttonElement = baseElement.querySelector('button#dropdownMenuButton') as HTMLButtonElement;
45
+ expect(buttonElement).toBeTruthy();
46
+ expect(buttonElement.textContent).toBe('Test label');
47
+ });
48
+ });
@@ -13,6 +13,7 @@ const DropdownButton = ({ children, handleOnClick, isDisabled, isActive, label }
13
13
  return (
14
14
  <button
15
15
  aria-label={label}
16
+ id="dropdownMenuButton"
16
17
  title={label}
17
18
  type="button"
18
19
  onClick={handleOnClick}
@@ -1,8 +1,14 @@
1
1
  .dropdown-button {
2
+ @apply px-2 py-1 text-gray-600;
3
+
2
4
  height: 40px;
3
5
  width: 100%;
4
6
  justify-content: space-between;
5
7
  align-items: center;
6
8
  display: flex;
7
- @apply px-2 py-1 text-gray-600;
9
+
10
+ &:hover,
11
+ &:focus {
12
+ background-color: rgba(black, 0.04);
13
+ }
8
14
  }
@@ -1,4 +1,4 @@
1
- .sds-btn {
1
+ .squiz-fte-btn {
2
2
  @apply font-normal rounded ease-linear transition-all duration-150;
3
3
  display: flex;
4
4
  align-items: center;
@@ -1,4 +1,4 @@
1
- .sds {
1
+ .squiz-fte {
2
2
  &-form-group {
3
3
  @apply flex flex-col;
4
4
  }
@@ -75,11 +75,9 @@ module.exports = {
75
75
  300: '#0774d2',
76
76
  400: '#044985',
77
77
  },
78
- orange: {
79
- 100: '#dadbe9',
80
- },
81
78
  },
82
79
  },
83
80
  },
84
- plugins: [require('flowbite/plugin')],
81
+ plugins: [],
82
+ important: true,
85
83
  };