@atlaskit/editor-toolbar 0.0.0
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/CHANGELOG.md +1 -0
- package/README.md +3 -0
- package/examples/basic.tsx +3 -0
- package/examples/config.jsonc +8 -0
- package/examples/toolbar/examples/ExampleManuallyComposedToolbar.tsx +336 -0
- package/examples/toolbar/examples/useExampleToolbarState.tsx +86 -0
- package/examples/toolbar-ui.tsx +26 -0
- package/package.json +86 -0
- package/src/index.ts +33 -0
- package/src/types.ts +4 -0
- package/src/ui/ColorIndicatorWrapper.tsx +25 -0
- package/src/ui/Toolbar.tsx +31 -0
- package/src/ui/ToolbarButton.tsx +127 -0
- package/src/ui/ToolbarButtonGroup.tsx +18 -0
- package/src/ui/ToolbarDivider.tsx +20 -0
- package/src/ui/ToolbarDropdownItem.tsx +121 -0
- package/src/ui/ToolbarDropdownMenu.tsx +44 -0
- package/src/ui/ToolbarKeyboardShortcutHint.tsx +11 -0
- package/src/ui/ToolbarSection.tsx +19 -0
- package/src/ui/icons/AIAdjustLengthIcon.tsx +2 -0
- package/src/ui/icons/AIChatIcon.tsx +12 -0
- package/src/ui/icons/AICommandIcon.tsx +2 -0
- package/src/ui/icons/AddIcon.tsx +2 -0
- package/src/ui/icons/AppsIcon.tsx +2 -0
- package/src/ui/icons/BoldIcon.tsx +2 -0
- package/src/ui/icons/CommentIcon.tsx +2 -0
- package/src/ui/icons/HeadingFiveIcon.tsx +2 -0
- package/src/ui/icons/HeadingFourIcon.tsx +2 -0
- package/src/ui/icons/HeadingOneIcon.tsx +2 -0
- package/src/ui/icons/HeadingSixIcon.tsx +2 -0
- package/src/ui/icons/HeadingThreeIcon.tsx +2 -0
- package/src/ui/icons/HeadingTwoIcon.tsx +2 -0
- package/src/ui/icons/ItalicIcon.tsx +2 -0
- package/src/ui/icons/LinkIcon.tsx +2 -0
- package/src/ui/icons/ListBulletedIcon.tsx +2 -0
- package/src/ui/icons/ListNumberedIcon.tsx +2 -0
- package/src/ui/icons/MoreItemsIcon.tsx +22 -0
- package/src/ui/icons/PinIcon.tsx +2 -0
- package/src/ui/icons/PinnedIcon.tsx +2 -0
- package/src/ui/icons/QuoteIcon.tsx +2 -0
- package/src/ui/icons/TextColorIcon.tsx +2 -0
- package/src/ui/icons/TextIcon.tsx +2 -0
- package/tsconfig.app.json +63 -0
- package/tsconfig.dev.json +47 -0
- package/tsconfig.json +12 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @atlaskit/editor-toolbar
|
package/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is used by the test scaling project to optimise test result caching
|
|
3
|
+
* Examples that are used by tests affect the outcome of tests so must be included when hashing
|
|
4
|
+
* They are defined here so the hashing algorithm doesn't need to search test files for example usage each time
|
|
5
|
+
*/
|
|
6
|
+
{
|
|
7
|
+
"testExamples": ["basic.tsx"],
|
|
8
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
4
|
+
import { token } from '@atlaskit/tokens';
|
|
5
|
+
|
|
6
|
+
import { ColorIndicatorWrapper } from '../../../src/ui/ColorIndicatorWrapper';
|
|
7
|
+
import { AddIcon } from '../../../src/ui/icons/AddIcon';
|
|
8
|
+
import { AIAdjustLengthIcon } from '../../../src/ui/icons/AIAdjustLengthIcon';
|
|
9
|
+
import { AIChatIcon } from '../../../src/ui/icons/AIChatIcon';
|
|
10
|
+
import { AICommandIcon } from '../../../src/ui/icons/AICommandIcon';
|
|
11
|
+
import { AppsIcon } from '../../../src/ui/icons/AppsIcon';
|
|
12
|
+
import { BoldIcon } from '../../../src/ui/icons/BoldIcon';
|
|
13
|
+
import { CommentIcon } from '../../../src/ui/icons/CommentIcon';
|
|
14
|
+
import { HeadingFiveIcon } from '../../../src/ui/icons/HeadingFiveIcon';
|
|
15
|
+
import { HeadingFourIcon } from '../../../src/ui/icons/HeadingFourIcon';
|
|
16
|
+
import { HeadingOneIcon } from '../../../src/ui/icons/HeadingOneIcon';
|
|
17
|
+
import { HeadingSixIcon } from '../../../src/ui/icons/HeadingSixIcon';
|
|
18
|
+
import { HeadingThreeIcon } from '../../../src/ui/icons/HeadingThreeIcon';
|
|
19
|
+
import { HeadingTwoIcon } from '../../../src/ui/icons/HeadingTwoIcon';
|
|
20
|
+
import { ItalicIcon } from '../../../src/ui/icons/ItalicIcon';
|
|
21
|
+
import { LinkIcon } from '../../../src/ui/icons/LinkIcon';
|
|
22
|
+
import { ListBulletedIcon } from '../../../src/ui/icons/ListBulletedIcon';
|
|
23
|
+
import { ListNumberedIcon } from '../../../src/ui/icons/ListNumberedIcon';
|
|
24
|
+
import { MoreItemsIcon } from '../../../src/ui/icons/MoreItemsIcon';
|
|
25
|
+
import { PinIcon } from '../../../src/ui/icons/PinIcon';
|
|
26
|
+
import { PinnedIcon } from '../../../src/ui/icons/PinnedIcon';
|
|
27
|
+
import { QuoteIcon } from '../../../src/ui/icons/QuoteIcon';
|
|
28
|
+
import { TextColorIcon } from '../../../src/ui/icons/TextColorIcon';
|
|
29
|
+
import { TextIcon } from '../../../src/ui/icons/TextIcon';
|
|
30
|
+
import { Toolbar } from '../../../src/ui/Toolbar';
|
|
31
|
+
import { ToolbarButton } from '../../../src/ui/ToolbarButton';
|
|
32
|
+
import { ToolbarButtonGroup } from '../../../src/ui/ToolbarButtonGroup';
|
|
33
|
+
import { ToolbarDivider } from '../../../src/ui/ToolbarDivider';
|
|
34
|
+
import { ToolbarDropdownItem } from '../../../src/ui/ToolbarDropdownItem';
|
|
35
|
+
import { ToolbarDropdownMenu } from '../../../src/ui/ToolbarDropdownMenu';
|
|
36
|
+
import { ToolbarKeyboardShortcutHint } from '../../../src/ui/ToolbarKeyboardShortcutHint';
|
|
37
|
+
import { ToolbarSection } from '../../../src/ui/ToolbarSection';
|
|
38
|
+
|
|
39
|
+
import { useExampleToolbarState } from './useExampleToolbarState';
|
|
40
|
+
|
|
41
|
+
export const ExampleManuallyComposedToolbar = () => {
|
|
42
|
+
const {
|
|
43
|
+
textStyle,
|
|
44
|
+
onSetTextStyle,
|
|
45
|
+
formatting,
|
|
46
|
+
onToggleFormatting,
|
|
47
|
+
listOrAlignment,
|
|
48
|
+
onToggleListOrAlignment,
|
|
49
|
+
pinning,
|
|
50
|
+
onTogglePinning,
|
|
51
|
+
onClick,
|
|
52
|
+
lastAction,
|
|
53
|
+
} = useExampleToolbarState();
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<Toolbar label="Editor Toolbar">
|
|
58
|
+
<ToolbarSection>
|
|
59
|
+
<ToolbarButtonGroup>
|
|
60
|
+
<ToolbarButton
|
|
61
|
+
icon={AIChatIcon}
|
|
62
|
+
label="Ask Rovo"
|
|
63
|
+
onClick={onClick('Ask Rovo')}
|
|
64
|
+
groupLocation="start"
|
|
65
|
+
>
|
|
66
|
+
Ask Rovo
|
|
67
|
+
</ToolbarButton>
|
|
68
|
+
<ToolbarDropdownMenu icon={MoreItemsIcon} label="More formatting" groupLocation="end">
|
|
69
|
+
<ToolbarDropdownItem
|
|
70
|
+
elemBefore={<AIAdjustLengthIcon label="Adjust length" />}
|
|
71
|
+
onClick={onClick('Adjust length')}
|
|
72
|
+
>
|
|
73
|
+
Adjust length
|
|
74
|
+
</ToolbarDropdownItem>
|
|
75
|
+
</ToolbarDropdownMenu>
|
|
76
|
+
</ToolbarButtonGroup>
|
|
77
|
+
|
|
78
|
+
<ToolbarButtonGroup>
|
|
79
|
+
<ToolbarButton
|
|
80
|
+
icon={AICommandIcon}
|
|
81
|
+
label="Improve writing"
|
|
82
|
+
onClick={onClick('Improve writing')}
|
|
83
|
+
>
|
|
84
|
+
Improve writing
|
|
85
|
+
</ToolbarButton>
|
|
86
|
+
</ToolbarButtonGroup>
|
|
87
|
+
</ToolbarSection>
|
|
88
|
+
|
|
89
|
+
<ToolbarDivider />
|
|
90
|
+
|
|
91
|
+
<ToolbarSection>
|
|
92
|
+
<ToolbarButtonGroup>
|
|
93
|
+
<ToolbarDropdownMenu
|
|
94
|
+
icon={
|
|
95
|
+
{
|
|
96
|
+
none: TextIcon,
|
|
97
|
+
normal: TextIcon,
|
|
98
|
+
heading1: HeadingOneIcon,
|
|
99
|
+
heading2: HeadingTwoIcon,
|
|
100
|
+
heading3: HeadingThreeIcon,
|
|
101
|
+
heading4: HeadingFourIcon,
|
|
102
|
+
heading5: HeadingFiveIcon,
|
|
103
|
+
heading6: HeadingSixIcon,
|
|
104
|
+
quote: QuoteIcon,
|
|
105
|
+
}[textStyle]
|
|
106
|
+
}
|
|
107
|
+
label="Text styles"
|
|
108
|
+
>
|
|
109
|
+
<ToolbarDropdownItem
|
|
110
|
+
elemBefore={<TextIcon label="Normal text" />}
|
|
111
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥0" />}
|
|
112
|
+
onClick={onClick('Normal text', onSetTextStyle('normal'))}
|
|
113
|
+
isSelected={textStyle === 'normal'}
|
|
114
|
+
textStyle="normal"
|
|
115
|
+
>
|
|
116
|
+
Normal text
|
|
117
|
+
</ToolbarDropdownItem>
|
|
118
|
+
<ToolbarDropdownItem
|
|
119
|
+
elemBefore={<HeadingOneIcon label="Heading One" />}
|
|
120
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥1" />}
|
|
121
|
+
onClick={onClick('Heading one', onSetTextStyle('heading1'))}
|
|
122
|
+
isSelected={textStyle === 'heading1'}
|
|
123
|
+
textStyle="heading1"
|
|
124
|
+
>
|
|
125
|
+
Heading 1
|
|
126
|
+
</ToolbarDropdownItem>
|
|
127
|
+
<ToolbarDropdownItem
|
|
128
|
+
elemBefore={<HeadingTwoIcon label="Heading Two" />}
|
|
129
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥2" />}
|
|
130
|
+
onClick={onClick('Heading two', onSetTextStyle('heading2'))}
|
|
131
|
+
isSelected={textStyle === 'heading2'}
|
|
132
|
+
textStyle="heading2"
|
|
133
|
+
>
|
|
134
|
+
Heading 2
|
|
135
|
+
</ToolbarDropdownItem>
|
|
136
|
+
<ToolbarDropdownItem
|
|
137
|
+
elemBefore={<HeadingThreeIcon label="Heading Three" />}
|
|
138
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥3" />}
|
|
139
|
+
onClick={onClick('Heading three', onSetTextStyle('heading3'))}
|
|
140
|
+
isSelected={textStyle === 'heading3'}
|
|
141
|
+
textStyle="heading3"
|
|
142
|
+
>
|
|
143
|
+
Heading 3
|
|
144
|
+
</ToolbarDropdownItem>
|
|
145
|
+
<ToolbarDropdownItem
|
|
146
|
+
elemBefore={<HeadingFourIcon label="Heading Four" />}
|
|
147
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥4" />}
|
|
148
|
+
onClick={onClick('Heading four', onSetTextStyle('heading4'))}
|
|
149
|
+
isSelected={textStyle === 'heading4'}
|
|
150
|
+
textStyle="heading4"
|
|
151
|
+
>
|
|
152
|
+
Heading 4
|
|
153
|
+
</ToolbarDropdownItem>
|
|
154
|
+
<ToolbarDropdownItem
|
|
155
|
+
elemBefore={<HeadingFiveIcon label="Heading Five" />}
|
|
156
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥5" />}
|
|
157
|
+
onClick={onClick('Heading five', onSetTextStyle('heading5'))}
|
|
158
|
+
isSelected={textStyle === 'heading5'}
|
|
159
|
+
textStyle="heading5"
|
|
160
|
+
>
|
|
161
|
+
Heading 5
|
|
162
|
+
</ToolbarDropdownItem>
|
|
163
|
+
<ToolbarDropdownItem
|
|
164
|
+
elemBefore={<HeadingSixIcon label="Heading Six" />}
|
|
165
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥6" />}
|
|
166
|
+
onClick={onClick('Heading six', onSetTextStyle('heading6'))}
|
|
167
|
+
isSelected={textStyle === 'heading6'}
|
|
168
|
+
textStyle="heading6"
|
|
169
|
+
>
|
|
170
|
+
Heading 6
|
|
171
|
+
</ToolbarDropdownItem>
|
|
172
|
+
<ToolbarDropdownItem
|
|
173
|
+
elemBefore={<QuoteIcon label="Quote" />}
|
|
174
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⌥9" />}
|
|
175
|
+
onClick={onClick('Quote', onSetTextStyle('quote'))}
|
|
176
|
+
isSelected={textStyle === 'quote'}
|
|
177
|
+
textStyle="normal"
|
|
178
|
+
>
|
|
179
|
+
Quote
|
|
180
|
+
</ToolbarDropdownItem>
|
|
181
|
+
</ToolbarDropdownMenu>
|
|
182
|
+
</ToolbarButtonGroup>
|
|
183
|
+
|
|
184
|
+
<ToolbarButtonGroup>
|
|
185
|
+
<ToolbarButton
|
|
186
|
+
icon={formatting.italic && !formatting.bold ? ItalicIcon : BoldIcon}
|
|
187
|
+
label={formatting.italic && !formatting.bold ? 'Italic' : 'Bold'}
|
|
188
|
+
onClick={onClick(
|
|
189
|
+
formatting.italic && !formatting.bold ? 'Italic' : 'Bold',
|
|
190
|
+
onToggleFormatting(formatting.italic && !formatting.bold ? 'italic' : 'bold'),
|
|
191
|
+
)}
|
|
192
|
+
groupLocation="start"
|
|
193
|
+
isSelected={formatting.bold || formatting.italic}
|
|
194
|
+
/>
|
|
195
|
+
<ToolbarDropdownMenu icon={MoreItemsIcon} label="More formatting" groupLocation="end">
|
|
196
|
+
<ToolbarDropdownItem
|
|
197
|
+
elemBefore={<BoldIcon label="Bold" />}
|
|
198
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘B" />}
|
|
199
|
+
onClick={onClick('Bold', onToggleFormatting('bold'))}
|
|
200
|
+
isSelected={formatting.bold}
|
|
201
|
+
>
|
|
202
|
+
Bold
|
|
203
|
+
</ToolbarDropdownItem>
|
|
204
|
+
<ToolbarDropdownItem
|
|
205
|
+
elemBefore={<ItalicIcon label="Italic" />}
|
|
206
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘I" />}
|
|
207
|
+
onClick={onClick('Italic', onToggleFormatting('italic'))}
|
|
208
|
+
isSelected={formatting.italic}
|
|
209
|
+
>
|
|
210
|
+
Italic
|
|
211
|
+
</ToolbarDropdownItem>
|
|
212
|
+
</ToolbarDropdownMenu>
|
|
213
|
+
</ToolbarButtonGroup>
|
|
214
|
+
|
|
215
|
+
<ToolbarButtonGroup>
|
|
216
|
+
<ToolbarDropdownMenu
|
|
217
|
+
icon={({ label, color, shouldRecommendSmallIcon, size, spacing, testId }) => (
|
|
218
|
+
<ColorIndicatorWrapper color={token('color.border.accent.blue')}>
|
|
219
|
+
<TextColorIcon
|
|
220
|
+
label={label}
|
|
221
|
+
color={color}
|
|
222
|
+
shouldRecommendSmallIcon={shouldRecommendSmallIcon}
|
|
223
|
+
size={size}
|
|
224
|
+
spacing={spacing}
|
|
225
|
+
testId={testId}
|
|
226
|
+
/>
|
|
227
|
+
</ColorIndicatorWrapper>
|
|
228
|
+
)}
|
|
229
|
+
label="Text color"
|
|
230
|
+
>
|
|
231
|
+
<ToolbarDropdownItem
|
|
232
|
+
elemBefore={<TextIcon label="Text color" />}
|
|
233
|
+
onClick={onClick('Text color')}
|
|
234
|
+
>
|
|
235
|
+
Text color
|
|
236
|
+
</ToolbarDropdownItem>
|
|
237
|
+
</ToolbarDropdownMenu>
|
|
238
|
+
</ToolbarButtonGroup>
|
|
239
|
+
|
|
240
|
+
<ToolbarButtonGroup>
|
|
241
|
+
<ToolbarButton
|
|
242
|
+
icon={listOrAlignment === 'numbered' ? ListNumberedIcon : ListBulletedIcon}
|
|
243
|
+
label={listOrAlignment === 'numbered' ? 'Numbered list' : 'Bulleted list'}
|
|
244
|
+
onClick={onClick(
|
|
245
|
+
listOrAlignment === 'numbered' ? 'Numbered list' : 'Bulleted list',
|
|
246
|
+
onToggleListOrAlignment(listOrAlignment === 'numbered' ? 'numbered' : 'bulleted'),
|
|
247
|
+
)}
|
|
248
|
+
groupLocation="start"
|
|
249
|
+
isSelected={listOrAlignment !== 'none'}
|
|
250
|
+
/>
|
|
251
|
+
<ToolbarDropdownMenu
|
|
252
|
+
icon={MoreItemsIcon}
|
|
253
|
+
label="Lists, indentation and alignment"
|
|
254
|
+
groupLocation="end"
|
|
255
|
+
>
|
|
256
|
+
<ToolbarDropdownItem
|
|
257
|
+
elemBefore={<ListBulletedIcon label="Bulleted list" />}
|
|
258
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⇧8" />}
|
|
259
|
+
onClick={onClick('Bulleted list', onToggleListOrAlignment('bulleted'))}
|
|
260
|
+
isSelected={listOrAlignment === 'bulleted'}
|
|
261
|
+
>
|
|
262
|
+
Bulleted list
|
|
263
|
+
</ToolbarDropdownItem>
|
|
264
|
+
<ToolbarDropdownItem
|
|
265
|
+
elemBefore={<ListNumberedIcon label="Numbered list" />}
|
|
266
|
+
elemAfter={<ToolbarKeyboardShortcutHint shortcut="⌘⇧7" />}
|
|
267
|
+
onClick={onClick('Numbered list', onToggleListOrAlignment('numbered'))}
|
|
268
|
+
isSelected={listOrAlignment === 'numbered'}
|
|
269
|
+
>
|
|
270
|
+
Numbered list
|
|
271
|
+
</ToolbarDropdownItem>
|
|
272
|
+
</ToolbarDropdownMenu>
|
|
273
|
+
</ToolbarButtonGroup>
|
|
274
|
+
</ToolbarSection>
|
|
275
|
+
|
|
276
|
+
<ToolbarDivider />
|
|
277
|
+
|
|
278
|
+
<ToolbarSection>
|
|
279
|
+
<ToolbarButtonGroup>
|
|
280
|
+
<ToolbarButton icon={LinkIcon} label="Link" onClick={onClick('Link')} />
|
|
281
|
+
</ToolbarButtonGroup>
|
|
282
|
+
</ToolbarSection>
|
|
283
|
+
|
|
284
|
+
<ToolbarDivider />
|
|
285
|
+
|
|
286
|
+
<ToolbarSection>
|
|
287
|
+
<ToolbarButtonGroup>
|
|
288
|
+
<ToolbarButton icon={CommentIcon} label="Comment" onClick={onClick('Comment')} />
|
|
289
|
+
</ToolbarButtonGroup>
|
|
290
|
+
</ToolbarSection>
|
|
291
|
+
|
|
292
|
+
<ToolbarDivider />
|
|
293
|
+
|
|
294
|
+
<ToolbarSection>
|
|
295
|
+
<ToolbarButtonGroup>
|
|
296
|
+
<ToolbarDropdownMenu icon={AppsIcon} label="Apps and extensions">
|
|
297
|
+
<ToolbarDropdownItem
|
|
298
|
+
elemBefore={<AddIcon label="Create Jira work item" />}
|
|
299
|
+
onClick={onClick('Create Jira work item')}
|
|
300
|
+
>
|
|
301
|
+
Create Jira work item
|
|
302
|
+
</ToolbarDropdownItem>
|
|
303
|
+
</ToolbarDropdownMenu>
|
|
304
|
+
</ToolbarButtonGroup>
|
|
305
|
+
</ToolbarSection>
|
|
306
|
+
|
|
307
|
+
<ToolbarDivider />
|
|
308
|
+
|
|
309
|
+
<ToolbarSection>
|
|
310
|
+
<ToolbarButtonGroup>
|
|
311
|
+
<ToolbarButton
|
|
312
|
+
icon={pinning === 'pinned' ? PinnedIcon : PinIcon}
|
|
313
|
+
label={pinning === 'pinned' ? 'Unpin toolbar' : 'Pin toolbar'}
|
|
314
|
+
onClick={onClick(
|
|
315
|
+
pinning === 'pinned' ? 'Unpin toolbar' : 'Pin toolbar',
|
|
316
|
+
onTogglePinning,
|
|
317
|
+
)}
|
|
318
|
+
/>
|
|
319
|
+
</ToolbarButtonGroup>
|
|
320
|
+
</ToolbarSection>
|
|
321
|
+
</Toolbar>
|
|
322
|
+
<Box as="pre">
|
|
323
|
+
{`
|
|
324
|
+
Last action: ${lastAction || 'None'}
|
|
325
|
+
Text style: ${textStyle}
|
|
326
|
+
Formatting: ${Object.entries(formatting)
|
|
327
|
+
.filter(([, value]) => value)
|
|
328
|
+
.map(([key]) => key)
|
|
329
|
+
.join(', ')}
|
|
330
|
+
List/Align: ${listOrAlignment}
|
|
331
|
+
Pinning: ${pinning}
|
|
332
|
+
`}
|
|
333
|
+
</Box>
|
|
334
|
+
</>
|
|
335
|
+
);
|
|
336
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
type TextStyle =
|
|
4
|
+
| 'normal'
|
|
5
|
+
| 'heading1'
|
|
6
|
+
| 'heading2'
|
|
7
|
+
| 'heading3'
|
|
8
|
+
| 'heading4'
|
|
9
|
+
| 'heading5'
|
|
10
|
+
| 'heading6'
|
|
11
|
+
| 'quote';
|
|
12
|
+
type Formatting =
|
|
13
|
+
| 'bold'
|
|
14
|
+
| 'italic'
|
|
15
|
+
| 'underline'
|
|
16
|
+
| 'strikethrough'
|
|
17
|
+
| 'code'
|
|
18
|
+
| 'subscript'
|
|
19
|
+
| 'superscript';
|
|
20
|
+
type Pinning = 'none' | 'pinned';
|
|
21
|
+
type ListOrAlignment = 'none' | 'left' | 'center' | 'right' | 'bulleted' | 'numbered';
|
|
22
|
+
|
|
23
|
+
export const useExampleToolbarState = () => {
|
|
24
|
+
const [textStyle, setTextStyle] = useState<TextStyle>('normal');
|
|
25
|
+
const [formatting, setFormatting] = useState<Partial<Record<Formatting, boolean>>>({});
|
|
26
|
+
const [listOrAlignment, setListOrAlignment] = useState<ListOrAlignment>('none');
|
|
27
|
+
const [pinning, setPinning] = useState<Pinning>('none');
|
|
28
|
+
const [lastAction, setLastAction] = useState<string | null>(null);
|
|
29
|
+
|
|
30
|
+
const onSetTextStyle = (style: TextStyle) => () => {
|
|
31
|
+
setTextStyle(style);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const onToggleFormatting = (format: Formatting) => () => {
|
|
35
|
+
setFormatting((prev) => {
|
|
36
|
+
if (format === 'code') {
|
|
37
|
+
return {
|
|
38
|
+
code: !prev.code,
|
|
39
|
+
};
|
|
40
|
+
} else if (prev.code) {
|
|
41
|
+
return prev;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...prev,
|
|
45
|
+
[format]: !prev[format],
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const onToggleListOrAlignment = (newListOrAlignment: ListOrAlignment) => () => {
|
|
51
|
+
setListOrAlignment((prev) => {
|
|
52
|
+
const isList = (value: ListOrAlignment) => value === 'bulleted' || value === 'numbered';
|
|
53
|
+
if (isList(prev) && !isList(newListOrAlignment)) {
|
|
54
|
+
return prev;
|
|
55
|
+
}
|
|
56
|
+
if (prev === newListOrAlignment) {
|
|
57
|
+
return 'none';
|
|
58
|
+
}
|
|
59
|
+
return newListOrAlignment;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const onTogglePinning = () => {
|
|
64
|
+
setPinning((prev) => (prev === 'none' ? 'pinned' : 'none'));
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const onClick = (action: string, callback?: () => void) => () => {
|
|
68
|
+
callback?.();
|
|
69
|
+
setLastAction(action);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
console.log('rendering with list or alignment:', listOrAlignment);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
textStyle,
|
|
76
|
+
onSetTextStyle,
|
|
77
|
+
formatting,
|
|
78
|
+
onToggleFormatting,
|
|
79
|
+
listOrAlignment,
|
|
80
|
+
onToggleListOrAlignment,
|
|
81
|
+
pinning,
|
|
82
|
+
onTogglePinning,
|
|
83
|
+
onClick,
|
|
84
|
+
lastAction,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
import { token } from '@atlaskit/tokens';
|
|
6
|
+
|
|
7
|
+
import { ExampleManuallyComposedToolbar } from './toolbar/examples/ExampleManuallyComposedToolbar';
|
|
8
|
+
|
|
9
|
+
const styles = cssMap({
|
|
10
|
+
container: {
|
|
11
|
+
paddingTop: token('space.400'),
|
|
12
|
+
paddingRight: token('space.400'),
|
|
13
|
+
paddingBottom: token('space.400'),
|
|
14
|
+
paddingLeft: token('space.400'),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const App = () => {
|
|
19
|
+
return (
|
|
20
|
+
<Box xcss={styles.container} as="main">
|
|
21
|
+
<ExampleManuallyComposedToolbar />
|
|
22
|
+
</Box>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default App;
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlaskit/editor-toolbar",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"registry": "https://registry.npmjs.org/"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.0.0",
|
|
7
|
+
"description": "Common UI for Toolbars across the platform",
|
|
8
|
+
"atlassian": {
|
|
9
|
+
"team": "Editor"
|
|
10
|
+
},
|
|
11
|
+
"repository": "https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo",
|
|
12
|
+
"author": "Atlassian Pty Ltd",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"main": "dist/cjs/index.js",
|
|
15
|
+
"module": "dist/esm/index.js",
|
|
16
|
+
"module:es2019": "dist/es2019/index.js",
|
|
17
|
+
"types": "dist/types/index.d.ts",
|
|
18
|
+
"sideEffects": [
|
|
19
|
+
"*.compiled.css"
|
|
20
|
+
],
|
|
21
|
+
"atlaskit:src": "src/index.ts",
|
|
22
|
+
"af:exports": {
|
|
23
|
+
".": "./src/index.ts"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@atlaskit/badge": "^18.1.0",
|
|
27
|
+
"@atlaskit/button": "^23.2.0",
|
|
28
|
+
"@atlaskit/css": "^0.12.0",
|
|
29
|
+
"@atlaskit/dropdown-menu": "^16.1.0",
|
|
30
|
+
"@atlaskit/icon": "^27.3.0",
|
|
31
|
+
"@atlaskit/icon-lab": "^5.1.0",
|
|
32
|
+
"@atlaskit/logo": "^19.5.0",
|
|
33
|
+
"@atlaskit/popup": "^4.3.0",
|
|
34
|
+
"@atlaskit/primitives": "^14.10.0",
|
|
35
|
+
"@atlaskit/tokens": "^5.5.0",
|
|
36
|
+
"@babel/runtime": "^7.0.0",
|
|
37
|
+
"@compiled/react": "^0.18.3"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": "^18.2.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@af/integration-testing": "workspace:^",
|
|
44
|
+
"@af/visual-regression": "workspace:^",
|
|
45
|
+
"@atlaskit/ssr": "workspace:^",
|
|
46
|
+
"@atlaskit/visual-regression": "workspace:^",
|
|
47
|
+
"@testing-library/react": "^13.4.0",
|
|
48
|
+
"react-dom": "^18.2.0",
|
|
49
|
+
"typescript": "~5.4.2"
|
|
50
|
+
},
|
|
51
|
+
"techstack": {
|
|
52
|
+
"@atlassian/frontend": {
|
|
53
|
+
"import-structure": [
|
|
54
|
+
"atlassian-conventions"
|
|
55
|
+
],
|
|
56
|
+
"circular-dependencies": [
|
|
57
|
+
"file-and-folder-level"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"@repo/internal": {
|
|
61
|
+
"dom-events": "use-bind-event-listener",
|
|
62
|
+
"analytics": [
|
|
63
|
+
"analytics-next"
|
|
64
|
+
],
|
|
65
|
+
"design-tokens": [
|
|
66
|
+
"color"
|
|
67
|
+
],
|
|
68
|
+
"theming": [
|
|
69
|
+
"react-context"
|
|
70
|
+
],
|
|
71
|
+
"ui-components": [
|
|
72
|
+
"lite-mode"
|
|
73
|
+
],
|
|
74
|
+
"deprecation": [
|
|
75
|
+
"no-deprecated-imports"
|
|
76
|
+
],
|
|
77
|
+
"styling": [
|
|
78
|
+
"static",
|
|
79
|
+
"compiled"
|
|
80
|
+
],
|
|
81
|
+
"imports": [
|
|
82
|
+
"import-no-extraneous-disable-for-examples-and-docs"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
+
export { Toolbar } from './ui/Toolbar';
|
|
3
|
+
export { ToolbarButton } from './ui/ToolbarButton';
|
|
4
|
+
export { ToolbarDropdownItem } from './ui/ToolbarDropdownItem';
|
|
5
|
+
export { ToolbarDropdownMenu } from './ui/ToolbarDropdownMenu';
|
|
6
|
+
export { ToolbarKeyboardShortcutHint } from './ui/ToolbarKeyboardShortcutHint';
|
|
7
|
+
export { ToolbarSection } from './ui/ToolbarSection';
|
|
8
|
+
|
|
9
|
+
export { AIAdjustLengthIcon } from './ui/icons/AIAdjustLengthIcon';
|
|
10
|
+
export { AIChatIcon } from './ui/icons/AIChatIcon';
|
|
11
|
+
export { AICommandIcon } from './ui/icons/AICommandIcon';
|
|
12
|
+
export { AddIcon } from './ui/icons/AddIcon';
|
|
13
|
+
export { AppsIcon } from './ui/icons/AppsIcon';
|
|
14
|
+
export { BoldIcon } from './ui/icons/BoldIcon';
|
|
15
|
+
export { CommentIcon } from './ui/icons/CommentIcon';
|
|
16
|
+
export { HeadingFiveIcon } from './ui/icons/HeadingFiveIcon';
|
|
17
|
+
export { HeadingFourIcon } from './ui/icons/HeadingFourIcon';
|
|
18
|
+
export { HeadingOneIcon } from './ui/icons/HeadingOneIcon';
|
|
19
|
+
export { HeadingSixIcon } from './ui/icons/HeadingSixIcon';
|
|
20
|
+
export { HeadingThreeIcon } from './ui/icons/HeadingThreeIcon';
|
|
21
|
+
export { HeadingTwoIcon } from './ui/icons/HeadingTwoIcon';
|
|
22
|
+
export { ItalicIcon } from './ui/icons/ItalicIcon';
|
|
23
|
+
export { LinkIcon } from './ui/icons/LinkIcon';
|
|
24
|
+
export { ListBulletedIcon } from './ui/icons/ListBulletedIcon';
|
|
25
|
+
export { ListNumberedIcon } from './ui/icons/ListNumberedIcon';
|
|
26
|
+
export { MoreItemsIcon } from './ui/icons/MoreItemsIcon';
|
|
27
|
+
export { PinIcon } from './ui/icons/PinIcon';
|
|
28
|
+
export { PinnedIcon } from './ui/icons/PinnedIcon';
|
|
29
|
+
export { QuoteIcon } from './ui/icons/QuoteIcon';
|
|
30
|
+
export { TextColorIcon } from './ui/icons/TextColorIcon';
|
|
31
|
+
export { TextIcon } from './ui/icons/TextIcon';
|
|
32
|
+
|
|
33
|
+
export type { ToolbarButtonGroupLocation } from './types';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
import { token } from '@atlaskit/tokens';
|
|
6
|
+
|
|
7
|
+
type ColorIndicatorWrapperProps = {
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
color?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const styles = cssMap({
|
|
13
|
+
indicator: {
|
|
14
|
+
height: '16px',
|
|
15
|
+
borderBottomColor: token('color.border.bold'),
|
|
16
|
+
borderBottomStyle: 'solid',
|
|
17
|
+
borderBottomWidth: token('border.width.indicator'),
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const ColorIndicatorWrapper = ({ color, children }: ColorIndicatorWrapperProps) => (
|
|
22
|
+
<Box xcss={styles.indicator} style={{ borderBottomColor: color }} as="span">
|
|
23
|
+
{children}
|
|
24
|
+
</Box>
|
|
25
|
+
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
import { token } from '@atlaskit/tokens';
|
|
6
|
+
|
|
7
|
+
const styles = cssMap({
|
|
8
|
+
toolbar: {
|
|
9
|
+
paddingRight: token('space.050'),
|
|
10
|
+
paddingLeft: token('space.050'),
|
|
11
|
+
boxShadow: token('elevation.shadow.overlay'),
|
|
12
|
+
borderRadius: '6px',
|
|
13
|
+
height: '40px',
|
|
14
|
+
width: 'min-content',
|
|
15
|
+
display: 'flex',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type ToolbarProps = {
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Toolbar = ({ children, label }: ToolbarProps) => {
|
|
26
|
+
return (
|
|
27
|
+
<Box xcss={styles.toolbar} role="toolbar" aria-label={label}>
|
|
28
|
+
{children}
|
|
29
|
+
</Box>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, { forwardRef, type ReactNode, type Ref } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap, cx } from '@atlaskit/css';
|
|
4
|
+
import { type TriggerProps } from '@atlaskit/popup';
|
|
5
|
+
import { Pressable } from '@atlaskit/primitives/compiled';
|
|
6
|
+
import { token } from '@atlaskit/tokens';
|
|
7
|
+
|
|
8
|
+
import { type IconComponent, type ToolbarButtonGroupLocation } from '../types';
|
|
9
|
+
|
|
10
|
+
const styles = cssMap({
|
|
11
|
+
button: {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
gap: token('space.075'),
|
|
14
|
+
backgroundColor: token('color.background.neutral.subtle'),
|
|
15
|
+
whiteSpace: 'nowrap',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
borderRadius: token('border.radius.100'),
|
|
19
|
+
minHeight: '32px',
|
|
20
|
+
color: token('color.text.subtle'),
|
|
21
|
+
fontWeight: token('font.weight.medium'),
|
|
22
|
+
paddingLeft: token('space.100'),
|
|
23
|
+
paddingRight: token('space.100'),
|
|
24
|
+
|
|
25
|
+
'&:hover': {
|
|
26
|
+
backgroundColor: token('color.background.neutral.subtle.hovered'),
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
'&:active': {
|
|
30
|
+
backgroundColor: token('color.background.neutral.subtle.pressed'),
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
selected: {
|
|
34
|
+
backgroundColor: token('color.background.selected'),
|
|
35
|
+
|
|
36
|
+
'&:hover': {
|
|
37
|
+
backgroundColor: token('color.background.selected.hovered'),
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
'&:active': {
|
|
41
|
+
backgroundColor: token('color.background.selected.pressed'),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
groupStart: {
|
|
45
|
+
borderTopRightRadius: '0px',
|
|
46
|
+
borderBottomRightRadius: '0px',
|
|
47
|
+
justifyContent: 'flex-end',
|
|
48
|
+
paddingLeft: token('space.075'),
|
|
49
|
+
paddingRight: token('space.025'),
|
|
50
|
+
},
|
|
51
|
+
groupMiddle: {
|
|
52
|
+
borderTopLeftRadius: '0px',
|
|
53
|
+
borderBottomLeftRadius: '0px',
|
|
54
|
+
borderTopRightRadius: '0px',
|
|
55
|
+
borderBottomRightRadius: '0px',
|
|
56
|
+
paddingLeft: token('space.050'),
|
|
57
|
+
paddingRight: token('space.050'),
|
|
58
|
+
},
|
|
59
|
+
groupEnd: {
|
|
60
|
+
borderTopLeftRadius: '0px',
|
|
61
|
+
borderBottomLeftRadius: '0px',
|
|
62
|
+
justifyContent: 'flex-start',
|
|
63
|
+
paddingLeft: token('space.025'),
|
|
64
|
+
paddingRight: token('space.075'),
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
type ToolbarButtonProps = Partial<TriggerProps> & {
|
|
69
|
+
children?: ReactNode;
|
|
70
|
+
isSelected?: boolean;
|
|
71
|
+
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
72
|
+
onBlur?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
73
|
+
onFocus?: (event: React.FocusEvent<HTMLButtonElement>) => void;
|
|
74
|
+
testId?: string;
|
|
75
|
+
label: string;
|
|
76
|
+
icon: IconComponent;
|
|
77
|
+
groupLocation?: ToolbarButtonGroupLocation;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const ToolbarButton = forwardRef(
|
|
81
|
+
(
|
|
82
|
+
{
|
|
83
|
+
icon: IconComponent,
|
|
84
|
+
label,
|
|
85
|
+
children,
|
|
86
|
+
onClick,
|
|
87
|
+
isSelected,
|
|
88
|
+
'aria-expanded': ariaExpanded,
|
|
89
|
+
'aria-haspopup': ariaHasPopup,
|
|
90
|
+
'aria-controls': ariaControls,
|
|
91
|
+
'data-ds--level': dataDsLevel,
|
|
92
|
+
onBlur,
|
|
93
|
+
onFocus,
|
|
94
|
+
testId,
|
|
95
|
+
groupLocation,
|
|
96
|
+
}: ToolbarButtonProps,
|
|
97
|
+
ref: Ref<HTMLButtonElement>,
|
|
98
|
+
) => {
|
|
99
|
+
return (
|
|
100
|
+
<Pressable
|
|
101
|
+
ref={ref}
|
|
102
|
+
xcss={cx(
|
|
103
|
+
styles.button,
|
|
104
|
+
isSelected && styles.selected,
|
|
105
|
+
groupLocation === 'start' && styles.groupStart,
|
|
106
|
+
groupLocation === 'middle' && styles.groupMiddle,
|
|
107
|
+
groupLocation === 'end' && styles.groupEnd,
|
|
108
|
+
)}
|
|
109
|
+
aria-expanded={ariaExpanded}
|
|
110
|
+
aria-haspopup={ariaHasPopup}
|
|
111
|
+
aria-controls={ariaControls}
|
|
112
|
+
data-ds--level={dataDsLevel}
|
|
113
|
+
onClick={onClick}
|
|
114
|
+
onBlur={onBlur}
|
|
115
|
+
onFocus={onFocus}
|
|
116
|
+
testId={testId}
|
|
117
|
+
>
|
|
118
|
+
<IconComponent
|
|
119
|
+
label={label}
|
|
120
|
+
size="medium"
|
|
121
|
+
color={isSelected ? token('color.icon.selected') : token('color.icon.subtle')}
|
|
122
|
+
/>
|
|
123
|
+
{children}
|
|
124
|
+
</Pressable>
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
|
|
6
|
+
const styles = cssMap({
|
|
7
|
+
container: {
|
|
8
|
+
display: 'flex',
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
type ToolbarButtonGroupProps = {
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const ToolbarButtonGroup = ({ children }: ToolbarButtonGroupProps) => {
|
|
17
|
+
return <Box xcss={styles.container}>{children}</Box>;
|
|
18
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
import { token } from '@atlaskit/tokens';
|
|
6
|
+
|
|
7
|
+
const styles = cssMap({
|
|
8
|
+
divider: {
|
|
9
|
+
height: '16px',
|
|
10
|
+
borderLeftColor: token('color.border'),
|
|
11
|
+
borderLeftStyle: 'solid',
|
|
12
|
+
borderLeftWidth: token('border.width'),
|
|
13
|
+
marginLeft: token('space.050'),
|
|
14
|
+
marginRight: token('space.050'),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const ToolbarDivider = () => {
|
|
19
|
+
return <Box xcss={styles.divider} />;
|
|
20
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap, cx } from '@atlaskit/css';
|
|
4
|
+
import { DropdownItem } from '@atlaskit/dropdown-menu';
|
|
5
|
+
import { Box, Pressable } from '@atlaskit/primitives/compiled';
|
|
6
|
+
import { token } from '@atlaskit/tokens';
|
|
7
|
+
|
|
8
|
+
type TextStyle =
|
|
9
|
+
| 'normal'
|
|
10
|
+
| 'heading1'
|
|
11
|
+
| 'heading2'
|
|
12
|
+
| 'heading3'
|
|
13
|
+
| 'heading4'
|
|
14
|
+
| 'heading5'
|
|
15
|
+
| 'heading6';
|
|
16
|
+
|
|
17
|
+
const styles = cssMap({
|
|
18
|
+
toolbarDropdownItem: {
|
|
19
|
+
position: 'relative',
|
|
20
|
+
backgroundColor: token('color.background.neutral.subtle'),
|
|
21
|
+
width: '100%',
|
|
22
|
+
minHeight: '36px',
|
|
23
|
+
paddingLeft: token('space.150'),
|
|
24
|
+
paddingRight: token('space.150'),
|
|
25
|
+
|
|
26
|
+
'&:hover': {
|
|
27
|
+
backgroundColor: token('color.background.neutral.subtle.hovered'),
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
'&:active': {
|
|
31
|
+
backgroundColor: token('color.background.neutral.subtle.pressed'),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
selected: {
|
|
35
|
+
backgroundColor: token('color.background.selected'),
|
|
36
|
+
color: token('color.text.selected'),
|
|
37
|
+
|
|
38
|
+
'&:hover': {
|
|
39
|
+
backgroundColor: token('color.background.selected.hovered'),
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
'&:active': {
|
|
43
|
+
backgroundColor: token('color.background.selected.pressed'),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
normal: {
|
|
47
|
+
font: token('font.body'),
|
|
48
|
+
},
|
|
49
|
+
heading1: {
|
|
50
|
+
font: token('font.heading.xlarge'),
|
|
51
|
+
},
|
|
52
|
+
heading2: {
|
|
53
|
+
font: token('font.heading.large'),
|
|
54
|
+
},
|
|
55
|
+
heading3: {
|
|
56
|
+
font: token('font.heading.medium'),
|
|
57
|
+
},
|
|
58
|
+
heading4: {
|
|
59
|
+
font: token('font.heading.small'),
|
|
60
|
+
},
|
|
61
|
+
heading5: {
|
|
62
|
+
font: token('font.heading.xsmall'),
|
|
63
|
+
},
|
|
64
|
+
heading6: {
|
|
65
|
+
font: token('font.heading.xxsmall'),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
type ToolbarDropdownItemProps = {
|
|
70
|
+
onClick: () => void;
|
|
71
|
+
elemBefore?: ReactNode;
|
|
72
|
+
elemAfter?: ReactNode;
|
|
73
|
+
isSelected?: boolean;
|
|
74
|
+
children?: React.ReactNode;
|
|
75
|
+
textStyle?: TextStyle;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const ToolbarDropdownItem = ({
|
|
79
|
+
onClick,
|
|
80
|
+
elemBefore,
|
|
81
|
+
elemAfter,
|
|
82
|
+
isSelected,
|
|
83
|
+
children,
|
|
84
|
+
textStyle = 'normal',
|
|
85
|
+
}: ToolbarDropdownItemProps) => {
|
|
86
|
+
return (
|
|
87
|
+
<DropdownItem
|
|
88
|
+
onClick={onClick}
|
|
89
|
+
elemBefore={elemBefore}
|
|
90
|
+
elemAfter={elemAfter}
|
|
91
|
+
isSelected={isSelected}
|
|
92
|
+
component={({
|
|
93
|
+
children,
|
|
94
|
+
'data-testid': testId,
|
|
95
|
+
disabled,
|
|
96
|
+
draggable,
|
|
97
|
+
onClick,
|
|
98
|
+
onDragStart,
|
|
99
|
+
onMouseDown,
|
|
100
|
+
ref,
|
|
101
|
+
tabIndex,
|
|
102
|
+
}) => (
|
|
103
|
+
<Pressable
|
|
104
|
+
testId={testId}
|
|
105
|
+
xcss={cx(styles.toolbarDropdownItem, isSelected && styles.selected)}
|
|
106
|
+
isDisabled={disabled}
|
|
107
|
+
draggable={draggable}
|
|
108
|
+
onClick={onClick}
|
|
109
|
+
onDragStart={onDragStart}
|
|
110
|
+
onMouseDown={onMouseDown}
|
|
111
|
+
tabIndex={tabIndex}
|
|
112
|
+
ref={ref}
|
|
113
|
+
>
|
|
114
|
+
{children}
|
|
115
|
+
</Pressable>
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
<Box xcss={styles[textStyle]}>{children}</Box>
|
|
119
|
+
</DropdownItem>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import DropdownMenu from '@atlaskit/dropdown-menu';
|
|
4
|
+
|
|
5
|
+
import { type IconComponent, type ToolbarButtonGroupLocation } from '../types';
|
|
6
|
+
|
|
7
|
+
import { ToolbarButton } from './ToolbarButton';
|
|
8
|
+
|
|
9
|
+
type ToolbarDropdownMenuProps = {
|
|
10
|
+
icon: IconComponent;
|
|
11
|
+
label: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
groupLocation?: ToolbarButtonGroupLocation;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const ToolbarDropdownMenu = ({
|
|
17
|
+
icon,
|
|
18
|
+
label,
|
|
19
|
+
groupLocation,
|
|
20
|
+
children,
|
|
21
|
+
}: ToolbarDropdownMenuProps) => {
|
|
22
|
+
return (
|
|
23
|
+
<DropdownMenu<HTMLButtonElement>
|
|
24
|
+
trigger={(triggerProps) => (
|
|
25
|
+
<ToolbarButton
|
|
26
|
+
ref={triggerProps.triggerRef}
|
|
27
|
+
isSelected={triggerProps.isSelected}
|
|
28
|
+
aria-expanded={triggerProps['aria-expanded']}
|
|
29
|
+
aria-haspopup={triggerProps['aria-haspopup']}
|
|
30
|
+
aria-controls={triggerProps['aria-controls']}
|
|
31
|
+
onBlur={triggerProps.onBlur}
|
|
32
|
+
onClick={triggerProps.onClick}
|
|
33
|
+
onFocus={triggerProps.onFocus}
|
|
34
|
+
testId={triggerProps.testId}
|
|
35
|
+
icon={icon}
|
|
36
|
+
label={label}
|
|
37
|
+
groupLocation={groupLocation}
|
|
38
|
+
/>
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</DropdownMenu>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import Badge from '@atlaskit/badge';
|
|
4
|
+
|
|
5
|
+
type ToolbarKeyboardShortcutHintProps = {
|
|
6
|
+
shortcut: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const ToolbarKeyboardShortcutHint = ({ shortcut }: ToolbarKeyboardShortcutHintProps) => {
|
|
10
|
+
return <Badge>{shortcut}</Badge>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cssMap } from '@atlaskit/css';
|
|
4
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
5
|
+
|
|
6
|
+
const styles = cssMap({
|
|
7
|
+
container: {
|
|
8
|
+
display: 'flex',
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
type ToolbarSectionProps = {
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const ToolbarSection = ({ children }: ToolbarSectionProps) => {
|
|
18
|
+
return <Box xcss={styles.container}>{children}</Box>;
|
|
19
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { RovoIcon as RovoLogoIcon } from '@atlaskit/logo';
|
|
4
|
+
|
|
5
|
+
type AIChatIconProps = {
|
|
6
|
+
label: string;
|
|
7
|
+
testId?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const AIChatIcon = ({ label, testId }: AIChatIconProps) => (
|
|
11
|
+
<RovoLogoIcon label={label} testId={testId} size="small" appearance="neutral" />
|
|
12
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import Icon from '@atlaskit/icon/core/chevron-down';
|
|
4
|
+
|
|
5
|
+
import { type IconComponent } from '../../types';
|
|
6
|
+
|
|
7
|
+
export const MoreItemsIcon: IconComponent = ({
|
|
8
|
+
label,
|
|
9
|
+
testId,
|
|
10
|
+
color,
|
|
11
|
+
shouldRecommendSmallIcon,
|
|
12
|
+
spacing,
|
|
13
|
+
}) => (
|
|
14
|
+
<Icon
|
|
15
|
+
label={label}
|
|
16
|
+
testId={testId}
|
|
17
|
+
color={color}
|
|
18
|
+
shouldRecommendSmallIcon={shouldRecommendSmallIcon}
|
|
19
|
+
spacing={spacing}
|
|
20
|
+
size="small"
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
|
4
|
+
"exclude": [
|
|
5
|
+
"**/docs/**/*",
|
|
6
|
+
"**/__tests__/**/*",
|
|
7
|
+
"**/vr-tests/**/*",
|
|
8
|
+
"**/__perf__/**/*",
|
|
9
|
+
"**/*.test.*",
|
|
10
|
+
"**/test.*",
|
|
11
|
+
"**/test-*",
|
|
12
|
+
"**/examples.ts",
|
|
13
|
+
"**/examples.tsx",
|
|
14
|
+
"**/examples/*.ts",
|
|
15
|
+
"**/examples/*.tsx",
|
|
16
|
+
"**/examples/**/*.ts",
|
|
17
|
+
"**/examples/**/*.tsx",
|
|
18
|
+
"**/storybook/**/*",
|
|
19
|
+
"**/constellation/**/*",
|
|
20
|
+
".storybook/*",
|
|
21
|
+
"./__fixtures__/**/*",
|
|
22
|
+
"./__generated__/**/*",
|
|
23
|
+
"./mocks/**/*",
|
|
24
|
+
"./__mocks__/**/*",
|
|
25
|
+
"**/mock.*",
|
|
26
|
+
"**/codemods/**/*.ts",
|
|
27
|
+
"**/codemods/**/*.tsx"
|
|
28
|
+
],
|
|
29
|
+
"compilerOptions": {
|
|
30
|
+
"composite": true,
|
|
31
|
+
"outDir": "../../../tsDist/@atlaskit__editor-toolbar/app"
|
|
32
|
+
},
|
|
33
|
+
"references": [
|
|
34
|
+
{
|
|
35
|
+
"path": "../../design-system/badge/tsconfig.app.json"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "../../design-system/css/tsconfig.app.json"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "../../design-system/dropdown-menu/tsconfig.app.json"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "../../design-system/icon/tsconfig.app.json"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"path": "../../design-system/icon-lab/tsconfig.app.json"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"path": "../../design-system/logo/tsconfig.app.json"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"path": "../../design-system/popup/tsconfig.app.json"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": "../../design-system/primitives/tsconfig.app.json"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"path": "../../design-system/tokens/tsconfig.app.json"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"files": []
|
|
63
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"include": [
|
|
4
|
+
"**/docs/**/*",
|
|
5
|
+
"**/__tests__/**/*",
|
|
6
|
+
"**/vr-tests/**/*",
|
|
7
|
+
"**/__perf__/**/*",
|
|
8
|
+
"**/*.test.*",
|
|
9
|
+
"**/test.*",
|
|
10
|
+
"**/test-*",
|
|
11
|
+
"**/examples.ts",
|
|
12
|
+
"**/examples.tsx",
|
|
13
|
+
"**/examples/*.ts",
|
|
14
|
+
"**/examples/*.tsx",
|
|
15
|
+
"**/examples/**/*.ts",
|
|
16
|
+
"**/examples/**/*.tsx",
|
|
17
|
+
"**/storybook/**/*",
|
|
18
|
+
"**/constellation/**/*",
|
|
19
|
+
".storybook/*",
|
|
20
|
+
"./__fixtures__/**/*",
|
|
21
|
+
"./__generated__/**/*",
|
|
22
|
+
"./mocks/**/*",
|
|
23
|
+
"./__mocks__/**/*",
|
|
24
|
+
"**/mock.*",
|
|
25
|
+
"**/codemods/**/*.ts",
|
|
26
|
+
"**/codemods/**/*.tsx"
|
|
27
|
+
],
|
|
28
|
+
"exclude": ["./dist/**/*", "./build/**/*", "./node_modules/**/*"],
|
|
29
|
+
"compilerOptions": {
|
|
30
|
+
"composite": true,
|
|
31
|
+
"outDir": "../../../tsDist/@atlaskit__editor-toolbar/dev"
|
|
32
|
+
},
|
|
33
|
+
"references": [
|
|
34
|
+
{
|
|
35
|
+
"path": "./tsconfig.app.json"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "../../design-system/css/tsconfig.app.json"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "../../design-system/primitives/tsconfig.app.json"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "../../design-system/tokens/tsconfig.app.json"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|