Skip to content

Commit 613bc18

Browse files
committed
feat: Wrap selected text in parens, brackets, or quotes.
1 parent b055e11 commit 613bc18

File tree

3 files changed

+235
-2
lines changed

3 files changed

+235
-2
lines changed

src/SelectionText.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class SelectionText {
5252
str.replace(/(^(\s)+)/, (str, old) => (indent = old));
5353
return indent;
5454
}
55-
lineStarInstert(text: string = '') {
55+
lineStarInstert(text: string) {
5656
if (text) {
5757
const oldStart = this.start;
5858
const start = this.getLineStartNumber();
@@ -68,7 +68,7 @@ export class SelectionText {
6868
}
6969
return this;
7070
}
71-
lineStarRemove(text: string = '') {
71+
lineStarRemove(text: string) {
7272
if (text) {
7373
const oldStart = this.start;
7474
const start = this.getLineStartNumber();

src/__test__/index.test.tsx

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,203 @@ it('TextareaCodeEditor onKeyDown Enter Input', async () => {
284284
});
285285
}
286286
});
287+
288+
it('TextareaCodeEditor onKeyDown Input `()`', async () => {
289+
const example = `/** Hello Wold **/`;
290+
const expected = `/** (Hello) Wold **/`;
291+
const {
292+
container: { firstChild },
293+
} = render(
294+
<TextareaCodeEditor
295+
language="js"
296+
data-testid="textarea"
297+
autoFocus
298+
value={example}
299+
onKeyDown={(evn) => {
300+
expect(evn.code.toLowerCase()).toEqual('digit9');
301+
expect((evn.target as any).value).toEqual(expected);
302+
}}
303+
/>,
304+
);
305+
306+
if (firstChild && firstChild.firstChild) {
307+
(firstChild.firstChild as any).setSelectionRange(4, 9);
308+
fireEvent.keyDown(firstChild.firstChild, {
309+
key: '(',
310+
code: 'Digit9',
311+
charCode: 57,
312+
shiftKey: true,
313+
});
314+
}
315+
});
316+
317+
it('TextareaCodeEditor onKeyDown Input `<>`', async () => {
318+
const example = `/** Hello Wold **/`;
319+
const expected = `/** <Hello> Wold **/`;
320+
const {
321+
container: { firstChild },
322+
} = render(
323+
<TextareaCodeEditor
324+
language="js"
325+
data-testid="textarea"
326+
autoFocus
327+
value={example}
328+
onKeyDown={(evn) => {
329+
expect(evn.code.toLowerCase()).toEqual('comma');
330+
expect((evn.target as any).value).toEqual(expected);
331+
}}
332+
/>,
333+
);
334+
335+
if (firstChild && firstChild.firstChild) {
336+
(firstChild.firstChild as any).setSelectionRange(4, 9);
337+
fireEvent.keyDown(firstChild.firstChild, {
338+
key: '<',
339+
code: 'Comma',
340+
charCode: 188,
341+
shiftKey: true,
342+
});
343+
}
344+
});
345+
346+
it('TextareaCodeEditor onKeyDown Input `[]`', async () => {
347+
const example = `/** Hello Wold **/`;
348+
const expected = `/** [Hello] Wold **/`;
349+
const {
350+
container: { firstChild },
351+
} = render(
352+
<TextareaCodeEditor
353+
language="js"
354+
data-testid="textarea"
355+
autoFocus
356+
value={example}
357+
onKeyDown={(evn) => {
358+
expect(evn.code.toLowerCase()).toEqual('bracketleft');
359+
expect((evn.target as any).value).toEqual(expected);
360+
}}
361+
/>,
362+
);
363+
364+
if (firstChild && firstChild.firstChild) {
365+
(firstChild.firstChild as any).setSelectionRange(4, 9);
366+
fireEvent.keyDown(firstChild.firstChild, {
367+
key: '[',
368+
code: 'BracketLeft',
369+
charCode: 219,
370+
});
371+
}
372+
});
373+
374+
it('TextareaCodeEditor onKeyDown Input `{}`', async () => {
375+
const example = `/** Hello Wold **/`;
376+
const expected = `/** {Hello} Wold **/`;
377+
const {
378+
container: { firstChild },
379+
} = render(
380+
<TextareaCodeEditor
381+
language="js"
382+
data-testid="textarea"
383+
autoFocus
384+
value={example}
385+
onKeyDown={(evn) => {
386+
expect(evn.code.toLowerCase()).toEqual('bracketleft');
387+
expect((evn.target as any).value).toEqual(expected);
388+
}}
389+
/>,
390+
);
391+
392+
if (firstChild && firstChild.firstChild) {
393+
(firstChild.firstChild as any).setSelectionRange(4, 9);
394+
fireEvent.keyDown(firstChild.firstChild, {
395+
key: '{',
396+
code: 'BracketLeft',
397+
charCode: 219,
398+
shiftKey: true,
399+
});
400+
}
401+
});
402+
403+
it("TextareaCodeEditor onKeyDown Input `''`", async () => {
404+
const example = `/** Hello Wold **/`;
405+
const expected = `/** 'Hello' Wold **/`;
406+
const {
407+
container: { firstChild },
408+
} = render(
409+
<TextareaCodeEditor
410+
language="js"
411+
data-testid="textarea"
412+
autoFocus
413+
value={example}
414+
onKeyDown={(evn) => {
415+
expect(evn.code.toLowerCase()).toEqual('quote');
416+
expect((evn.target as any).value).toEqual(expected);
417+
}}
418+
/>,
419+
);
420+
421+
if (firstChild && firstChild.firstChild) {
422+
(firstChild.firstChild as any).setSelectionRange(4, 9);
423+
fireEvent.keyDown(firstChild.firstChild, {
424+
key: "'",
425+
code: 'Quote',
426+
charCode: 222,
427+
});
428+
}
429+
});
430+
431+
it('TextareaCodeEditor onKeyDown Input `""`', async () => {
432+
const example = `/** Hello Wold **/`;
433+
const expected = `/** "Hello" Wold **/`;
434+
const {
435+
container: { firstChild },
436+
} = render(
437+
<TextareaCodeEditor
438+
language="js"
439+
data-testid="textarea"
440+
autoFocus
441+
value={example}
442+
onKeyDown={(evn) => {
443+
expect(evn.code.toLowerCase()).toEqual('quote');
444+
expect((evn.target as any).value).toEqual(expected);
445+
}}
446+
/>,
447+
);
448+
449+
if (firstChild && firstChild.firstChild) {
450+
(firstChild.firstChild as any).setSelectionRange(4, 9);
451+
fireEvent.keyDown(firstChild.firstChild, {
452+
key: '"',
453+
code: 'Quote',
454+
charCode: 222,
455+
shiftKey: true,
456+
});
457+
}
458+
});
459+
460+
it('TextareaCodeEditor onKeyDown Input ``', async () => {
461+
const example = `/** Hello Wold **/`;
462+
const expected = `/** \`Hello\` Wold **/`;
463+
const {
464+
container: { firstChild },
465+
} = render(
466+
<TextareaCodeEditor
467+
language="js"
468+
data-testid="textarea"
469+
autoFocus
470+
value={example}
471+
onKeyDown={(evn) => {
472+
expect(evn.code.toLowerCase()).toEqual('backquote');
473+
expect((evn.target as any).value).toEqual(expected);
474+
}}
475+
/>,
476+
);
477+
478+
if (firstChild && firstChild.firstChild) {
479+
(firstChild.firstChild as any).setSelectionRange(4, 9);
480+
fireEvent.keyDown(firstChild.firstChild, {
481+
key: '`',
482+
code: 'Backquote',
483+
charCode: 192,
484+
});
485+
}
486+
});

src/shortcuts.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,38 @@ export default function shortcuts(e: React.KeyboardEvent<HTMLTextAreaElement>) {
2020
const indent = `\n${api.getIndentText()}`;
2121
api.insertText(indent).position(api.start + indent.length, api.start + indent.length);
2222
api.notifyChange();
23+
} else if (
24+
e.code &&
25+
/^(quote|backquote|bracketleft|digit9|comma)$/.test(e.code.toLowerCase()) &&
26+
api.getSelectedValue()
27+
) {
28+
stopPropagation(e);
29+
const val = api.getSelectedValue();
30+
let txt = '';
31+
switch (e.code.toLowerCase()) {
32+
case 'quote':
33+
txt = `'${val}'`;
34+
if (e.shiftKey) {
35+
txt = `"${val}"`;
36+
}
37+
break;
38+
case 'backquote':
39+
txt = `\`${val}\``;
40+
break;
41+
case 'bracketleft':
42+
txt = `[${val}]`;
43+
if (e.shiftKey) {
44+
txt = `{${val}}`;
45+
}
46+
break;
47+
case 'digit9':
48+
txt = `(${val})`;
49+
break;
50+
case 'comma':
51+
txt = `<${val}>`;
52+
break;
53+
}
54+
api.insertText(txt);
55+
api.notifyChange();
2356
}
2457
}

0 commit comments

Comments
 (0)