@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 +1 -1
- package/dist/time-axis.js +9 -5
- package/dist/time-axis.js.map +1 -1
- package/package.json +3 -3
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
|
-
/**
|
|
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,
|
|
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
|
}
|
package/dist/time-axis.js.map
CHANGED
|
@@ -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":"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"}
|
|
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.
|
|
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.
|
|
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.
|
|
72
|
+
"@dou-ui/icons": "0.1.0-alpha.1"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"y-protocols": "^1.0.7",
|