Skip to content

Commit e4fcd93

Browse files
authored
Merge pull request #314 from Found-L/fix/colorConfigure
2 parents 849a1cb + d3be320 commit e4fcd93

File tree

6 files changed

+491
-64
lines changed

6 files changed

+491
-64
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-text-style](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: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,24 @@ export interface ColorOptions extends TiptapColorOptions, GeneralOptions<ColorOp
1515
defaultColor?: string
1616
}
1717

18+
export interface ColorStorage {
19+
currentColor?: string
20+
}
21+
22+
declare module '@tiptap/core' {
23+
interface Storage {
24+
color: ColorStorage
25+
}
26+
}
27+
1828
export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
29+
addStorage() {
30+
return {
31+
// Stores the currently selected text color; undefined indicates "No Fill" (default color)
32+
currentColor: this.options.defaultColor || undefined,
33+
};
34+
},
35+
1936
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
2037
//@ts-expect-error
2138
addOptions() {
@@ -28,12 +45,16 @@ export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
2845
colors: extension.options.colors,
2946
defaultColor: extension.options.defaultColor,
3047
action: (color?: unknown) => {
31-
if (color === undefined) {
32-
editor.chain().focus().unsetColor().run();
33-
}
3448
if (typeof color === 'string') {
49+
// Update the stored current color
50+
editor.storage.color.currentColor = color;
3551
editor.chain().focus().setColor(color).run();
3652
}
53+
if (color === undefined) {
54+
// Clear the color and set currentColor to undefined
55+
editor.storage.color.currentColor = undefined;
56+
editor.chain().focus().unsetColor().run();
57+
}
3758
},
3859
isActive: () => {
3960
const { color } = editor.getAttributes('textStyle');
@@ -43,11 +64,43 @@ export const Color = /* @__PURE__ */ TiptapColor.extend<ColorOptions>({
4364
return editor.isActive({ color }) || false;
4465
},
4566
editor,
67+
extension,
4668
disabled: false,
69+
shortcutKeys: extension.options.shortcutKeys ?? ['⇧', 'alt', 'C'],
4770
tooltip: t('editor.color.tooltip'),
4871
},
4972
};
5073
},
5174
};
5275
},
76+
77+
addKeyboardShortcuts() {
78+
return {
79+
...this.parent?.(),
80+
'Alt-Shift-c': () => {
81+
// Use the stored current color
82+
const colorToUse = this.storage.currentColor || this.options.defaultColor;
83+
84+
// If colorToUse is undefined, remove any existing color
85+
if (!colorToUse) {
86+
const { color: currentTextColor } = this.editor.getAttributes('textStyle');
87+
if (currentTextColor) {
88+
return this.editor.chain().focus().unsetColor().run();
89+
}
90+
return false;
91+
}
92+
93+
// Check if the ENTIRE selection has the exact same text color
94+
const isExactColorActive = this.editor.isActive('textStyle', { color: colorToUse });
95+
96+
if (isExactColorActive) {
97+
// If the entire selection has this exact color, remove it
98+
return this.editor.chain().focus().unsetColor().run();
99+
}
100+
101+
// Otherwise (no color, different color, or mixed state), apply the color
102+
return this.editor.chain().focus().setColor(colorToUse).run();
103+
},
104+
};
105+
},
53106
});

0 commit comments

Comments
 (0)