-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathFormattingToolbar.tsx
More file actions
146 lines (135 loc) · 4.89 KB
/
FormattingToolbar.tsx
File metadata and controls
146 lines (135 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { useLingui } from '@lingui/react';
import { CanvasIcon } from '@uipath/apollo-react/canvas';
import { memo, type RefObject, useCallback } from 'react';
import { CanvasTooltip } from '../CanvasTooltip';
import type { ActiveFormats } from './markdown-formatting';
import {
toggleBold,
toggleBulletList,
toggleItalic,
toggleNumberedList,
toggleStrikethrough,
} from './markdown-formatting';
import {
FormattingButton,
FormattingToolbarContainer,
ToolbarSeparator,
} from './StickyNoteNode.styles';
import type { TextSelection } from './StickyNoteNode.types';
import { getModifierKey, isMac } from './StickyNoteNode.utils';
interface FormattingToolbarProps {
textAreaRef: RefObject<HTMLTextAreaElement | null>;
borderColor: string;
activeFormats: ActiveFormats;
onFormat: (result: TextSelection) => void;
}
const FormattingToolbarComponent = ({
textAreaRef,
borderColor,
activeFormats,
onFormat,
}: FormattingToolbarProps) => {
const { _ } = useLingui();
const mod = getModifierKey();
const shift = isMac() ? '⇧' : '+Shift+';
const applyFormat = useCallback(
(formatFn: (input: TextSelection) => TextSelection) => {
const textarea = textAreaRef.current;
if (!textarea) return;
const input: TextSelection = {
value: textarea.value,
selectionStart: textarea.selectionStart,
selectionEnd: textarea.selectionEnd,
};
onFormat(formatFn(input));
textarea.focus();
},
[textAreaRef, onFormat]
);
const handleBold = useCallback(() => applyFormat(toggleBold), [applyFormat]);
const handleItalic = useCallback(() => applyFormat(toggleItalic), [applyFormat]);
const handleStrikethrough = useCallback(() => applyFormat(toggleStrikethrough), [applyFormat]);
const handleBulletList = useCallback(() => applyFormat(toggleBulletList), [applyFormat]);
const handleNumberedList = useCallback(() => applyFormat(toggleNumberedList), [applyFormat]);
// Hoisted so each label is used for both the tooltip text AND the button's
// aria-label — icon-only buttons otherwise have no accessible name.
// Values go inside the descriptor (Lingui v5 `_(descriptor)` overload does not
// take a separate values arg).
const boldLabel = _({
id: 'sticky-note.formatting.bold',
message: 'Bold ({boldShortcut})',
values: { boldShortcut: `${mod}+B` },
});
const italicLabel = _({
id: 'sticky-note.formatting.italic',
message: 'Italic ({italicShortcut})',
values: { italicShortcut: `${mod}+I` },
});
const strikethroughLabel = _({
id: 'sticky-note.formatting.strikethrough',
message: 'Strikethrough ({strikethroughShortcut})',
values: { strikethroughShortcut: `${mod}${shift}X` },
});
const bulletListLabel = _({
id: 'sticky-note.formatting.bullet-list',
message: 'Bullet list',
});
const numberedListLabel = _({
id: 'sticky-note.formatting.numbered-list',
message: 'Numbered list',
});
const toolbarLabel = _({ id: 'sticky-note.formatting.toolbar', message: 'Text formatting' });
return (
<FormattingToolbarContainer
role="toolbar"
aria-label={toolbarLabel}
borderColor={borderColor}
onMouseDown={(e) => e.preventDefault()}
className="nodrag nowheel"
>
<CanvasTooltip content={boldLabel} placement="top" delay>
<FormattingButton isActive={activeFormats.bold} onClick={handleBold} aria-label={boldLabel}>
<CanvasIcon icon="bold" size={14} />
</FormattingButton>
</CanvasTooltip>
<CanvasTooltip content={italicLabel} placement="top" delay>
<FormattingButton
isActive={activeFormats.italic}
onClick={handleItalic}
aria-label={italicLabel}
>
<CanvasIcon icon="italic" size={14} />
</FormattingButton>
</CanvasTooltip>
<CanvasTooltip content={strikethroughLabel} placement="top" delay>
<FormattingButton
isActive={activeFormats.strikethrough}
onClick={handleStrikethrough}
aria-label={strikethroughLabel}
>
<CanvasIcon icon="strikethrough" size={14} />
</FormattingButton>
</CanvasTooltip>
<ToolbarSeparator />
<CanvasTooltip content={bulletListLabel} placement="top" delay>
<FormattingButton
isActive={activeFormats.bulletList}
onClick={handleBulletList}
aria-label={bulletListLabel}
>
<CanvasIcon icon="list" size={14} />
</FormattingButton>
</CanvasTooltip>
<CanvasTooltip content={numberedListLabel} placement="top" delay>
<FormattingButton
isActive={activeFormats.numberedList}
onClick={handleNumberedList}
aria-label={numberedListLabel}
>
<CanvasIcon icon="list-ordered" size={14} />
</FormattingButton>
</CanvasTooltip>
</FormattingToolbarContainer>
);
};
export const FormattingToolbar = memo(FormattingToolbarComponent);