awesome-timeline-react
Version:
awesome timeline for react applications
1 lines • 144 kB
Source Map (JSON)
{"version":3,"sources":["../src/timeline.tsx","../src/components/time-bar.tsx","../src/hooks/use-generate-blocks.tsx","../src/helpers/get-month-name.ts","../src/helpers/get-week-day-name.ts","../src/hooks/use-get-block-properties.ts","../src/components/rows-header.tsx","../src/components/row-header.tsx","../src/contexts/row-height-context.ts","../src/components/content.tsx","../src/components/lines-canvas.tsx","../src/hooks/use-produce-content.tsx","../src/components/static-event.tsx","../src/components/row-content.tsx","../node_modules/immer/src/utils/env.ts","../node_modules/immer/src/utils/errors.ts","../node_modules/immer/src/utils/common.ts","../node_modules/immer/src/utils/plugins.ts","../node_modules/immer/src/core/scope.ts","../node_modules/immer/src/core/finalize.ts","../node_modules/immer/src/core/proxy.ts","../node_modules/immer/src/core/immerClass.ts","../node_modules/immer/src/core/current.ts","../node_modules/immer/src/plugins/patches.ts","../node_modules/immer/src/plugins/mapset.ts","../node_modules/immer/src/immer.ts","../src/contexts/drag-started-context.ts","../src/contexts/external-properties-context.ts","../src/helpers/sort-events.ts","../src/components/event.tsx","../src/components/resize-icon.tsx","../src/hooks/use-intersection-observer.ts","../src/hooks/use-resize-observer.ts","../src/components/rt-indicator.tsx","../src/components/event-prompt.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\r\nimport {\r\n EventPromptActionsType,\r\n EventType,\r\n RowsHeightType,\r\n TimelineType,\r\n} from \"./types\";\r\nimport \"./style.css\";\r\nimport TimeBar from \"./components/time-bar\";\r\nimport RowsHeader from \"./components/rows-header\";\r\nimport Content from \"./components/content\";\r\nimport { RowsHeightContext } from \"./contexts/row-height-context\";\r\nimport { DragStartedContext } from \"./contexts/drag-started-context\";\r\nimport useResizeObserver from \"./hooks/use-resize-observer\";\r\nimport { ExternalPropertiesContext } from \"./contexts/external-properties-context\";\r\nimport sortEvents from \"./helpers/sort-events\";\r\nimport RTIndicator from \"./components/rt-indicator\";\r\nimport EventPrompt from \"./components/event-prompt\";\r\n\r\nexport const Timeline = ({\r\n rows,\r\n events,\r\n staticEvents,\r\n onDrop,\r\n onResize,\r\n startDate,\r\n endDate,\r\n additionalClassNames,\r\n showRTIndicator = true,\r\n eventsResize = true,\r\n eventPromptTemplate,\r\n showEventPrompt = true,\r\n}: TimelineType) => {\r\n const [windowTime, setWindowTime] = useState([\r\n new Date(\r\n startDate.getFullYear(),\r\n startDate.getMonth(),\r\n startDate.getDate(),\r\n startDate.getHours(),\r\n 0,\r\n 0\r\n ).getTime() / 1000,\r\n new Date(\r\n endDate.getFullYear(),\r\n endDate.getMonth(),\r\n endDate.getDate(),\r\n endDate.getHours(),\r\n 0,\r\n 0\r\n ).getTime() / 1000,\r\n ]);\r\n\r\n // cellWidth is in px\r\n const [cellWidth, setCellWidth] = useState(0);\r\n\r\n const [internalEvents, setInternalEvents] = useState<EventType[]>([]);\r\n\r\n const contentRef = useRef<HTMLDivElement | null>(null);\r\n\r\n const mainRef = useRef<HTMLDivElement | null>(null);\r\n\r\n const bodyRef = useRef<HTMLDivElement | null>(null);\r\n\r\n // tick is represent how many seconds is a one pixel\r\n const [tick, setTick] = useState<number | null>(null);\r\n\r\n const [scrollWidth, setScrollWidth] = useState(0);\r\n\r\n const [rowsHeight, setRowsHeight] = useState<Record<\r\n string,\r\n RowsHeightType\r\n > | null>(null);\r\n\r\n const [allRowsHeight, setAllRowsHeight] = useState<number>(0);\r\n\r\n const eventPromptRef = useRef<EventPromptActionsType | null>(null);\r\n\r\n useEffect(() => {\r\n if (contentRef.current) {\r\n const windowDuration = windowTime[1] - windowTime[0];\r\n const numberOfHourBlocks = windowDuration / 3600;\r\n setTick(\r\n windowDuration / contentRef.current.getBoundingClientRect().width\r\n );\r\n setCellWidth(\r\n contentRef.current.getBoundingClientRect().width / numberOfHourBlocks\r\n );\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (bodyRef.current) {\r\n setScrollWidth(\r\n bodyRef.current.getBoundingClientRect().width -\r\n bodyRef.current.scrollWidth\r\n );\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n setInternalEvents(events.sort(sortEvents));\r\n }, [events]);\r\n\r\n const [dragStarted, setDragStarted] = useState<boolean>(false);\r\n\r\n useEffect(() => {\r\n let tempRowsHeight: Record<string, RowsHeightType> | null = null;\r\n rows.forEach((row) => {\r\n if (tempRowsHeight === null) {\r\n tempRowsHeight = { [row.id]: { minHeight: 40 } };\r\n } else {\r\n tempRowsHeight[row.id] = { minHeight: 40 };\r\n }\r\n });\r\n setRowsHeight(tempRowsHeight);\r\n }, [rows]);\r\n\r\n useResizeObserver({ contentRef, setCellWidth, setTick, windowTime });\r\n\r\n const eventPrompt = useMemo(\r\n () => (\r\n <EventPrompt\r\n ref={eventPromptRef}\r\n template={eventPromptTemplate}\r\n ></EventPrompt>\r\n ),\r\n [eventPromptTemplate]\r\n );\r\n\r\n return (\r\n <div className=\"main-wrapper\" ref={mainRef}>\r\n {showRTIndicator && (\r\n <RTIndicator tick={tick} windowTime={windowTime}></RTIndicator>\r\n )}\r\n <TimeBar\r\n windowTime={windowTime}\r\n tick={tick}\r\n contentWidth={\r\n contentRef.current\r\n ? contentRef.current.getBoundingClientRect().width\r\n : null\r\n }\r\n scrollWidth={scrollWidth}\r\n />\r\n\r\n <div className=\"body-wrapper\" ref={bodyRef}>\r\n <RowsHeightContext.Provider\r\n value={{ rowsHeight, setRowsHeight, allRowsHeight, setAllRowsHeight }}\r\n >\r\n <RowsHeader\r\n rows={rows}\r\n className={additionalClassNames?.rowsHeader}\r\n />\r\n <DragStartedContext.Provider value={{ dragStarted, setDragStarted }}>\r\n <ExternalPropertiesContext.Provider\r\n value={{ onDrop, onResize, eventsResize, eventPromptRef }}\r\n >\r\n <Content\r\n events={internalEvents}\r\n staticEvents={staticEvents}\r\n rows={rows}\r\n setEvents={setInternalEvents}\r\n tick={tick}\r\n windowTime={windowTime}\r\n cellWidth={cellWidth}\r\n setWindowTime={setWindowTime}\r\n ref={contentRef}\r\n setCellWidth={setCellWidth}\r\n contentWidth={\r\n contentRef.current\r\n ? contentRef.current.getBoundingClientRect().width\r\n : null\r\n }\r\n bodyRef={bodyRef}\r\n lineClassName={additionalClassNames?.gridLine}\r\n />\r\n {showEventPrompt && eventPrompt}\r\n </ExternalPropertiesContext.Provider>\r\n </DragStartedContext.Provider>\r\n </RowsHeightContext.Provider>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useRef } from \"react\";\r\nimport useGenerateBlocks from \"../hooks/use-generate-blocks\";\r\nimport useGetBlockProperties from \"../hooks/use-get-block-properties\";\r\nimport { PartialRecord, ModifableElements } from \"../types\";\r\n\r\nconst TimeBar = ({\r\n windowTime,\r\n tick,\r\n contentWidth,\r\n scrollWidth,\r\n additionalClassNames,\r\n}: {\r\n windowTime: number[];\r\n tick: number | null;\r\n contentWidth: number | null;\r\n scrollWidth: number;\r\n additionalClassNames?: PartialRecord<keyof ModifableElements, string>;\r\n}) => {\r\n const timeContentRef = useRef<HTMLDivElement | null>(null);\r\n\r\n const { blockWidth } = useGetBlockProperties({\r\n windowTime,\r\n contentWidth,\r\n });\r\n\r\n const { dayBlocks, hourBlocks } = useGenerateBlocks({\r\n windowTime,\r\n tick,\r\n contentWidth,\r\n blockWidth,\r\n });\r\n\r\n const timeBarClassNames = additionalClassNames?.timeBar\r\n ? \"time-bar \" + additionalClassNames.timeBar\r\n : \"time-bar\";\r\n\r\n const dayRowClassNames = additionalClassNames?.dayRow\r\n ? \"day-row \" + additionalClassNames.dayRow\r\n : \"day-row\";\r\n\r\n const hourRowClassNames = additionalClassNames?.hourRow\r\n ? \"hour-row \" + additionalClassNames.hourRow\r\n : \"hour-row\";\r\n return (\r\n <div className={timeBarClassNames}>\r\n <div className=\"empty-block\"></div>\r\n <div\r\n className=\"time-content\"\r\n ref={timeContentRef}\r\n style={{ minWidth: contentWidth ? contentWidth : 0 }}\r\n >\r\n <div\r\n className={dayRowClassNames}\r\n style={{\r\n gridTemplateColumns: `repeat(auto-fill, minmax(${blockWidth}px, 1fr))`,\r\n }}\r\n >\r\n {dayBlocks.map((block) => block)}\r\n </div>\r\n <div\r\n className={hourRowClassNames}\r\n style={{\r\n gridTemplateColumns: `repeat(auto-fill, minmax(${blockWidth}px, 1fr))`,\r\n }}\r\n >\r\n {hourBlocks.map((block) => block)}\r\n </div>\r\n </div>\r\n {scrollWidth ? (\r\n <div\r\n style={{\r\n width: scrollWidth,\r\n height: \"100%\",\r\n boxSizing: \"border-box\",\r\n borderLeft: \"1px solid yellow\",\r\n }}\r\n ></div>\r\n ) : null}\r\n </div>\r\n );\r\n};\r\n\r\nexport default TimeBar;\r\n","import React from \"react\";\r\nimport { useMemo } from \"react\";\r\nimport getMonthName from \"../helpers/get-month-name\";\r\nimport getWeekDayName from \"../helpers/get-week-day-name\";\r\n\r\nconst useGenerateBlocks = ({\r\n windowTime,\r\n tick,\r\n contentWidth,\r\n blockWidth,\r\n}: {\r\n windowTime: number[];\r\n tick: number | null;\r\n contentWidth: number | null;\r\n blockWidth: number;\r\n}) => {\r\n const { dayBlocks, hourBlocks } = useMemo(() => {\r\n let timePoint = windowTime[0];\r\n const dayBlocks: JSX.Element[] = [];\r\n const hourBlocks: JSX.Element[] = [];\r\n if (tick === null || contentWidth === null) {\r\n return { dayBlocks: [], hourBlocks: [] };\r\n }\r\n\r\n let widthLeft = contentWidth;\r\n\r\n let prevNumBlocks = 1;\r\n\r\n while (1) {\r\n let datePoint = new Date(timePoint * 1000);\r\n const endDatePoint = new Date(\r\n datePoint.getFullYear(),\r\n datePoint.getMonth(),\r\n datePoint.getDate(),\r\n 23,\r\n 59,\r\n 59\r\n );\r\n const dateDuration = endDatePoint.getTime() - datePoint.getTime();\r\n const dateWidth = dateDuration / 1000 / tick;\r\n\r\n widthLeft -= dateWidth;\r\n\r\n if (Math.round(widthLeft) < 0) {\r\n const numBlocks = Math.round((dateWidth + widthLeft) / blockWidth);\r\n\r\n for (let i = 0; i < numBlocks; i++) {\r\n hourBlocks.push(\r\n <div\r\n className=\"hour-block\"\r\n key={`${datePoint.getDate()}_hour_${i}`}\r\n >\r\n {i < 10 ? `0${i}:00` : `${i}:00`}\r\n </div>\r\n );\r\n }\r\n\r\n dayBlocks.push(\r\n <div\r\n className=\"day-block\"\r\n key={`${datePoint.getDate()} ${datePoint.getMonth()}`}\r\n style={{\r\n gridColumn: `${prevNumBlocks} / ${prevNumBlocks + numBlocks}`,\r\n // width: dateWidth + widthLeft,\r\n // minWidth: dateWidth + widthLeft,\r\n }}\r\n >\r\n {getWeekDayName(datePoint.getDay())} {datePoint.getDate()}{\" \"}\r\n {getMonthName(datePoint.getMonth())}\r\n </div>\r\n );\r\n prevNumBlocks += numBlocks;\r\n break;\r\n }\r\n\r\n const numBlocks = Math.round(dateWidth / blockWidth);\r\n\r\n for (let i = 24 - numBlocks; i < 24; i++) {\r\n hourBlocks.push(\r\n <div className=\"hour-block\" key={`${datePoint.getDate()}_hour_${i}`}>\r\n {i < 10 ? `0${i}:00` : `${i}:00`}\r\n </div>\r\n );\r\n }\r\n\r\n dayBlocks.push(\r\n <div\r\n className=\"day-block\"\r\n key={`${datePoint.getDate()} ${datePoint.getMonth()}`}\r\n style={{\r\n gridColumn: `${prevNumBlocks} / ${prevNumBlocks + numBlocks}`,\r\n // width: dateWidth,\r\n // minWidth: dateWidth,\r\n }}\r\n >\r\n {getWeekDayName(datePoint.getDay())} {datePoint.getDate()}{\" \"}\r\n {getMonthName(datePoint.getMonth())}\r\n </div>\r\n );\r\n prevNumBlocks += numBlocks;\r\n if (Math.round(widthLeft) === 0) {\r\n break;\r\n }\r\n timePoint = (endDatePoint.getTime() + 1000) / 1000;\r\n }\r\n\r\n return { dayBlocks, hourBlocks };\r\n }, [tick, windowTime, contentWidth]);\r\n return { dayBlocks, hourBlocks };\r\n};\r\n\r\nexport default useGenerateBlocks;\r\n","const getMonthName = (monthIndex: number) => {\r\n let monthName: string | null = null;\r\n switch (monthIndex) {\r\n case 0:\r\n monthName = \"Jan\";\r\n break;\r\n case 1:\r\n monthName = \"Feb\";\r\n break;\r\n case 2:\r\n monthName = \"Mar\";\r\n break;\r\n case 3:\r\n monthName = \"Apr\";\r\n break;\r\n case 4:\r\n monthName = \"May\";\r\n break;\r\n case 5:\r\n monthName = \"Jun\";\r\n break;\r\n case 6:\r\n monthName = \"Jul\";\r\n break;\r\n case 7:\r\n monthName = \"Aug\";\r\n break;\r\n case 8:\r\n monthName = \"Sep\";\r\n break;\r\n case 9:\r\n monthName = \"Oct\";\r\n break;\r\n case 10:\r\n monthName = \"Nov\";\r\n break;\r\n case 11:\r\n monthName = \"Dec\";\r\n break;\r\n default:\r\n monthName = \"Jan\";\r\n }\r\n\r\n return monthName;\r\n};\r\n\r\nexport default getMonthName;\r\n","const getWeekDayName = (dayIndex: number) => {\r\n let dayName: string | null = null;\r\n switch (dayIndex) {\r\n case 0:\r\n dayName = \"Mon\";\r\n break;\r\n case 1:\r\n dayName = \"Tue\";\r\n break;\r\n case 2:\r\n dayName = \"Wed\";\r\n break;\r\n case 3:\r\n dayName = \"Thu\";\r\n break;\r\n case 4:\r\n dayName = \"Fri\";\r\n break;\r\n case 5:\r\n dayName = \"Sat\";\r\n break;\r\n case 6:\r\n dayName = \"Sun\";\r\n break;\r\n default:\r\n dayName = \"Mon\";\r\n }\r\n\r\n return dayName;\r\n};\r\n\r\nexport default getWeekDayName;\r\n","import { useMemo } from \"react\";\r\n\r\nconst useGetBlockProperties = ({\r\n windowTime,\r\n contentWidth,\r\n}: {\r\n windowTime: number[];\r\n contentWidth: number | null;\r\n}) => {\r\n const numberOfHourBlocks = useMemo(\r\n () => (windowTime[1] - windowTime[0]) / 3600,\r\n [windowTime]\r\n );\r\n\r\n const blockWidth = contentWidth ? contentWidth / numberOfHourBlocks : 0;\r\n\r\n return { numberOfHourBlocks, blockWidth };\r\n};\r\n\r\nexport default useGetBlockProperties;\r\n","import React from \"react\";\r\nimport RowHeader from \"./row-header\";\r\nimport { RowType } from \"../types\";\r\n\r\nconst RowsHeader = ({\r\n rows,\r\n className,\r\n}: {\r\n rows: RowType[];\r\n className?: string;\r\n}) => {\r\n const classNames = className\r\n ? \"rows-header-wrapper \" + className\r\n : \"rows-header-wrapper\";\r\n return (\r\n <div className={classNames}>\r\n {rows.map((row) => (\r\n <RowHeader\r\n key={`row_header_${row.id}`}\r\n id={row.id}\r\n name={row.name}\r\n ></RowHeader>\r\n ))}\r\n </div>\r\n );\r\n};\r\nexport default RowsHeader;\r\n","import React, { useContext } from \"react\";\r\nimport \"./style.css\";\r\nimport { RowsHeightContext } from \"../contexts/row-height-context\";\r\n\r\nconst RowHeader = ({ name, id }: { name: string; id: string }) => {\r\n const rowsHeightContext = useContext(RowsHeightContext);\r\n\r\n const minHeight =\r\n rowsHeightContext &&\r\n rowsHeightContext.rowsHeight &&\r\n rowsHeightContext.rowsHeight[id]\r\n ? rowsHeightContext.rowsHeight[id].minHeight\r\n : 40;\r\n\r\n return (\r\n <div className=\"row-header\" style={{ minHeight: minHeight }}>\r\n {name}\r\n </div>\r\n );\r\n};\r\n\r\nexport default RowHeader;\r\n","import { createContext } from \"react\";\r\nimport { RowsHeightType } from \"../types\";\r\n\r\ntype RowsHeightContextType = {\r\n rowsHeight: Record<string, RowsHeightType> | null;\r\n setRowsHeight: React.Dispatch<\r\n React.SetStateAction<Record<string, RowsHeightType> | null>\r\n >;\r\n allRowsHeight: number;\r\n setAllRowsHeight: React.Dispatch<React.SetStateAction<number>>;\r\n};\r\n\r\nexport const RowsHeightContext = createContext<RowsHeightContextType | null>(\r\n null\r\n);\r\n","import React, {\r\n forwardRef,\r\n useCallback,\r\n useContext,\r\n useEffect,\r\n useRef,\r\n useState,\r\n} from \"react\";\r\nimport { EventType, RowType } from \"../types\";\r\nimport LinesCanvas from \"./lines-canvas\";\r\nimport useProduceContent from \"../hooks/use-produce-content\";\r\nimport useGetBlockProperties from \"../hooks/use-get-block-properties\";\r\nimport { RowsHeightContext } from \"../contexts/row-height-context\";\r\n\r\ntype ContentType = {\r\n rows: RowType[];\r\n events: EventType[];\r\n staticEvents?: EventType[];\r\n setEvents: React.Dispatch<React.SetStateAction<EventType[]>>;\r\n tick: number | null;\r\n windowTime: number[];\r\n cellWidth: number;\r\n setWindowTime: React.Dispatch<React.SetStateAction<number[]>>;\r\n contentWidth: number | null;\r\n setCellWidth: React.Dispatch<React.SetStateAction<number>>;\r\n bodyRef: React.MutableRefObject<HTMLDivElement | null>;\r\n lineClassName?: string;\r\n};\r\n\r\nconst Content = forwardRef<HTMLDivElement, ContentType>(\r\n (\r\n {\r\n rows,\r\n events,\r\n staticEvents,\r\n setEvents,\r\n tick,\r\n windowTime,\r\n cellWidth,\r\n setWindowTime,\r\n contentWidth,\r\n setCellWidth,\r\n bodyRef,\r\n lineClassName,\r\n },\r\n ref\r\n ) => {\r\n const [mouseDown, setMouseDown] = useState(false);\r\n const startMovePosition = useRef<number | null>(null);\r\n\r\n const [changeGrid, setChangeGrid] = useState(false);\r\n\r\n const { blockWidth } = useGetBlockProperties({ windowTime, contentWidth });\r\n\r\n const rowsHeightContext = useContext(RowsHeightContext);\r\n\r\n const handleOnMouseMove = useCallback(\r\n (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\r\n event.preventDefault();\r\n if (!mouseDown) {\r\n return;\r\n }\r\n const element = event.target as HTMLElement;\r\n const { left } = element.getBoundingClientRect();\r\n const movePosition = event.clientX - left;\r\n\r\n const moveTimestamp = tick ? Math.floor(tick * blockWidth) : 0;\r\n\r\n if (\r\n startMovePosition.current &&\r\n startMovePosition.current - movePosition >= blockWidth\r\n ) {\r\n startMovePosition.current = movePosition;\r\n setWindowTime((prev) => [\r\n prev[0] + moveTimestamp,\r\n prev[1] + moveTimestamp,\r\n ]);\r\n } else if (\r\n startMovePosition.current &&\r\n movePosition - startMovePosition.current >= blockWidth\r\n ) {\r\n startMovePosition.current = movePosition;\r\n setWindowTime((prev) => [\r\n prev[0] - moveTimestamp,\r\n prev[1] - moveTimestamp,\r\n ]);\r\n }\r\n },\r\n [blockWidth, setWindowTime, mouseDown]\r\n );\r\n\r\n const handleOnMouseDown = useCallback(\r\n (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\r\n setMouseDown(true);\r\n // disable auto-scroll when adjusting the grid granulation by wheeling\r\n if (event.button === 1) {\r\n event.preventDefault();\r\n }\r\n const element = event.target as HTMLElement;\r\n const { left } = element.getBoundingClientRect();\r\n startMovePosition.current = event.clientX - left;\r\n },\r\n [setMouseDown]\r\n );\r\n\r\n const handleOnMouseUp = useCallback(() => {\r\n setMouseDown(false);\r\n }, [setMouseDown]);\r\n\r\n const handleOnMouseLeave = useCallback(\r\n () => setMouseDown(false),\r\n [setMouseDown]\r\n );\r\n\r\n const content = useProduceContent({\r\n rows,\r\n windowTime,\r\n tick,\r\n events,\r\n staticEvents,\r\n cellWidth,\r\n setEvents,\r\n bodyRef,\r\n });\r\n\r\n const handleAuxClick = useCallback(\r\n (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\r\n event.preventDefault();\r\n if (event.button === 1) {\r\n setChangeGrid((prev) => !prev);\r\n }\r\n },\r\n []\r\n );\r\n\r\n const handleOnWheel = useCallback(\r\n (event: React.WheelEvent<HTMLDivElement>) => {\r\n const pixelsToCalculate = tick ? 900 / tick : 0;\r\n if (changeGrid) {\r\n setCellWidth((cellWidth) => {\r\n const newCellWidth =\r\n event.deltaY > 0\r\n ? cellWidth + pixelsToCalculate\r\n : cellWidth - pixelsToCalculate;\r\n\r\n if (\r\n newCellWidth < pixelsToCalculate ||\r\n newCellWidth > pixelsToCalculate * 12\r\n ) {\r\n return cellWidth;\r\n }\r\n\r\n return newCellWidth;\r\n });\r\n }\r\n },\r\n [changeGrid, cellWidth, tick]\r\n );\r\n\r\n useEffect(() => {\r\n if (bodyRef.current) {\r\n bodyRef.current.style.overflow = changeGrid ? \"hidden\" : \"auto\";\r\n }\r\n }, [changeGrid]);\r\n\r\n return (\r\n <div\r\n key=\"content\"\r\n ref={ref}\r\n className=\"content-wrapper\"\r\n onMouseDown={handleOnMouseDown}\r\n onMouseUp={handleOnMouseUp}\r\n onMouseMove={handleOnMouseMove}\r\n onMouseLeave={handleOnMouseLeave}\r\n onAuxClick={handleAuxClick}\r\n onWheel={handleOnWheel}\r\n style={{\r\n cursor: mouseDown ? \"grabbing\" : \"grab\",\r\n height: rowsHeightContext?.allRowsHeight,\r\n }}\r\n >\r\n <LinesCanvas\r\n contentWidth={contentWidth}\r\n cellWidth={cellWidth}\r\n lineClassName={lineClassName}\r\n ></LinesCanvas>\r\n {content}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nexport default Content;\r\n","import React from \"react\";\r\nimport { useMemo } from \"react\";\r\n\r\nconst LinesCanvas = ({\r\n contentWidth,\r\n cellWidth,\r\n lineClassName,\r\n}: {\r\n contentWidth: number | null;\r\n cellWidth: number;\r\n lineClassName?: string;\r\n}) => {\r\n const lines = useMemo(() => {\r\n const lines: JSX.Element[] = [];\r\n const classNames = lineClassName ? \"line \" + lineClassName : \"line\";\r\n if (contentWidth) {\r\n for (let i = cellWidth; i < contentWidth; i = i + cellWidth) {\r\n lines.push(<div key={`line_${i}`} className={classNames}></div>);\r\n }\r\n }\r\n return lines;\r\n }, [cellWidth, contentWidth]);\r\n\r\n const minWidth = useMemo(() => {\r\n return contentWidth ? contentWidth - lines.length * cellWidth : 0;\r\n }, [contentWidth, cellWidth, lines]);\r\n\r\n return (\r\n <div\r\n className={minWidth < 1 ? \"lines-canvas hide-last-line\" : \"lines-canvas\"}\r\n style={\r\n minWidth < 1\r\n ? {\r\n gridTemplateColumns: `repeat(auto-fill, minmax(${cellWidth}px, 1fr))`,\r\n }\r\n : {\r\n gridTemplateColumns: `repeat(auto-fill, minmax(${minWidth}px, ${cellWidth}px))`,\r\n }\r\n }\r\n >\r\n {lines}\r\n </div>\r\n );\r\n};\r\n\r\nexport default LinesCanvas;\r\n","import { useContext, useEffect, useMemo, useRef } from \"react\";\r\nimport { EventType, RowsHeightType, RowType } from \"../types\";\r\nimport React from \"react\";\r\nimport StaticEvent from \"../components/static-event\";\r\nimport RowContent from \"../components/row-content\";\r\nimport Event from \"../components/event\";\r\nimport { RowsHeightContext } from \"../contexts/row-height-context\";\r\nimport useIntersectionObserver from \"./use-intersection-observer\";\r\n\r\ntype ProduceContentType = {\r\n rows: RowType[];\r\n events: EventType[];\r\n staticEvents?: EventType[];\r\n setEvents: React.Dispatch<React.SetStateAction<EventType[]>>;\r\n tick: number | null;\r\n windowTime: number[];\r\n cellWidth: number;\r\n bodyRef: React.MutableRefObject<HTMLDivElement | null>;\r\n};\r\n\r\nconst useProduceContent = ({\r\n rows,\r\n windowTime,\r\n tick,\r\n events,\r\n staticEvents,\r\n cellWidth,\r\n setEvents,\r\n bodyRef,\r\n}: ProduceContentType) => {\r\n const rowsHeightContext = useContext(RowsHeightContext);\r\n\r\n const tempRowsHeightRef = useRef<Record<string, RowsHeightType> | null>(null);\r\n\r\n const rowsContentRef = useRef<HTMLDivElement[]>([]);\r\n\r\n const [content, internalAllRowsHeight] = useMemo(() => {\r\n let internalAllRowsHeight = 0;\r\n return [\r\n rows.map((row, i) => {\r\n let eventOrder = 0;\r\n let prevEvent: EventType[] = [];\r\n let highestEventOrder = 0;\r\n const rowEvents = tick\r\n ? events\r\n .filter((event) => event.rowId === row.id)\r\n .map((event) => {\r\n if (\r\n event.endTime >= windowTime[0] &&\r\n event.startTime <= windowTime[1]\r\n ) {\r\n let tempEventOrder = 0;\r\n let assignEventOrder = true;\r\n for (let i = 0; i <= eventOrder; i++) {\r\n if (\r\n prevEvent &&\r\n prevEvent[i] &&\r\n prevEvent[i].endTime > event.startTime\r\n ) {\r\n tempEventOrder += 1;\r\n } else {\r\n if (eventOrder > highestEventOrder) {\r\n highestEventOrder = eventOrder;\r\n }\r\n eventOrder = 0;\r\n assignEventOrder = false;\r\n break;\r\n }\r\n }\r\n\r\n if (assignEventOrder) {\r\n eventOrder = tempEventOrder;\r\n }\r\n\r\n prevEvent[tempEventOrder] = event;\r\n return (\r\n <Event\r\n key={`event_${event.id}`}\r\n eventData={event}\r\n startPosition={(event.startTime - windowTime[0]) / tick}\r\n width={(event.endTime - event.startTime) / tick}\r\n top={10 + 22 * tempEventOrder}\r\n setEvents={setEvents}\r\n tick={tick}\r\n ></Event>\r\n );\r\n }\r\n })\r\n : null;\r\n\r\n if (eventOrder > highestEventOrder) {\r\n highestEventOrder = eventOrder;\r\n }\r\n\r\n if (tempRowsHeightRef.current === null) {\r\n tempRowsHeightRef.current = {\r\n [row.id]: { minHeight: 40 + highestEventOrder * 22 },\r\n };\r\n } else {\r\n tempRowsHeightRef.current[row.id] = {\r\n minHeight: 40 + highestEventOrder * 22,\r\n };\r\n }\r\n internalAllRowsHeight += 40 + highestEventOrder * 22;\r\n\r\n const rowStaticEvents =\r\n tick && staticEvents\r\n ? staticEvents\r\n .filter((event) => event.rowId === row.id)\r\n .map((event) => {\r\n if (\r\n event.endTime >= windowTime[0] &&\r\n event.startTime <= windowTime[1]\r\n ) {\r\n return (\r\n <StaticEvent\r\n key={`static_event_${event.id}`}\r\n id={event.id}\r\n startPosition={(event.startTime - windowTime[0]) / tick}\r\n width={(event.endTime - event.startTime) / tick}\r\n top={10}\r\n height={20 + highestEventOrder * 22}\r\n ></StaticEvent>\r\n );\r\n }\r\n })\r\n : null;\r\n\r\n return (\r\n <React.Fragment key={`row_content_${row.id}`}>\r\n <RowContent\r\n id={row.id}\r\n ref={(el) => {\r\n if (rowsContentRef.current && rowsContentRef.current[i] && el) {\r\n rowsContentRef.current[i] = el;\r\n } else if (rowsContentRef.current && el) {\r\n rowsContentRef.current.push(el);\r\n }\r\n }}\r\n setEvents={setEvents}\r\n tick={tick}\r\n windowTime={windowTime}\r\n cellWidth={cellWidth}\r\n >\r\n {rowEvents}\r\n {rowStaticEvents}\r\n </RowContent>\r\n </React.Fragment>\r\n );\r\n }),\r\n internalAllRowsHeight,\r\n ];\r\n }, [rows, events, tick, windowTime, cellWidth]);\r\n\r\n useIntersectionObserver({\r\n rowsContentRef,\r\n bodyRef,\r\n });\r\n\r\n useEffect(() => {\r\n if (rowsHeightContext) {\r\n rowsHeightContext.setRowsHeight(tempRowsHeightRef.current);\r\n rowsHeightContext.setAllRowsHeight(internalAllRowsHeight);\r\n }\r\n }, [content, internalAllRowsHeight]);\r\n\r\n return content;\r\n};\r\n\r\nexport default useProduceContent;\r\n","import React, { CSSProperties, useCallback, useContext } from \"react\";\r\nimport { DragStartedContext } from \"../contexts/drag-started-context\";\r\n\r\nconst StaticEvent = ({\r\n id,\r\n startPosition,\r\n width,\r\n top,\r\n height,\r\n}: {\r\n id: string;\r\n startPosition: CSSProperties[\"left\"];\r\n width: CSSProperties[\"width\"];\r\n top: CSSProperties[\"top\"];\r\n height: CSSProperties[\"height\"];\r\n}) => {\r\n return (\r\n <div\r\n id={`static_event_${id}`}\r\n key={`static_event_${id}`}\r\n className=\"static-event\"\r\n onDrop={(event) => event.stopPropagation()}\r\n style={{\r\n left: startPosition,\r\n width: width,\r\n top: top,\r\n minHeight: height,\r\n }}\r\n ></div>\r\n );\r\n};\r\nexport default StaticEvent;\r\n","import React, {\r\n forwardRef,\r\n PropsWithChildren,\r\n useCallback,\r\n useContext,\r\n} from \"react\";\r\nimport { EventType } from \"../types\";\r\nimport { produce } from \"immer\";\r\nimport { RowsHeightContext } from \"../contexts/row-height-context\";\r\nimport { DragStartedContext } from \"../contexts/drag-started-context\";\r\nimport { ExternalPropertiesContext } from \"../contexts/external-properties-context\";\r\nimport sortEvents from \"../helpers/sort-events\";\r\n\r\ntype RowContentProps = {\r\n id: string;\r\n setEvents: React.Dispatch<React.SetStateAction<EventType[]>>;\r\n tick: number | null;\r\n windowTime: number[];\r\n cellWidth: number;\r\n};\r\n\r\nconst RowContent = forwardRef<\r\n HTMLDivElement,\r\n PropsWithChildren<RowContentProps>\r\n>((props: PropsWithChildren<RowContentProps>, ref) => {\r\n const { setEvents, tick, id, windowTime, cellWidth, children } = props;\r\n\r\n const { dragStarted, setDragStarted } = useContext(DragStartedContext);\r\n\r\n const { onDrop } = useContext(ExternalPropertiesContext);\r\n\r\n const handleOnDrop = useCallback(\r\n (event: React.DragEvent<HTMLDivElement>) => {\r\n event.preventDefault();\r\n const element = event.target as HTMLElement;\r\n const { left } = element.getBoundingClientRect();\r\n const draggedEventId = event.dataTransfer.getData(\"eventId\");\r\n //new position in px within container\r\n const closestCell = Math.round((event.clientX - left) / cellWidth);\r\n const newPosition = cellWidth * closestCell;\r\n setEvents(\r\n produce((draft) => {\r\n const event = draft.find((event) => event.id === draggedEventId);\r\n\r\n if (event && tick) {\r\n const newStartTime = windowTime[0] + newPosition * tick;\r\n const eventDuration = event.endTime - event.startTime;\r\n const newEndTime =\r\n windowTime[0] + eventDuration + newPosition * tick;\r\n\r\n if (onDrop) {\r\n onDrop({\r\n eventId: event.id,\r\n oldRowId: event.rowId,\r\n newRowId: props.id,\r\n startTime: newStartTime,\r\n endTime: newEndTime,\r\n });\r\n }\r\n\r\n event.startTime = newStartTime;\r\n event.endTime = newEndTime;\r\n event.rowId = props.id;\r\n }\r\n draft.sort(sortEvents);\r\n })\r\n );\r\n setDragStarted(false);\r\n },\r\n [setEvents, tick, windowTime, cellWidth]\r\n );\r\n\r\n const rowsHeightContext = useContext(RowsHeightContext);\r\n\r\n const minHeight =\r\n rowsHeightContext &&\r\n rowsHeightContext.rowsHeight &&\r\n rowsHeightContext.rowsHeight[id]\r\n ? rowsHeightContext.rowsHeight[id].minHeight\r\n : 40;\r\n\r\n return (\r\n <div\r\n id={`row_${id}`}\r\n ref={ref}\r\n onDragOver={(event) => event.preventDefault()}\r\n onDrop={handleOnDrop}\r\n className={dragStarted ? \"row-content not-clickable\" : \"row-content\"}\r\n data-index={id}\r\n style={{\r\n minHeight: minHeight,\r\n }}\r\n >\r\n {children}\r\n </div>\r\n );\r\n});\r\n\r\nexport default RowContent;\r\n","// Should be no imports here!\n\n/**\n * The sentinel value returned by producers to replace the draft with undefined.\n */\nexport const NOTHING: unique symbol = Symbol.for(\"immer-nothing\")\n\n/**\n * To let Immer treat your class instances as plain immutable objects\n * (albeit with a custom prototype), you must define either an instance property\n * or a static property on each of your custom classes.\n *\n * Otherwise, your class instance will never be drafted, which means it won't be\n * safe to mutate in a produce callback.\n */\nexport const DRAFTABLE: unique symbol = Symbol.for(\"immer-draftable\")\n\nexport const DRAFT_STATE: unique symbol = Symbol.for(\"immer-state\")\n","export const errors =\n\tprocess.env.NODE_ENV !== \"production\"\n\t\t? [\n\t\t\t\t// All error codes, starting by 0:\n\t\t\t\tfunction(plugin: string) {\n\t\t\t\t\treturn `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \\`enable${plugin}()\\` when initializing your application.`\n\t\t\t\t},\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`\n\t\t\t\t},\n\t\t\t\t\"This object has been frozen and should not be mutated\",\n\t\t\t\tfunction(data: any) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t\"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? \" +\n\t\t\t\t\t\tdata\n\t\t\t\t\t)\n\t\t\t\t},\n\t\t\t\t\"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.\",\n\t\t\t\t\"Immer forbids circular references\",\n\t\t\t\t\"The first or second argument to `produce` must be a function\",\n\t\t\t\t\"The third argument to `produce` must be a function or undefined\",\n\t\t\t\t\"First argument to `createDraft` must be a plain object, an array, or an immerable object\",\n\t\t\t\t\"First argument to `finishDraft` must be a draft returned by `createDraft`\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'current' expects a draft, got: ${thing}`\n\t\t\t\t},\n\t\t\t\t\"Object.defineProperty() cannot be used on an Immer draft\",\n\t\t\t\t\"Object.setPrototypeOf() cannot be used on an Immer draft\",\n\t\t\t\t\"Immer only supports deleting array indices\",\n\t\t\t\t\"Immer only supports setting array indices and the 'length' property\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'original' expects a draft, got: ${thing}`\n\t\t\t\t}\n\t\t\t\t// Note: if more errors are added, the errorOffset in Patches.ts should be increased\n\t\t\t\t// See Patches.ts for additional errors\n\t\t ]\n\t\t: []\n\nexport function die(error: number, ...args: any[]): never {\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\tconst e = errors[error]\n\t\tconst msg = typeof e === \"function\" ? e.apply(null, args as any) : e\n\t\tthrow new Error(`[Immer] ${msg}`)\n\t}\n\tthrow new Error(\n\t\t`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`\n\t)\n}\n","import {\n\tDRAFT_STATE,\n\tDRAFTABLE,\n\tObjectish,\n\tDrafted,\n\tAnyObject,\n\tAnyMap,\n\tAnySet,\n\tImmerState,\n\tArchType,\n\tdie,\n\tStrictMode\n} from \"../internal\"\n\nexport const getPrototypeOf = Object.getPrototypeOf\n\n/** Returns true if the given value is an Immer draft */\n/*#__PURE__*/\nexport function isDraft(value: any): boolean {\n\treturn !!value && !!value[DRAFT_STATE]\n}\n\n/** Returns true if the given value can be drafted by Immer */\n/*#__PURE__*/\nexport function isDraftable(value: any): boolean {\n\tif (!value) return false\n\treturn (\n\t\tisPlainObject(value) ||\n\t\tArray.isArray(value) ||\n\t\t!!value[DRAFTABLE] ||\n\t\t!!value.constructor?.[DRAFTABLE] ||\n\t\tisMap(value) ||\n\t\tisSet(value)\n\t)\n}\n\nconst objectCtorString = Object.prototype.constructor.toString()\n/*#__PURE__*/\nexport function isPlainObject(value: any): boolean {\n\tif (!value || typeof value !== \"object\") return false\n\tconst proto = getPrototypeOf(value)\n\tif (proto === null) {\n\t\treturn true\n\t}\n\tconst Ctor =\n\t\tObject.hasOwnProperty.call(proto, \"constructor\") && proto.constructor\n\n\tif (Ctor === Object) return true\n\n\treturn (\n\t\ttypeof Ctor == \"function\" &&\n\t\tFunction.toString.call(Ctor) === objectCtorString\n\t)\n}\n\n/** Get the underlying object that is represented by the given draft */\n/*#__PURE__*/\nexport function original<T>(value: T): T | undefined\nexport function original(value: Drafted<any>): any {\n\tif (!isDraft(value)) die(15, value)\n\treturn value[DRAFT_STATE].base_\n}\n\n/**\n * Each iterates a map, set or array.\n * Or, if any other kind of object, all of its own properties.\n * Regardless whether they are enumerable or symbols\n */\nexport function each<T extends Objectish>(\n\tobj: T,\n\titer: (key: string | number, value: any, source: T) => void\n): void\nexport function each(obj: any, iter: any) {\n\tif (getArchtype(obj) === ArchType.Object) {\n\t\tReflect.ownKeys(obj).forEach(key => {\n\t\t\titer(key, obj[key], obj)\n\t\t})\n\t} else {\n\t\tobj.forEach((entry: any, index: any) => iter(index, entry, obj))\n\t}\n}\n\n/*#__PURE__*/\nexport function getArchtype(thing: any): ArchType {\n\tconst state: undefined | ImmerState = thing[DRAFT_STATE]\n\treturn state\n\t\t? state.type_\n\t\t: Array.isArray(thing)\n\t\t? ArchType.Array\n\t\t: isMap(thing)\n\t\t? ArchType.Map\n\t\t: isSet(thing)\n\t\t? ArchType.Set\n\t\t: ArchType.Object\n}\n\n/*#__PURE__*/\nexport function has(thing: any, prop: PropertyKey): boolean {\n\treturn getArchtype(thing) === ArchType.Map\n\t\t? thing.has(prop)\n\t\t: Object.prototype.hasOwnProperty.call(thing, prop)\n}\n\n/*#__PURE__*/\nexport function get(thing: AnyMap | AnyObject, prop: PropertyKey): any {\n\t// @ts-ignore\n\treturn getArchtype(thing) === ArchType.Map ? thing.get(prop) : thing[prop]\n}\n\n/*#__PURE__*/\nexport function set(thing: any, propOrOldValue: PropertyKey, value: any) {\n\tconst t = getArchtype(thing)\n\tif (t === ArchType.Map) thing.set(propOrOldValue, value)\n\telse if (t === ArchType.Set) {\n\t\tthing.add(value)\n\t} else thing[propOrOldValue] = value\n}\n\n/*#__PURE__*/\nexport function is(x: any, y: any): boolean {\n\t// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js\n\tif (x === y) {\n\t\treturn x !== 0 || 1 / x === 1 / y\n\t} else {\n\t\treturn x !== x && y !== y\n\t}\n}\n\n/*#__PURE__*/\nexport function isMap(target: any): target is AnyMap {\n\treturn target instanceof Map\n}\n\n/*#__PURE__*/\nexport function isSet(target: any): target is AnySet {\n\treturn target instanceof Set\n}\n/*#__PURE__*/\nexport function latest(state: ImmerState): any {\n\treturn state.copy_ || state.base_\n}\n\n/*#__PURE__*/\nexport function shallowCopy(base: any, strict: StrictMode) {\n\tif (isMap(base)) {\n\t\treturn new Map(base)\n\t}\n\tif (isSet(base)) {\n\t\treturn new Set(base)\n\t}\n\tif (Array.isArray(base)) return Array.prototype.slice.call(base)\n\n\tconst isPlain = isPlainObject(base)\n\n\tif (strict === true || (strict === \"class_only\" && !isPlain)) {\n\t\t// Perform a strict copy\n\t\tconst descriptors = Object.getOwnPropertyDescriptors(base)\n\t\tdelete descriptors[DRAFT_STATE as any]\n\t\tlet keys = Reflect.ownKeys(descriptors)\n\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\tconst key: any = keys[i]\n\t\t\tconst desc = descriptors[key]\n\t\t\tif (desc.writable === false) {\n\t\t\t\tdesc.writable = true\n\t\t\t\tdesc.configurable = true\n\t\t\t}\n\t\t\t// like object.assign, we will read any _own_, get/set accessors. This helps in dealing\n\t\t\t// with libraries that trap values, like mobx or vue\n\t\t\t// unlike object.assign, non-enumerables will be copied as well\n\t\t\tif (desc.get || desc.set)\n\t\t\t\tdescriptors[key] = {\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true, // could live with !!desc.set as well here...\n\t\t\t\t\tenumerable: desc.enumerable,\n\t\t\t\t\tvalue: base[key]\n\t\t\t\t}\n\t\t}\n\t\treturn Object.create(getPrototypeOf(base), descriptors)\n\t} else {\n\t\t// perform a sloppy copy\n\t\tconst proto = getPrototypeOf(base)\n\t\tif (proto !== null && isPlain) {\n\t\t\treturn {...base} // assumption: better inner class optimization than the assign below\n\t\t}\n\t\tconst obj = Object.create(proto)\n\t\treturn Object.assign(obj, base)\n\t}\n}\n\n/**\n * Freezes draftable objects. Returns the original object.\n * By default freezes shallowly, but if the second argument is `true` it will freeze recursively.\n *\n * @param obj\n * @param deep\n */\nexport function freeze<T>(obj: T, deep?: boolean): T\nexport function freeze<T>(obj: any, deep: boolean = false): T {\n\tif (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj\n\tif (getArchtype(obj) > 1 /* Map or Set */) {\n\t\tobj.set = obj.add = obj.clear = obj.delete = dontMutateFrozenCollections as any\n\t}\n\tObject.freeze(obj)\n\tif (deep)\n\t\t// See #590, don't recurse into non-enumerable / Symbol properties when freezing\n\t\t// So use Object.entries (only string-like, enumerables) instead of each()\n\t\tObject.entries(obj).forEach(([key, value]) => freeze(value, true))\n\treturn obj\n}\n\nfunction dontMutateFrozenCollections() {\n\tdie(2)\n}\n\nexport function isFrozen(obj: any): boolean {\n\treturn Object.isFrozen(obj)\n}\n","import {\n\tImmerState,\n\tPatch,\n\tDrafted,\n\tImmerBaseState,\n\tAnyMap,\n\tAnySet,\n\tArchType,\n\tdie\n} from \"../internal\"\n\n/** Plugin utilities */\nconst plugins: {\n\tPatches?: {\n\t\tgeneratePatches_(\n\t\t\tstate: ImmerState,\n\t\t\tbasePath: PatchPath,\n\t\t\tpatches: Patch[],\n\t\t\tinversePatches: Patch[]\n\t\t): void\n\t\tgenerateReplacementPatches_(\n\t\t\tbase: any,\n\t\t\treplacement: any,\n\t\t\tpatches: Patch[],\n\t\t\tinversePatches: Patch[]\n\t\t): void\n\t\tapplyPatches_<T>(draft: T, patches: readonly Patch[]): T\n\t}\n\tMapSet?: {\n\t\tproxyMap_<T extends AnyMap>(target: T, parent?: ImmerState): T\n\t\tproxySet_<T extends AnySet>(target: T, parent?: ImmerState): T\n\t}\n} = {}\n\ntype Plugins = typeof plugins\n\nexport function getPlugin<K extends keyof Plugins>(\n\tpluginKey: K\n): Exclude<Plugins[K], undefined> {\n\tconst plugin = plugins[pluginKey]\n\tif (!plugin) {\n\t\tdie(0, pluginKey)\n\t}\n\t// @ts-ignore\n\treturn plugin\n}\n\nexport function loadPlugin<K extends keyof Plugins>(\n\tpluginKey: K,\n\timplementation: Plugins[K]\n): void {\n\tif (!plugins[pluginKey]) plugins[pluginKey] = implementation\n}\n/** Map / Set plugin */\n\nexport interface MapState extends ImmerBaseState {\n\ttype_: ArchType.Map\n\tcopy_: AnyMap | undefined\n\tassigned_: Map<any, boolean> | undefined\n\tbase_: AnyMap\n\trevoked_: boolean\n\tdraft_: Drafted<AnyMap, MapState>\n}\n\nexport interface SetState extends ImmerBaseState {\n\ttype_: ArchType.Set\n\tcopy_: AnySet | undefined\n\tbase_: AnySet\n\tdrafts_: Map<any, Drafted> // maps the original value to the draft value in the new set\n\trevoked_: boolean\n\tdraft_: Drafted<AnySet, SetState>\n}\n\n/** Patches plugin */\n\nexport type PatchPath = (string | number)[]\n","import {\n\tPatch,\n\tPatchListener,\n\tDrafted,\n\tImmer,\n\tDRAFT_STATE,\n\tImmerState,\n\tArchType,\n\tgetPlugin\n} from \"../internal\"\n\n/** Each scope represents a `produce` call. */\n\nexport interface ImmerScope {\n\tpatches_?: Patch[]\n\tinversePatches_?: Patch[]\n\tcanAutoFreeze_: boolean\n\tdrafts_: any[]\n\tparent_?: ImmerScope\n\tpatchListener_?: PatchListener\n\timmer_: Immer\n\tunfinalizedDrafts_: number\n}\n\nlet currentScope: ImmerScope | undefined\n\nexport function getCurrentScope() {\n\treturn currentScope!\n}\n\nfunction createScope(\n\tparent_: ImmerScope | undefined,\n\timmer_: Immer\n): ImmerScope {\n\treturn {\n\t\tdrafts_: [],\n\t\tparent_,\n\t\timmer_,\n\t\t// Whenever the modified draft contains a draft from another scope, we\n\t\t// need to prevent auto-freezing so the unowned draft can be finalized.\n\t\tcanAutoFreeze_: true,\n\t\tunfinalizedDrafts_: 0\n\t}\n}\n\nexport function usePatchesInScope(\n\tscope: ImmerScope,\n\tpatchListener?: PatchListener\n) {\n\tif (patchListener) {\n\t\tgetPlugin(\"Patches\") // assert we have the plugin\n\t\tscope.patches_ = []\n\t\tscope.inversePatches_ = []\n\t\tscope.patchListener_ = patchListener\n\t}\n}\n\nexport function revokeScope(scope: ImmerScope) {\n\tleaveScope(scope)\n\tscope.drafts_.forEach(revokeDraft)\n\t// @ts-ignore\n\tscope.drafts_ = null\n}\n\nexport function leaveScope(scope: ImmerScope) {\n\tif (scope === currentScope) {\n\t\tcurrentScope = scope.parent_\n\t}\n}\n\nexport function enterScope(immer: Immer) {\n\treturn (currentScope = createScope(currentScope, immer))\n}\n\nfunction revokeDraft(draft: Drafted) {\n\tconst state: ImmerState = draft[DRAFT_STATE]\n\tif (state.type_ === ArchType.Object || state.type_ === ArchType.Array)\n\t\tstate.revoke_()\n\telse state.revoked_ = true\n}\n","import {\n\tImmerScope,\n\tDRAFT_STATE,\n\tisDraftable,\n\tNOTHING,\n\tPatchPath,\n\teach,\n\thas,\n\tfreeze,\n\tImmerState,\n\tisDraft,\n\tSetState,\n\tset,\n\tArchType,\n\tgetPlugin,\n\tdie,\n\trevokeScope,\n\tisFrozen\n} from \"../internal\"\n\nexport function processResult(result: any, scope: ImmerScope) {\n\tscope.unfinalizedDrafts_ = scope.drafts_.length\n\tconst baseDraft = scope.drafts_![0]\n\tconst isReplaced = result !== undefined && result !== baseDraft\n\tif (isReplaced) {\n\t\tif (baseDraft[DRAFT_STATE].modified_) {\n\t\t\trevokeScope(scope)\n\t\t\tdie(4)\n\t\t}\n\t\tif (isDraftable(result)) {\n\t\t\t// Finalize the result in case it contains (or is) a subset of the draft.\n\t\t\tresult = finalize(scope, result)\n\t\t\tif (!scope.parent_) maybeFreeze(scope, result)\n\t\t}\n\t\tif (scope.patches_) {\n\t\t\tgetPlugin(\"Patches\").generateReplacementPatches_(\n\t\t\t\tbaseDraft[DRAFT_STATE].base_,\n\t\t\t\tresult,\n\t\t\t\tscope.patches_,\n\t\t\t\tscope.inversePatches_!\n\t\t\t)\n\t\t}\n\t} else {\n\t\t// Finalize the base draft.\n\t\tresult = finalize(scope, baseDraft, [])\n\t}\n\trevokeScope(scope)\n\tif (scope.patches_) {\n\t\tscope.patchListener_!(scope.patches_, scope.inversePatches_!)\n\t}\n\treturn result !== NOTHING ? result : undefined\n}\n\nfunction finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {\n\t// Don't recurse in tho recursive data structures\n\tif (isFrozen(value)) return value\n\n\tconst state: ImmerState = value[DRAFT_STATE]\n\t// A plain object, might need freezing, might contain drafts\n\tif (!state) {\n\t\teach(value, (key, childValue) =>\n\t\t\tfinalizeProperty(rootScope, state, value, key, childValue, path)\n\t\t)\n\t\treturn value\n\t}\n\t// Never finalize drafts owned by another scope.\n\tif (state.scope_ !== rootScope) return value\n\t// Unmodified draft, return the (frozen) original\n\tif (!state.modified_) {\n\t\tmaybeFreeze(rootScope, state.base_, true)\n\t\treturn state.base_\n\t}\n\t// Not finalized yet, let's do that now\n\tif (!state.finalized_) {\n\t\tstate.finalized_ = true\n\t\tstate.scope_.unfinalizedDrafts_--\n\t\tconst result = state.copy_\n\t\t// Finalize all children of the copy\n\t\t// For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628\n\t\t// To preserve insertion order in all cases we then clear the set\n\t\t// And we let finalizeProperty know it needs to re-add non-draft childr