Skip to content

Commit 04cca77

Browse files
committed
Lexical: Added color picker/indicator to form fields
1 parent c091f67 commit 04cca77

File tree

10 files changed

+125
-36
lines changed

10 files changed

+125
-36
lines changed
Lines changed: 10 additions & 0 deletions
Loading

resources/js/wysiwyg/todo.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@
1010

1111
## Secondary Todo
1212

13-
- Color picker support in table form color fields
14-
- Color picker for color controls
1513
- Table caption text support
1614
- Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
1715
- Deep check of translation coverage
18-
- About button & view
19-
- Mobile display and handling
2016

2117
## Bugs
2218

resources/js/wysiwyg/ui/defaults/buttons/inline-formats.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import subscriptIcon from "@icons/editor/subscript.svg";
1212
import codeIcon from "@icons/editor/code.svg";
1313
import formatClearIcon from "@icons/editor/format-clear.svg";
1414
import {$selectionContainsTextFormat} from "../../../utils/selection";
15+
import {$patchStyleText} from "@lexical/selection";
16+
import {context} from "esbuild";
1517

1618
function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition {
1719
return {
@@ -32,6 +34,18 @@ export const underline: EditorButtonDefinition = buildFormatButton('Underline',
3234
export const textColor: EditorBasicButtonDefinition = {label: 'Text color', icon: textColorIcon};
3335
export const highlightColor: EditorBasicButtonDefinition = {label: 'Background color', icon: highlightIcon};
3436

37+
function colorAction(context: EditorUiContext, property: string, color: string): void {
38+
context.editor.update(() => {
39+
const selection = $getSelection();
40+
if (selection) {
41+
$patchStyleText(selection, {[property]: color || null});
42+
}
43+
});
44+
}
45+
46+
export const textColorAction = (color: string, context: EditorUiContext) => colorAction(context, 'color', color);
47+
export const highlightColorAction = (color: string, context: EditorUiContext) => colorAction(context, 'color', color);
48+
3549
export const strikethrough: EditorButtonDefinition = buildFormatButton('Strikethrough', 'strikethrough', strikethroughIcon);
3650
export const superscript: EditorButtonDefinition = buildFormatButton('Superscript', 'superscript', superscriptIcon);
3751
export const subscript: EditorButtonDefinition = buildFormatButton('Subscript', 'subscript', subscriptIcon);

resources/js/wysiwyg/ui/defaults/forms/tables.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
EditorFormDefinition,
3-
EditorFormFieldDefinition,
3+
EditorFormFieldDefinition, EditorFormFields,
44
EditorFormTabs,
55
EditorSelectFormFieldDefinition
66
} from "../../framework/forms";
@@ -17,6 +17,7 @@ import {
1717
import {formatSizeValue} from "../../../utils/dom";
1818
import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
1919
import {CommonBlockAlignment} from "lexical/nodes/common";
20+
import {colorFieldBuilder} from "../../framework/blocks/color-field";
2021

2122
const borderStyleInput: EditorSelectFormFieldDefinition = {
2223
label: 'Border style',
@@ -145,15 +146,15 @@ export const cellProperties: EditorFormDefinition = {
145146
} as EditorSelectFormFieldDefinition,
146147
];
147148

148-
const advancedFields: EditorFormFieldDefinition[] = [
149+
const advancedFields: EditorFormFields = [
149150
{
150151
label: 'Border width', // inline-style: border-width
151152
name: 'border_width',
152153
type: 'text',
153154
},
154155
borderStyleInput, // inline-style: border-style
155-
borderColorInput, // inline-style: border-color
156-
backgroundColorInput, // inline-style: background-color
156+
colorFieldBuilder(borderColorInput),
157+
colorFieldBuilder(backgroundColorInput),
157158
];
158159

159160
return new EditorFormTabs([
@@ -210,8 +211,8 @@ export const rowProperties: EditorFormDefinition = {
210211
type: 'text',
211212
},
212213
borderStyleInput, // style on tr: height
213-
borderColorInput, // style on tr: height
214-
backgroundColorInput, // style on tr: height
214+
colorFieldBuilder(borderColorInput),
215+
colorFieldBuilder(backgroundColorInput),
215216
],
216217
};
217218

@@ -305,10 +306,10 @@ export const tableProperties: EditorFormDefinition = {
305306
alignmentInput, // alignment class
306307
];
307308

308-
const advancedFields: EditorFormFieldDefinition[] = [
309-
borderStyleInput, // Style - border-style
310-
borderColorInput, // Style - border-color
311-
backgroundColorInput, // Style - background-color
309+
const advancedFields: EditorFormFields = [
310+
borderStyleInput,
311+
colorFieldBuilder(borderColorInput),
312+
colorFieldBuilder(backgroundColorInput),
312313
];
313314

314315
return new EditorFormTabs([

resources/js/wysiwyg/ui/defaults/toolbars.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ import {
4444
} from "./buttons/block-formats";
4545
import {
4646
bold, clearFormating, code,
47-
highlightColor,
47+
highlightColor, highlightColorAction,
4848
italic,
4949
strikethrough, subscript,
5050
superscript,
51-
textColor,
51+
textColor, textColorAction,
5252
underline
5353
} from "./buttons/inline-formats";
5454
import {
@@ -114,10 +114,10 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
114114
new EditorButton(italic),
115115
new EditorButton(underline),
116116
new EditorDropdownButton({ button: new EditorColorButton(textColor, 'color') }, [
117-
new EditorColorPicker('color'),
117+
new EditorColorPicker(textColorAction),
118118
]),
119119
new EditorDropdownButton({button: new EditorColorButton(highlightColor, 'background-color')}, [
120-
new EditorColorPicker('background-color'),
120+
new EditorColorPicker(highlightColorAction),
121121
]),
122122
new EditorButton(strikethrough),
123123
new EditorButton(superscript),
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {EditorContainerUiElement, EditorUiBuilderDefinition, EditorUiContext} from "../core";
2+
import {EditorFormField, EditorFormFieldDefinition} from "../forms";
3+
import {EditorColorPicker} from "./color-picker";
4+
import {EditorDropdownButton} from "./dropdown-button";
5+
6+
import colorDisplayIcon from "@icons/editor/color-display.svg"
7+
8+
export class EditorColorField extends EditorContainerUiElement {
9+
protected input: EditorFormField;
10+
protected pickerButton: EditorDropdownButton;
11+
12+
constructor(input: EditorFormField) {
13+
super([]);
14+
15+
this.input = input;
16+
17+
this.pickerButton = new EditorDropdownButton({
18+
button: { icon: colorDisplayIcon, label: 'Select color'}
19+
}, [
20+
new EditorColorPicker(this.onColorSelect.bind(this))
21+
]);
22+
this.addChildren(this.pickerButton, this.input);
23+
}
24+
25+
protected buildDOM(): HTMLElement {
26+
const dom = this.input.getDOMElement();
27+
dom.append(this.pickerButton.getDOMElement());
28+
dom.classList.add('editor-color-field-container');
29+
30+
const field = dom.querySelector('input') as HTMLInputElement;
31+
field.addEventListener('change', () => {
32+
this.setIconColor(field.value);
33+
});
34+
35+
return dom;
36+
}
37+
38+
onColorSelect(color: string, context: EditorUiContext): void {
39+
this.input.setValue(color);
40+
}
41+
42+
setIconColor(color: string) {
43+
const icon = this.getDOMElement().querySelector('svg .editor-icon-color-display');
44+
if (icon) {
45+
icon.setAttribute('fill', color || 'url(#pattern2)');
46+
}
47+
}
48+
}
49+
50+
export function colorFieldBuilder(field: EditorFormFieldDefinition): EditorUiBuilderDefinition {
51+
return {
52+
build() {
53+
return new EditorColorField(new EditorFormField(field));
54+
}
55+
}
56+
}

resources/js/wysiwyg/ui/framework/blocks/color-picker.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import {EditorUiElement} from "../core";
2-
import {$getSelection} from "lexical";
3-
import {$patchStyleText} from "@lexical/selection";
1+
import {EditorUiContext, EditorUiElement} from "../core";
42
import {el} from "../../../utils/dom";
53

64
import removeIcon from "@icons/editor/color-clear.svg";
@@ -38,13 +36,15 @@ const colorChoices = [
3836

3937
const storageKey = 'bs-lexical-custom-colors';
4038

39+
export type EditorColorPickerCallback = (color: string, context: EditorUiContext) => void;
40+
4141
export class EditorColorPicker extends EditorUiElement {
4242

43-
protected styleProperty: string;
43+
protected callback: EditorColorPickerCallback;
4444

45-
constructor(styleProperty: string) {
45+
constructor(callback: EditorColorPickerCallback) {
4646
super();
47-
this.styleProperty = styleProperty;
47+
this.callback = callback;
4848
}
4949

5050
buildDOM(): HTMLElement {
@@ -131,11 +131,6 @@ export class EditorColorPicker extends EditorUiElement {
131131
}
132132

133133
setColor(color: string) {
134-
this.getContext().editor.update(() => {
135-
const selection = $getSelection();
136-
if (selection) {
137-
$patchStyleText(selection, {[this.styleProperty]: color || null});
138-
}
139-
});
134+
this.callback(color, this.getContext());
140135
}
141136
}

resources/js/wysiwyg/ui/framework/blocks/link-field.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export class LinkField extends EditorContainerUiElement {
4444

4545
updateFormFromHeader(header: HeadingNode) {
4646
this.getHeaderIdAndText(header).then(({id, text}) => {
47-
console.log('updating form', id, text);
4847
const modal = this.getContext().manager.getActiveModal('link');
4948
if (modal) {
5049
modal.getForm().setValues({
@@ -60,7 +59,6 @@ export class LinkField extends EditorContainerUiElement {
6059
return new Promise((res) => {
6160
this.getContext().editor.update(() => {
6261
let id = header.getId();
63-
console.log('header', id, header.__id);
6462
if (!id) {
6563
id = 'header-' + uniqueIdSmall();
6664
header.setId(id);

resources/js/wysiwyg/ui/framework/forms.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefiniti
1919
valuesByLabel: Record<string, string>
2020
}
2121

22+
export type EditorFormFields = (EditorFormFieldDefinition|EditorUiBuilderDefinition)[];
23+
2224
interface EditorFormTabDefinition {
2325
label: string;
24-
contents: EditorFormFieldDefinition[];
26+
contents: EditorFormFields;
2527
}
2628

2729
export interface EditorFormDefinition {
2830
submitText: string;
2931
action: (formData: FormData, context: EditorUiContext) => Promise<boolean>;
30-
fields: (EditorFormFieldDefinition|EditorUiBuilderDefinition)[];
32+
fields: EditorFormFields;
3133
}
3234

3335
export class EditorFormField extends EditorUiElement {
@@ -41,6 +43,7 @@ export class EditorFormField extends EditorUiElement {
4143
setValue(value: string) {
4244
const input = this.getDOMElement().querySelector('input,select,textarea') as HTMLInputElement;
4345
input.value = value;
46+
input.dispatchEvent(new Event('change'));
4447
}
4548

4649
getName(): string {
@@ -155,11 +158,17 @@ export class EditorForm extends EditorContainerUiElement {
155158
export class EditorFormTab extends EditorContainerUiElement {
156159

157160
protected definition: EditorFormTabDefinition;
158-
protected fields: EditorFormField[];
161+
protected fields: EditorUiElement[];
159162
protected id: string;
160163

161164
constructor(definition: EditorFormTabDefinition) {
162-
const fields = definition.contents.map(fieldDef => new EditorFormField(fieldDef));
165+
const fields = definition.contents.map(fieldDef => {
166+
if (isUiBuilderDefinition(fieldDef)) {
167+
return fieldDef.build();
168+
}
169+
return new EditorFormField(fieldDef)
170+
});
171+
163172
super(fields);
164173

165174
this.definition = definition;

resources/sass/_editor.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,16 @@ textarea.editor-form-field-input {
649649
width: $inputWidth - 40px;
650650
}
651651
}
652+
.editor-color-field-container {
653+
position: relative;
654+
input {
655+
padding-left: 36px;
656+
}
657+
.editor-dropdown-menu-container {
658+
position: absolute;
659+
bottom: 0;
660+
}
661+
}
652662

653663
// Editor theme styles
654664
.editor-theme-bold {

0 commit comments

Comments
 (0)