From 6c51146f91b9a855fbba09a6882ece13f5025fe9 Mon Sep 17 00:00:00 2001 From: MaTeMaTuK Date: Mon, 28 Jun 2021 23:15:53 +0300 Subject: [PATCH 1/4] rtl experiment --- example/src/App.tsx | 25 ++++---- src/components/gantt/gantt.tsx | 10 ++- src/components/gantt/task-gantt-content.tsx | 8 ++- src/components/other/horizontal-scroll.tsx | 9 ++- src/components/task-item/bar/bar-display.tsx | 5 +- src/components/task-item/bar/bar-small.tsx | 11 ++-- src/components/task-item/bar/bar.tsx | 11 ++-- src/components/task-item/project/project.tsx | 6 +- src/helpers/bar-helper.ts | 67 ++++++++++++++++---- src/types/bar-task.ts | 2 + src/types/public-types.ts | 1 + 11 files changed, 106 insertions(+), 49 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index e2717d63..a15fd19e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -64,17 +64,20 @@ const App = () => { isChecked={isChecked} />

Gantt With Unlimited Height

- +
+ +

Gantt With Limited Height

= ({ projectBackgroundSelectedColor = "#f7bb53", milestoneBackgroundColor = "#f1c453", milestoneBackgroundSelectedColor = "#f29e4c", + rtl = false, handleWidth = 8, timeStep = 300000, arrowColor = "grey", @@ -83,7 +84,10 @@ export const Gantt: React.FunctionComponent = ({ // task change events useEffect(() => { const [startDate, endDate] = ganttDateRange(tasks, viewMode); - const newDates = seedDates(startDate, endDate, viewMode); + let newDates = seedDates(startDate, endDate, viewMode); + if (rtl) { + newDates = newDates.reverse(); + } setDateSetup({ dates: newDates, viewMode }); setBarTasks( convertToBarTasks( @@ -94,6 +98,7 @@ export const Gantt: React.FunctionComponent = ({ taskHeight, barCornerRadius, handleWidth, + rtl, barProgressColor, barProgressSelectedColor, barBackgroundColor, @@ -124,6 +129,7 @@ export const Gantt: React.FunctionComponent = ({ projectBackgroundSelectedColor, milestoneBackgroundColor, milestoneBackgroundSelectedColor, + rtl, ]); useEffect(() => { @@ -344,6 +350,7 @@ export const Gantt: React.FunctionComponent = ({ fontSize, arrowIndent, svgWidth, + rtl, setGanttEvent, setFailedTask, setSelectedTask: handleSelectedTask, @@ -415,6 +422,7 @@ export const Gantt: React.FunctionComponent = ({ svgWidth={svgWidth} taskListWidth={taskListWidth} scroll={scrollX} + rtl={rtl} onScroll={handleScrollX} /> diff --git a/src/components/gantt/task-gantt-content.tsx b/src/components/gantt/task-gantt-content.tsx index f316b8ed..bc0814cd 100644 --- a/src/components/gantt/task-gantt-content.tsx +++ b/src/components/gantt/task-gantt-content.tsx @@ -26,6 +26,7 @@ export type TaskGanttContentProps = { arrowIndent: number; fontSize: string; fontFamily: string; + rtl: boolean; setGanttEvent: (value: GanttEvent) => void; setFailedTask: (value: BarTask | null) => void; setSelectedTask: (taskId: string) => void; @@ -45,6 +46,7 @@ export const TaskGanttContent: React.FC = ({ arrowIndent, fontFamily, fontSize, + rtl, setGanttEvent, setFailedTask, setSelectedTask, @@ -85,7 +87,8 @@ export const TaskGanttContent: React.FC = ({ ganttEvent.changedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); if (isChanged) { setGanttEvent({ action: ganttEvent.action, changedTask }); @@ -108,7 +111,8 @@ export const TaskGanttContent: React.FC = ({ changedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); const isNotLikeOriginal = diff --git a/src/components/other/horizontal-scroll.tsx b/src/components/other/horizontal-scroll.tsx index 1f5668e5..3a179dd4 100644 --- a/src/components/other/horizontal-scroll.tsx +++ b/src/components/other/horizontal-scroll.tsx @@ -5,8 +5,9 @@ export const HorizontalScroll: React.FC<{ scroll: number; svgWidth: number; taskListWidth: number; + rtl: boolean; onScroll: (event: SyntheticEvent) => void; -}> = ({ scroll, svgWidth, taskListWidth, onScroll }) => { +}> = ({ scroll, svgWidth, taskListWidth, rtl, onScroll }) => { const scrollRef = useRef(null); useEffect(() => { @@ -17,7 +18,11 @@ export const HorizontalScroll: React.FC<{ return (
= ({ width, height, isSelected, + progressX, progressWidth, barCornerRadius, styles, @@ -49,7 +52,7 @@ export const BarDisplay: React.FC = ({ className={style.barBackground} /> = ({ onEventStart, isSelected, }) => { - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const progressPoint = getProgressPoint( - progressWidth + task.x1, + task.progressWidth + task.x1, task.y, task.height ); @@ -28,7 +24,8 @@ export const BarSmall: React.FC = ({ y={task.y} width={task.x2 - task.x1} height={task.height} - progressWidth={progressWidth} + progressX={task.progressX} + progressWidth={task.progressWidth} barCornerRadius={task.barCornerRadius} styles={task.styles} isSelected={isSelected} diff --git a/src/components/task-item/bar/bar.tsx b/src/components/task-item/bar/bar.tsx index 2796a5cd..6a50ee72 100644 --- a/src/components/task-item/bar/bar.tsx +++ b/src/components/task-item/bar/bar.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - progressWithByParams, - getProgressPoint, -} from "../../../helpers/bar-helper"; +import { getProgressPoint } from "../../../helpers/bar-helper"; import { BarDisplay } from "./bar-display"; import { BarDateHandle } from "./bar-date-handle"; import { BarProgressHandle } from "./bar-progress-handle"; @@ -16,9 +13,8 @@ export const Bar: React.FC = ({ onEventStart, isSelected, }) => { - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const progressPoint = getProgressPoint( - progressWidth + task.x1, + task.progressWidth + task.x1, task.y, task.height ); @@ -30,7 +26,8 @@ export const Bar: React.FC = ({ y={task.y} width={task.x2 - task.x1} height={task.height} - progressWidth={progressWidth} + progressX={task.progressX} + progressWidth={task.progressWidth} barCornerRadius={task.barCornerRadius} styles={task.styles} isSelected={isSelected} diff --git a/src/components/task-item/project/project.tsx b/src/components/task-item/project/project.tsx index 21bddb33..5a47ba90 100644 --- a/src/components/task-item/project/project.tsx +++ b/src/components/task-item/project/project.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { progressWithByParams } from "../../../helpers/bar-helper"; import { TaskItemProps } from "../task-item"; import styles from "./project.module.css"; @@ -10,7 +9,6 @@ export const Project: React.FC = ({ task, isSelected }) => { const processColor = isSelected ? task.styles.progressSelectedColor : task.styles.progressColor; - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const projectWith = task.x2 - task.x1; const projectLeftTriangle = [ @@ -43,8 +41,8 @@ export const Project: React.FC = ({ task, isSelected }) => { className={styles.projectBackground} /> { - const x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); - let x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + let x1: number; + let x2: number; + if (rtl) { + x2 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); + x1 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + } else { + x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); + x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + } + let typeInternal: TaskTypeInternal = task.type; + if (typeInternal === "task" && x2 - x1 < handleWidth * 2) { + typeInternal = "smalltask"; + x2 = x1 + handleWidth * 2; + } + + const progressWidth = progressWithByParams(x1, x2, task.progress); + let progressX: number; + if (rtl) { + progressX = x2 - progressWidth; + } else { + progressX = x1; + } + const y = taskYCoordinate(index, rowHeight, taskHeight); const styles = { @@ -167,11 +194,6 @@ const convertToBar = ( progressSelectedColor: barProgressSelectedColor, ...task.styles, }; - let typeInternal: TaskTypeInternal = task.type; - if (typeInternal === "task" && x2 - x1 < handleWidth * 2) { - typeInternal = "smalltask"; - x2 = x1 + handleWidth * 2; - } return { ...task, typeInternal, @@ -179,6 +201,8 @@ const convertToBar = ( x2, y, index, + progressX, + progressWidth, barCornerRadius, handleWidth, height: taskHeight, @@ -199,7 +223,7 @@ const convertToMilestone = ( handleWidth: number, milestoneBackgroundColor: string, milestoneBackgroundSelectedColor: string -) => { +): BarTask => { const x = taskXCoordinate(task.start, dates, dateDelta, columnWidth); const y = taskYCoordinate(index, rowHeight, taskHeight); @@ -221,6 +245,8 @@ const convertToMilestone = ( x2, y, index, + progressX: 0, + progressWidth: 0, barCornerRadius, handleWidth, typeInternal: task.type, @@ -281,9 +307,7 @@ export const progressByProgressWidth = ( const progressPercent = Math.round((progressWidth * 100) / barWidth); if (progressPercent >= 100) return 100; else if (progressPercent <= 0) return 0; - else { - return progressPercent; - } + else return progressPercent; }; const progressByX = (x: number, task: BarTask) => { @@ -364,7 +388,8 @@ export const handleTaskBySVGMouseEvent = ( selectedTask: BarTask, xStep: number, timeStep: number, - initEventX1Delta: number + initEventX1Delta: number, + rtl: boolean ): { isChanged: boolean; changedTask: BarTask } => { let result: { isChanged: boolean; changedTask: BarTask }; switch (selectedTask.type) { @@ -385,7 +410,8 @@ export const handleTaskBySVGMouseEvent = ( selectedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); break; } @@ -398,7 +424,8 @@ const handleTaskBySVGMouseEventForBar = ( selectedTask: BarTask, xStep: number, timeStep: number, - initEventX1Delta: number + initEventX1Delta: number, + rtl: boolean ): { isChanged: boolean; changedTask: BarTask } => { const changedTask: BarTask = { ...selectedTask }; let isChanged = false; @@ -406,6 +433,18 @@ const handleTaskBySVGMouseEventForBar = ( case "progress": changedTask.progress = progressByX(svgX, selectedTask); isChanged = changedTask.progress !== selectedTask.progress; + if (isChanged) { + changedTask.progressWidth = progressWithByParams( + changedTask.x1, + changedTask.x2, + changedTask.progress + ); + if (rtl) { + changedTask.progressX = changedTask.x2 - changedTask.progressWidth; + } else { + changedTask.progressX = changedTask.x1; + } + } break; case "start": { const newX1 = startByX(svgX, xStep, selectedTask); diff --git a/src/types/bar-task.ts b/src/types/bar-task.ts index 1b45371a..4f3f783f 100644 --- a/src/types/bar-task.ts +++ b/src/types/bar-task.ts @@ -7,6 +7,8 @@ export interface BarTask extends Task { x2: number; y: number; height: number; + progressX: number; + progressWidth: number; barCornerRadius: number; handleWidth: number; barChildren: number[]; diff --git a/src/types/public-types.ts b/src/types/public-types.ts index c4428fe1..f51b88c1 100644 --- a/src/types/public-types.ts +++ b/src/types/public-types.ts @@ -65,6 +65,7 @@ export interface DisplayOption { * Specifies the month name language. Able formats: ISO 639-2, Java Locale */ locale?: string; + rtl?: boolean; } export interface StylingOption { From a85961cc20e0568f5bef7ed13d676d45abe1f7d9 Mon Sep 17 00:00:00 2001 From: MaTeMaTuK Date: Tue, 3 Aug 2021 21:27:44 +0300 Subject: [PATCH 2/4] RTL + NEW ROWS --- example/src/App.tsx | 25 ++-- src/components/calendar/calendar.tsx | 27 +++- src/components/gantt/gantt.tsx | 21 ++- src/components/gantt/task-gantt-content.tsx | 2 + src/components/gantt/task-gantt.tsx | 1 + src/components/grid/grid-body.tsx | 19 +++ src/components/other/arrow.tsx | 86 +++++++++-- src/components/other/horizontal-scroll.tsx | 1 + src/components/other/tooltip.tsx | 54 ++++--- .../other/vertical-scroll.module.css | 1 - src/components/other/vertical-scroll.tsx | 16 ++- src/components/task-item/bar/bar.tsx | 3 +- src/components/task-item/task-item.tsx | 18 ++- src/components/task-list/task-list-table.tsx | 2 +- src/helpers/bar-helper.ts | 136 +++++++++++++----- src/helpers/date-helper.ts | 14 +- 16 files changed, 328 insertions(+), 98 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index a15fd19e..e2717d63 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -64,20 +64,17 @@ const App = () => { isChecked={isChecked} />

Gantt With Unlimited Height

-
- -
+

Gantt With Limited Height

= ({ dateSetup, locale, viewMode, + rtl, headerHeight, columnWidth, fontFamily, @@ -30,7 +33,6 @@ export const Calendar: React.FC = ({ const getCalendarValuesForMonth = () => { const topValues: ReactChild[] = []; const bottomValues: ReactChild[] = []; - const topDefaultWidth = columnWidth * 6; const topDefaultHeight = headerHeight * 0.5; for (let i = 0; i < dateSetup.dates.length; i++) { const date = dateSetup.dates[i]; @@ -50,6 +52,12 @@ export const Calendar: React.FC = ({ date.getFullYear() !== dateSetup.dates[i - 1].getFullYear() ) { const topValue = date.getFullYear().toString(); + let xText: number; + if (rtl) { + xText = (6 + i + date.getMonth() + 1) * columnWidth; + } else { + xText = (6 + i - date.getMonth()) * columnWidth; + } topValues.push( = ({ x1Line={columnWidth * i} y1Line={0} y2Line={topDefaultHeight} - xText={ - topDefaultWidth + columnWidth * i - date.getMonth() * columnWidth - } + xText={xText} yText={topDefaultHeight * 0.9} /> ); @@ -88,7 +94,7 @@ export const Calendar: React.FC = ({ {bottomValue} @@ -149,7 +155,12 @@ export const Calendar: React.FC = ({ x1Line={columnWidth * (i + 1)} y1Line={0} y2Line={topDefaultHeight} - xText={columnWidth * (i + 1) - date.getDate() * columnWidth * 0.5} + xText={ + columnWidth * (i + 1) - + getDaysInMonth(date.getMonth(), date.getFullYear()) * + columnWidth * + 0.5 + } yText={topDefaultHeight * 0.9} /> ); @@ -174,7 +185,7 @@ export const Calendar: React.FC = ({ @@ -196,8 +207,10 @@ export const Calendar: React.FC = ({ ); } } + return [topValues, bottomValues]; }; + let topValues: ReactChild[] = []; let bottomValues: ReactChild[] = []; switch (dateSetup.viewMode) { diff --git a/src/components/gantt/gantt.tsx b/src/components/gantt/gantt.tsx index 1236bab6..e2eaf067 100644 --- a/src/components/gantt/gantt.tsx +++ b/src/components/gantt/gantt.tsx @@ -74,19 +74,22 @@ export const Gantt: React.FunctionComponent = ({ const [selectedTask, setSelectedTask] = useState(); const [failedTask, setFailedTask] = useState(null); - const [scrollY, setScrollY] = useState(0); - const [scrollX, setScrollX] = useState(0); - const [ignoreScrollEvent, setIgnoreScrollEvent] = useState(false); - const svgWidth = dateSetup.dates.length * columnWidth; const ganttFullHeight = barTasks.length * rowHeight; + const [scrollY, setScrollY] = useState(0); + const [scrollX, setScrollX] = useState(-1); + const [ignoreScrollEvent, setIgnoreScrollEvent] = useState(false); + // task change events useEffect(() => { const [startDate, endDate] = ganttDateRange(tasks, viewMode); let newDates = seedDates(startDate, endDate, viewMode); if (rtl) { newDates = newDates.reverse(); + if (scrollX === -1) { + setScrollX(newDates.length * columnWidth); + } } setDateSetup({ dates: newDates, viewMode }); setBarTasks( @@ -130,6 +133,7 @@ export const Gantt: React.FunctionComponent = ({ milestoneBackgroundColor, milestoneBackgroundSelectedColor, rtl, + scrollX, ]); useEffect(() => { @@ -211,7 +215,7 @@ export const Gantt: React.FunctionComponent = ({ } setScrollX(newScrollX); event.preventDefault(); - } else { + } else if (ganttHeight) { let newScrollY = scrollY + event.deltaY; if (newScrollY < 0) { newScrollY = 0; @@ -238,7 +242,7 @@ export const Gantt: React.FunctionComponent = ({ wrapperRef.current.removeEventListener("wheel", handleWheel); } }; - }, [wrapperRef.current, scrollY, scrollX, ganttHeight, svgWidth]); + }, [wrapperRef.current, scrollY, scrollX, ganttHeight, svgWidth, rtl]); const handleScrollY = (event: SyntheticEvent) => { if (scrollY !== event.currentTarget.scrollTop && !ignoreScrollEvent) { @@ -326,6 +330,7 @@ export const Gantt: React.FunctionComponent = ({ rowHeight, dates: dateSetup.dates, todayColor, + rtl, }; const calendarProps: CalendarProps = { dateSetup, @@ -335,6 +340,7 @@ export const Gantt: React.FunctionComponent = ({ columnWidth, fontFamily, fontSize, + rtl, }; const barProps: TaskGanttContentProps = { tasks: barTasks, @@ -408,6 +414,8 @@ export const Gantt: React.FunctionComponent = ({ headerHeight={headerHeight} taskListWidth={taskListWidth} TooltipContent={TooltipContent} + rtl={rtl} + svgWidth={svgWidth} /> )} = ({ headerHeight={headerHeight} scroll={scrollY} onScroll={handleScrollY} + rtl={rtl} />
= ({ rowHeight={rowHeight} taskHeight={taskHeight} arrowIndent={arrowIndent} + rtl={rtl} /> ); }); @@ -278,6 +279,7 @@ export const TaskGanttContent: React.FC = ({ onEventStart={handleBarEventStart} key={task.id} isSelected={!!selectedTask && task.id === selectedTask.id} + rtl={rtl} /> ); })} diff --git a/src/components/gantt/task-gantt.tsx b/src/components/gantt/task-gantt.tsx index 7f9bc57c..73a76688 100644 --- a/src/components/gantt/task-gantt.tsx +++ b/src/components/gantt/task-gantt.tsx @@ -41,6 +41,7 @@ export const TaskGantt: React.FC = ({
= ({ tasks, @@ -18,6 +19,7 @@ export const GridBody: React.FC = ({ svgWidth, columnWidth, todayColor, + rtl, }) => { let y = 0; const gridRows: ReactChild[] = []; @@ -95,6 +97,23 @@ export const GridBody: React.FC = ({ /> ); } + // rtl for today + if ( + rtl && + i + 1 !== dates.length && + date.getTime() >= now.getTime() && + dates[i + 1].getTime() < now.getTime() + ) { + today = ( + + ); + } tickX += columnWidth; } return ( diff --git a/src/components/other/arrow.tsx b/src/components/other/arrow.tsx index 5ba35475..52e8f28b 100644 --- a/src/components/other/arrow.tsx +++ b/src/components/other/arrow.tsx @@ -7,6 +7,7 @@ type ArrowProps = { rowHeight: number; taskHeight: number; arrowIndent: number; + rtl: boolean; }; export const Arrow: React.FC = ({ taskFrom, @@ -14,23 +15,92 @@ export const Arrow: React.FC = ({ rowHeight, taskHeight, arrowIndent, + rtl, }) => { + let path: string; + let trianglePoints: string; + if (rtl) { + [path, trianglePoints] = drownPathAndTriangleRTL( + taskFrom, + taskTo, + rowHeight, + taskHeight, + arrowIndent + ); + } else { + [path, trianglePoints] = drownPathAndTriangle( + taskFrom, + taskTo, + rowHeight, + taskHeight, + arrowIndent + ); + } + + return ( + + + + + ); +}; + +const drownPathAndTriangle = ( + taskFrom: BarTask, + taskTo: BarTask, + rowHeight: number, + taskHeight: number, + arrowIndent: number +) => { const indexCompare = taskFrom.index > taskTo.index ? -1 : 1; const taskToEndPosition = taskTo.y + taskHeight / 2; + const taskFromEndPosition = taskFrom.x2 + arrowIndent * 2; + const taskFromHorizontalOffsetValue = + taskFromEndPosition < taskTo.x1 ? "" : `H ${taskTo.x1 - arrowIndent}`; + const taskToHorizontalOffsetValue = + taskFromEndPosition > taskTo.x1 + ? arrowIndent + : taskTo.x1 - taskFrom.x2 - arrowIndent; const path = `M ${taskFrom.x2} ${taskFrom.y + taskHeight / 2} h ${arrowIndent} v ${(indexCompare * rowHeight) / 2} - H ${taskTo.x1 - arrowIndent} + ${taskFromHorizontalOffsetValue} V ${taskToEndPosition} - h ${arrowIndent}`; + h ${taskToHorizontalOffsetValue}`; + const trianglePoints = `${taskTo.x1},${taskToEndPosition} ${taskTo.x1 - 5},${taskToEndPosition - 5} ${taskTo.x1 - 5},${taskToEndPosition + 5}`; - return ( - - - - - ); + return [path, trianglePoints]; +}; + +const drownPathAndTriangleRTL = ( + taskFrom: BarTask, + taskTo: BarTask, + rowHeight: number, + taskHeight: number, + arrowIndent: number +) => { + const indexCompare = taskFrom.index > taskTo.index ? -1 : 1; + const taskToEndPosition = taskTo.y + taskHeight / 2; + const taskFromEndPosition = taskFrom.x1 - arrowIndent * 2; + const taskFromHorizontalOffsetValue = + taskFromEndPosition > taskTo.x2 ? "" : `H ${taskTo.x2 + arrowIndent}`; + const taskToHorizontalOffsetValue = + taskFromEndPosition < taskTo.x2 + ? -arrowIndent + : taskTo.x2 - taskFrom.x1 + arrowIndent; + + const path = `M ${taskFrom.x1} ${taskFrom.y + taskHeight / 2} + h ${-arrowIndent} + v ${(indexCompare * rowHeight) / 2} + ${taskFromHorizontalOffsetValue} + V ${taskToEndPosition} + h ${taskToHorizontalOffsetValue}`; + + const trianglePoints = `${taskTo.x2},${taskToEndPosition} + ${taskTo.x2 + 5},${taskToEndPosition + 5} + ${taskTo.x2 + 5},${taskToEndPosition - 5}`; + return [path, trianglePoints]; }; diff --git a/src/components/other/horizontal-scroll.tsx b/src/components/other/horizontal-scroll.tsx index 3a179dd4..250d6a06 100644 --- a/src/components/other/horizontal-scroll.tsx +++ b/src/components/other/horizontal-scroll.tsx @@ -18,6 +18,7 @@ export const HorizontalScroll: React.FC<{ return (
= ({ task, rowHeight, + rtl, svgContainerHeight, svgContainerWidth, scrollX, @@ -40,30 +43,41 @@ export const Tooltip: React.FC = ({ const [relatedX, setRelatedX] = useState(0); useEffect(() => { if (tooltipRef.current) { - let newRelatedX = - task.x2 + arrowIndent + arrowIndent * 0.5 + taskListWidth - scrollX; - let newRelatedY = task.index * rowHeight - scrollY + headerHeight; - const tooltipHeight = tooltipRef.current.offsetHeight * 1.1; const tooltipWidth = tooltipRef.current.offsetWidth * 1.1; - const tooltipLowerPoint = tooltipHeight + newRelatedY - scrollY; - const tooltipLeftmostPoint = tooltipWidth + newRelatedX; - const fullChartWidth = taskListWidth + svgContainerWidth; - - if (tooltipLeftmostPoint > fullChartWidth) { - newRelatedX = - task.x1 + - taskListWidth - - arrowIndent - - arrowIndent * 0.5 - - scrollX - - tooltipWidth; + let newRelatedY = task.index * rowHeight - scrollY + headerHeight; + let newRelatedX: number; + if (rtl) { + newRelatedX = task.x1 - arrowIndent * 1.5 - tooltipWidth - scrollX; + if (newRelatedX < 0) { + newRelatedX = task.x2 + arrowIndent * 1.5 - scrollX; + } + const tooltipLeftmostPoint = tooltipWidth + newRelatedX; + if (tooltipLeftmostPoint > svgContainerWidth) { + newRelatedX = svgContainerWidth - tooltipWidth; + newRelatedY += rowHeight; + } + } else { + newRelatedX = task.x2 + arrowIndent * 1.5 + taskListWidth - scrollX; + const tooltipLeftmostPoint = tooltipWidth + newRelatedX; + const fullChartWidth = taskListWidth + svgContainerWidth; + if (tooltipLeftmostPoint > fullChartWidth) { + newRelatedX = + task.x1 + + taskListWidth - + arrowIndent * 1.5 - + scrollX - + tooltipWidth; + } + if (newRelatedX < taskListWidth) { + newRelatedX = svgContainerWidth + taskListWidth - tooltipWidth; + newRelatedY += rowHeight; + } } - if (newRelatedX < taskListWidth) { - newRelatedX = svgContainerWidth + taskListWidth - tooltipWidth; - newRelatedY += rowHeight; - } else if (tooltipLowerPoint > svgContainerHeight - scrollY) { + + const tooltipLowerPoint = tooltipHeight + newRelatedY - scrollY; + if (tooltipLowerPoint > svgContainerHeight - scrollY) { newRelatedY = svgContainerHeight - tooltipHeight; } setRelatedY(newRelatedY); diff --git a/src/components/other/vertical-scroll.module.css b/src/components/other/vertical-scroll.module.css index c2dcbc5f..dddf3c54 100644 --- a/src/components/other/vertical-scroll.module.css +++ b/src/components/other/vertical-scroll.module.css @@ -1,6 +1,5 @@ .scroll { overflow: hidden auto; - margin-left: -17px; width: 17px; flex-shrink: 0; } diff --git a/src/components/other/vertical-scroll.tsx b/src/components/other/vertical-scroll.tsx index a3bd157f..87b3f21e 100644 --- a/src/components/other/vertical-scroll.tsx +++ b/src/components/other/vertical-scroll.tsx @@ -6,8 +6,16 @@ export const VerticalScroll: React.FC<{ ganttHeight: number; ganttFullHeight: number; headerHeight: number; + rtl: boolean; onScroll: (event: SyntheticEvent) => void; -}> = ({ scroll, ganttHeight, ganttFullHeight, headerHeight, onScroll }) => { +}> = ({ + scroll, + ganttHeight, + ganttFullHeight, + headerHeight, + rtl, + onScroll, +}) => { const scrollRef = useRef(null); useEffect(() => { @@ -18,7 +26,11 @@ export const VerticalScroll: React.FC<{ return (
= ({ task, isProgressChangeable, isDateChangeable, + rtl, onEventStart, isSelected, }) => { const progressPoint = getProgressPoint( - task.progressWidth + task.x1, + +!rtl * task.progressWidth + task.progressX, task.y, task.height ); diff --git a/src/components/task-item/task-item.tsx b/src/components/task-item/task-item.tsx index 3314bbb1..fc20311b 100644 --- a/src/components/task-item/task-item.tsx +++ b/src/components/task-item/task-item.tsx @@ -15,6 +15,7 @@ export type TaskItemProps = { isDateChangeable: boolean; isDelete: boolean; isSelected: boolean; + rtl: boolean; onEventStart: ( action: GanttContentMoveAction, selectedTask: BarTask, @@ -29,6 +30,7 @@ export const TaskItem: React.FC = props => { isDelete, taskHeight, isSelected, + rtl, onEventStart, } = { ...props, @@ -63,9 +65,19 @@ export const TaskItem: React.FC = props => { const getX = () => { const width = task.x2 - task.x1; const hasChild = task.barChildren.length > 0; - return isTextInside - ? task.x1 + width * 0.5 - : task.x1 + width + arrowIndent * +hasChild + arrowIndent * 0.2; + if (isTextInside) { + return task.x1 + width * 0.5; + } + if (rtl && textRef.current) { + return ( + task.x1 - + textRef.current.getBBox().width - + arrowIndent * +hasChild - + arrowIndent * 0.2 + ); + } else { + return task.x1 + width + arrowIndent * +hasChild + arrowIndent * 0.2; + } }; return ( diff --git a/src/components/task-list/task-list-table.tsx b/src/components/task-list/task-list-table.tsx index 1a276e49..e2a7229c 100644 --- a/src/components/task-list/task-list-table.tsx +++ b/src/components/task-list/task-list-table.tsx @@ -12,7 +12,7 @@ export const TaskListTableDefault: React.FC<{ selectedTaskId: string; setSelectedTask: (taskId: string) => void; }> = ({ rowHeight, rowWidth, tasks, fontFamily, fontSize, locale }) => { - const dateTimeOptions = { + const dateTimeOptions: Intl.DateTimeFormatOptions = { weekday: "short", year: "numeric", month: "long", diff --git a/src/helpers/bar-helper.ts b/src/helpers/bar-helper.ts index 69ee6775..9531c0cb 100644 --- a/src/helpers/bar-helper.ts +++ b/src/helpers/bar-helper.ts @@ -165,8 +165,8 @@ const convertToBar = ( let x1: number; let x2: number; if (rtl) { - x2 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); - x1 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + x2 = taskXCoordinateRTL(task.start, dates, dateDelta, columnWidth); + x1 = taskXCoordinateRTL(task.end, dates, dateDelta, columnWidth); } else { x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); @@ -177,14 +177,12 @@ const convertToBar = ( x2 = x1 + handleWidth * 2; } - const progressWidth = progressWithByParams(x1, x2, task.progress); - let progressX: number; - if (rtl) { - progressX = x2 - progressWidth; - } else { - progressX = x1; - } - + const [progressWidth, progressX] = progressWithByParams( + x1, + x2, + task.progress, + rtl + ); const y = taskYCoordinate(index, rowHeight, taskHeight); const styles = { @@ -281,7 +279,16 @@ const taskXCoordinate = ( ); return x; }; - +const taskXCoordinateRTL = ( + xDate: Date, + dates: Date[], + dateDelta: number, + columnWidth: number +) => { + let x = taskXCoordinate(xDate, dates, dateDelta, columnWidth); + x += columnWidth; + return x; +}; const taskYCoordinate = ( index: number, rowHeight: number, @@ -294,9 +301,17 @@ const taskYCoordinate = ( export const progressWithByParams = ( taskX1: number, taskX2: number, - progress: number + progress: number, + rtl: boolean ) => { - return (taskX2 - taskX1) * progress * 0.01; + const progressWidth = (taskX2 - taskX1) * progress * 0.01; + let progressX: number; + if (rtl) { + progressX = taskX2 - progressWidth; + } else { + progressX = taskX1; + } + return [progressWidth, progressX]; }; export const progressByProgressWidth = ( @@ -319,6 +334,15 @@ const progressByX = (x: number, task: BarTask) => { return progressPercent; } }; +const progressByXRTL = (x: number, task: BarTask) => { + if (x >= task.x2) return 0; + else if (x <= task.x1) return 100; + else { + const barWidth = task.x2 - task.x1; + const progressPercent = Math.round(((task.x2 - x) * 100) / barWidth); + return progressPercent; + } +}; export const getProgressPoint = ( progressX: number, @@ -431,19 +455,21 @@ const handleTaskBySVGMouseEventForBar = ( let isChanged = false; switch (action) { case "progress": - changedTask.progress = progressByX(svgX, selectedTask); + if (rtl) { + changedTask.progress = progressByXRTL(svgX, selectedTask); + } else { + changedTask.progress = progressByX(svgX, selectedTask); + } isChanged = changedTask.progress !== selectedTask.progress; if (isChanged) { - changedTask.progressWidth = progressWithByParams( + const [progressWidth, progressX] = progressWithByParams( changedTask.x1, changedTask.x2, - changedTask.progress + changedTask.progress, + rtl ); - if (rtl) { - changedTask.progressX = changedTask.x2 - changedTask.progressWidth; - } else { - changedTask.progressX = changedTask.x1; - } + changedTask.progressWidth = progressWidth; + changedTask.progressX = progressX; } break; case "start": { @@ -451,13 +477,31 @@ const handleTaskBySVGMouseEventForBar = ( changedTask.x1 = newX1; isChanged = changedTask.x1 !== selectedTask.x1; if (isChanged) { - changedTask.start = dateByX( - newX1, - selectedTask.x1, - selectedTask.start, - xStep, - timeStep + if (rtl) { + changedTask.end = dateByX( + newX1, + selectedTask.x1, + selectedTask.end, + xStep, + timeStep + ); + } else { + changedTask.start = dateByX( + newX1, + selectedTask.x1, + selectedTask.start, + xStep, + timeStep + ); + } + const [progressWidth, progressX] = progressWithByParams( + changedTask.x1, + changedTask.x2, + changedTask.progress, + rtl ); + changedTask.progressWidth = progressWidth; + changedTask.progressX = progressX; } break; } @@ -466,13 +510,31 @@ const handleTaskBySVGMouseEventForBar = ( changedTask.x2 = newX2; isChanged = changedTask.x2 !== selectedTask.x2; if (isChanged) { - changedTask.end = dateByX( - newX2, - selectedTask.x2, - selectedTask.end, - xStep, - timeStep + if (rtl) { + changedTask.start = dateByX( + newX2, + selectedTask.x2, + selectedTask.start, + xStep, + timeStep + ); + } else { + changedTask.end = dateByX( + newX2, + selectedTask.x2, + selectedTask.end, + xStep, + timeStep + ); + } + const [progressWidth, progressX] = progressWithByParams( + changedTask.x1, + changedTask.x2, + changedTask.progress, + rtl ); + changedTask.progressWidth = progressWidth; + changedTask.progressX = progressX; } break; } @@ -500,6 +562,14 @@ const handleTaskBySVGMouseEventForBar = ( ); changedTask.x1 = newMoveX1; changedTask.x2 = newMoveX2; + const [progressWidth, progressX] = progressWithByParams( + changedTask.x1, + changedTask.x2, + changedTask.progress, + rtl + ); + changedTask.progressWidth = progressWidth; + changedTask.progressX = progressX; } break; } diff --git a/src/helpers/date-helper.ts b/src/helpers/date-helper.ts index 795fd653..400b47d3 100644 --- a/src/helpers/date-helper.ts +++ b/src/helpers/date-helper.ts @@ -83,11 +83,17 @@ export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => { newStartDate = addToDate(newStartDate, -1, "day"); newEndDate = addToDate(newEndDate, 19, "day"); break; - default: + case ViewMode.QuarterDay: newStartDate = startOfDate(newStartDate, "day"); newEndDate = startOfDate(newEndDate, "day"); newStartDate = addToDate(newStartDate, -1, "day"); - newEndDate = addToDate(newEndDate, 5, "day"); + newEndDate = addToDate(newEndDate, 66, "hour"); // 24(1 day)*3 - 6 + break; + case ViewMode.HalfDay: + newStartDate = startOfDate(newStartDate, "day"); + newEndDate = startOfDate(newEndDate, "day"); + newStartDate = addToDate(newStartDate, -1, "day"); + newEndDate = addToDate(newEndDate, 108, "hour"); // 24(1 day)*5 - 12 break; } return [newStartDate, newEndDate]; @@ -163,3 +169,7 @@ export const getWeekNumberISO8601 = (date: Date) => { return weekNumber; } }; + +export const getDaysInMonth = (month: number, year: number) => { + return new Date(year, month + 1, 0).getDate(); +}; From dc0a224f9da1d5990350cc69c08996b068894af8 Mon Sep 17 00:00:00 2001 From: MaTeMaTuK Date: Tue, 3 Aug 2021 21:34:39 +0300 Subject: [PATCH 3/4] version & documentation changes --- README.md | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8c0508d0..eb0b4c1a 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,11 @@ npm start ### DisplayOption -| Parameter Name | Type | Description | -| :------------- | :----- | :---------------------------------------------------------------------------------------------- | -| viewMode | enum | Specifies the time scale. Quarter Day, Half Day, Day, Week(ISO-8601, 1st day is Monday), Month. | -| locale | string | Specifies the month name language. Able formats: ISO 639-2, Java Locale. | +| Parameter Name | Type | Description | +| :------------- | :------ | :---------------------------------------------------------------------------------------------- | +| viewMode | enum | Specifies the time scale. Quarter Day, Half Day, Day, Week(ISO-8601, 1st day is Monday), Month. | +| locale | string | Specifies the month name language. Able formats: ISO 639-2, Java Locale. | +| rtl | boolean | Sets rtl mode. | ### StylingOption diff --git a/package.json b/package.json index 0fd75b3c..0eb4ba32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gantt-task-react", - "version": "0.3.2", + "version": "0.3.3", "description": "Interactive Gantt Chart for React with TypeScript.", "author": "MaTeMaTuK ", "homepage": "https://github.com/MaTeMaTuK/gantt-task-react", From 3343a10c32f6c16586ee3b7bd30b79e0247eb6b8 Mon Sep 17 00:00:00 2001 From: MaTeMaTuK Date: Tue, 3 Aug 2021 21:41:04 +0300 Subject: [PATCH 4/4] json lock --- example/package-lock.json | 244 +++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 122 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index c96c3e18..7614e022 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -34,19 +34,19 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", + "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", - "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz", + "integrity": "sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw==", "requires": { - "core-js-pure": "^3.0.0", + "core-js-pure": "^3.16.0", "regenerator-runtime": "^0.13.4" } }, @@ -63,9 +63,9 @@ }, "dependencies": { "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -87,47 +87,47 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "26.0.23", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", - "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "requires": { "jest-diff": "^26.0.0", "pretty-format": "^26.0.0" } }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" + "version": "16.4.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz", + "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ==" }, "@types/testing-library__jest-dom": { - "version": "5.9.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz", - "integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz", + "integrity": "sha512-Gk9vaXfbzc5zCXI9eYE9BI5BNHEp4D3FWjgqBE/ePGYElLAP+KvxBcsdkwfIVvezs605oiyd/VrpiHe3Oeg+Aw==", "requires": { "@types/jest": "*" } }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "ansi-regex": { "version": "5.0.0", @@ -179,9 +179,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "core-js-pure": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", - "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==" + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz", + "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ==" }, "css": { "version": "3.0.0", @@ -235,9 +235,9 @@ }, "dependencies": { "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -286,9 +286,9 @@ } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "source-map": { "version": "0.6.1", @@ -331,24 +331,24 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==" + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" }, "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -366,19 +366,19 @@ } }, "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", + "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", - "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz", + "integrity": "sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw==", "requires": { - "core-js-pure": "^3.0.0", + "core-js-pure": "^3.16.0", "regenerator-runtime": "^0.13.4" } }, @@ -395,24 +395,24 @@ } }, "@testing-library/dom": { - "version": "7.31.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.0.tgz", - "integrity": "sha512-0X7ACg4YvTRDFMIuTOEj6B4NpN7i3F/4j5igOcTI5NC5J+N4TribNdErCHOZF1LBWhhcyfwxelVwvoYNMUXTOA==", + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^4.2.0", "aria-query": "^4.2.2", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.4", + "dom-accessibility-api": "^0.5.6", "lz-string": "^1.4.4", "pretty-format": "^26.6.2" } }, "@types/aria-query": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" }, "@types/istanbul-lib-coverage": { "version": "2.0.3", @@ -428,30 +428,30 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "requires": { "@types/istanbul-lib-report": "*" } }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" + "version": "16.4.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz", + "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ==" }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "ansi-regex": { "version": "5.0.0", @@ -476,9 +476,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -534,14 +534,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "core-js-pure": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", - "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==" + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz", + "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ==" }, "dom-accessibility-api": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", + "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==" }, "escape-string-regexp": { "version": "1.0.5", @@ -603,9 +603,9 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "supports-color": { "version": "5.5.0", @@ -625,17 +625,17 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", + "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" } } }, @@ -673,30 +673,30 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "requires": { "@types/istanbul-lib-report": "*" } }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" + "version": "16.4.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz", + "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ==" }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "ansi-regex": { "version": "5.0.0", @@ -712,9 +712,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -799,14 +799,14 @@ }, "dependencies": { "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "csstype": { "version": "3.0.8", @@ -823,14 +823,14 @@ }, "dependencies": { "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/react": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.5.tgz", - "integrity": "sha512-bj4biDB9ZJmGAYTWSKJly6bMr4BLUiBrx9ujiJEoP9XIDY9CTaPGxE5QWN/1WjpPLzYF7/jRNnV2nNxNe970sw==", + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz", + "integrity": "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -838,9 +838,9 @@ } }, "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "csstype": { "version": "3.0.8",