@dxos/react-ui-editor 0.4.3-main.97fc241 → 0.4.3-main.aa1c078
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 +89 -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/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 +68 -75
- package/src/extensions/markdown/formatting.test.ts +1 -1
- package/src/extensions/markdown/formatting.ts +2 -5
- package/src/hooks/useActionHandler.ts +1 -1
- package/src/translations.ts +3 -3
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
TextHSix,
|
|
24
24
|
TextItalic,
|
|
25
25
|
Quotes,
|
|
26
|
+
CaretDown,
|
|
26
27
|
} from '@phosphor-icons/react';
|
|
27
28
|
import { createContext } from '@radix-ui/react-context';
|
|
28
29
|
import React, { type PropsWithChildren } from 'react';
|
|
@@ -64,7 +65,7 @@ export type ActionType =
|
|
|
64
65
|
| 'link'
|
|
65
66
|
| 'list-bullet'
|
|
66
67
|
| 'list-ordered'
|
|
67
|
-
| 'list-
|
|
68
|
+
| 'list-tasks'
|
|
68
69
|
| 'mention'
|
|
69
70
|
| 'prompt'
|
|
70
71
|
| 'strikethrough'
|
|
@@ -98,17 +99,12 @@ const ToolbarRoot = ({ children, onAction, classNames, state }: ToolbarProps) =>
|
|
|
98
99
|
);
|
|
99
100
|
};
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
const iconStyles = getSize(5);
|
|
103
|
-
|
|
104
|
-
type ButtonProps = {
|
|
105
|
-
type: ActionType;
|
|
102
|
+
type ToolbarButtonProps = ToolbarToggleGroupItemProps & {
|
|
106
103
|
Icon: Icon;
|
|
107
|
-
getState: (state: Formatting) => boolean;
|
|
108
|
-
disabled?: (state: Formatting) => boolean;
|
|
109
104
|
};
|
|
110
105
|
|
|
111
|
-
|
|
106
|
+
const buttonStyles = 'min-bs-0 p-2';
|
|
107
|
+
const iconStyles = getSize(4);
|
|
112
108
|
|
|
113
109
|
const ToolbarButton = ({ Icon, children, ...props }: ToolbarButtonProps) => {
|
|
114
110
|
return (
|
|
@@ -122,7 +118,7 @@ const ToolbarButton = ({ Icon, children, ...props }: ToolbarButtonProps) => {
|
|
|
122
118
|
const ToolbarSeparator = () => <div role='separator' className='grow' />;
|
|
123
119
|
|
|
124
120
|
const MarkdownHeading = () => {
|
|
125
|
-
|
|
121
|
+
const { t } = useTranslation(translationKey);
|
|
126
122
|
const { onAction, state } = useToolbarContext('MarkdownFormatting');
|
|
127
123
|
const blockType = state ? state.blockType : 'paragraph';
|
|
128
124
|
const header = blockType && /heading(\d)/.exec(blockType);
|
|
@@ -134,30 +130,21 @@ const MarkdownHeading = () => {
|
|
|
134
130
|
value={value ?? '0'}
|
|
135
131
|
onValueChange={(value) => onAction?.({ type: 'heading', data: parseInt(value) })}
|
|
136
132
|
>
|
|
137
|
-
<Select.
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{/* </NaturalToolbar.Button> */}
|
|
145
|
-
</Select.TriggerButton>
|
|
133
|
+
<Select.Trigger asChild>
|
|
134
|
+
<NaturalToolbar.Button variant='ghost' classNames={buttonStyles}>
|
|
135
|
+
<span className='sr-only'>{t('heading label')}</span>
|
|
136
|
+
<HeadingIcon className={iconStyles} />
|
|
137
|
+
<CaretDown className={getSize(2)} weight='bold' />
|
|
138
|
+
</NaturalToolbar.Button>
|
|
139
|
+
</Select.Trigger>
|
|
146
140
|
<Select.Portal>
|
|
147
141
|
<Select.Content>
|
|
148
142
|
<Select.ScrollUpButton />
|
|
149
143
|
<Select.Viewport>
|
|
150
|
-
<Select.Option value='0'>
|
|
151
|
-
<Paragraph className={iconStyles} />
|
|
152
|
-
</Select.Option>
|
|
144
|
+
<Select.Option value='0'>Paragraph</Select.Option>
|
|
153
145
|
{[1, 2, 3, 4, 5, 6].map((level) => (
|
|
154
146
|
<Select.Option key={level} value={String(level)}>
|
|
155
|
-
{level
|
|
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} />}
|
|
147
|
+
Heading {level}
|
|
161
148
|
</Select.Option>
|
|
162
149
|
))}
|
|
163
150
|
</Select.Viewport>
|
|
@@ -169,12 +156,14 @@ const MarkdownHeading = () => {
|
|
|
169
156
|
);
|
|
170
157
|
};
|
|
171
158
|
|
|
172
|
-
const markdownStyles
|
|
173
|
-
{
|
|
174
|
-
{
|
|
175
|
-
{
|
|
176
|
-
{
|
|
177
|
-
{
|
|
159
|
+
const markdownStyles = [
|
|
160
|
+
{ key: 'strong' as const, Icon: TextB },
|
|
161
|
+
{ key: 'emphasis' as const, Icon: TextItalic },
|
|
162
|
+
{ key: 'strikethrough' as const, Icon: TextStrikethrough },
|
|
163
|
+
{ key: 'code' as const, Icon: Code },
|
|
164
|
+
{ key: 'link' as const, Icon: Link },
|
|
165
|
+
// <ToolbarButton Icon={At} title='Mention' onClick={() => ({ type: 'mention' })} />
|
|
166
|
+
// <ToolbarButton Icon={Image} title='Image' onClick={() => ({ type: 'image' })} />
|
|
178
167
|
];
|
|
179
168
|
|
|
180
169
|
const MarkdownStyles = () => {
|
|
@@ -184,27 +173,27 @@ const MarkdownStyles = () => {
|
|
|
184
173
|
return (
|
|
185
174
|
<NaturalToolbar.ToggleGroup
|
|
186
175
|
type='multiple'
|
|
187
|
-
value={markdownStyles.filter(({
|
|
176
|
+
value={markdownStyles.filter(({ key }) => !!state?.[key]).map(({ key }) => key)}
|
|
188
177
|
>
|
|
189
|
-
{markdownStyles.map(({
|
|
178
|
+
{markdownStyles.map(({ key, Icon }) => (
|
|
190
179
|
<ToolbarButton
|
|
191
|
-
key={
|
|
192
|
-
value={
|
|
180
|
+
key={key}
|
|
181
|
+
value={key}
|
|
193
182
|
Icon={Icon}
|
|
194
183
|
disabled={state?.blockType === 'codeblock'}
|
|
195
|
-
onClick={
|
|
184
|
+
onClick={() => onAction?.({ type: key, data: state ? !state[key] : null })}
|
|
196
185
|
>
|
|
197
|
-
{t(`${
|
|
186
|
+
{t(`${key} label`)}
|
|
198
187
|
</ToolbarButton>
|
|
199
188
|
))}
|
|
200
189
|
</NaturalToolbar.ToggleGroup>
|
|
201
190
|
);
|
|
202
191
|
};
|
|
203
192
|
|
|
204
|
-
const markdownLists
|
|
205
|
-
{
|
|
206
|
-
{
|
|
207
|
-
{
|
|
193
|
+
const markdownLists = [
|
|
194
|
+
{ key: 'bullet' as const, Icon: ListBullets, actionType: 'list-bullet' as const },
|
|
195
|
+
{ key: 'ordered' as const, Icon: ListNumbers, actionType: 'list-ordered' as const },
|
|
196
|
+
{ key: 'task' as const, Icon: ListChecks, actionType: 'list-tasks' as const },
|
|
208
197
|
];
|
|
209
198
|
|
|
210
199
|
const MarkdownLists = () => {
|
|
@@ -212,58 +201,62 @@ const MarkdownLists = () => {
|
|
|
212
201
|
const { t } = useTranslation(translationKey);
|
|
213
202
|
return (
|
|
214
203
|
<NaturalToolbar.ToggleGroup type='single' value={state?.listStyle ?? undefined}>
|
|
215
|
-
{markdownLists.map(({
|
|
204
|
+
{markdownLists.map(({ key, Icon, actionType }) => (
|
|
216
205
|
<ToolbarButton
|
|
217
|
-
key={
|
|
218
|
-
value={
|
|
206
|
+
key={key}
|
|
207
|
+
value={key}
|
|
219
208
|
Icon={Icon}
|
|
220
|
-
onClick={
|
|
209
|
+
onClick={() => onAction?.({ type: actionType, data: state ? state.listStyle !== key : null })}
|
|
221
210
|
>
|
|
222
|
-
{t(`${
|
|
211
|
+
{t(`${key} label`)}
|
|
223
212
|
</ToolbarButton>
|
|
224
213
|
))}
|
|
225
214
|
</NaturalToolbar.ToggleGroup>
|
|
226
215
|
);
|
|
227
216
|
};
|
|
228
217
|
|
|
229
|
-
const markdownBlocks
|
|
218
|
+
const markdownBlocks = [
|
|
230
219
|
{
|
|
231
|
-
|
|
220
|
+
key: 'blockquote' as const,
|
|
232
221
|
Icon: Quotes,
|
|
233
|
-
|
|
222
|
+
pressed: (state: Formatting | null) => state?.blockQuote,
|
|
223
|
+
action: (state: Formatting | null) => ({ type: 'blockquote' as const, data: state ? !state.blockQuote : null }),
|
|
224
|
+
disabled: (state: Formatting | null) => false,
|
|
234
225
|
},
|
|
235
226
|
{
|
|
236
|
-
|
|
227
|
+
key: 'codeblock' as const,
|
|
237
228
|
Icon: CodeBlock,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
{
|
|
242
|
-
type: 'table',
|
|
243
|
-
Icon: Table,
|
|
244
|
-
getState: (state) => state.blockType === 'tablecell',
|
|
245
|
-
disabled: (state) => !state.blankLine,
|
|
229
|
+
pressed: (state: Formatting | null) => state?.blockType === 'codeblock',
|
|
230
|
+
action: (state: Formatting | null) => ({ type: 'blockquote' as const, data: state ? !state.blockQuote : null }),
|
|
231
|
+
disabled: (state: Formatting | null) => !state?.blankLine,
|
|
246
232
|
},
|
|
247
233
|
];
|
|
248
234
|
|
|
249
235
|
const MarkdownBlocks = () => {
|
|
250
236
|
const { onAction, state } = useToolbarContext('MarkdownStyles');
|
|
251
237
|
const { t } = useTranslation(translationKey);
|
|
252
|
-
const value = markdownBlocks.find(({ getState }) => state && getState(state));
|
|
253
238
|
return (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
239
|
+
<>
|
|
240
|
+
<NaturalToolbar.ToggleGroup
|
|
241
|
+
type='multiple'
|
|
242
|
+
value={markdownBlocks.filter(({ pressed }) => pressed(state)).map(({ key }) => key)}
|
|
243
|
+
>
|
|
244
|
+
{markdownBlocks.map(({ key, Icon, action }) => (
|
|
245
|
+
<ToolbarButton key={key} value={key} Icon={Icon} onClick={() => onAction?.(action(state))}>
|
|
246
|
+
{t(`${key} label`)}
|
|
247
|
+
</ToolbarButton>
|
|
248
|
+
))}
|
|
249
|
+
</NaturalToolbar.ToggleGroup>
|
|
250
|
+
<NaturalToolbar.Button
|
|
251
|
+
variant='ghost'
|
|
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
|
+
</>
|
|
267
260
|
);
|
|
268
261
|
};
|
|
269
262
|
|
|
@@ -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\n```');
|
|
374
374
|
|
|
375
375
|
testCommand(
|
|
376
376
|
'can turn a paragraph into a code block',
|
|
@@ -356,6 +356,7 @@ const snippets = {
|
|
|
356
356
|
[
|
|
357
357
|
//
|
|
358
358
|
'```#{}',
|
|
359
|
+
'#{}',
|
|
359
360
|
'```',
|
|
360
361
|
].join('\n'),
|
|
361
362
|
),
|
|
@@ -514,7 +515,6 @@ export const addLink: StateCommand = ({ state, dispatch }) => {
|
|
|
514
515
|
// Lists
|
|
515
516
|
//
|
|
516
517
|
|
|
517
|
-
// TODO(burdon): Cursor is positioned incorrectly.
|
|
518
518
|
export const addList =
|
|
519
519
|
(type: List): StateCommand =>
|
|
520
520
|
({ state, dispatch }) => {
|
|
@@ -576,21 +576,18 @@ 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. ' : '- [ ] ';
|
|
580
579
|
dispatch(
|
|
581
580
|
state.update({
|
|
582
581
|
changes: [
|
|
583
582
|
{
|
|
584
583
|
from,
|
|
585
|
-
insert,
|
|
584
|
+
insert: type === List.Bullet ? '- ' : type === List.Ordered ? '1. ' : '- [ ] ',
|
|
586
585
|
},
|
|
587
586
|
],
|
|
588
|
-
selection: { anchor: from + insert.length },
|
|
589
587
|
userEvent: 'format.list.add',
|
|
590
588
|
scrollIntoView: true,
|
|
591
589
|
}),
|
|
592
590
|
);
|
|
593
|
-
|
|
594
591
|
return true;
|
|
595
592
|
}
|
|
596
593
|
|
|
@@ -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-tasks':
|
|
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
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
15
|
+
'bullet label': 'Bullet list',
|
|
16
|
+
'ordered label': 'Numbered list',
|
|
17
|
+
'task label': 'Task list',
|
|
18
18
|
'blockquote label': 'Block quote',
|
|
19
19
|
'codeblock label': 'Code block',
|
|
20
20
|
'comment label': 'Create comment',
|