@dxos/react-ui-editor 0.4.3-main.dda98d3 → 0.4.3-main.e5bbcda
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/dist/lib/browser/index.mjs +100 -91
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +3 -3
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -3
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts +3 -3
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts +3 -3
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +3 -3
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -3
- package/package.json +24 -24
- package/src/components/Toolbar/Toolbar.tsx +81 -69
- package/src/extensions/comments.ts +5 -2
- package/src/extensions/markdown/formatting.test.ts +1 -1
- package/src/extensions/markdown/formatting.ts +5 -2
- package/src/hooks/useActionHandler.ts +1 -1
- package/src/translations.ts +3 -3
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
TextHSix,
|
|
24
24
|
TextItalic,
|
|
25
25
|
Quotes,
|
|
26
|
-
CaretDown,
|
|
27
26
|
} from '@phosphor-icons/react';
|
|
28
27
|
import { createContext } from '@radix-ui/react-context';
|
|
29
28
|
import React, { type PropsWithChildren } from 'react';
|
|
@@ -65,7 +64,7 @@ export type ActionType =
|
|
|
65
64
|
| 'link'
|
|
66
65
|
| 'list-bullet'
|
|
67
66
|
| 'list-ordered'
|
|
68
|
-
| 'list-
|
|
67
|
+
| 'list-task'
|
|
69
68
|
| 'mention'
|
|
70
69
|
| 'prompt'
|
|
71
70
|
| 'strikethrough'
|
|
@@ -99,12 +98,17 @@ const ToolbarRoot = ({ children, onAction, classNames, state }: ToolbarProps) =>
|
|
|
99
98
|
);
|
|
100
99
|
};
|
|
101
100
|
|
|
102
|
-
|
|
101
|
+
const buttonStyles = 'min-bs-0 p-2';
|
|
102
|
+
const iconStyles = getSize(5);
|
|
103
|
+
|
|
104
|
+
type ButtonProps = {
|
|
105
|
+
type: ActionType;
|
|
103
106
|
Icon: Icon;
|
|
107
|
+
getState: (state: Formatting) => boolean;
|
|
108
|
+
disabled?: (state: Formatting) => boolean;
|
|
104
109
|
};
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
const iconStyles = getSize(4);
|
|
111
|
+
type ToolbarButtonProps = ToolbarToggleGroupItemProps & { Icon: Icon };
|
|
108
112
|
|
|
109
113
|
const ToolbarButton = ({ Icon, children, ...props }: ToolbarButtonProps) => {
|
|
110
114
|
return (
|
|
@@ -118,7 +122,7 @@ const ToolbarButton = ({ Icon, children, ...props }: ToolbarButtonProps) => {
|
|
|
118
122
|
const ToolbarSeparator = () => <div role='separator' className='grow' />;
|
|
119
123
|
|
|
120
124
|
const MarkdownHeading = () => {
|
|
121
|
-
const { t } = useTranslation(translationKey);
|
|
125
|
+
// const { t } = useTranslation(translationKey);
|
|
122
126
|
const { onAction, state } = useToolbarContext('MarkdownFormatting');
|
|
123
127
|
const blockType = state ? state.blockType : 'paragraph';
|
|
124
128
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
@@ -130,21 +134,30 @@ const MarkdownHeading = () => {
|
|
|
130
134
|
value={value ?? '0'}
|
|
131
135
|
onValueChange={(value) => onAction?.({ type: 'heading', data: parseInt(value) })}
|
|
132
136
|
>
|
|
133
|
-
<Select.
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
<Select.TriggerButton>
|
|
138
|
+
<HeadingIcon className={iconStyles} />
|
|
139
|
+
{/* TODO(burdon): Incorrectly positioned. */}
|
|
140
|
+
{/* <NaturalToolbar.Button variant='ghost' classNames={buttonStyles}> */}
|
|
141
|
+
{/* <span className='sr-only'>{t('heading label')}</span> */}
|
|
142
|
+
{/* <HeadingIcon className={iconStyles} /> */}
|
|
143
|
+
{/* <CaretDown className={getSize(2)} weight='bold' /> */}
|
|
144
|
+
{/* </NaturalToolbar.Button> */}
|
|
145
|
+
</Select.TriggerButton>
|
|
140
146
|
<Select.Portal>
|
|
141
147
|
<Select.Content>
|
|
142
148
|
<Select.ScrollUpButton />
|
|
143
149
|
<Select.Viewport>
|
|
144
|
-
<Select.Option value='0'>
|
|
150
|
+
<Select.Option value='0'>
|
|
151
|
+
<Paragraph className={iconStyles} />
|
|
152
|
+
</Select.Option>
|
|
145
153
|
{[1, 2, 3, 4, 5, 6].map((level) => (
|
|
146
154
|
<Select.Option key={level} value={String(level)}>
|
|
147
|
-
|
|
155
|
+
{level === 1 && <TextHOne className={iconStyles} />}
|
|
156
|
+
{level === 2 && <TextHTwo className={iconStyles} />}
|
|
157
|
+
{level === 3 && <TextHThree className={iconStyles} />}
|
|
158
|
+
{level === 4 && <TextHFour className={iconStyles} />}
|
|
159
|
+
{level === 5 && <TextHFive className={iconStyles} />}
|
|
160
|
+
{level === 6 && <TextHSix className={iconStyles} />}
|
|
148
161
|
</Select.Option>
|
|
149
162
|
))}
|
|
150
163
|
</Select.Viewport>
|
|
@@ -156,14 +169,12 @@ const MarkdownHeading = () => {
|
|
|
156
169
|
);
|
|
157
170
|
};
|
|
158
171
|
|
|
159
|
-
const markdownStyles = [
|
|
160
|
-
{
|
|
161
|
-
{
|
|
162
|
-
{
|
|
163
|
-
{
|
|
164
|
-
{
|
|
165
|
-
// <ToolbarButton Icon={At} title='Mention' onClick={() => ({ type: 'mention' })} />
|
|
166
|
-
// <ToolbarButton Icon={Image} title='Image' onClick={() => ({ type: 'image' })} />
|
|
172
|
+
const markdownStyles: ButtonProps[] = [
|
|
173
|
+
{ type: 'strong', Icon: TextB, getState: (state) => state.strong },
|
|
174
|
+
{ type: 'emphasis', Icon: TextItalic, getState: (state) => state.emphasis },
|
|
175
|
+
{ type: 'strikethrough', Icon: TextStrikethrough, getState: (state) => state.strikethrough },
|
|
176
|
+
{ type: 'code', Icon: Code, getState: (state) => state.code },
|
|
177
|
+
{ type: 'link', Icon: Link, getState: (state) => state.link },
|
|
167
178
|
];
|
|
168
179
|
|
|
169
180
|
const MarkdownStyles = () => {
|
|
@@ -173,27 +184,27 @@ const MarkdownStyles = () => {
|
|
|
173
184
|
return (
|
|
174
185
|
<NaturalToolbar.ToggleGroup
|
|
175
186
|
type='multiple'
|
|
176
|
-
value={markdownStyles.filter(({
|
|
187
|
+
value={markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
|
|
177
188
|
>
|
|
178
|
-
{markdownStyles.map(({
|
|
189
|
+
{markdownStyles.map(({ type, getState, Icon }) => (
|
|
179
190
|
<ToolbarButton
|
|
180
|
-
key={
|
|
181
|
-
value={
|
|
191
|
+
key={type}
|
|
192
|
+
value={type}
|
|
182
193
|
Icon={Icon}
|
|
183
194
|
disabled={state?.blockType === 'codeblock'}
|
|
184
|
-
onClick={() => onAction?.({ type
|
|
195
|
+
onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
|
|
185
196
|
>
|
|
186
|
-
{t(`${
|
|
197
|
+
{t(`${type} label`)}
|
|
187
198
|
</ToolbarButton>
|
|
188
199
|
))}
|
|
189
200
|
</NaturalToolbar.ToggleGroup>
|
|
190
201
|
);
|
|
191
202
|
};
|
|
192
203
|
|
|
193
|
-
const markdownLists = [
|
|
194
|
-
{
|
|
195
|
-
{
|
|
196
|
-
{
|
|
204
|
+
const markdownLists: ButtonProps[] = [
|
|
205
|
+
{ type: 'list-bullet', Icon: ListBullets, getState: (state) => state.listStyle === 'bullet' },
|
|
206
|
+
{ type: 'list-ordered', Icon: ListNumbers, getState: (state) => state.listStyle === 'ordered' },
|
|
207
|
+
{ type: 'list-task', Icon: ListChecks, getState: (state) => state.listStyle === 'task' },
|
|
197
208
|
];
|
|
198
209
|
|
|
199
210
|
const MarkdownLists = () => {
|
|
@@ -201,62 +212,58 @@ const MarkdownLists = () => {
|
|
|
201
212
|
const { t } = useTranslation(translationKey);
|
|
202
213
|
return (
|
|
203
214
|
<NaturalToolbar.ToggleGroup type='single' value={state?.listStyle ?? undefined}>
|
|
204
|
-
{markdownLists.map(({
|
|
215
|
+
{markdownLists.map(({ type, getState, Icon }) => (
|
|
205
216
|
<ToolbarButton
|
|
206
|
-
key={
|
|
207
|
-
value={
|
|
217
|
+
key={type}
|
|
218
|
+
value={type}
|
|
208
219
|
Icon={Icon}
|
|
209
|
-
onClick={() => onAction?.({ type
|
|
220
|
+
onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
|
|
210
221
|
>
|
|
211
|
-
{t(`${
|
|
222
|
+
{t(`${type} label`)}
|
|
212
223
|
</ToolbarButton>
|
|
213
224
|
))}
|
|
214
225
|
</NaturalToolbar.ToggleGroup>
|
|
215
226
|
);
|
|
216
227
|
};
|
|
217
228
|
|
|
218
|
-
const markdownBlocks = [
|
|
229
|
+
const markdownBlocks: ButtonProps[] = [
|
|
219
230
|
{
|
|
220
|
-
|
|
231
|
+
type: 'blockquote',
|
|
221
232
|
Icon: Quotes,
|
|
222
|
-
|
|
223
|
-
action: (state: Formatting | null) => ({ type: 'blockquote' as const, data: state ? !state.blockQuote : null }),
|
|
224
|
-
disabled: (state: Formatting | null) => false,
|
|
233
|
+
getState: (state) => state.blockQuote,
|
|
225
234
|
},
|
|
226
235
|
{
|
|
227
|
-
|
|
236
|
+
type: 'codeblock',
|
|
228
237
|
Icon: CodeBlock,
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
getState: (state) => state.blockQuote,
|
|
239
|
+
disabled: (state) => !state.blankLine,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
type: 'table',
|
|
243
|
+
Icon: Table,
|
|
244
|
+
getState: (state) => state.blockType === 'tablecell',
|
|
245
|
+
disabled: (state) => !state.blankLine,
|
|
232
246
|
},
|
|
233
247
|
];
|
|
234
248
|
|
|
235
249
|
const MarkdownBlocks = () => {
|
|
236
250
|
const { onAction, state } = useToolbarContext('MarkdownStyles');
|
|
237
251
|
const { t } = useTranslation(translationKey);
|
|
252
|
+
const value = markdownBlocks.find(({ getState }) => state && getState(state));
|
|
238
253
|
return (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
disabled={!state?.blankLine}
|
|
253
|
-
onClick={() => onAction?.({ type: 'table' })}
|
|
254
|
-
classNames={buttonStyles}
|
|
255
|
-
>
|
|
256
|
-
<Table className={iconStyles} />
|
|
257
|
-
<span className='sr-only'>{t('table label')}</span>
|
|
258
|
-
</NaturalToolbar.Button>
|
|
259
|
-
</>
|
|
254
|
+
<NaturalToolbar.ToggleGroup type='single' value={value?.type}>
|
|
255
|
+
{markdownBlocks.map(({ type, disabled, getState, Icon }) => (
|
|
256
|
+
<ToolbarButton
|
|
257
|
+
key={type}
|
|
258
|
+
value={type}
|
|
259
|
+
Icon={Icon}
|
|
260
|
+
disabled={!state || disabled?.(state)}
|
|
261
|
+
onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
|
|
262
|
+
>
|
|
263
|
+
{t(`${type} label`)}
|
|
264
|
+
</ToolbarButton>
|
|
265
|
+
))}
|
|
266
|
+
</NaturalToolbar.ToggleGroup>
|
|
260
267
|
);
|
|
261
268
|
};
|
|
262
269
|
|
|
@@ -273,7 +280,12 @@ const MarkdownExtended = () => {
|
|
|
273
280
|
const { onAction } = useToolbarContext('MarkdownStyles');
|
|
274
281
|
const { t } = useTranslation(translationKey);
|
|
275
282
|
return (
|
|
276
|
-
<NaturalToolbar.Button
|
|
283
|
+
<NaturalToolbar.Button
|
|
284
|
+
variant='ghost'
|
|
285
|
+
data-testid='editor.toolbar.comment'
|
|
286
|
+
onClick={() => onAction?.({ type: 'comment' })}
|
|
287
|
+
classNames={buttonStyles}
|
|
288
|
+
>
|
|
277
289
|
<ChatText className={iconStyles} />
|
|
278
290
|
<span className='sr-only'>{t('comment label')}</span>
|
|
279
291
|
</NaturalToolbar.Button>
|
|
@@ -36,8 +36,11 @@ const styles = EditorView.baseTheme({
|
|
|
36
36
|
},
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
const commentMark = Decoration.mark({ class: 'cm-comment' });
|
|
40
|
-
const commentCurrentMark = Decoration.mark({
|
|
39
|
+
const commentMark = Decoration.mark({ class: 'cm-comment', attributes: { 'data-testid': 'cm-comment' } });
|
|
40
|
+
const commentCurrentMark = Decoration.mark({
|
|
41
|
+
class: 'cm-comment-current',
|
|
42
|
+
attributes: { 'data-testid': 'cm-comment' },
|
|
43
|
+
});
|
|
41
44
|
|
|
42
45
|
type CommentState = {
|
|
43
46
|
comment: Comment;
|
|
@@ -370,7 +370,7 @@ describe('removeBlockquote', () => {
|
|
|
370
370
|
});
|
|
371
371
|
|
|
372
372
|
describe('addCodeblock', () => {
|
|
373
|
-
testCommand('add a code block to a blank line', '{}', addCodeblock, '```{}\n
|
|
373
|
+
testCommand('add a code block to a blank line', '{}', addCodeblock, '```{}\n```');
|
|
374
374
|
|
|
375
375
|
testCommand(
|
|
376
376
|
'can turn a paragraph into a code block',
|
|
@@ -356,7 +356,6 @@ const snippets = {
|
|
|
356
356
|
[
|
|
357
357
|
//
|
|
358
358
|
'```#{}',
|
|
359
|
-
'#{}',
|
|
360
359
|
'```',
|
|
361
360
|
].join('\n'),
|
|
362
361
|
),
|
|
@@ -515,6 +514,7 @@ export const addLink: StateCommand = ({ state, dispatch }) => {
|
|
|
515
514
|
// Lists
|
|
516
515
|
//
|
|
517
516
|
|
|
517
|
+
// TODO(burdon): Cursor is positioned incorrectly.
|
|
518
518
|
export const addList =
|
|
519
519
|
(type: List): StateCommand =>
|
|
520
520
|
({ state, dispatch }) => {
|
|
@@ -576,18 +576,21 @@ export const addList =
|
|
|
576
576
|
// Insert a new list item if the selection is empty.
|
|
577
577
|
const { from, to } = state.doc.lineAt(state.selection.main.anchor);
|
|
578
578
|
if (from === to) {
|
|
579
|
+
const insert = type === List.Bullet ? '- ' : type === List.Ordered ? '1. ' : '- [ ] ';
|
|
579
580
|
dispatch(
|
|
580
581
|
state.update({
|
|
581
582
|
changes: [
|
|
582
583
|
{
|
|
583
584
|
from,
|
|
584
|
-
insert
|
|
585
|
+
insert,
|
|
585
586
|
},
|
|
586
587
|
],
|
|
588
|
+
selection: { anchor: from + insert.length },
|
|
587
589
|
userEvent: 'format.list.add',
|
|
588
590
|
scrollIntoView: true,
|
|
589
591
|
}),
|
|
590
592
|
);
|
|
593
|
+
|
|
591
594
|
return true;
|
|
592
595
|
}
|
|
593
596
|
|
|
@@ -54,7 +54,7 @@ export const useActionHandler = (view?: EditorView | null): ToolbarProps['onActi
|
|
|
54
54
|
|
|
55
55
|
case 'list-ordered':
|
|
56
56
|
case 'list-bullet':
|
|
57
|
-
case 'list-
|
|
57
|
+
case 'list-task':
|
|
58
58
|
listType =
|
|
59
59
|
action.type === 'list-ordered' ? List.Ordered : action.type === 'list-bullet' ? List.Bullet : List.Task;
|
|
60
60
|
(action.data === false
|
package/src/translations.ts
CHANGED
|
@@ -12,9 +12,9 @@ export default [
|
|
|
12
12
|
'emphasis label': 'Emphasis',
|
|
13
13
|
'strikethrough label': 'Strike-through',
|
|
14
14
|
'code label': 'Code',
|
|
15
|
-
'bullet label': 'Bullet list',
|
|
16
|
-
'ordered label': 'Numbered list',
|
|
17
|
-
'task label': 'Task list',
|
|
15
|
+
'list-bullet label': 'Bullet list',
|
|
16
|
+
'list-ordered label': 'Numbered list',
|
|
17
|
+
'list-task label': 'Task list',
|
|
18
18
|
'blockquote label': 'Block quote',
|
|
19
19
|
'codeblock label': 'Code block',
|
|
20
20
|
'comment label': 'Create comment',
|