Skip to content
Snippets Groups Projects
Commit f7eace14 authored by Christos's avatar Christos
Browse files

Merge branch 'buttons' into 'master'

Buttons

See merge request !171
parents ec53fcff 83ef309a
No related branches found
No related tags found
1 merge request!171Buttons
Showing
with 593 additions and 264 deletions
...@@ -22,7 +22,11 @@ eslint.parserOptions = { ...@@ -22,7 +22,11 @@ eslint.parserOptions = {
}; };
eslint.rules = { eslint.rules = {
'sort-keys': 'off', 'class-methods-use-this': [
1,
{ exceptMethods: ['run', 'enable', 'active', 'select'] },
],
// 'import/no-named-as-default': 0,
'import/no-extraneous-dependencies': [ 'import/no-extraneous-dependencies': [
'error', 'error',
{ {
...@@ -30,13 +34,20 @@ eslint.rules = { ...@@ -30,13 +34,20 @@ eslint.rules = {
}, },
], ],
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'class-methods-use-this': [1, { exceptMethods: ['run', 'enable', 'active'] }],
'react/prop-types': [ 'react/prop-types': [
2, 2,
{ ignore: ['children', 'className', 'onClick', 'onMouseEnter', 'theme'] }, {
ignore: [
'children',
'className',
'onClick',
'onMouseDown',
'onMouseEnter',
'theme',
],
},
], ],
// 'import/no-named-as-default': 0, 'sort-keys': 'off',
}; };
module.exports = eslint; module.exports = eslint;
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import styled, { createGlobalStyle } from 'styled-components'; import { createGlobalStyle } from 'styled-components';
import { EditoriaLayout } from 'wax-prosemirror-layouts'; import { EditoriaLayout } from 'wax-prosemirror-layouts';
import { Wax } from 'wax-prosemirror-core'; import { Wax } from 'wax-prosemirror-core';
...@@ -12,17 +12,12 @@ const GlobalStyle = createGlobalStyle` ...@@ -12,17 +12,12 @@ const GlobalStyle = createGlobalStyle`
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-y: hidden; overflow-y: hidden;
}
#root { #root {
height:100vh; height:100vh;
width:100vw; width:100vw;
} }
}
`;
const StyledWax = styled(Wax)`
.wax-surface-scroll {
/* height: ${props => (props.debug ? '50vh' : '100%')}; */
}
`; `;
const renderImage = file => { const renderImage = file => {
...@@ -43,7 +38,7 @@ const user = { ...@@ -43,7 +38,7 @@ const user = {
const Editoria = () => ( const Editoria = () => (
<Fragment> <Fragment>
<GlobalStyle /> <GlobalStyle />
<StyledWax <Wax
config={config} config={config}
autoFocus autoFocus
placeholder="Type Something..." placeholder="Type Something..."
......
...@@ -24,6 +24,7 @@ import { ...@@ -24,6 +24,7 @@ import {
CodeBlockService, CodeBlockService,
CodeBlockToolGroupService, CodeBlockToolGroupService,
TrackChangeToolGroupService, TrackChangeToolGroupService,
DisplayTextToolGroupService,
} from 'wax-prosemirror-services'; } from 'wax-prosemirror-services';
import { WaxSelectionPlugin } from 'wax-prosemirror-plugins'; import { WaxSelectionPlugin } from 'wax-prosemirror-plugins';
...@@ -54,7 +55,7 @@ export default { ...@@ -54,7 +55,7 @@ export default {
}, },
{ {
templateArea: 'leftSideBar', templateArea: 'leftSideBar',
toolGroups: ['Display', 'Text'], toolGroups: ['DisplayText'],
}, },
], ],
...@@ -95,5 +96,6 @@ export default { ...@@ -95,5 +96,6 @@ export default {
new CodeBlockService(), new CodeBlockService(),
new CodeBlockToolGroupService(), new CodeBlockToolGroupService(),
new TrackChangeToolGroupService(), new TrackChangeToolGroupService(),
new DisplayTextToolGroupService(),
], ],
}; };
import React from 'react'
const Button = ({ onClick }) => (
<button onClick={onClick} type="button">
Click me
</button>
)
export const Base = () => <Button onClick={() => console.log('clicked!')} />
export default {
component: Button,
title: 'Test/Button',
}
import React from 'react';
import styled from 'styled-components';
import Dropdown from '../../wax-prosemirror-components/src/ui/buttons/Dropdown';
const Wrapper = styled.div`
height: 150px;
`;
// const RightWrapper = styled(Wrapper)`
// display: flex;
// justify-content: flex-end;
// `;
const DropElement = styled.div`
background: palegoldenrod;
height: 100px;
width: 100px;
`;
export const Base = () => (
<Wrapper>
<Dropdown iconName="bold" dropComponent={<DropElement />} />
</Wrapper>
);
// export const RightSide = () => (
// <RightWrapper>
// <Dropdown iconName="bold" />
// </RightWrapper>
// );
export default {
component: Dropdown,
title: 'Buttons/Dropdown',
};
import React from 'react';
import Icon from '../../wax-prosemirror-components/src/ui/buttons/Icon';
export const Base = () => <Icon name="commentBubble" />;
export default {
component: Icon,
title: 'Buttons/Icon',
};
import React, { useState } from 'react';
import MenuButton from '../../wax-prosemirror-components/src/ui/buttons/MenuButton';
import { Demo } from '../_helpers';
export const Base = () => {
const [active, setActive] = useState(false);
const reset = () => {
setActive(false);
};
return (
<Demo onClickButton={reset}>
<MenuButton
active={active}
iconName="bold"
onMouseDown={() => setActive(!active)}
title="bold"
/>
</Demo>
);
};
export const Inactive = () => <MenuButton iconName="bold" />;
export const Active = () => <MenuButton active iconName="bold" />;
export const Disabled = () => <MenuButton disabled iconName="bold" />;
export const IconAndText = () => {
const [active, setActive] = useState(false);
const reset = () => {
setActive(false);
};
return (
<Demo onClickButton={reset}>
<MenuButton
active={active}
iconName="bold"
label="Make it bold"
onMouseDown={() => setActive(!active)}
/>
</Demo>
);
};
export const TextOnly = () => {
const [active, setActive] = useState(false);
const reset = () => {
setActive(false);
};
return (
<Demo onClickButton={reset}>
<MenuButton
active={active}
label="Make it bold"
onMouseDown={() => setActive(!active)}
/>
</Demo>
);
};
export default {
component: MenuButton,
title: 'Buttons/Menu Button',
};
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import BlockElement from '../../wax-prosemirror-components/src/ui/tabs/BlockElement'; import BlockElement from '../../wax-prosemirror-components/src/ui/tabs/BlockElement';
const item = { const item = {
content: 'something', label: 'something',
}; };
export const Base = () => <BlockElement item={item} isNested={false} />; export const Base = () => <BlockElement item={item} isNested={false} />;
......
...@@ -4,10 +4,10 @@ import BlockElementGroup from '../../wax-prosemirror-components/src/ui/tabs/Bloc ...@@ -4,10 +4,10 @@ import BlockElementGroup from '../../wax-prosemirror-components/src/ui/tabs/Bloc
const items = [ const items = [
{ {
content: 'Heading 1', label: 'Heading 1',
}, },
{ {
content: 'Heading 2', label: 'Heading 2',
}, },
]; ];
......
...@@ -6,6 +6,8 @@ export { default as TableDropDown } from './src/components/TableDropDown'; ...@@ -6,6 +6,8 @@ export { default as TableDropDown } from './src/components/TableDropDown';
export { default as ImageUpload } from './src/components/ImageUpload'; export { default as ImageUpload } from './src/components/ImageUpload';
export { default as LeftMenuTitle } from './src/components/LeftMenuTitle'; export { default as LeftMenuTitle } from './src/components/LeftMenuTitle';
export { default as ToolGroupComponent } from './src/components/ToolGroupComponent'; export { default as ToolGroupComponent } from './src/components/ToolGroupComponent';
export { default as ToolGroups } from './src/components/ToolGroups';
export { default as NoteEditorContainer } from './src/components/notes/NoteEditorContainer'; export { default as NoteEditorContainer } from './src/components/notes/NoteEditorContainer';
export { default as LinkComponent } from './src/components/link/LinkComponent'; export { default as LinkComponent } from './src/components/link/LinkComponent';
...@@ -17,3 +19,6 @@ export { default as RightArea } from './src/components/rightArea/RightArea'; ...@@ -17,3 +19,6 @@ export { default as RightArea } from './src/components/rightArea/RightArea';
export { default as TrackChangeEnable } from './src/components/trackChanges/TrackChangeEnable'; export { default as TrackChangeEnable } from './src/components/trackChanges/TrackChangeEnable';
export { default as CreateTable } from './src/components/tables/CreateTable'; export { default as CreateTable } from './src/components/tables/CreateTable';
export { default as Tabs } from './src/ui/tabs/Tabs';
export { default as BlockLevelTools } from './src/ui/tabs/BlockLevelTools';
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"version": "0.0.19", "version": "0.0.19",
"description": "Wax prosemirror UI components", "description": "Wax prosemirror UI components",
"license": "MIT", "license": "MIT",
"main": "dist/index.js", "main": "index.js",
"files": [ "files": [
"dist" "dist"
], ],
......
/* eslint react/prop-types: 0 */
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import styled from 'styled-components';
import { ButtonStyles } from 'wax-prosemirror-themes';
import { WaxContext } from 'wax-prosemirror-core'; import { WaxContext } from 'wax-prosemirror-core';
import MenuButton from '../ui/buttons/MenuButton';
const ButtonStyled = styled.button`
${ButtonStyles};
opacity: ${props => (props.select ? 1 : 0.4)};
pointer-events: ${props => (props.select ? 'default' : 'none')};
color: ${props => (props.isActive ? 'white' : props.theme.colorButton)};
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'};
&:hover {
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'};
}
`;
const Button = ({ view = {}, item }) => { const Button = ({ view = {}, item }) => {
const { active, enable, icon, label, onlyOnMain, run, select, title } = item;
const { const {
view: { main }, view: { main },
activeViewId, activeViewId,
} = useContext(WaxContext); } = useContext(WaxContext);
if (item.onlyOnMain) {
view = main; if (onlyOnMain) view = main;
}
const { dispatch, state } = view;
const handleMouseDown = e => {
e.preventDefault();
run(state, dispatch);
};
const isActive = active && active(state);
const isDisabled =
enable && !enable(state) && !(select && select(view.state, activeViewId));
return ( return (
<ButtonStyled <MenuButton
type="button" active={isActive}
isActive={item.active && item.active(view.state)} disabled={isDisabled}
title={item.title} iconName={icon}
disabled={item.enable && !item.enable(view.state)} label={label}
onMouseDown={e => { onMouseDown={handleMouseDown}
e.preventDefault(); title={title}
item.run(view.state, view.dispatch); />
}}
select={item.select && item.select(view.state, activeViewId)}
>
{item.content}
</ButtonStyled>
); );
}; };
......
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
import React, { useContext } from 'react'; import React, { useContext, useRef } from 'react';
import { WaxContext } from 'wax-prosemirror-core'; import { WaxContext } from 'wax-prosemirror-core';
import styled from 'styled-components'; import styled from 'styled-components';
const UploadImage = styled.div` import MenuButton from '../ui/buttons/MenuButton';
opacity: ${props => (props.select ? 1 : 0.4)};
pointer-events: ${props => (props.select ? 'default' : 'none')}; const Wrapper = styled.div`
color: #777;
display: inline-flex;
padding: 0px 10px;
.custom-file-upload {
cursor: pointer;
}
&:hover {
}
input { input {
display: none; display: none;
} }
`; `;
const ImageUpload = ({ item, fileUpload, view }) => { const ImageUpload = ({ item, fileUpload, view }) => {
const { activeViewId } = useContext(WaxContext); const { activeViewId } = useContext(WaxContext);
const inputRef = useRef(null);
const handleMouseDown = () => inputRef.current.click();
return ( return (
<UploadImage select={item.select && item.select(view.state, activeViewId)}> <Wrapper>
<label <label htmlFor="file-upload">
className="custom-file-upload" <MenuButton
title="upload image" active={false}
htmlFor="file-upload" disabled={!(item.select && item.select(view.state, activeViewId))}
> iconName={item.icon}
{item.content} onMouseDown={handleMouseDown}
title="Upload Image"
/>
<input <input
id="file-upload" id="file-upload"
ref={inputRef}
onChange={e => fileUpload(e.target.files[0])} onChange={e => fileUpload(e.target.files[0])}
type="file" type="file"
/> />
</label> </label>
</UploadImage> </Wrapper>
); );
}; };
export default ImageUpload; export default ImageUpload;
import React, { useState } from "react"; import React from 'react';
import { isFunction } from "lodash"; import { isFunction } from 'lodash';
import styled from "styled-components"; import styled from 'styled-components';
import icons from "../icons/icons";
import Dropdown from '../ui/buttons/Dropdown';
const ToolGroupStyled = styled.div`
border-right: 1px solid #ecedf1; const Wrapper = styled.div`
&:last-child { background: #fff;
border-right: none; display: inline-flex;
} align-items: center;
`; padding: 0 4px;
const MoreButton = styled.button` > button,
background: none; > div {
border: none; margin: 0 2px;
cursor: pointer;
&:active {
outline: none;
} }
`; `;
const InnerStyled = styled.div` const DropWrapper = styled(Wrapper)`
display: flex; border: 1px solid gray;
width: 0; padding: 4px;
top: 40px;
position: relative;
right: 100%;
`; `;
const ToolGroupComponent = ({ view, tools, name, title }) => { const ToolGroupComponent = ({ view, tools, name }) => {
const [more, showHide] = useState(false), const toolsShown = [];
toolsShown = [], const rest = [];
rest = [],
DisplayTitle = isFunction(title) ? title : () => title;
tools.forEach(tool => { tools.forEach(tool => {
tool.isIntoMoreSection() && tool.isDisplayed() tool.isIntoMoreSection() && tool.isDisplayed()
...@@ -40,23 +32,16 @@ const ToolGroupComponent = ({ view, tools, name, title }) => { ...@@ -40,23 +32,16 @@ const ToolGroupComponent = ({ view, tools, name, title }) => {
}); });
return ( return (
<ToolGroupStyled data-name={name}> <Wrapper data-name={name}>
<DisplayTitle />
{toolsShown} {toolsShown}
{rest.length && !more ? ( {rest.length > 0 && (
<MoreButton title="show more tools" onClick={() => showHide(!more)}> <Dropdown
{icons.ellipses} iconName="more"
</MoreButton> dropComponent={<DropWrapper>{rest}</DropWrapper>}
) : null} title="Show more tools"
{more && ( />
<div>
<MoreButton title="hide" onClick={() => showHide(!more)}>
{icons.ellipses}
</MoreButton>
<InnerStyled>{rest}</InnerStyled>
</div>
)} )}
</ToolGroupStyled> </Wrapper>
); );
}; };
......
/* eslint no-underscore-dangle: 0 */
/* eslint react/prop-types: 0 */
import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import ToolGroupComponent from './ToolGroupComponent';
const ToolGroups = ({ toolGroups, view }) => {
return toolGroups.map(toolGroup => {
if (toolGroup._toolGroups.length > 0) {
return <ToolGroups toolGroups={toolGroup._toolGroups} view={view} />;
}
return (
<ToolGroupComponent
key={uuidv4()}
view={view}
tools={toolGroup._tools}
// title={this.title}
// name={name}
/>
);
});
};
export default ToolGroups;
/* eslint react/prop-types: 0 */
import React, { useState, useContext } from 'react'; import React, { useState, useContext } from 'react';
import styled from 'styled-components';
import { ButtonStyles } from 'wax-prosemirror-themes';
import { WaxContext } from 'wax-prosemirror-core'; import { WaxContext } from 'wax-prosemirror-core';
import InsertTableTool from '../../ui/tables/InsertTableTool';
const ButtonStyled = styled.button`
${ButtonStyles};
opacity: ${props => (props.select ? 1 : 0.4)};
pointer-events: ${props => (props.select ? 'default' : 'none')};
color: ${props => (props.isActive ? 'white' : props.theme.colorButton)};
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'};
&:hover {
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'};
}
`;
const InsertTableToolContainer = styled.div` import Dropdown from '../../ui/buttons/Dropdown';
display: block; import InsertTableTool from '../../ui/tables/InsertTableTool';
height: auto;
top: 53px;
position: absolute;
`;
const CreateTable = ({ view = {}, item }) => { const CreateTable = ({ view = {}, item }) => {
const { const {
...@@ -34,37 +13,32 @@ const CreateTable = ({ view = {}, item }) => { ...@@ -34,37 +13,32 @@ const CreateTable = ({ view = {}, item }) => {
view = main; view = main;
} }
const [showTool, setShowTool] = useState(false);
const toggleShowTool = () => setShowTool(!showTool);
const { state, dispatch } = view; const { state, dispatch } = view;
const [isTableToolDisplayed, setTableToolDisplay] = useState(false); const { enable, icon, run, select, title } = item;
const CreateButton = ( const dropComponent = (
<ButtonStyled <InsertTableTool
type="button" onGridSelect={colRows => {
isActive={isTableToolDisplayed} run(colRows, state, dispatch);
title={item.title}
disabled={item.enable && !item.enable(view.state)}
onMouseDown={e => {
e.preventDefault();
setTableToolDisplay(!isTableToolDisplayed);
}} }}
select={item.select && item.select(view.state, activeViewId)} />
>
{item.content}
</ButtonStyled>
); );
return isTableToolDisplayed ? (
<> const isDisabled =
{CreateButton} enable && !enable(state) && !(select && select(state, activeViewId));
<InsertTableToolContainer>
<InsertTableTool return (
onGridSelect={colRows => { <Dropdown
item.run(colRows, state, dispatch); active={showTool}
}} dropComponent={dropComponent}
/> iconName={icon}
</InsertTableToolContainer> disabled={isDisabled}
</> onClick={toggleShowTool}
) : ( title={title}
<>{CreateButton}</> />
); );
}; };
......
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import styled from 'styled-components'; // import styled from 'styled-components';
import { ButtonStyles } from 'wax-prosemirror-themes'; // import { ButtonStyles } from 'wax-prosemirror-themes';
import { WaxContext } from 'wax-prosemirror-core'; import { WaxContext } from 'wax-prosemirror-core';
import MenuButton from '../../ui/buttons/MenuButton';
const ButtonStyled = styled.button` // const ButtonStyled = styled.button`
${ButtonStyles}; // ${ButtonStyles};
opacity: ${props => (props.select ? 1 : 0.4)}; // opacity: ${props => (props.select ? 1 : 0.4)};
pointer-events: ${props => (props.select ? 'default' : 'none')}; // pointer-events: ${props => (props.select ? 'default' : 'none')};
color: ${props => (props.isActive ? 'white' : props.theme.colorButton)}; // color: ${props => (props.isActive ? 'white' : props.theme.colorButton)};
background-color: ${props => // background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'}; // props.isActive ? props.theme.colorPrimary : 'transparent'};
&:hover { // &:hover {
background-color: ${props => // background-color: ${props =>
props.isActive ? props.theme.colorPrimary : 'transparent'}; // props.isActive ? props.theme.colorPrimary : 'transparent'};
} // }
`; // `;
const TrackChangeEnable = ({ view = {}, item, enabled }) => { const TrackChangeEnable = ({ view = {}, item, enabled }) => {
if (item.onlyOnMain) { if (item.onlyOnMain) {
...@@ -27,21 +28,36 @@ const TrackChangeEnable = ({ view = {}, item, enabled }) => { ...@@ -27,21 +28,36 @@ const TrackChangeEnable = ({ view = {}, item, enabled }) => {
const [isEnabled, setEnabled] = useState(enabled); const [isEnabled, setEnabled] = useState(enabled);
// return (
// <ButtonStyled
// type="button"
// isActive={isEnabled}
// title={item.title}
// disabled={item.enable && !item.enable(view.state)}
// onMouseDown={e => {
// e.preventDefault();
// setEnabled(!isEnabled);
// item.run(view.state, view.dispatch);
// }}
// select={item.select && item.select(view.state)}
// >
// {item.content}
// </ButtonStyled>
// );
const handleMouseDown = () => {
setEnabled(!isEnabled);
item.run(view.state, view.dispatch);
};
return ( return (
<ButtonStyled <MenuButton
type="button" active={isEnabled}
isActive={isEnabled}
title={item.title}
disabled={item.enable && !item.enable(view.state)} disabled={item.enable && !item.enable(view.state)}
onMouseDown={e => { label="Track Changes"
e.preventDefault(); onMouseDown={handleMouseDown}
setEnabled(!isEnabled); title={item.title}
item.run(view.state, view.dispatch); />
}}
select={item.select && item.select(view.state)}
>
{item.content}
</ButtonStyled>
); );
}; };
......
/**
* SVG source for icons: https://material.io/resources/icons
*/
import React from 'react'; import React from 'react';
import styled from 'styled-components';
import FontAwesomeIcon from '@fortawesome/react-fontawesome'; import FontAwesomeIcon from '@fortawesome/react-fontawesome';
import { import {
faBold,
faItalic,
faCheck, faCheck,
faCode,
faSuperscript,
faSubscript,
faUnderline,
faStrikethrough,
faLink,
faParagraph, faParagraph,
faHeading, faHeading,
faQuoteLeft, faQuoteLeft,
faListOl,
faListUl,
faImage,
faTable,
faTimes, faTimes,
faUndo,
faRedo,
faOutdent,
faAngleUp,
faStickyNote,
faVial, faVial,
faFileCode,
faEllipsisH,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
// default values
// to explain vertical align: https://stackoverflow.com/a/24626986
const Svg = styled.svg.attrs(() => ({
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
xmlnsXlink: 'http://www.w3.org/1999/xlink',
}))`
height: 24px;
width: 24px;
fill: gray;
vertical-align: top;
`;
export default { export default {
em: <FontAwesomeIcon icon={faItalic} />,
italic: <FontAwesomeIcon icon={faItalic} />,
strong: <FontAwesomeIcon icon={faBold} />,
bold: <FontAwesomeIcon icon={faBold} />,
code: <FontAwesomeIcon icon={faCode} />,
subscript: <FontAwesomeIcon icon={faSubscript} />,
superscript: <FontAwesomeIcon icon={faSuperscript} />,
underline: <FontAwesomeIcon icon={faUnderline} />,
strikethrough: <FontAwesomeIcon icon={faStrikethrough} />,
link: <FontAwesomeIcon icon={faLink} />,
paragraph: <FontAwesomeIcon icon={faParagraph} />, paragraph: <FontAwesomeIcon icon={faParagraph} />,
heading: <FontAwesomeIcon icon={faHeading} />, heading: <FontAwesomeIcon icon={faHeading} />,
blockquote: <FontAwesomeIcon icon={faQuoteLeft} />, blockquote: <FontAwesomeIcon icon={faQuoteLeft} />,
code_block: <FontAwesomeIcon icon={faFileCode} />,
ordered_list: <FontAwesomeIcon icon={faListOl} />,
bullet_list: <FontAwesomeIcon icon={faListUl} />,
image: <FontAwesomeIcon icon={faImage} />,
table: <FontAwesomeIcon icon={faTable} />,
footnote: <FontAwesomeIcon icon={faStickyNote} />,
undo: <FontAwesomeIcon icon={faUndo} />,
redo: <FontAwesomeIcon icon={faRedo} />,
lift: <FontAwesomeIcon icon={faOutdent} />,
join_up: <FontAwesomeIcon icon={faAngleUp} />,
source: <FontAwesomeIcon icon={faVial} />, source: <FontAwesomeIcon icon={faVial} />,
ellipses: <FontAwesomeIcon icon={faEllipsisH} />,
small_caps: (
<span className="small-caps">
<svg
width="35"
height="20"
viewBox="0 0 35 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.21799 1.12207L9.34998 0H0V1.12207H4.004V15.0701H5.258V1.12207H9.21799ZM14.14 6.34912L14.242 5.51611H7.935V6.34912H10.587V15.0701H11.539V6.34912H14.14Z"
transform="translate(10.286 8.92993)"
fill="#4F4F4F"
/>
</svg>
</span>
),
check: <FontAwesomeIcon icon={faCheck} />, check: <FontAwesomeIcon icon={faCheck} />,
times: <FontAwesomeIcon icon={faTimes} />, times: <FontAwesomeIcon icon={faTimes} />,
commentBubble: ({ className }) => (
<Svg viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 9h12v2H6V9zm8 5H6v-2h8v2zm4-6H6V6h12v2z" />
</Svg>
),
bold: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z" />
</Svg>
),
italic: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" />
</Svg>
),
undo: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z" />
</Svg>
),
redo: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z" />
</Svg>
),
code: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z" />
</Svg>
),
link: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" />
</Svg>
),
strikethrough: ({ className }) => (
<Svg
className={className}
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
>
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<g>
<g>
<path d="M6.85,7.08C6.85,4.37,9.45,3,12.24,3c1.64,0,3,0.49,3.9,1.28c0.77,0.65,1.46,1.73,1.46,3.24h-3.01 c0-0.31-0.05-0.59-0.15-0.85c-0.29-0.86-1.2-1.28-2.25-1.28c-1.86,0-2.34,1.02-2.34,1.7c0,0.48,0.25,0.88,0.74,1.21 C10.97,8.55,11.36,8.78,12,9H7.39C7.18,8.66,6.85,8.11,6.85,7.08z M21,12v-2H3v2h9.62c1.15,0.45,1.96,0.75,1.96,1.97 c0,1-0.81,1.67-2.28,1.67c-1.54,0-2.93-0.54-2.93-2.51H6.4c0,0.55,0.08,1.13,0.24,1.58c0.81,2.29,3.29,3.3,5.67,3.3 c2.27,0,5.3-0.89,5.3-4.05c0-0.3-0.01-1.16-0.48-1.94H21V12z" />
</g>
</g>
</g>
</Svg>
),
underline: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z" />
</Svg>
),
more: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
</Svg>
),
subscript: ({ className }) => (
<Svg
className={className}
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
>
<g>
<rect fill="none" height="24" width="24" />
<path d="M22,18h-2v1h3v1h-4v-2c0-0.55,0.45-1,1-1h2v-1h-3v-1h3c0.55,0,1,0.45,1,1v1C23,17.55,22.55,18,22,18z M5.88,18h2.66 l3.4-5.42h0.12l3.4,5.42h2.66l-4.65-7.27L17.81,4h-2.68l-3.07,4.99h-0.12L8.85,4H6.19l4.32,6.73L5.88,18z" />
</g>
</Svg>
),
superscript: ({ className }) => (
<Svg
className={className}
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
>
<g>
<rect fill="none" height="24" width="24" x="0" y="0" />
<path d="M22,7h-2v1h3v1h-4V7c0-0.55,0.45-1,1-1h2V5h-3V4h3c0.55,0,1,0.45,1,1v1C23,6.55,22.55,7,22,7z M5.88,20h2.66l3.4-5.42h0.12 l3.4,5.42h2.66l-4.65-7.27L17.81,6h-2.68l-3.07,4.99h-0.12L8.85,6H6.19l4.32,6.73L5.88,20z" />
</g>
</Svg>
),
smallCaps: ({ className }) => (
<Svg
className={className}
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
>
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<g>
<g>
<path d="M2.5,4v3h5v12h3V7h5V4H2.5z M21.5,9h-9v3h3v7h3v-7h3V9z" />
</g>
</g>
</g>
</Svg>
),
note: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M22 10l-6-6H4c-1.1 0-2 .9-2 2v12.01c0 1.1.9 1.99 2 1.99l16-.01c1.1 0 2-.89 2-1.99v-8zm-7-4.5l5.5 5.5H15V5.5z" />
</Svg>
),
numberedList: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" />
</Svg>
),
bulletList: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z" />
</Svg>
),
indentDecrease: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M11 17h10v-2H11v2zm-8-5l4 4V8l-4 4zm0 9h18v-2H3v2zM3 3v2h18V3H3zm8 6h10V7H11v2zm0 4h10v-2H11v2z" />
</Svg>
),
image: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" />
</Svg>
),
table: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M3 3v18h18V3H3zm8 16H5v-6h6v6zm0-8H5V5h6v6zm8 8h-6v-6h6v6zm0-8h-6V5h6v6z" />
</Svg>
),
/* -- table alternative icon -- */
// table: ({ className }) => (
// <Svg className={className} viewBox="0 0 24 24">
// <path d="M0 0h24v24H0V0z" fill="none" />
// <path d="M10 10.02h5V21h-5zM17 21h3c1.1 0 2-.9 2-2v-9h-5v11zm3-18H5c-1.1 0-2 .9-2 2v3h19V5c0-1.1-.9-2-2-2zM3 19c0 1.1.9 2 2 2h3V10H3v9z" />
// </Svg>
// ),
arrowUp: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" />
</Svg>
),
codeBlock: ({ className }) => (
<Svg
className={className}
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
>
<g>
<rect fill="none" height="24" width="24" />
<circle cx="12" cy="3.5" fill="none" r=".75" />
<circle cx="12" cy="3.5" fill="none" r=".75" />
<circle cx="12" cy="3.5" fill="none" r=".75" />
<path d="M19,3h-4.18C14.4,1.84,13.3,1,12,1S9.6,1.84,9.18,3H5C4.86,3,4.73,3.01,4.6,3.04C4.21,3.12,3.86,3.32,3.59,3.59 c-0.18,0.18-0.33,0.4-0.43,0.64C3.06,4.46,3,4.72,3,5v14c0,0.27,0.06,0.54,0.16,0.78c0.1,0.24,0.25,0.45,0.43,0.64 c0.27,0.27,0.62,0.47,1.01,0.55C4.73,20.99,4.86,21,5,21h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M11,14.17l-1.41,1.42L6,12 l3.59-3.59L11,9.83L8.83,12L11,14.17z M12,4.25c-0.41,0-0.75-0.34-0.75-0.75S11.59,2.75,12,2.75s0.75,0.34,0.75,0.75 S12.41,4.25,12,4.25z M14.41,15.59L13,14.17L15.17,12L13,9.83l1.41-1.42L18,12L14.41,15.59z" />
</g>
</Svg>
),
title: ({ className }) => (
<Svg className={className} viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M5 4v3h5.5v12h3V7H19V4z" />
</Svg>
),
}; };
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import MenuButton from './MenuButton';
// font size 0 reason: https://stackoverflow.com/a/19212391
const Wrapper = styled.div`
font-size: 0;
position: relative;
`;
const DropWrapper = styled.div`
margin-top: 4px;
position: absolute;
z-index: 2;
`;
const Dropdown = props => {
const { className, disabled, dropComponent, iconName, label, title } = props;
const [isOpen, setIsOpen] = useState(false);
// const dropElementRef = useRef(null);
return (
<Wrapper className={className}>
<MenuButton
active={isOpen}
disabled={disabled}
iconName={iconName}
label={label}
onMouseDown={() => setIsOpen(!isOpen)}
title={title}
/>
{isOpen && <DropWrapper>{dropComponent}</DropWrapper>}
</Wrapper>
);
};
Dropdown.propTypes = {
disabled: PropTypes.bool,
dropComponent: PropTypes.node.isRequired,
iconName: PropTypes.string,
label: PropTypes.string,
title: PropTypes.string,
};
Dropdown.defaultProps = {
disabled: false,
iconName: null,
label: null,
title: null,
};
export default Dropdown;
import React from 'react';
import PropTypes from 'prop-types';
import icons from '../../icons/icons';
/**
* Only works with SVG icons from icons.js
*/
const SVGIcon = props => {
const { className, name } = props;
const Component = icons[name];
return <Component className={className} />;
};
SVGIcon.propTypes = {
name: PropTypes.string.isRequired,
};
export default SVGIcon;
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment