@ -1,27 +1,87 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import type { Props } from '../types';
|
import type { Props } from '../types';
|
||||||
import { color } from 'styles/constants';
|
import { color } from 'styles/constants';
|
||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
const StyledImg = styled.img`
|
class Image extends Component {
|
||||||
box-shadow: ${props => (props.active ? `0 0 0 3px ${color.slate}` : '0')};
|
props: Props;
|
||||||
opacity: ${props => (props.loading ? 0.5 : 1)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function Image({ attributes, state, node }: Props) {
|
handleChange = (ev: SyntheticInputEvent) => {
|
||||||
|
const alt = ev.target.value;
|
||||||
|
const { editor, node } = this.props;
|
||||||
|
const data = node.data.toObject();
|
||||||
|
const state = editor
|
||||||
|
.getState()
|
||||||
|
.transform()
|
||||||
|
.setNodeByKey(node.key, { data: { ...data, alt } })
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
editor.onChange(state);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClick = (ev: SyntheticInputEvent) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { attributes, state, node, readOnly } = this.props;
|
||||||
const loading = node.data.get('loading');
|
const loading = node.data.get('loading');
|
||||||
const alt = node.data.get('alt');
|
const caption = node.data.get('alt');
|
||||||
const src = node.data.get('src');
|
const src = node.data.get('src');
|
||||||
const active = state.isFocused && state.selection.hasEdgeIn(node);
|
const active = state.isFocused && state.selection.hasEdgeIn(node);
|
||||||
|
const showCaption = !readOnly || caption;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<CenteredImage>
|
||||||
<StyledImg
|
<StyledImg
|
||||||
{...attributes}
|
{...attributes}
|
||||||
src={src}
|
src={src}
|
||||||
alt={alt}
|
alt={caption}
|
||||||
active={active}
|
active={active}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
|
{showCaption &&
|
||||||
|
<Caption
|
||||||
|
type="text"
|
||||||
|
placeholder="Write a caption"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onClick={this.handleClick}
|
||||||
|
defaultValue={caption}
|
||||||
|
contentEditable={false}
|
||||||
|
disabled={readOnly}
|
||||||
|
tabIndex={-1}
|
||||||
|
/>}
|
||||||
|
</CenteredImage>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StyledImg = styled.img`
|
||||||
|
box-shadow: ${props => (props.active ? `0 0 0 2px ${color.slate}` : '0')};
|
||||||
|
border-radius: ${props => (props.active ? `2px` : '0')};
|
||||||
|
opacity: ${props => (props.loading ? 0.5 : 1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CenteredImage = styled.div`
|
||||||
|
text-align: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Caption = styled.input`
|
||||||
|
border: 0;
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: italic;
|
||||||
|
color: ${color.slate};
|
||||||
|
padding: 2px 0;
|
||||||
|
line-height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: ${color.slate};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default Image;
|
||||||
|
@ -215,6 +215,19 @@ export default function MarkdownShortcuts() {
|
|||||||
return this.onBackspace(ev, state);
|
return this.onBackspace(ev, state);
|
||||||
if (endOffset !== startBlock.length) return;
|
if (endOffset !== startBlock.length) return;
|
||||||
|
|
||||||
|
// Hitting enter while an image is selected should jump caret below and
|
||||||
|
// insert a new paragraph
|
||||||
|
if (startBlock.type === 'image') {
|
||||||
|
ev.preventDefault();
|
||||||
|
return state
|
||||||
|
.transform()
|
||||||
|
.collapseToEnd()
|
||||||
|
.insertBlock('paragraph')
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitting enter in a heading or blockquote will split the node at that
|
||||||
|
// point and make the new node a paragraph
|
||||||
if (
|
if (
|
||||||
startBlock.type !== 'heading1' &&
|
startBlock.type !== 'heading1' &&
|
||||||
startBlock.type !== 'heading2' &&
|
startBlock.type !== 'heading2' &&
|
||||||
@ -228,7 +241,6 @@ export default function MarkdownShortcuts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
return state.transform().splitBlock().setBlock('paragraph').apply();
|
return state.transform().splitBlock().setBlock('paragraph').apply();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user