@squiz/formatted-text-editor 1.33.1-alpha.2 → 1.33.1-alpha.3
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/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +9 -14
- package/lib/EditorToolbar/Tools/Image/ImageModal.js +3 -2
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +12 -20
- package/lib/EditorToolbar/Tools/Link/LinkModal.js +3 -2
- package/lib/Extensions/LinkExtension/AssetLinkExtension.js +1 -1
- package/lib/Extensions/LinkExtension/LinkExtension.js +1 -1
- package/lib/index.css +77 -2
- package/lib/ui/Fields/Checkbox/Checkbox.d.ts +8 -0
- package/lib/ui/Fields/Checkbox/Checkbox.js +47 -0
- package/lib/ui/Modal/Modal.d.ts +1 -0
- package/lib/ui/Modal/Modal.js +3 -2
- package/lib/ui/Tabs/Tabs.d.ts +10 -0
- package/lib/ui/Tabs/Tabs.js +46 -0
- package/package.json +2 -2
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +2 -2
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +12 -24
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +11 -10
- package/src/EditorToolbar/Tools/Image/ImageModal.spec.tsx +1 -0
- package/src/EditorToolbar/Tools/Image/ImageModal.tsx +3 -2
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +10 -11
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +21 -37
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +8 -8
- package/src/EditorToolbar/Tools/Link/LinkModal.tsx +3 -2
- package/src/Extensions/LinkExtension/AssetLinkExtension.ts +1 -1
- package/src/Extensions/LinkExtension/LinkExtension.ts +1 -1
- package/src/index.scss +1 -0
- package/src/ui/Fields/Checkbox/Checkbox.spec.tsx +50 -0
- package/src/ui/Fields/Checkbox/Checkbox.tsx +49 -0
- package/src/ui/Fields/Checkbox/_checkbox.scss +26 -0
- package/src/ui/Modal/FormModal.spec.tsx +2 -1
- package/src/ui/Modal/Modal.spec.tsx +15 -7
- package/src/ui/Modal/Modal.tsx +4 -2
- package/src/ui/Tabs/Tabs.spec.tsx +44 -0
- package/src/ui/Tabs/Tabs.tsx +41 -0
- package/lib/ui/Fields/Select/Select.d.ts +0 -12
- package/lib/ui/Fields/Select/Select.js +0 -53
@@ -35,18 +35,18 @@ const LinkOff_1 = __importDefault(require("@mui/icons-material/LinkOff"));
|
|
35
35
|
const InsertLinkRounded_1 = __importDefault(require("@mui/icons-material/InsertLinkRounded"));
|
36
36
|
const clsx_1 = __importDefault(require("clsx"));
|
37
37
|
const Extensions_1 = require("../../../../Extensions/Extensions");
|
38
|
-
const Select_1 = require("../../../../ui/Fields/Select/Select");
|
39
38
|
const EditorContext_1 = require("../../../../Editor/EditorContext");
|
40
39
|
const validation_1 = require("../../../../utils/validation");
|
40
|
+
const Tabs_1 = require("../../../../ui/Tabs/Tabs");
|
41
41
|
const imageTypeOptions = {
|
42
|
-
[Extensions_1.NodeName.
|
43
|
-
[Extensions_1.NodeName.
|
42
|
+
[Extensions_1.NodeName.AssetImage]: { label: 'From source' },
|
43
|
+
[Extensions_1.NodeName.Image]: { label: 'From URL' },
|
44
44
|
};
|
45
45
|
const ImageForm = ({ data, onSubmit }) => {
|
46
46
|
const { register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
|
47
47
|
defaultValues: data,
|
48
48
|
});
|
49
|
-
const imageType = watch('imageType') || Extensions_1.NodeName.
|
49
|
+
const imageType = watch('imageType') || Extensions_1.NodeName.AssetImage;
|
50
50
|
const context = (0, react_1.useContext)(EditorContext_1.EditorContext);
|
51
51
|
const [aspectRatioFromWidth, setAspectRatioFromWidth] = (0, react_1.useState)(9 / 16);
|
52
52
|
const [aspectRatioFromHeight, setAspectRatioFromHeight] = (0, react_1.useState)(16 / 9);
|
@@ -88,8 +88,8 @@ const ImageForm = ({ data, onSubmit }) => {
|
|
88
88
|
setAspectRatioLocked(!aspectRatioLocked);
|
89
89
|
};
|
90
90
|
return (react_1.default.createElement("form", { className: "squiz-fte-form", onSubmit: handleSubmit(onSubmit) },
|
91
|
-
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-
|
92
|
-
react_1.default.createElement(
|
91
|
+
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-4" },
|
92
|
+
react_1.default.createElement(Tabs_1.Tabs, { value: imageType, options: imageTypeOptions, onChange: (value) => setValue('imageType', value) })),
|
93
93
|
imageType === Extensions_1.NodeName.Image && (react_1.default.createElement(react_1.default.Fragment, null,
|
94
94
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
95
95
|
react_1.default.createElement(Input_1.Input, { label: "Source", required: true, error: errors?.image?.src?.message, ...register('image.src', {
|
@@ -107,13 +107,6 @@ const ImageForm = ({ data, onSubmit }) => {
|
|
107
107
|
noEmptySpaces: validation_1.noEmptySpacesValidation,
|
108
108
|
},
|
109
109
|
}) })),
|
110
|
-
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
111
|
-
react_1.default.createElement(Input_1.Input, { label: "Alternative description", required: true, error: errors?.image?.alt?.message, ...register('image.alt', {
|
112
|
-
required: 'Alternative description is required',
|
113
|
-
validate: {
|
114
|
-
noEmptySpaces: validation_1.noEmptySpacesValidation,
|
115
|
-
},
|
116
|
-
}) })),
|
117
110
|
react_1.default.createElement("div", { className: "flex flex-row" },
|
118
111
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
119
112
|
react_1.default.createElement(Input_1.Input, { label: "Width", type: "number", required: true, error: errors?.image?.width?.message, ...register('image.width', {
|
@@ -140,7 +133,9 @@ const ImageForm = ({ data, onSubmit }) => {
|
|
140
133
|
}
|
141
134
|
},
|
142
135
|
},
|
143
|
-
}) })))
|
136
|
+
}) }))),
|
137
|
+
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
138
|
+
react_1.default.createElement(Input_1.Input, { label: "Alternative description", error: errors?.image?.alt?.message, ...register('image.alt') })))),
|
144
139
|
imageType === Extensions_1.NodeName.AssetImage && (react_1.default.createElement(react_1.default.Fragment, null,
|
145
140
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
146
141
|
react_1.default.createElement(Input_1.Input, { label: "Asset ID", required: true, error: errors?.assetImage?.matrixAssetId?.message, ...register('assetImage.matrixAssetId', {
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const ImageForm_1 = __importDefault(require("./Form/ImageForm"));
|
7
7
|
const react_1 = __importDefault(require("react"));
|
8
8
|
const react_2 = require("@remirror/react");
|
9
|
+
const ImageRounded_1 = __importDefault(require("@mui/icons-material/ImageRounded"));
|
9
10
|
const FormModal_1 = __importDefault(require("../../../ui/Modal/FormModal"));
|
10
11
|
const Extensions_1 = require("../../../Extensions/Extensions");
|
11
12
|
const ImageModal = ({ onCancel, onSubmit }) => {
|
@@ -13,11 +14,11 @@ const ImageModal = ({ onCancel, onSubmit }) => {
|
|
13
14
|
const currentImage = selection?.node;
|
14
15
|
const currentImageAttrs = { ...currentImage?.attrs };
|
15
16
|
const formData = {
|
16
|
-
imageType: currentImage?.type.name === Extensions_1.NodeName.
|
17
|
+
imageType: currentImage?.type.name === Extensions_1.NodeName.Image ? Extensions_1.NodeName.Image : Extensions_1.NodeName.AssetImage,
|
17
18
|
image: currentImage?.type?.name === Extensions_1.NodeName.Image ? currentImageAttrs : {},
|
18
19
|
assetImage: currentImage?.type?.name === Extensions_1.NodeName.AssetImage ? currentImageAttrs : {},
|
19
20
|
};
|
20
|
-
return (react_1.default.createElement(FormModal_1.default, { title: "Image", onCancel: onCancel },
|
21
|
+
return (react_1.default.createElement(FormModal_1.default, { title: "Image", icon: react_1.default.createElement(ImageRounded_1.default, null), onCancel: onCancel },
|
21
22
|
react_1.default.createElement(ImageForm_1.default, { data: formData, onSubmit: onSubmit })));
|
22
23
|
};
|
23
24
|
exports.default = ImageModal;
|
@@ -31,28 +31,25 @@ const react_1 = __importStar(require("react"));
|
|
31
31
|
const clsx_1 = __importDefault(require("clsx"));
|
32
32
|
const react_hook_form_1 = require("react-hook-form");
|
33
33
|
const Input_1 = require("../../../../ui/Fields/Input/Input");
|
34
|
-
const
|
34
|
+
const Checkbox_1 = require("../../../../ui/Fields/Checkbox/Checkbox");
|
35
35
|
const common_1 = require("../../../../Extensions/LinkExtension/common");
|
36
36
|
const EditorContext_1 = require("../../../../Editor/EditorContext");
|
37
37
|
const Extensions_1 = require("../../../../Extensions/Extensions");
|
38
38
|
const validation_1 = require("../../../../utils/validation");
|
39
|
+
const Tabs_1 = require("../../../../ui/Tabs/Tabs");
|
39
40
|
const linkTypeOptions = {
|
40
|
-
[Extensions_1.MarkName.
|
41
|
-
[Extensions_1.MarkName.
|
42
|
-
};
|
43
|
-
const targetOptions = {
|
44
|
-
[common_1.LinkTarget.Self]: { label: 'Current window' },
|
45
|
-
[common_1.LinkTarget.Blank]: { label: 'New window' },
|
41
|
+
[Extensions_1.MarkName.AssetLink]: { label: 'From source' },
|
42
|
+
[Extensions_1.MarkName.Link]: { label: 'From URL' },
|
46
43
|
};
|
47
44
|
const LinkForm = ({ data, onSubmit }) => {
|
48
45
|
const context = (0, react_1.useContext)(EditorContext_1.EditorContext);
|
49
46
|
const { register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
|
50
47
|
defaultValues: data,
|
51
48
|
});
|
52
|
-
const linkType = watch('linkType') || Extensions_1.MarkName.
|
49
|
+
const linkType = watch('linkType') || Extensions_1.MarkName.AssetLink;
|
53
50
|
return (react_1.default.createElement("form", { className: "squiz-fte-form", onSubmit: handleSubmit(onSubmit) },
|
54
|
-
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-
|
55
|
-
react_1.default.createElement(
|
51
|
+
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-4" },
|
52
|
+
react_1.default.createElement(Tabs_1.Tabs, { value: linkType, options: linkTypeOptions, onChange: (value) => setValue('linkType', value) })),
|
56
53
|
linkType === Extensions_1.MarkName.Link && (react_1.default.createElement(react_1.default.Fragment, null,
|
57
54
|
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
|
58
55
|
react_1.default.createElement(Input_1.Input, { label: "URL", required: true, error: errors?.link?.href?.message, ...register('link.href', {
|
@@ -69,14 +66,9 @@ const LinkForm = ({ data, onSubmit }) => {
|
|
69
66
|
},
|
70
67
|
}) })),
|
71
68
|
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
|
72
|
-
react_1.default.createElement(Input_1.Input, { label: "Title",
|
73
|
-
|
74
|
-
|
75
|
-
noEmptySpaces: validation_1.noEmptySpacesValidation,
|
76
|
-
},
|
77
|
-
}) })),
|
78
|
-
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-0') },
|
79
|
-
react_1.default.createElement(Select_1.Select, { name: "link.target", label: "Target", value: data?.link?.target || '_self', options: targetOptions, onChange: (value) => setValue('link.target', value) })))),
|
69
|
+
react_1.default.createElement(Input_1.Input, { label: "Title", error: errors?.link?.title?.message, ...register('link.title') })),
|
70
|
+
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
|
71
|
+
react_1.default.createElement(Checkbox_1.Checkbox, { label: "Open link in new window", onChange: (value) => setValue('link.target', value), defaultChecked: data?.link?.target === common_1.LinkTarget.Blank, unchecked: common_1.LinkTarget.Self, checked: common_1.LinkTarget.Blank })))),
|
80
72
|
linkType === Extensions_1.MarkName.AssetLink && (react_1.default.createElement(react_1.default.Fragment, null,
|
81
73
|
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
|
82
74
|
react_1.default.createElement(Input_1.Input, { label: "Asset ID", required: true, error: errors?.assetLink?.matrixAssetId?.message, ...register('assetLink.matrixAssetId', {
|
@@ -97,7 +89,7 @@ const LinkForm = ({ data, onSubmit }) => {
|
|
97
89
|
noEmptySpaces: validation_1.noEmptySpacesValidation,
|
98
90
|
},
|
99
91
|
}) })),
|
100
|
-
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-
|
101
|
-
react_1.default.createElement(
|
92
|
+
react_1.default.createElement("div", { className: (0, clsx_1.default)('squiz-fte-form-group mb-2') },
|
93
|
+
react_1.default.createElement(Checkbox_1.Checkbox, { label: "Open link in new window", onChange: (value) => setValue('assetLink.target', value), defaultChecked: data?.assetLink?.target === '_blank', unchecked: '_self', checked: '_blank' }))))));
|
102
94
|
};
|
103
95
|
exports.LinkForm = LinkForm;
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const LinkForm_1 = require("./Form/LinkForm");
|
7
7
|
const react_1 = __importDefault(require("react"));
|
8
8
|
const react_2 = require("@remirror/react");
|
9
|
+
const InsertLinkRounded_1 = __importDefault(require("@mui/icons-material/InsertLinkRounded"));
|
9
10
|
const FormModal_1 = __importDefault(require("../../../ui/Modal/FormModal"));
|
10
11
|
const hooks_1 = require("../../../hooks");
|
11
12
|
const Extensions_1 = require("../../../Extensions/Extensions");
|
@@ -14,13 +15,13 @@ const LinkModal = ({ onCancel, onSubmit }) => {
|
|
14
15
|
const { selection, marks } = (0, hooks_1.useExpandedSelection)([Extensions_1.MarkName.Link, Extensions_1.MarkName.AssetLink]);
|
15
16
|
const selectedText = helpers.getTextBetween(selection.from, selection.to, state.doc);
|
16
17
|
const data = {
|
17
|
-
linkType: marks[0]?.type?.name === Extensions_1.MarkName.
|
18
|
+
linkType: marks[0]?.type?.name === Extensions_1.MarkName.Link ? Extensions_1.MarkName.Link : Extensions_1.MarkName.AssetLink,
|
18
19
|
text: selectedText,
|
19
20
|
link: { ...marks.find((mark) => mark.type.name === 'link')?.attrs },
|
20
21
|
assetLink: { ...marks.find((mark) => mark.type.name === Extensions_1.MarkName.AssetLink)?.attrs },
|
21
22
|
range: { from: selection.from, to: selection.to },
|
22
23
|
};
|
23
|
-
return (react_1.default.createElement(FormModal_1.default, { title: "Link", onCancel: onCancel },
|
24
|
+
return (react_1.default.createElement(FormModal_1.default, { title: "Link", icon: react_1.default.createElement(InsertLinkRounded_1.default, null), onCancel: onCancel },
|
24
25
|
react_1.default.createElement(LinkForm_1.LinkForm, { data: data, onSubmit: onSubmit })));
|
25
26
|
};
|
26
27
|
exports.default = LinkModal;
|
@@ -20,7 +20,7 @@ let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
|
|
20
20
|
createMarkSpec(extra, override) {
|
21
21
|
return {
|
22
22
|
inclusive: false,
|
23
|
-
excludes: Extensions_1.MarkName.Link,
|
23
|
+
excludes: [this.name, Extensions_1.MarkName.Link].join(' '),
|
24
24
|
...override,
|
25
25
|
attrs: {
|
26
26
|
...extra.defaults(),
|
@@ -19,7 +19,7 @@ let LinkExtension = class LinkExtension extends core_1.MarkExtension {
|
|
19
19
|
createMarkSpec(extra, override) {
|
20
20
|
return {
|
21
21
|
inclusive: false,
|
22
|
-
excludes: Extensions_1.MarkName.AssetLink,
|
22
|
+
excludes: [this.name, Extensions_1.MarkName.AssetLink].join(' '),
|
23
23
|
...override,
|
24
24
|
attrs: {
|
25
25
|
...extra.defaults(),
|
package/lib/index.css
CHANGED
@@ -404,18 +404,33 @@
|
|
404
404
|
.squiz-fte-scope .mb-2 {
|
405
405
|
margin-bottom: 0.5rem !important;
|
406
406
|
}
|
407
|
+
.squiz-fte-scope .mb-4 {
|
408
|
+
margin-bottom: 1rem !important;
|
409
|
+
}
|
407
410
|
.squiz-fte-scope .ml-3 {
|
408
411
|
margin-left: 0.75rem !important;
|
409
412
|
}
|
410
413
|
.squiz-fte-scope .ml-auto {
|
411
414
|
margin-left: auto !important;
|
412
415
|
}
|
416
|
+
.squiz-fte-scope .mr-1 {
|
417
|
+
margin-right: 0.25rem !important;
|
418
|
+
}
|
419
|
+
.squiz-fte-scope .mr-1\.5 {
|
420
|
+
margin-right: 0.375rem !important;
|
421
|
+
}
|
413
422
|
.squiz-fte-scope .mr-2 {
|
414
423
|
margin-right: 0.5rem !important;
|
415
424
|
}
|
416
425
|
.squiz-fte-scope .mt-1 {
|
417
426
|
margin-top: 0.25rem !important;
|
418
427
|
}
|
428
|
+
.squiz-fte-scope .mt-\[-1px\] {
|
429
|
+
margin-top: -1px !important;
|
430
|
+
}
|
431
|
+
.squiz-fte-scope .mt-\[7px\] {
|
432
|
+
margin-top: 7px !important;
|
433
|
+
}
|
419
434
|
.squiz-fte-scope .block {
|
420
435
|
display: block !important;
|
421
436
|
}
|
@@ -425,9 +440,21 @@
|
|
425
440
|
.squiz-fte-scope .flex {
|
426
441
|
display: flex !important;
|
427
442
|
}
|
443
|
+
.squiz-fte-scope .grid {
|
444
|
+
display: grid !important;
|
445
|
+
}
|
428
446
|
.squiz-fte-scope .hidden {
|
429
447
|
display: none !important;
|
430
448
|
}
|
449
|
+
.squiz-fte-scope .h-10 {
|
450
|
+
height: 2.5rem !important;
|
451
|
+
}
|
452
|
+
.squiz-fte-scope .h-\[3px\] {
|
453
|
+
height: 3px !important;
|
454
|
+
}
|
455
|
+
.squiz-fte-scope .w-11\/12 {
|
456
|
+
width: 91.666667% !important;
|
457
|
+
}
|
431
458
|
.squiz-fte-scope .w-169 {
|
432
459
|
width: 169px !important;
|
433
460
|
}
|
@@ -445,17 +472,29 @@
|
|
445
472
|
-moz-user-select: none !important;
|
446
473
|
user-select: none !important;
|
447
474
|
}
|
475
|
+
.squiz-fte-scope .grid-flow-col {
|
476
|
+
grid-auto-flow: column !important;
|
477
|
+
}
|
448
478
|
.squiz-fte-scope .flex-row {
|
449
479
|
flex-direction: row !important;
|
450
480
|
}
|
481
|
+
.squiz-fte-scope .flex-col {
|
482
|
+
flex-direction: column !important;
|
483
|
+
}
|
451
484
|
.squiz-fte-scope .items-center {
|
452
485
|
align-items: center !important;
|
453
486
|
}
|
487
|
+
.squiz-fte-scope .justify-between {
|
488
|
+
justify-content: space-between !important;
|
489
|
+
}
|
454
490
|
.squiz-fte-scope .divide-y > :not([hidden]) ~ :not([hidden]) {
|
455
491
|
--tw-divide-y-reverse: 0 !important;
|
456
492
|
border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))) !important;
|
457
493
|
border-bottom-width: calc(1px * var(--tw-divide-y-reverse)) !important;
|
458
494
|
}
|
495
|
+
.squiz-fte-scope .self-center {
|
496
|
+
align-self: center !important;
|
497
|
+
}
|
459
498
|
.squiz-fte-scope .overflow-auto {
|
460
499
|
overflow: auto !important;
|
461
500
|
}
|
@@ -467,12 +506,19 @@
|
|
467
506
|
.squiz-fte-scope .rounded {
|
468
507
|
border-radius: 4px !important;
|
469
508
|
}
|
509
|
+
.squiz-fte-scope .rounded-t-sm {
|
510
|
+
border-top-left-radius: 0.125rem !important;
|
511
|
+
border-top-right-radius: 0.125rem !important;
|
512
|
+
}
|
470
513
|
.squiz-fte-scope .border-0 {
|
471
514
|
border-width: 0px !important;
|
472
515
|
}
|
473
516
|
.squiz-fte-scope .border-2 {
|
474
517
|
border-width: 2px !important;
|
475
518
|
}
|
519
|
+
.squiz-fte-scope .border-b {
|
520
|
+
border-bottom-width: 1px !important;
|
521
|
+
}
|
476
522
|
.squiz-fte-scope .border-gray-300 {
|
477
523
|
--tw-border-opacity: 1 !important;
|
478
524
|
border-color: rgb(224 224 224 / var(--tw-border-opacity)) !important;
|
@@ -493,6 +539,10 @@
|
|
493
539
|
--tw-bg-opacity: 1 !important;
|
494
540
|
background-color: rgb(237 237 237 / var(--tw-bg-opacity)) !important;
|
495
541
|
}
|
542
|
+
.squiz-fte-scope .bg-gray-800 {
|
543
|
+
--tw-bg-opacity: 1 !important;
|
544
|
+
background-color: rgb(61 61 61 / var(--tw-bg-opacity)) !important;
|
545
|
+
}
|
496
546
|
.squiz-fte-scope .bg-transparent {
|
497
547
|
background-color: transparent !important;
|
498
548
|
}
|
@@ -511,8 +561,8 @@
|
|
511
561
|
padding-top: 0.5rem !important;
|
512
562
|
padding-bottom: 0.5rem !important;
|
513
563
|
}
|
514
|
-
.squiz-fte-scope .pb-
|
515
|
-
padding-bottom:
|
564
|
+
.squiz-fte-scope .pb-4 {
|
565
|
+
padding-bottom: 1rem !important;
|
516
566
|
}
|
517
567
|
.squiz-fte-scope .pl-3 {
|
518
568
|
padding-left: 0.75rem !important;
|
@@ -533,6 +583,9 @@
|
|
533
583
|
.squiz-fte-scope .text-md {
|
534
584
|
font-size: 0.875rem !important;
|
535
585
|
}
|
586
|
+
.squiz-fte-scope .font-bold {
|
587
|
+
font-weight: 700 !important;
|
588
|
+
}
|
536
589
|
.squiz-fte-scope .font-semibold {
|
537
590
|
font-weight: 600 !important;
|
538
591
|
}
|
@@ -901,6 +954,28 @@
|
|
901
954
|
.squiz-fte-scope .dropdown-button:focus {
|
902
955
|
background-color: rgba(0, 0, 0, 0.04);
|
903
956
|
}
|
957
|
+
.squiz-fte-scope .squiz-fte-checkbox {
|
958
|
+
--tw-text-opacity: 1;
|
959
|
+
color: rgb(61 61 61 / var(--tw-text-opacity));
|
960
|
+
font-size: 14px;
|
961
|
+
display: flex;
|
962
|
+
align-items: center;
|
963
|
+
margin-top: 0.75rem;
|
964
|
+
gap: 0.75rem;
|
965
|
+
}
|
966
|
+
.squiz-fte-scope .squiz-fte-checkbox .checkbox {
|
967
|
+
display: flex;
|
968
|
+
justify-content: center;
|
969
|
+
align-items: center;
|
970
|
+
width: 1.25rem;
|
971
|
+
height: 1.25rem;
|
972
|
+
background-color: #fff;
|
973
|
+
border: 2px solid #e0e0e0;
|
974
|
+
border-radius: 4px;
|
975
|
+
}
|
976
|
+
.squiz-fte-scope .squiz-fte-checkbox .checkbox svg {
|
977
|
+
width: 100%;
|
978
|
+
}
|
904
979
|
.squiz-fte-scope .squiz-fte-modal {
|
905
980
|
display: flex;
|
906
981
|
width: 100%;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export type CheckboxProps<TChecked, TUnchecked> = {
|
2
|
+
label: string;
|
3
|
+
onChange: (value: TChecked | TUnchecked) => void;
|
4
|
+
defaultChecked?: boolean;
|
5
|
+
unchecked: TUnchecked;
|
6
|
+
checked: TChecked;
|
7
|
+
};
|
8
|
+
export declare const Checkbox: <TChecked, TUnchecked>({ label, onChange, defaultChecked, unchecked, checked, }: CheckboxProps<TChecked, TUnchecked>) => JSX.Element;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
exports.Checkbox = void 0;
|
30
|
+
const react_1 = __importStar(require("react"));
|
31
|
+
const CheckRounded_1 = __importDefault(require("@mui/icons-material/CheckRounded"));
|
32
|
+
const Checkbox = ({ label, onChange, defaultChecked = false, unchecked, checked, }) => {
|
33
|
+
const [toggled, setToggled] = (0, react_1.useState)(defaultChecked);
|
34
|
+
(0, react_1.useEffect)(() => {
|
35
|
+
if (toggled) {
|
36
|
+
onChange(checked);
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
onChange(unchecked);
|
40
|
+
}
|
41
|
+
}, [toggled]);
|
42
|
+
const toggleCheckbox = () => setToggled(!toggled);
|
43
|
+
return (react_1.default.createElement("div", { className: "squiz-fte-checkbox" },
|
44
|
+
react_1.default.createElement("button", { type: "button", role: "checkbox", "aria-label": label, "aria-checked": toggled, className: "checkbox", onClick: toggleCheckbox }, toggled && react_1.default.createElement(CheckRounded_1.default, null)),
|
45
|
+
react_1.default.createElement("button", { type: "button", className: "label", onClick: toggleCheckbox }, label)));
|
46
|
+
};
|
47
|
+
exports.Checkbox = Checkbox;
|
package/lib/ui/Modal/Modal.d.ts
CHANGED
package/lib/ui/Modal/Modal.js
CHANGED
@@ -31,7 +31,7 @@ const react_dom_1 = require("react-dom");
|
|
31
31
|
const CloseRounded_1 = __importDefault(require("@mui/icons-material/CloseRounded"));
|
32
32
|
const base_1 = require("@mui/base");
|
33
33
|
const clsx_1 = __importDefault(require("clsx"));
|
34
|
-
const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
|
34
|
+
const Modal = ({ children, title, icon, onCancel, onSubmit, className }, ref) => {
|
35
35
|
const content = (0, react_1.useRef)(null);
|
36
36
|
const container = (0, react_1.useMemo)(() => {
|
37
37
|
const element = document.createElement('div');
|
@@ -65,7 +65,8 @@ const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
|
|
65
65
|
react_1.default.createElement("div", { ref: ref, className: (0, clsx_1.default)('squiz-fte-modal-wrapper', className), tabIndex: -1 },
|
66
66
|
react_1.default.createElement("div", { className: "w-modal-sm my-6 mx-auto" },
|
67
67
|
react_1.default.createElement("div", { className: "squiz-fte-modal" },
|
68
|
-
react_1.default.createElement("div", { className: "squiz-fte-modal-header p-6 pb-
|
68
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal-header p-6 pb-4" },
|
69
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal-header-icon mr-1.5 mt-[-1px]" }, icon),
|
69
70
|
react_1.default.createElement("h2", { className: "font-semibold text-gray-900 text-heading-2" }, title),
|
70
71
|
react_1.default.createElement("button", { type: "button", 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", onClick: onCancel, "aria-label": "Close" },
|
71
72
|
react_1.default.createElement(CloseRounded_1.default, null))),
|
@@ -0,0 +1,10 @@
|
|
1
|
+
export type TabOptions = Record<string, TabOption>;
|
2
|
+
export type TabOption = {
|
3
|
+
label: string;
|
4
|
+
};
|
5
|
+
export type TabsProps = {
|
6
|
+
value: string;
|
7
|
+
options: TabOptions;
|
8
|
+
onChange?: (value: string) => void;
|
9
|
+
};
|
10
|
+
export declare const Tabs: ({ value, options, onChange }: TabsProps) => JSX.Element;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
exports.Tabs = void 0;
|
30
|
+
const react_1 = require("@headlessui/react");
|
31
|
+
const react_2 = __importStar(require("react"));
|
32
|
+
const clsx_1 = __importDefault(require("clsx"));
|
33
|
+
const Tabs = ({ value, options, onChange }) => (react_2.default.createElement(react_1.Tab.Group
|
34
|
+
// Check what index the selected tab is, otherwise default to first tab
|
35
|
+
, {
|
36
|
+
// Check what index the selected tab is, otherwise default to first tab
|
37
|
+
defaultIndex: Object.keys(options).indexOf(value) || 0,
|
38
|
+
// Check what the selected tab key is and trigger onChange
|
39
|
+
onChange: (index) => {
|
40
|
+
const selectedTab = Object.keys(options)[index];
|
41
|
+
onChange?.(selectedTab);
|
42
|
+
} },
|
43
|
+
react_2.default.createElement(react_1.Tab.List, { className: "grid grid-flow-col h-10 border-b border-gray-300" }, Object.entries(options).map(([key, option]) => (react_2.default.createElement(react_1.Tab, { key: key, as: react_2.Fragment }, ({ selected }) => (react_2.default.createElement("div", { className: "flex flex-col justify-between", "data-testid": key, "aria-selected": selected },
|
44
|
+
react_2.default.createElement("button", { type: "button", className: (0, clsx_1.default)('mt-[7px] text-gray-800', selected && 'font-bold') }, option.label),
|
45
|
+
selected && react_2.default.createElement("span", { className: "h-[3px] bg-gray-800 w-11/12 self-center rounded-t-sm" })))))))));
|
46
|
+
exports.Tabs = Tabs;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "1.33.1-alpha.
|
3
|
+
"version": "1.33.1-alpha.3",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"scripts": {
|
@@ -74,5 +74,5 @@
|
|
74
74
|
"volta": {
|
75
75
|
"node": "18.15.0"
|
76
76
|
},
|
77
|
-
"gitHead": "
|
77
|
+
"gitHead": "5189e21fcd9ad091397cacfa50765caf6138b034"
|
78
78
|
}
|
@@ -19,7 +19,7 @@ describe('Image Form', () => {
|
|
19
19
|
it('Renders the form with the relevant fields for arbitrary images', () => {
|
20
20
|
render(<ImageForm data={data} onSubmit={handleSubmit} />);
|
21
21
|
|
22
|
-
expect(
|
22
|
+
expect(document.querySelector('div[data-headlessui-state="selected"]')).toHaveTextContent('From URL');
|
23
23
|
expect(screen.getByLabelText('Source')).toHaveValue('https://httpcats.com/302.jpg');
|
24
24
|
expect(screen.getByLabelText('Alternative description')).toHaveValue('Cat with mouse in mouth');
|
25
25
|
expect(screen.getByLabelText('Width')).toHaveValue(1600);
|
@@ -38,7 +38,7 @@ describe('Image Form', () => {
|
|
38
38
|
/>,
|
39
39
|
);
|
40
40
|
|
41
|
-
expect(
|
41
|
+
expect(document.querySelector('div[data-headlessui-state="selected"]')).toHaveTextContent('From source');
|
42
42
|
expect(screen.getByLabelText('Asset ID')).toHaveValue('100');
|
43
43
|
});
|
44
44
|
|
@@ -10,9 +10,9 @@ import clsx from 'clsx';
|
|
10
10
|
import { NodeName } from '../../../../Extensions/Extensions';
|
11
11
|
import { AssetImageAttributes } from '../../../../Extensions/ImageExtension/AssetImageExtension';
|
12
12
|
import { DeepPartial } from '../../../../types';
|
13
|
-
import { Select, SelectOptions } from '../../../../ui/Fields/Select/Select';
|
14
13
|
import { EditorContext } from '../../../../Editor/EditorContext';
|
15
14
|
import { noEmptySpacesValidation, regexDataURI } from '../../../../utils/validation';
|
15
|
+
import { TabOptions, Tabs } from '../../../../ui/Tabs/Tabs';
|
16
16
|
|
17
17
|
export type ImageFormData = {
|
18
18
|
imageType: NodeName;
|
@@ -20,9 +20,9 @@ export type ImageFormData = {
|
|
20
20
|
assetImage: AssetImageAttributes;
|
21
21
|
};
|
22
22
|
|
23
|
-
const imageTypeOptions:
|
24
|
-
[NodeName.
|
25
|
-
[NodeName.
|
23
|
+
const imageTypeOptions: TabOptions = {
|
24
|
+
[NodeName.AssetImage]: { label: 'From source' },
|
25
|
+
[NodeName.Image]: { label: 'From URL' },
|
26
26
|
};
|
27
27
|
|
28
28
|
export type FormProps = {
|
@@ -41,7 +41,7 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
41
41
|
} = useForm<ImageFormData>({
|
42
42
|
defaultValues: data,
|
43
43
|
});
|
44
|
-
const imageType = watch('imageType') || NodeName.
|
44
|
+
const imageType = watch('imageType') || NodeName.AssetImage;
|
45
45
|
const context = useContext(EditorContext);
|
46
46
|
const [aspectRatioFromWidth, setAspectRatioFromWidth] = useState(9 / 16);
|
47
47
|
const [aspectRatioFromHeight, setAspectRatioFromHeight] = useState(16 / 9);
|
@@ -88,10 +88,8 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
88
88
|
|
89
89
|
return (
|
90
90
|
<form className="squiz-fte-form" onSubmit={handleSubmit(onSubmit)}>
|
91
|
-
<div className="squiz-fte-form-group mb-
|
92
|
-
<
|
93
|
-
name="imageType"
|
94
|
-
label="Type"
|
91
|
+
<div className="squiz-fte-form-group mb-4">
|
92
|
+
<Tabs
|
95
93
|
value={imageType}
|
96
94
|
options={imageTypeOptions}
|
97
95
|
onChange={(value) => setValue('imageType', value as NodeName)}
|
@@ -121,19 +119,6 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
121
119
|
})}
|
122
120
|
/>
|
123
121
|
</div>
|
124
|
-
<div className="squiz-fte-form-group mb-2">
|
125
|
-
<Input
|
126
|
-
label="Alternative description"
|
127
|
-
required
|
128
|
-
error={errors?.image?.alt?.message}
|
129
|
-
{...register('image.alt', {
|
130
|
-
required: 'Alternative description is required',
|
131
|
-
validate: {
|
132
|
-
noEmptySpaces: noEmptySpacesValidation,
|
133
|
-
},
|
134
|
-
})}
|
135
|
-
/>
|
136
|
-
</div>
|
137
122
|
<div className="flex flex-row">
|
138
123
|
<div className="squiz-fte-form-group mb-2">
|
139
124
|
<Input
|
@@ -146,7 +131,7 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
146
131
|
required: 'Width is required',
|
147
132
|
validate: {
|
148
133
|
isValidWidth: (value) => {
|
149
|
-
if (value && !(value > 0)) {
|
134
|
+
if (value && !((value as number) > 0)) {
|
150
135
|
return 'Must be higher than 0';
|
151
136
|
}
|
152
137
|
},
|
@@ -175,7 +160,7 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
175
160
|
required: 'Height is required',
|
176
161
|
validate: {
|
177
162
|
isValidHeight: (value) => {
|
178
|
-
if (value && !(value > 0)) {
|
163
|
+
if (value && !((value as number) > 0)) {
|
179
164
|
return 'Must be higher than 0';
|
180
165
|
}
|
181
166
|
},
|
@@ -184,6 +169,9 @@ const ImageForm = ({ data, onSubmit }: FormProps): ReactElement => {
|
|
184
169
|
/>
|
185
170
|
</div>
|
186
171
|
</div>
|
172
|
+
<div className="squiz-fte-form-group mb-2">
|
173
|
+
<Input label="Alternative description" error={errors?.image?.alt?.message} {...register('image.alt')} />
|
174
|
+
</div>
|
187
175
|
</>
|
188
176
|
)}
|
189
177
|
{imageType === NodeName.AssetImage && (
|