moved to create-react-library
This commit is contained in:
parent
d27d58d44c
commit
09520361c2
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
6
.eslintignore
Normal file
6
.eslintignore
Normal file
@ -0,0 +1,6 @@
|
||||
build/
|
||||
dist/
|
||||
node_modules/
|
||||
.snapshots/
|
||||
*.min.js
|
||||
*.css
|
||||
37
.eslintrc
Normal file
37
.eslintrc
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"standard",
|
||||
"standard-react",
|
||||
"plugin:prettier/recommended",
|
||||
"prettier/standard",
|
||||
"prettier/react",
|
||||
"plugin:@typescript-eslint/eslint-recommended"
|
||||
],
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"ecmaFeatures": {
|
||||
"legacyDecorators": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "16"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"space-before-function-paren": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/jsx-handler-names": 0,
|
||||
"react/jsx-fragments": 0,
|
||||
"react/no-unused-prop-types": 0,
|
||||
"import/export": 0,
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error"
|
||||
}
|
||||
}
|
||||
42
.github/workflows/main.yml
vendored
42
.github/workflows/main.yml
vendored
@ -1,42 +0,0 @@
|
||||
name: CI
|
||||
on: [push]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Begin CI...
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node 12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
|
||||
- name: Use cached node_modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: node_modules
|
||||
key: nodeModules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
nodeModules-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Test
|
||||
run: yarn test --ci --coverage --maxWorkers=2
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
env:
|
||||
CI: true
|
||||
27
.github/workflows/npm-publish.yml
vendored
27
.github/workflows/npm-publish.yml
vendored
@ -1,27 +0,0 @@
|
||||
name: publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published, edited]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Begin CI...
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node 12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: NPM Publish
|
||||
run: |
|
||||
npm ci
|
||||
npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@ -1,5 +1,22 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
.cache
|
||||
|
||||
# builds
|
||||
build
|
||||
dist
|
||||
.rpt2_cache
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
12
.prettierrc
Normal file
12
.prettierrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "avoid",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
4
.travis.yml
Normal file
4
.travis.yml
Normal file
@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 12
|
||||
- 10
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -1,5 +0,0 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"callout"
|
||||
]
|
||||
}
|
||||
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Maksym Vikarii https://github.com/MaTeMaTuK
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -13,6 +13,7 @@ npm install gantt-task-react
|
||||
## How to use it
|
||||
|
||||
```javascript
|
||||
import { Gantt, Task, EventOption, StylingOption, ViewMode, DisplayOption } from 'gantt-task-react';
|
||||
let tasks: Task[] = [
|
||||
{
|
||||
start: new Date(2020, 1, 1),
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
node_modules
|
||||
.cache
|
||||
dist
|
||||
5
example/README.md
Normal file
5
example/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
It is linked to the gantt-task-react package in the parent directory for development purposes.
|
||||
|
||||
You can run `npm install` and then `npm start` to test your package.
|
||||
@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>Playground</title>
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="./index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,259 +0,0 @@
|
||||
import 'react-app-polyfill/ie11';
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import {
|
||||
Gantt,
|
||||
Task,
|
||||
EventOption,
|
||||
StylingOption,
|
||||
ViewMode,
|
||||
DisplayOption,
|
||||
} from '../src/index';
|
||||
|
||||
//Init
|
||||
const App = () => {
|
||||
const currentDate = new Date();
|
||||
const [view, setView] = React.useState<ViewMode>(ViewMode.Day);
|
||||
let tasks: Task[] = [
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 1),
|
||||
end: new Date(
|
||||
currentDate.getFullYear(),
|
||||
currentDate.getMonth(),
|
||||
2,
|
||||
12,
|
||||
28
|
||||
),
|
||||
name: 'Idea',
|
||||
id: 'Task 0',
|
||||
progress: 45,
|
||||
isDisabled: true,
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 2),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 4, 0, 0),
|
||||
name: 'Research',
|
||||
id: 'Task 1',
|
||||
progress: 25,
|
||||
dependencies: ['Task 0'],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 4),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8, 0, 0),
|
||||
name: 'Discussion with team',
|
||||
id: 'Task 2',
|
||||
progress: 10,
|
||||
dependencies: ['Task 1'],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 9, 0, 0),
|
||||
name: 'Developing',
|
||||
id: 'Task 3',
|
||||
progress: 2,
|
||||
dependencies: ['Task 2'],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 10),
|
||||
name: 'Review',
|
||||
id: 'Task 4',
|
||||
progress: 70,
|
||||
dependencies: ['Task 2'],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 15),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 26),
|
||||
name: 'Release',
|
||||
id: 'Task 6',
|
||||
progress: currentDate.getMonth(),
|
||||
dependencies: ['Task 4'],
|
||||
styles: { progressColor: '#ffbb54', progressSelectedColor: '#ff9e0d' },
|
||||
},
|
||||
];
|
||||
|
||||
let onTaskChange = (task: Task) => {
|
||||
console.log('On date change');
|
||||
};
|
||||
|
||||
let onTaskDelete = (task: Task) => {
|
||||
const conf = confirm('Are you sure?');
|
||||
if (!conf) throw 'No del';
|
||||
};
|
||||
|
||||
let onProgressChange = (task: Task) => {
|
||||
console.log('On progress change');
|
||||
};
|
||||
|
||||
let onDblClick = (task: Task) => {
|
||||
alert('On Double Click event');
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ViewSwitcher onViewChange={viewMode => setView(viewMode)} />
|
||||
<GanttTableExample
|
||||
tasks={tasks}
|
||||
viewMode={view}
|
||||
onDateChange={onTaskChange}
|
||||
onTaskDelete={onTaskDelete}
|
||||
onProgressChange={onProgressChange}
|
||||
onDoubleClick={onDblClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
//Gantt with Custom table example
|
||||
type GanttTableExampleProps = { tasks: Task[] } & EventOption & DisplayOption;
|
||||
export const GanttTableExample: React.SFC<GanttTableExampleProps> = props => {
|
||||
const gridColumnWidth = 150;
|
||||
let options: StylingOption = {
|
||||
fontSize: '14px',
|
||||
fontFamily:
|
||||
'Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue',
|
||||
headerHeight: 50,
|
||||
rowHeight: 50,
|
||||
};
|
||||
if (props.viewMode === ViewMode.Month) {
|
||||
options.columnWidth = 300;
|
||||
} else if (props.viewMode === ViewMode.Week) {
|
||||
options.columnWidth = 250;
|
||||
}
|
||||
|
||||
const [tasks, setTasks] = React.useState(props.tasks);
|
||||
const onTaskDateChange = async (task: Task) => {
|
||||
if (props.onDateChange) {
|
||||
try {
|
||||
await props.onDateChange(task);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
setTasks(tasks.map(t => (t.id === task.id ? task : t)));
|
||||
}
|
||||
};
|
||||
|
||||
const onTaskProgressChange = async (task: Task) => {
|
||||
if (props.onProgressChange) {
|
||||
try {
|
||||
await props.onProgressChange(task);
|
||||
} catch (e) {
|
||||
setTasks(props.tasks.slice());
|
||||
throw e;
|
||||
}
|
||||
|
||||
setTasks(tasks.map(t => (t.id === task.id ? task : t)));
|
||||
}
|
||||
};
|
||||
|
||||
const onTaskItemDelete = async (task: Task) => {
|
||||
if (props.onTaskDelete) {
|
||||
await props.onTaskDelete(task);
|
||||
setTasks(tasks.filter(t => t.id !== task.id));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="Wrapper">
|
||||
<div
|
||||
className="GanttTable"
|
||||
style={{
|
||||
fontFamily: options.fontFamily,
|
||||
fontSize: options.fontSize,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="GanttTable-header"
|
||||
style={{
|
||||
height: options.headerHeight,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="fromDate" className="GanttTable-icon">
|
||||
📃
|
||||
</span>
|
||||
Name
|
||||
</div>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="fromDate" className="GanttTable-icon">
|
||||
📅
|
||||
</span>
|
||||
From
|
||||
</div>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="toDate" className="GanttTable-icon">
|
||||
📅
|
||||
</span>
|
||||
To
|
||||
</div>
|
||||
</div>
|
||||
{tasks.map(t => {
|
||||
return (
|
||||
<div
|
||||
className="GanttTable-row"
|
||||
style={{ height: options.rowHeight }}
|
||||
>
|
||||
<div className="GanttTable-cell">{t.name}</div>
|
||||
<div className="GanttTable-cell">{t.start.toDateString()}</div>
|
||||
<div className="GanttTable-cell">{t.end.toDateString()}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div style={{ overflowX: 'scroll' }}>
|
||||
<Gantt
|
||||
{...options}
|
||||
{...props}
|
||||
tasks={tasks}
|
||||
onDateChange={onTaskDateChange}
|
||||
onTaskDelete={onTaskItemDelete}
|
||||
onProgressChange={onTaskProgressChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type ViewSwitcherProps = {
|
||||
onViewChange: (viewMode: ViewMode) => void;
|
||||
};
|
||||
const ViewSwitcher: React.SFC<ViewSwitcherProps> = ({ onViewChange }) => {
|
||||
return (
|
||||
<div className="ViewContainer">
|
||||
<button
|
||||
className="Button"
|
||||
onClick={() => onViewChange(ViewMode.QuarterDay)}
|
||||
>
|
||||
Quarter of Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.HalfDay)}>
|
||||
Half of Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Day)}>
|
||||
Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Week)}>
|
||||
Week
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Month)}>
|
||||
Month
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
27343
example/package-lock.json
generated
27343
example/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,44 @@
|
||||
{
|
||||
"name": "example",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"name": "gantt-task-react-example",
|
||||
"homepage": ".",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "parcel index.html",
|
||||
"build": "parcel build index.html"
|
||||
"start": "node ../node_modules/react-scripts/bin/react-scripts.js start",
|
||||
"build": "node ../node_modules/react-scripts/bin/react-scripts.js build",
|
||||
"test": "node ../node_modules/react-scripts/bin/react-scripts.js test",
|
||||
"eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-app-polyfill": "^1.0.0"
|
||||
},
|
||||
"alias": {
|
||||
"react": "../node_modules/react",
|
||||
"react-dom": "../node_modules/react-dom/profiling",
|
||||
"scheduler/tracing": "../node_modules/scheduler/tracing-profiling"
|
||||
"@testing-library/jest-dom": "file:../node_modules/@testing-library/jest-dom",
|
||||
"@testing-library/react": "file:../node_modules/@testing-library/react",
|
||||
"@testing-library/user-event": "file:../node_modules/@testing-library/user-event",
|
||||
"@types/jest": "file:../node_modules/@types/jest",
|
||||
"@types/node": "file:../node_modules/@types/node",
|
||||
"@types/react": "file:../node_modules/@types/react",
|
||||
"@types/react-dom": "file:../node_modules/@types/react-dom",
|
||||
"react": "file:../node_modules/react",
|
||||
"react-dom": "file:../node_modules/react-dom",
|
||||
"react-scripts": "file:../node_modules/react-scripts",
|
||||
"typescript": "file:../node_modules/typescript",
|
||||
"gantt-task-react": "file:.."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"parcel": "^1.12.3",
|
||||
"typescript": "^3.4.5"
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
BIN
example/public/favicon.ico
Normal file
BIN
example/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
48
example/public/index.html
Normal file
48
example/public/index.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>gantt-task-react</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
15
example/public/manifest.json
Normal file
15
example/public/manifest.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "gantt-task-react",
|
||||
"name": "gantt-task-react",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
9
example/src/App.test.tsx
Normal file
9
example/src/App.test.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div')
|
||||
ReactDOM.render(<App />, div)
|
||||
ReactDOM.unmountComponentAtNode(div)
|
||||
})
|
||||
101
example/src/App.tsx
Normal file
101
example/src/App.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import React from "react";
|
||||
import "gantt-task-react/dist/index.css";
|
||||
import { Task, ViewMode } from "gantt-task-react";
|
||||
import { ViewSwitcher } from "./components/view-switcher";
|
||||
import { GanttTableExample } from "./components/gantt-table";
|
||||
|
||||
//Init
|
||||
const App = () => {
|
||||
const currentDate = new Date();
|
||||
const [view, setView] = React.useState<ViewMode>(ViewMode.Day);
|
||||
let tasks: Task[] = [
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 1),
|
||||
end: new Date(
|
||||
currentDate.getFullYear(),
|
||||
currentDate.getMonth(),
|
||||
2,
|
||||
12,
|
||||
28
|
||||
),
|
||||
name: "Idea",
|
||||
id: "Task 0",
|
||||
progress: 45,
|
||||
isDisabled: true,
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 2),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 4, 0, 0),
|
||||
name: "Research",
|
||||
id: "Task 1",
|
||||
progress: 25,
|
||||
dependencies: ["Task 0"],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 4),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8, 0, 0),
|
||||
name: "Discussion with team",
|
||||
id: "Task 2",
|
||||
progress: 10,
|
||||
dependencies: ["Task 1"],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 9, 0, 0),
|
||||
name: "Developing",
|
||||
id: "Task 3",
|
||||
progress: 2,
|
||||
dependencies: ["Task 2"],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 8),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 10),
|
||||
name: "Review",
|
||||
id: "Task 4",
|
||||
progress: 70,
|
||||
dependencies: ["Task 2"],
|
||||
},
|
||||
{
|
||||
start: new Date(currentDate.getFullYear(), currentDate.getMonth(), 15),
|
||||
end: new Date(currentDate.getFullYear(), currentDate.getMonth(), 26),
|
||||
name: "Release",
|
||||
id: "Task 6",
|
||||
progress: currentDate.getMonth(),
|
||||
dependencies: ["Task 4"],
|
||||
styles: { progressColor: "#ffbb54", progressSelectedColor: "#ff9e0d" },
|
||||
},
|
||||
];
|
||||
|
||||
let onTaskChange = (task: Task) => {
|
||||
console.log("On date change Id:" + task.id);
|
||||
};
|
||||
|
||||
let onTaskDelete = (task: Task) => {
|
||||
const conf = window.confirm("Are you sure?");
|
||||
if (!conf) throw "No del Id:" + task.id;
|
||||
};
|
||||
|
||||
let onProgressChange = (task: Task) => {
|
||||
console.log("On progress change Id:" + task.id);
|
||||
};
|
||||
|
||||
let onDblClick = (task: Task) => {
|
||||
alert("On Double Click event Id:" + task.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ViewSwitcher onViewChange={viewMode => setView(viewMode)} />
|
||||
<GanttTableExample
|
||||
tasks={tasks}
|
||||
viewMode={view}
|
||||
onDateChange={onTaskChange}
|
||||
onTaskDelete={onTaskDelete}
|
||||
onProgressChange={onProgressChange}
|
||||
onDoubleClick={onDblClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
135
example/src/components/gantt-table.tsx
Normal file
135
example/src/components/gantt-table.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
import React from "react";
|
||||
import "gantt-task-react/dist/index.css";
|
||||
import {
|
||||
Gantt,
|
||||
Task,
|
||||
EventOption,
|
||||
StylingOption,
|
||||
ViewMode,
|
||||
DisplayOption,
|
||||
} from "gantt-task-react";
|
||||
|
||||
//Gantt with Custom table example
|
||||
type GanttTableExampleProps = { tasks: Task[] } & EventOption & DisplayOption;
|
||||
export const GanttTableExample: React.SFC<GanttTableExampleProps> = props => {
|
||||
const gridColumnWidth = 150;
|
||||
let options: StylingOption = {
|
||||
fontSize: "14px",
|
||||
fontFamily:
|
||||
"Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue",
|
||||
headerHeight: 50,
|
||||
rowHeight: 50,
|
||||
};
|
||||
if (props.viewMode === ViewMode.Month) {
|
||||
options.columnWidth = 300;
|
||||
} else if (props.viewMode === ViewMode.Week) {
|
||||
options.columnWidth = 250;
|
||||
}
|
||||
|
||||
const [tasks, setTasks] = React.useState(props.tasks);
|
||||
const onTaskDateChange = async (task: Task) => {
|
||||
if (props.onDateChange) {
|
||||
try {
|
||||
await props.onDateChange(task);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
setTasks(tasks.map(t => (t.id === task.id ? task : t)));
|
||||
}
|
||||
};
|
||||
|
||||
const onTaskProgressChange = async (task: Task) => {
|
||||
if (props.onProgressChange) {
|
||||
try {
|
||||
await props.onProgressChange(task);
|
||||
} catch (e) {
|
||||
setTasks(props.tasks.slice());
|
||||
throw e;
|
||||
}
|
||||
|
||||
setTasks(tasks.map(t => (t.id === task.id ? task : t)));
|
||||
}
|
||||
};
|
||||
|
||||
const onTaskItemDelete = async (task: Task) => {
|
||||
if (props.onTaskDelete) {
|
||||
await props.onTaskDelete(task);
|
||||
setTasks(tasks.filter(t => t.id !== task.id));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="Wrapper">
|
||||
<div
|
||||
className="GanttTable"
|
||||
style={{
|
||||
fontFamily: options.fontFamily,
|
||||
fontSize: options.fontSize,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="GanttTable-header"
|
||||
style={{
|
||||
height: options.headerHeight,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="fromDate" className="GanttTable-icon">
|
||||
📃
|
||||
</span>
|
||||
Name
|
||||
</div>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="fromDate" className="GanttTable-icon">
|
||||
📅
|
||||
</span>
|
||||
From
|
||||
</div>
|
||||
<div
|
||||
className="GanttTable-headerItem"
|
||||
style={{
|
||||
minWidth: gridColumnWidth,
|
||||
}}
|
||||
>
|
||||
<span role="img" aria-label="toDate" className="GanttTable-icon">
|
||||
📅
|
||||
</span>
|
||||
To
|
||||
</div>
|
||||
</div>
|
||||
{tasks.map(t => {
|
||||
return (
|
||||
<div
|
||||
className="GanttTable-row"
|
||||
style={{ height: options.rowHeight }}
|
||||
>
|
||||
<div className="GanttTable-cell">{t.name}</div>
|
||||
<div className="GanttTable-cell">{t.start.toDateString()}</div>
|
||||
<div className="GanttTable-cell">{t.end.toDateString()}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div style={{ overflowX: "scroll" }}>
|
||||
<Gantt
|
||||
{...options}
|
||||
{...props}
|
||||
tasks={tasks}
|
||||
onDateChange={onTaskDateChange}
|
||||
onTaskDelete={onTaskItemDelete}
|
||||
onProgressChange={onTaskProgressChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
32
example/src/components/view-switcher.tsx
Normal file
32
example/src/components/view-switcher.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import "gantt-task-react/dist/index.css";
|
||||
import { ViewMode } from "gantt-task-react";
|
||||
type ViewSwitcherProps = {
|
||||
onViewChange: (viewMode: ViewMode) => void;
|
||||
};
|
||||
export const ViewSwitcher: React.SFC<ViewSwitcherProps> = ({
|
||||
onViewChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="ViewContainer">
|
||||
<button
|
||||
className="Button"
|
||||
onClick={() => onViewChange(ViewMode.QuarterDay)}
|
||||
>
|
||||
Quarter of Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.HalfDay)}>
|
||||
Half of Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Day)}>
|
||||
Day
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Week)}>
|
||||
Week
|
||||
</button>
|
||||
<button className="Button" onClick={() => onViewChange(ViewMode.Month)}>
|
||||
Month
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
7
example/src/index.tsx
Normal file
7
example/src/index.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import './index.css'
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
1
example/src/react-app-env.d.ts
vendored
Normal file
1
example/src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
5
example/src/setupTests.ts
Normal file
5
example/src/setupTests.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
@ -1,19 +1,38 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"outDir": "dist",
|
||||
"module": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"esnext"
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"removeComments": true,
|
||||
"strictNullChecks": true,
|
||||
"preserveConstEnums": true,
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"lib": ["es2015", "es2016", "dom"],
|
||||
"baseUrl": ".",
|
||||
"types": ["node"]
|
||||
}
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
moduleNameMapper: {
|
||||
'^.+\\.(css|less|scss)$': 'babel-jest',
|
||||
},
|
||||
};
|
||||
11208
package-lock.json
generated
11208
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
89
package.json
89
package.json
@ -1,58 +1,63 @@
|
||||
{
|
||||
"version": "0.0.2",
|
||||
"license": "MIT",
|
||||
"name": "gantt-task-react",
|
||||
"author": "Maksym Vikarii <maksym.vikarii@gmail.com>",
|
||||
"homepage": "https://github.com/MaTeMaTuK/gantt-task-react",
|
||||
"module": "dist/gantt-task-react.esm.js",
|
||||
"version": "0.0.3",
|
||||
"description": "Interactive Gantt Chart for React with TypeScript.",
|
||||
"author": "MaTeMaTuK",
|
||||
"license": "MIT",
|
||||
"repository": "MaTeMaTuK/gantt-task-react",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"module": "dist/index.modern.js",
|
||||
"source": "src/index.tsx",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "tsdx watch",
|
||||
"build": "tsdx build",
|
||||
"test": "tsdx test --passWithNoTests",
|
||||
"lint": "tsdx lint",
|
||||
"prepare": "tsdx build"
|
||||
"build": "microbundle-crl --no-compress --format modern,cjs",
|
||||
"start": "microbundle-crl watch --no-compress --format modern,cjs",
|
||||
"prepare": "run-s build",
|
||||
"test": "run-s test:unit test:lint test:build",
|
||||
"test:build": "run-s build",
|
||||
"test:lint": "eslint --ext .tsx src/**/*",
|
||||
"test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
|
||||
"test:watch": "react-scripts test --env=jsdom",
|
||||
"predeploy": "cd example && npm install && npm run build",
|
||||
"deploy": "gh-pages -d example/build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "tsdx lint"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 80,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
"react": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.9.41",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"husky": "^4.2.5",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"@types/jest": "^25.1.4",
|
||||
"@types/node": "^12.12.38",
|
||||
"@types/react": "^16.9.27",
|
||||
"@types/react-dom": "^16.9.7",
|
||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||
"@typescript-eslint/parser": "^2.26.0",
|
||||
"microbundle-crl": "^0.13.10",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.7.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-config-standard-react": "^9.2.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.17.0",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"gh-pages": "^2.2.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.0.4",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"tsdx": "^0.13.2",
|
||||
"tslib": "^2.0.0",
|
||||
"typescript": "^3.9.6"
|
||||
"react-scripts": "^3.4.1",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"autoprefixer": "^9.8.5",
|
||||
"cssnano": "^4.1.10",
|
||||
"rollup-plugin-postcss": "^3.1.2"
|
||||
},
|
||||
"keywords": [
|
||||
"gantt",
|
||||
"typescript",
|
||||
"react"
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
|
||||
5
src/.eslintrc
Normal file
5
src/.eslintrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import '../../style.css';
|
||||
import React from "react";
|
||||
import styles from "./bar.module.css";
|
||||
|
||||
type BarDateHandleProps = {
|
||||
x: number;
|
||||
@ -23,10 +23,10 @@ export const BarDateHandle: React.FC<BarDateHandleProps> = ({
|
||||
y={y}
|
||||
width={width}
|
||||
height={height}
|
||||
className="GanttBar-handle"
|
||||
className={styles.barHandle}
|
||||
ry={barCornerRadius}
|
||||
rx={barCornerRadius}
|
||||
onMouseDown={onMouseDown}
|
||||
></rect>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import '../../style.css';
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import style from "./bar.module.css";
|
||||
|
||||
type BarDisplayProps = {
|
||||
x: number;
|
||||
@ -66,7 +66,7 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
|
||||
ry={barCornerRadius}
|
||||
rx={barCornerRadius}
|
||||
fill={getBarColor()}
|
||||
className="GanttBar"
|
||||
className={style.barBackground}
|
||||
/>
|
||||
<rect
|
||||
x={x}
|
||||
@ -80,9 +80,11 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
|
||||
<text
|
||||
x={getX()}
|
||||
y={y + height * 0.5}
|
||||
className={`GanttBar-label ${
|
||||
isTextInside ? '' : 'GanttBar-label-outside'
|
||||
}`}
|
||||
className={
|
||||
isTextInside
|
||||
? style.barLabel
|
||||
: style.barLabel && style.barLabelOutside
|
||||
}
|
||||
ref={textRef}
|
||||
>
|
||||
{text}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import '../../style.css';
|
||||
import React from "react";
|
||||
import styles from "./bar.module.css";
|
||||
|
||||
type BarProgressHandleProps = {
|
||||
progressPoint: string;
|
||||
@ -11,9 +11,9 @@ export const BarProgressHandle: React.FC<BarProgressHandleProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<polygon
|
||||
className="GanttBar-handle"
|
||||
className={styles.barHandle}
|
||||
points={progressPoint}
|
||||
onMouseDown={onMouseDown}
|
||||
></polygon>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
40
src/components/Bar/bar.module.css
Normal file
40
src/components/Bar/bar.module.css
Normal file
@ -0,0 +1,40 @@
|
||||
.barWrapper {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.barWrapper:hover .barHandle {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.barHandle {
|
||||
fill: #ddd;
|
||||
cursor: ew-resize;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.barLabel {
|
||||
fill: #fff;
|
||||
text-anchor: middle;
|
||||
font-weight: lighter;
|
||||
dominant-baseline: central;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.barLabelOutside {
|
||||
fill: #555;
|
||||
text-anchor: start;
|
||||
}
|
||||
|
||||
.barBackground {
|
||||
user-select: none;
|
||||
stroke-width: 0;
|
||||
}
|
||||
@ -1,15 +1,15 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Task } from '../../types/public-types';
|
||||
import { BarProgressHandle } from './bar-progress-handle';
|
||||
import { BarDateHandle } from './bar-date-handle';
|
||||
import { BarDisplay } from './bar-display';
|
||||
import { BarTask } from '../../types/bar-task';
|
||||
import { BarAction } from '../Gantt/gantt-content';
|
||||
import React, { useState } from "react";
|
||||
import { Task } from "../../types/public-types";
|
||||
import { BarProgressHandle } from "./bar-progress-handle";
|
||||
import { BarDateHandle } from "./bar-date-handle";
|
||||
import { BarDisplay } from "./bar-display";
|
||||
import { BarTask } from "../../types/bar-task";
|
||||
import { BarAction } from "../Gantt/gantt-content";
|
||||
import {
|
||||
progressWithByParams,
|
||||
getProgressPoint,
|
||||
} from '../../helpers/bar-helper';
|
||||
import '../../style.css';
|
||||
} from "../../helpers/bar-helper";
|
||||
import styles from "./bar.module.css";
|
||||
|
||||
export type BarProps = {
|
||||
task: BarTask;
|
||||
@ -51,7 +51,7 @@ export const Bar: React.FC<BarProps> = ({
|
||||
|
||||
return (
|
||||
<g
|
||||
className="GanttBar-wrapper"
|
||||
className={styles.barWrapper}
|
||||
onDoubleClick={() => {
|
||||
!!onDoubleClick && onDoubleClick(task);
|
||||
}}
|
||||
@ -60,10 +60,10 @@ export const Bar: React.FC<BarProps> = ({
|
||||
handleButtonSVGEvents(e, task);
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
handleMouseEvents(e, 'mouseenter', task);
|
||||
handleMouseEvents(e, "mouseenter", task);
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
handleMouseEvents(e, 'mouseleave', task);
|
||||
handleMouseEvents(e, "mouseleave", task);
|
||||
}}
|
||||
onFocus={() => setIsSelected(true)}
|
||||
onBlur={() => setIsSelected(false)}
|
||||
@ -81,12 +81,12 @@ export const Bar: React.FC<BarProps> = ({
|
||||
styles={task.styles}
|
||||
isSelected={isSelected}
|
||||
onMouseDown={e => {
|
||||
isDateChangeable && handleMouseEvents(e, 'move', task);
|
||||
isDateChangeable && handleMouseEvents(e, "move", task);
|
||||
}}
|
||||
/>
|
||||
<g className="handleGroup">
|
||||
{isDateChangeable && (
|
||||
<>
|
||||
<g>
|
||||
{/* left */}
|
||||
<BarDateHandle
|
||||
x={task.x1 + 1}
|
||||
@ -95,7 +95,7 @@ export const Bar: React.FC<BarProps> = ({
|
||||
height={task.height - 2}
|
||||
barCornerRadius={task.barCornerRadius}
|
||||
onMouseDown={e => {
|
||||
handleMouseEvents(e, 'start', task);
|
||||
handleMouseEvents(e, "start", task);
|
||||
}}
|
||||
/>
|
||||
{/* right */}
|
||||
@ -106,16 +106,16 @@ export const Bar: React.FC<BarProps> = ({
|
||||
height={task.height - 2}
|
||||
barCornerRadius={task.barCornerRadius}
|
||||
onMouseDown={e => {
|
||||
handleMouseEvents(e, 'end', task);
|
||||
handleMouseEvents(e, "end", task);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</g>
|
||||
)}
|
||||
{isProgressChangeable && (
|
||||
<BarProgressHandle
|
||||
progressPoint={progressPoint}
|
||||
onMouseDown={e => {
|
||||
handleMouseEvents(e, 'progress', task);
|
||||
handleMouseEvents(e, "progress", task);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
25
src/components/Calendar/calendar.module.css
Normal file
25
src/components/Calendar/calendar.module.css
Normal file
@ -0,0 +1,25 @@
|
||||
.calendarBottomText {
|
||||
text-anchor: middle;
|
||||
fill: #333;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.calendarTopTick {
|
||||
stroke: #e6e4e4;
|
||||
}
|
||||
|
||||
.calendarTopText {
|
||||
text-anchor: middle;
|
||||
fill: #555;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
import React, { ReactChild } from 'react';
|
||||
import { ViewMode } from '../../types/public-types';
|
||||
import { TopPartOfCalendar } from './top-part-of-calendar';
|
||||
import React, { ReactChild } from "react";
|
||||
import { ViewMode } from "../../types/public-types";
|
||||
import { TopPartOfCalendar } from "./top-part-of-calendar";
|
||||
import {
|
||||
getLocaleMonth,
|
||||
getWeekNumberISO8601,
|
||||
} from '../../helpers/date-helper';
|
||||
import '../../style.css';
|
||||
} from "../../helpers/date-helper";
|
||||
import styles from "./calendar.module.css";
|
||||
|
||||
export type CalendarProps = {
|
||||
dates: Date[];
|
||||
locale: string;
|
||||
@ -26,25 +27,25 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
fontSize,
|
||||
}) => {
|
||||
const getCalendarValuesForMonth = () => {
|
||||
let topValues: ReactChild[] = [];
|
||||
let bottomValues: ReactChild[] = [];
|
||||
const topValues: ReactChild[] = [];
|
||||
const bottomValues: ReactChild[] = [];
|
||||
const topDefaultWidth = columnWidth * 6;
|
||||
const topDefaultHeight = headerHeight * 0.5;
|
||||
for (let i = 0; i < dates.length; i++) {
|
||||
const date = dates[i];
|
||||
let bottomValue = getLocaleMonth(date, locale);
|
||||
const bottomValue = getLocaleMonth(date, locale);
|
||||
bottomValues.push(
|
||||
<text
|
||||
key={bottomValue + date.getFullYear()}
|
||||
y={headerHeight * 0.8}
|
||||
x={columnWidth * i + columnWidth * 0.5}
|
||||
className="GanttCalendar-bottomText"
|
||||
className={styles.calendarBottomText}
|
||||
>
|
||||
{bottomValue}
|
||||
</text>
|
||||
);
|
||||
if (i === 0 || date.getFullYear() !== dates[i - 1].getFullYear()) {
|
||||
let topValue = date.getFullYear().toString();
|
||||
const topValue = date.getFullYear().toString();
|
||||
topValues.push(
|
||||
<TopPartOfCalendar
|
||||
key={topValue}
|
||||
@ -64,13 +65,13 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
};
|
||||
|
||||
const getCalendarValuesForWeek = () => {
|
||||
let topValues: ReactChild[] = [];
|
||||
let bottomValues: ReactChild[] = [];
|
||||
const topValues: ReactChild[] = [];
|
||||
const bottomValues: ReactChild[] = [];
|
||||
let weeksCount: number = 0;
|
||||
const topDefaultHeight = headerHeight * 0.5;
|
||||
for (let i = dates.length - 1; i >= 0; i--) {
|
||||
const date = dates[i];
|
||||
let topValue = '';
|
||||
let topValue = "";
|
||||
if (i === 0 || date.getMonth() !== dates[i - 1].getMonth()) {
|
||||
// top
|
||||
topValue = `${getLocaleMonth(date, locale)}, ${date.getFullYear()}`;
|
||||
@ -83,7 +84,7 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
key={date.getTime()}
|
||||
y={headerHeight * 0.8}
|
||||
x={columnWidth * i}
|
||||
className="GanttCalendar-bottomText"
|
||||
className={styles.calendarBottomText}
|
||||
>
|
||||
{bottomValue}
|
||||
</text>
|
||||
@ -112,8 +113,8 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
};
|
||||
|
||||
const getCalendarValuesForDay = () => {
|
||||
let topValues: ReactChild[] = [];
|
||||
let bottomValues: ReactChild[] = [];
|
||||
const topValues: ReactChild[] = [];
|
||||
const bottomValues: ReactChild[] = [];
|
||||
const topDefaultHeight = headerHeight * 0.5;
|
||||
for (let i = 0; i < dates.length; i++) {
|
||||
const date = dates[i];
|
||||
@ -124,7 +125,7 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
key={date.getTime()}
|
||||
y={headerHeight * 0.8}
|
||||
x={columnWidth * i + columnWidth * 0.5}
|
||||
className="GanttCalendar-bottomText"
|
||||
className={styles.calendarBottomText}
|
||||
>
|
||||
{bottomValue}
|
||||
</text>
|
||||
@ -133,7 +134,7 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
i + 1 !== dates.length &&
|
||||
date.getMonth() !== dates[i + 1].getMonth()
|
||||
) {
|
||||
let topValue = getLocaleMonth(date, locale);
|
||||
const topValue = getLocaleMonth(date, locale);
|
||||
|
||||
topValues.push(
|
||||
<TopPartOfCalendar
|
||||
@ -152,15 +153,15 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
};
|
||||
|
||||
const getCalendarValuesForOther = () => {
|
||||
let topValues: ReactChild[] = [];
|
||||
let bottomValues: ReactChild[] = [];
|
||||
let ticks = viewMode === ViewMode.HalfDay ? 2 : 4;
|
||||
const topValues: ReactChild[] = [];
|
||||
const bottomValues: ReactChild[] = [];
|
||||
const ticks = viewMode === ViewMode.HalfDay ? 2 : 4;
|
||||
const topDefaultHeight = headerHeight * 0.5;
|
||||
|
||||
for (let i = 0; i < dates.length; i++) {
|
||||
const date = dates[i];
|
||||
const bottomValue = Intl.DateTimeFormat(locale, {
|
||||
hour: 'numeric',
|
||||
hour: "numeric",
|
||||
}).format(date);
|
||||
|
||||
bottomValues.push(
|
||||
@ -168,7 +169,7 @@ export const Calendar: React.FC<CalendarProps> = ({
|
||||
key={date.getTime()}
|
||||
y={headerHeight * 0.8}
|
||||
x={columnWidth * i}
|
||||
className="GanttCalendar-bottomText"
|
||||
className={styles.calendarBottomText}
|
||||
fontFamily={fontFamily}
|
||||
>
|
||||
{bottomValue}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import '../../style.css';
|
||||
import React from "react";
|
||||
import styles from "./calendar.module.css";
|
||||
|
||||
type TopPartOfCalendarProps = {
|
||||
value: string;
|
||||
@ -19,23 +19,23 @@ export const TopPartOfCalendar: React.FC<TopPartOfCalendarProps> = ({
|
||||
yText,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<g className="calendarTop">
|
||||
<line
|
||||
x1={x1Line}
|
||||
y1={y1Line}
|
||||
x2={x1Line}
|
||||
y2={y2Line}
|
||||
className="GanttCalendar-topTick"
|
||||
key={value + 'line'}
|
||||
></line>
|
||||
className={styles.calendarTopTick}
|
||||
key={value + "line"}
|
||||
/>
|
||||
<text
|
||||
key={value + 'text'}
|
||||
key={value + "text"}
|
||||
y={yText}
|
||||
x={xText}
|
||||
className="GanttCalendar-topText"
|
||||
className={styles.calendarTopText}
|
||||
>
|
||||
{value}
|
||||
</text>
|
||||
</>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Task, EventOption } from '../../types/public-types';
|
||||
import { Bar } from '../Bar/bar';
|
||||
import { BarTask } from '../../types/bar-task';
|
||||
import { Arrow } from '../Other/arrow';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Task, EventOption } from "../../types/public-types";
|
||||
import { Bar } from "../Bar/bar";
|
||||
import { BarTask } from "../../types/bar-task";
|
||||
import { Arrow } from "../Other/arrow";
|
||||
import {
|
||||
convertToBarTasks,
|
||||
progressByX,
|
||||
@ -10,8 +10,9 @@ import {
|
||||
endByX,
|
||||
moveByX,
|
||||
dateByX,
|
||||
} from '../../helpers/bar-helper';
|
||||
import { Tooltip } from '../Other/tooltip';
|
||||
} from "../../helpers/bar-helper";
|
||||
import { Tooltip } from "../Other/tooltip";
|
||||
|
||||
export interface GanttTask extends Task {
|
||||
x1: number;
|
||||
x2: number;
|
||||
@ -46,13 +47,13 @@ export type GanttContentProps = {
|
||||
} & EventOption;
|
||||
|
||||
export type BarAction =
|
||||
| 'progress'
|
||||
| 'end'
|
||||
| 'start'
|
||||
| 'move'
|
||||
| 'mouseenter'
|
||||
| 'mouseleave'
|
||||
| '';
|
||||
| "progress"
|
||||
| "end"
|
||||
| "start"
|
||||
| "move"
|
||||
| "mouseenter"
|
||||
| "mouseleave"
|
||||
| "";
|
||||
|
||||
type BarEvent = {
|
||||
action: BarAction;
|
||||
@ -84,7 +85,7 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
getTooltipContent,
|
||||
}) => {
|
||||
const [barEvent, setBarEvent] = useState<BarEvent>({
|
||||
action: '',
|
||||
action: "",
|
||||
selectedTask: null,
|
||||
});
|
||||
const [isSVGListen, setIsSVGListen] = useState(false);
|
||||
@ -146,19 +147,20 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
* Method handles event in real time(mousemove) and on finish(mouseup)
|
||||
*/
|
||||
const handleMouseSVGChangeEventsSubscribe = async (event: MouseEvent) => {
|
||||
if (!barEvent.selectedTask || !barEvent.action) return;
|
||||
if (!barEvent.selectedTask || !barEvent.action || !svg || !svg.current)
|
||||
return;
|
||||
|
||||
const selectedTask = barEvent.selectedTask;
|
||||
const changedTask = { ...selectedTask } as BarTask;
|
||||
switch (event.type) {
|
||||
// On Event changing
|
||||
case 'mousemove': {
|
||||
case "mousemove": {
|
||||
switch (barEvent.action) {
|
||||
case 'progress':
|
||||
case "progress":
|
||||
changedTask.progress = progressByX(event.offsetX, selectedTask);
|
||||
break;
|
||||
case 'start':
|
||||
let newX1 = startByX(event.offsetX, xStep, selectedTask);
|
||||
case "start": {
|
||||
const newX1 = startByX(event.offsetX, xStep, selectedTask);
|
||||
changedTask.x1 = newX1;
|
||||
changedTask.start = dateByX(
|
||||
newX1,
|
||||
@ -168,8 +170,9 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
timeStep
|
||||
);
|
||||
break;
|
||||
case 'end':
|
||||
let newX2 = endByX(event.offsetX, xStep, selectedTask);
|
||||
}
|
||||
case "end": {
|
||||
const newX2 = endByX(event.offsetX, xStep, selectedTask);
|
||||
changedTask.x2 = newX2;
|
||||
changedTask.end = dateByX(
|
||||
newX2,
|
||||
@ -179,7 +182,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
timeStep
|
||||
);
|
||||
break;
|
||||
case 'move':
|
||||
}
|
||||
case "move": {
|
||||
const [newMoveX1, newMoveX2] = moveByX(
|
||||
event.offsetX - initEventX1Delta,
|
||||
xStep,
|
||||
@ -203,6 +207,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
changedTask.x2 = newMoveX2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update internal state
|
||||
setBarTasks(
|
||||
barTasks.map(t => (t.id === changedTask.id ? changedTask : t))
|
||||
@ -212,18 +218,18 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
}
|
||||
|
||||
// On finish Event
|
||||
case 'mouseup': {
|
||||
case "mouseup": {
|
||||
let eventForExecution: (
|
||||
task: Task
|
||||
) => void | Promise<void> = () => {};
|
||||
switch (barEvent.action) {
|
||||
case 'progress':
|
||||
case "progress":
|
||||
changedTask.progress = progressByX(event.offsetX, selectedTask);
|
||||
if (onProgressChange) {
|
||||
eventForExecution = onProgressChange;
|
||||
}
|
||||
break;
|
||||
case 'start':
|
||||
case "start": {
|
||||
const newX1 = startByX(event.offsetX, xStep, selectedTask);
|
||||
changedTask.start = dateByX(
|
||||
newX1,
|
||||
@ -236,7 +242,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
eventForExecution = onDateChange;
|
||||
}
|
||||
break;
|
||||
case 'end':
|
||||
}
|
||||
case "end": {
|
||||
const newX2 = endByX(event.offsetX, xStep, selectedTask);
|
||||
changedTask.end = dateByX(
|
||||
newX2,
|
||||
@ -250,7 +257,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
eventForExecution = onDateChange;
|
||||
}
|
||||
break;
|
||||
case 'move':
|
||||
}
|
||||
case "move": {
|
||||
const [newMoveX1, newMoveX2] = moveByX(
|
||||
event.offsetX - initEventX1Delta,
|
||||
xStep,
|
||||
@ -279,15 +287,16 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setBarEvent({ action: '', selectedTask: null });
|
||||
setBarEvent({ action: "", selectedTask: null });
|
||||
setIsSVGListen(false);
|
||||
svg.current?.removeEventListener(
|
||||
'mousemove',
|
||||
svg.current.removeEventListener(
|
||||
"mousemove",
|
||||
handleMouseSVGChangeEventsSubscribe
|
||||
);
|
||||
svg.current?.removeEventListener(
|
||||
'mouseup',
|
||||
svg.current.removeEventListener(
|
||||
"mouseup",
|
||||
handleMouseSVGChangeEventsSubscribe
|
||||
);
|
||||
|
||||
@ -298,14 +307,20 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
if (barEvent.selectedTask && barEvent.action && !isSVGListen) {
|
||||
if (
|
||||
barEvent.selectedTask &&
|
||||
barEvent.action &&
|
||||
!isSVGListen &&
|
||||
svg &&
|
||||
svg.current
|
||||
) {
|
||||
setIsSVGListen(true);
|
||||
svg.current?.addEventListener(
|
||||
'mousemove',
|
||||
svg.current.addEventListener(
|
||||
"mousemove",
|
||||
handleMouseSVGChangeEventsSubscribe
|
||||
);
|
||||
svg.current?.addEventListener(
|
||||
'mouseup',
|
||||
svg.current.addEventListener(
|
||||
"mouseup",
|
||||
handleMouseSVGChangeEventsSubscribe
|
||||
);
|
||||
}
|
||||
@ -336,18 +351,19 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
task: BarTask
|
||||
) => {
|
||||
switch (event.type) {
|
||||
case 'mousedown':
|
||||
case "mousedown":
|
||||
setBarEvent({ ...barEvent, selectedTask: task, action: eventType });
|
||||
setInitEventX1Delta(event.nativeEvent.offsetX - task.x1);
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case 'mouseleave':
|
||||
case "mouseleave":
|
||||
console.log("mouseleave");
|
||||
if (!barEvent.action)
|
||||
setBarEvent({ ...barEvent, selectedTask: task, action: '' });
|
||||
setBarEvent({ ...barEvent, selectedTask: null, action: "" });
|
||||
break;
|
||||
case 'mouseenter':
|
||||
case "mouseenter":
|
||||
if (!barEvent.selectedTask) {
|
||||
setBarEvent({ ...barEvent, selectedTask: task, action: '' });
|
||||
setBarEvent({ ...barEvent, selectedTask: task, action: "" });
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -364,7 +380,7 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
) => {
|
||||
if (task.isDisabled) return;
|
||||
switch (event.key) {
|
||||
case 'Delete': {
|
||||
case "Delete": {
|
||||
if (onTaskDelete) {
|
||||
onTaskDelete(task);
|
||||
}
|
||||
@ -374,8 +390,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<g className="arrow" fill={arrowColor} stroke={arrowColor}>
|
||||
<g className="content">
|
||||
<g className="arrows" fill={arrowColor} stroke={arrowColor}>
|
||||
{barTasks.map(task => {
|
||||
return task.barChildren.map(child => {
|
||||
return (
|
||||
@ -408,8 +424,8 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
</g>
|
||||
<g className="toolTip">
|
||||
{barEvent.selectedTask &&
|
||||
barEvent.action !== 'end' &&
|
||||
barEvent.action !== 'start' && (
|
||||
barEvent.action !== "end" &&
|
||||
barEvent.action !== "start" && (
|
||||
<Tooltip
|
||||
x={barEvent.selectedTask.x2 + columnWidth + arrowIndent}
|
||||
y={barEvent.selectedTask.y + rowHeight}
|
||||
@ -420,6 +436,6 @@ export const GanttContent: React.FC<GanttContentProps> = ({
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
</>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { ViewMode, GanttProps } from '../../types/public-types';
|
||||
import { Grid, GridProps } from '../Grid/grid';
|
||||
import { Calendar, CalendarProps } from '../Calendar/calendar';
|
||||
import { GanttContent, GanttContentProps } from './gantt-content';
|
||||
import { ganttDateRange, seedDates } from '../../helpers/date-helper';
|
||||
import React, { useRef } from "react";
|
||||
import { ViewMode, GanttProps } from "../../types/public-types";
|
||||
import { Grid, GridProps } from "../Grid/grid";
|
||||
import { Calendar, CalendarProps } from "../Calendar/calendar";
|
||||
import { GanttContent, GanttContentProps } from "./gantt-content";
|
||||
import { ganttDateRange, seedDates } from "../../helpers/date-helper";
|
||||
|
||||
export const Gantt: React.SFC<GanttProps> = ({
|
||||
tasks,
|
||||
@ -11,20 +11,20 @@ export const Gantt: React.SFC<GanttProps> = ({
|
||||
columnWidth = 60,
|
||||
rowHeight = 50,
|
||||
viewMode = ViewMode.Day,
|
||||
locale = 'en-GB',
|
||||
locale = "en-GB",
|
||||
barFill = 60,
|
||||
barCornerRadius = 3,
|
||||
barProgressColor = '#a3a3ff',
|
||||
barProgressSelectedColor = '#8282f5',
|
||||
barBackgroundColor = '#b8c2cc',
|
||||
barBackgroundSelectedColor = '#aeb8c2',
|
||||
barProgressColor = "#a3a3ff",
|
||||
barProgressSelectedColor = "#8282f5",
|
||||
barBackgroundColor = "#b8c2cc",
|
||||
barBackgroundSelectedColor = "#aeb8c2",
|
||||
handleWidth = 8,
|
||||
timeStep = 300000,
|
||||
arrowColor = 'grey',
|
||||
fontFamily = 'Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue',
|
||||
fontSize = '14px',
|
||||
arrowColor = "grey",
|
||||
fontFamily = "Arial, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue",
|
||||
fontSize = "14px",
|
||||
arrowIndent = 20,
|
||||
todayColor = 'rgba(252, 248, 227, 0.5)',
|
||||
todayColor = "rgba(252, 248, 227, 0.5)",
|
||||
onDateChange,
|
||||
onProgressChange,
|
||||
onDoubleClick,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React, { ReactChild } from 'react';
|
||||
import { Task } from '../../types/public-types';
|
||||
import { addToDate } from '../../helpers/date-helper';
|
||||
import '../../style.css';
|
||||
import React, { ReactChild } from "react";
|
||||
import { Task } from "../../types/public-types";
|
||||
import { addToDate } from "../../helpers/date-helper";
|
||||
import styles from "./grid.module.css";
|
||||
|
||||
export type GridBodyProps = {
|
||||
tasks: Task[];
|
||||
@ -22,36 +22,36 @@ export const GridBody: React.FC<GridBodyProps> = ({
|
||||
todayColor,
|
||||
}) => {
|
||||
let y = headerHeight;
|
||||
let gridRows: ReactChild[] = [];
|
||||
let rowLines: ReactChild[] = [];
|
||||
const gridRows: ReactChild[] = [];
|
||||
const rowLines: ReactChild[] = [];
|
||||
for (const task of tasks) {
|
||||
gridRows.push(
|
||||
<rect
|
||||
key={'Row' + task.id}
|
||||
key={"Row" + task.id}
|
||||
x="0"
|
||||
y={y}
|
||||
width={gridWidth}
|
||||
height={rowHeight}
|
||||
className="GanttGrid-row"
|
||||
></rect>
|
||||
className={styles.gridRow}
|
||||
/>
|
||||
);
|
||||
rowLines.push(
|
||||
<line
|
||||
key={'RowLine' + task.id}
|
||||
key={"RowLine" + task.id}
|
||||
x="0"
|
||||
y1={y + rowHeight}
|
||||
x2={gridWidth}
|
||||
y2={y + rowHeight}
|
||||
className="GanttGrid-rowLine"
|
||||
></line>
|
||||
className={styles.gridRowLine}
|
||||
/>
|
||||
);
|
||||
y += rowHeight;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
let tickX = 0;
|
||||
let ticks: ReactChild[] = [];
|
||||
let today: ReactChild = <></>;
|
||||
const ticks: ReactChild[] = [];
|
||||
let today: ReactChild = <rect />;
|
||||
for (let i = 0; i < dates.length; i++) {
|
||||
const date = dates[i];
|
||||
ticks.push(
|
||||
@ -61,8 +61,8 @@ export const GridBody: React.FC<GridBodyProps> = ({
|
||||
y1={headerHeight}
|
||||
x2={tickX}
|
||||
y2={y}
|
||||
className="GanttGrid-tick"
|
||||
></line>
|
||||
className={styles.gridTick}
|
||||
/>
|
||||
);
|
||||
if (
|
||||
(i + 1 !== dates.length &&
|
||||
@ -75,7 +75,7 @@ export const GridBody: React.FC<GridBodyProps> = ({
|
||||
addToDate(
|
||||
date,
|
||||
date.getTime() - dates[i - 1].getTime(),
|
||||
'millisecond'
|
||||
"millisecond"
|
||||
).getTime() >= now.getTime())
|
||||
) {
|
||||
today = (
|
||||
@ -85,17 +85,17 @@ export const GridBody: React.FC<GridBodyProps> = ({
|
||||
width={columnWidth}
|
||||
height={y}
|
||||
fill={todayColor}
|
||||
></rect>
|
||||
/>
|
||||
);
|
||||
}
|
||||
tickX += columnWidth;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<g className="gridBody">
|
||||
<g className="rows">{gridRows}</g>
|
||||
<g className="rowLines">{rowLines}</g>
|
||||
<g className="ticks">{ticks}</g>
|
||||
<g className="today">{today}</g>
|
||||
</>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import '../../style.css';
|
||||
import React from "react";
|
||||
import styles from "./grid.module.css";
|
||||
|
||||
export type GridHeaderProps = {
|
||||
gridWidth: number;
|
||||
@ -15,7 +15,7 @@ export const GridHeader: React.FC<GridHeaderProps> = ({
|
||||
y="0"
|
||||
width={gridWidth}
|
||||
height={headerHeight}
|
||||
className="GanttGrid-header"
|
||||
></rect>
|
||||
className={styles.gridHeader}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
21
src/components/Grid/grid.module.css
Normal file
21
src/components/Grid/grid.module.css
Normal file
@ -0,0 +1,21 @@
|
||||
.gridRow {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.gridRow:nth-child(even) {
|
||||
fill: #f5f5f5;
|
||||
}
|
||||
|
||||
.gridHeader {
|
||||
fill: #ffffff;
|
||||
stroke: #e0e0e0;
|
||||
stroke-width: 1.4;
|
||||
}
|
||||
|
||||
.gridRowLine {
|
||||
stroke: #ebeff2;
|
||||
}
|
||||
|
||||
.gridTick {
|
||||
stroke: #e6e4e4;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { GridBody, GridBodyProps } from './grid-body';
|
||||
import { GridHeader, GridHeaderProps } from './grid-header';
|
||||
import React from "react";
|
||||
import { GridBody, GridBodyProps } from "./grid-body";
|
||||
import { GridHeader, GridHeaderProps } from "./grid-header";
|
||||
|
||||
export type GridProps = GridBodyProps & GridHeaderProps;
|
||||
export const Grid: React.FC<GridProps> = props => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { BarTask } from '../../types/bar-task';
|
||||
import React from "react";
|
||||
import { BarTask } from "../../types/bar-task";
|
||||
|
||||
type ArrowProps = {
|
||||
taskFrom: BarTask;
|
||||
@ -26,9 +26,9 @@ export const Arrow: React.FC<ArrowProps> = ({
|
||||
${taskTo.x1 - 5},${taskToEndPosition - 5}
|
||||
${taskTo.x1 - 5},${taskToEndPosition + 5}`;
|
||||
return (
|
||||
<>
|
||||
<g className="arrow">
|
||||
<path strokeWidth="1.5" d={path} fill="none" />
|
||||
<polygon points={trianglePoints} />
|
||||
</>
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
15
src/components/Other/tooltip.module.css
Normal file
15
src/components/Other/tooltip.module.css
Normal file
@ -0,0 +1,15 @@
|
||||
.tooltipDefaultContainer {
|
||||
background: #fff;
|
||||
padding: 12px;
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
|
||||
}
|
||||
|
||||
.tooltipDefaultContainerParagraph {
|
||||
font-size: 12px;
|
||||
margin-bottom: 6px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tooltipDetailsContainer {
|
||||
display: table;
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { Task } from '../../types/public-types';
|
||||
import '../../style.css';
|
||||
import React, { useRef, useEffect, useState } from "react";
|
||||
import { Task } from "../../types/public-types";
|
||||
import styles from "./tooltip.module.css";
|
||||
|
||||
export type TooltipProps = {
|
||||
x: number;
|
||||
y: number;
|
||||
@ -36,7 +37,7 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
||||
}, [tooltipRef, y]);
|
||||
return (
|
||||
<foreignObject x={x} y={relatedY} width={toolWidth} height={1000}>
|
||||
<div ref={tooltipRef} className="TooltipDetailsContainer">
|
||||
<div ref={tooltipRef} className={styles.tooltipDetailsContainer}>
|
||||
{getTooltipContent(task, fontSize, fontFamily)}
|
||||
</div>
|
||||
</foreignObject>
|
||||
@ -53,17 +54,21 @@ const getStandardTooltipContent = (
|
||||
fontFamily,
|
||||
};
|
||||
return (
|
||||
<div className="TooltipDefaultContainer" style={style}>
|
||||
<div className={styles.tooltipDefaultContainer} style={style}>
|
||||
<b style={{ fontSize: fontSize + 6 }}>{`${
|
||||
task.name
|
||||
}: ${task.start.getDate()}-${task.start.getMonth() +
|
||||
1}-${task.start.getFullYear()} - ${task.end.getDate()}-${task.end.getMonth() +
|
||||
1}-${task.end.getFullYear()}`}</b>
|
||||
<p className="TooltipDefaultContainer-paragraph">{`Duration: ${~~(
|
||||
}: ${task.start.getDate()}-${
|
||||
task.start.getMonth() + 1
|
||||
}-${task.start.getFullYear()} - ${task.end.getDate()}-${
|
||||
task.end.getMonth() + 1
|
||||
}-${task.end.getFullYear()}`}</b>
|
||||
<p className={styles.tooltipDefaultContainerParagraph}>{`Duration: ${~~(
|
||||
(task.end.getTime() - task.start.getTime()) /
|
||||
(1000 * 60 * 60 * 24)
|
||||
)} day(s)`}</p>
|
||||
<p className="TooltipDefaultContainer-paragraph">{`Progress: ${task.progress} %`}</p>
|
||||
<p
|
||||
className={styles.tooltipDefaultContainerParagraph}
|
||||
>{`Progress: ${task.progress} %`}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Task } from '../types/public-types';
|
||||
import { BarTask } from '../types/bar-task';
|
||||
import { Task } from "../types/public-types";
|
||||
import { BarTask } from "../types/bar-task";
|
||||
|
||||
export const convertToBarTasks = (
|
||||
tasks: Task[],
|
||||
@ -168,7 +168,7 @@ export const getProgressPoint = (
|
||||
progressX,
|
||||
taskY + taskHeight - 8.66,
|
||||
];
|
||||
return point.join(',');
|
||||
return point.join(",");
|
||||
};
|
||||
|
||||
export const startByX = (x: number, xStep: number, task: BarTask) => {
|
||||
|
||||
@ -1,54 +1,54 @@
|
||||
import { Task, ViewMode } from '../types/public-types';
|
||||
import { Task, ViewMode } from "../types/public-types";
|
||||
|
||||
type DateHelperScales =
|
||||
| 'year'
|
||||
| 'month'
|
||||
| 'day'
|
||||
| 'hour'
|
||||
| 'minute'
|
||||
| 'second'
|
||||
| 'millisecond';
|
||||
| "year"
|
||||
| "month"
|
||||
| "day"
|
||||
| "hour"
|
||||
| "minute"
|
||||
| "second"
|
||||
| "millisecond";
|
||||
|
||||
export const addToDate = (
|
||||
date: Date,
|
||||
quantity: number,
|
||||
scale: DateHelperScales
|
||||
) => {
|
||||
let newDate = new Date(
|
||||
date.getFullYear() + (scale === 'year' ? quantity : 0),
|
||||
date.getMonth() + (scale === 'month' ? quantity : 0),
|
||||
date.getDate() + (scale === 'day' ? quantity : 0),
|
||||
date.getHours() + (scale === 'hour' ? quantity : 0),
|
||||
date.getMinutes() + (scale === 'minute' ? quantity : 0),
|
||||
date.getSeconds() + (scale === 'second' ? quantity : 0),
|
||||
date.getMilliseconds() + (scale === 'millisecond' ? quantity : 0)
|
||||
const newDate = new Date(
|
||||
date.getFullYear() + (scale === "year" ? quantity : 0),
|
||||
date.getMonth() + (scale === "month" ? quantity : 0),
|
||||
date.getDate() + (scale === "day" ? quantity : 0),
|
||||
date.getHours() + (scale === "hour" ? quantity : 0),
|
||||
date.getMinutes() + (scale === "minute" ? quantity : 0),
|
||||
date.getSeconds() + (scale === "second" ? quantity : 0),
|
||||
date.getMilliseconds() + (scale === "millisecond" ? quantity : 0)
|
||||
);
|
||||
return newDate;
|
||||
};
|
||||
|
||||
export const startOfDate = (date: Date, scale: DateHelperScales) => {
|
||||
const scores = [
|
||||
'millisecond',
|
||||
'second',
|
||||
'minute',
|
||||
'hour',
|
||||
'day',
|
||||
'month',
|
||||
'year',
|
||||
"millisecond",
|
||||
"second",
|
||||
"minute",
|
||||
"hour",
|
||||
"day",
|
||||
"month",
|
||||
"year",
|
||||
];
|
||||
|
||||
const shouldReset = (_scale: DateHelperScales) => {
|
||||
const max_score = scores.indexOf(scale);
|
||||
return scores.indexOf(_scale) <= max_score;
|
||||
const maxScore = scores.indexOf(scale);
|
||||
return scores.indexOf(_scale) <= maxScore;
|
||||
};
|
||||
let newDate = new Date(
|
||||
const newDate = new Date(
|
||||
date.getFullYear(),
|
||||
shouldReset('year') ? 0 : date.getMonth(),
|
||||
shouldReset('month') ? 1 : date.getDate(),
|
||||
shouldReset('day') ? 0 : date.getHours(),
|
||||
shouldReset('hour') ? 0 : date.getMinutes(),
|
||||
shouldReset('minute') ? 0 : date.getSeconds(),
|
||||
shouldReset('second') ? 0 : date.getMilliseconds()
|
||||
shouldReset("year") ? 0 : date.getMonth(),
|
||||
shouldReset("month") ? 1 : date.getDate(),
|
||||
shouldReset("day") ? 0 : date.getHours(),
|
||||
shouldReset("hour") ? 0 : date.getMinutes(),
|
||||
shouldReset("minute") ? 0 : date.getSeconds(),
|
||||
shouldReset("second") ? 0 : date.getMilliseconds()
|
||||
);
|
||||
return newDate;
|
||||
};
|
||||
@ -56,7 +56,7 @@ export const startOfDate = (date: Date, scale: DateHelperScales) => {
|
||||
export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
|
||||
let newStartDate: Date = tasks[0].start;
|
||||
let newEndDate: Date = tasks[0].end;
|
||||
for (let task of tasks) {
|
||||
for (const task of tasks) {
|
||||
if (task.start < newStartDate) {
|
||||
newStartDate = task.start;
|
||||
}
|
||||
@ -64,22 +64,24 @@ export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
|
||||
newEndDate = task.end;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewMode === ViewMode.Month) {
|
||||
newStartDate = addToDate(newStartDate, -1, 'month');
|
||||
newEndDate = addToDate(newEndDate, 1, 'year');
|
||||
newEndDate = startOfDate(newEndDate, 'year');
|
||||
} else if (viewMode === ViewMode.Week) {
|
||||
newStartDate = startOfDate(newStartDate, 'day');
|
||||
newEndDate = startOfDate(newEndDate, 'day');
|
||||
|
||||
newStartDate = addToDate(getMonday(newStartDate), -7, 'day');
|
||||
newEndDate = addToDate(newEndDate, 1.5, 'month');
|
||||
} else {
|
||||
newStartDate = startOfDate(newStartDate, 'day');
|
||||
newEndDate = startOfDate(newEndDate, 'day');
|
||||
newStartDate = addToDate(newStartDate, -1, 'day');
|
||||
newEndDate = addToDate(newEndDate, 19, 'day');
|
||||
switch (viewMode) {
|
||||
case ViewMode.Month:
|
||||
newStartDate = addToDate(newStartDate, -1, "month");
|
||||
newEndDate = addToDate(newEndDate, 1, "year");
|
||||
newEndDate = startOfDate(newEndDate, "year");
|
||||
break;
|
||||
case ViewMode.Week:
|
||||
newStartDate = startOfDate(newStartDate, "day");
|
||||
newEndDate = startOfDate(newEndDate, "day");
|
||||
newStartDate = addToDate(getMonday(newStartDate), -7, "day");
|
||||
newEndDate = addToDate(newEndDate, 1.5, "month");
|
||||
break;
|
||||
default:
|
||||
newStartDate = startOfDate(newStartDate, "day");
|
||||
newEndDate = startOfDate(newEndDate, "day");
|
||||
newStartDate = addToDate(newStartDate, -1, "day");
|
||||
newEndDate = addToDate(newEndDate, 19, "day");
|
||||
break;
|
||||
}
|
||||
return [newStartDate, newEndDate];
|
||||
};
|
||||
@ -90,18 +92,24 @@ export const seedDates = (
|
||||
viewMode: ViewMode
|
||||
) => {
|
||||
let currentDate: Date = new Date(startDate);
|
||||
let dates: Date[] = [currentDate];
|
||||
const dates: Date[] = [currentDate];
|
||||
while (currentDate < endDate) {
|
||||
if (viewMode === ViewMode.Month) {
|
||||
currentDate = addToDate(currentDate, 1, 'month');
|
||||
} else if (viewMode === ViewMode.Week) {
|
||||
currentDate = addToDate(currentDate, 7, 'day');
|
||||
} else if (viewMode === ViewMode.Day) {
|
||||
currentDate = addToDate(currentDate, 1, 'day');
|
||||
} else if (viewMode === ViewMode.HalfDay) {
|
||||
currentDate = addToDate(currentDate, 12, 'hour');
|
||||
} else if (viewMode === ViewMode.QuarterDay) {
|
||||
currentDate = addToDate(currentDate, 6, 'hour');
|
||||
switch (viewMode) {
|
||||
case ViewMode.Month:
|
||||
currentDate = addToDate(currentDate, 1, "month");
|
||||
break;
|
||||
case ViewMode.Week:
|
||||
currentDate = addToDate(currentDate, 7, "day");
|
||||
break;
|
||||
case ViewMode.Day:
|
||||
currentDate = addToDate(currentDate, 1, "day");
|
||||
break;
|
||||
case ViewMode.HalfDay:
|
||||
currentDate = addToDate(currentDate, 12, "hour");
|
||||
break;
|
||||
case ViewMode.QuarterDay:
|
||||
currentDate = addToDate(currentDate, 6, "hour");
|
||||
break;
|
||||
}
|
||||
dates.push(currentDate);
|
||||
}
|
||||
@ -110,7 +118,7 @@ export const seedDates = (
|
||||
|
||||
export const getLocaleMonth = (date: Date, locale: string) => {
|
||||
let bottomValue = new Intl.DateTimeFormat(locale, {
|
||||
month: 'long',
|
||||
month: "long",
|
||||
}).format(date);
|
||||
bottomValue = bottomValue.replace(
|
||||
bottomValue[0],
|
||||
@ -130,7 +138,7 @@ const getMonday = (date: Date) => {
|
||||
};
|
||||
|
||||
export const getWeekNumberISO8601 = (date: Date) => {
|
||||
let tmpDate = new Date(date.valueOf());
|
||||
const tmpDate = new Date(date.valueOf());
|
||||
const dayNumber = (tmpDate.getDay() + 6) % 7;
|
||||
tmpDate.setDate(tmpDate.getDate() - dayNumber + 3);
|
||||
const firstThursday = tmpDate.valueOf();
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
export { Gantt } from './components/Gantt/gantt';
|
||||
export {
|
||||
export { Gantt } from "./components/Gantt/gantt";
|
||||
export { ViewMode } from "./types/public-types";
|
||||
export type {
|
||||
GanttProps,
|
||||
Task,
|
||||
ViewMode,
|
||||
StylingOption,
|
||||
DisplayOption,
|
||||
EventOption,
|
||||
} from './types/public-types';
|
||||
} from "./types/public-types";
|
||||
|
||||
1
src/react-app-env.d.ts
vendored
Normal file
1
src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@ -1,34 +0,0 @@
|
||||
import { Task } from '../types/public-types';
|
||||
|
||||
type GanttReduceState = {
|
||||
ganttTasks: Task[];
|
||||
};
|
||||
|
||||
export type GanttReduceAction = {
|
||||
type: 'update' | 'delete';
|
||||
changedTask?: Task;
|
||||
};
|
||||
|
||||
export function ganttReducer(
|
||||
state: GanttReduceState,
|
||||
action: GanttReduceAction
|
||||
): GanttReduceState {
|
||||
switch (action.type) {
|
||||
case 'update': {
|
||||
return {
|
||||
ganttTasks: state.ganttTasks.map(t =>
|
||||
t.id === action.changedTask?.id ? action.changedTask : t
|
||||
),
|
||||
};
|
||||
}
|
||||
case 'delete': {
|
||||
return {
|
||||
ganttTasks: state.ganttTasks.filter(
|
||||
t => t.id !== action.changedTask?.id
|
||||
),
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { Task } from './public-types';
|
||||
import { Task } from "./public-types";
|
||||
|
||||
export interface BarTask extends Task {
|
||||
index: number;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
export enum ViewMode {
|
||||
QuarterDay = 'Quarter Day',
|
||||
HalfDay = 'Half Day',
|
||||
Day = 'Day',
|
||||
QuarterDay = "Quarter Day",
|
||||
HalfDay = "Half Day",
|
||||
Day = "Day",
|
||||
/** ISO-8601 week */
|
||||
Week = 'Week',
|
||||
Month = 'Month',
|
||||
Week = "Week",
|
||||
Month = "Month",
|
||||
}
|
||||
export interface Task {
|
||||
id: string;
|
||||
|
||||
18
src/typings.d.ts
vendored
Normal file
18
src/typings.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Default CSS definition for typescript,
|
||||
* will be overridden with file-specific definitions by rollup
|
||||
*/
|
||||
declare module "*.css" {
|
||||
const content: { [className: string]: string };
|
||||
export default content;
|
||||
}
|
||||
|
||||
interface SvgrComponent
|
||||
extends React.StatelessComponent<React.SVGAttributes<SVGElement>> {}
|
||||
|
||||
declare module "*.svg" {
|
||||
const svgUrl: string;
|
||||
const svgComponent: SvgrComponent;
|
||||
export default svgUrl;
|
||||
export { svgComponent as ReactComponent };
|
||||
}
|
||||
@ -2,11 +2,11 @@ import {
|
||||
seedDates,
|
||||
addToDate,
|
||||
getWeekNumberISO8601,
|
||||
} from '../src/helpers/date-helper';
|
||||
import { ViewMode } from '../src/types/public-types';
|
||||
} from "../helpers/date-helper";
|
||||
import { ViewMode } from "../types/public-types";
|
||||
|
||||
describe('seed date', () => {
|
||||
test('daily', () => {
|
||||
describe("seed date", () => {
|
||||
test("daily", () => {
|
||||
expect(
|
||||
seedDates(new Date(2020, 5, 28), new Date(2020, 6, 2), ViewMode.Day)
|
||||
).toEqual([
|
||||
@ -18,7 +18,7 @@ describe('seed date', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('weekly', () => {
|
||||
test("weekly", () => {
|
||||
expect(
|
||||
seedDates(new Date(2020, 5, 28), new Date(2020, 6, 19), ViewMode.Week)
|
||||
).toEqual([
|
||||
@ -29,13 +29,13 @@ describe('seed date', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('monthly', () => {
|
||||
test("monthly", () => {
|
||||
expect(
|
||||
seedDates(new Date(2020, 5, 28), new Date(2020, 6, 19), ViewMode.Month)
|
||||
).toEqual([new Date(2020, 5, 28), new Date(2020, 6, 28)]);
|
||||
});
|
||||
|
||||
test('quarterly', () => {
|
||||
test("quarterly", () => {
|
||||
expect(
|
||||
seedDates(
|
||||
new Date(2020, 5, 28),
|
||||
@ -52,22 +52,22 @@ describe('seed date', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('add to date', () => {
|
||||
test('add month', () => {
|
||||
expect(addToDate(new Date(2020, 0, 1), 40, 'month')).toEqual(
|
||||
describe("add to date", () => {
|
||||
test("add month", () => {
|
||||
expect(addToDate(new Date(2020, 0, 1), 40, "month")).toEqual(
|
||||
new Date(2023, 4, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('add day', () => {
|
||||
expect(addToDate(new Date(2020, 0, 1), 40, 'day')).toEqual(
|
||||
test("add day", () => {
|
||||
expect(addToDate(new Date(2020, 0, 1), 40, "day")).toEqual(
|
||||
new Date(2020, 1, 10)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('get week number', () => {
|
||||
expect(getWeekNumberISO8601(new Date(2019, 11, 31))).toEqual('01');
|
||||
expect(getWeekNumberISO8601(new Date(2021, 0, 1))).toEqual('53');
|
||||
expect(getWeekNumberISO8601(new Date(2020, 6, 20))).toEqual('30');
|
||||
test("get week number", () => {
|
||||
expect(getWeekNumberISO8601(new Date(2019, 11, 31))).toEqual("01");
|
||||
expect(getWeekNumberISO8601(new Date(2021, 0, 1))).toEqual("53");
|
||||
expect(getWeekNumberISO8601(new Date(2020, 6, 20))).toEqual("30");
|
||||
});
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Gantt } from '../src/index';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Gantt } from "../index";
|
||||
|
||||
describe('gantt', () => {
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
describe("gantt", () => {
|
||||
it("renders without crashing", () => {
|
||||
const div = document.createElement("div");
|
||||
ReactDOM.render(
|
||||
<Gantt
|
||||
tasks={[
|
||||
{
|
||||
start: new Date(2020, 0, 1),
|
||||
end: new Date(2020, 2, 2),
|
||||
name: 'Redesign website',
|
||||
id: 'Task 0',
|
||||
name: "Redesign website",
|
||||
id: "Task 0",
|
||||
progress: 45,
|
||||
},
|
||||
]}
|
||||
|
||||
@ -1,23 +1,39 @@
|
||||
{
|
||||
"include": ["src", "types", "tsdx.config.js", "tsdx.config.js"],
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "esnext"],
|
||||
"importHelpers": true,
|
||||
"declaration": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"esnext"
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"*": ["src/*", "node_modules/*"]
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"example"
|
||||
]
|
||||
}
|
||||
|
||||
6
tsconfig.test.json
Normal file
6
tsconfig.test.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const cssnano = require('cssnano');
|
||||
module.exports = {
|
||||
rollup(config, options) {
|
||||
config.plugins.push(
|
||||
postcss({
|
||||
plugins: [
|
||||
autoprefixer(),
|
||||
cssnano({
|
||||
preset: 'default',
|
||||
}),
|
||||
],
|
||||
inject: false,
|
||||
extract: !!options.writeMeta,
|
||||
})
|
||||
);
|
||||
return config;
|
||||
},
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user