Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table editing #1

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
5f976f0
First pass
tommoor Apr 29, 2019
9b53908
Stash
tommoor Apr 29, 2019
565ed8a
Table alignment
tommoor May 4, 2019
b24abbf
Don't override table schema
tommoor May 5, 2019
aa129a2
Beginning TableToolbar
tommoor May 5, 2019
93c2ed2
Working TableToolbar
tommoor May 5, 2019
7b25774
grips
tommoor May 5, 2019
a89ce34
Grip toggle behavior looking good
tommoor May 6, 2019
d7acbfb
:green_heart:
tommoor May 7, 2019
d244310
Fixes: Can't delete characters until cell is edited
tommoor May 7, 2019
0f08535
Fixes: Deselect on click outside
tommoor May 7, 2019
0fc005c
Column actions
tommoor May 7, 2019
a62c550
Table toolbar
tommoor May 11, 2019
cdfffaa
Button titles
tommoor May 11, 2019
621b574
Fixes: Hanging block insert toolbar
tommoor May 11, 2019
1550998
Fix: Incorrect toolbar positioning when page is scrolled
tommoor May 11, 2019
4a9c951
:green_heart:
tommoor May 11, 2019
62cf328
Improve 'shadows'
tommoor May 12, 2019
269337b
Row toolbar
tommoor May 12, 2019
874a197
Fix: Selection after col/row addition
tommoor May 12, 2019
038a311
Fixes: Row alignment and first column grip re-render
tommoor May 12, 2019
69390f1
:green_heart:
tommoor May 12, 2019
09b425a
Fix: Flash of empty menu
tommoor May 12, 2019
2b394c5
Fix: Highlight selected alignment
tommoor May 12, 2019
1a22819
Component refactor
tommoor May 12, 2019
8b6f242
Refactor commands
tommoor May 12, 2019
1c4b459
Fix: Right table shadow does not appear until remount
tommoor May 12, 2019
39f7028
Table selection and deletion
tommoor May 12, 2019
d48a66a
Fix: Allow toggling table selection
tommoor May 12, 2019
923db8b
Descrease fidgetyness around grips
tommoor May 12, 2019
7a986b7
Fixes: Behavior when selecting a column or row while entire table is …
tommoor May 12, 2019
d692c97
Place cursor in correct position to continue typing after adding a co…
tommoor May 12, 2019
895ef97
Color tweak
tommoor May 12, 2019
0666343
Fix: Remove focus with col/row select (shouldn't show cursor and tool…
tommoor May 12, 2019
fb1c17d
Fix: Menu positioning
tommoor May 14, 2019
6375aae
Improve table shadows
tommoor May 14, 2019
63278a9
No, does't work with theme switch
tommoor May 14, 2019
0df0bca
Bump outline-icons
tommoor May 14, 2019
761a957
9.5.0-0
tommoor May 14, 2019
bc26586
Ensure box-sizing
tommoor May 14, 2019
f21c810
Ensure a touch of padding at the top and bottom
tommoor May 14, 2019
013c635
9.5.0-1
tommoor May 14, 2019
48699b0
Cleanup
tommoor May 14, 2019
cf307ac
9.5.0-2
tommoor May 14, 2019
2dd823b
Merge master
tommoor May 25, 2019
622476e
9.5.0-3
tommoor May 25, 2019
d847d9f
9.5.0-4
tommoor May 25, 2019
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
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "rich-markdown-editor",
"description": "A rich text editor with Markdown shortcuts built on Slate",
"version": "9.4.2",
"version": "9.5.0-4",
"main": "lib/index.js",
"license": "BSD-3-Clause",
"scripts": {
Expand All @@ -12,6 +12,7 @@
"prepublish": "yarn build"
},
"dependencies": {
"@domoinc/slate-edit-table": "^0.22.2",
"@tommoor/slate-edit-list": "0.19.0-0",
"@wikifactory/slate-edit-blockquote": "^0.7.1",
"@wikifactory/slate-edit-code": "^0.16.0",
Expand All @@ -24,7 +25,7 @@
"eslint-plugin-prettier": "^2.6.0",
"golery-slate-prism": "0.6.0-golery.2",
"lodash": "^4.17.11",
"outline-icons": "^1.6.0",
"outline-icons": "^1.9.0",
"prismjs": "^1.16.0",
"react-autosize-textarea": "^6.0.0",
"react-keydown": "^1.9.7",
Expand All @@ -33,7 +34,7 @@
"slate": "^0.45.0",
"slate-collapse-on-escape": "^0.8.1",
"slate-drop-or-paste-images": "^0.9.1",
"slate-md-serializer": "^5.3.3",
"slate-md-serializer": "^5.4.0-5",
"slate-paste-linkify": "^0.7.0",
"slate-react": "^0.21.20",
"slate-schema-violations": "^0.1.39",
Expand Down
196 changes: 196 additions & 0 deletions src/components/Table/Cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// @flow
import * as React from "react";
import styled from "styled-components";
import Toolbar from "./Toolbar";
import Grip from "./Grip";

class Cell extends React.Component<*> {
cell: ?HTMLElement;

render() {
const { children, editor, readOnly, attributes, node } = this.props;
const { document } = editor.value;

const position = editor.getPositionByKey(document, node.key);
const isFirstRow = position.isFirstRow();
const isFirstColumn = position.isFirstColumn();
const isLastRow = position.isLastRow();
const isLastColumn = position.isLastColumn();
const isSelected = node.data.get("selected");
const isTableSelected = position.table.data.get("selectedTable");
const isActive = editor.isSelectionInTable() && !isTableSelected;
const selectedRows = position.table.data.get("selectedRows");
const selectedColumns = position.table.data.get("selectedColumns");
const isRowSelected =
selectedRows && selectedRows.includes(position.getRowIndex());
const isColumnSelected =
selectedColumns && selectedColumns.includes(position.getColumnIndex());

return (
<StyledTd
ref={ref => (this.cell = ref)}
isFirstRow={isFirstRow}
isFirstColumn={isFirstColumn}
isSelected={isSelected}
onClick={() => editor.clearSelected(position.table)}
{...attributes}
>
{!readOnly && (
<React.Fragment>
{isFirstColumn && isFirstRow && (
<React.Fragment>
<GripTable
contentEditable={false}
isSelected={isTableSelected}
onClick={ev => {
ev.preventDefault();
ev.stopPropagation();

if (isTableSelected) {
editor.clearSelected(position.table);
} else {
editor.selectAll().blur();
}
}}
/>
<Toolbar
editor={editor}
cell={this.cell}
active={isTableSelected}
type="table"
/>
</React.Fragment>
)}
{isFirstColumn && (
<React.Fragment>
<GripRow
isFirstRow={isFirstRow}
isLastRow={isLastRow}
isSelected={isRowSelected}
contentEditable={false}
onClick={ev => {
ev.preventDefault();
ev.stopPropagation();
editor.selectRow(!isSelected || isTableSelected).blur();
}}
/>
{isActive && (
<Toolbar
editor={editor}
cell={this.cell}
active={isRowSelected}
type="row"
/>
)}
</React.Fragment>
)}
{isFirstRow && (
<React.Fragment>
<GripColumn
isFirstColumn={isFirstColumn}
isLastColumn={isLastColumn}
isSelected={isColumnSelected}
contentEditable={false}
onClick={ev => {
ev.preventDefault();
ev.stopPropagation();
editor.selectColumn(!isSelected || isTableSelected).blur();
}}
/>
{isActive && (
<Toolbar
editor={editor}
cell={this.cell}
active={isColumnSelected}
type="column"
/>
)}
</React.Fragment>
)}
</React.Fragment>
)}

<RowContent align={node.data.get("align")}>{children}</RowContent>
</StyledTd>
);
}
}

export const GripTable = styled(Grip)`
width: 9px;
height: 9px;
border-radius: 9px;
border: 2px solid ${props => props.theme.background};

position: absolute;
top: -14px;
left: -14px;
`;

export const GripRow = styled(Grip)`
left: -12px;
top: 0.5px;
height: 100%;
width: 8px;
border-right: 3px solid ${props => props.theme.background};

${props =>
props.isFirstRow &&
`
border-top-left-radius: 3px;
border-top-right-radius: 3px;
`}

${props =>
props.isLastRow &&
`
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
`}
`;

export const GripColumn = styled(Grip)`
top: -12px;
left: -0.5px;
width: 100%;
height: 8px;
border-bottom: 3px solid ${props => props.theme.background};

${props =>
props.isFirstColumn &&
`
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
`}

${props =>
props.isLastColumn &&
`
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
`}
`;

const RowContent = styled.div`
padding: 4px 8px;
text-align: ${props => props.align};
`;

const StyledTd = styled.td`
vertical-align: top;
border-right: 1px solid ${props => props.theme.tableDivider};
position: relative;
background: ${props =>
props.isSelected
? props.theme.tableSelectedBackground
: props.theme.background};

${props =>
props.isFirstRow &&
`
box-shadow: 0 1px 1px ${props.theme.tableDivider};
min-width: 100px;
`}
`;

export default Cell;
20 changes: 20 additions & 0 deletions src/components/Table/Grip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow
import styled from "styled-components";

const Grip = styled.a`
position: absolute;
cursor: pointer;
background: ${props =>
props.isSelected ? props.theme.tableSelected : props.theme.tableDivider};

${props => props.isSelected && "opacity: 1 !important;"}

&:hover {
background: ${props =>
props.isSelected
? props.theme.tableSelected
: props.theme.toolbarBackground};
}
`;

export default Grip;
14 changes: 14 additions & 0 deletions src/components/Table/Row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @flow
import * as React from "react";
import styled from "styled-components";

const StyledTr = styled.tr`
position: relative;
border-bottom: 1px solid ${props => props.theme.tableDivider};
`;

const Row = ({ children, attributes }: *) => {
return <StyledTr {...attributes}>{children}</StyledTr>;
};

export default Row;
105 changes: 105 additions & 0 deletions src/components/Table/Scrollable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// @flow
import * as React from "react";
import styled from "styled-components";

type Props = { children: React.Node };

type State = {
shadowLeft: boolean,
shadowRight: boolean,
};

class Scrollable extends React.Component<Props, State> {
element: ?HTMLElement;

state = {
shadowLeft: false,
shadowRight: false,
};

componentDidMount() {
this.updateRightShadow();
}

componentDidUpdate() {
this.updateRightShadow();
}

updateRightShadow() {
const shadowRight = !!(
this.element && this.element.scrollWidth > this.element.clientWidth
);

if (this.state.shadowRight !== shadowRight) {
this.setState({ shadowRight });
}
}

handleScroll = (ev: SyntheticMouseEvent<*>) => {
const shadowLeft = ev.currentTarget.scrollLeft > 0;

if (this.state.shadowLeft !== shadowLeft) {
this.setState({ shadowLeft });
}
};

render() {
const { children, ...rest } = this.props;
return (
<Wrapper>
<Scrolling
ref={ref => (this.element = ref)}
onScroll={this.handleScroll}
{...rest}
>
{children}
</Scrolling>
<Shadow left={this.state.shadowLeft} />
<Shadow right={this.state.shadowRight} />
</Wrapper>
);
}
}

const Wrapper = styled.div`
position: relative;
margin: 0.5em 0;
`;

const Scrolling = styled.div`
overflow-y: hidden;
overflow-x: scroll;
padding-left: 1em;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
transition: border 250ms ease-in-out;
margin-left: -1em;
`;

const Shadow = styled.div`
position: absolute;
top: 0;
bottom: 0;
left: -1em;
width: 16px;
transition: box-shadow 250ms ease-in-out;
border: 0px solid transparent;
border-left-width: 1em;
pointer-events: none;

${props =>
props.left &&
`
box-shadow: 16px 0 16px -16px inset rgba(0,0,0,0.25);
border-left: 1em solid ${props.theme.background};
`}

${props =>
props.right &&
`right: 0;
left: auto;
box-shadow: -16px 0 16px -16px inset rgba(0,0,0,0.25);
`}
`;

export default Scrollable;
Loading