Skip to content

Commit 419a0c8

Browse files
committed
fix: Sync issues for Color/Highlight
1. Fixed issue where Highlight applied red fill when no color was selected or after clearing the color via shortcuts. 2. Fixed issue where switching Highlight color but applying via shortcut still used red fill. 3. Fixed desync between Color/Highlight toolbar and bubble menu color states. 4. Added shortcut Shift+Alt+C for Color. 5. Updated user documentation for Color/Highlight.
1 parent ce8bc39 commit 419a0c8

File tree

6 files changed

+473
-62
lines changed

6 files changed

+473
-62
lines changed

docs/extensions/Color/index.md

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ next:
88

99
# Color
1010

11-
The Color extension allows you to add color to your editor.
11+
The Color extension allows you to add text color to your editor with support for custom colors, keyboard shortcuts, and synchronized color selection across toolbar and bubble menu.
1212

1313
- Based on TipTap's Color extension. [@tiptap/extension-color](https://tiptap.dev/docs/editor/extensions/functionality/color)
1414

@@ -20,10 +20,24 @@ import { Color } from 'reactjs-tiptap-editor/color'; // [!code ++]
2020
const extensions = [
2121
...,
2222
// Import Extensions Here
23-
Color // [!code ++]
23+
Color, // [!code ++]
24+
// or with configuration
25+
Color.configure({ // [!code ++]
26+
colors: COLORS_LIST, // [!code ++]
27+
defaultColor: '#000000', // [!code ++]
28+
}), // [!code ++]
2429
];
2530
```
2631

32+
## Features
33+
34+
- 🎨 **Rich Color Palette**: Choose from a wide range of predefined colors
35+
- ⌨️ **Keyboard Shortcuts**: Quick color application with `Mod-Shift-C`
36+
- 🔄 **Smart Toggle**: Intelligent color toggling and replacement
37+
- 🎯 **Synchronized Selection**: Color picker syncs between toolbar and bubble menu
38+
- 🎨 **Custom Colors**: Add custom colors via color picker
39+
- 💾 **Recent Colors**: Automatically tracks recently used colors
40+
2741
## Options
2842

2943
### colors
@@ -35,20 +49,103 @@ An array of color options to display in the color picker. If not provided, a def
3549

3650
```js
3751
import { COLORS_LIST } from 'reactjs-tiptap-editor'
52+
53+
Color.configure({
54+
colors: COLORS_LIST,
55+
// or custom colors
56+
colors: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'],
57+
})
3858
```
3959

4060
### defaultColor
4161

4262
Type: `string`\
4363
Default: `undefined`
4464

65+
The default color to use when the extension is initialized. This color will be used when applying color via keyboard shortcut for the first time.
66+
4567
```js
4668
import { DEFAULT_COLOR } from 'reactjs-tiptap-editor'
69+
70+
Color.configure({
71+
defaultColor: DEFAULT_COLOR,
72+
// or
73+
defaultColor: '#000000',
74+
})
4775
```
4876

49-
### initialDisplayedColor
77+
### shortcutKeys
5078

51-
Type: `string`\
52-
Default: `undefined`
79+
Type: `string[]`\
80+
Default: `['⇧', 'mod', 'C']`
81+
82+
Keyboard shortcuts for applying the color. Default is `Mod-Shift-C` (Ctrl-Shift-C on Windows/Linux, Cmd-Shift-C on Mac).
83+
84+
```js
85+
Color.configure({
86+
shortcutKeys: ['', 'mod', 'C'],
87+
})
88+
```
89+
90+
## Keyboard Shortcut Behavior
91+
92+
The `Mod-Shift-C` keyboard shortcut has intelligent toggle behavior:
93+
94+
1. **No color applied**: Applies the currently selected color
95+
2. **Same color already applied**: Removes the color (toggle off)
96+
3. **Different color applied**: Replaces with the currently selected color
97+
4. **"No Fill" selected**: Does nothing (prevents applying undefined color)
98+
99+
## Color Selection Synchronization
100+
101+
The extension maintains a shared color state across all instances:
102+
103+
- Selecting a color in the toolbar updates the bubble menu
104+
- Selecting a color in the bubble menu updates the toolbar
105+
- Keyboard shortcut uses the last selected color
106+
- All color pickers show the same selected color
107+
108+
## Examples
109+
110+
### Basic Usage
53111

54-
The initial color to be displayed in the action button. If not provided, a default color will be used.
112+
```tsx
113+
import { Color } from 'reactjs-tiptap-editor/color';
114+
115+
const extensions = [
116+
Color,
117+
];
118+
```
119+
120+
### With Custom Colors
121+
122+
```tsx
123+
import { Color, COLORS_LIST } from 'reactjs-tiptap-editor';
124+
125+
const extensions = [
126+
Color.configure({
127+
colors: [
128+
...COLORS_LIST,
129+
'#FF69B4', // Hot Pink
130+
'#8A2BE2', // Blue Violet
131+
],
132+
defaultColor: '#000000',
133+
}),
134+
];
135+
```
136+
137+
### Programmatic Usage
138+
139+
```tsx
140+
// Apply color
141+
editor.chain().focus().setColor('#FF0000').run();
142+
143+
// Remove color
144+
editor.chain().focus().unsetColor().run();
145+
146+
// Check if color is active
147+
const isColorActive = editor.isActive('textStyle', { color: '#FF0000' });
148+
149+
// Get current color
150+
const { color } = editor.getAttributes('textStyle');
151+
```

docs/extensions/Highlight/index.md

Lines changed: 118 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ next:
88

99
# Highlight
1010

11-
The Highlight extension allows you to highlight text in your editor.
11+
The Highlight extension allows you to highlight text in your editor with support for multiple colors, keyboard shortcuts, and synchronized color selection across toolbar and bubble menu.
1212

1313
- Based on TipTap's highlight extension. [@tiptap/extension-highlight](https://tiptap.dev/docs/editor/extensions/marks/highlight)
1414

@@ -20,22 +20,133 @@ import { Highlight } from 'reactjs-tiptap-editor/highlight'; // [!code ++]
2020
const extensions = [
2121
...,
2222
// Import Extensions Here
23-
Highlight // [!code ++]
23+
Highlight, // [!code ++]
24+
// or with configuration
25+
Highlight.configure({ // [!code ++]
26+
defaultColor: '#ffff00', // [!code ++]
27+
}), // [!code ++]
2428
];
2529
```
2630

31+
## Features
32+
33+
- 🎨 **Multiple Colors**: Support for multiple highlight colors
34+
- ⌨️ **Keyboard Shortcuts**: Quick highlighting with `Mod-Shift-H`
35+
- 🔄 **Smart Toggle**: Intelligent highlight toggling and replacement
36+
- 🎯 **Synchronized Selection**: Color picker syncs between toolbar and bubble menu
37+
- 🎨 **Custom Colors**: Add custom highlight colors via color picker
38+
- 💾 **Recent Colors**: Automatically tracks recently used colors
39+
-**No Fill Option**: Option to remove highlight
40+
2741
## Options
2842

43+
### defaultColor
44+
45+
Type: `string`\
46+
Default: `undefined`
47+
48+
The default highlight color to use when the extension is initialized. This color will be used when applying highlight via keyboard shortcut for the first time.
49+
50+
```js
51+
Highlight.configure({
52+
defaultColor: '#ffff00', // Yellow
53+
// or
54+
defaultColor: '#ffc078', // Orange
55+
})
56+
```
57+
2958
### shortcutKeys
3059

3160
Type: `string[]`\
3261
Default: `['⇧', 'mod', 'H']`
3362

34-
Keyboard shortcuts for the extension.
63+
Keyboard shortcuts for applying the highlight. Default is `Mod-Shift-H` (Ctrl-Shift-H on Windows/Linux, Cmd-Shift-H on Mac).
3564

36-
### defaultColor
65+
```js
66+
Highlight.configure({
67+
shortcutKeys: ['', 'mod', 'H'],
68+
})
69+
```
3770

38-
Type: `string`\
39-
Default: `none`
71+
## Keyboard Shortcut Behavior
72+
73+
The `Mod-Shift-H` keyboard shortcut has intelligent toggle behavior:
74+
75+
1. **No highlight applied**: Applies the currently selected highlight color
76+
2. **Same color already applied**: Removes the highlight (toggle off)
77+
3. **Different color applied**: Replaces with the currently selected highlight color
78+
4. **"No Fill" selected**: Does nothing (prevents applying undefined highlight)
79+
80+
## Color Selection Synchronization
81+
82+
The extension maintains a shared highlight color state across all instances:
83+
84+
- Selecting a color in the toolbar updates the bubble menu
85+
- Selecting a color in the bubble menu updates the toolbar
86+
- Keyboard shortcut uses the last selected color
87+
- All color pickers show the same selected color
88+
- Selecting "No Fill" clears the stored color
89+
90+
## Examples
91+
92+
### Basic Usage
93+
94+
```tsx
95+
import { Highlight } from 'reactjs-tiptap-editor/highlight';
96+
97+
const extensions = [
98+
Highlight,
99+
];
100+
```
101+
102+
### With Default Color
103+
104+
```tsx
105+
import { Highlight } from 'reactjs-tiptap-editor/highlight';
106+
107+
const extensions = [
108+
Highlight.configure({
109+
defaultColor: '#ffc078', // Orange highlight
110+
}),
111+
];
112+
```
113+
114+
### Programmatic Usage
115+
116+
```tsx
117+
// Apply highlight with color
118+
editor.chain().focus().setHighlight({ color: '#ffff00' }).run();
119+
120+
// Remove highlight
121+
editor.chain().focus().unsetHighlight().run();
122+
123+
// Toggle highlight (removes if same color, applies if different or none)
124+
editor.chain().focus().toggleHighlight({ color: '#ffff00' }).run();
125+
126+
// Check if highlight is active
127+
const isHighlightActive = editor.isActive('highlight');
128+
129+
// Check if specific color is active
130+
const isYellowActive = editor.isActive('highlight', { color: '#ffff00' });
131+
132+
// Get current highlight color
133+
const { color } = editor.getAttributes('highlight');
134+
```
135+
136+
## Color Picker
137+
138+
The highlight color picker includes:
139+
140+
- **No Fill**: Remove highlight from text
141+
- **Color Palette**: Predefined colors for quick selection
142+
- **Recent Colors**: Last 10 used colors
143+
- **Custom Color**: Pick any color using the color picker
144+
145+
## Differences from Color Extension
40146

41-
The initial color used in the action button. If not provided, no color is selected.
147+
| Feature | Highlight | Color |
148+
|---------|-----------|-------|
149+
| Purpose | Background highlighting | Text color |
150+
| Default Shortcut | `Mod-Shift-H` | `Mod-Shift-C` |
151+
| No Fill Behavior | Removes highlight | Removes text color |
152+
| Visual Style | Background color | Foreground color |

src/extensions/Color/Color.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ export interface ColorOptions extends TiptapColorOptions, GeneralOptions<ColorOp
1717
}
1818

1919
export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
20+
addStorage() {
21+
return {
22+
// Stores the currently selected text color; undefined indicates "No Fill" (default color)
23+
currentColor: this.options.defaultColor || undefined,
24+
};
25+
},
26+
2027
addOptions() {
2128
return {
2229
...this.parent?.(),
@@ -27,12 +34,16 @@ export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
2734
colors: extension.options.colors,
2835
defaultColor: extension.options.defaultColor,
2936
action: (color?: unknown) => {
30-
if (color === undefined) {
31-
editor.chain().focus().unsetColor().run();
32-
}
3337
if (typeof color === 'string') {
38+
// Update the stored current color
39+
extension.storage.currentColor = color;
3440
editor.chain().focus().setColor(color).run();
3541
}
42+
if (color === undefined) {
43+
// Clear the color and set currentColor to undefined
44+
extension.storage.currentColor = undefined;
45+
editor.chain().focus().unsetColor().run();
46+
}
3647
},
3748
isActive: () => {
3849
const { color } = editor.getAttributes('textStyle');
@@ -42,11 +53,44 @@ export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
4253
return editor.isActive({ color }) || false;
4354
},
4455
editor,
56+
extension,
4557
disabled: false,
58+
shortcutKeys: extension.options.shortcutKeys ?? ['⇧', 'alt', 'C'],
4659
tooltip: t('editor.color.tooltip'),
4760
},
4861
};
4962
},
5063
};
5164
},
65+
66+
addKeyboardShortcuts() {
67+
return {
68+
...this.parent?.(),
69+
'Alt-Shift-c': () => {
70+
// Use the stored current color
71+
const colorToUse = this.storage.currentColor || this.options.defaultColor;
72+
73+
// If currentColor is undefined (indicating No Fill/default), do not perform color operation
74+
if (!colorToUse) {
75+
return false;
76+
}
77+
78+
// Check if there is already a text color
79+
const { color: currentTextColor } = this.editor.getAttributes('textStyle');
80+
81+
if (currentTextColor) {
82+
// If the current text color is the same as colorToUse, remove it
83+
if (currentTextColor === colorToUse) {
84+
return this.editor.chain().focus().unsetColor().run();
85+
}
86+
87+
// Otherwise, replace with the new color
88+
return this.editor.chain().focus().setColor(colorToUse).run();
89+
}
90+
91+
// If there is no color, add it
92+
return this.editor.chain().focus().setColor(colorToUse).run();
93+
},
94+
};
95+
},
5296
});

0 commit comments

Comments
 (0)