Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/markups/src/blocks/OrderedListBlock.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import InlineElements from '../elements/InlineElements';
import { listStyles } from './blocks.styles';

const OrderedListBlock = ({ items }) => (
<ol>
<ol css={listStyles}>
{items.map((item, index) => (
<li key={index} value={item.number}>
<InlineElements contents={item.value} />
Expand Down
3 changes: 2 additions & 1 deletion packages/markups/src/blocks/UnOrderedListBlock.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import InlineElements from '../elements/InlineElements';
import { listStyles } from './blocks.styles';

const UnOrderedListBlock = ({ items }) => (
<ul>
<ul css={listStyles}>
{items.map((item, index) => (
<li key={index}>
<InlineElements contents={item.value} />
Expand Down
5 changes: 5 additions & 0 deletions packages/markups/src/blocks/blocks.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ export const TaskListBlockStyles = {
gap: 0.5em;
`,
};

export const listStyles = css`
padding-left: 1.5em;
margin: 0;
`;
20 changes: 20 additions & 0 deletions packages/react/src/lib/insertListPrefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const insertListPrefix = (messageRef, listPrefix) => {
const input = messageRef.current;
if (!input) return;

const { selectionStart, value } = input;
const before = value.slice(0, selectionStart);
const after = value.slice(selectionStart);

const needsNewline = before.length > 0 && !before.endsWith('\n');
const prefix = listPrefix(1);
const insert = (needsNewline ? '\n' : '') + prefix;

input.value = before + insert + after;
const cursorPos = selectionStart + insert.length;
input.selectionStart = cursorPos;
input.selectionEnd = cursorPos;
input.focus();
};

export default insertListPrefix;
12 changes: 12 additions & 0 deletions packages/react/src/lib/textFormat.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,16 @@ export const formatter = [
pattern: '```\n{{text}}\n```',
tooltip: 'Multi-line code',
},
{
name: 'list-numbers',
type: 'list',
listPrefix: (n) => `${n}. `,
tooltip: 'Ordered list',
},
{
name: 'list-bullets',
type: 'list',
listPrefix: () => '- ',
tooltip: 'Unordered list',
},
];
45 changes: 43 additions & 2 deletions packages/react/src/views/ChatInput/ChatInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,10 +449,51 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
formatSelection(messageRef, '*{{text}}*');
break;
}
case (e.ctrlKey || e.metaKey || e.shiftKey) && e.code === 'Enter':
case (e.ctrlKey || e.metaKey || e.shiftKey) && e.code === 'Enter': {
e.preventDefault();
handleNewLine(e);
const input = messageRef.current;
const { value, selectionStart } = input;
const textBefore = value.slice(0, selectionStart);
const currentLine = textBefore.split('\n').pop();
// Match numbered list: "1. ", "2. ", etc.
const olMatch = currentLine.match(/^(\d+)\.\s/);
// Match bullet list: "- "
const ulMatch = currentLine.match(/^-\s/);

if (olMatch && currentLine.trim() === `${olMatch[1]}.`) {
const lineStart = selectionStart - currentLine.length;
const rest = value.slice(selectionStart);
input.value = value.slice(0, lineStart) + rest;
input.selectionStart = lineStart;
input.selectionEnd = lineStart;
handleNewLine(e, false);
} else if (ulMatch && currentLine.trim() === '-') {
const lineStart = selectionStart - currentLine.length;
const rest = value.slice(selectionStart);
input.value = value.slice(0, lineStart) + rest;
input.selectionStart = lineStart;
input.selectionEnd = lineStart;
handleNewLine(e, false);
} else if (olMatch) {
const nextNum = parseInt(olMatch[1], 10) + 1;
const prefix = `\n${nextNum}. `;
const after = value.slice(selectionStart);
input.value = textBefore + prefix + after;
input.selectionStart = selectionStart + prefix.length;
input.selectionEnd = selectionStart + prefix.length;
handleNewLine(e, false);
} else if (ulMatch) {
const prefix = '\n- ';
const after = value.slice(selectionStart);
input.value = textBefore + prefix + after;
input.selectionStart = selectionStart + prefix.length;
input.selectionEnd = selectionStart + prefix.length;
handleNewLine(e, false);
} else {
handleNewLine(e);
}
break;
}
case e.code === 'Escape':
if (editMessage.msg || editMessage.attachments) {
e.preventDefault();
Expand Down
23 changes: 17 additions & 6 deletions packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import AudioMessageRecorder from './AudioMessageRecorder';
import VideoMessageRecorder from './VideoMessageRecoder';
import { getChatInputFormattingToolbarStyles } from './ChatInput.styles';
import formatSelection from '../../lib/formatSelection';
import insertListPrefix from '../../lib/insertListPrefix';
import InsertLinkToolBox from './InsertLinkToolBox';

const ChatInputFormattingToolbar = ({
Expand All @@ -23,7 +24,15 @@ const ChatInputFormattingToolbar = ({
triggerButton,
optionConfig = {
surfaceItems: ['emoji', 'formatter', 'link', 'audio', 'video', 'file'],
formatters: ['bold', 'italic', 'strike', 'code', 'multiline'],
formatters: [
'bold',
'italic',
'strike',
'code',
'multiline',
'list-numbers',
'list-bullets',
],
smallScreenSurfaceItems: ['emoji', 'video', 'audio', 'file'],
popOverItems: ['formatter', 'link'],
},
Expand Down Expand Up @@ -55,7 +64,11 @@ const ChatInputFormattingToolbar = ({
inputRef.current.click();
};
const handleFormatterClick = (item) => {
formatSelection(messageRef, item.pattern);
if (item.type === 'list') {
insertListPrefix(messageRef, item.listPrefix);
} else {
formatSelection(messageRef, item.pattern);
}
setPopoverOpen(false);
};
const handleEmojiClick = (emojiEvent) => {
Expand Down Expand Up @@ -224,7 +237,7 @@ const ChatInputFormattingToolbar = ({
ghost
onClick={() => {
if (isRecordingMessage) return;
formatSelection(messageRef, item.pattern);
handleFormatterClick(item);
}}
>
<Icon
Expand Down Expand Up @@ -302,9 +315,7 @@ const ChatInputFormattingToolbar = ({
square
disabled={isRecordingMessage}
ghost
onClick={() =>
formatSelection(messageRef, itemInFormatter.pattern)
}
onClick={() => handleFormatterClick(itemInFormatter)}
>
<Icon
disabled={isRecordingMessage}
Expand Down
14 changes: 14 additions & 0 deletions packages/ui-elements/src/components/Icon/icons/ListBullets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

const ListBullets = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
fill="currentColor"
{...props}
>
<path d="M8 8C8 9.10457 7.10457 10 6 10C4.89543 10 4 9.10457 4 8C4 6.89543 4.89543 6 6 6C7.10457 6 8 6.89543 8 8ZM8 16C8 17.1046 7.10457 18 6 18C4.89543 18 4 17.1046 4 16C4 14.8954 4.89543 14 6 14C7.10457 14 8 14.8954 8 16ZM8 24C8 25.1046 7.10457 26 6 26C4.89543 26 4 25.1046 4 24C4 22.8954 4.89543 22 6 22C7.10457 22 8 22.8954 8 24ZM10 8C10 7.44772 10.4477 7 11 7H27C27.5523 7 28 7.44772 28 8C28 8.55228 27.5523 9 27 9H11C10.4477 9 10 8.55228 10 8ZM11.0005 15C10.4482 15 10.0005 15.4477 10.0005 16C10.0005 16.5523 10.4482 17 11.0005 17H26.9997C27.552 17 27.9997 16.5523 27.9997 16C27.9997 15.4477 27.552 15 26.9997 15H11.0005ZM11.0005 23C10.4482 23 10.0005 23.4477 10.0005 24C10.0005 24.5523 10.4482 25 11.0005 25H26.9997C27.552 25 27.9997 24.5523 27.9997 24C27.9997 23.4477 27.552 23 26.9997 23H11.0005Z" />
</svg>
);

export default ListBullets;
14 changes: 14 additions & 0 deletions packages/ui-elements/src/components/Icon/icons/ListNumbers.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/ui-elements/src/components/Icon/icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ import Arc from './Arc';
import Avatar from './Avatar';
import FormatText from './FormatText';
import Cog from './Cog';
import ListNumbers from './ListNumbers';
import ListBullets from './ListBullets';
import Team from './Team';

const icons = {
Expand Down Expand Up @@ -136,6 +138,8 @@ const icons = {
avatar: Avatar,
'format-text': FormatText,
cog: Cog,
'list-numbers': ListNumbers,
'list-bullets': ListBullets,
};

export default icons;