@dou-ui/gantt 0.1.0-alpha.0 → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @layer dou.components{.dou-gantt{--dou-gantt-header-bg:var(--dou-color-bg-canvas);--dou-gantt-line:var(--dou-color-border-subtle);--dou-gantt-line-strong:var(--dou-color-border);--dou-gantt-off:color-mix(in oklab,var(--dou-color-text)5%,transparent);--dou-gantt-hover:color-mix(in oklab,var(--dou-color-text)3%,transparent);--dou-gantt-selected:color-mix(in oklab,var(--dou-color-primary)7%,transparent);--dou-gantt-link:color-mix(in oklab,var(--dou-color-text)32%,transparent);--dou-gantt-today:var(--dou-color-primary);--dou-gantt-bar-height:20px;position:relative;display:flex;box-sizing:border-box;overflow:hidden;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-container);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font-family:var(--dou-font-family);font-size:var(--dou-font-size-md);line-height:var(--dou-font-line-height);outline:none;width:100%;min-width:0;height:480px}.dou-gantt:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt.is-dragging{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging *{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging-move{cursor:grabbing}.dou-gantt.is-dragging-move *{cursor:grabbing}.dou-gantt.is-dragging-start *{cursor:ew-resize}.dou-gantt.is-dragging-end *{cursor:ew-resize}.dou-gantt.is-dragging-progress *{cursor:ew-resize}.dou-gantt.is-dragging-draw *{cursor:ew-resize}.dou-gantt.is-dragging-link *{cursor:crosshair}.dou-gantt.is-dragging-row *{cursor:grabbing}.dou-gantt__table-pane{display:flex;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;flex:none;min-width:0}.dou-gantt__table{display:flex;flex-direction:column;flex:1 0 auto}.dou-gantt__table-head{display:flex;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);flex:none;height:56px}.dou-gantt__th,.dou-gantt__td{display:flex;box-sizing:border-box;white-space:nowrap;align-items: center;min-width:0;padding:0 12px}:is(.dou-gantt__th,.dou-gantt__td).is-center{justify-content:center}:is(.dou-gantt__th,.dou-gantt__td).is-end{justify-content:flex-end}.dou-gantt__th.is-title{min-width:120px}.dou-gantt__table-body{position:relative;overflow-x:hidden;overflow-y:auto;scrollbar-width:none;flex:1;min-height:0}.dou-gantt__table-body::-webkit-scrollbar{display:none}.dou-gantt__table-rows{position:relative}.dou-gantt__tr{position:absolute;display:flex;height:var(--dou-gantt-row-height);box-shadow:inset 0 -1px 0 var(--dou-gantt-line);cursor:default;top:0;left:0;right:0}.dou-gantt__tr.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__tr.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__tr.is-summary .dou-gantt__td.is-title{font-weight:var(--dou-font-weight-medium)}.dou-gantt__td{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-gantt__td.is-title{color:var(--dou-color-text);font-size:var(--dou-font-size-md);min-width:120px;padding-left:6px}.dou-gantt__cell-text{overflow-x:clip;text-overflow:ellipsis;min-width:0}.dou-gantt__indent{flex:none}.dou-gantt__toggle,.dou-gantt__toggle-space{display:inline-flex;flex:none;justify-content:center;align-items: center;width:20px;height:20px;margin-right:4px}.dou-gantt__toggle{color:var(--dou-color-text-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:0;font-size:14px}.dou-gantt__toggle:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__tr.is-moving{opacity:.45}.dou-gantt__tr.is-drop-inside{background-color:var(--dou-gantt-selected);box-shadow:inset 0 0 0 1px var(--dou-color-primary),inset 0 -1px 0 var(--dou-gantt-line)}.dou-gantt__drop-line{position:absolute;z-index:2;background-color:var(--dou-color-primary);pointer-events:none;border-radius:1px;height:2px;top:-1px;right:8px}.dou-gantt__add-row{position:absolute;display:flex;height:var(--dou-gantt-row-height);top:0;left:0;right:0}.dou-gantt__add-row>.dou-gantt__td{flex:1}.dou-gantt__add{display:inline-flex;text-align:start;border-radius:var(--dou-radius-control);color:var(--dou-color-text-tertiary);font:inherit;font-size:var(--dou-font-size-sm);cursor:pointer;background:0 0;border:0;flex:1;align-items: center;gap:6px;height:24px;margin-left:-6px;padding:0 6px}.dou-gantt__add>svg{font-size:14px}.dou-gantt__add:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__add:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:1px}.dou-gantt__editor{display:flex;flex:1;align-items: center;min-width:0}.dou-gantt__editor>*{flex:1;min-width:0}.dou-gantt__editor.is-date{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{width:208px}.dou-gantt__td{position:relative}.is-editable .dou-gantt__tr{user-select:none;-webkit-user-select:none}.dou-gantt__editor-input{box-sizing:border-box;border:1px solid var(--dou-color-border-strong,var(--dou-color-border));border-radius:var(--dou-radius-control);outline:none;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:max(var(--dou-font-size-input-min,0px),1em);width:100%;height:26px;margin-left:-7px;padding:0 6px}.dou-gantt__editor-input:focus{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)30%,transparent)}.dou-gantt__editor-input::placeholder{color:var(--dou-color-text-tertiary)}.dou-gantt__editor-input[aria-invalid=true]{border-color:var(--dou-color-danger);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-danger)24%,transparent)}.dou-gantt__menu-anchor{position:absolute;overflow:hidden;width:0;height:0}.dou-gantt__divider{position:relative;z-index:3;background-color:var(--dou-gantt-line-strong);outline:none;touch-action:none;cursor:col-resize;transition:background-color var(--dou-motion-duration-fast)var(--dou-motion-easing);flex:none;order:1;width:1px}.dou-gantt__divider:before{position:absolute;content:"";inset:0 -4px}.dou-gantt__divider:hover{background-color:var(--dou-color-focus)}.dou-gantt__divider:focus-visible{background-color:var(--dou-color-focus)}.dou-gantt__chart{position:relative;overflow:auto;outline:none;overscroll-behavior-x:none;flex:1;order:2;min-width:0}.dou-gantt__chart.is-fixed{overscroll-behavior-x:contain}.dou-gantt__canvas{position:relative;min-height:100%}.dou-gantt__header{position:sticky;z-index:4;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;height:56px;top:0}.dou-gantt__tier{position:relative;overflow:clip;height:28px}.dou-gantt__tier.is-top{box-shadow:inset 0 -1px 0 var(--dou-gantt-line);color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__tier.is-bottom{height:27px}.dou-gantt__cell{position:absolute;display:flex;box-sizing:border-box;box-shadow:inset 1px 0 0 var(--dou-gantt-line);align-items: center;top:0;bottom:0}.is-bottom>.dou-gantt__cell{justify-content:center}.dou-gantt__cell-label{position:sticky;overflow-x:clip;text-overflow:ellipsis;text-box:trim-both cap alphabetic;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__cell.is-off{color:var(--dou-color-text-tertiary)}.dou-gantt__cell.is-now{color:var(--dou-gantt-today);font-weight:var(--dou-font-weight-medium)}.dou-gantt__today-mark{position:absolute;background-color:var(--dou-gantt-today);clip-path:polygon(50% 0,100% 100%,0 100%);width:8px;height:4px;margin-left:-3.5px;bottom:-1px}.dou-gantt__body{position:relative;background-image:linear-gradient(to top,var(--dou-gantt-line)1px,transparent 1px);background-size:100% var(--dou-gantt-row-height)}.dou-gantt__row-titles{position:sticky;z-index:3;overflow:visible;width:0;height:0;left:0}.dou-gantt__row-title{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;padding:0 12px;top:0;left:0}.dou-gantt__row-title.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__off,.dou-gantt__gridline,.dou-gantt__today{position:absolute;pointer-events:none;top:0;bottom:0}.dou-gantt__off{background-color:var(--dou-gantt-off)}.dou-gantt__gridline{background-color:var(--dou-gantt-line);width:1px}.dou-gantt__today{z-index:1;background-color:var(--dou-gantt-today);width:1px}.dou-gantt__row-highlight{position:absolute;height:var(--dou-gantt-row-height);background-color:var(--dou-gantt-hover);pointer-events:none;top:0;left:0;right:0}.dou-gantt__row-highlight.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__links{position:absolute;z-index:1;overflow:visible;pointer-events:none;top:0;left:0}.dou-gantt__link{color:var(--dou-gantt-link)}.dou-gantt__link:hover{color:var(--dou-color-primary)}.dou-gantt__link.is-related{color:var(--dou-color-primary)}.dou-gantt__link-hit{fill:none;stroke:transparent;stroke-width:10px;pointer-events:stroke}.dou-gantt__link-line{fill:none;stroke:currentColor;stroke-width:1px}.dou-gantt__link-arrow{fill:currentColor}.dou-gantt__link.is-selected{color:var(--dou-color-primary)}.dou-gantt__link.is-selected .dou-gantt__link-line{stroke-width:2px}.dou-gantt__link.is-critical{color:color-mix(in oklab,var(--dou-color-danger)72%,var(--dou-color-bg-surface))}.dou-gantt__link.is-broken{color:var(--dou-color-warning)}.dou-gantt__link.is-broken .dou-gantt__link-line{stroke-dasharray:4 3}.dou-gantt__link-draft{fill:none;stroke:var(--dou-color-primary);stroke-dasharray:4 3;stroke-width:1.5px}.dou-gantt__link-draft.is-refused{stroke:var(--dou-color-danger)}.dou-gantt__bar-row{position:absolute;z-index:2;height:var(--dou-gantt-row-height);top:0;left:0}.dou-gantt__bar{--dou-gantt-tone:var(--dou-color-text);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);display:flex;box-sizing:border-box;height:var(--dou-gantt-bar-height);overflow:clip;border:1px solid color-mix(in oklab,var(--dou-gantt-tone)18%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)5%,var(--dou-color-bg-surface));box-shadow:var(--dou-shadow-sm);cursor:default;border-radius:6px;align-items: center}.dou-gantt__bar:hover{border-color:color-mix(in oklab,var(--dou-gantt-tone)34%,var(--dou-color-bg-surface))}.is-editable .dou-gantt__bar:not(.is-locked){cursor:grab}.dou-gantt__bar.is-link-target{border-color:var(--dou-color-primary);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-primary)22%,transparent)}.dou-gantt__bar.is-link-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-move-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-selected{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)35%,transparent)}.dou-gantt__bar.is-primary{--dou-gantt-tone:var(--dou-color-primary)}.dou-gantt__bar.is-success{--dou-gantt-tone:var(--dou-color-success)}.dou-gantt__bar.is-warning{--dou-gantt-tone:var(--dou-color-warning)}.dou-gantt__bar.is-danger{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical:not(:-webkit-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:-moz-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:is(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt.has-baseline :-webkit-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :-moz-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :is(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt__baseline{--dou-gantt-baseline:color-mix(in oklab,var(--dou-color-text)24%,var(--dou-color-bg-surface));position:absolute;top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 2px);z-index:1;background-color:var(--dou-gantt-baseline);pointer-events:none;border-radius:2px;height:4px;left:0}.dou-gantt__baseline.is-milestone{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 4px);border-radius:1px;width:8px;height:8px;margin-left:-4px}.dou-gantt__ghost{position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);z-index:2;box-sizing:border-box;height:var(--dou-gantt-bar-height);border:1px dashed color-mix(in oklab,var(--dou-color-text)40%,transparent);pointer-events:none;border-radius:6px;left:0}.dou-gantt__ghost.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-radius:2px;width:10px;height:10px;margin-left:-5px}.dou-gantt__peer{--dou-gantt-peer-color:var(--dou-color-text-secondary);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2 - 2px);z-index:2;box-sizing:content-box;height:var(--dou-gantt-bar-height);border:1px solid var(--dou-gantt-peer-color);pointer-events:none;border-radius:8px;padding:1px;left:-2px}.dou-gantt__peer.is-moving{background-color:color-mix(in oklab,var(--dou-gantt-peer-color)8%,transparent);border-style:dashed}.dou-gantt__peer.is-milestone{top:calc((var(--dou-gantt-row-height) - 14px)/2 - 2px);border-radius:3px;width:14px;height:14px;margin-left:-9px}.dou-gantt__peer.is-milestone>.dou-gantt__peer-name{transform-origin:0 0;top:100%;left:0;right:auto;transform:rotate(-45deg)translate(calc(-100% - 4px),-50%);translate:none}.dou-gantt__peer.is-milestone.is-moving>.dou-gantt__peer-name{top:0;left:100%;transform:rotate(-45deg)translate(4px,-50%)}.dou-gantt__peer.is-moving>.dou-gantt__peer-name{left:calc(100% + 4px);right:auto}.dou-gantt__peer-name{position:absolute;background-color:var(--dou-gantt-peer-color);color:oklch(from var(--dou-gantt-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;padding:0 6px;line-height:18px;top:50%;right:calc(100% + 4px);translate:0 -50%}.dou-gantt__progress{position:absolute;background-color:color-mix(in oklab,var(--dou-gantt-tone)12%,var(--dou-color-bg-surface));top:0;bottom:0;left:0}.dou-gantt__bar-label{position:sticky;overflow-x:clip;font-size:var(--dou-font-size-sm);text-overflow:ellipsis;white-space:nowrap;text-box:trim-both cap alphabetic;min-width:0;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__bar.is-summary{top:calc((var(--dou-gantt-row-height) - 8px)/2 - 2px);overflow:visible;background-color:color-mix(in oklab,var(--dou-gantt-tone)40%,var(--dou-color-bg-surface));box-shadow:none;border:0;border-radius:2px 2px 0 0;height:6px}.dou-gantt__bar.is-summary:before{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:after{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:before{clip-path:polygon(0 0,100% 0,0 100%);left:0}.dou-gantt__bar.is-summary:after{clip-path:polygon(0 0,100% 0,100% 100%);right:0}.dou-gantt__bar.is-summary.is-selected{background-color:var(--dou-color-primary);box-shadow:none}.dou-gantt__bar.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-color:color-mix(in oklab,var(--dou-gantt-tone)70%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)62%,var(--dou-color-bg-surface));border-radius:2px;width:10px;height:10px;margin-left:-5px;transform:rotate(45deg)}.dou-gantt__bar.is-milestone.is-selected{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}.dou-gantt__bar-side{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;top:0}.dou-gantt__bar-side.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.is-editable .dou-gantt__bar-row:-webkit-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:-moz-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:is(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot{position:absolute;z-index:1;opacity:0;touch-action:none;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-gantt__bar-row:hover>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-selected>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-active>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.is-dragging .dou-gantt__bar-row:not(.is-active)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:0}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 12px)/2);cursor:ew-resize;width:12px;height:12px;margin-left:-6px}.dou-gantt__handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)40%,transparent);content:"";border-radius:1px;width:2px;height:8px;top:2px;left:5px}.dou-gantt__handle.is-start:after{left:7px}.dou-gantt__handle.is-end:after{left:3px}.dou-gantt__progress-handle{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 1px);cursor:ew-resize;width:12px;height:10px;margin-left:-6px}.dou-gantt__progress-handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)45%,transparent);clip-path:polygon(50% 0,100% 100%,0 100%);content:"";width:8px;height:6px;top:2px;left:2px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 16px)/2);cursor:crosshair;width:16px;height:16px;margin-left:-8px}.dou-gantt__dot.is-start{transform:translate(-10px)}.dou-gantt__dot.is-end{transform:translate(10px)}.dou-gantt__dot:after{position:absolute;box-sizing:border-box;border:1px solid color-mix(in oklab,var(--dou-color-text)45%,transparent);background-color:var(--dou-color-bg-surface);content:"";border-radius:50%;inset:4px}.dou-gantt__dot:hover:after{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}@media (pointer:coarse){.dou-gantt__bar-row:not(.is-selected)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){display:none}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__handle:after{top:12px;left:15px}.dou-gantt__handle.is-start:after{left:19px}.dou-gantt__handle.is-end:after{left:11px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__dot:after{inset:11px}.dou-gantt__dot.is-start{transform:translate(-20px)}.dou-gantt__dot.is-end{transform:translate(20px)}}.dou-gantt__tip{position:absolute;z-index:4;display:flex;border-radius:var(--dou-radius-control);background-color:var(--dou-color-neutral);box-shadow:var(--dou-shadow-md);color:var(--dou-color-neutral-on);white-space:nowrap;pointer-events:none;align-items: center;height:22px;padding:0 8px;font-size:12px;top:-26px;left:0}.dou-gantt__tip.is-refused{background-color:var(--dou-color-danger);color:var(--dou-color-danger-on)}.dou-gantt__bar:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt__tr:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:-2px}.dou-gantt__notice{position:absolute;z-index:20;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);box-shadow:var(--dou-shadow-md);color:var(--dou-color-text);font-size:var(--dou-font-size-sm);pointer-events:none;width:max-content;max-width:calc(100% - 24px);padding:6px 12px;bottom:12px;left:50%;transform:translate(-50%)}.dou-gantt__sr-only{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-gantt__marker,.dou-gantt__marker-label{--dou-gantt-marker:color-mix(in oklab,var(--dou-color-text)45%,transparent);--dou-gantt-marker-text:var(--dou-color-text-secondary)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-primary{--dou-gantt-marker:var(--dou-color-primary);--dou-gantt-marker-text:var(--dou-color-primary-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-success{--dou-gantt-marker:var(--dou-color-success);--dou-gantt-marker-text:var(--dou-color-success-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-warning{--dou-gantt-marker:var(--dou-color-warning);--dou-gantt-marker-text:var(--dou-color-warning-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-danger{--dou-gantt-marker:var(--dou-color-danger);--dou-gantt-marker-text:var(--dou-color-danger-text)}.dou-gantt__marker{position:absolute;z-index:1;border-left:1px dashed var(--dou-gantt-marker);pointer-events:none;top:0;bottom:0}.dou-gantt__marker-label{position:absolute;z-index:1;display:flex;border:1px solid color-mix(in oklab,var(--dou-gantt-marker)40%,transparent);border-radius:var(--dou-radius-control);background-color:var(--dou-gantt-header-bg);color:var(--dou-gantt-marker-text);box-sizing:border-box;white-space:nowrap;pointer-events:none;align-items: center;height:18px;padding:0 6px;font-size:12px;top:5px;transform:translate(4px)}.dou-gantt__marker-label.is-cut{pointer-events:auto}.dou-gantt__marker-label.is-crowded{background-color:#0000;border-color:#0000;width:12px;padding:0}.dou-gantt__marker-label.is-crowded>.dou-gantt__marker-text{display:none}.dou-gantt__marker-label:before{position:absolute;border-left:1px dashed var(--dou-gantt-marker);content:"";height:56px;top:-6px;left:-5px}.dou-gantt__marker-label:empty{display:none}.dou-gantt__marker-text{overflow:hidden;text-overflow:ellipsis;min-width:0}.dou-gantt.is-scheduler .dou-gantt__body{background-image:none}.is-scheduler .dou-gantt__row-title:not(.is-summary){gap:6px;height:16px;padding:0 12px;font-size:12px;top:2px}.dou-gantt__lane-row{position:absolute;box-shadow:inset 0 -1px 0 var(--dou-gantt-line);pointer-events:none;top:0;left:0;right:0}.dou-gantt__lane-row.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__lane-row.is-group{background-color:var(--dou-gantt-hover)}.is-scheduler .dou-gantt__tr{align-items: flex-start}.is-scheduler .dou-gantt__tr>.dou-gantt__td{height:var(--dou-gantt-row-height)}.is-scheduler .dou-gantt__tr.is-group{background-color:var(--dou-gantt-hover);font-weight:var(--dou-font-weight-medium)}.dou-gantt__overload{display:grid;flex:none;place-items: center;width:16px;height:16px;margin-left:2px}.dou-gantt__overload:before{background-color:var(--dou-color-warning);content:"";border-radius:50%;width:6px;height:6px}.dou-gantt__cell-text.is-unassigned{color:var(--dou-color-text-secondary)}.dou-gantt__load{--dou-gantt-load:1;position:absolute;z-index:1;background-color:color-mix(in oklab,var(--dou-color-text)calc(6% + 14%*var(--dou-gantt-load)),transparent);pointer-events:none;border-radius:2px;height:4px;top:0;left:0}.dou-gantt__load.is-over{background-color:var(--dou-color-warning)}@media print{.dou-gantt{print-color-adjust:exact;-webkit-print-color-adjust:exact}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__tip,.dou-gantt__divider{display:none}}}
1
+ @layer dou.components{.dou-gantt{--dou-gantt-header-bg:var(--dou-color-bg-canvas);--dou-gantt-line:var(--dou-color-border-subtle);--dou-gantt-line-strong:var(--dou-color-border);--dou-gantt-off:color-mix(in oklab,var(--dou-color-text)5%,transparent);--dou-gantt-hover:color-mix(in oklab,var(--dou-color-text)3%,transparent);--dou-gantt-selected:color-mix(in oklab,var(--dou-color-primary)7%,transparent);--dou-gantt-link:color-mix(in oklab,var(--dou-color-text)32%,transparent);--dou-gantt-today:var(--dou-color-primary);--dou-gantt-bar-height:20px;position:relative;display:flex;box-sizing:border-box;overflow:hidden;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-container);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font-family:var(--dou-font-family);font-size:var(--dou-font-size-md);line-height:var(--dou-font-line-height);outline:none;width:100%;min-width:0;height:480px}.dou-gantt:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt.is-dragging{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging *{user-select:none;-webkit-user-select:none}.dou-gantt.is-dragging-move{cursor:grabbing}.dou-gantt.is-dragging-move *{cursor:grabbing}.dou-gantt.is-dragging-start *{cursor:ew-resize}.dou-gantt.is-dragging-end *{cursor:ew-resize}.dou-gantt.is-dragging-progress *{cursor:ew-resize}.dou-gantt.is-dragging-draw *{cursor:ew-resize}.dou-gantt.is-dragging-link *{cursor:crosshair}.dou-gantt.is-dragging-row *{cursor:grabbing}.dou-gantt__table-pane{display:flex;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;flex:none;min-width:0}.dou-gantt__table{display:flex;flex-direction:column;flex:1 0 auto}.dou-gantt__table-head{display:flex;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);flex:none;height:56px}.dou-gantt__th,.dou-gantt__td{display:flex;box-sizing:border-box;white-space:nowrap;align-items: center;min-width:0;padding:0 12px}:is(.dou-gantt__th,.dou-gantt__td).is-center{justify-content:center}:is(.dou-gantt__th,.dou-gantt__td).is-end{justify-content:flex-end}.dou-gantt__th.is-title{min-width:120px}.dou-gantt__table-body{position:relative;overflow-x:hidden;overflow-y:auto;scrollbar-width:none;flex:1;min-height:0}.dou-gantt__table-body::-webkit-scrollbar{display:none}.dou-gantt__table-rows{position:relative}.dou-gantt__tr{position:absolute;display:flex;height:var(--dou-gantt-row-height);box-shadow:inset 0 -1px 0 var(--dou-gantt-line);cursor:default;top:0;left:0;right:0}.dou-gantt__tr.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__tr.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__tr.is-summary .dou-gantt__td.is-title{font-weight:var(--dou-font-weight-medium)}.dou-gantt__td{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-gantt__td.is-title{color:var(--dou-color-text);font-size:var(--dou-font-size-md);min-width:120px;padding-left:6px}.dou-gantt__cell-text{overflow-x:clip;text-overflow:ellipsis;min-width:0}.dou-gantt__indent{flex:none}.dou-gantt__toggle,.dou-gantt__toggle-space{display:inline-flex;flex:none;justify-content:center;align-items: center;width:20px;height:20px;margin-right:4px}.dou-gantt__toggle{color:var(--dou-color-text-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:0;font-size:14px}.dou-gantt__toggle:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__tr.is-moving{opacity:.45}.dou-gantt__tr.is-drop-inside{background-color:var(--dou-gantt-selected);box-shadow:inset 0 0 0 1px var(--dou-color-primary),inset 0 -1px 0 var(--dou-gantt-line)}.dou-gantt__drop-line{position:absolute;z-index:2;background-color:var(--dou-color-primary);pointer-events:none;border-radius:1px;height:2px;top:-1px;right:8px}.dou-gantt__add-row{position:absolute;display:flex;height:var(--dou-gantt-row-height);top:0;left:0;right:0}.dou-gantt__add-row>.dou-gantt__td{flex:1}.dou-gantt__add{display:inline-flex;text-align:start;border-radius:var(--dou-radius-control);color:var(--dou-color-text-tertiary);font:inherit;font-size:var(--dou-font-size-sm);cursor:pointer;background:0 0;border:0;flex:1;align-items: center;gap:6px;height:24px;margin-left:-6px;padding:0 6px}.dou-gantt__add>svg{font-size:14px}.dou-gantt__add:hover{background-color:var(--dou-color-bg-muted);color:var(--dou-color-text)}.dou-gantt__add:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:1px}.dou-gantt__editor{display:flex;flex:1;align-items: center;min-width:0}.dou-gantt__editor>*{flex:1;min-width:0}.dou-gantt__editor.is-date{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{position:absolute;z-index:3;width:156px;top:50%;left:6px;transform:translateY(-50%)}.dou-gantt__editor.is-datetime{width:208px}.dou-gantt__td{position:relative}.is-editable .dou-gantt__tr{user-select:none;-webkit-user-select:none}.dou-gantt__editor-input{box-sizing:border-box;border:1px solid var(--dou-color-border-strong,var(--dou-color-border));border-radius:var(--dou-radius-control);outline:none;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:max(var(--dou-font-size-input-min,0px),1em);width:100%;height:26px;margin-left:-7px;padding:0 6px}.dou-gantt__editor-input:focus{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)30%,transparent)}.dou-gantt__editor-input::placeholder{color:var(--dou-color-text-tertiary)}.dou-gantt__editor-input[aria-invalid=true]{border-color:var(--dou-color-danger);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-danger)24%,transparent)}.dou-gantt__menu-anchor{position:absolute;overflow:hidden;width:0;height:0}.dou-gantt__divider{position:relative;z-index:3;background-color:var(--dou-gantt-line-strong);outline:none;touch-action:none;cursor:col-resize;transition:background-color var(--dou-motion-duration-fast)var(--dou-motion-easing);flex:none;order:1;width:1px}.dou-gantt__divider:before{position:absolute;content:"";inset:0 -4px}.dou-gantt__divider:hover{background-color:var(--dou-color-focus)}.dou-gantt__divider:focus-visible{background-color:var(--dou-color-focus)}.dou-gantt__chart{position:relative;overflow:auto;outline:none;overscroll-behavior-x:none;flex:1;order:2;min-width:0}.dou-gantt__chart.is-fixed{overscroll-behavior-x:contain}.dou-gantt__canvas{position:relative;min-height:100%}.dou-gantt__header{position:sticky;z-index:4;box-sizing:border-box;border-bottom:1px solid var(--dou-gantt-line-strong);background-color:var(--dou-gantt-header-bg);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;height:56px;top:0}.dou-gantt__tier{position:relative;overflow:clip;height:28px}.dou-gantt__tier.is-top{box-shadow:inset 0 -1px 0 var(--dou-gantt-line);color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__tier.is-bottom{height:27px}.dou-gantt__cell{position:absolute;display:flex;box-sizing:border-box;box-shadow:inset 1px 0 0 var(--dou-gantt-line);align-items: center;top:0;bottom:0}.is-bottom>.dou-gantt__cell{justify-content:center}.dou-gantt__cell-label{position:sticky;box-sizing:border-box;overflow-x:clip;text-overflow:ellipsis;white-space:nowrap;text-box:trim-both cap alphabetic;min-width:0;max-width:100%;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__cell.is-off{color:var(--dou-color-text-tertiary)}.dou-gantt__cell.is-now{color:var(--dou-gantt-today);font-weight:var(--dou-font-weight-medium)}.dou-gantt__today-mark{position:absolute;background-color:var(--dou-gantt-today);clip-path:polygon(50% 0,100% 100%,0 100%);width:8px;height:4px;margin-left:-3.5px;bottom:-1px}.dou-gantt__body{position:relative;background-image:linear-gradient(to top,var(--dou-gantt-line)1px,transparent 1px);background-size:100% var(--dou-gantt-row-height)}.dou-gantt__row-titles{position:sticky;z-index:3;overflow:visible;width:0;height:0;left:0}.dou-gantt__row-title{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;padding:0 12px;top:0;left:0}.dou-gantt__row-title.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.dou-gantt__off,.dou-gantt__gridline,.dou-gantt__today{position:absolute;pointer-events:none;top:0;bottom:0}.dou-gantt__off{background-color:var(--dou-gantt-off)}.dou-gantt__gridline{background-color:var(--dou-gantt-line);width:1px}.dou-gantt__today{z-index:1;background-color:var(--dou-gantt-today);width:1px}.dou-gantt__row-highlight{position:absolute;height:var(--dou-gantt-row-height);background-color:var(--dou-gantt-hover);pointer-events:none;top:0;left:0;right:0}.dou-gantt__row-highlight.is-selected{background-color:var(--dou-gantt-selected)}.dou-gantt__links{position:absolute;z-index:1;overflow:visible;pointer-events:none;top:0;left:0}.dou-gantt__link{color:var(--dou-gantt-link)}.dou-gantt__link:hover{color:var(--dou-color-primary)}.dou-gantt__link.is-related{color:var(--dou-color-primary)}.dou-gantt__link-hit{fill:none;stroke:transparent;stroke-width:10px;pointer-events:stroke}.dou-gantt__link-line{fill:none;stroke:currentColor;stroke-width:1px}.dou-gantt__link-arrow{fill:currentColor}.dou-gantt__link.is-selected{color:var(--dou-color-primary)}.dou-gantt__link.is-selected .dou-gantt__link-line{stroke-width:2px}.dou-gantt__link.is-critical{color:color-mix(in oklab,var(--dou-color-danger)72%,var(--dou-color-bg-surface))}.dou-gantt__link.is-broken{color:var(--dou-color-warning)}.dou-gantt__link.is-broken .dou-gantt__link-line{stroke-dasharray:4 3}.dou-gantt__link-draft{fill:none;stroke:var(--dou-color-primary);stroke-dasharray:4 3;stroke-width:1.5px}.dou-gantt__link-draft.is-refused{stroke:var(--dou-color-danger)}.dou-gantt__bar-row{position:absolute;z-index:2;height:var(--dou-gantt-row-height);top:0;left:0}.dou-gantt__bar{--dou-gantt-tone:var(--dou-color-text);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);display:flex;box-sizing:border-box;height:var(--dou-gantt-bar-height);overflow:clip;border:1px solid color-mix(in oklab,var(--dou-gantt-tone)18%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)5%,var(--dou-color-bg-surface));box-shadow:var(--dou-shadow-sm);cursor:default;border-radius:6px;align-items: center}.dou-gantt__bar:hover{border-color:color-mix(in oklab,var(--dou-gantt-tone)34%,var(--dou-color-bg-surface))}.is-editable .dou-gantt__bar:not(.is-locked){cursor:grab}.dou-gantt__bar.is-link-target{border-color:var(--dou-color-primary);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-primary)22%,transparent)}.dou-gantt__bar.is-link-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-move-refused{border-color:var(--dou-color-danger);box-shadow:0 0 0 3px color-mix(in oklab,var(--dou-color-danger)18%,transparent)}.dou-gantt__bar.is-selected{border-color:var(--dou-color-primary);box-shadow:0 0 0 2px color-mix(in oklab,var(--dou-color-focus)35%,transparent)}.dou-gantt__bar.is-primary{--dou-gantt-tone:var(--dou-color-primary)}.dou-gantt__bar.is-success{--dou-gantt-tone:var(--dou-color-success)}.dou-gantt__bar.is-warning{--dou-gantt-tone:var(--dou-color-warning)}.dou-gantt__bar.is-danger{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical{--dou-gantt-tone:var(--dou-color-danger)}.dou-gantt__bar.is-critical:not(:-webkit-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:-moz-any(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt__bar.is-critical:not(:is(.is-selected,.is-summary)){border-color:color-mix(in oklab,var(--dou-color-danger)48%,var(--dou-color-bg-surface))}.dou-gantt.has-baseline :-webkit-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :-moz-any(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt.has-baseline :is(.dou-gantt__bar-row,.dou-gantt__ghost,.dou-gantt__peer){translate:0 -4px}.dou-gantt__baseline{--dou-gantt-baseline:color-mix(in oklab,var(--dou-color-text)24%,var(--dou-color-bg-surface));position:absolute;top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 2px);z-index:1;background-color:var(--dou-gantt-baseline);pointer-events:none;border-radius:2px;height:4px;left:0}.dou-gantt__baseline.is-milestone{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 4px);border-radius:1px;width:8px;height:8px;margin-left:-4px}.dou-gantt__ghost{position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2);z-index:2;box-sizing:border-box;height:var(--dou-gantt-bar-height);border:1px dashed color-mix(in oklab,var(--dou-color-text)40%,transparent);pointer-events:none;border-radius:6px;left:0}.dou-gantt__ghost.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-radius:2px;width:10px;height:10px;margin-left:-5px}.dou-gantt__peer{--dou-gantt-peer-color:var(--dou-color-text-secondary);position:absolute;top:calc((var(--dou-gantt-row-height) - var(--dou-gantt-bar-height))/2 - 2px);z-index:2;box-sizing:content-box;height:var(--dou-gantt-bar-height);border:1px solid var(--dou-gantt-peer-color);pointer-events:none;border-radius:8px;padding:1px;left:-2px}.dou-gantt__peer.is-moving{background-color:color-mix(in oklab,var(--dou-gantt-peer-color)8%,transparent);border-style:dashed}.dou-gantt__peer.is-milestone{top:calc((var(--dou-gantt-row-height) - 14px)/2 - 2px);border-radius:3px;width:14px;height:14px;margin-left:-9px}.dou-gantt__peer.is-milestone>.dou-gantt__peer-name{transform-origin:0 0;top:100%;left:0;right:auto;transform:rotate(-45deg)translate(calc(-100% - 4px),-50%);translate:none}.dou-gantt__peer.is-milestone.is-moving>.dou-gantt__peer-name{top:0;left:100%;transform:rotate(-45deg)translate(4px,-50%)}.dou-gantt__peer.is-moving>.dou-gantt__peer-name{left:calc(100% + 4px);right:auto}.dou-gantt__peer-name{position:absolute;background-color:var(--dou-gantt-peer-color);color:oklch(from var(--dou-gantt-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;padding:0 6px;line-height:18px;top:50%;right:calc(100% + 4px);translate:0 -50%}.dou-gantt__progress{position:absolute;background-color:color-mix(in oklab,var(--dou-gantt-tone)12%,var(--dou-color-bg-surface));top:0;bottom:0;left:0}.dou-gantt__bar-label{position:sticky;overflow-x:clip;font-size:var(--dou-font-size-sm);text-overflow:ellipsis;white-space:nowrap;text-box:trim-both cap alphabetic;min-width:0;margin-block-start:-4px;margin-block-end:-4px;padding:4px 8px;left:0}.dou-gantt__bar.is-summary{top:calc((var(--dou-gantt-row-height) - 8px)/2 - 2px);overflow:visible;background-color:color-mix(in oklab,var(--dou-gantt-tone)40%,var(--dou-color-bg-surface));box-shadow:none;border:0;border-radius:2px 2px 0 0;height:6px}.dou-gantt__bar.is-summary:before{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:after{position:absolute;background-color:inherit;content:"";width:6px;height:5px;top:100%}.dou-gantt__bar.is-summary:before{clip-path:polygon(0 0,100% 0,0 100%);left:0}.dou-gantt__bar.is-summary:after{clip-path:polygon(0 0,100% 0,100% 100%);right:0}.dou-gantt__bar.is-summary.is-selected{background-color:var(--dou-color-primary);box-shadow:none}.dou-gantt__bar.is-milestone{top:calc((var(--dou-gantt-row-height) - 10px)/2);border-color:color-mix(in oklab,var(--dou-gantt-tone)70%,var(--dou-color-bg-surface));background-color:color-mix(in oklab,var(--dou-gantt-tone)62%,var(--dou-color-bg-surface));border-radius:2px;width:10px;height:10px;margin-left:-5px;transform:rotate(45deg)}.dou-gantt__bar.is-milestone.is-selected{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}.dou-gantt__bar-side{position:absolute;display:flex;height:var(--dou-gantt-row-height);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;pointer-events:none;text-shadow:0 0 2px var(--dou-color-bg-surface),0 0 2px var(--dou-color-bg-surface),0 0 4px var(--dou-color-bg-surface);align-items: center;top:0}.dou-gantt__bar-side.is-summary{color:var(--dou-color-text);font-weight:var(--dou-font-weight-medium)}.is-editable .dou-gantt__bar-row:-webkit-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:-moz-any(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.is-editable .dou-gantt__bar-row:is(:hover,.is-selected,.is-active)>.dou-gantt__bar-side{transform:translate(12px)}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot{position:absolute;z-index:1;opacity:0;touch-action:none;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-gantt__bar-row:hover>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-selected>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.dou-gantt__bar-row.is-active>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:1}.is-dragging .dou-gantt__bar-row:not(.is-active)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){opacity:0}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 12px)/2);cursor:ew-resize;width:12px;height:12px;margin-left:-6px}.dou-gantt__handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)40%,transparent);content:"";border-radius:1px;width:2px;height:8px;top:2px;left:5px}.dou-gantt__handle.is-start:after{left:7px}.dou-gantt__handle.is-end:after{left:3px}.dou-gantt__progress-handle{top:calc((var(--dou-gantt-row-height) + var(--dou-gantt-bar-height))/2 - 1px);cursor:ew-resize;width:12px;height:10px;margin-left:-6px}.dou-gantt__progress-handle:after{position:absolute;background-color:color-mix(in oklab,var(--dou-color-text)45%,transparent);clip-path:polygon(50% 0,100% 100%,0 100%);content:"";width:8px;height:6px;top:2px;left:2px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 16px)/2);cursor:crosshair;width:16px;height:16px;margin-left:-8px}.dou-gantt__dot.is-start{transform:translate(-10px)}.dou-gantt__dot.is-end{transform:translate(10px)}.dou-gantt__dot:after{position:absolute;box-sizing:border-box;border:1px solid color-mix(in oklab,var(--dou-color-text)45%,transparent);background-color:var(--dou-color-bg-surface);content:"";border-radius:50%;inset:4px}.dou-gantt__dot:hover:after{border-color:var(--dou-color-primary);background-color:var(--dou-color-primary)}@media (pointer:coarse){.dou-gantt__bar-row:not(.is-selected)>:is(.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__dot){display:none}.dou-gantt__handle{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__handle:after{top:12px;left:15px}.dou-gantt__handle.is-start:after{left:19px}.dou-gantt__handle.is-end:after{left:11px}.dou-gantt__dot{top:calc((var(--dou-gantt-row-height) - 32px)/2);width:32px;height:32px;margin-left:-16px}.dou-gantt__dot:after{inset:11px}.dou-gantt__dot.is-start{transform:translate(-20px)}.dou-gantt__dot.is-end{transform:translate(20px)}}.dou-gantt__tip{position:absolute;z-index:4;display:flex;border-radius:var(--dou-radius-control);background-color:var(--dou-color-neutral);box-shadow:var(--dou-shadow-md);color:var(--dou-color-neutral-on);white-space:nowrap;pointer-events:none;align-items: center;height:22px;padding:0 8px;font-size:12px;top:-26px;left:0}.dou-gantt__tip.is-refused{background-color:var(--dou-color-danger);color:var(--dou-color-danger-on)}.dou-gantt__bar:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-gantt__tr:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:-2px}.dou-gantt__notice{position:absolute;z-index:20;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);box-shadow:var(--dou-shadow-md);color:var(--dou-color-text);font-size:var(--dou-font-size-sm);pointer-events:none;width:max-content;max-width:calc(100% - 24px);padding:6px 12px;bottom:12px;left:50%;transform:translate(-50%)}.dou-gantt__sr-only{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-gantt__marker,.dou-gantt__marker-label{--dou-gantt-marker:color-mix(in oklab,var(--dou-color-text)45%,transparent);--dou-gantt-marker-text:var(--dou-color-text-secondary)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-primary{--dou-gantt-marker:var(--dou-color-primary);--dou-gantt-marker-text:var(--dou-color-primary-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-success{--dou-gantt-marker:var(--dou-color-success);--dou-gantt-marker-text:var(--dou-color-success-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-warning{--dou-gantt-marker:var(--dou-color-warning);--dou-gantt-marker-text:var(--dou-color-warning-text)}:is(.dou-gantt__marker,.dou-gantt__marker-label).is-danger{--dou-gantt-marker:var(--dou-color-danger);--dou-gantt-marker-text:var(--dou-color-danger-text)}.dou-gantt__marker{position:absolute;z-index:1;border-left:1px dashed var(--dou-gantt-marker);pointer-events:none;top:0;bottom:0}.dou-gantt__marker-label{position:absolute;z-index:1;display:flex;border:1px solid color-mix(in oklab,var(--dou-gantt-marker)40%,transparent);border-radius:var(--dou-radius-control);background-color:var(--dou-gantt-header-bg);color:var(--dou-gantt-marker-text);box-sizing:border-box;white-space:nowrap;pointer-events:none;align-items: center;height:18px;padding:0 6px;font-size:12px;top:5px;transform:translate(4px)}.dou-gantt__marker-label.is-cut{pointer-events:auto}.dou-gantt__marker-label.is-crowded{background-color:#0000;border-color:#0000;width:12px;padding:0}.dou-gantt__marker-label.is-crowded>.dou-gantt__marker-text{display:none}.dou-gantt__marker-label:before{position:absolute;border-left:1px dashed var(--dou-gantt-marker);content:"";height:56px;top:-6px;left:-5px}.dou-gantt__marker-label:empty{display:none}.dou-gantt__marker-text{overflow:hidden;text-overflow:ellipsis;min-width:0}.dou-gantt.is-scheduler .dou-gantt__body{background-image:none}.is-scheduler .dou-gantt__row-title:not(.is-summary){gap:6px;height:16px;padding:0 12px;font-size:12px;top:2px}.dou-gantt__lane-row{position:absolute;box-shadow:inset 0 -1px 0 var(--dou-gantt-line);pointer-events:none;top:0;left:0;right:0}.dou-gantt__lane-row.is-hovered{background-color:var(--dou-gantt-hover)}.dou-gantt__lane-row.is-group{background-color:var(--dou-gantt-hover)}.is-scheduler .dou-gantt__tr{align-items: flex-start}.is-scheduler .dou-gantt__tr>.dou-gantt__td{height:var(--dou-gantt-row-height)}.is-scheduler .dou-gantt__tr.is-group{background-color:var(--dou-gantt-hover);font-weight:var(--dou-font-weight-medium)}.dou-gantt__overload{display:grid;flex:none;place-items: center;width:16px;height:16px;margin-left:2px}.dou-gantt__overload:before{background-color:var(--dou-color-warning);content:"";border-radius:50%;width:6px;height:6px}.dou-gantt__cell-text.is-unassigned{color:var(--dou-color-text-secondary)}.dou-gantt__load{--dou-gantt-load:1;position:absolute;z-index:1;background-color:color-mix(in oklab,var(--dou-color-text)calc(6% + 14%*var(--dou-gantt-load)),transparent);pointer-events:none;border-radius:2px;height:4px;top:0;left:0}.dou-gantt__load.is-over{background-color:var(--dou-color-warning)}@media print{.dou-gantt{print-color-adjust:exact;-webkit-print-color-adjust:exact}.dou-gantt__handle,.dou-gantt__progress-handle,.dou-gantt__tip,.dou-gantt__divider{display:none}}}
package/dist/time-axis.js CHANGED
@@ -259,18 +259,22 @@ function useTimeAxis(o) {
259
259
  function pinchEnd(event) {
260
260
  if (event.touches.length < 2) pinch = null;
261
261
  }
262
- /** The time in view, with some room either side. */
262
+ /**
263
+ * The time in view, with some room either side, but never past either end:
264
+ * what is drawn past the end would widen the timeline, and scrolling on
265
+ * would draw more, so a fixed `range` would scroll on for ever.
266
+ */
263
267
  const timeWindow = computed(() => ({
264
- start: origin.value + (scrollLeft.value - OVERSCAN_X) / ppm.value,
265
- end: origin.value + (scrollLeft.value + (o.viewWidth.value || 800) + OVERSCAN_X) / ppm.value
268
+ start: Math.max(extent.value.start, origin.value + (scrollLeft.value - OVERSCAN_X) / ppm.value),
269
+ end: Math.min(extent.value.end, origin.value + (scrollLeft.value + (o.viewWidth.value || 800) + OVERSCAN_X) / ppm.value)
266
270
  }));
267
271
  function cells(unit, step = 1) {
268
272
  const { start, end } = timeWindow.value;
269
- return unitsBetween(unit, Math.max(start, origin.value), end, o.weekStart.value, step).map((cell) => ({
273
+ return unitsBetween(unit, start, end, o.weekStart.value, step).map((cell) => ({
270
274
  key: cell.start,
271
275
  end: cell.end,
272
276
  left: xOf(cell.start),
273
- width: (cell.end - cell.start) * ppm.value,
277
+ width: (Math.min(cell.end, extent.value.end) - cell.start) * ppm.value,
274
278
  label: unitLabel(unit, cell.start, o.messages.value, dayWidth.value)
275
279
  }));
276
280
  }
@@ -1 +1 @@
1
- {"version":3,"file":"time-axis.js","names":[],"sources":["../src/time-axis.ts"],"sourcesContent":["import { createScrollLink, scrollPositionOf, useNow, useTouchScroll } from 'dou-ui'\nimport { computed, onMounted, ref, watch, type ComputedRef, type Ref, type ShallowRef } from 'vue'\nimport { offTime, type WorkCalendar } from './core/calendar'\nimport {\n DAY_WIDTH_RANGE,\n hourStep,\n levelByName,\n levelOf,\n unitStart,\n unitsBetween,\n type GanttScale,\n type TimeUnit,\n} from './core/scale'\nimport { MINUTES_PER_DAY, dayStart, parseTime, wallClockNow } from './core/time'\nimport { unitLabel } from './labels'\nimport type { GanttMessages } from './locale'\n\n/** Room around the visible part that is rendered too, in px. */\nconst OVERSCAN_X = 320\n/** The widest a day gets when fitting, so short plans don't zoom to hours. */\nconst FIT_MAX = 64\nconst ZOOM_STEP = 1.5\n/**\n * Room kept before the view on a touch screen, in screens and at least in\n * px, but no more time than `ROOM_BEFORE_TIME`. Time can only be added there\n * once a touch scroll is over, so it is enough for a long run of fast swipes\n * that never lets the momentum stop. Only what is in view is drawn, so room\n * costs nothing but scroll width.\n */\nconst ROOM_BEFORE = 300\nconst ROOM_BEFORE_MIN = 400_000\n/** Ten thousand years, in minutes: room for a run of swipes at the widest scale too. */\nconst ROOM_BEFORE_TIME = 10_000 * 365 * MINUTES_PER_DAY\n/** The earliest the timeline goes, some 190,000 years back, well within what a date can be. */\nconst EARLIEST = -1e11\n/**\n * Room kept before the view with a mouse or trackpad, in screens. It is\n * filled as soon as the view comes near the start, and stays small so the\n * scrollbar thumb still shows where the view is.\n */\nconst ROOM_BEFORE_POINTER = 4\n/** Room kept after the view, in screens; time is added there as you scroll. */\nconst ROOM_AFTER = 4\n\nfunction fingers(event: TouchEvent) {\n const [a, b] = [event.touches[0]!, event.touches[1]!]\n return { a, b, distance: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY) }\n}\n\nexport interface HeaderCell {\n key: number\n end: number\n left: number\n width: number\n label: string\n}\n\nexport interface TimeAxisOptions {\n /** The scrolling timeline. */\n chart: Readonly<ShallowRef<HTMLElement | null>>\n /** The table body, kept at the same vertical scroll. */\n tableBody: Readonly<ShallowRef<HTMLElement | null>>\n viewWidth: Ref<number>\n scale: Ref<GanttScale | undefined>\n range: () => [string, string] | undefined\n today: () => boolean\n weekStart: ComputedRef<0 | 1>\n calendar: ComputedRef<WorkCalendar>\n messages: ComputedRef<GanttMessages>\n /** The time the content covers, or `null` when nothing is scheduled. */\n content: ComputedRef<{ start: number; end: number } | null>\n /** The width the timeline will have once laid out, for fitting. */\n fitWidth: () => number\n}\n\n/**\n * The time axis the gantt chart and the scheduler share: zoom, the extent\n * that grows as you scroll, the header cells, days off and the today line.\n */\nexport function useTimeAxis(o: TimeAxisOptions) {\n /** How wide a day is, in px; zooming changes it smoothly. */\n const dayWidth = ref(levelByName(o.scale.value ?? 'day').base)\n /** Without a `scale`, the first view picks the day width that fits the content. */\n let fitPending = o.scale.value == null\n const level = computed(() => levelOf(dayWidth.value))\n /** px per minute. */\n const ppm = computed(() => dayWidth.value / MINUTES_PER_DAY)\n\n watch(level, (next) => {\n if (o.scale.value !== next.name) o.scale.value = next.name\n })\n // a picked level zooms around now when it is in view, else around the middle\n watch(o.scale, (name) => {\n if (!name || level.value.name === name) return\n const x = todayX.value == null ? null : todayX.value - scrollLeft.value\n zoomTo(levelByName(name).base, x != null && x >= 0 && x <= o.viewWidth.value ? x : undefined)\n })\n\n const nowMs = useNow({ interval: 60_000 })\n const now = computed(() => wallClockNow(new Date(nowMs.value)))\n\n /** The content's time, or the coming month when nothing is scheduled. */\n const content = computed(() => {\n const known = o.content.value\n if (known) return known\n const start = dayStart(now.value)\n return { start, end: start + 30 * MINUTES_PER_DAY }\n })\n\n /** The furthest the view has gone either way, so the timeline keeps it. */\n const reach = ref<{ start: number; end: number } | null>(null)\n\n /** px of room kept before the view. */\n /** Whether there is a touch screen; read once mounted, so the server render matches. */\n const coarse = ref(false)\n const roomBefore = computed(() => {\n const width = o.viewWidth.value || 800\n if (!coarse.value) return ROOM_BEFORE_POINTER * width\n return Math.min(Math.max(ROOM_BEFORE * width, ROOM_BEFORE_MIN), ROOM_BEFORE_TIME * ppm.value)\n })\n\n const touch = useTouchScroll()\n\n /** Where the timeline would start, without a fixed range. */\n const freeStart = computed(() => {\n const start = Math.min(content.value.start, reach.value?.start ?? Infinity)\n return Math.max(EARLIEST, dayStart(start - roomBefore.value / ppm.value))\n })\n\n /**\n * The start held while a touch scroll goes on. A later start moves the\n * content, and the scroll position has to follow it, which iOS drops then:\n * content coming in earlier, the room changing as the screen turns. So the\n * start stays where it was and moves once the scroll is over.\n */\n const heldStart = ref<number | null>(null)\n watch(\n touch.active,\n (on) => {\n heldStart.value = on ? freeStart.value : null\n },\n { flush: 'sync' },\n )\n\n /** The span the timeline covers. */\n const extent = computed(() => {\n const fixed = o.range()?.map((text) => parseTime(text))\n if (fixed?.[0] && fixed[1])\n return { start: dayStart(fixed[0].at), end: dayStart(fixed[1].at) + MINUTES_PER_DAY }\n const width = o.viewWidth.value || 800\n const after = Math.max((ROOM_AFTER * width) / ppm.value, 7 * MINUTES_PER_DAY)\n const end = Math.max(content.value.end, reach.value?.end ?? -Infinity)\n return {\n start: heldStart.value ?? freeStart.value,\n end: dayStart(end + after) + MINUTES_PER_DAY,\n }\n })\n const origin = computed(() => extent.value.start)\n const totalWidth = computed(() => Math.ceil((extent.value.end - extent.value.start) * ppm.value))\n const xOf = (at: number) => (at - origin.value) * ppm.value\n\n // Scrolling ---------------------------------------------------------------------\n\n const scrollTop = ref(0)\n const scrollLeft = ref(0)\n /**\n * The time at the left edge of the view. It is what stays put: when the\n * extent grows or the zoom changes, the scroll position follows it.\n */\n const viewStart = ref(0)\n const scrollbar = ref(0)\n\n const link = createScrollLink('y')\n\n function onChartScroll() {\n const el = o.chart.value!\n const body = o.tableBody.value\n // iOS reports positions past either end while the content bounces back\n const { top, left } = scrollPositionOf(el)\n scrollTop.value = top\n scrollLeft.value = left\n viewStart.value = origin.value + left / ppm.value\n if (body) link.follow(el, body)\n grow()\n }\n\n /** Keeps time `at` on the timeline, adding room around it. */\n function keep(at: number, until = at) {\n const known = reach.value\n const start = Math.min(known?.start ?? at, at)\n const end = Math.max(known?.end ?? until, until)\n if (known?.start !== start || known.end !== end) reach.value = { start, end }\n }\n\n /**\n * Adds time at the end the view comes near. After the end that is safe at\n * any time. Before the start it moves the content right, and the scroll\n * position has to follow it; iOS drops that move while a touch scroll or\n * its momentum goes on, and the next scroll event would read the old\n * position against the new start. So the room before is wide enough for a\n * run of swipes, and is filled again once the scroll is over.\n */\n function grow() {\n const el = o.chart.value\n if (!el || o.range()) return\n const width = o.viewWidth.value\n const left = scrollPositionOf(el).left\n if (left + width > totalWidth.value - ROOM_AFTER * width)\n keep(viewStart.value, viewStart.value + ((ROOM_AFTER + 1) * width) / ppm.value)\n if (touch.active.value) touch.whenSettled(growBefore)\n // without a finger it is filled right away, but only near the start: a\n // scrollbar thumb dragged there would jump back under the pointer\n else if (left < 2 * width) growBefore()\n }\n\n function growBefore() {\n const el = o.chart.value\n // an end bouncing back reports positions past it\n if (!el || o.range() || el.scrollLeft < 0) return\n if (scrollPositionOf(el).left < roomBefore.value - o.viewWidth.value) keep(viewStart.value)\n }\n\n function onTableScroll() {\n const body = o.tableBody.value!\n const el = o.chart.value\n if (el) link.follow(body, el)\n }\n\n // keep the time at the left edge in place as the axis changes under it\n watch(\n [origin, ppm, totalWidth],\n () => {\n const el = o.chart.value\n if (!el) return\n const target = Math.round((viewStart.value - origin.value) * ppm.value)\n if (Math.abs(el.scrollLeft - target) >= 1) el.scrollLeft = target\n scrollLeft.value = scrollPositionOf(el).left\n },\n { flush: 'post' },\n )\n\n function measureScrollbar() {\n const el = o.chart.value\n if (el) scrollbar.value = el.offsetHeight - el.clientHeight\n }\n\n function scrollToTime(at: number, offset = 48) {\n // start the view on a whole header cell, so its label isn't cut at the edge\n const target = at - offset / ppm.value\n viewStart.value = unitStart(level.value.bottom, target, o.weekStart.value, headerStep.value)\n if (!o.range()) keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value)\n const el = o.chart.value\n if (!el) return\n el.scrollLeft = Math.round((viewStart.value - origin.value) * ppm.value)\n scrollLeft.value = scrollPositionOf(el).left\n }\n\n function fit() {\n const width = o.fitWidth()\n if (!width) return\n const days = Math.max(1, (content.value.end - content.value.start) / MINUTES_PER_DAY)\n dayWidth.value = Math.min(FIT_MAX, Math.max(DAY_WIDTH_RANGE[0], (width - 96) / days))\n scrollToTime(content.value.start)\n }\n\n onMounted(() => {\n coarse.value = window.matchMedia?.('(any-pointer: coarse)').matches ?? false\n measureScrollbar()\n scrollToTime(content.value.start)\n })\n\n /** Fits the content once the timeline has a width, unless a `scale` was given. */\n function fitWhenSized() {\n if (!fitPending || !o.fitWidth() || !o.viewWidth.value) return\n fitPending = false\n fit()\n }\n\n // Zoom --------------------------------------------------------------------------\n\n /** Changes the day width, keeping the time under `anchor` (px from the view's left) in place. */\n function zoomTo(width: number, anchor = o.viewWidth.value / 2) {\n const next = Math.min(DAY_WIDTH_RANGE[1], Math.max(DAY_WIDTH_RANGE[0], width))\n const at = viewStart.value + anchor / ppm.value\n dayWidth.value = next\n viewStart.value = at - anchor / ppm.value\n // what was scrolled past at the old zoom could be very wide at the new one\n if (reach.value && !o.range()) {\n reach.value = null\n keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value)\n }\n // a pinch moves the scroll position anyway, so the start moves with it\n if (heldStart.value != null) heldStart.value = freeStart.value\n }\n\n function onWheel(event: WheelEvent) {\n if (!(event.ctrlKey || event.metaKey)) return\n event.preventDefault()\n const rect = o.chart.value!.getBoundingClientRect()\n zoomTo(dayWidth.value * Math.exp(-event.deltaY * 0.01), event.clientX - rect.left)\n }\n\n const zoomIn = () => zoomTo(dayWidth.value * ZOOM_STEP)\n const zoomOut = () => zoomTo(dayWidth.value / ZOOM_STEP)\n\n /** Two fingers on the timeline zoom it, as a held Ctrl and the wheel do. */\n let pinch: { distance: number; dayWidth: number } | null = null\n\n /** Starts a pinch when two fingers rest on the timeline; `true` when one began. */\n function pinchStart(event: TouchEvent) {\n const el = o.chart.value\n if (event.touches.length !== 2 || !el) return false\n const { a, b, distance } = fingers(event)\n if (!el.contains(a.target as Node) || !el.contains(b.target as Node)) return false\n pinch = { distance: Math.max(1, distance), dayWidth: dayWidth.value }\n return true\n }\n\n /** Zooms with the fingers; `true` while a pinch is going on. */\n function pinchMove(event: TouchEvent) {\n if (!pinch || event.touches.length !== 2) return false\n event.preventDefault()\n const { a, b, distance } = fingers(event)\n const rect = o.chart.value!.getBoundingClientRect()\n zoomTo(pinch.dayWidth * (distance / pinch.distance), (a.clientX + b.clientX) / 2 - rect.left)\n return true\n }\n\n function pinchEnd(event: TouchEvent) {\n if (event.touches.length < 2) pinch = null\n }\n\n // What is in view ---------------------------------------------------------------\n\n /** The time in view, with some room either side. */\n const timeWindow = computed(() => ({\n start: origin.value + (scrollLeft.value - OVERSCAN_X) / ppm.value,\n end: origin.value + (scrollLeft.value + (o.viewWidth.value || 800) + OVERSCAN_X) / ppm.value,\n }))\n\n function cells(unit: TimeUnit, step = 1): HeaderCell[] {\n const { start, end } = timeWindow.value\n return unitsBetween(unit, Math.max(start, origin.value), end, o.weekStart.value, step).map(\n (cell) => ({\n key: cell.start,\n end: cell.end,\n left: xOf(cell.start),\n width: (cell.end - cell.start) * ppm.value,\n label: unitLabel(unit, cell.start, o.messages.value, dayWidth.value),\n }),\n )\n }\n\n const headerStep = computed(() => (level.value.bottom === 'hour' ? hourStep(dayWidth.value) : 1))\n const topCells = computed(() => cells(level.value.top))\n const bottomCells = computed(() => cells(level.value.bottom, headerStep.value))\n\n /** Days off, shaded; at hour level the hours outside work too. */\n const shaded = computed(() => {\n if (dayWidth.value < 8) return []\n const { start, end } = timeWindow.value\n return offTime(o.calendar.value, start, end, level.value.name === 'hour').map((range) => ({\n key: range.start,\n left: xOf(range.start),\n width: (range.end - range.start) * ppm.value,\n }))\n })\n\n const todayX = computed(() =>\n o.today() && now.value >= extent.value.start && now.value <= extent.value.end\n ? xOf(now.value)\n : null,\n )\n\n /** A pointer's x on screen as timeline px. */\n const contentX = (clientX: number) =>\n clientX - o.chart.value!.getBoundingClientRect().left + o.chart.value!.scrollLeft\n\n function scrollToDate(date: string) {\n const parsed = parseTime(date)\n if (parsed) scrollToTime(parsed.at)\n }\n\n function scrollToToday() {\n scrollToTime(now.value, o.viewWidth.value / 3)\n }\n\n return {\n dayWidth,\n level,\n ppm,\n now,\n extent,\n origin,\n totalWidth,\n xOf,\n contentX,\n scrollTop,\n scrollLeft,\n scrollbar,\n measureScrollbar,\n onChartScroll,\n onTableScroll,\n scrollToTime,\n scrollToDate,\n scrollToToday,\n fit,\n fitWhenSized,\n zoomTo,\n zoomIn,\n zoomOut,\n onWheel,\n pinchStart,\n pinchMove,\n pinchEnd,\n timeWindow,\n topCells,\n bottomCells,\n shaded,\n todayX,\n }\n}\n\nexport type TimeAxis = ReturnType<typeof useTimeAxis>\n"],"mappings":";;;;;;;;AAkBA,IAAM,aAAa;;AAEnB,IAAM,UAAU;AAChB,IAAM,YAAY;;;;;;;;AAQlB,IAAM,cAAc;AACpB,IAAM,kBAAkB;;AAExB,IAAM,mBAAmB,QAAe;;AAExC,IAAM,WAAW;;;;;;AAMjB,IAAM,sBAAsB;;AAE5B,IAAM,aAAa;AAEnB,SAAS,QAAQ,OAAmB;CAClC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,QAAQ,IAAK,MAAM,QAAQ,EAAG;CACpD,OAAO;EAAE;EAAG;EAAG,UAAU,KAAK,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO;CAAE;AACpF;;;;;AAgCA,SAAgB,YAAY,GAAoB;;CAE9C,MAAM,WAAW,IAAI,YAAY,EAAE,MAAM,SAAS,KAAK,CAAC,CAAC,IAAI;;CAE7D,IAAI,aAAa,EAAE,MAAM,SAAS;CAClC,MAAM,QAAQ,eAAe,QAAQ,SAAS,KAAK,CAAC;;CAEpD,MAAM,MAAM,eAAe,SAAS,QAAQ,eAAe;CAE3D,MAAM,QAAQ,SAAS;EACrB,IAAI,EAAE,MAAM,UAAU,KAAK,MAAM,EAAE,MAAM,QAAQ,KAAK;CACxD,CAAC;CAED,MAAM,EAAE,QAAQ,SAAS;EACvB,IAAI,CAAC,QAAQ,MAAM,MAAM,SAAS,MAAM;EACxC,MAAM,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,WAAW;EAClE,OAAO,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,KAAK,KAAK,KAAK,EAAE,UAAU,QAAQ,IAAI,KAAA,CAAS;CAC9F,CAAC;CAED,MAAM,QAAQ,OAAO,EAAE,UAAU,IAAO,CAAC;CACzC,MAAM,MAAM,eAAe,aAAa,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC;;CAG9D,MAAM,UAAU,eAAe;EAC7B,MAAM,QAAQ,EAAE,QAAQ;EACxB,IAAI,OAAO,OAAO;EAClB,MAAM,QAAQ,SAAS,IAAI,KAAK;EAChC,OAAO;GAAE;GAAO,KAAK,QAAQ,KAAK;EAAgB;CACpD,CAAC;;CAGD,MAAM,QAAQ,IAA2C,IAAI;;;CAI7D,MAAM,SAAS,IAAI,KAAK;CACxB,MAAM,aAAa,eAAe;EAChC,MAAM,QAAQ,EAAE,UAAU,SAAS;EACnC,IAAI,CAAC,OAAO,OAAO,OAAO,sBAAsB;EAChD,OAAO,KAAK,IAAI,KAAK,IAAI,cAAc,OAAO,eAAe,GAAG,mBAAmB,IAAI,KAAK;CAC9F,CAAC;CAED,MAAM,QAAQ,eAAe;;CAG7B,MAAM,YAAY,eAAe;EAC/B,MAAM,QAAQ,KAAK,IAAI,QAAQ,MAAM,OAAO,MAAM,OAAO,SAAS,QAAQ;EAC1E,OAAO,KAAK,IAAI,UAAU,SAAS,QAAQ,WAAW,QAAQ,IAAI,KAAK,CAAC;CAC1E,CAAC;;;;;;;CAQD,MAAM,YAAY,IAAmB,IAAI;CACzC,MACE,MAAM,SACL,OAAO;EACN,UAAU,QAAQ,KAAK,UAAU,QAAQ;CAC3C,GACA,EAAE,OAAO,OAAO,CAClB;;CAGA,MAAM,SAAS,eAAe;EAC5B,MAAM,QAAQ,EAAE,MAAM,CAAC,EAAE,KAAK,SAAS,UAAU,IAAI,CAAC;EACtD,IAAI,QAAQ,MAAM,MAAM,IACtB,OAAO;GAAE,OAAO,SAAS,MAAM,EAAE,CAAC,EAAE;GAAG,KAAK,SAAS,MAAM,EAAE,CAAC,EAAE,IAAI;EAAgB;EACtF,MAAM,QAAQ,EAAE,UAAU,SAAS;EACnC,MAAM,QAAQ,KAAK,IAAK,aAAa,QAAS,IAAI,OAAO,IAAI,eAAe;EAC5E,MAAM,MAAM,KAAK,IAAI,QAAQ,MAAM,KAAK,MAAM,OAAO,OAAO,SAAS;EACrE,OAAO;GACL,OAAO,UAAU,SAAS,UAAU;GACpC,KAAK,SAAS,MAAM,KAAK,IAAI;EAC/B;CACF,CAAC;CACD,MAAM,SAAS,eAAe,OAAO,MAAM,KAAK;CAChD,MAAM,aAAa,eAAe,KAAK,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,SAAS,IAAI,KAAK,CAAC;CAChG,MAAM,OAAO,QAAgB,KAAK,OAAO,SAAS,IAAI;CAItD,MAAM,YAAY,IAAI,CAAC;CACvB,MAAM,aAAa,IAAI,CAAC;;;;;CAKxB,MAAM,YAAY,IAAI,CAAC;CACvB,MAAM,YAAY,IAAI,CAAC;CAEvB,MAAM,OAAO,iBAAiB,GAAG;CAEjC,SAAS,gBAAgB;EACvB,MAAM,KAAK,EAAE,MAAM;EACnB,MAAM,OAAO,EAAE,UAAU;EAEzB,MAAM,EAAE,KAAK,SAAS,iBAAiB,EAAE;EACzC,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACnB,UAAU,QAAQ,OAAO,QAAQ,OAAO,IAAI;EAC5C,IAAI,MAAM,KAAK,OAAO,IAAI,IAAI;EAC9B,KAAK;CACP;;CAGA,SAAS,KAAK,IAAY,QAAQ,IAAI;EACpC,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,KAAK,IAAI,OAAO,SAAS,IAAI,EAAE;EAC7C,MAAM,MAAM,KAAK,IAAI,OAAO,OAAO,OAAO,KAAK;EAC/C,IAAI,OAAO,UAAU,SAAS,MAAM,QAAQ,KAAK,MAAM,QAAQ;GAAE;GAAO;EAAI;CAC9E;;;;;;;;;CAUA,SAAS,OAAO;EACd,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG;EACtB,MAAM,QAAQ,EAAE,UAAU;EAC1B,MAAM,OAAO,iBAAiB,EAAE,CAAC,CAAC;EAClC,IAAI,OAAO,QAAQ,WAAW,QAAQ,aAAa,OACjD,KAAK,UAAU,OAAO,UAAU,QAAU,IAAkB,QAAS,IAAI,KAAK;EAChF,IAAI,MAAM,OAAO,OAAO,MAAM,YAAY,UAAU;OAG/C,IAAI,OAAO,IAAI,OAAO,WAAW;CACxC;CAEA,SAAS,aAAa;EACpB,MAAM,KAAK,EAAE,MAAM;EAEnB,IAAI,CAAC,MAAM,EAAE,MAAM,KAAK,GAAG,aAAa,GAAG;EAC3C,IAAI,iBAAiB,EAAE,CAAC,CAAC,OAAO,WAAW,QAAQ,EAAE,UAAU,OAAO,KAAK,UAAU,KAAK;CAC5F;CAEA,SAAS,gBAAgB;EACvB,MAAM,OAAO,EAAE,UAAU;EACzB,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,IAAI,KAAK,OAAO,MAAM,EAAE;CAC9B;CAGA,MACE;EAAC;EAAQ;EAAK;CAAU,SAClB;EACJ,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,CAAC,IAAI;EACT,MAAM,SAAS,KAAK,OAAO,UAAU,QAAQ,OAAO,SAAS,IAAI,KAAK;EACtE,IAAI,KAAK,IAAI,GAAG,aAAa,MAAM,KAAK,GAAG,GAAG,aAAa;EAC3D,WAAW,QAAQ,iBAAiB,EAAE,CAAC,CAAC;CAC1C,GACA,EAAE,OAAO,OAAO,CAClB;CAEA,SAAS,mBAAmB;EAC1B,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,IAAI,UAAU,QAAQ,GAAG,eAAe,GAAG;CACjD;CAEA,SAAS,aAAa,IAAY,SAAS,IAAI;EAE7C,MAAM,SAAS,KAAK,SAAS,IAAI;EACjC,UAAU,QAAQ,UAAU,MAAM,MAAM,QAAQ,QAAQ,EAAE,UAAU,OAAO,WAAW,KAAK;EAC3F,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,UAAU,OAAO,UAAU,QAAQ,EAAE,UAAU,QAAQ,IAAI,KAAK;EACrF,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,CAAC,IAAI;EACT,GAAG,aAAa,KAAK,OAAO,UAAU,QAAQ,OAAO,SAAS,IAAI,KAAK;EACvE,WAAW,QAAQ,iBAAiB,EAAE,CAAC,CAAC;CAC1C;CAEA,SAAS,MAAM;EACb,MAAM,QAAQ,EAAE,SAAS;EACzB,IAAI,CAAC,OAAO;EACZ,MAAM,OAAO,KAAK,IAAI,IAAI,QAAQ,MAAM,MAAM,QAAQ,MAAM,SAAS,eAAe;EACpF,SAAS,QAAQ,KAAK,IAAI,SAAS,KAAK,IAAI,gBAAgB,KAAK,QAAQ,MAAM,IAAI,CAAC;EACpF,aAAa,QAAQ,MAAM,KAAK;CAClC;CAEA,gBAAgB;EACd,OAAO,QAAQ,OAAO,aAAa,uBAAuB,CAAC,CAAC,WAAW;EACvE,iBAAiB;EACjB,aAAa,QAAQ,MAAM,KAAK;CAClC,CAAC;;CAGD,SAAS,eAAe;EACtB,IAAI,CAAC,cAAc,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,UAAU,OAAO;EACxD,aAAa;EACb,IAAI;CACN;;CAKA,SAAS,OAAO,OAAe,SAAS,EAAE,UAAU,QAAQ,GAAG;EAC7D,MAAM,OAAO,KAAK,IAAI,gBAAgB,IAAI,KAAK,IAAI,gBAAgB,IAAI,KAAK,CAAC;EAC7E,MAAM,KAAK,UAAU,QAAQ,SAAS,IAAI;EAC1C,SAAS,QAAQ;EACjB,UAAU,QAAQ,KAAK,SAAS,IAAI;EAEpC,IAAI,MAAM,SAAS,CAAC,EAAE,MAAM,GAAG;GAC7B,MAAM,QAAQ;GACd,KAAK,UAAU,OAAO,UAAU,QAAQ,EAAE,UAAU,QAAQ,IAAI,KAAK;EACvE;EAEA,IAAI,UAAU,SAAS,MAAM,UAAU,QAAQ,UAAU;CAC3D;CAEA,SAAS,QAAQ,OAAmB;EAClC,IAAI,EAAE,MAAM,WAAW,MAAM,UAAU;EACvC,MAAM,eAAe;EACrB,MAAM,OAAO,EAAE,MAAM,MAAO,sBAAsB;EAClD,OAAO,SAAS,QAAQ,KAAK,IAAI,CAAC,MAAM,SAAS,GAAI,GAAG,MAAM,UAAU,KAAK,IAAI;CACnF;CAEA,MAAM,eAAe,OAAO,SAAS,QAAQ,SAAS;CACtD,MAAM,gBAAgB,OAAO,SAAS,QAAQ,SAAS;;CAGvD,IAAI,QAAuD;;CAG3D,SAAS,WAAW,OAAmB;EACrC,MAAM,KAAK,EAAE,MAAM;EACnB,IAAI,MAAM,QAAQ,WAAW,KAAK,CAAC,IAAI,OAAO;EAC9C,MAAM,EAAE,GAAG,GAAG,aAAa,QAAQ,KAAK;EACxC,IAAI,CAAC,GAAG,SAAS,EAAE,MAAc,KAAK,CAAC,GAAG,SAAS,EAAE,MAAc,GAAG,OAAO;EAC7E,QAAQ;GAAE,UAAU,KAAK,IAAI,GAAG,QAAQ;GAAG,UAAU,SAAS;EAAM;EACpE,OAAO;CACT;;CAGA,SAAS,UAAU,OAAmB;EACpC,IAAI,CAAC,SAAS,MAAM,QAAQ,WAAW,GAAG,OAAO;EACjD,MAAM,eAAe;EACrB,MAAM,EAAE,GAAG,GAAG,aAAa,QAAQ,KAAK;EACxC,MAAM,OAAO,EAAE,MAAM,MAAO,sBAAsB;EAClD,OAAO,MAAM,YAAY,WAAW,MAAM,YAAY,EAAE,UAAU,EAAE,WAAW,IAAI,KAAK,IAAI;EAC5F,OAAO;CACT;CAEA,SAAS,SAAS,OAAmB;EACnC,IAAI,MAAM,QAAQ,SAAS,GAAG,QAAQ;CACxC;;CAKA,MAAM,aAAa,gBAAgB;EACjC,OAAO,OAAO,SAAS,WAAW,QAAQ,cAAc,IAAI;EAC5D,KAAK,OAAO,SAAS,WAAW,SAAS,EAAE,UAAU,SAAS,OAAO,cAAc,IAAI;CACzF,EAAE;CAEF,SAAS,MAAM,MAAgB,OAAO,GAAiB;EACrD,MAAM,EAAE,OAAO,QAAQ,WAAW;EAClC,OAAO,aAAa,MAAM,KAAK,IAAI,OAAO,OAAO,KAAK,GAAG,KAAK,EAAE,UAAU,OAAO,IAAI,CAAC,CAAC,KACpF,UAAU;GACT,KAAK,KAAK;GACV,KAAK,KAAK;GACV,MAAM,IAAI,KAAK,KAAK;GACpB,QAAQ,KAAK,MAAM,KAAK,SAAS,IAAI;GACrC,OAAO,UAAU,MAAM,KAAK,OAAO,EAAE,SAAS,OAAO,SAAS,KAAK;EACrE,EACF;CACF;CAEA,MAAM,aAAa,eAAgB,MAAM,MAAM,WAAW,SAAS,SAAS,SAAS,KAAK,IAAI,CAAE;CAChG,MAAM,WAAW,eAAe,MAAM,MAAM,MAAM,GAAG,CAAC;CACtD,MAAM,cAAc,eAAe,MAAM,MAAM,MAAM,QAAQ,WAAW,KAAK,CAAC;;CAG9E,MAAM,SAAS,eAAe;EAC5B,IAAI,SAAS,QAAQ,GAAG,OAAO,CAAC;EAChC,MAAM,EAAE,OAAO,QAAQ,WAAW;EAClC,OAAO,QAAQ,EAAE,SAAS,OAAO,OAAO,KAAK,MAAM,MAAM,SAAS,MAAM,CAAC,CAAC,KAAK,WAAW;GACxF,KAAK,MAAM;GACX,MAAM,IAAI,MAAM,KAAK;GACrB,QAAQ,MAAM,MAAM,MAAM,SAAS,IAAI;EACzC,EAAE;CACJ,CAAC;CAED,MAAM,SAAS,eACb,EAAE,MAAM,KAAK,IAAI,SAAS,OAAO,MAAM,SAAS,IAAI,SAAS,OAAO,MAAM,MACtE,IAAI,IAAI,KAAK,IACb,IACN;;CAGA,MAAM,YAAY,YAChB,UAAU,EAAE,MAAM,MAAO,sBAAsB,CAAC,CAAC,OAAO,EAAE,MAAM,MAAO;CAEzE,SAAS,aAAa,MAAc;EAClC,MAAM,SAAS,UAAU,IAAI;EAC7B,IAAI,QAAQ,aAAa,OAAO,EAAE;CACpC;CAEA,SAAS,gBAAgB;EACvB,aAAa,IAAI,OAAO,EAAE,UAAU,QAAQ,CAAC;CAC/C;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"time-axis.js","names":[],"sources":["../src/time-axis.ts"],"sourcesContent":["import { createScrollLink, scrollPositionOf, useNow, useTouchScroll } from 'dou-ui'\nimport { computed, onMounted, ref, watch, type ComputedRef, type Ref, type ShallowRef } from 'vue'\nimport { offTime, type WorkCalendar } from './core/calendar'\nimport {\n DAY_WIDTH_RANGE,\n hourStep,\n levelByName,\n levelOf,\n unitStart,\n unitsBetween,\n type GanttScale,\n type TimeUnit,\n} from './core/scale'\nimport { MINUTES_PER_DAY, dayStart, parseTime, wallClockNow } from './core/time'\nimport { unitLabel } from './labels'\nimport type { GanttMessages } from './locale'\n\n/** Room around the visible part that is rendered too, in px. */\nconst OVERSCAN_X = 320\n/** The widest a day gets when fitting, so short plans don't zoom to hours. */\nconst FIT_MAX = 64\nconst ZOOM_STEP = 1.5\n/**\n * Room kept before the view on a touch screen, in screens and at least in\n * px, but no more time than `ROOM_BEFORE_TIME`. Time can only be added there\n * once a touch scroll is over, so it is enough for a long run of fast swipes\n * that never lets the momentum stop. Only what is in view is drawn, so room\n * costs nothing but scroll width.\n */\nconst ROOM_BEFORE = 300\nconst ROOM_BEFORE_MIN = 400_000\n/** Ten thousand years, in minutes: room for a run of swipes at the widest scale too. */\nconst ROOM_BEFORE_TIME = 10_000 * 365 * MINUTES_PER_DAY\n/** The earliest the timeline goes, some 190,000 years back, well within what a date can be. */\nconst EARLIEST = -1e11\n/**\n * Room kept before the view with a mouse or trackpad, in screens. It is\n * filled as soon as the view comes near the start, and stays small so the\n * scrollbar thumb still shows where the view is.\n */\nconst ROOM_BEFORE_POINTER = 4\n/** Room kept after the view, in screens; time is added there as you scroll. */\nconst ROOM_AFTER = 4\n\nfunction fingers(event: TouchEvent) {\n const [a, b] = [event.touches[0]!, event.touches[1]!]\n return { a, b, distance: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY) }\n}\n\nexport interface HeaderCell {\n key: number\n end: number\n left: number\n width: number\n label: string\n}\n\nexport interface TimeAxisOptions {\n /** The scrolling timeline. */\n chart: Readonly<ShallowRef<HTMLElement | null>>\n /** The table body, kept at the same vertical scroll. */\n tableBody: Readonly<ShallowRef<HTMLElement | null>>\n viewWidth: Ref<number>\n scale: Ref<GanttScale | undefined>\n range: () => [string, string] | undefined\n today: () => boolean\n weekStart: ComputedRef<0 | 1>\n calendar: ComputedRef<WorkCalendar>\n messages: ComputedRef<GanttMessages>\n /** The time the content covers, or `null` when nothing is scheduled. */\n content: ComputedRef<{ start: number; end: number } | null>\n /** The width the timeline will have once laid out, for fitting. */\n fitWidth: () => number\n}\n\n/**\n * The time axis the gantt chart and the scheduler share: zoom, the extent\n * that grows as you scroll, the header cells, days off and the today line.\n */\nexport function useTimeAxis(o: TimeAxisOptions) {\n /** How wide a day is, in px; zooming changes it smoothly. */\n const dayWidth = ref(levelByName(o.scale.value ?? 'day').base)\n /** Without a `scale`, the first view picks the day width that fits the content. */\n let fitPending = o.scale.value == null\n const level = computed(() => levelOf(dayWidth.value))\n /** px per minute. */\n const ppm = computed(() => dayWidth.value / MINUTES_PER_DAY)\n\n watch(level, (next) => {\n if (o.scale.value !== next.name) o.scale.value = next.name\n })\n // a picked level zooms around now when it is in view, else around the middle\n watch(o.scale, (name) => {\n if (!name || level.value.name === name) return\n const x = todayX.value == null ? null : todayX.value - scrollLeft.value\n zoomTo(levelByName(name).base, x != null && x >= 0 && x <= o.viewWidth.value ? x : undefined)\n })\n\n const nowMs = useNow({ interval: 60_000 })\n const now = computed(() => wallClockNow(new Date(nowMs.value)))\n\n /** The content's time, or the coming month when nothing is scheduled. */\n const content = computed(() => {\n const known = o.content.value\n if (known) return known\n const start = dayStart(now.value)\n return { start, end: start + 30 * MINUTES_PER_DAY }\n })\n\n /** The furthest the view has gone either way, so the timeline keeps it. */\n const reach = ref<{ start: number; end: number } | null>(null)\n\n /** px of room kept before the view. */\n /** Whether there is a touch screen; read once mounted, so the server render matches. */\n const coarse = ref(false)\n const roomBefore = computed(() => {\n const width = o.viewWidth.value || 800\n if (!coarse.value) return ROOM_BEFORE_POINTER * width\n return Math.min(Math.max(ROOM_BEFORE * width, ROOM_BEFORE_MIN), ROOM_BEFORE_TIME * ppm.value)\n })\n\n const touch = useTouchScroll()\n\n /** Where the timeline would start, without a fixed range. */\n const freeStart = computed(() => {\n const start = Math.min(content.value.start, reach.value?.start ?? Infinity)\n return Math.max(EARLIEST, dayStart(start - roomBefore.value / ppm.value))\n })\n\n /**\n * The start held while a touch scroll goes on. A later start moves the\n * content, and the scroll position has to follow it, which iOS drops then:\n * content coming in earlier, the room changing as the screen turns. So the\n * start stays where it was and moves once the scroll is over.\n */\n const heldStart = ref<number | null>(null)\n watch(\n touch.active,\n (on) => {\n heldStart.value = on ? freeStart.value : null\n },\n { flush: 'sync' },\n )\n\n /** The span the timeline covers. */\n const extent = computed(() => {\n const fixed = o.range()?.map((text) => parseTime(text))\n if (fixed?.[0] && fixed[1])\n return { start: dayStart(fixed[0].at), end: dayStart(fixed[1].at) + MINUTES_PER_DAY }\n const width = o.viewWidth.value || 800\n const after = Math.max((ROOM_AFTER * width) / ppm.value, 7 * MINUTES_PER_DAY)\n const end = Math.max(content.value.end, reach.value?.end ?? -Infinity)\n return {\n start: heldStart.value ?? freeStart.value,\n end: dayStart(end + after) + MINUTES_PER_DAY,\n }\n })\n const origin = computed(() => extent.value.start)\n const totalWidth = computed(() => Math.ceil((extent.value.end - extent.value.start) * ppm.value))\n const xOf = (at: number) => (at - origin.value) * ppm.value\n\n // Scrolling ---------------------------------------------------------------------\n\n const scrollTop = ref(0)\n const scrollLeft = ref(0)\n /**\n * The time at the left edge of the view. It is what stays put: when the\n * extent grows or the zoom changes, the scroll position follows it.\n */\n const viewStart = ref(0)\n const scrollbar = ref(0)\n\n const link = createScrollLink('y')\n\n function onChartScroll() {\n const el = o.chart.value!\n const body = o.tableBody.value\n // iOS reports positions past either end while the content bounces back\n const { top, left } = scrollPositionOf(el)\n scrollTop.value = top\n scrollLeft.value = left\n viewStart.value = origin.value + left / ppm.value\n if (body) link.follow(el, body)\n grow()\n }\n\n /** Keeps time `at` on the timeline, adding room around it. */\n function keep(at: number, until = at) {\n const known = reach.value\n const start = Math.min(known?.start ?? at, at)\n const end = Math.max(known?.end ?? until, until)\n if (known?.start !== start || known.end !== end) reach.value = { start, end }\n }\n\n /**\n * Adds time at the end the view comes near. After the end that is safe at\n * any time. Before the start it moves the content right, and the scroll\n * position has to follow it; iOS drops that move while a touch scroll or\n * its momentum goes on, and the next scroll event would read the old\n * position against the new start. So the room before is wide enough for a\n * run of swipes, and is filled again once the scroll is over.\n */\n function grow() {\n const el = o.chart.value\n if (!el || o.range()) return\n const width = o.viewWidth.value\n const left = scrollPositionOf(el).left\n if (left + width > totalWidth.value - ROOM_AFTER * width)\n keep(viewStart.value, viewStart.value + ((ROOM_AFTER + 1) * width) / ppm.value)\n if (touch.active.value) touch.whenSettled(growBefore)\n // without a finger it is filled right away, but only near the start: a\n // scrollbar thumb dragged there would jump back under the pointer\n else if (left < 2 * width) growBefore()\n }\n\n function growBefore() {\n const el = o.chart.value\n // an end bouncing back reports positions past it\n if (!el || o.range() || el.scrollLeft < 0) return\n if (scrollPositionOf(el).left < roomBefore.value - o.viewWidth.value) keep(viewStart.value)\n }\n\n function onTableScroll() {\n const body = o.tableBody.value!\n const el = o.chart.value\n if (el) link.follow(body, el)\n }\n\n // keep the time at the left edge in place as the axis changes under it\n watch(\n [origin, ppm, totalWidth],\n () => {\n const el = o.chart.value\n if (!el) return\n const target = Math.round((viewStart.value - origin.value) * ppm.value)\n if (Math.abs(el.scrollLeft - target) >= 1) el.scrollLeft = target\n scrollLeft.value = scrollPositionOf(el).left\n },\n { flush: 'post' },\n )\n\n function measureScrollbar() {\n const el = o.chart.value\n if (el) scrollbar.value = el.offsetHeight - el.clientHeight\n }\n\n function scrollToTime(at: number, offset = 48) {\n // start the view on a whole header cell, so its label isn't cut at the edge\n const target = at - offset / ppm.value\n viewStart.value = unitStart(level.value.bottom, target, o.weekStart.value, headerStep.value)\n if (!o.range()) keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value)\n const el = o.chart.value\n if (!el) return\n el.scrollLeft = Math.round((viewStart.value - origin.value) * ppm.value)\n scrollLeft.value = scrollPositionOf(el).left\n }\n\n function fit() {\n const width = o.fitWidth()\n if (!width) return\n const days = Math.max(1, (content.value.end - content.value.start) / MINUTES_PER_DAY)\n dayWidth.value = Math.min(FIT_MAX, Math.max(DAY_WIDTH_RANGE[0], (width - 96) / days))\n scrollToTime(content.value.start)\n }\n\n onMounted(() => {\n coarse.value = window.matchMedia?.('(any-pointer: coarse)').matches ?? false\n measureScrollbar()\n scrollToTime(content.value.start)\n })\n\n /** Fits the content once the timeline has a width, unless a `scale` was given. */\n function fitWhenSized() {\n if (!fitPending || !o.fitWidth() || !o.viewWidth.value) return\n fitPending = false\n fit()\n }\n\n // Zoom --------------------------------------------------------------------------\n\n /** Changes the day width, keeping the time under `anchor` (px from the view's left) in place. */\n function zoomTo(width: number, anchor = o.viewWidth.value / 2) {\n const next = Math.min(DAY_WIDTH_RANGE[1], Math.max(DAY_WIDTH_RANGE[0], width))\n const at = viewStart.value + anchor / ppm.value\n dayWidth.value = next\n viewStart.value = at - anchor / ppm.value\n // what was scrolled past at the old zoom could be very wide at the new one\n if (reach.value && !o.range()) {\n reach.value = null\n keep(viewStart.value, viewStart.value + o.viewWidth.value / ppm.value)\n }\n // a pinch moves the scroll position anyway, so the start moves with it\n if (heldStart.value != null) heldStart.value = freeStart.value\n }\n\n function onWheel(event: WheelEvent) {\n if (!(event.ctrlKey || event.metaKey)) return\n event.preventDefault()\n const rect = o.chart.value!.getBoundingClientRect()\n zoomTo(dayWidth.value * Math.exp(-event.deltaY * 0.01), event.clientX - rect.left)\n }\n\n const zoomIn = () => zoomTo(dayWidth.value * ZOOM_STEP)\n const zoomOut = () => zoomTo(dayWidth.value / ZOOM_STEP)\n\n /** Two fingers on the timeline zoom it, as a held Ctrl and the wheel do. */\n let pinch: { distance: number; dayWidth: number } | null = null\n\n /** Starts a pinch when two fingers rest on the timeline; `true` when one began. */\n function pinchStart(event: TouchEvent) {\n const el = o.chart.value\n if (event.touches.length !== 2 || !el) return false\n const { a, b, distance } = fingers(event)\n if (!el.contains(a.target as Node) || !el.contains(b.target as Node)) return false\n pinch = { distance: Math.max(1, distance), dayWidth: dayWidth.value }\n return true\n }\n\n /** Zooms with the fingers; `true` while a pinch is going on. */\n function pinchMove(event: TouchEvent) {\n if (!pinch || event.touches.length !== 2) return false\n event.preventDefault()\n const { a, b, distance } = fingers(event)\n const rect = o.chart.value!.getBoundingClientRect()\n zoomTo(pinch.dayWidth * (distance / pinch.distance), (a.clientX + b.clientX) / 2 - rect.left)\n return true\n }\n\n function pinchEnd(event: TouchEvent) {\n if (event.touches.length < 2) pinch = null\n }\n\n // What is in view ---------------------------------------------------------------\n\n /**\n * The time in view, with some room either side, but never past either end:\n * what is drawn past the end would widen the timeline, and scrolling on\n * would draw more, so a fixed `range` would scroll on for ever.\n */\n const timeWindow = computed(() => ({\n start: Math.max(extent.value.start, origin.value + (scrollLeft.value - OVERSCAN_X) / ppm.value),\n end: Math.min(\n extent.value.end,\n origin.value + (scrollLeft.value + (o.viewWidth.value || 800) + OVERSCAN_X) / ppm.value,\n ),\n }))\n\n function cells(unit: TimeUnit, step = 1): HeaderCell[] {\n const { start, end } = timeWindow.value\n return unitsBetween(unit, start, end, o.weekStart.value, step).map((cell) => ({\n key: cell.start,\n end: cell.end,\n left: xOf(cell.start),\n // a cell that runs past the end stops there\n width: (Math.min(cell.end, extent.value.end) - cell.start) * ppm.value,\n label: unitLabel(unit, cell.start, o.messages.value, dayWidth.value),\n }))\n }\n\n const headerStep = computed(() => (level.value.bottom === 'hour' ? hourStep(dayWidth.value) : 1))\n const topCells = computed(() => cells(level.value.top))\n const bottomCells = computed(() => cells(level.value.bottom, headerStep.value))\n\n /** Days off, shaded; at hour level the hours outside work too. */\n const shaded = computed(() => {\n if (dayWidth.value < 8) return []\n const { start, end } = timeWindow.value\n return offTime(o.calendar.value, start, end, level.value.name === 'hour').map((range) => ({\n key: range.start,\n left: xOf(range.start),\n width: (range.end - range.start) * ppm.value,\n }))\n })\n\n const todayX = computed(() =>\n o.today() && now.value >= extent.value.start && now.value <= extent.value.end\n ? xOf(now.value)\n : null,\n )\n\n /** A pointer's x on screen as timeline px. */\n const contentX = (clientX: number) =>\n clientX - o.chart.value!.getBoundingClientRect().left + o.chart.value!.scrollLeft\n\n function scrollToDate(date: string) {\n const parsed = parseTime(date)\n if (parsed) scrollToTime(parsed.at)\n }\n\n function scrollToToday() {\n scrollToTime(now.value, o.viewWidth.value / 3)\n }\n\n return {\n dayWidth,\n level,\n ppm,\n now,\n extent,\n origin,\n totalWidth,\n xOf,\n contentX,\n scrollTop,\n scrollLeft,\n scrollbar,\n measureScrollbar,\n onChartScroll,\n onTableScroll,\n scrollToTime,\n scrollToDate,\n scrollToToday,\n fit,\n fitWhenSized,\n zoomTo,\n zoomIn,\n zoomOut,\n onWheel,\n pinchStart,\n pinchMove,\n pinchEnd,\n timeWindow,\n topCells,\n bottomCells,\n shaded,\n todayX,\n }\n}\n\nexport type TimeAxis = ReturnType<typeof useTimeAxis>\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dou-ui/gantt",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.1",
4
4
  "description": "DouUI 的甘特图:任务排期、依赖与工作日历",
5
5
  "keywords": [
6
6
  "vue",
@@ -59,7 +59,7 @@
59
59
  "build": "vite build && vue-tsc -p tsconfig.build.json && bun scripts/build-style.ts"
60
60
  },
61
61
  "peerDependencies": {
62
- "dou-ui": "0.1.0-alpha.0",
62
+ "dou-ui": "0.1.0-alpha.1",
63
63
  "vue": "^3.5.0",
64
64
  "yjs": "^13.6.0"
65
65
  },
@@ -69,7 +69,7 @@
69
69
  }
70
70
  },
71
71
  "dependencies": {
72
- "@dou-ui/icons": "0.1.0-alpha.0"
72
+ "@dou-ui/icons": "0.1.0-alpha.1"
73
73
  },
74
74
  "devDependencies": {
75
75
  "y-protocols": "^1.0.7",