{"_id":"@dizzy_yakov/vue-gantt","_rev":"10-84870fb9beb01d9085a678e776fd329a","name":"@dizzy_yakov/vue-gantt","dist-tags":{"latest":"1.10.0"},"versions":{"1.0.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.0.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.0.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"476f79f24338f8dd12cc3eda3ca4484d31adb764","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.0.0.tgz","fileCount":31,"integrity":"sha512-7taMFyf6dTKQ6TmBslRyS/L0itBXK4zgSf1jRvPLjXeFGRV1L3Tol+SxsWlNCkkpJII8jALsorOQ5YuoNXosVA==","signatures":[{"sig":"MEQCIBnCLxcHdZfiR4UOsNnzmtLzX64Vj6CezzUaCirfIOIZAiAWekw5wvCYBo58ttBTt84+i8Up6WE7FJpWKE1A+xdD8Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":142411},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"407827a0321ff2d44a6af5d0da66c2aa22bf80c2","scripts":{"dev":"vite","lint":"run-s lint:*","build":"run-s type-check build-only build:types","format":"oxfmt src/","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.22.3","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","oxfmt":"^0.45.0","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.0.0_1782212463174_0.6361111395311858","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.1.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.1.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"132da1d652dc44a926e25529aad6d07d94d182ec","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.1.0.tgz","fileCount":31,"integrity":"sha512-BQJHJ9BfvyNZxit6QD0PfSABEAzbsBG0ap/IPeD1vFeqX4i1QAr3WN6NVKMRtmfrn4NqdBixLbpkVcZuQPSO2A==","signatures":[{"sig":"MEYCIQDCUNjSjxzBV2c2cOVv3wRi8x8maNHRaIDXqtPcnkg2kAIhAJO3kq3bdnHyQG/e0ZBFXVKlJhB6H+6zctL4Z1/S+OYn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":160644},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"b054269fd62a8c25e6347b1b3c267f73756d12b5","scripts":{"dev":"vite","lint":"run-s lint:*","build":"run-s type-check build-only build:types","format":"oxfmt src/","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.0","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","oxfmt":"^0.45.0","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.1.0_1782391127215_0.09929168844516445","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.2.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.2.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"aa260cdd53e12554f1fe177ffc462078a95b59b6","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.2.0.tgz","fileCount":33,"integrity":"sha512-p5mZbGdgRGpRKo30SPCJY4pj1pLrkYbEFmQzDQV7P3yJMYUzTVavUvgAQdUvDzIbCo8NlqUzAOWz6oT+4Q98Yg==","signatures":[{"sig":"MEUCIBpvSbEdTls35pzXU3EbyWGvmoMTp8z8S/EGdh4cPu7wAiEA8QeDILb3VTlqOqf48b7uTHW/e8R9fTw4+5qls+pb7XI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":173417},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"24eb8350644170154bd808e5a44d33a02512102d","scripts":{"dev":"vite","lint":"run-s lint:*","build":"run-s type-check build-only build:types","format":"oxfmt src/","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.0","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","oxfmt":"^0.45.0","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.2.0_1782426379123_0.4115379199803073","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.3.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.3.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"7a7339f4c8b5ef8668f7d3bb5f21864e6fd0a901","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.3.0.tgz","fileCount":34,"integrity":"sha512-8rN7FGSyggGP0XC6oOphD9wVs2tuQApouQpUGmcElmC5HzgBWNw9fS8XbtbH96Qm9M3PR9/B7mFlF+B3ZuguBA==","signatures":[{"sig":"MEQCIHFZGVILdpTUq5Uis03+py1BFR5FEiJpAACXfGD/ql+iAiBPn8DZqsTkuIO3bPckqVqkJn+54qiVw3OiiVCPzzpXbg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":177927},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"08f9e662dbf87c449135cda13971b9bdebe07d11","scripts":{"dev":"vite","lint":"run-s lint:*","build":"run-s type-check build-only build:types","format":"oxfmt src/","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.0","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","oxfmt":"^0.45.0","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.3.0_1782709477816_0.010953041492665516","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.5.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.5.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"b71ddd340d724090ef95b7179e03af22dce754a3","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.5.0.tgz","fileCount":43,"integrity":"sha512-1yPSC0ZfMmdcjdP2yvgwRa6eoUn3t124Le+vusajH1Bphr+hJ2X9RW3MZNjAItfiraXMhjvCYOrr2QIKBz74/A==","signatures":[{"sig":"MEQCIBDuyIJD0ag/msI0yteyjf1w5HTwPclTjSQ6iEos6726AiBpn+T4A3onVq92+fxp32HsSaoengkZ9STHzscVARbjgw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":263791},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"15945c2a48587a46071dba646511f27b4d0abf12","scripts":{"dev":"vite","lint":"run-s lint:*","bench":"vitest bench --run","build":"run-s type-check build-only build:types","format":"prettier --write .","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","format:check":"prettier --check .","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.1","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","prettier":"^3.4.2","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.5.0_1782987933192_0.8596542603797395","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.6.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.6.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"231b3930fb9ad4e6f72925326abbddc631e1c253","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.6.0.tgz","fileCount":46,"integrity":"sha512-HHk7ugHj01jNkoy6xuop/USX39d4ZORvlYWZX5WR6yhCZsmN/m4Uox7pcytBeX35/rGGQWwj/pkOeH4J0YgFag==","signatures":[{"sig":"MEUCIGxIZEhdLxLg7pmDMHye4YBetfSRmLm+ckZKKzS3h1qKAiEAwCl8yXswYHO1nHK8mPMtWbjPucgGe7xxbfuAsO3iFb8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":297932},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"53f66dee6593877665e7df23821fc3859b023bc1","scripts":{"dev":"vite","lint":"run-s lint:*","bench":"vitest bench --run","build":"run-s type-check build-only build:types","format":"prettier --write .","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","format:check":"prettier --check .","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.1","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","prettier":"^3.4.2","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.6.0_1783116784054_0.7380659837913504","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.7.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.7.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"09be801cb348e47e11aa4dc5b7631d9e219e7e1d","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.7.0.tgz","fileCount":53,"integrity":"sha512-oxzlmO8zCWUElwm9oY2sgqyC1NRBbKpklh+EzUKGibuxSRiwbmz6np+9PW93kCnpRyt5m2GbgwIpMEg2GhCllQ==","signatures":[{"sig":"MEQCIGWpdzw60frW1wQbp2w3PnfcoQ+UrHLe8Gny5rmRdhwjAiAQOIQtx9qoqeC+g0DMXGtPIqTPVeS+OFKlWwP0IJmJCQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":329433},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"fdb925e58198449242595680eecf4c7f54dd969b","scripts":{"dev":"vite","lint":"run-s lint:*","bench":"vitest bench --run","build":"run-s type-check build-only build:types","format":"prettier --write .","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","format:check":"prettier --check .","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.1","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","prettier":"^3.4.2","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.7.0_1783406213830_0.8915623175294141","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.8.0","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.8.0","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/LavaYasha/vue-gantt#readme","bugs":{"url":"https://github.com/LavaYasha/vue-gantt/issues"},"dist":{"shasum":"4029f9c78ae5dccbd08725f241f7f95cc7f5ccb7","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.8.0.tgz","fileCount":54,"integrity":"sha512-WrzznSYGenhCA3TiRhkXMIk1+GrFEbo2c9TPJajCeK3D4pRQayc1723GXUwX6UujWA4tJ3rJbQsd8Wge104sXg==","signatures":[{"sig":"MEYCIQDC1bSYfOJmPtibySEfgHiiLQlNqKxtZQ21TXn+o3Xs7wIhAP2vKC9Ol8hgyFsQp9msV50Wnw9HKCdr6zTX079KJPtK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":343204},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"ba380b9dd36492452dd30e5c054a8c51a190f917","scripts":{"dev":"vite","lint":"run-s lint:*","bench":"vitest bench --run","build":"run-s type-check build-only build:types","format":"prettier --write .","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","format:check":"prettier --check .","build-storybook":"storybook build"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/LavaYasha/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.1","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"^4.1.4","vue-tsc":"^3.2.6","prettier":"^3.4.2","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^4.1.9","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.8.0_1783425079797_0.4031836112716112","host":"s3://npm-registry-packages-npm-production"}},"1.9.1":{"name":"@dizzy_yakov/vue-gantt","version":"1.9.1","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"license":"MIT","_id":"@dizzy_yakov/vue-gantt@1.9.1","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"homepage":"https://github.com/DizzyYakov/vue-gantt#readme","bugs":{"url":"https://github.com/DizzyYakov/vue-gantt/issues"},"dist":{"shasum":"daf7121faa5b8c59d67081f6377c87718e71fe34","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.9.1.tgz","fileCount":59,"integrity":"sha512-FA8tlKJAjZQmKcRAra+wTGcurokzBe3BqBIAO2k/BIQbYtm7nXdBxCkHYDh/yun0sYEzFiB0FPC4yDvG2iO23Q==","signatures":[{"sig":"MEQCIA4dW733dyrxqNDAoLgT2bubYXYMg9e4Vn9X721mv1wdAiA9QQc7tTr4vsNE/WXbXGOamQlwBRH/zn0Wl4QkrnmF4w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.9.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":398740},"main":"./dist/vue-gantt.js","type":"module","types":"./dist/index.d.ts","module":"./dist/vue-gantt.js","engines":{"node":"^20.19.0 || >=22.12.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"gitHead":"956a7015ea92f3a8baf101cff1a3359a61206045","scripts":{"dev":"vite","lint":"run-s lint:*","bench":"vitest bench --run","build":"run-s type-check build-only build:types","format":"prettier --write .","prepack":"bun run build","preview":"vite preview","test:e2e":"playwright test","storybook":"storybook dev -p 6006","test:unit":"vitest","build-only":"vite build","type-check":"vue-tsc --build","build:types":"vue-tsc -p tsconfig.build.json","lint:eslint":"eslint . --fix --cache","lint:oxlint":"oxlint . --fix","test:visual":"run-s build-storybook test:visual:run","format:check":"prettier --check .","test:browser":"vitest run -c vitest.browser.config.ts","test:stories":"run-s build-storybook test:stories:run","test:coverage":"vitest run --coverage","build-storybook":"storybook build","test:visual:run":"playwright test -c playwright.visual.config.ts","test:e2e:install":"playwright install","test:stories:run":"playwright test -c playwright.stories.config.ts"},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"repository":{"url":"git+https://github.com/DizzyYakov/vue-gantt.git","type":"git"},"_npmVersion":"10.9.8","description":"Headless, composable Gantt chart components for Vue 3","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.23.1","dependencies":{"date-fns":"^4.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","jiti":"^2.6.1","vite":"^8.0.8","jsdom":"^29.0.2","eslint":"^10.2.1","oxlint":"~1.60.0","vitest":"4.1.10","vue-tsc":"^3.2.6","prettier":"^3.4.2","storybook":"^10","typescript":"~6.0.0","@types/node":"^24.12.2","http-server":"^14.1.1","@types/jsdom":"^28.0.1","npm-run-all2":"^8.0.4","@vue/tsconfig":"^0.9.1","sass-embedded":"^1.100.0","@vitest/browser":"^4.1.10","@vue/test-utils":"^2.4.6","@playwright/test":"^1.59.1","@tsconfig/node24":"^24.0.4","eslint-plugin-vue":"~10.8.0","@vitejs/plugin-vue":"^6.0.6","vitest-browser-vue":"^2.1.0","@vitest/coverage-v8":"4.1.10","@axe-core/playwright":"^4.12.1","@storybook/vue3-vite":"^10","eslint-plugin-oxlint":"~1.60.0","@storybook/addon-docs":"^10","@vitest/eslint-plugin":"^1.6.16","eslint-config-prettier":"^10.1.8","eslint-plugin-playwright":"^2.10.1","vite-plugin-vue-devtools":"^8.1.1","@vitest/browser-playwright":"^4.1.10","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-gantt_1.9.1_1783881650738_0.3300633805172626","host":"s3://npm-registry-packages-npm-production"}},"1.10.0":{"name":"@dizzy_yakov/vue-gantt","version":"1.10.0","type":"module","description":"Headless, composable Gantt chart components for Vue 3","license":"MIT","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"repository":{"type":"git","url":"git+https://github.com/DizzyYakov/vue-gantt.git"},"homepage":"https://github.com/DizzyYakov/vue-gantt#readme","bugs":{"url":"https://github.com/DizzyYakov/vue-gantt/issues"},"publishConfig":{"access":"public"},"main":"./dist/vue-gantt.js","module":"./dist/vue-gantt.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-gantt.js"},"./styles":"./dist/gantt.css","./styles.css":"./dist/gantt.css"},"sideEffects":["**/*.css"],"scripts":{"dev":"vite","build":"run-s type-check build-only build:types","prepack":"bun run build","preview":"vite preview","test:unit":"vitest","bench":"vitest bench --run","test:e2e":"playwright test","build-only":"vite build","build:types":"vue-tsc -p tsconfig.build.json","type-check":"vue-tsc --build","lint":"run-s lint:*","lint:oxlint":"oxlint . --fix","lint:eslint":"eslint . --fix --cache","format":"prettier --write .","format:check":"prettier --check .","storybook":"storybook dev -p 6006","build-storybook":"storybook build","test:browser":"vitest run -c vitest.browser.config.ts","test:coverage":"vitest run --coverage","test:e2e:install":"playwright install","test:stories":"run-s build-storybook test:stories:run","test:stories:run":"playwright test -c playwright.stories.config.ts","test:visual":"run-s build-storybook test:visual:run","test:visual:run":"playwright test -c playwright.visual.config.ts"},"peerDependencies":{"vue":"^3.5.0"},"dependencies":{"date-fns":"^4.4.0"},"devDependencies":{"@axe-core/playwright":"^4.12.1","@playwright/test":"^1.59.1","@storybook/addon-docs":"^10","@storybook/vue3-vite":"^10","@tsconfig/node24":"^24.0.4","@types/jsdom":"^28.0.1","@types/node":"^24.12.2","@vitejs/plugin-vue":"^6.0.6","@vitest/browser":"^4.1.10","@vitest/browser-playwright":"^4.1.10","@vitest/coverage-v8":"4.1.10","@vitest/eslint-plugin":"^1.6.16","@vue/eslint-config-typescript":"^14.7.0","@vue/test-utils":"^2.4.6","@vue/tsconfig":"^0.9.1","eslint":"^10.2.1","eslint-config-prettier":"^10.1.8","eslint-plugin-oxlint":"~1.60.0","eslint-plugin-playwright":"^2.10.1","eslint-plugin-vue":"~10.8.0","http-server":"^14.1.1","jiti":"^2.6.1","jsdom":"^29.0.2","npm-run-all2":"^8.0.4","oxlint":"~1.60.0","prettier":"^3.4.2","sass-embedded":"^1.100.0","storybook":"^10","typescript":"~6.0.0","vite":"^8.0.8","vite-plugin-vue-devtools":"^8.1.1","vitest":"4.1.10","vitest-browser-vue":"^2.1.0","vue":"^3.5.13","vue-tsc":"^3.2.6"},"engines":{"node":"^20.19.0 || >=22.12.0"},"_id":"@dizzy_yakov/vue-gantt@1.10.0","gitHead":"f469a0074b387645c46526020ca028622fea6a2a","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-x7KSanyWxVui9DoRhQXQs9LqTRPrtSl9W6EYb1xETvlne7y/qG27762n2DOwb98yR7ZvLvb+WMmtKy1+uyt7MQ==","shasum":"f7dd493725d2f56702ad4d5a815071220d6a760c","tarball":"https://registry.npmjs.org/@dizzy_yakov/vue-gantt/-/vue-gantt-1.10.0.tgz","fileCount":59,"unpackedSize":403944,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dizzy_yakov%2fvue-gantt@1.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICVCu86RciA2KMgEppSuj4+0Ag8BTlWSszX7JnhmNgvdAiEArXSxDb4OrIpnqZJXz/BF43/VFcehtgqw4YfmEPeGzG8="}]},"_npmUser":{"name":"yakov_dragon","email":"dizertir64@gmail.com"},"directories":{},"maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-gantt_1.10.0_1783930783744_0.5490248010958083"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-23T11:01:03.023Z","modified":"2026-07-13T08:19:44.169Z","1.0.0":"2026-06-23T11:01:03.316Z","1.1.0":"2026-06-25T12:38:47.339Z","1.2.0":"2026-06-25T22:26:19.250Z","1.3.0":"2026-06-29T05:04:37.944Z","1.5.0":"2026-07-02T10:25:33.324Z","1.6.0":"2026-07-03T22:13:04.262Z","1.7.0":"2026-07-07T06:36:53.976Z","1.8.0":"2026-07-07T11:51:19.967Z","1.9.1":"2026-07-12T18:40:50.884Z","1.10.0":"2026-07-13T08:19:43.883Z"},"bugs":{"url":"https://github.com/DizzyYakov/vue-gantt/issues"},"license":"MIT","homepage":"https://github.com/DizzyYakov/vue-gantt#readme","keywords":["vue","vue3","gantt","gantt-chart","timeline","scheduler","headless"],"repository":{"type":"git","url":"git+https://github.com/DizzyYakov/vue-gantt.git"},"description":"Headless, composable Gantt chart components for Vue 3","maintainers":[{"name":"yakov_dragon","email":"dizertir64@gmail.com"}],"readme":"# vue-gantt\n\n[![npm version](https://img.shields.io/npm/v/@dizzy_yakov/vue-gantt.svg)](https://www.npmjs.com/package/@dizzy_yakov/vue-gantt)\n[![npm downloads](https://img.shields.io/npm/dm/@dizzy_yakov/vue-gantt.svg)](https://www.npmjs.com/package/@dizzy_yakov/vue-gantt)\n[![CI](https://github.com/LavaYasha/vue-gantt/actions/workflows/ci.yml/badge.svg)](https://github.com/LavaYasha/vue-gantt/actions/workflows/ci.yml)\n[![minzipped size](https://img.shields.io/bundlephobia/minzip/@dizzy_yakov/vue-gantt)](https://bundlephobia.com/package/@dizzy_yakov/vue-gantt)\n[![types](https://img.shields.io/npm/types/@dizzy_yakov/vue-gantt.svg)](https://www.npmjs.com/package/@dizzy_yakov/vue-gantt)\n[![license](https://img.shields.io/npm/l/@dizzy_yakov/vue-gantt.svg)](./LICENSE)\n[![Storybook](https://img.shields.io/badge/docs-Storybook-ff4785?logo=storybook&logoColor=white)](https://dizzyyakov.github.io/vue-gantt/)\n\nA **headless, composable Gantt chart for Vue 3**. It ships only structural\nlayout — every colour, size and font is a CSS variable — so it drops into any\ndesign system. One runtime dependency (`date-fns`), fully typed.\n\n**📖 [Live docs & interactive demo →](https://dizzyyakov.github.io/vue-gantt/)** — every\ncomponent and feature, explorable in Storybook.\n\n![vue-gantt](https://raw.githubusercontent.com/LavaYasha/vue-gantt/main/docs/hero.png)\n\n## Features\n\n- ⏱️ **Multi-tier time axis** (year · quarter · month · week · day · hour ·\n  minute) — show any subset via `tiers`.\n- 📊 Task **bars with progress**, **milestones**, finish-to-start **dependency\n  arrows**, **baselines** (planned vs actual), and a live **\"today\"** line.\n- 🧩 **Two APIs** — a prop-driven `<Gantt :rows>` or composable primitives.\n- 🗂️ Collapsible **row groups** with rolled-up summary bars, and a deep\n  **row tree (WBS)** via `parentId` with per-parent rollup bars.\n- 🏷️ **Row decoration** — an add-on `row-suffix` slot for badges, plus a\n  `meta` → `data-*` passthrough for CSS-only row highlighting.\n- ✋ **Drag interactions** (all opt-in, controlled): move, resize an edge, set\n  progress, create/edit dependencies, and drag out a new task on an empty row —\n  with a live, formattable tooltip and edge **auto-scroll** to reach drop\n  targets off-screen.\n- 🧊 Frozen header + sidebar, sticky period labels, **row/column\n  virtualization** (kicks in whenever the scroll viewport is height-constrained —\n  by a `height` cap or a fixed-height parent). The scrolling body is its own\n  stacking context, so bars/dependency arrows never paint over the frozen\n  sidebar/header while scrolling.\n- ⌨️ **Keyboard & a11y** (opt-in via `keyboard`) — focusable bars/milestones with\n  ARIA labels, a visible focus ring, Enter/Space activation, roving arrow-key\n  navigation between bars, Shift/Alt+arrow keyboard move/resize, and an accessible\n  sidebar (`tree`/`list` roles, arrow-key row navigation, expand/collapse).\n- 🎨 **Themeable** through `--gantt-*` CSS variables; ships typed `.d.ts`.\n\n## Install\n\n```sh\nbun add @dizzy_yakov/vue-gantt\n```\n\n```sh\nnpm install @dizzy_yakov/vue-gantt\n```\n\n```sh\npnpm add @dizzy_yakov/vue-gantt\n```\n\n```sh\nyarn add @dizzy_yakov/vue-gantt\n```\n\n> `vue` `^3.5` is a peer dependency.\n\nOptionally import the default theme (CSS variables); skip it to style from\nscratch:\n\n```ts\nimport '@dizzy_yakov/vue-gantt/styles'\n```\n\n## Quick start\n\nData is two-level: **rows** are the sidebar entries and each row **contains a\nlist of tasks** plotted on its band (so a row can hold several bars).\n\n```vue\n<script setup lang=\"ts\">\nimport {\n  Gantt,\n  applyMove,\n  type GanttRowData,\n  type GanttMoveEvent,\n} from '@dizzy_yakov/vue-gantt'\nimport { ref } from 'vue'\nimport '@dizzy_yakov/vue-gantt/styles'\n\nconst rows = ref<GanttRowData[]>([\n  {\n    id: 'planning',\n    name: 'Planning',\n    tasks: [\n      {\n        id: 'spec',\n        name: 'Spec',\n        start: '2026-06-01',\n        end: '2026-06-08',\n        progress: 100,\n      },\n      {\n        id: 'ship',\n        name: 'Ship',\n        type: 'milestone',\n        start: '2026-06-16',\n        dependencies: ['design'],\n      },\n    ],\n  },\n  {\n    id: 'design',\n    name: 'Design',\n    tasks: [\n      {\n        id: 'design',\n        name: 'Design',\n        start: '2026-06-08',\n        end: '2026-06-16',\n        progress: 70,\n        dependencies: ['spec'],\n      },\n    ],\n  },\n])\n\n// Drag & drop is controlled — apply the event to your data with the helpers.\nconst onMove = (e: GanttMoveEvent) => (rows.value = applyMove(rows.value, e))\n</script>\n\n<template>\n  <Gantt\n    :rows=\"rows\"\n    :tiers=\"['month', 'week', 'day']\"\n    :height=\"480\"\n    draggable\n    row-movable\n    @move=\"onMove\"\n  />\n</template>\n```\n\n## Two ways to provide data\n\n### 1. Prop-driven wrapper\n\nPass `rows` to `<Gantt>`; it renders the full standard layout and exposes named\nslots for overriding any part. Every slot is scoped — its props give you the same\n(virtualized) data the default renderer uses, so an override stays in sync.\n\n**Section slots** replace a whole band of the layout:\n\n| Slot           | Scoped props                      | Replaces                            |\n| -------------- | --------------------------------- | ----------------------------------- |\n| `corner`       | `{ config }`                      | the sidebar/header corner cell      |\n| `timeline`     | `{ config, visibleColumnsFor }`   | `<GanttTimeline>` (the axis header) |\n| `sidebar`      | `{ rows, groups }`                | `<GanttTaskList>` (the row labels)  |\n| `grid`         | `{ columns, rows }`               | `<GanttGrid>` (the body grid)       |\n| `non-working`  | `{ bands }`                       | `<GanttNonWorking>` (calendar shading) |\n| `period-bands` | `{ periods }`                     | `<GanttPeriods>` (sprint bands)     |\n| `bars`         | `{ tasks }`                       | the task bar / milestone layer      |\n| `group-bars`   | `{ groups }`                      | `<GanttGroupBar>` (group rollups)   |\n| `summary-bars` | `{ rows }`                        | `<GanttSummaryBar>` (row-tree WBS rollups) |\n| `conflicts`    | `{ conflicts }`                   | `<GanttConflicts>`                  |\n| `baselines`    | `{ tasks }`                       | `<GanttBaselines>` (planned bars)   |\n| `slack`        | `{ slack }`                       | `<GanttSlack>` (free-float bars)    |\n| `deadlines`    | `{ tasks }`                       | `<GanttDeadlines>` (deadline lines) |\n| `dependencies` | `{ tasks }`                       | `<GanttDependencies>`               |\n| `marker-lines` | `{ markers }`                     | `<GanttMarkers>` (reference marker lines) |\n| `today`        | `{ today, dateToX }`              | `<GanttToday>`                      |\n| `body-extra`   | `{ contentWidth, contentHeight }` | (extra layer over the body)         |\n\n`visibleColumnsFor` is `(tier: GanttUnit) => GanttColumn[]` (windowed), `dateToX`\nis `(date: Date \\| string \\| number) => number`, `rows`/`groups` are the visible\n`ResolvedRow[]` / `ResolvedGroup[]`, `columns` are the visible base-unit\n`GanttColumn[]`, `periods` is the resolved `ResolvedPeriod[]` (empty unless the\n`periods` prop is set), `bands` is the resolved `ResolvedNonWorkingBand[]` (empty\nunless the `nonWorking` prop is set), `tasks` are `ResolvedTask[]` (all of them for\n`dependencies`, the plotted/visible ones for `bars`, `baselines` and `deadlines`),\n`today` is the configured reference `Date`, `conflicts` is `GanttConflict[]` (empty\nunless `overlap: 'conflict'`), `markers` is the resolved `ResolvedMarker[]` (empty\nunless the `markers` prop is set), and `slack` is a `Map<string, number>` of\nfree-float days by task id (empty unless `slack` is on).\n\n**Leaf slots** customize a single repeated item: `row`\n(`{ row, index, depth, collapsed, hasChildren, toggle }`), `row-suffix`\n(same scope minus `toggle` — an add-on rendered *after* the row name without\nreplacing `row`; see [Row decoration](#row-decoration)), `group`\n(`{ group, collapsed, toggle }`), `groupBar` (`{ group, collapsed, left, width }`),\n`summaryBar` (`{ row, collapsed, left, width }` — a WBS parent row, see\n[row tree](#row-tree-wbs)), `column`\n(`{ column, tier }`), `period` (`{ period }`), `marker` (`{ marker }` — a\n`ResolvedMarker`, see [Reference markers](#reference-markers)), `bar`\n(`{ task, progress, resources }`), `milestone`\n(`{ task, resources, labelMaxWidth }`), `tooltip` (`{ task }`), `rowEditor`\n(`{ row, value, commit, cancel }`) and `taskEditor`\n(`{ task, value, commit, cancel }`). `resources` is the task's assigned\n`ResolvedResource[]` (resolved from `resourceIds`, unknown ids dropped; empty\nunless `resources` is set) — see [Resources](#resources). `labelMaxWidth` is\nthe adaptive gap in px to the next item on the same row — bind it as an inline\nstyle (`:style=\"{ maxWidth: labelMaxWidth + 'px' }\"`) on a `.gantt-milestone__label`\nelement rendered in the `milestone` slot to ellipsize a label instead of\nletting it overlap a neighbouring milestone.\n\n**Per-variant item slots.** Tag an item with a free-form `variant` and the\nprop-driven render picks a slot by it: a bar looks for `task-${variant}`\n(`{ task, progress, resources }`), a marker for `milestone-${variant}`\n(`{ task, resources }`). When no such slot is provided it falls back to the\ngeneric `bar` / `milestone` slot, then to the built-in default — so variants are\npurely additive. Handy for rendering\ncategories (design vs. dev bars, release vs. checkpoint markers) differently:\n\n```vue\n<Gantt :rows=\"rows\">\n  <!-- rows include e.g. { id, start, end, variant: 'design' } and a { type: 'milestone', variant: 'release' } -->\n  <template #task-design=\"{ task }\">🎨 {{ task.name }}</template>\n  <template #milestone-release=\"{ task }\">🚀 {{ task.name }}</template>\n  <template #bar=\"{ task }\">{{ task.name }}</template> <!-- fallback for un-tagged / other bars -->\n</Gantt>\n```\n\nThe `rowEditor` / `taskEditor` slots replace the built-in inline `<input>` (see\n[Inline editing](#inline-editing)) with your own editor — a `<select>`, a masked\nfield, etc. They render only while that row/task is being edited (`editable`\nmust be on). `value` is the current name; call `commit(newValue)` to save (fires\n`row-edit` / `task-edit`) or `cancel()` to discard.\n\nThe `tooltip` slot overrides the content of the opt-in hover tooltip shown on\nbars and milestones; providing it also **enables** the tooltip (you don't need\nthe `tooltip` prop too). Its `task` is the resolved task under the pointer. When\nthe tooltip is enabled without the slot, the default content is the name plus\n`start – end` (and `progress%`) for a bar, or the name plus the date for a\nmilestone. The tooltip is hidden while a drag is in progress. Both the hover\ntooltip and the live drag label flip to sit *below* the bar/milestone instead of\nabove it when there isn't enough room above — e.g. a task on the first row,\nwhere \"above\" would slide under the sticky timeline header.\n\n```vue\n<Gantt :rows=\"rows\" :tiers=\"['month', 'week', 'day']\" :height=\"480\">\n  <!-- the `today` slot gets the reference date + a positioning helper -->\n  <template #today=\"{ today, dateToX }\">\n    <div class=\"my-today\" :style=\"{ left: `${dateToX(today)}px` }\" />\n  </template>\n</Gantt>\n```\n\n### 2. Declarative composition\n\n`<GanttRoot>` provides the shared scale/config; drop the feature components into\nits slots. `<GanttRow>` declares a row and the `<GanttTask>` / `<GanttMilestone>`\ninside it register into that row.\n\n```vue\n<GanttRoot :tiers=\"['month', 'week', 'day']\">\n  <GanttTimeline />\n  <GanttTaskList />\n  <GanttGroup id=\"be\" name=\"Backend\">\n    <GanttRow id=\"api\" name=\"API\">\n      <GanttTask id=\"spec\" name=\"Spec\" start=\"2026-06-01\" end=\"2026-06-08\" :progress=\"100\" />\n      <GanttMilestone id=\"ship\" name=\"Ship\" start=\"2026-06-16\" :dependencies=\"['spec']\" />\n    </GanttRow>\n  </GanttGroup>\n  <GanttGroupBar />\n  <GanttDependencies />\n  <GanttToday />\n</GanttRoot>\n```\n\n## Components\n\nEvery component is exported from the package entry. `<Gantt>` and `<GanttRoot>`\ntake the full [configuration props](#configuration-props-ganttrootprops) and emit\nevery [chart event](#events); the rest are the building blocks.\n\n| Component             | Props                                            | Emits                                            |\n| --------------------- | ------------------------------------------------ | ------------------------------------------------ |\n| `<Gantt>`             | `GanttRootProps` + `height?: number \\| string`   | all [events](#events) · exposes `scrollTo*`      |\n| `<GanttRoot>`         | `GanttRootProps`                                 | all [events](#events) · exposes `scrollTo*`      |\n| `<GanttView>`         | `height?: number \\| string`                      | —                                                |\n| `<GanttTimeline>`     | —                                                | `column-click`                                   |\n| `<GanttTaskList>`     | —                                                | `row-click` · `row-dblclick` · `row-contextmenu` |\n| `<GanttGroup>`        | `id` · `name?` · `collapsed?` · `meta?`          | — (toggle bubbles as `group-toggle` on the root) |\n| `<GanttGroupBar>`     | —                                                | —                                                |\n| `<GanttRow>`          | `id` · `name?` · `tasks?` · `groupId?` · `parentId?` · `collapsed?` · `meta?` | — (toggle bubbles as `row-toggle` on the root) |\n| `<GanttSummaryBar>`   | —                                                | —                                                |\n| `<GanttTask>`         | `GanttItemProps`                                 | `click` · `dblclick` · `contextmenu`             |\n| `<GanttMilestone>`    | `GanttItemProps`                                 | `click` · `dblclick` · `contextmenu`             |\n| `<GanttGrid>`         | `tier?: GanttUnit` (slot `create-hint` `{ row }`, see [drag-to-create](#drag-to-create-tasks)) | `cell-click` · `cell-dblclick` |\n| `<GanttNonWorking>`   | — (default slot `{ band }`)                      | —                                                |\n| `<GanttDependencies>` | —                                                | `dependency-click`                               |\n| `<GanttConflicts>`    | —                                                | —                                                |\n| `<GanttSlack>`        | — (default slot `{ taskId, slack }`)             | —                                                |\n| `<GanttDeadlines>`    | — (default slot `{ taskId, deadline }`)          | —                                                |\n| `<GanttBaselines>`    | — (default slot `{ task }`)                      | —                                                |\n| `<GanttPeriods>`      | — (default slot `{ period }`)                    | —                                                |\n| `<GanttMarkers>`      | — (default slot `{ marker }`)                    | —                                                |\n| `<GanttWorkload>`     | — (slots `label` `{ resource, workload }` · default `{ workload, peak, bars }`) | — |\n| `<GanttToday>`        | `interval?: number` (ms, default `1000`)         | —                                                |\n| `<GanttZoom>`         | — (reads context; default slot for custom UI)    | — (calls `setZoom`/`zoomIn`/`zoomOut` on root)   |\n\nThe leaf components emit short names for **declarative** use (`<GanttTask @click>`).\nThe same interactions are re-emitted, namespaced, on `<GanttRoot>` / `<Gantt>`\n(`task-click`, `milestone-click`, …) so **prop-driven** consumers can listen at\nthe root — see [Events](#events).\n\n**`height` (`<Gantt>` / `<GanttView>`)** — a number is treated as pixels, a\nstring is used verbatim. When set, it **caps** the scroll viewport (`max-height`)\nand enables vertical scrolling + row virtualization. When **omitted**, the chart\nfills its parent's height (`height: 100%`): a height-constrained parent gives\nscrolling + virtualization without an explicit `height`, while an auto-height\nparent collapses to the content height and simply grows to fit (as before).\n\n### Configuration props (`GanttRootProps`)\n\n| Prop                    | Type                                              | Default         | Description                                                                                                                                                                                                                                                   |\n| ----------------------- | ------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `rows`                  | `GanttRowData[]`                                  | —               | Prop-driven data source (omit for declarative `<GanttRow>`).                                                                                                                                                                                                  |\n| `groups`                | `GanttGroupData[]`                                | —               | Group labels + initial `collapsed`, keyed by `id`.                                                                                                                                                                                                            |\n| `unit`                  | `GanttUnit`                                       | `'day'`         | Base granularity when `tiers` is omitted.                                                                                                                                                                                                                     |\n| `tiers`                 | `GanttUnit[]`                                     | `[unit]`        | Header rows, coarse → fine, e.g. `['month','week','day']`.                                                                                                                                                                                                    |\n| `columnWidth`           | `number`                                          | `40`            | Width of one base-unit cell, px.                                                                                                                                                                                                                              |\n| `zoomLevels`            | `GanttZoomLevel[]`                                | `DEFAULT_ZOOM_LEVELS` | Named view-mode presets the `zoom` prop / `GanttZoom` switch between; each bundles `tiers` + `columnWidth` (year → hour).                                                                                                                                |\n| `periods`               | `GanttPeriod[]`                                   | —               | Custom timeline periods (sprints): a background band over the body + a labelled header row. Build a cadence with `sprintPeriods` or pass your own list. See [Timeline period bands](#timeline-period-bands-sprints).                                            |\n| `resources`             | `GanttResource[]`                                 | —               | Flat lookup table of resources (people/equipment) tasks can be assigned to via `resourceIds`. See [Resources](#resources).                                                                                                                                       |\n| `markers`               | `GanttMarker[]`                                   | —               | Reference markers: labelled full-height vertical lines at arbitrary dates (quarter boundaries, release dates). Purely decorative — never extends the axis or adds a header row. See [Reference markers](#reference-markers).                                    |\n| `nonWorking`            | `boolean \\| NonWorkingCalendar`                   | —               | Working calendar: shade non-working time (weekends/holidays/custom off periods) as a background band. `true` shades Sat/Sun. Purely decorative — never extends the axis or adds a header row. See [Non-working calendar](#non-working-calendar).              |\n| `zoom`                  | `string`                                          | —               | Active zoom level id; supports `v-model:zoom`. When set, the matching level's `tiers`/`columnWidth` override those props. Omit for the classic `tiers`/`columnWidth`/`unit` behavior.                                                                          |\n| `rowHeight`             | `number`                                          | `36`            | Row height, px.                                                                                                                                                                                                                                               |\n| `headerRowHeight`       | `number`                                          | `28`            | Height of one timeline tier row, px.                                                                                                                                                                                                                          |\n| `groupHeaderHeight`     | `number`                                          | `36`            | Group header band height, px.                                                                                                                                                                                                                                 |\n| `sidebarWidth`          | `number`                                          | `200`           | Frozen task-list width, px.                                                                                                                                                                                                                                   |\n| `overlap`               | `'lanes' \\| 'overlap' \\| 'cascade' \\| 'conflict'` | `'lanes'`       | How time-overlapping tasks in a row are shown.                                                                                                                                                                                                                |\n| `summaryStyle`          | `'bracket' \\| 'bar'`                              | `'bracket'`     | How rolled-up rows (WBS tree parents, row groups) draw their summary. `bracket`: expanded → a thin span line with downward end caps (no progress fill); collapsed → a filled accent bar. `bar` (legacy): a filled progress bar in both states.                 |\n| `draggable`             | `boolean`                                         | `false`         | Drag bars along their row to change start/end.                                                                                                                                                                                                                |\n| `rowMovable`            | `boolean`                                         | `false`         | Drag a task into another row (implies `draggable`).                                                                                                                                                                                                           |\n| `resizable`             | `boolean`                                         | `false`         | Resize bars by dragging an edge (sides flip past each other).                                                                                                                                                                                                 |\n| `progressDraggable`     | `boolean`                                         | `false`         | Edit progress by dragging a handle on the bar.                                                                                                                                                                                                                |\n| `editable`              | `boolean`                                         | `false`         | Inline-edit the row name (sidebar) and task name (bar label) on double-click (or a long-press on touch). Enter/blur commits, Esc cancels; empty/unchanged is ignored. Surfaces `row-edit`/`task-edit` (and syncs `v-model:rows`).                              |\n| `tooltip`               | `boolean`                                         | `false`         | Show a hover tooltip on bars/milestones — a tap toggles it on touch (override its content via the `tooltip` slot).                                                                                                                                            |\n| `touchTargets`          | `boolean`                                         | `false`         | Enlarge interactive hit areas (resize/progress/connector handles, milestones, dependency handles) for touch. Coarse pointers get the larger targets automatically via `@media (pointer: coarse)`; this forces them on regardless (adds `data-touch` to the root). Sizes stay overridable via the `--gantt-*` tokens. |\n| `criticalPath`          | `boolean`                                         | `false`         | Highlight the tasks on the critical path (`data-critical` on their bars/markers; styled via `--gantt-critical-*`).                                                                                                                                            |\n| `slack`                 | `boolean`                                         | `false`         | Draw each task's free-float slack as a translucent bar after its end (the `<GanttSlack>` overlay; styled via `--gantt-slack-*`).                                                                                                                               |\n| `linkable`              | `boolean`                                         | `false`         | Create/edit dependencies by dragging between tasks.                                                                                                                                                                                                           |\n| `keyboard`              | `boolean`                                         | `false`         | Make task bars and milestones keyboard-operable via a roving tab stop: `role=\"button\"`, a descriptive `aria-label`, a visible focus ring, Enter/Space activation (fires the same `task-click`/`milestone-click` as a mouse click), arrow-key navigation (Left/Right/Up/Down/Home/End) between bars, and Shift/Alt+Left/Right keyboard move/resize (gated by `draggable`/`resizable`). Also makes the sidebar an accessible `tree`/`list` with its own roving row navigation. The chart root also gets a labelled landmark. See [Keyboard & accessibility](#keyboard--accessibility).       |\n| `ariaLabel`             | `string`                                          | `'Gantt chart'` | Accessible name for the chart landmark (used when `keyboard` is on).                                                                                                                                                                                          |\n| `cellCreatable`         | `boolean`                                         | `false`         | Create a task by dragging across an empty grid row (emits `create`). Below the drag threshold a plain click still falls through to `cell-click`. Lives in the default `<GanttGrid>` — a custom `grid` slot takes over creation yourself.                     |\n| `dependencyShape`       | `(tail, head) => string`                          | `elbowPath`     | Connector path builder. Pass `elbowPath`/`straightPath`/`bezierPath` or your own.                                                                                                                                                                             |\n| `arrowHead`             | `() => ArrowHeadShape \\| null`                    | `triangleArrow` | Arrowhead builder. Pass `triangleArrow`/`openArrow`/`noArrow` or your own (`null` = no head).                                                                                                                                                                 |\n| `snapToGrid`            | `boolean`                                         | `false`         | Snap dragged dates to the base unit (off = full precision).                                                                                                                                                                                                   |\n| `autoSchedule`          | `boolean`                                         | `false`         | On a move/resize or a dependency create/update, push finish-to-start successors forward so none starts before a predecessor ends (MS-Project style), preserving each task's duration. Effective only with `v-model:rows` (or prop-driven `rows`).             |\n| `dragLabelFormat`       | `string`                                          | `'d MMM HH:mm'` | date-fns format for the live drag tooltip.                                                                                                                                                                                                                    |\n| `dragLabel`             | `(info: GanttDragLabelInfo) => string`            | —               | Override the drag tooltip text (move/resize/progress).                                                                                                                                                                                                        |\n| `startDate` / `endDate` | `Date \\| string \\| number`                        | auto            | Explicit axis bounds (auto-derived from tasks otherwise).                                                                                                                                                                                                     |\n| `timelineMode`          | `'fixed' \\| 'infinite'`                           | `'fixed'`       | Edge behaviour. `infinite` auto-extends the range by one screen when you scroll to an edge (anchoring the scroll on the left). Both modes emit `range-change` at an edge — see [Timeline range](#timeline-range-infinite-scroll).                              |\n| `today`                 | `Date \\| string \\| number`                        | now             | The \"today\" reference.                                                                                                                                                                                                                                        |\n| `labelFormat`           | `GanttLabelFormat`                                | per tier        | Column label formatting. A date-fns `string` (base unit only — other tiers keep defaults), a per-tier map `Partial<Record<GanttUnit, string>>`, or a `(date, tier) => string` function (full control). E.g. `{ month: 'LLLL yyyy', week: \"'W'w\", day: 'd' }`. |\n| `locale`                | `Locale` (date-fns)                               | English         | date-fns locale for all date labels (headers, drag labels, tooltips). See [Localization](#localization-i18n).                                                                                                                                                  |\n| `weekStartsOn`          | `Day` (date-fns, `0`–`6`)                          | from `locale`, else `0` | First day of the week (`0`=Sunday … `6`=Saturday). Overrides the `locale`'s own week start. Affects week-tier column boundaries, the week `w` number label, and week snapping. See [Localization](#localization-i18n).                                        |\n\n### Item props (`GanttItemProps`, for `<GanttTask>` / `<GanttMilestone>`)\n\nDeclarative fields — the item registers into the enclosing `<GanttRow>`:\n\n| Prop           | Type                       | Description                                    |\n| -------------- | -------------------------- | ---------------------------------------------- |\n| `id`           | `string`                   | Stable id (used by dependencies).              |\n| `name`         | `string`                   | Bar/marker label (falls back to `id`).         |\n| `start`        | `Date \\| string \\| number` | Start date (`YYYY-MM-DD` is parsed local).     |\n| `end`          | `Date \\| string \\| number` | End date (ignored for milestones).             |\n| `progress`     | `number`                   | Completion 0–100.                              |\n| `dependencies` | `string[]`                 | Ids of predecessors (finish-to-start).         |\n| `variant`      | `string`                   | Free-form category → per-variant slot (above). |\n| `segments`     | `GanttSegment[]`           | Work spans with paused gaps (a \"split\" task).  |\n| `deadline`     | `Date \\| string \\| number` | Target date (drawn as a line; flags overdue).  |\n| `constraint`   | `GanttConstraint`          | Scheduling constraint (`{ type, date }`).      |\n| `baselineStart`| `Date \\| string \\| number` | Planned start (baseline). Needs `baselineEnd`. |\n| `baselineEnd`  | `Date \\| string \\| number` | Planned end (baseline). Needs `baselineStart`. |\n| `meta`         | `Record<string, unknown>`  | Arbitrary data forwarded to slots.             |\n| `rowId`        | `string`                   | Explicit row id (overrides the enclosing row). |\n\n> `<GanttTask :task>` / `<GanttMilestone :task>` also accept an already-resolved\n> task — this is how `<Gantt>` renders bars internally.\n\n#### Split tasks (`segments`)\n\nA task can carry `segments` — an array of `{ start, end }` work spans. When set,\nthe bar renders as those spans with **paused gaps** between them (a \"split\" task):\na thin connecting line bridges the gaps, and each span is drawn as its own segment\ninside the single bar. The task's own `start`/`end` still define the overall\nextent; the segments are drawn within it.\n\n```vue\n<GanttTask\n  id=\"build\"\n  name=\"Build\"\n  start=\"2026-06-01\"\n  end=\"2026-06-20\"\n  :progress=\"55\"\n  :segments=\"[\n    { start: '2026-06-01', end: '2026-06-06' },\n    { start: '2026-06-10', end: '2026-06-14' },\n    { start: '2026-06-17', end: '2026-06-20' },\n  ]\"\n/>\n```\n\nProp-driven, the same field lives on the task:\n\n```ts\n{ id: 'build', name: 'Build', start: '2026-06-01', end: '2026-06-20', progress: 55,\n  segments: [\n    { start: '2026-06-01', end: '2026-06-06' },\n    { start: '2026-06-10', end: '2026-06-14' },\n    { start: '2026-06-17', end: '2026-06-20' },\n  ] }\n```\n\nProgress on a split bar is **cumulative**: the task's overall `progress` is spread\nacross the segments' combined working duration, so the fill \"flows\" through the\nwork spans — earlier segments fill first (MS-Project style). Drag/resize still move\nthe whole task (its `start`/`end`); the segments are purely visual. The raw\n`GanttSegment` and coerced `ResolvedSegment` (`{ start: Date; end: Date }`) types\nare both exported. Style the split bits with the `--gantt-split-*`\n[variables](#css-variables).\n\n> While a drag is in progress (move/resize via `draggable`/`rowMovable`/`resizable`,\n> or linking via `linkable`), the viewport **auto-scrolls** on both axes when the\n> pointer nears an edge of the scroll container — so you can drop a bar or land a\n> dependency arrow on a target outside the current view. The preview (ghost / drop\n> target / draft arrow) keeps following the content, and scrolling stops on release.\n> This is automatic; there are no extra props.\n\n### Drag-to-create tasks\n\nWith `cellCreatable`, dragging across an empty grid row (left mouse button) draws\na translucent ghost preview with a live **start → end** label (formatted via\n`dragLabelFormat`/`locale`, same as a move/resize drag) and emits `create` on\nrelease — the chart stays controlled, so you add the task yourself (e.g. with the\n[`addTask`](#utilities) utility). Since an empty row has no bar to grab, `<GanttGrid>`\nalso renders a \"Drag to create\" hint across each empty leaf row's band as an\naffordance; customize or replace it via the `create-hint` slot (`{ row }`):\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { Gantt, addTask } from '@dizzy_yakov/vue-gantt'\n\nconst rows = ref(initialRows)\n\nfunction onCreate({ row, start, end }) {\n  rows.value = addTask(rows.value, row.id, { id: crypto.randomUUID(), name: 'New task', start, end })\n}\n</script>\n\n<template>\n  <Gantt :rows=\"rows\" cell-creatable @create=\"onCreate\" />\n</template>\n```\n\nBelow the drag threshold (same 3px mouse / 8px touch slop as `draggable`) the\npress is read as a plain click, so `cell-click` still fires as before. `snapToGrid`\nsnaps the drafted `start`/`end` like any other drag. Style the ghost via\n`--gantt-create-preview-bg` (falls back to `--gantt-bar-bg`) plus the shared\n`--gantt-bar-height` / `--gantt-bar-radius` / `--gantt-ghost-opacity` tokens; style\nthe hint via `--gantt-create-hint-color` / `--gantt-create-hint-border` /\n`--gantt-create-hint-opacity`.\n\n> `cell-click`/`cell-dblclick` and drag-to-create both live in the default\n> `<GanttGrid>`; overriding the `grid` slot on `<GanttView>` / `<Gantt>` replaces\n> it entirely, so creation (and cell clicks) become your responsibility.\n\n### Deadlines & constraints\n\nGive a task a `deadline` (a target date) or a scheduling `constraint` and the\nchart reflects both automatically:\n\n- **`deadline`** — `<GanttDeadlines>` (rendered by default; override via the\n  `deadlines` slot) draws a vertical line at the date across the task's band. When\n  the task's `end` passes the deadline the bar is flagged **overdue**\n  (`data-overdue`), tinted and outlined via the `--gantt-overdue-*` /\n  `--gantt-deadline-color` tokens.\n- **`constraint`** — a `{ type, date }` where `type` is a `GanttConstraintType`:\n  `'start-no-earlier-than'`, `'start-no-later-than'`, `'finish-no-earlier-than'`,\n  `'finish-no-later-than'`, `'must-start-on'` or `'must-finish-on'`. Lower-bound\n  types (`*-no-earlier-than`, `must-*-on`) are honored by [`autoSchedule`](#utilities),\n  which pushes the task's start so the bound is met (duration preserved). Upper\n  bounds can't be enforced by the forward-only scheduler, so a breach is surfaced\n  instead: the bar gets `data-constraint-violation` (dashed `--gantt-constraint-*`\n  outline).\n\n```ts\nconst rows = [\n  {\n    id: 'delivery',\n    name: 'Delivery',\n    tasks: [\n      {\n        id: 'build',\n        name: 'Build',\n        start: '2026-06-01',\n        end: '2026-06-20',\n        deadline: '2026-06-15', // end > deadline → overdue bar + line\n        constraint: { type: 'start-no-earlier-than', date: '2026-06-03' },\n      },\n    ],\n  },\n]\n```\n\nThe pure detectors [`isOverdue(task)`](#utilities) (`end > deadline`) and\n[`violatesConstraint(task)`](#utilities) (upper/exact bound breached) are exported\nso you can flag or filter tasks yourself; they take a `ResolvedTask` (or the\nmatching `end`/`deadline` / `start`/`end`/`constraint` subset).\n\n### Events\n\nAll drag events are **controlled**: the chart emits an intent, you apply it to\nyour data (the [utilities](#utilities) make this one-liners).\n\n| Event                          | Payload                                      | Fired when                                             |\n| ------------------------------ | -------------------------------------------- | ------------------------------------------------------ |\n| `move`                         | `GanttMoveEvent`                             | a bar is dragged (start/end, possibly a new row).      |\n| `resize`                       | `GanttResizeEvent`                           | a bar edge is dragged.                                 |\n| `progress`                     | `GanttProgressEvent`                         | the progress handle is dragged.                        |\n| `task-edit`                    | `GanttTaskEditEvent`                         | a bar label is inline-edited (`editable`).             |\n| `row-edit`                     | `GanttRowEditEvent`                          | a sidebar row name is inline-edited (`editable`).      |\n| `update:rows`                  | `GanttRowData[]`                             | a task/dependency change is applied (`v-model:rows`).  |\n| `update:zoom`                  | `string`                                     | the active zoom level changes (`v-model:zoom`).        |\n| `zoom-change`                  | `GanttZoomEvent`                             | the active zoom level changes (carries the level).     |\n| `range-change`                 | `GanttRangeChangeEvent`                      | a scroll reaches a timeline edge (both `timelineMode`s).  |\n| `group-toggle`                 | `GanttGroupToggleEvent`                      | a group is collapsed/expanded.                         |\n| `row-toggle`                   | `GanttRowToggleEvent`                        | a tree row's ([WBS](#row-tree-wbs)) subtree is collapsed/expanded. |\n| `dependency-create`            | `GanttDependencyChange`                      | a link is dragged from one task to another.            |\n| `dependency-update`            | `GanttDependencyUpdate`                      | an arrow endpoint is re-routed (carries `previous`).   |\n| `dependency-remove`            | `GanttDependencyChange`                      | an arrow is clicked (when `linkable`).                 |\n| `task-*` / `milestone-*`       | `GanttTaskEvent` `{ task, event }`           | `click` / `dblclick` / `contextmenu` on a bar/marker.  |\n| `row-*`                        | `GanttRowEvent` `{ row, event }`             | `click` / `dblclick` / `contextmenu` on a sidebar row. |\n| `cell-click` / `cell-dblclick` | `GanttCellEvent` `{ row, date, event }`      | an empty body cell is clicked.                         |\n| `create`                       | `GanttCreateEvent` `{ row, start, end, event }` | a new task is dragged out of an empty row (`cellCreatable`). |\n| `column-click`                 | `GanttColumnEvent` `{ column, tier, event }` | a timeline header cell is clicked.                     |\n| `dependency-click`             | `GanttDependencyEvent` `{ from, to, event }` | an arrow is clicked.                                   |\n\nPayload shapes (all exported as types):\n\n```ts\ninterface GanttMoveEvent {\n  id: string\n  start: Date\n  end: Date\n  fromRowId: string\n  toRowId: string\n  task: ResolvedTask\n}\ninterface GanttResizeEvent {\n  id: string\n  start: Date\n  end: Date\n  task: ResolvedTask\n}\ninterface GanttProgressEvent {\n  id: string\n  progress: number\n  task: ResolvedTask\n}\ninterface GanttTaskEditEvent {\n  id: string\n  patch: Partial<GanttTask> // changed fields to merge (e.g. `{ name }`)\n  task: ResolvedTask\n}\ninterface GanttRowEditEvent {\n  id: string\n  patch: Partial<GanttRow> // changed fields to merge (e.g. `{ name }`)\n  row: ResolvedRow\n}\ninterface GanttGroupToggleEvent {\n  id: string\n  collapsed: boolean\n}\ninterface GanttRowToggleEvent {\n  id: string\n  collapsed: boolean\n}\ninterface GanttDependencyChange {\n  from: string\n  to: string\n}\ninterface GanttDependencyUpdate extends GanttDependencyChange {\n  previous: GanttDependencyChange\n}\ninterface GanttDragLabelInfo {\n  mode: 'move' | 'resize' | 'progress'\n  task: ResolvedTask\n  start: Date\n  end: Date\n  progress: number\n}\ninterface GanttZoomLevel {\n  id: string // stable id; also the v-model:zoom value\n  label?: string // control label (defaults to id)\n  tiers: GanttUnit[] // timeline tiers, coarse → fine\n  columnWidth: number // base-unit cell width, px\n}\ninterface GanttZoomEvent {\n  id: string\n  level: GanttZoomLevel\n}\ninterface GanttRangeChangeEvent {\n  side: 'start' | 'end'\n  start: Date\n  end: Date\n}\n```\n\n### Two-way binding (`v-model:rows`)\n\n`v-model:rows` is a convenience layer over the controlled events on `<Gantt>` and\n`<GanttRoot>`. It pairs the existing `rows` prop with an `update:rows` emit: when\na drag change (`move` / `resize` / `progress`), an inline edit (`row-edit` /\n`task-edit` via `editable`) or a dependency edit (`dependency-create` /\n`dependency-remove` / `dependency-update`) happens, the component applies it to\nyour data with the same immutable [utilities](#utilities) (`applyMove` /\n`updateTask` / `updateRow` / `addDependency` / `removeDependency`) and emits\n`update:rows` with the new array — so the chart stays in sync without a manual\nhandler.\n\n```vue\n<Gantt v-model:rows=\"rows\" draggable resizable progress-draggable editable linkable />\n```\n\nThis works **only** in prop-driven mode (when `rows` is passed); in declarative\nmode (`<GanttRow>` without `rows`) there is nothing to update, so `update:rows`\nis not emitted. `group-toggle` is **not** part of the model — it is a view-state\nchange, not a task-data change.\n\nThe plain controlled events (`@move`, `@resize`, `@progress`, `@row-edit`,\n`@task-edit`, `@dependency-*`) are still emitted alongside `update:rows`. Choose\n**one** approach: use `v-model:rows` for automatic sync, or the manual events to\napply changes yourself (`updateRow` / `updateTask` for the inline edits) —\ncombining both double-applies each change.\n\n### Undo / redo (`useGanttHistory`)\n\n`useGanttHistory(rows)` adds undo/redo over the same `rows` ref you bind to\n`v-model:rows`. Every reassignment is recorded as a snapshot — each drag / resize /\nprogress / link edit goes through one `update:rows`, so one user action is one\nhistory entry. It returns `{ undo, redo, canUndo, canRedo, clear }`.\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { Gantt, useGanttHistory } from '@dizzy_yakov/vue-gantt'\n\nconst rows = ref(initialRows)\nconst { undo, redo, canUndo, canRedo } = useGanttHistory(rows)\n</script>\n\n<template>\n  <button :disabled=\"!canUndo\" @click=\"undo\">Undo</button>\n  <button :disabled=\"!canRedo\" @click=\"redo\">Redo</button>\n  <Gantt v-model:rows=\"rows\" draggable resizable progress-draggable linkable />\n</template>\n```\n\n- `undo()` / `redo()` restore a snapshot back into the ref without recording it; a\n  fresh edit after an undo drops the redo tail.\n- `canUndo` / `canRedo` are `ComputedRef<boolean>` — wire them to your buttons'\n  `:disabled`.\n- `clear()` drops all history, keeping the current value as the only entry.\n- `useGanttHistory(rows, { limit })` caps the stack size, dropping the oldest\n  snapshots (default: unlimited).\n\nSnapshots are cheap: the edit [utilities](#utilities) are immutable, so entries\nshare structure — no deep clone. The composable is pure and context-free (no\n`GanttRoot`, SSR-safe). Keyboard shortcuts are yours to wire — e.g. bind Ctrl+Z /\nCtrl+Shift+Z to `undo` / `redo`.\n\n### Auto-scheduling\n\nThe `autoSchedule` prop turns the chart into an MS-Project-style scheduler: when\nyou move or resize a task, or create / re-route a dependency, every finish-to-start\nsuccessor is pushed forward so none starts before its predecessor ends — each\ntask's duration is preserved. It cascades transitively (a → b → c), so dragging\n`a` later also shifts `b` and `c`.\n\n```vue\n<Gantt v-model:rows=\"rows\" auto-schedule draggable resizable linkable />\n```\n\nIt is built on top of the exported [`autoSchedule(rows, changedId?)`](#utilities)\nutility, applied to the emitted `update:rows`. So it is effective **only** in\nprop-driven / `v-model:rows` mode; in the purely event-driven flow (`@move` +\nyour own `applyMove`, no `v-model`) and in declarative mode (`<GanttRow>` children)\nthe prop is a no-op — call `autoSchedule` yourself where you apply the change.\n`dependency-remove` and progress edits do **not** trigger the cascade. The live\ndrag preview (ghost) does not show the cascade; successors snap into place on\nrelease.\n\n<h3 id=\"inline-editing\">Inline editing</h3>\n\nThe `editable` prop turns on inline renaming: **double-click** a row name in the\nsidebar or a bar's label in the body to open an inline `<input>`. **Enter** or\n**blur** commits, **Esc** cancels; an empty or unchanged value is ignored. Like\nevery other interaction the edit is **controlled** — the chart emits an intent and\nyou apply it:\n\n- `row-edit` → `GanttRowEditEvent { id, patch: Partial<GanttRow>, row }`\n- `task-edit` → `GanttTaskEditEvent { id, patch: Partial<GanttTask>, task }`\n\nWith `v-model:rows` the patch is applied for you (via `updateRow` / `updateTask`)\nand re-emitted through `update:rows`; without it, listen and apply the patch\nyourself.\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { Gantt, updateRow, updateTask } from '@dizzy_yakov/vue-gantt'\n\nconst rows = ref(initialRows)\n</script>\n\n<template>\n  <!-- automatic sync -->\n  <Gantt v-model:rows=\"rows\" editable />\n\n  <!-- or apply the patches yourself -->\n  <Gantt\n    :rows=\"rows\"\n    editable\n    @row-edit=\"e => (rows = updateRow(rows, e.id, e.patch))\"\n    @task-edit=\"e => (rows = updateTask(rows, e.id, e.patch))\"\n  />\n</template>\n```\n\nReplace the built-in input with your own editor via the `rowEditor`\n(`{ row, value, commit, cancel }`) / `taskEditor` (`{ task, value, commit, cancel }`)\nslots — render your control, then call `commit(newValue)` to save or `cancel()` to\ndiscard:\n\n```vue\n<Gantt v-model:rows=\"rows\" editable>\n  <template #rowEditor=\"{ value, commit, cancel }\">\n    <input :value=\"value\" @keydown.enter=\"commit($event.target.value)\" @keydown.esc=\"cancel\" />\n  </template>\n</Gantt>\n```\n\nStyle the default input with the `--gantt-edit-*` [variables](#css-variables)\n(class `.gantt-edit-input`).\n\n### Imperative methods\n\n`<Gantt>` / `<GanttRoot>` expose scroll and zoom helpers via a template ref:\n\n```ts\nconst chart = useTemplateRef('chart')\nchart.value?.scrollToToday()\nchart.value?.scrollToTask('spec', { align: 'center' })\nchart.value?.scrollToDate('2026-06-10')\n\nchart.value?.setZoom('week') // activate a level by id\nchart.value?.zoomIn() // step to the next finer level\nchart.value?.zoomOut() // step to the next coarser level\n```\n\n`<GanttRoot>` additionally exposes `activeZoom` (the active level id, or\n`undefined`).\n\n### Utilities\n\nPure, tree-shakeable helpers over your `rows`/`tasks` — apply controlled events,\nedit data, query dependencies, validate:\n\n```ts\nimport {\n  applyMove,\n  updateTask,\n  updateRow, // patch a task / row by id (immutable; use with row-edit / task-edit)\n  addTask,\n  removeTask, // edits (immutable)\n  addDependency,\n  removeDependency, // dependency edits\n  flattenTasks,\n  findTask,\n  findRow,\n  tasksExtent, // lookups\n  sortRows,\n  filterRows, // reorder / filter rows (immutable; pass the result back as `rows`)\n  getDependents,\n  detectCycles,\n  topologicalOrder,\n  criticalPath,\n  slack, // longest finish-to-start chain · free-float days per task\n  autoSchedule, // honors lower-bound constraints when shifting starts\n  isOverdue,\n  violatesConstraint, // deadline / constraint detectors\n  rollupProgress,\n  validateRows,\n  sprintPeriods, // build a run of equal-length timeline periods (sprints; see SprintPeriodsOptions)\n  nonWorkingBands, // compute non-working (weekend/holiday/off-period) bands over a range\n  resourceWorkload, // sweep-line concurrent-load histogram per resource (see Resource workload; types: WorkloadSegment, ResourceWorkload, WorkloadOptions)\n  toCSV,\n  downloadCSV, // serialize tasks to CSV / trigger a browser download (see Export)\n  toExcel,\n  downloadExcel, // serialize tasks to a SpreadsheetML (.xls) workbook / trigger a download (see Export)\n} from '@dizzy_yakov/vue-gantt'\n```\n\n`criticalPath(rows)` returns the ids on the longest finish-to-start chain (by total\nduration), and `slack(rows)` returns a `Map<string, number>` of each task's\n**free float** in days — how far its finish can slip before it hits the start of its\nnearest successor (tasks with no successors, or no positive gap, are absent). These\nback the matching `criticalPath` / `slack` props: the prop visualizes what the\nutility computes, so you can also call the utility directly (e.g. to label or report\nthe schedule).\n\n### Export (CSV / Excel)\n\n`toCSV(rows, options?)` serializes the tasks of your `rows` to an RFC-4180 CSV\nstring — one line per task, with its owning row's id/name as leading columns. It's\npure and framework-free (accepts raw `GanttRow[]` or the resolved rows from the\ncontext). `downloadCSV(rows, filename?, options?)` wraps it and triggers a browser\ndownload (`filename` defaults to `'gantt.csv'`).\n\n```ts\nimport { toCSV, downloadCSV } from '@dizzy_yakov/vue-gantt'\n\ndownloadCSV(rows, 'schedule.csv')\n\n// Custom columns / delimiter / date format:\nconst csv = toCSV(rows, {\n  delimiter: ';',\n  dateFormat: 'dd.MM.yyyy',\n  columns: [\n    { header: 'ID', value: (task) => task.id },\n    { header: 'Owner', value: (task) => String(task.meta?.owner ?? '') },\n    { header: 'Start', value: (task) => (task.start instanceof Date ? task.start.toISOString() : task.start) },\n  ],\n})\n```\n\nDefault columns: `Row Id`, `Row`, `Task Id`, `Task`, `Type`, `Start`, `End`,\n`Progress`, `Dependencies`, `Deadline`. Options: `columns`, `delimiter` (`,`),\n`dateFormat` (`yyyy-MM-dd`), `locale`, `header` (`true`), `eol` (`\\r\\n`).\n\n`toExcel(rows, options?)` serializes the same tasks to a **SpreadsheetML 2003**\nworkbook string — the `.xls` XML dialect Excel opens directly. It's pure,\nframework-free and **zero-dependency** (no `xlsx`/`exceljs`), and cells are\ntyped: dates are real Excel dates (`ss:Type=\"DateTime\"`) and progress is a\n`ss:Type=\"Number\"` cell, so Excel sorts/filters them correctly instead of\ntreating everything as text. `downloadExcel(rows, filename?, options?)` wraps\nit and triggers a browser download (`filename` defaults to `'gantt.xls'`, MIME\n`application/vnd.ms-excel`).\n\n```ts\nimport { toExcel, downloadExcel } from '@dizzy_yakov/vue-gantt'\n\ndownloadExcel(rows, 'schedule.xls')\n```\n\n```vue\n<button @click=\"downloadExcel(rows, 'schedule.xls')\">Export to Excel</button>\n```\n\n```ts\n// Custom columns / sheet name — a Number/DateTime `type` drives the cell's\n// SpreadsheetML data type (defaults to 'String'):\nconst xls = toExcel(rows, {\n  sheetName: 'Schedule',\n  columns: [\n    { header: 'ID', value: (task) => task.id },\n    { header: 'Start', type: 'DateTime', value: (task) => task.start },\n    { header: 'Progress %', type: 'Number', value: (task) => task.progress ?? 0 },\n  ],\n})\n```\n\nDefault columns: same as CSV — `Row Id`, `Row`, `Task Id`, `Task`, `Type`,\n`Start` (`DateTime`), `End` (`DateTime`), `Progress` (`Number`),\n`Dependencies`, `Deadline` (`DateTime`). Options: `columns`, `sheetName`\n(`'Tasks'`), `header` (`true`).\n\n## Row grouping\n\nRows that reference the same `groupId` render under a collapsible header band\nwith a rolled-up summary bar. Provide group labels via the `groups` prop (or the\ndeclarative `<GanttGroup>`). The `summaryStyle` root prop controls how that\nrollup renders — see [Row tree (WBS)](#row-tree-wbs) for details (it applies to\nboth groups and tree parents).\n\n![Row grouping](https://raw.githubusercontent.com/LavaYasha/vue-gantt/main/docs/grouping.png)\n\n## Row tree (WBS)\n\nSet `GanttRow.parentId` to nest a row under another, building a collapsible tree\nof arbitrary depth (a work-breakdown structure). Rows must be given in\n**pre-order** — a parent immediately before its subtree, same as `groupId`\nmembers must be contiguous — and a dataset mixes one or the other, never both\n(`parentId` and `groupId` are mutually exclusive across the same rows). A\nparent row keeps its own tasks (if any) **and** shows a rolled-up **summary\nbar** spanning the earliest start to the latest end across its whole subtree,\nwith duration-weighted aggregate progress. The sidebar indents each row by\n`depth * --gantt-row-indent` and gives rows with children a chevron toggle.\n\nCollapse is **uncontrolled**: `GanttRow.collapsed` seeds the initial state,\nclicking the chevron (or calling `ctx.toggleRow(id)`) flips it, and\n`row-toggle` fires with the new state. Collapsing a parent recursively hides\nits descendants (excluded from layout/render, no vertical space) while its\nsummary bar keeps covering the full (still collapsed) subtree extent.\n\n```vue\n<Gantt :rows=\"rows\" />\n```\n\n```ts\nconst rows: GanttRowData[] = [\n  { id: 'project', name: 'Project' },\n  {\n    id: 'phase-design',\n    name: 'Design',\n    parentId: 'project',\n    tasks: [{ id: 'design', start: '2026-06-01', end: '2026-06-10', progress: 80 }],\n  },\n  {\n    id: 'phase-build',\n    name: 'Build',\n    parentId: 'project',\n    collapsed: true, // starts folded; its summary bar still shows the rolled-up span\n    tasks: [{ id: 'build', start: '2026-06-10', end: '2026-06-24', progress: 20 }],\n  },\n]\n```\n\nDeclaratively, nest `<GanttRow>`s — the inner row inherits `parentId` from the\nenclosing one (like `<GanttTask>` inherits its row):\n\n```vue\n<GanttRoot>\n  <GanttTaskList />\n  <GanttRow id=\"project\" name=\"Project\">\n    <GanttRow id=\"phase-design\" name=\"Design\">\n      <GanttTask id=\"design\" start=\"2026-06-01\" end=\"2026-06-10\" :progress=\"80\" />\n    </GanttRow>\n    <GanttRow id=\"phase-build\" name=\"Build\">\n      <GanttTask id=\"build\" start=\"2026-06-10\" end=\"2026-06-24\" :progress=\"20\" />\n    </GanttRow>\n  </GanttRow>\n  <GanttSummaryBar />\n</GanttRoot>\n```\n\nThe rollup bar is rendered by `<GanttSummaryBar>` (auto-mounted by\n`<GanttView>` / `<Gantt>`; override it via the `summary-bars` section slot, or\njust its rollup content via the `summaryBar` leaf slot,\n`{ row, collapsed, left, width }`). Customize the sidebar row itself —\nchevron, indent, name — via the `row` slot\n(`{ row, index, depth, collapsed, hasChildren, toggle }`). Style with the\n`--gantt-row-indent` / `--gantt-summary-bar-*` / `--gantt-summary-bracket-*`\n[variables](#css-variables).\n\nThe `summaryStyle` root prop (`'bracket'` default, or `'bar'` for the legacy\nlook) controls how both this summary bar and `<GanttGroupBar>`'s group rollup\nrender: `bracket` draws an **expanded** parent/group as a thin span line with\ndownward end caps toward its children (no progress fill — the children carry\nthe detail), and a **collapsed** one as a filled accent bar with progress,\nsame as `bar` always renders in both states.\n\n## Row decoration\n\nTwo lightweight, additive hooks let you mark up a sidebar row without\noverriding its whole render:\n\n- **`row-suffix` slot** — rendered *after* the row name (`{ row, index, depth,\n  collapsed, hasChildren }`, same scope as `row` minus `toggle`). Use it to\n  append a badge/marker while keeping the default name rendering (and the\n  `row` slot, if you also use one) untouched:\n\n  ```vue\n  <Gantt :rows=\"rows\">\n    <template #row-suffix=\"{ row }\">\n      <span v-if=\"row.meta.ppr\" class=\"badge\">PPR</span>\n    </template>\n  </Gantt>\n  ```\n\n- **`meta` → `data-*` passthrough** — primitive (`string`/`number`/`boolean`)\n  entries of a row's `meta` are forwarded as `data-<key>` attributes on its\n  `.gantt-task-list__row` element, so you can highlight/mark the row with\n  plain CSS, no slot needed:\n\n  ```ts\n  const rows: GanttRowData[] = [{ id: 'task', name: 'Task', meta: { ppr: true } }]\n  ```\n\n  ```css\n  .gantt-task-list__row[data-ppr] {\n    background: var(--gantt-critical-color, #ef4444);\n  }\n  ```\n\n  Only primitive values are forwarded (objects/arrays are skipped), and the\n  reserved `data-id` / `data-group` / `data-depth` / `data-has-children` /\n  `data-collapsed` attributes are never overwritten by `meta`.\n\n## Baselines (planned vs actual)\n\nGive a task both `baselineStart` and `baselineEnd` to draw its **baseline** — the\nplanned interval — as a thin \"shadow\" bar at the bottom of the task's row band,\nunder the actual (`start`/`end`) bar. It makes slippage visible at a glance: a\ntask running late has its actual bar sitting to the right of / longer than its\nbaseline. Both fields are required for the shadow to draw; a baseline is always an\ninterval (never collapsed like a milestone's end).\n\n```vue\n<Gantt :rows=\"rows\" />\n```\n\n```ts\nconst rows = [\n  {\n    id: 'dev',\n    name: 'Development',\n    tasks: [\n      {\n        id: 'build',\n        name: 'Implementation',\n        start: '2026-06-18',\n        end: '2026-06-30', // actual — running late\n        baselineStart: '2026-06-16',\n        baselineEnd: '2026-06-26', // planned\n        progress: 40,\n      },\n    ],\n  },\n]\n```\n\nDeclaratively it's `<GanttTask baseline-start=\"…\" baseline-end=\"…\" />`. The layer\nis rendered by `<GanttBaselines>` (auto-mounted by `<GanttView>` / `<Gantt>`;\noverride it via the `baselines` section slot). `<GanttBaselines>` exposes a\ndefault slot `{ task }` to render each baseline segment yourself. Style the shadow\nbars with the `--gantt-baseline-*` [variables](#css-variables).\n\n## Timeline period bands (sprints)\n\nCustom **periods** group the *time axis* (unlike [row groups](#row-grouping), which\ngroup rows). Each period renders a faint full-height **band** over the chart body\nplus a **labelled row** in the timeline header — ideal for sprints, phases or\nrelease windows. Pass a `periods` list (uneven spans + custom labels are fine); the\n`periods` also extend the auto date range so a period before the first task stays\nvisible.\n\n```vue\n<script setup>\nimport { Gantt, sprintPeriods } from '@dizzy_yakov/vue-gantt'\n\n// A regular cadence…\nconst periods = sprintPeriods({ from: '2026-06-01', every: 2, unit: 'week', count: 6 })\n// …or your own: [{ id: 's1', start: '2026-06-01', end: '2026-06-15', label: 'Sprint 1' }, …]\n</script>\n\n<template>\n  <Gantt :rows=\"rows\" :periods=\"periods\" :tiers=\"['month', 'week', 'day']\" />\n</template>\n```\n\n`sprintPeriods({ from, every, unit: 'day' | 'week', count, label?, id? })` builds a\ncontiguous run of equal-length periods. The bands are rendered by `<GanttPeriods>`\n(auto-mounted; override via the `period-bands` section slot for the body band, or\nthe `period` slot for the header label). Style with the `--gantt-period-*`\n[variables](#css-variables).\n\n## Resources\n\nAssign a task to one or more **resources** (people/equipment) via its\n`resourceIds` (an array of ids), and pass the flat lookup table to the\n`resources` prop. The library resolves each task's assigned resources and\nsurfaces them into its bar/milestone slots as `resources`\n(`ResolvedResource[]`) — rendering (a badge, an avatar, initials) is entirely up\nto you; resources don't add their own swimlane.\n\n```vue\n<script setup>\nimport { Gantt } from '@dizzy_yakov/vue-gantt'\n\nconst resources = [\n  { id: 'alice', name: 'Alice', color: '#6366f1' },\n  { id: 'bob', name: 'Bob', color: '#f59e0b' },\n]\n\nconst rows = [\n  {\n    id: 'dev',\n    name: 'Development',\n    tasks: [\n      { id: 'build', name: 'Build', start: '2026-06-01', end: '2026-06-10', resourceIds: ['alice', 'bob'] },\n    ],\n  },\n]\n</script>\n\n<template>\n  <Gantt :rows=\"rows\" :resources=\"resources\">\n    <template #bar=\"{ task, progress, resources }\">\n      {{ task.name }}\n      <span v-for=\"r in resources\" :key=\"r.id\" class=\"resource-badge\" :style=\"{ background: r.color }\">\n        {{ r.name }}\n      </span>\n    </template>\n  </Gantt>\n</template>\n```\n\nA `GanttResource` is `{ id, name?, color?, meta? }` (`name` falls back to `id`);\nthe resolved `ResolvedResource` always has `name`/`meta` filled in. `resourceIds`\nisn't (yet) an individual `GanttItemProps` field, so declarative composition\nassigns it via the presentational `<GanttTask :task>` / `<GanttMilestone :task>`\nmode rather than a dedicated prop. In the shared context, `ctx.resources` holds\nevery resolved resource and `ctx.resourcesFor(task)` resolves one task's\nassignees (unknown ids dropped).\n\n## Resource workload\n\n`<GanttWorkload>` is a standalone, headless **load histogram** you mount BELOW\nthe chart body — one row per resource showing how many of its assigned tasks run\nconcurrently over time. It reads the shared context, so it must be a descendant\nof `GanttRoot`, but it is **not** part of `GanttView`'s layout (no dedicated slot\nthere): place it as a sibling underneath, inside the same `GanttRoot`.\n\n```vue\n<script setup>\nimport { GanttRoot, GanttView, GanttWorkload } from '@dizzy_yakov/vue-gantt'\n\nconst resources = [\n  { id: 'alice', name: 'Alice', color: '#6366f1' },\n  { id: 'bob', name: 'Bob', color: '#f59e0b' },\n]\n\nconst rows = [\n  {\n    id: 'dev',\n    name: 'Development',\n    tasks: [\n      { id: 'spec', name: 'Spec', start: '2026-06-01', end: '2026-06-12', resourceIds: ['alice'] },\n      { id: 'build', name: 'Build', start: '2026-06-08', end: '2026-06-20', resourceIds: ['alice', 'bob'] },\n    ],\n  },\n]\n</script>\n\n<template>\n  <GanttRoot :rows=\"rows\" :resources=\"resources\">\n    <GanttView height=\"240\" />\n    <GanttWorkload />\n  </GanttRoot>\n</template>\n```\n\nResources come from the `resources` prop + each task's `resourceIds` — same data\nas [Resources](#resources). Its label gutter is the same width as\n`--gantt-sidebar-width` and its track mirrors the chart body's horizontal scroll\nvia `viewport.scrollLeft` (a `transform: translateX`), so bars stay aligned with\nthe timeline above as you scroll — the sync is one-directional (the strip\nfollows the chart, not the other way around); mount its container at the same\nwidth as the chart above it.\n\nRendering is driven by the exported sweep-line helper `resourceWorkload(tasks,\noptions?)` (in `src/layout.ts`): for each resource it returns a `{ resourceId,\nsegments, peak }` where `segments` are the piecewise `{ start, end, count }`\nintervals where 1+ of its tasks overlap (milestones ignored) and `peak` is the\nhighest concurrent count — used to scale ","readmeFilename":"README.md"}