Skip to content

Commit

Permalink
new toolbar and color options, under featureflag
Browse files Browse the repository at this point in the history
  • Loading branch information
sojinantony01 committed Aug 10, 2024
1 parent f3ed474 commit ff77fe3
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 15 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Able to render 1Lakh+ input boxes in react, A quick solution for web based sprea
## Getting Started

Input data format
```
```json
[
[{value: 1},{value: 1},{value: "a"},{value: "b"},{value: "d"}]
]
Expand All @@ -48,7 +48,7 @@ npm install react-spread-sheet-excel

![alt text](https://raw.githubusercontent.com/sojinantony01/react-spread-sheet/main/public/images/samplesheet.png)

```
```js
import React, { useRef, useState } from "react";
import Sheet, { SheetRef } from "./lib";
import packageConf from "../package.json";
Expand Down
41 changes: 37 additions & 4 deletions src/lib/list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Row from "./row";
import { addData, deleteSelectItems, selectAllCells, updateStyles } from "../reducer";
import SheetXAxis from "./sheet-x-axis";
import { generateDummyContent } from "./utils";
import Tools from "./tools/tools"
export interface Props {
data?: any[][];
onChange?(i: number, j: number, value: string): void;
Expand All @@ -13,10 +14,13 @@ export interface Props {
headerValues?: string[];
readonly?: boolean;
}

const featureFlag = {
tools: false
}
const List = (props: Props) => {
const dispatch = useAppDispatch();
const itemLength = useAppSelector((store) => store.list.data.length);

const divRef = useRef<HTMLDivElement>(null);
const parentDivRef = useRef<HTMLDivElement>(null);
const [j, setJ] = useState(0);
Expand Down Expand Up @@ -55,13 +59,41 @@ const List = (props: Props) => {
if (e.code === "Backspace") {
dispatch(deleteSelectItems());
} else if (e.code === "KeyB" && (e.ctrlKey || e.metaKey)) {
dispatch(updateStyles({ value: { key: "fontWeight", value: "bold" } }));
changeStyle("B");
} else if (e.code === "KeyU" && (e.ctrlKey || e.metaKey)) {
dispatch(updateStyles({ value: { key: "text-decoration", value: "underline" } }));
changeStyle("U");
} else if (e.code === "KeyI" && (e.ctrlKey || e.metaKey)) {
dispatch(updateStyles({ value: { key: "fontStyle", value: "italic" } }));
changeStyle("I");
}
}
const getStyle = (key: string, value?:string) => {
switch (key) {
case "B":
return { value: { key: "fontWeight", value: "bold" } };
case "U":
return { value: { key: "text-decoration", value: "underline" } };
case "I":
return { value: { key: "fontStyle", value: "italic" } };
case "ALIGN-LEFT":
return { value: { key: "textAlign", value: "left" } };
case "ALIGN-CENTER":
return { value: { key: "textAlign", value: "center" } };
case "ALIGN-RIGHT":
return { value: { key: "textAlign", value: "right" } };
case "ALIGN-JUSTIFY":
return { value: { key: "textAlign", value: "justify" } };
case "FONT":
return { value: { key: "fontSize", value: value ? value + "px" : "" }, replace: true };
case "COLOR":
return { value: { key: "color", value: value }, replace: true };
case "BACKGROUND":
return { value: { key: "background", value: value }, replace: true };
}
};
const changeStyle = (key: string, value?: string) => {
dispatch(updateStyles(getStyle(key, value)));
};

return (
<div
onKeyDown={handleKeyDown}
Expand All @@ -70,6 +102,7 @@ const List = (props: Props) => {
ref={parentDivRef}
data-testid="sheet-table"
>
{featureFlag.tools && <Tools changeStyle={changeStyle}/>}
<div style={{ height: (itemLength + 1) * 28 }}>
<div ref={divRef}>
{items.length && (
Expand Down
3 changes: 1 addition & 2 deletions src/lib/list/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,11 @@ const Input = (props: Prop) => {
onKeyDown={keyDown}
onMouseMoveCapture={onDrag}
onMouseDown={onClick}
className={`${editMode ? "" : "view_mode"} ${selected ? "selected" : ""}`}
className={`input ${editMode ? "" : "view_mode"} ${selected ? "selected" : ""}`}
onBlur={() => {
setEdit(false);
setFocus(false);
}}
// onClick={onClick}
onDoubleClick={() => setEdit(true)}
onChange={change}
/>
Expand Down
5 changes: 4 additions & 1 deletion src/lib/list/sheet-x-axis.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import { useAppSelector, useAppDispatch } from "../store";
import { printToLetter } from "./utils";
import { selectVerticalCells } from "../reducer";
import { selectAllCells, selectVerticalCells } from "../reducer";
interface Props {
resize?: boolean;
headerValues?: string[];
Expand All @@ -26,6 +26,9 @@ const SheetXAxis = ({ resize, headerValues }: Props) => {
key={`${i}-x-axis`}
tabIndex={0}
onClick={(e) => {
if(i === 0) {
dispatch(selectAllCells());
} else
dispatch(selectVerticalCells({ j: i - 1, ctrlPressed: e.metaKey || e.ctrlKey }));
}}
>
Expand Down
60 changes: 60 additions & 0 deletions src/lib/list/tools/tools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from "react";
import Icons from "../../svg/icons";
import { useAppSelector } from "../../store";
let timer: string | number | NodeJS.Timeout | undefined;
const Tools = ({ changeStyle }: {changeStyle: (type:string, val?:string)=> void}) => {
const selectedStyles = useAppSelector((store) => {
const index = store.list.selected[0];
if (index) {
return store.list.data[index[0]][index[1]].styles || {};
}
return {};
});
const changeStyleWithDebounce = (type: string, val: string) => {
clearTimeout(timer);
timer = setTimeout(() => {changeStyle(type, val)}, 200)
}
return (
<div>
<button onClick={() => changeStyle("B")}>B</button>
<button onClick={() => changeStyle("U")}>U</button>
<button onClick={() => changeStyle("I")}>I</button>
{/* <button onClick={() => changeStyle("FONT", ((parseInt(selectedFontSize) || 12) - 1).toString())}>-</button> */}
<span>
<input
className="font-size-input"
type="number"
placeholder="size"
value={selectedStyles?.["fontSize"]?.split("px")?.[0] || ""}
onChange={(e) => changeStyle("FONT", e.target.value)}
onKeyDown={(e) => e.stopPropagation()}
/>
</span>
{/* <button onClick={() => changeStyle("FONT", ((parseInt(selectedFontSize) || 12) + 1).toString())}>+</button> */}

<button onClick={() => changeStyle("ALIGN-LEFT")}>
<Icons type="align-left" />
</button>
<button onClick={() => changeStyle("ALIGN-CENTER")}>
<Icons type="align-center" />
</button>
<button onClick={() => changeStyle("ALIGN-RIGHT")}>
<Icons type="align-right" />
</button>
<button onClick={() => changeStyle("ALIGN-JUSTIFY")}>
<Icons type="align-justify" />
</button>
<input
type="color"
value={selectedStyles?.["color"] || "#000000"}
onChange={(e) => changeStyleWithDebounce("COLOR", e.target.value)}
/>
<input
type="color"
value={selectedStyles?.["background"] || "#000000"}
onChange={(e) => changeStyleWithDebounce("BACKGROUND", e.target.value)}
/>
</div>
);
};
export default Tools;
14 changes: 9 additions & 5 deletions src/lib/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const listSlice = createSlice({
updateStyles(state, action) {
let add = true;
if (
!action.payload.replace &&
state.selected[0] &&
state.data[state.selected[0][0]][state.selected[0][1]]?.styles?.[action.payload.value.key] ===
action.payload.value.value
Expand Down Expand Up @@ -95,8 +96,8 @@ const listSlice = createSlice({
selectCellsDrag(state, action) {
const [startRow, startCol] = state.lastSelected || [0, 0];
const [endRow, endCol] = [action.payload.i, action.payload.j];
const result:Selected[] = [];
if(startRow === endRow && startCol === endCol) {
const result: Selected[] = [];
if (startRow === endRow && startCol === endCol) {
return;
}
// Determine iteration directions
Expand All @@ -106,13 +107,16 @@ const listSlice = createSlice({
for (let row = startRow; row !== endRow + rowIncrement; row += rowIncrement) {
for (let col = startCol; col !== endCol + colIncrement; col += colIncrement) {
if (row >= 0 && row < matrix.length && col >= 0 && col < matrix[row].length) {
result.push([row,col]);
result.push([row, col]);
}
}
}

state.selected = result;
}
},
updateFont(state, action) {

},
},
});

Expand Down
6 changes: 5 additions & 1 deletion src/lib/sheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ th {
overflow: auto;
}

.sheet-table input {
.sheet-table .input {
margin: 0;
box-sizing: border-box;
border: none;
Expand Down Expand Up @@ -86,4 +86,8 @@ th {
.sheet-table tr td:first-child {
position: sticky;
left: -2px;
}

.font-size-input {
width: 50px;
}
66 changes: 66 additions & 0 deletions src/lib/svg/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const Icons = ({type}: {type: string}) => {
switch (type) {
case "align-left":
return (
<svg width="12px" height="12px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M3 10H16M3 14H21M3 18H16M3 6H21"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</g>
</svg>
);
case "align-right":
return (
<svg width="12px" height="12px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M8 10H21M3 14H21M8 18H21M3 6H21"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</g>
</svg>
);
case "align-center":
return (
<svg width="12px" height="12px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M3 6H21M3 14H21M17 10H7M17 18H7"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</g>
</svg>
);
case "align-justify":
return (
<svg width="12px" height="12px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3 10H21M3 14H21M3 18H21M3 6H21"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
}
return <></>
}
export default Icons;

0 comments on commit ff77fe3

Please sign in to comment.