moved to create-react-library

This commit is contained in:
unknown committed 2020-08-05 08:14:22 +03:00
1 parent d27d58d44c
commit 09520361c2
65 files changed
+40755 -16260

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
{
"env": {
"jest": true
}
}
+4 -4
View File
@@ -1,5 +1,5 @@
import React from 'react';
import '../../style.css';
import React from "react";
import styles from "./bar.module.css";
type BarDateHandleProps = {
x: number;
@@ -23,10 +23,10 @@ export const BarDateHandle: React.FC<BarDateHandleProps> = ({
y={y}
width={width}
height={height}
className="GanttBar-handle"
className={styles.barHandle}
ry={barCornerRadius}
rx={barCornerRadius}
onMouseDown={onMouseDown}
></rect>
/>
);
};
+8 -6
View File
@@ -1,5 +1,5 @@
import React, { useRef, useState, useEffect } from 'react';
import '../../style.css';
import React, { useRef, useState, useEffect } from "react";
import style from "./bar.module.css";
type BarDisplayProps = {
x: number;
@@ -66,7 +66,7 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
ry={barCornerRadius}
rx={barCornerRadius}
fill={getBarColor()}
className="GanttBar"
className={style.barBackground}
/>
<rect
x={x}
@@ -80,9 +80,11 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
<text
x={getX()}
y={y + height * 0.5}
className={`GanttBar-label ${
isTextInside ? '' : 'GanttBar-label-outside'
}`}
className={
isTextInside
? style.barLabel
: style.barLabel && style.barLabelOutside
}
ref={textRef}
>
{text}
+4 -4
View File
@@ -1,5 +1,5 @@
import React from 'react';
import '../../style.css';
import React from "react";
import styles from "./bar.module.css";
type BarProgressHandleProps = {
progressPoint: string;
@@ -11,9 +11,9 @@ export const BarProgressHandle: React.FC<BarProgressHandleProps> = ({
}) => {
return (
<polygon
className="GanttBar-handle"
className={styles.barHandle}
points={progressPoint}
onMouseDown={onMouseDown}
></polygon>
/>
);
};
+40
View File
@@ -0,0 +1,40 @@
.barWrapper {
cursor: pointer;
outline: none;
}
.barWrapper:hover .barHandle {
visibility: visible;
opacity: 1;
}
.barHandle {
fill: #ddd;
cursor: ew-resize;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease;
}
.barLabel {
fill: #fff;
text-anchor: middle;
font-weight: lighter;
dominant-baseline: central;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
}
.barLabelOutside {
fill: #555;
text-anchor: start;
}
.barBackground {
user-select: none;
stroke-width: 0;
}
+20 -20
View File
@@ -1,15 +1,15 @@
import React, { useState } from 'react';
import { Task } from '../../types/public-types';
import { BarProgressHandle } from './bar-progress-handle';
import { BarDateHandle } from './bar-date-handle';
import { BarDisplay } from './bar-display';
import { BarTask } from '../../types/bar-task';
import { BarAction } from '../Gantt/gantt-content';
import React, { useState } from "react";
import { Task } from "../../types/public-types";
import { BarProgressHandle } from "./bar-progress-handle";
import { BarDateHandle } from "./bar-date-handle";
import { BarDisplay } from "./bar-display";
import { BarTask } from "../../types/bar-task";
import { BarAction } from "../Gantt/gantt-content";
import {
progressWithByParams,
getProgressPoint,
} from '../../helpers/bar-helper';
import '../../style.css';
} from "../../helpers/bar-helper";
import styles from "./bar.module.css";
export type BarProps = {
task: BarTask;
@@ -51,7 +51,7 @@ export const Bar: React.FC<BarProps> = ({
return (
<g
className="GanttBar-wrapper"
className={styles.barWrapper}
onDoubleClick={() => {
!!onDoubleClick && onDoubleClick(task);
}}
@@ -60,10 +60,10 @@ export const Bar: React.FC<BarProps> = ({
handleButtonSVGEvents(e, task);
}}
onMouseEnter={e => {
handleMouseEvents(e, 'mouseenter', task);
handleMouseEvents(e, "mouseenter", task);
}}
onMouseLeave={e => {
handleMouseEvents(e, 'mouseleave', task);
handleMouseEvents(e, "mouseleave", task);
}}
onFocus={() => setIsSelected(true)}
onBlur={() => setIsSelected(false)}
@@ -81,13 +81,13 @@ export const Bar: React.FC<BarProps> = ({
styles={task.styles}
isSelected={isSelected}
onMouseDown={e => {
isDateChangeable && handleMouseEvents(e, 'move', task);
isDateChangeable && handleMouseEvents(e, "move", task);
}}
/>
<g className="handleGroup">
{isDateChangeable && (
<>
{/*left*/}
<g>
{/* left */}
<BarDateHandle
x={task.x1 + 1}
y={task.y + 1}
@@ -95,10 +95,10 @@ export const Bar: React.FC<BarProps> = ({
height={task.height - 2}
barCornerRadius={task.barCornerRadius}
onMouseDown={e => {
handleMouseEvents(e, 'start', task);
handleMouseEvents(e, "start", task);
}}
/>
{/*right*/}
{/* right */}
<BarDateHandle
x={task.x2 - task.handleWidth - 1}
y={task.y + 1}
@@ -106,16 +106,16 @@ export const Bar: React.FC<BarProps> = ({
height={task.height - 2}
barCornerRadius={task.barCornerRadius}
onMouseDown={e => {
handleMouseEvents(e, 'end', task);
handleMouseEvents(e, "end", task);
}}
/>
</>
</g>
)}
{isProgressChangeable && (
<BarProgressHandle
progressPoint={progressPoint}
onMouseDown={e => {
handleMouseEvents(e, 'progress', task);
handleMouseEvents(e, "progress", task);
}}
/>
)}
@@ -0,0 +1,25 @@
.calendarBottomText {
text-anchor: middle;
fill: #333;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
}
.calendarTopTick {
stroke: #e6e4e4;
}
.calendarTopText {
text-anchor: middle;
fill: #555;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
}
+27 -26
View File
@@ -1,11 +1,12 @@
import React, { ReactChild } from 'react';
import { ViewMode } from '../../types/public-types';
import { TopPartOfCalendar } from './top-part-of-calendar';
import React, { ReactChild } from "react";
import { ViewMode } from "../../types/public-types";
import { TopPartOfCalendar } from "./top-part-of-calendar";
import {
getLocaleMonth,
getWeekNumberISO8601,
} from '../../helpers/date-helper';
import '../../style.css';
} from "../../helpers/date-helper";
import styles from "./calendar.module.css";
export type CalendarProps = {
dates: Date[];
locale: string;
@@ -26,25 +27,25 @@ export const Calendar: React.FC<CalendarProps> = ({
fontSize,
}) => {
const getCalendarValuesForMonth = () => {
let topValues: ReactChild[] = [];
let bottomValues: ReactChild[] = [];
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
const topDefaultWidth = columnWidth * 6;
const topDefaultHeight = headerHeight * 0.5;
for (let i = 0; i < dates.length; i++) {
const date = dates[i];
let bottomValue = getLocaleMonth(date, locale);
const bottomValue = getLocaleMonth(date, locale);
bottomValues.push(
<text
key={bottomValue + date.getFullYear()}
y={headerHeight * 0.8}
x={columnWidth * i + columnWidth * 0.5}
className="GanttCalendar-bottomText"
className={styles.calendarBottomText}
>
{bottomValue}
</text>
);
if (i === 0 || date.getFullYear() !== dates[i - 1].getFullYear()) {
let topValue = date.getFullYear().toString();
const topValue = date.getFullYear().toString();
topValues.push(
<TopPartOfCalendar
key={topValue}
@@ -64,18 +65,18 @@ export const Calendar: React.FC<CalendarProps> = ({
};
const getCalendarValuesForWeek = () => {
let topValues: ReactChild[] = [];
let bottomValues: ReactChild[] = [];
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
let weeksCount: number = 0;
const topDefaultHeight = headerHeight * 0.5;
for (let i = dates.length - 1; i >= 0; i--) {
const date = dates[i];
let topValue = '';
let topValue = "";
if (i === 0 || date.getMonth() !== dates[i - 1].getMonth()) {
//top
// top
topValue = `${getLocaleMonth(date, locale)}, ${date.getFullYear()}`;
}
//bottom
// bottom
const bottomValue = `W${getWeekNumberISO8601(date)}`;
bottomValues.push(
@@ -83,14 +84,14 @@ export const Calendar: React.FC<CalendarProps> = ({
key={date.getTime()}
y={headerHeight * 0.8}
x={columnWidth * i}
className="GanttCalendar-bottomText"
className={styles.calendarBottomText}
>
{bottomValue}
</text>
);
if (topValue) {
//if last day is new month
// if last day is new month
if (i !== dates.length - 1) {
topValues.push(
<TopPartOfCalendar
@@ -112,8 +113,8 @@ export const Calendar: React.FC<CalendarProps> = ({
};
const getCalendarValuesForDay = () => {
let topValues: ReactChild[] = [];
let bottomValues: ReactChild[] = [];
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
const topDefaultHeight = headerHeight * 0.5;
for (let i = 0; i < dates.length; i++) {
const date = dates[i];
@@ -124,7 +125,7 @@ export const Calendar: React.FC<CalendarProps> = ({
key={date.getTime()}
y={headerHeight * 0.8}
x={columnWidth * i + columnWidth * 0.5}
className="GanttCalendar-bottomText"
className={styles.calendarBottomText}
>
{bottomValue}
</text>
@@ -133,7 +134,7 @@ export const Calendar: React.FC<CalendarProps> = ({
i + 1 !== dates.length &&
date.getMonth() !== dates[i + 1].getMonth()
) {
let topValue = getLocaleMonth(date, locale);
const topValue = getLocaleMonth(date, locale);
topValues.push(
<TopPartOfCalendar
@@ -152,15 +153,15 @@ export const Calendar: React.FC<CalendarProps> = ({
};
const getCalendarValuesForOther = () => {
let topValues: ReactChild[] = [];
let bottomValues: ReactChild[] = [];
let ticks = viewMode === ViewMode.HalfDay ? 2 : 4;
const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = [];
const ticks = viewMode === ViewMode.HalfDay ? 2 : 4;
const topDefaultHeight = headerHeight * 0.5;
for (let i = 0; i < dates.length; i++) {
const date = dates[i];
const bottomValue = Intl.DateTimeFormat(locale, {
hour: 'numeric',
hour: "numeric",
}).format(date);
bottomValues.push(
@@ -168,7 +169,7 @@ export const Calendar: React.FC<CalendarProps> = ({
key={date.getTime()}
y={headerHeight * 0.8}
x={columnWidth * i}
className="GanttCalendar-bottomText"
className={styles.calendarBottomText}
fontFamily={fontFamily}
>
{bottomValue}
@@ -1,5 +1,5 @@
import React from 'react';
import '../../style.css';
import React from "react";
import styles from "./calendar.module.css";
type TopPartOfCalendarProps = {
value: string;
@@ -19,23 +19,23 @@ export const TopPartOfCalendar: React.FC<TopPartOfCalendarProps> = ({
yText,
}) => {
return (
<>
<g className="calendarTop">
<line
x1={x1Line}
y1={y1Line}
x2={x1Line}
y2={y2Line}
className="GanttCalendar-topTick"
key={value + 'line'}
></line>
className={styles.calendarTopTick}
key={value + "line"}
/>
<text
key={value + 'text'}
key={value + "text"}
y={yText}
x={xText}
className="GanttCalendar-topText"
className={styles.calendarTopText}
>
{value}
</text>
</>
</g>
);
};
+69 -53
View File
@@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react';
import { Task, EventOption } from '../../types/public-types';
import { Bar } from '../Bar/bar';
import { BarTask } from '../../types/bar-task';
import { Arrow } from '../Other/arrow';
import React, { useState, useEffect } from "react";
import { Task, EventOption } from "../../types/public-types";
import { Bar } from "../Bar/bar";
import { BarTask } from "../../types/bar-task";
import { Arrow } from "../Other/arrow";
import {
convertToBarTasks,
progressByX,
@@ -10,8 +10,9 @@ import {
endByX,
moveByX,
dateByX,
} from '../../helpers/bar-helper';
import { Tooltip } from '../Other/tooltip';
} from "../../helpers/bar-helper";
import { Tooltip } from "../Other/tooltip";
export interface GanttTask extends Task {
x1: number;
x2: number;
@@ -46,13 +47,13 @@ export type GanttContentProps = {
} & EventOption;
export type BarAction =
| 'progress'
| 'end'
| 'start'
| 'move'
| 'mouseenter'
| 'mouseleave'
| '';
| "progress"
| "end"
| "start"
| "move"
| "mouseenter"
| "mouseleave"
| "";
type BarEvent = {
action: BarAction;
@@ -84,7 +85,7 @@ export const GanttContent: React.FC<GanttContentProps> = ({
getTooltipContent,
}) => {
const [barEvent, setBarEvent] = useState<BarEvent>({
action: '',
action: "",
selectedTask: null,
});
const [isSVGListen, setIsSVGListen] = useState(false);
@@ -146,19 +147,20 @@ export const GanttContent: React.FC<GanttContentProps> = ({
* Method handles event in real time(mousemove) and on finish(mouseup)
*/
const handleMouseSVGChangeEventsSubscribe = async (event: MouseEvent) => {
if (!barEvent.selectedTask || !barEvent.action) return;
if (!barEvent.selectedTask || !barEvent.action || !svg || !svg.current)
return;
const selectedTask = barEvent.selectedTask;
const changedTask = { ...selectedTask } as BarTask;
switch (event.type) {
//On Event changing
case 'mousemove': {
// On Event changing
case "mousemove": {
switch (barEvent.action) {
case 'progress':
case "progress":
changedTask.progress = progressByX(event.offsetX, selectedTask);
break;
case 'start':
let newX1 = startByX(event.offsetX, xStep, selectedTask);
case "start": {
const newX1 = startByX(event.offsetX, xStep, selectedTask);
changedTask.x1 = newX1;
changedTask.start = dateByX(
newX1,
@@ -168,8 +170,9 @@ export const GanttContent: React.FC<GanttContentProps> = ({
timeStep
);
break;
case 'end':
let newX2 = endByX(event.offsetX, xStep, selectedTask);
}
case "end": {
const newX2 = endByX(event.offsetX, xStep, selectedTask);
changedTask.x2 = newX2;
changedTask.end = dateByX(
newX2,
@@ -179,7 +182,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
timeStep
);
break;
case 'move':
}
case "move": {
const [newMoveX1, newMoveX2] = moveByX(
event.offsetX - initEventX1Delta,
xStep,
@@ -202,8 +206,10 @@ export const GanttContent: React.FC<GanttContentProps> = ({
changedTask.x1 = newMoveX1;
changedTask.x2 = newMoveX2;
break;
}
}
//Update internal state
// Update internal state
setBarTasks(
barTasks.map(t => (t.id === changedTask.id ? changedTask : t))
);
@@ -211,19 +217,19 @@ export const GanttContent: React.FC<GanttContentProps> = ({
break;
}
//On finish Event
case 'mouseup': {
// On finish Event
case "mouseup": {
let eventForExecution: (
task: Task
) => void | Promise<void> = () => {};
switch (barEvent.action) {
case 'progress':
case "progress":
changedTask.progress = progressByX(event.offsetX, selectedTask);
if (onProgressChange) {
eventForExecution = onProgressChange;
}
break;
case 'start':
case "start": {
const newX1 = startByX(event.offsetX, xStep, selectedTask);
changedTask.start = dateByX(
newX1,
@@ -236,7 +242,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
eventForExecution = onDateChange;
}
break;
case 'end':
}
case "end": {
const newX2 = endByX(event.offsetX, xStep, selectedTask);
changedTask.end = dateByX(
newX2,
@@ -250,7 +257,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
eventForExecution = onDateChange;
}
break;
case 'move':
}
case "move": {
const [newMoveX1, newMoveX2] = moveByX(
event.offsetX - initEventX1Delta,
xStep,
@@ -278,34 +286,41 @@ export const GanttContent: React.FC<GanttContentProps> = ({
eventForExecution = onDateChange;
}
break;
}
}
setBarEvent({ action: '', selectedTask: null });
setBarEvent({ action: "", selectedTask: null });
setIsSVGListen(false);
svg.current?.removeEventListener(
'mousemove',
svg.current.removeEventListener(
"mousemove",
handleMouseSVGChangeEventsSubscribe
);
svg.current?.removeEventListener(
'mouseup',
svg.current.removeEventListener(
"mouseup",
handleMouseSVGChangeEventsSubscribe
);
//If update successful - update Gantt state, otherwise we shell back old Bar state
// If update successful - update Gantt state, otherwise we shell back old Bar state
await eventForExecution(changedTask);
break;
}
}
};
if (barEvent.selectedTask && barEvent.action && !isSVGListen) {
if (
barEvent.selectedTask &&
barEvent.action &&
!isSVGListen &&
svg &&
svg.current
) {
setIsSVGListen(true);
svg.current?.addEventListener(
'mousemove',
svg.current.addEventListener(
"mousemove",
handleMouseSVGChangeEventsSubscribe
);
svg.current?.addEventListener(
'mouseup',
svg.current.addEventListener(
"mouseup",
handleMouseSVGChangeEventsSubscribe
);
}
@@ -336,18 +351,19 @@ export const GanttContent: React.FC<GanttContentProps> = ({
task: BarTask
) => {
switch (event.type) {
case 'mousedown':
case "mousedown":
setBarEvent({ ...barEvent, selectedTask: task, action: eventType });
setInitEventX1Delta(event.nativeEvent.offsetX - task.x1);
event.stopPropagation();
break;
case 'mouseleave':
case "mouseleave":
console.log("mouseleave");
if (!barEvent.action)
setBarEvent({ ...barEvent, selectedTask: task, action: '' });
setBarEvent({ ...barEvent, selectedTask: null, action: "" });
break;
case 'mouseenter':
case "mouseenter":
if (!barEvent.selectedTask) {
setBarEvent({ ...barEvent, selectedTask: task, action: '' });
setBarEvent({ ...barEvent, selectedTask: task, action: "" });
}
break;
}
@@ -364,7 +380,7 @@ export const GanttContent: React.FC<GanttContentProps> = ({
) => {
if (task.isDisabled) return;
switch (event.key) {
case 'Delete': {
case "Delete": {
if (onTaskDelete) {
onTaskDelete(task);
}
@@ -374,8 +390,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
};
return (
<>
<g className="arrow" fill={arrowColor} stroke={arrowColor}>
<g className="content">
<g className="arrows" fill={arrowColor} stroke={arrowColor}>
{barTasks.map(task => {
return task.barChildren.map(child => {
return (
@@ -408,8 +424,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
</g>
<g className="toolTip">
{barEvent.selectedTask &&
barEvent.action !== 'end' &&
barEvent.action !== 'start' && (
barEvent.action !== "end" &&
barEvent.action !== "start" && (
<Tooltip
x={barEvent.selectedTask.x2 + columnWidth + arrowIndent}
y={barEvent.selectedTask.y + rowHeight}
@@ -420,6 +436,6 @@ export const GanttContent: React.FC<GanttContentProps> = ({
/>
)}
</g>
</>
</g>
);
};
+15 -15
View File
@@ -1,9 +1,9 @@
import React, { useRef } from 'react';
import { ViewMode, GanttProps } from '../../types/public-types';
import { Grid, GridProps } from '../Grid/grid';
import { Calendar, CalendarProps } from '../Calendar/calendar';
import { GanttContent, GanttContentProps } from './gantt-content';
import { ganttDateRange, seedDates } from '../../helpers/date-helper';
import React, { useRef } from "react";
import { ViewMode, GanttProps } from "../../types/public-types";
import { Grid, GridProps } from "../Grid/grid";
import { Calendar, CalendarProps } from "../Calendar/calendar";
import { GanttContent, GanttContentProps } from "./gantt-content";
import { ganttDateRange, seedDates } from "../../helpers/date-helper";
export const Gantt: React.SFC<GanttProps> = ({
tasks,
@@ -11,20 +11,20 @@ export const Gantt: React.SFC<GanttProps> = ({
columnWidth = 60,
rowHeight = 50,
viewMode = ViewMode.Day,
locale = 'en-GB',
locale = "en-GB",
barFill = 60,
barCornerRadius = 3,
barProgressColor = '#a3a3ff',
barProgressSelectedColor = '#8282f5',
barBackgroundColor = '#b8c2cc',
barBackgroundSelectedColor = '#aeb8c2',
barProgressColor = "#a3a3ff",
barProgressSelectedColor = "#8282f5",
barBackgroundColor = "#b8c2cc",
barBackgroundSelectedColor = "#aeb8c2",
handleWidth = 8,
timeStep = 300000,
arrowColor = 'grey',
fontFamily = 'Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue',
fontSize = '14px',
arrowColor = "grey",
fontFamily = "Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue",
fontSize = "14px",
arrowIndent = 20,
todayColor = 'rgba(252, 248, 227, 0.5)',
todayColor = "rgba(252, 248, 227, 0.5)",
onDateChange,
onProgressChange,
onDoubleClick,
+21 -21
View File
@@ -1,7 +1,7 @@
import React, { ReactChild } from 'react';
import { Task } from '../../types/public-types';
import { addToDate } from '../../helpers/date-helper';
import '../../style.css';
import React, { ReactChild } from "react";
import { Task } from "../../types/public-types";
import { addToDate } from "../../helpers/date-helper";
import styles from "./grid.module.css";
export type GridBodyProps = {
tasks: Task[];
@@ -22,36 +22,36 @@ export const GridBody: React.FC<GridBodyProps> = ({
todayColor,
}) => {
let y = headerHeight;
let gridRows: ReactChild[] = [];
let rowLines: ReactChild[] = [];
const gridRows: ReactChild[] = [];
const rowLines: ReactChild[] = [];
for (const task of tasks) {
gridRows.push(
<rect
key={'Row' + task.id}
key={"Row" + task.id}
x="0"
y={y}
width={gridWidth}
height={rowHeight}
className="GanttGrid-row"
></rect>
className={styles.gridRow}
/>
);
rowLines.push(
<line
key={'RowLine' + task.id}
key={"RowLine" + task.id}
x="0"
y1={y + rowHeight}
x2={gridWidth}
y2={y + rowHeight}
className="GanttGrid-rowLine"
></line>
className={styles.gridRowLine}
/>
);
y += rowHeight;
}
const now = new Date();
let tickX = 0;
let ticks: ReactChild[] = [];
let today: ReactChild = <></>;
const ticks: ReactChild[] = [];
let today: ReactChild = <rect />;
for (let i = 0; i < dates.length; i++) {
const date = dates[i];
ticks.push(
@@ -61,21 +61,21 @@ export const GridBody: React.FC<GridBodyProps> = ({
y1={headerHeight}
x2={tickX}
y2={y}
className="GanttGrid-tick"
></line>
className={styles.gridTick}
/>
);
if (
(i + 1 !== dates.length &&
date.getTime() < now.getTime() &&
dates[i + 1].getTime() >= now.getTime()) ||
//if current date is last
// if current date is last
(i !== 0 &&
i + 1 === dates.length &&
date.getTime() < now.getTime() &&
addToDate(
date,
date.getTime() - dates[i - 1].getTime(),
'millisecond'
"millisecond"
).getTime() >= now.getTime())
) {
today = (
@@ -85,17 +85,17 @@ export const GridBody: React.FC<GridBodyProps> = ({
width={columnWidth}
height={y}
fill={todayColor}
></rect>
/>
);
}
tickX += columnWidth;
}
return (
<>
<g className="gridBody">
<g className="rows">{gridRows}</g>
<g className="rowLines">{rowLines}</g>
<g className="ticks">{ticks}</g>
<g className="today">{today}</g>
</>
</g>
);
};
+4 -4
View File
@@ -1,5 +1,5 @@
import React from 'react';
import '../../style.css';
import React from "react";
import styles from "./grid.module.css";
export type GridHeaderProps = {
gridWidth: number;
@@ -15,7 +15,7 @@ export const GridHeader: React.FC<GridHeaderProps> = ({
y="0"
width={gridWidth}
height={headerHeight}
className="GanttGrid-header"
></rect>
className={styles.gridHeader}
/>
);
};
+21
View File
@@ -0,0 +1,21 @@
.gridRow {
fill: #ffffff;
}
.gridRow:nth-child(even) {
fill: #f5f5f5;
}
.gridHeader {
fill: #ffffff;
stroke: #e0e0e0;
stroke-width: 1.4;
}
.gridRowLine {
stroke: #ebeff2;
}
.gridTick {
stroke: #e6e4e4;
}
+3 -3
View File
@@ -1,6 +1,6 @@
import React from 'react';
import { GridBody, GridBodyProps } from './grid-body';
import { GridHeader, GridHeaderProps } from './grid-header';
import React from "react";
import { GridBody, GridBodyProps } from "./grid-body";
import { GridHeader, GridHeaderProps } from "./grid-header";
export type GridProps = GridBodyProps & GridHeaderProps;
export const Grid: React.FC<GridProps> = props => {
+4 -4
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { BarTask } from '../../types/bar-task';
import React from "react";
import { BarTask } from "../../types/bar-task";
type ArrowProps = {
taskFrom: BarTask;
@@ -26,9 +26,9 @@ export const Arrow: React.FC<ArrowProps> = ({
${taskTo.x1 - 5},${taskToEndPosition - 5}
${taskTo.x1 - 5},${taskToEndPosition + 5}`;
return (
<>
<g className="arrow">
<path strokeWidth="1.5" d={path} fill="none" />
<polygon points={trianglePoints} />
</>
</g>
);
};
+15
View File
@@ -0,0 +1,15 @@
.tooltipDefaultContainer {
background: #fff;
padding: 12px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
.tooltipDefaultContainerParagraph {
font-size: 12px;
margin-bottom: 6px;
color: #666;
}
.tooltipDetailsContainer {
display: table;
}
+15 -10
View File
@@ -1,6 +1,7 @@
import React, { useRef, useEffect, useState } from 'react';
import { Task } from '../../types/public-types';
import '../../style.css';
import React, { useRef, useEffect, useState } from "react";
import { Task } from "../../types/public-types";
import styles from "./tooltip.module.css";
export type TooltipProps = {
x: number;
y: number;
@@ -36,7 +37,7 @@ export const Tooltip: React.FC<TooltipProps> = ({
}, [tooltipRef, y]);
return (
<foreignObject x={x} y={relatedY} width={toolWidth} height={1000}>
<div ref={tooltipRef} className="TooltipDetailsContainer">
<div ref={tooltipRef} className={styles.tooltipDetailsContainer}>
{getTooltipContent(task, fontSize, fontFamily)}
</div>
</foreignObject>
@@ -53,17 +54,21 @@ const getStandardTooltipContent = (
fontFamily,
};
return (
<div className="TooltipDefaultContainer" style={style}>
<div className={styles.tooltipDefaultContainer} style={style}>
<b style={{ fontSize: fontSize + 6 }}>{`${
task.name
}: ${task.start.getDate()}-${task.start.getMonth() +
1}-${task.start.getFullYear()} - ${task.end.getDate()}-${task.end.getMonth() +
1}-${task.end.getFullYear()}`}</b>
<p className="TooltipDefaultContainer-paragraph">{`Duration: ${~~(
}: ${task.start.getDate()}-${
task.start.getMonth() + 1
}-${task.start.getFullYear()} - ${task.end.getDate()}-${
task.end.getMonth() + 1
}-${task.end.getFullYear()}`}</b>
<p className={styles.tooltipDefaultContainerParagraph}>{`Duration: ${~~(
(task.end.getTime() - task.start.getTime()) /
(1000 * 60 * 60 * 24)
)} day(s)`}</p>
<p className="TooltipDefaultContainer-paragraph">{`Progress: ${task.progress} %`}</p>
<p
className={styles.tooltipDefaultContainerParagraph}
>{`Progress: ${task.progress} %`}</p>
</div>
);
};
+3 -3
View File
@@ -1,5 +1,5 @@
import { Task } from '../types/public-types';
import { BarTask } from '../types/bar-task';
import { Task } from "../types/public-types";
import { BarTask } from "../types/bar-task";
export const convertToBarTasks = (
tasks: Task[],
@@ -168,7 +168,7 @@ export const getProgressPoint = (
progressX,
taskY + taskHeight - 8.66,
];
return point.join(',');
return point.join(",");
};
export const startByX = (x: number, xStep: number, task: BarTask) => {
+70 -62
View File
@@ -1,54 +1,54 @@
import { Task, ViewMode } from '../types/public-types';
import { Task, ViewMode } from "../types/public-types";
type DateHelperScales =
| 'year'
| 'month'
| 'day'
| 'hour'
| 'minute'
| 'second'
| 'millisecond';
| "year"
| "month"
| "day"
| "hour"
| "minute"
| "second"
| "millisecond";
export const addToDate = (
date: Date,
quantity: number,
scale: DateHelperScales
) => {
let newDate = new Date(
date.getFullYear() + (scale === 'year' ? quantity : 0),
date.getMonth() + (scale === 'month' ? quantity : 0),
date.getDate() + (scale === 'day' ? quantity : 0),
date.getHours() + (scale === 'hour' ? quantity : 0),
date.getMinutes() + (scale === 'minute' ? quantity : 0),
date.getSeconds() + (scale === 'second' ? quantity : 0),
date.getMilliseconds() + (scale === 'millisecond' ? quantity : 0)
const newDate = new Date(
date.getFullYear() + (scale === "year" ? quantity : 0),
date.getMonth() + (scale === "month" ? quantity : 0),
date.getDate() + (scale === "day" ? quantity : 0),
date.getHours() + (scale === "hour" ? quantity : 0),
date.getMinutes() + (scale === "minute" ? quantity : 0),
date.getSeconds() + (scale === "second" ? quantity : 0),
date.getMilliseconds() + (scale === "millisecond" ? quantity : 0)
);
return newDate;
};
export const startOfDate = (date: Date, scale: DateHelperScales) => {
const scores = [
'millisecond',
'second',
'minute',
'hour',
'day',
'month',
'year',
"millisecond",
"second",
"minute",
"hour",
"day",
"month",
"year",
];
const shouldReset = (_scale: DateHelperScales) => {
const max_score = scores.indexOf(scale);
return scores.indexOf(_scale) <= max_score;
const maxScore = scores.indexOf(scale);
return scores.indexOf(_scale) <= maxScore;
};
let newDate = new Date(
const newDate = new Date(
date.getFullYear(),
shouldReset('year') ? 0 : date.getMonth(),
shouldReset('month') ? 1 : date.getDate(),
shouldReset('day') ? 0 : date.getHours(),
shouldReset('hour') ? 0 : date.getMinutes(),
shouldReset('minute') ? 0 : date.getSeconds(),
shouldReset('second') ? 0 : date.getMilliseconds()
shouldReset("year") ? 0 : date.getMonth(),
shouldReset("month") ? 1 : date.getDate(),
shouldReset("day") ? 0 : date.getHours(),
shouldReset("hour") ? 0 : date.getMinutes(),
shouldReset("minute") ? 0 : date.getSeconds(),
shouldReset("second") ? 0 : date.getMilliseconds()
);
return newDate;
};
@@ -56,7 +56,7 @@ export const startOfDate = (date: Date, scale: DateHelperScales) => {
export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
let newStartDate: Date = tasks[0].start;
let newEndDate: Date = tasks[0].end;
for (let task of tasks) {
for (const task of tasks) {
if (task.start < newStartDate) {
newStartDate = task.start;
}
@@ -64,22 +64,24 @@ export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
newEndDate = task.end;
}
}
if (viewMode === ViewMode.Month) {
newStartDate = addToDate(newStartDate, -1, 'month');
newEndDate = addToDate(newEndDate, 1, 'year');
newEndDate = startOfDate(newEndDate, 'year');
} else if (viewMode === ViewMode.Week) {
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(getMonday(newStartDate), -7, 'day');
newEndDate = addToDate(newEndDate, 1.5, 'month');
} else {
newStartDate = startOfDate(newStartDate, 'day');
newEndDate = startOfDate(newEndDate, 'day');
newStartDate = addToDate(newStartDate, -1, 'day');
newEndDate = addToDate(newEndDate, 19, 'day');
switch (viewMode) {
case ViewMode.Month:
newStartDate = addToDate(newStartDate, -1, "month");
newEndDate = addToDate(newEndDate, 1, "year");
newEndDate = startOfDate(newEndDate, "year");
break;
case ViewMode.Week:
newStartDate = startOfDate(newStartDate, "day");
newEndDate = startOfDate(newEndDate, "day");
newStartDate = addToDate(getMonday(newStartDate), -7, "day");
newEndDate = addToDate(newEndDate, 1.5, "month");
break;
default:
newStartDate = startOfDate(newStartDate, "day");
newEndDate = startOfDate(newEndDate, "day");
newStartDate = addToDate(newStartDate, -1, "day");
newEndDate = addToDate(newEndDate, 19, "day");
break;
}
return [newStartDate, newEndDate];
};
@@ -90,18 +92,24 @@ export const seedDates = (
viewMode: ViewMode
) => {
let currentDate: Date = new Date(startDate);
let dates: Date[] = [currentDate];
const dates: Date[] = [currentDate];
while (currentDate < endDate) {
if (viewMode === ViewMode.Month) {
currentDate = addToDate(currentDate, 1, 'month');
} else if (viewMode === ViewMode.Week) {
currentDate = addToDate(currentDate, 7, 'day');
} else if (viewMode === ViewMode.Day) {
currentDate = addToDate(currentDate, 1, 'day');
} else if (viewMode === ViewMode.HalfDay) {
currentDate = addToDate(currentDate, 12, 'hour');
} else if (viewMode === ViewMode.QuarterDay) {
currentDate = addToDate(currentDate, 6, 'hour');
switch (viewMode) {
case ViewMode.Month:
currentDate = addToDate(currentDate, 1, "month");
break;
case ViewMode.Week:
currentDate = addToDate(currentDate, 7, "day");
break;
case ViewMode.Day:
currentDate = addToDate(currentDate, 1, "day");
break;
case ViewMode.HalfDay:
currentDate = addToDate(currentDate, 12, "hour");
break;
case ViewMode.QuarterDay:
currentDate = addToDate(currentDate, 6, "hour");
break;
}
dates.push(currentDate);
}
@@ -110,7 +118,7 @@ export const seedDates = (
export const getLocaleMonth = (date: Date, locale: string) => {
let bottomValue = new Intl.DateTimeFormat(locale, {
month: 'long',
month: "long",
}).format(date);
bottomValue = bottomValue.replace(
bottomValue[0],
@@ -130,7 +138,7 @@ const getMonday = (date: Date) => {
};
export const getWeekNumberISO8601 = (date: Date) => {
let tmpDate = new Date(date.valueOf());
const tmpDate = new Date(date.valueOf());
const dayNumber = (tmpDate.getDay() + 6) % 7;
tmpDate.setDate(tmpDate.getDate() - dayNumber + 3);
const firstThursday = tmpDate.valueOf();
+4 -4
View File
@@ -1,9 +1,9 @@
export { Gantt } from './components/Gantt/gantt';
export {
export { Gantt } from "./components/Gantt/gantt";
export { ViewMode } from "./types/public-types";
export type {
GanttProps,
Task,
ViewMode,
StylingOption,
DisplayOption,
EventOption,
} from './types/public-types';
} from "./types/public-types";
+1
View File
@@ -0,0 +1 @@
/// <reference types="react-scripts" />
-34
View File
@@ -1,34 +0,0 @@
import { Task } from '../types/public-types';
type GanttReduceState = {
ganttTasks: Task[];
};
export type GanttReduceAction = {
type: 'update' | 'delete';
changedTask?: Task;
};
export function ganttReducer(
state: GanttReduceState,
action: GanttReduceAction
): GanttReduceState {
switch (action.type) {
case 'update': {
return {
ganttTasks: state.ganttTasks.map(t =>
t.id === action.changedTask?.id ? action.changedTask : t
),
};
}
case 'delete': {
return {
ganttTasks: state.ganttTasks.filter(
t => t.id !== action.changedTask?.id
),
};
}
default:
return state;
}
}
View File
File renamed without changes.
+1 -1
View File
@@ -1,4 +1,4 @@
import { Task } from './public-types';
import { Task } from "./public-types";
export interface BarTask extends Task {
index: number;
+5 -5
View File
@@ -1,10 +1,10 @@
export enum ViewMode {
QuarterDay = 'Quarter Day',
HalfDay = 'Half Day',
Day = 'Day',
QuarterDay = "Quarter Day",
HalfDay = "Half Day",
Day = "Day",
/** ISO-8601 week */
Week = 'Week',
Month = 'Month',
Week = "Week",
Month = "Month",
}
export interface Task {
id: string;
+18
View File
@@ -0,0 +1,18 @@
/**
* Default CSS definition for typescript,
* will be overridden with file-specific definitions by rollup
*/
declare module "*.css" {
const content: { [className: string]: string };
export default content;
}
interface SvgrComponent
extends React.StatelessComponent<React.SVGAttributes<SVGElement>> {}
declare module "*.svg" {
const svgUrl: string;
const svgComponent: SvgrComponent;
export default svgUrl;
export { svgComponent as ReactComponent };
}