@editora/ui-core 0.1.24 → 0.1.25
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/README.md +215 -5
- package/dist/components/gantt-schedule.d.ts +79 -0
- package/dist/components/gantt-schedule.d.ts.map +1 -0
- package/dist/components/ui-gantt.d.ts +186 -2
- package/dist/components/ui-gantt.d.ts.map +1 -1
- package/dist/gantt.cjs.js +519 -104
- package/dist/gantt.esm.js +1876 -371
- package/package.json +1 -1
package/dist/gantt.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const Ee=require("./ElementBase-DxbvhLJs.js");function H(n,t){const e=new Date(n);return e.setDate(e.getDate()+t),e.setHours(0,0,0,0),e.getTime()}function wt(n,t){return Math.round((t-n)/864e5)}function le(n){const t=new Set(n.map(r=>r.id)),e=new Map;for(const r of n){if(!r.parent||!t.has(r.parent)||r.parent===r.id)continue;const i=e.get(r.parent)||[];i.push(r),e.set(r.parent,i)}return e}function de(n,t){const e=le(n),r=[],i=new Set([t]),a=[t];for(;a.length;)for(const s of e.get(a.shift())||[])i.has(s.id)||(i.add(s.id),r.push(s),a.push(s.id));return r}function Te(n){const t=le(n),e=new Map,r=new Set,i=a=>{const s=e.get(a.id);if(s)return s;const o={start:a.start,end:a.end,progress:a.progress},c=t.get(a.id);if(!c?.length||r.has(a.id))return o;r.add(a.id);let h=1/0,d=-1/0,g=0,u=0;for(const m of c){const p=i(m);if(h=Math.min(h,p.start),d=Math.max(d,p.end),p.progress!=null){const k=Math.max(1,wt(p.start,p.end));g+=k,u+=p.progress*k}}r.delete(a.id);const b={start:h,end:d,progress:g?u/g:void 0};return e.set(a.id,b),b};for(const a of n)i(a);return e}function Bt(n,t){const e=n.type==="e2s"||n.type==="e2e"?t.end:t.start;return{side:n.type==="e2s"||n.type==="s2s"?"start":"end",min:H(e,n.lag)}}function Ae(n,t,e){const r=Bt(n,t);return(r.side==="start"?e.start:e.end)>=r.min}function Le(n,t){const e=new Map(n.map(i=>[i.id,i])),r=new Set;for(const i of t){const a=e.get(i.source),s=e.get(i.target);a&&s&&!Ae(i,a,s)&&r.add(i.id)}return r}function Ie(n,t,e,r=!1){const i=new Map(n.map(u=>[u.id,{start:u.start,end:u.end}]));for(const[u,b]of e)i.has(u)&&i.set(u,{...b});const a=new Map(n.map(u=>[u.id,u])),s=new Map;for(const u of t){const b=s.get(u.source)||[];b.push(u),s.set(u.source,b)}const o=new Set,c=new Map,h=[...e.keys()],d=(u,b)=>{const m=i.get(u);m&&(i.set(u,{start:H(m.start,b),end:H(m.end,b)}),o.add(u))};for(;h.length;){const u=h.shift(),b=i.get(u);if(b)for(const m of s.get(u)||[]){const p=a.get(m.target),k=i.get(m.target);if(!p||!k||p.readonly)continue;const y=Bt(m,b),w=y.side==="start"?k.start:k.end;if(w>=y.min)continue;const x=(c.get(m.target)||0)+1;if(x>n.length)continue;c.set(m.target,x);const M=wt(w,y.min);if(d(m.target,M),h.push(m.target),r)for(const T of de(n,m.target))T.readonly||(d(T.id,M),h.push(T.id))}}const g=[];for(const u of o){const b=i.get(u),m=e.get(u);(!m||m.start!==b.start||m.end!==b.end)&&g.push({id:u,...b})}return g}function ze(n,t){const e=new Set(n.map(p=>p.parent).filter(p=>!!p)),r=new Map(n.filter(p=>!e.has(p.id)).map(p=>[p.id,p])),i=t.filter(p=>r.has(p.source)&&r.has(p.target)&&p.source!==p.target);if(!i.length)return new Set;const a=p=>wt(p.start,p.end),s=Math.max(...[...r.values()].map(p=>p.end)),o=new Map,c=new Map;for(const p of i)o.set(p.source,[...o.get(p.source)||[],p]),c.set(p.target,[...c.get(p.target)||[],p]);const h=new Map([...r.keys()].map(p=>[p,s])),d=new Map([...r.keys()].map(p=>[p,(o.get(p)||[]).length])),g=[...r.keys()].filter(p=>d.get(p)===0),u=new Set;for(;g.length;){const p=g.shift();u.add(p);const k=r.get(p),y=h.get(p),w=H(y,-a(k));for(const x of c.get(p)||[]){const M=r.get(x.source),T=-x.lag,z=x.type==="e2s"?H(w,T):x.type==="s2s"?H(H(w,T),a(M)):x.type==="e2e"?H(y,T):H(H(y,T),a(M));h.set(x.source,Math.min(h.get(x.source),z));const U=d.get(x.source)-1;d.set(x.source,U),U===0&&g.push(x.source)}}const b=new Set;for(const p of i){const k=r.get(p.source),y=r.get(p.target),w=Bt(p,k);(w.side==="start"?y.start:y.end)===w.min&&b.add(p.target)}const m=new Set;for(const p of u){const k=r.get(p),y=(o.get(p)||[]).length+(c.get(p)||[]).length>0,w=wt(k.end,h.get(p));y&&w<=0&&(!(c.get(p)||[]).length||b.has(p))&&m.add(p)}return m}const D=1440*60*1e3,S=42,N=62,Tt=376,ce="minmax(170px, 1fr) 82px 80px 44px",Ce=640,De=148,Fe=2,vt=28,Re=15,he=Re*Math.SQRT2/2,Jt={day:36,week:13,month:4.4,quarter:2.2,year:1.15},Gt=`
|
|
2
2
|
:host {
|
|
3
3
|
--ui-gantt-bg: color-mix(in srgb, var(--ui-color-surface, #ffffff) 96%, transparent);
|
|
4
4
|
--ui-gantt-panel: var(--ui-color-surface, #ffffff);
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.frame {
|
|
24
|
+
container: ui-gantt / inline-size;
|
|
24
25
|
border: 1px solid var(--ui-gantt-border);
|
|
25
26
|
border-radius: 12px;
|
|
26
27
|
background: var(--ui-gantt-bg);
|
|
@@ -60,7 +61,9 @@
|
|
|
60
61
|
|
|
61
62
|
.control,
|
|
62
63
|
.select,
|
|
63
|
-
.zoom-button
|
|
64
|
+
.zoom-button,
|
|
65
|
+
.today-button,
|
|
66
|
+
.add-button {
|
|
64
67
|
border: 1px solid var(--ui-gantt-border);
|
|
65
68
|
background: var(--ui-gantt-panel);
|
|
66
69
|
color: var(--ui-gantt-text);
|
|
@@ -80,11 +83,18 @@
|
|
|
80
83
|
min-inline-size: 118px;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
.zoom-button
|
|
86
|
+
.zoom-button,
|
|
87
|
+
.today-button,
|
|
88
|
+
.add-button {
|
|
84
89
|
padding: 0 9px;
|
|
85
90
|
cursor: pointer;
|
|
86
91
|
}
|
|
87
92
|
|
|
93
|
+
.today-button:disabled {
|
|
94
|
+
opacity: 0.45;
|
|
95
|
+
cursor: default;
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
.zoom-button[aria-pressed="true"] {
|
|
89
99
|
border-color: color-mix(in srgb, var(--ui-gantt-accent) 46%, var(--ui-gantt-border));
|
|
90
100
|
background: color-mix(in srgb, var(--ui-gantt-accent) 10%, var(--ui-gantt-panel));
|
|
@@ -96,19 +106,67 @@
|
|
|
96
106
|
max-block-size: var(--ui-gantt-max-height, 620px);
|
|
97
107
|
}
|
|
98
108
|
|
|
109
|
+
/* fill: the chart takes the height of its container (which needs one): the toolbar keeps its height and the
|
|
110
|
+
scroll area takes the rest, however tall. */
|
|
111
|
+
:host([fill]) {
|
|
112
|
+
block-size: 100%;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
:host([fill]) .frame {
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
block-size: 100%;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
:host([fill]) .toolbar {
|
|
122
|
+
flex: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
:host([fill]) .viewport {
|
|
126
|
+
flex: 1 1 0;
|
|
127
|
+
min-block-size: 0;
|
|
128
|
+
max-block-size: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
99
131
|
.surface {
|
|
132
|
+
--gantt-grid-w: ${Tt}px;
|
|
133
|
+
--gantt-cols: ${ce};
|
|
100
134
|
display: grid;
|
|
101
|
-
grid-template-columns:
|
|
135
|
+
grid-template-columns: var(--gantt-grid-w) minmax(640px, 1fr);
|
|
102
136
|
min-inline-size: 100%;
|
|
103
137
|
}
|
|
104
138
|
|
|
139
|
+
/* The task grid is sticky, so at 376px it covers a phone-sized chart completely and no bar can be
|
|
140
|
+
reached. In a narrow host keep only the task name column and give the timeline the room. */
|
|
141
|
+
@container ui-gantt (max-width: 640px) {
|
|
142
|
+
.surface {
|
|
143
|
+
--gantt-grid-w: 148px;
|
|
144
|
+
--gantt-cols: minmax(0, 1fr);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.splitter-rail {
|
|
148
|
+
display: none;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* !important: the sortable header wrappers carry an inline display: contents. */
|
|
152
|
+
.grid-head > :nth-child(n + 2),
|
|
153
|
+
.grid-cell:nth-child(n + 2) {
|
|
154
|
+
display: none !important;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.grid-cell.task-name {
|
|
158
|
+
padding-inline-end: 6px;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
105
162
|
.grid-head,
|
|
106
163
|
.timeline-head {
|
|
107
164
|
position: sticky;
|
|
108
165
|
top: 0;
|
|
109
166
|
z-index: 4;
|
|
110
167
|
min-block-size: 62px;
|
|
111
|
-
|
|
168
|
+
/* Opaque: the rows scroll underneath, and at 96% they showed through as a ghost of the text. */
|
|
169
|
+
background: var(--ui-gantt-panel);
|
|
112
170
|
border-bottom: 1px solid var(--ui-gantt-border);
|
|
113
171
|
}
|
|
114
172
|
|
|
@@ -127,7 +185,7 @@
|
|
|
127
185
|
left: 0;
|
|
128
186
|
z-index: 5;
|
|
129
187
|
display: grid;
|
|
130
|
-
grid-template-columns:
|
|
188
|
+
grid-template-columns: var(--gantt-cols);
|
|
131
189
|
border-right: 1px solid var(--ui-gantt-border);
|
|
132
190
|
}
|
|
133
191
|
|
|
@@ -183,15 +241,79 @@
|
|
|
183
241
|
min-block-size: 62px;
|
|
184
242
|
}
|
|
185
243
|
|
|
244
|
+
.band {
|
|
245
|
+
position: absolute;
|
|
246
|
+
inset-inline: 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.band.top {
|
|
250
|
+
inset-block-start: 0;
|
|
251
|
+
block-size: 26px;
|
|
252
|
+
border-bottom: 1px solid var(--ui-gantt-grid);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.band.bottom {
|
|
256
|
+
inset-block-start: 26px;
|
|
257
|
+
block-size: 36px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.scale[data-zoom="year"] .band.bottom {
|
|
261
|
+
inset-block-start: 0;
|
|
262
|
+
block-size: 62px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.band-cell,
|
|
186
266
|
.tick {
|
|
187
267
|
position: absolute;
|
|
188
268
|
inset-block: 0;
|
|
269
|
+
display: flex;
|
|
270
|
+
align-items: center;
|
|
271
|
+
overflow: hidden;
|
|
189
272
|
border-left: 1px solid var(--ui-gantt-grid);
|
|
190
|
-
padding:
|
|
273
|
+
padding: 0 8px;
|
|
191
274
|
color: var(--ui-gantt-muted);
|
|
192
275
|
font-size: 11px;
|
|
193
276
|
font-weight: 650;
|
|
194
277
|
white-space: nowrap;
|
|
278
|
+
text-overflow: ellipsis;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.band-cell {
|
|
282
|
+
color: var(--ui-gantt-text);
|
|
283
|
+
font-weight: 700;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Labels sit at the top of their row so the today pill has the bottom of it to itself. */
|
|
287
|
+
.band.bottom .tick {
|
|
288
|
+
align-items: flex-start;
|
|
289
|
+
padding-block-start: 6px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.scale[data-zoom="year"] .tick {
|
|
293
|
+
padding-block-start: 9px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.tick.day {
|
|
297
|
+
flex-direction: column;
|
|
298
|
+
justify-content: flex-start;
|
|
299
|
+
gap: 1px;
|
|
300
|
+
padding: 3px 0 0;
|
|
301
|
+
line-height: 1.15;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.tick .dow {
|
|
305
|
+
font-size: 9px;
|
|
306
|
+
font-weight: 600;
|
|
307
|
+
opacity: 0.8;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.tick .num {
|
|
311
|
+
font-variant-numeric: tabular-nums;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.tick.today-cell {
|
|
315
|
+
color: var(--ui-gantt-accent);
|
|
316
|
+
background: color-mix(in srgb, var(--ui-gantt-accent) 9%, transparent);
|
|
195
317
|
}
|
|
196
318
|
|
|
197
319
|
.grid-body {
|
|
@@ -204,24 +326,165 @@
|
|
|
204
326
|
|
|
205
327
|
.timeline-body {
|
|
206
328
|
position: relative;
|
|
329
|
+
/* grid lines can run a scrollbar's width past the track; clip them, and keep y visible for drag tips */
|
|
330
|
+
overflow-x: clip;
|
|
207
331
|
background:
|
|
208
332
|
linear-gradient(to right, var(--ui-gantt-grid) 1px, transparent 1px) 0 0 / var(--day-width) 100%,
|
|
209
333
|
color-mix(in srgb, var(--ui-gantt-panel) 98%, transparent);
|
|
210
334
|
}
|
|
211
335
|
|
|
336
|
+
/* The task list can be resized: a handle on its right edge, in the header and down the body. They are grid items
|
|
337
|
+
of their own, in the cells of the header and the body, so the sticky grid underneath stays a plain treegrid. */
|
|
338
|
+
.splitter-rail {
|
|
339
|
+
position: sticky;
|
|
340
|
+
left: 0;
|
|
341
|
+
grid-column: 1;
|
|
342
|
+
z-index: 4;
|
|
343
|
+
pointer-events: none;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.splitter-rail.head {
|
|
347
|
+
grid-row: 1;
|
|
348
|
+
top: 0;
|
|
349
|
+
z-index: 6;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.splitter-rail.body {
|
|
353
|
+
grid-row: 2;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.splitter {
|
|
357
|
+
position: absolute;
|
|
358
|
+
inset-block: 0;
|
|
359
|
+
inset-inline-end: -4px;
|
|
360
|
+
inline-size: 8px;
|
|
361
|
+
cursor: col-resize;
|
|
362
|
+
pointer-events: auto;
|
|
363
|
+
touch-action: none;
|
|
364
|
+
outline: 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.splitter::after {
|
|
368
|
+
content: "";
|
|
369
|
+
position: absolute;
|
|
370
|
+
inset-block: 0;
|
|
371
|
+
inset-inline-start: 3px;
|
|
372
|
+
inline-size: 2px;
|
|
373
|
+
background: transparent;
|
|
374
|
+
transition: background 120ms ease;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.splitter:hover::after,
|
|
378
|
+
.splitter.dragging::after,
|
|
379
|
+
.splitter:focus-visible::after {
|
|
380
|
+
background: var(--ui-gantt-accent);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.timeline-body[data-zoom="month"],
|
|
384
|
+
.timeline-body[data-zoom="quarter"],
|
|
385
|
+
.timeline-body[data-zoom="year"] {
|
|
386
|
+
background: color-mix(in srgb, var(--ui-gantt-panel) 98%, transparent);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* Non-working days: a tint behind the rows, a warmer one for a holiday. */
|
|
390
|
+
.off-day {
|
|
391
|
+
position: absolute;
|
|
392
|
+
inset-block: 0;
|
|
393
|
+
background: color-mix(in srgb, var(--ui-gantt-muted) 11%, transparent);
|
|
394
|
+
pointer-events: none;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.off-day.holiday {
|
|
398
|
+
background: color-mix(in srgb, var(--ui-color-warning, #d97706) 15%, transparent);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.tick.off {
|
|
402
|
+
background: color-mix(in srgb, var(--ui-gantt-muted) 9%, transparent);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* The dots beside a bar that start a link (the linkable attribute), shown with the row's hover or focus. */
|
|
406
|
+
.connector {
|
|
407
|
+
position: absolute;
|
|
408
|
+
top: 15px;
|
|
409
|
+
inline-size: 12px;
|
|
410
|
+
block-size: 12px;
|
|
411
|
+
border: 2px solid var(--ui-gantt-accent);
|
|
412
|
+
border-radius: 50%;
|
|
413
|
+
background: var(--ui-gantt-panel);
|
|
414
|
+
cursor: crosshair;
|
|
415
|
+
opacity: 0;
|
|
416
|
+
z-index: 3;
|
|
417
|
+
touch-action: none;
|
|
418
|
+
transition: opacity 120ms ease;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.timeline-row:hover .connector,
|
|
422
|
+
.timeline-row:focus-within .connector,
|
|
423
|
+
.frame[data-linking] .connector {
|
|
424
|
+
opacity: 1;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.link-draft {
|
|
428
|
+
fill: none;
|
|
429
|
+
stroke: var(--ui-gantt-accent);
|
|
430
|
+
stroke-width: 2;
|
|
431
|
+
stroke-dasharray: 5 3;
|
|
432
|
+
stroke-linecap: round;
|
|
433
|
+
pointer-events: none;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.bar.link-target {
|
|
437
|
+
outline: 2px solid var(--ui-gantt-accent);
|
|
438
|
+
outline-offset: 2px;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.bar.link-target[data-link-side="start"] {
|
|
442
|
+
box-shadow: inset 7px 0 0 var(--ui-gantt-accent);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.bar.link-target[data-link-side="end"] {
|
|
446
|
+
box-shadow: inset -7px 0 0 var(--ui-gantt-accent);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.links path.selected:not(.link-hit) {
|
|
450
|
+
stroke: var(--ui-gantt-accent);
|
|
451
|
+
stroke-width: 2.4;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.links path.link-hit {
|
|
455
|
+
outline: 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.unit-line {
|
|
459
|
+
position: absolute;
|
|
460
|
+
inset-block: 0;
|
|
461
|
+
inline-size: 1px;
|
|
462
|
+
background: color-mix(in srgb, var(--ui-gantt-border) 90%, transparent);
|
|
463
|
+
pointer-events: none;
|
|
464
|
+
}
|
|
465
|
+
|
|
212
466
|
.grid-row,
|
|
213
467
|
.timeline-row {
|
|
214
|
-
block-size: ${
|
|
468
|
+
block-size: ${S}px;
|
|
215
469
|
border-bottom: 1px solid color-mix(in srgb, var(--ui-gantt-border) 56%, transparent);
|
|
216
470
|
}
|
|
217
471
|
|
|
218
472
|
.grid-row {
|
|
219
473
|
display: grid;
|
|
220
|
-
grid-template-columns:
|
|
474
|
+
grid-template-columns: var(--gantt-cols);
|
|
221
475
|
color: var(--ui-gantt-text);
|
|
222
476
|
font-size: 12px;
|
|
223
477
|
}
|
|
224
478
|
|
|
479
|
+
.grid-row {
|
|
480
|
+
outline: 0;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.grid-row:focus-visible {
|
|
484
|
+
outline: 2px solid var(--ui-gantt-accent);
|
|
485
|
+
outline-offset: -2px;
|
|
486
|
+
}
|
|
487
|
+
|
|
225
488
|
.grid-row.selected,
|
|
226
489
|
.timeline-row.selected {
|
|
227
490
|
background: var(--ui-gantt-selected);
|
|
@@ -251,6 +514,20 @@
|
|
|
251
514
|
color: var(--ui-gantt-accent);
|
|
252
515
|
}
|
|
253
516
|
|
|
517
|
+
.rename {
|
|
518
|
+
flex: 1 1 auto;
|
|
519
|
+
min-inline-size: 0;
|
|
520
|
+
block-size: 26px;
|
|
521
|
+
padding: 0 6px;
|
|
522
|
+
border: 1px solid var(--ui-gantt-accent);
|
|
523
|
+
border-radius: 6px;
|
|
524
|
+
background: var(--ui-gantt-panel);
|
|
525
|
+
color: var(--ui-gantt-text);
|
|
526
|
+
font: inherit;
|
|
527
|
+
font-weight: 650;
|
|
528
|
+
outline: 0;
|
|
529
|
+
}
|
|
530
|
+
|
|
254
531
|
.name-text {
|
|
255
532
|
overflow: hidden;
|
|
256
533
|
text-overflow: ellipsis;
|
|
@@ -321,13 +598,15 @@
|
|
|
321
598
|
overflow: visible;
|
|
322
599
|
}
|
|
323
600
|
|
|
324
|
-
|
|
601
|
+
/* A split bar shows the progress of each part, inside the part, and not one fill across the gaps. */
|
|
602
|
+
.bar.split > .progress {
|
|
325
603
|
display: none;
|
|
326
604
|
}
|
|
327
605
|
|
|
328
606
|
.split-segment {
|
|
329
607
|
position: absolute;
|
|
330
608
|
inset-block: 0;
|
|
609
|
+
overflow: hidden;
|
|
331
610
|
border-radius: 4px;
|
|
332
611
|
background:
|
|
333
612
|
linear-gradient(180deg, color-mix(in srgb, #ffffff 22%, transparent), transparent 42%),
|
|
@@ -401,13 +680,33 @@
|
|
|
401
680
|
display: none;
|
|
402
681
|
}
|
|
403
682
|
|
|
683
|
+
/* The done part of a bar: a solid, darker shade of the bar's tone with a light edge where it stops, so
|
|
684
|
+
the amount is readable from the bar itself and not only from the % column. */
|
|
404
685
|
.progress {
|
|
405
686
|
position: absolute;
|
|
406
687
|
inset-block: 0;
|
|
407
688
|
inset-inline-start: 0;
|
|
408
|
-
background: linear-gradient(90deg, color-mix(in srgb, #000 22%, transparent), transparent);
|
|
409
|
-
opacity: 0.3;
|
|
410
689
|
inline-size: var(--progress, 0%);
|
|
690
|
+
background:
|
|
691
|
+
linear-gradient(180deg, color-mix(in srgb, #ffffff 16%, transparent), transparent 46%),
|
|
692
|
+
color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 58%, #0b1220);
|
|
693
|
+
box-shadow: inset -2px 0 0 color-mix(in srgb, #ffffff 62%, transparent);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.bar.complete .progress,
|
|
697
|
+
.progress.full {
|
|
698
|
+
box-shadow: none;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.bar.summary .progress {
|
|
702
|
+
background: color-mix(in srgb, #0b1220 58%, transparent);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
:host([bar-variant="soft"]) .bar.task .progress {
|
|
706
|
+
background:
|
|
707
|
+
linear-gradient(180deg, color-mix(in srgb, #ffffff 24%, transparent), transparent 46%),
|
|
708
|
+
color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 62%, var(--ui-gantt-panel));
|
|
709
|
+
box-shadow: inset -2px 0 0 color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 85%, transparent);
|
|
411
710
|
}
|
|
412
711
|
|
|
413
712
|
.handle {
|
|
@@ -452,28 +751,75 @@
|
|
|
452
751
|
opacity: 1;
|
|
453
752
|
}
|
|
454
753
|
|
|
455
|
-
|
|
754
|
+
/* A finger needs the 24px minimum target size, and a touch screen has no hover to reveal the handles:
|
|
755
|
+
task bars grow from 18 to 24px tall (centred on the same line, so links and baselines still meet them),
|
|
756
|
+
the resize handles from 14 to 24px wide and always show their grip. A very short bar keeps a middle to
|
|
757
|
+
grab by giving each handle at most 35% of it. */
|
|
758
|
+
@media (pointer: coarse) {
|
|
759
|
+
.bar.task {
|
|
760
|
+
block-size: 24px;
|
|
761
|
+
top: 9px;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.handle {
|
|
765
|
+
inline-size: min(24px, 35%);
|
|
766
|
+
opacity: 1;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.handle.start::after {
|
|
770
|
+
inset-inline-start: 8px;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.handle.end::after {
|
|
774
|
+
inset-inline-end: 8px;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.connector {
|
|
778
|
+
opacity: 1;
|
|
779
|
+
inline-size: 20px;
|
|
780
|
+
block-size: 20px;
|
|
781
|
+
top: 11px;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/* One tooltip for the whole chart, outside the bars (which clip their children), placed by script. It
|
|
786
|
+
repeats the bar's accessible name, so it is hidden from assistive technology. */
|
|
787
|
+
.bar-tip {
|
|
456
788
|
position: absolute;
|
|
457
|
-
|
|
458
|
-
inset-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
padding:
|
|
462
|
-
border-radius:
|
|
789
|
+
inset-block-start: 0;
|
|
790
|
+
inset-inline-start: 0;
|
|
791
|
+
z-index: 7;
|
|
792
|
+
max-inline-size: 280px;
|
|
793
|
+
padding: 6px 9px;
|
|
794
|
+
border-radius: 8px;
|
|
463
795
|
background: #0f172a;
|
|
464
796
|
color: #f8fafc;
|
|
465
797
|
font-size: 11px;
|
|
466
|
-
|
|
467
|
-
|
|
798
|
+
line-height: 1.4;
|
|
799
|
+
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.28);
|
|
468
800
|
pointer-events: none;
|
|
469
801
|
opacity: 0;
|
|
802
|
+
visibility: hidden;
|
|
803
|
+
transition: opacity 90ms ease;
|
|
470
804
|
}
|
|
471
805
|
|
|
472
|
-
.bar
|
|
806
|
+
.bar-tip[data-open] {
|
|
473
807
|
opacity: 1;
|
|
808
|
+
visibility: visible;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.bar-tip strong {
|
|
812
|
+
display: block;
|
|
813
|
+
font-weight: 750;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.bar-tip span {
|
|
817
|
+
display: block;
|
|
818
|
+
opacity: 0.88;
|
|
474
819
|
}
|
|
475
820
|
|
|
476
|
-
:host([bar-variant="soft"]) .bar.task
|
|
821
|
+
:host([bar-variant="soft"]) .bar.task,
|
|
822
|
+
:host([bar-variant="soft"]) .split-segment {
|
|
477
823
|
background:
|
|
478
824
|
linear-gradient(180deg, color-mix(in srgb, #ffffff 38%, transparent), transparent 46%),
|
|
479
825
|
color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 22%, var(--ui-gantt-panel));
|
|
@@ -492,7 +838,8 @@
|
|
|
492
838
|
0 7px 16px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 16%, transparent);
|
|
493
839
|
}
|
|
494
840
|
|
|
495
|
-
:host([bar-variant="striped"]) .bar.task
|
|
841
|
+
:host([bar-variant="striped"]) .bar.task,
|
|
842
|
+
:host([bar-variant="striped"]) .split-segment {
|
|
496
843
|
background:
|
|
497
844
|
repeating-linear-gradient(135deg, color-mix(in srgb, #ffffff 24%, transparent) 0 7px, transparent 7px 14px),
|
|
498
845
|
var(--tone, var(--ui-gantt-accent));
|
|
@@ -504,7 +851,8 @@
|
|
|
504
851
|
var(--tone, var(--ui-gantt-accent));
|
|
505
852
|
}
|
|
506
853
|
|
|
507
|
-
:host([bar-variant="outline"]) .bar.task
|
|
854
|
+
:host([bar-variant="outline"]) .bar.task,
|
|
855
|
+
:host([bar-variant="outline"]) .split-segment {
|
|
508
856
|
background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 8%, var(--ui-gantt-panel));
|
|
509
857
|
box-shadow:
|
|
510
858
|
inset 0 0 0 1.5px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 72%, transparent),
|
|
@@ -512,8 +860,8 @@
|
|
|
512
860
|
}
|
|
513
861
|
|
|
514
862
|
:host([bar-variant="outline"]) .bar.task .progress {
|
|
515
|
-
background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent))
|
|
516
|
-
|
|
863
|
+
background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 42%, transparent);
|
|
864
|
+
box-shadow: inset -2px 0 0 color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 85%, transparent);
|
|
517
865
|
}
|
|
518
866
|
|
|
519
867
|
:host([bar-variant="outline"]) .milestone-shape {
|
|
@@ -523,7 +871,8 @@
|
|
|
523
871
|
0 7px 16px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 10%, transparent);
|
|
524
872
|
}
|
|
525
873
|
|
|
526
|
-
:host([bar-variant="glass"]) .bar.task
|
|
874
|
+
:host([bar-variant="glass"]) .bar.task,
|
|
875
|
+
:host([bar-variant="glass"]) .split-segment {
|
|
527
876
|
background:
|
|
528
877
|
linear-gradient(180deg, color-mix(in srgb, #ffffff 50%, transparent), color-mix(in srgb, #ffffff 10%, transparent)),
|
|
529
878
|
color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 72%, transparent);
|
|
@@ -541,6 +890,19 @@
|
|
|
541
890
|
backdrop-filter: blur(8px);
|
|
542
891
|
}
|
|
543
892
|
|
|
893
|
+
/* The parts of a split bar carry the variant skin; the bar around them stays empty so the gaps are gaps. */
|
|
894
|
+
:host([bar-variant]) .bar.split {
|
|
895
|
+
background: transparent;
|
|
896
|
+
box-shadow: none;
|
|
897
|
+
backdrop-filter: none;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/* After the variant skins, which draw their own edge: a finished bar or part has no edge to show. */
|
|
901
|
+
:host([bar-variant]) .bar.complete .progress,
|
|
902
|
+
:host([bar-variant]) .bar .progress.full {
|
|
903
|
+
box-shadow: none;
|
|
904
|
+
}
|
|
905
|
+
|
|
544
906
|
.today {
|
|
545
907
|
position: absolute;
|
|
546
908
|
inset-block: 0;
|
|
@@ -550,14 +912,22 @@
|
|
|
550
912
|
pointer-events: none;
|
|
551
913
|
}
|
|
552
914
|
|
|
553
|
-
|
|
554
|
-
|
|
915
|
+
/* In the header, under the unit labels (which sit at the top of their row), centred on the today line
|
|
916
|
+
and kept inside the track at either end. */
|
|
917
|
+
.today-pill {
|
|
555
918
|
position: absolute;
|
|
556
|
-
inset-block-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
919
|
+
inset-block-end: 3px;
|
|
920
|
+
z-index: 3;
|
|
921
|
+
transform: translateX(-50%);
|
|
922
|
+
padding: 0 6px;
|
|
923
|
+
block-size: 14px;
|
|
924
|
+
border-radius: 7px;
|
|
925
|
+
background: var(--ui-color-danger, #dc2626);
|
|
926
|
+
color: #ffffff;
|
|
927
|
+
font-size: 10px;
|
|
560
928
|
font-weight: 750;
|
|
929
|
+
line-height: 14px;
|
|
930
|
+
pointer-events: none;
|
|
561
931
|
}
|
|
562
932
|
|
|
563
933
|
.links {
|
|
@@ -590,6 +960,18 @@
|
|
|
590
960
|
pointer-events: none;
|
|
591
961
|
}
|
|
592
962
|
|
|
963
|
+
/* A dependency whose target starts or ends earlier than the link allows. */
|
|
964
|
+
.links path.violated:not(.link-hit) {
|
|
965
|
+
stroke: var(--ui-color-danger, #dc2626);
|
|
966
|
+
stroke-width: 1.8;
|
|
967
|
+
stroke-dasharray: 5 3;
|
|
968
|
+
marker-end: url(#ui-gantt-arrow-bad);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
.links marker#ui-gantt-arrow-bad path {
|
|
972
|
+
fill: var(--ui-color-danger, #dc2626);
|
|
973
|
+
}
|
|
974
|
+
|
|
593
975
|
.links marker path {
|
|
594
976
|
fill: color-mix(in srgb, var(--ui-gantt-muted) 82%, transparent);
|
|
595
977
|
stroke: none;
|
|
@@ -620,26 +1002,46 @@
|
|
|
620
1002
|
display: none;
|
|
621
1003
|
}
|
|
622
1004
|
|
|
623
|
-
@media (
|
|
624
|
-
.
|
|
625
|
-
|
|
1005
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1006
|
+
.bar,
|
|
1007
|
+
.progress {
|
|
1008
|
+
transition: none !important;
|
|
626
1009
|
}
|
|
1010
|
+
}
|
|
627
1011
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
1012
|
+
/* Print: the whole chart, not a scroll area. Controls and handles are for the screen; the sticky headers stay put on the
|
|
1013
|
+
page; colours print as they are. A wide timeline is cut at the page edge, so print with the fit zoom or use exportSvg(). */
|
|
1014
|
+
@media print {
|
|
1015
|
+
.frame {
|
|
1016
|
+
box-shadow: none;
|
|
1017
|
+
-webkit-print-color-adjust: exact;
|
|
1018
|
+
print-color-adjust: exact;
|
|
631
1019
|
}
|
|
632
1020
|
|
|
633
|
-
.
|
|
634
|
-
.
|
|
635
|
-
|
|
1021
|
+
.controls,
|
|
1022
|
+
.splitter-rail,
|
|
1023
|
+
.connector,
|
|
1024
|
+
.bar-tip,
|
|
1025
|
+
.handle {
|
|
1026
|
+
display: none !important;
|
|
636
1027
|
}
|
|
637
|
-
}
|
|
638
1028
|
|
|
639
|
-
|
|
640
|
-
.
|
|
641
|
-
|
|
642
|
-
|
|
1029
|
+
.viewport,
|
|
1030
|
+
:host([fill]) .viewport {
|
|
1031
|
+
overflow: visible;
|
|
1032
|
+
max-block-size: none;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
.grid-head,
|
|
1036
|
+
.timeline-head,
|
|
1037
|
+
.grid-body,
|
|
1038
|
+
.splitter-rail.head {
|
|
1039
|
+
position: static;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.grid-row,
|
|
1043
|
+
.timeline-row {
|
|
1044
|
+
break-inside: avoid;
|
|
643
1045
|
}
|
|
644
1046
|
}
|
|
645
1047
|
|
|
@@ -662,89 +1064,102 @@
|
|
|
662
1064
|
.bar,
|
|
663
1065
|
.select,
|
|
664
1066
|
.control,
|
|
665
|
-
.zoom-button
|
|
1067
|
+
.zoom-button,
|
|
1068
|
+
.today-button,
|
|
1069
|
+
.add-button {
|
|
1070
|
+
forced-color-adjust: none;
|
|
1071
|
+
box-shadow: none;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.bar-tip {
|
|
666
1075
|
forced-color-adjust: none;
|
|
1076
|
+
background: Canvas;
|
|
1077
|
+
color: CanvasText;
|
|
1078
|
+
border: 1px solid CanvasText;
|
|
667
1079
|
box-shadow: none;
|
|
668
1080
|
}
|
|
669
1081
|
}
|
|
670
|
-
`,mt={default:"var(--ui-color-primary, #2563eb)",info:"var(--ui-color-info, #0e7490)",success:"var(--ui-color-success, #15803d)",warning:"var(--ui-color-warning, #b45309)",danger:"var(--ui-color-danger, #dc2626)"};function b(a){return String(a??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function f(a){if(a instanceof Date){const n=a.getTime();return Number.isFinite(n)?F(n):null}const t=String(a||"").trim(),i=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t);if(i){const n=Number(i[1]),s=Number(i[2]),l=Number(i[3]),p=new Date(n,s-1,l).getTime();return Number.isFinite(p)?F(p):null}const e=Date.parse(t);return Number.isFinite(e)?F(e):null}function F(a){const t=new Date(a);return t.setHours(0,0,0,0),t.getTime()}function x(a,t){return F(a+t*I)}function E(a){const t=new Date(a),i=t.getFullYear(),e=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${i}-${e}-${n}`}function O(a){return new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric"}).format(new Date(a))}function bt(a){return a==="day"||a==="month"||a==="quarter"||a==="year"?a:"week"}function W(a){return a==="start"||a==="end"||a==="label"||a==="progress"?a:"none"}function Dt(a){return a==="soft"||a==="striped"||a==="outline"||a==="glass"?a:"solid"}function Ft(a,t){if(!a)return[];try{const i=JSON.parse(a);return Array.isArray(i)?i.map((e,n)=>{if(!e||typeof e!="object")return null;const s=e,l=String(s.label||s.text||"").trim(),o=f(s.start),p=Number(s.duration);let u=f(s.end);if(u==null&&o!=null&&Number.isFinite(p)&&(u=x(o,Math.max(0,p))),!l||o==null)return null;const d=s.type==="summary"||s.type==="milestone"?s.type:"task",g=d==="milestone"?o:Math.max(u??x(o,1),x(o,1)),c=String(s.id||`task-${n+1}`),m=t.get(c)||{};return{id:c,label:l,start:m.start||E(o),end:m.end||E(g),progress:Number.isFinite(Number(s.progress))?Math.max(0,Math.min(100,Number(s.progress))):void 0,tone:typeof s.tone=="string"?s.tone:void 0,type:d,parent:s.parent!=null?String(s.parent):void 0,open:s.open!==!1,assignee:s.assignee!=null?String(s.assignee):s.owner!=null?String(s.owner):void 0,readonly:s.readonly===!0,baselineStart:s.baselineStart!=null?String(s.baselineStart):void 0,baselineEnd:s.baselineEnd!=null?String(s.baselineEnd):void 0,critical:s.critical===!0,segments:Array.isArray(s.segments)?s.segments:void 0}}).filter(Boolean):[]}catch{return[]}}function Rt(a){if(!a)return[];try{const t=JSON.parse(a);return Array.isArray(t)?t.map((i,e)=>{if(!i||typeof i!="object")return null;const n=i,s=String(n.source||"").trim(),l=String(n.target||"").trim();if(!s||!l)return null;const o=n.type==="s2s"||n.type==="e2e"||n.type==="s2e"?n.type:"e2s";return{id:String(n.id||`link-${e+1}`),source:s,target:l,type:o}}).filter(Boolean):[]}catch{return[]}}function qt(a,t){return t==="none"?a:[...a].sort((i,e)=>{if(t==="label")return i.label.localeCompare(e.label);if(t==="progress")return Number(e.progress??0)-Number(i.progress??0);const n=f(t==="start"?i.start:i.end)??0,s=f(t==="start"?e.start:e.end)??0;return n-s})}function Nt(a,t,i,e){const n=new Map,s=new Map(a.map(d=>[d.id,d]));a.forEach(d=>{const g=d.parent&&s.has(d.parent)?d.parent:"__root__",c=n.get(g)||[];c.push(d),n.set(g,c)});const l=i.trim().toLowerCase(),o=d=>!l||d.label.toLowerCase().includes(l)||(d.assignee||"").toLowerCase().includes(l)?!0:(n.get(d.id)||[]).some(o),p=[],u=(d,g)=>{qt(n.get(d)||[],e).forEach(c=>{if(!o(c))return;const m=f(c.start),h=f(c.end);if(m==null||h==null)return;const w=(n.get(c.id)||[]).length>0;p.push({...c,depth:g,hasChildren:w,startMs:m,endMs:h}),w&&!t.has(c.id)&&u(c.id,g+1)})};return u("__root__",0),p}function Ht(a,t,i,e,n=0,s=Number.POSITIVE_INFINITY){const l=Math.max(1,Math.ceil((t-a)/I)),o=e==="day"?1:e==="week"?7:e==="month"?30:e==="quarter"?91:365,p=Math.max(0,Math.floor(Math.max(0,n-480)/i/o)*o),u=Math.min(l,Math.ceil((n+s+960)/i/o)*o),d=[];for(let g=p;g<=u;g+=o){const c=g*i,m=x(a,g),h=e==="day"?O(m):new Intl.DateTimeFormat(void 0,{month:"short",year:e==="week"||e==="month"?void 0:"numeric"}).format(new Date(m));d.push(`<span class="tick" style="left:${c.toFixed(2)}px">${b(h)}</span>`)}return d.join("")}function H(a){return a.type==="summary"||a.hasChildren?"summary":a.type==="milestone"||a.startMs===a.endMs?"milestone":"task"}function ft(a){const t=H(a);return t==="summary"?17+9/2:t==="milestone"?7+N/2:12+18/2}function _t(a,t){return H(a)==="milestone"?t(a.startMs)-vt:t(a.startMs)}function jt(a,t){return H(a)==="milestone"?t(a.startMs)+vt:t(a.endMs)}function xt(a,t,i){return t==="start"?_t(a,i):jt(a,i)}function Vt(a="e2s"){return a==="s2s"?{source:"start",target:"start"}:a==="e2e"?{source:"end",target:"end"}:a==="s2e"?{source:"start",target:"end"}:{source:"end",target:"start"}}function Wt(a,t,i,e,n,s){const l=Vt(n),o=l.source==="start"?-1:1,p=l.target==="start"?1:-1,u=xt(a,l.source,s),d=xt(i,l.target,s),g=t*y+ft(a),c=e*y+ft(i),m=22,h=u+o*m,w=d-p*m,M=26;let k=(h+w)/2;if(o===p){const T=o===1?Math.max(h,w,u,d)+M:Math.min(h,w,u,d)-M;k=(o===1?w>h+M:w<h-M)?k:T}else(o===1?w<h:w>h)&&(k=o===1?Math.max(h,u,d)+M:Math.min(h,u,d)-M);const A=Math.abs(c-g)<1?l.target==="start"?c-16:c+16:c>g?c-y/2+3:c+y/2-3;return[[u,g],[h,g],[k,g],[k,A],[w,A],[w,c],[d,c]].map(([T,R],P)=>`${P===0?"M":"L"} ${T.toFixed(1)} ${R.toFixed(1)}`).join(" ")}class wt extends At.ElementBase{constructor(){super(...arguments),this.collapsed=new Set,this.overrides=new Map,this.drag=null,this.selectedId=null,this.internalFilter="",this.viewportTop=0,this.viewportLeft=0,this.viewportWidth=1800,this.viewportHeight=620,this.renderedFirstRow=0,this.renderedLastRow=0,this.scrollFrame=null,this.overridesVersion=0,this.taskCacheRaw=null,this.taskCacheVersion=-1,this.taskCache=[],this.linkCacheRaw=null,this.linkCache=[],this.visibleCacheKey="",this.visibleCache=[]}static get observedAttributes(){return["tasks","links","zoom","filter","sort","bar-variant","variant","readonly","show-toolbar","show-today","headless"]}render(){const t=this.getTasks(),i=this.getLinks(),e=bt(this.getAttribute("zoom")),n=W(this.getAttribute("sort")),s=Dt(this.getAttribute("bar-variant")),l=this.getAttribute("filter")??this.internalFilter,o=this.getVisibleTasks(t,l,n),p=this.hasAttribute("readonly"),u=this.getAttribute("show-toolbar")!=="false",d=this.getAttribute("show-today")!=="false";if(!t.length){this.setContent(`
|
|
671
|
-
<style>${
|
|
1082
|
+
`,mt={default:"var(--ui-color-primary, #2563eb)",info:"var(--ui-color-info, #0e7490)",success:"var(--ui-color-success, #15803d)",warning:"var(--ui-color-warning, #b45309)",danger:"var(--ui-color-danger, #dc2626)"};function v(n){return String(n??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function $(n){if(n instanceof Date){const i=n.getTime();return Number.isFinite(i)?Y(i):null}const t=String(n||"").trim(),e=/^(\d{4})-(\d{2})-(\d{2})(?:[T\s].*)?$/.exec(t);if(e){const i=Number(e[1]),a=Number(e[2]),s=Number(e[3]),c=new Date(i,a-1,s).getTime();return Number.isFinite(c)?Y(c):null}const r=Date.parse(t);return Number.isFinite(r)?Y(r):null}function Y(n){const t=new Date(n);return t.setHours(0,0,0,0),t.getTime()}function A(n,t){return Y(n+t*D)}function W(n){const t=new Date(n),e=t.getFullYear(),r=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0");return`${e}-${r}-${i}`}function ht(n){return Z({month:"short",day:"numeric"}).format(new Date(n))}function qe(n){return n==="day"||n==="month"||n==="quarter"||n==="year"||n==="fit"?n:"week"}const Ne=.2,We=48,Be=680,Oe=160,He=7;function Pe(n){return n>=22?"day":n*7>=44?"week":n*30>=44?"month":n*91>=44?"quarter":"year"}function bt(n){return n==="start"||n==="end"||n==="label"||n==="progress"?n:"none"}function _e(n){return n==="soft"||n==="striped"||n==="outline"||n==="glass"?n:"solid"}const Qt=new Date(1970,0,1).getTime();function je(n,t,e=!1){if(!n)return[];try{const r=JSON.parse(n);return Array.isArray(r)?r.map((i,a)=>{if(!i||typeof i!="object")return null;const s=i,o=String(s.label||s.text||"").trim();let c=$(s.start);const h=Number(s.duration);let d=$(s.end);d==null&&c!=null&&Number.isFinite(h)&&(d=A(c,Math.max(0,h)));const g=e&&c==null&&s.type==="summary";if(g&&(c=Qt,d=A(Qt,1)),!o||c==null)return null;const u=s.type==="summary"||s.type==="milestone"?s.type:"task",b=u==="milestone"?c:Math.max(d??A(c,1),A(c,1)),m=String(s.id||`task-${a+1}`),p=t.get(m)||{};return{id:m,label:p.label||o,start:p.start||W(c),end:p.end||W(b),progress:Number.isFinite(Number(s.progress))?Math.max(0,Math.min(100,Number(s.progress))):void 0,tone:typeof s.tone=="string"?s.tone:void 0,type:u,parent:s.parent!=null?String(s.parent):void 0,open:s.open!==!1,assignee:s.assignee!=null?String(s.assignee):s.owner!=null?String(s.owner):void 0,readonly:s.readonly===!0,baselineStart:s.baselineStart!=null?String(s.baselineStart):void 0,baselineEnd:s.baselineEnd!=null?String(s.baselineEnd):void 0,critical:s.critical===!0,undated:g,segments:Array.isArray(s.segments)?s.segments:void 0}}).filter(Boolean):[]}catch{return[]}}function Zt(n){if(!n)return[];try{const t=JSON.parse(n);return Array.isArray(t)?t.map((e,r)=>{if(!e||typeof e!="object")return null;const i=e,a=String(i.source||"").trim(),s=String(i.target||"").trim();if(!a||!s)return null;const o=i.type==="s2s"||i.type==="e2e"||i.type==="s2e"?i.type:"e2s",c=Math.round(Number(i.lag));return{id:String(i.id||`link-${r+1}`),source:a,target:s,type:o,lag:Number.isFinite(c)?c:0}}).filter(Boolean):[]}catch{return[]}}function Ve(n,t){return t==="none"?n:[...n].sort((e,r)=>{if(t==="label")return e.label.localeCompare(r.label);if(t==="progress")return Number(r.progress??0)-Number(e.progress??0);const i=$(t==="start"?e.start:e.end)??0,a=$(t==="start"?r.start:r.end)??0;return i-a})}function Xe(n,t,e,r){const i=new Map,a=new Map(n.map(d=>[d.id,d]));n.forEach(d=>{const g=d.parent&&a.has(d.parent)?d.parent:"__root__",u=i.get(g)||[];u.push(d),i.set(g,u)});const s=e.trim().toLowerCase(),o=d=>!s||d.label.toLowerCase().includes(s)||(d.assignee||"").toLowerCase().includes(s)?!0:(i.get(d.id)||[]).some(o),c=[],h=(d,g)=>{Ve(i.get(d)||[],r).forEach(u=>{if(!o(u))return;const b=$(u.start),m=$(u.end);if(b==null||m==null)return;const p=(i.get(u.id)||[]).length>0;c.push({...u,depth:g,hasChildren:p,startMs:b,endMs:m}),p&&!t.has(u.id)&&h(u.id,g+1)})};return h("__root__",0),c}function Ye(){try{const n=Z({}).resolvedOptions().locale,t=new Intl.Locale(n),e=typeof t.getWeekInfo=="function"?t.getWeekInfo():t.weekInfo;if(e&&Number.isInteger(e.firstDay))return e.firstDay%7}catch{}return 1}function Ft(n){const t=n==null||n===""?NaN:Number(n);return Number.isInteger(t)&&t>=0&&t<=6?t:Ye()}function ue(n,t,e){const r=new Date(n);return r.setHours(0,0,0,0),t==="week"?r.setDate(r.getDate()-(r.getDay()-e+7)%7):t==="month"?r.setDate(1):t==="quarter"?r.setMonth(Math.floor(r.getMonth()/3)*3,1):t==="year"&&r.setMonth(0,1),r.getTime()}function pe(n,t){const e=new Date(n);return t==="day"?e.setDate(e.getDate()+1):t==="week"?e.setDate(e.getDate()+7):t==="month"?e.setMonth(e.getMonth()+1):t==="quarter"?e.setMonth(e.getMonth()+3):e.setFullYear(e.getFullYear()+1),e.getTime()}function kt(n,t,e,r,i,a,s){const o=[],c=e+Math.max(0,a-480)/i*D,h=a+s+960;let d=ue(Math.max(e,c),n,t);for(;d<r;){const g=pe(d,n),u=Math.max(d,e),b=Math.min(g,r),m=(u-e)/D*i;if(m>h)break;b>u&&o.push({left:m,width:(b-u)/D*i,start:d,label:""}),d=g}return o}const Ue={weekdays:new Set,holidays:new Map};function te(n,t){const e=new Set;if(n!=null){const i=n.trim();if(i==="")e.add(0),e.add(6);else{let a=i.split(",");try{const s=JSON.parse(i);Array.isArray(s)?a=s:typeof s=="number"&&(a=[s])}catch{}for(const s of a){const o=Number(typeof s=="string"?s.trim():s);Number.isInteger(o)&&o>=0&&o<=6&&e.add(o)}}}const r=new Map;if(t)try{const i=JSON.parse(t);if(Array.isArray(i))for(const a of i){const s=a&&typeof a=="object"?a:null,o=$(s?s.date:a);o!=null&&r.set(o,s&&typeof s.label=="string"?s.label:"")}}catch{}return{weekdays:e,holidays:r}}function ge(n,t){return t.holidays.has(n)||t.weekdays.has(new Date(n).getDay())}const fe=8;function Ke(n,t,e,r,i,a){if(e<fe||!r.weekdays.size&&!r.holidays.size)return"";const s=Math.max(0,Math.floor(Math.max(0,i-480)/e)),o=Math.min(Math.ceil((t-n)/D),Math.ceil((i+a+960)/e)),c=[];let h=-1,d="";const g=u=>{h>=0&&c.push(`<span class="off-day${d}" style="left:${(h*e).toFixed(2)}px;width:${((u-h)*e).toFixed(2)}px"></span>`),h=-1};for(let u=s;u<o;u+=1){const b=H(n,u),m=r.holidays.has(b)?" holiday":r.weekdays.has(new Date(b).getDay())?"":null;(m===null||h>=0&&m!==d)&&g(u),m!==null&&h<0&&(h=u,d=m)}return g(o),c.join("")}const It=36;function Je(n,t,e,r,i,a=0,s=Number.POSITIVE_INFINITY,o=Ue){const c=Y(Date.now()),h=Z({month:"long",year:"numeric"}),d=Z({month:"short"}),g=Z({weekday:"narrow"}),u=(y,w,x,M="")=>`<span class="${y}" style="left:${w.left.toFixed(2)}px;width:${w.width.toFixed(2)}px"${M?` title="${v(M)}"`:""}>${x}</span>`,m=kt(r,i,n,t,e,a,s).map(y=>{const w=new Date(y.start),x=y.width>=It;if(r==="day"){const M=y.start===c,T=o.holidays.get(y.start);return u(`tick day${M?" today-cell":""}${ge(y.start,o)?" off":""}`,y,`<span class="dow">${v(g.format(w))}</span><span class="num">${w.getDate()}</span>`,T||"")}return r==="week"?u("tick",y,x?`<span class="num">${w.getDate()}</span>`:"",ht(y.start)):r==="month"?u("tick",y,x?v(d.format(w)):"",h.format(w)):r==="quarter"?u("tick",y,x?`Q${Math.floor(w.getMonth()/3)+1}`:"",`Q${Math.floor(w.getMonth()/3)+1} ${w.getFullYear()}`):u("tick",y,x?String(w.getFullYear()):"")}).join("");if(r==="year")return`<div class="band bottom">${m}</div>`;const p=r==="day"||r==="week"?"month":"year";return`<div class="band top">${kt(p,i,n,t,e,a,s).map(y=>{const w=new Date(y.start),x=p==="month"?h.format(w):String(w.getFullYear()),M=y.width<It?"":p==="month"&&y.width<120?d.format(w):x;return u("band-cell",y,v(M),x)}).join("")}</div><div class="band bottom">${m}</div>`}function ee(n){const t=new Set;if(!n)return t;try{const e=JSON.parse(n);Array.isArray(e)&&e.forEach((r,i)=>{r&&typeof r=="object"&&t.add(String(r.id||`task-${i+1}`))})}catch{}return t}function Ge(n,t){for(const e of n)if(t.has(e))return!0;return!1}function Qe(n,t,e,r,i,a,s){return r==="day"?"":kt(r,i,n,t,e,a,s).filter(o=>o.start>=n).map(o=>`<span class="unit-line" style="left:${o.left.toFixed(2)}px"></span>`).join("")}function Ze(n,t){const e=i=>Math.max(0,Math.min(100,i));let r=n.reduce((i,a)=>a.progress==null?i+a.duration:i,0)*(e(t)/100);return n.map(i=>{if(i.progress!=null)return e(i.progress);const a=Math.min(i.duration,r);return r-=a,i.duration>0?a/i.duration*100:0})}function tr(n,t){const e=Math.max(D,n.endMs-n.startMs),r=[];for(const a of n.segments||[]){const s=$(a.start),o=$(a.end);if(s==null||o==null)continue;const c=Math.max(n.startMs,s),h=Math.min(n.endMs,o);if(h<=c)continue;const d=Math.max(0,Math.min(100,(c-n.startMs)/e*100)),g=Math.min(100-d,Math.max(1,(h-c)/e*100));if(g<=0)continue;const u=Number(a.progress);r.push({left:d,width:g,duration:h-c,progress:a.progress!=null&&Number.isFinite(u)?u:void 0})}const i=Ze(r,t);return r.map((a,s)=>`<span class="split-segment" style="left:${a.left.toFixed(2)}%;width:${a.width.toFixed(2)}%"><span class="progress${i[s]>=100?" full":""}" style="--progress:${i[s].toFixed(2)}%"></span></span>`).join("")}function ot(n){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(n):n.replace(/["\\]/g,"\\$&")}function Nt(n){return`.grid-row[data-task-id="${ot(n)}"]`}function At(n){return`.bar[data-task-id="${ot(n)}"]`}function er(n){return n.classList.contains("control")?".control":n.classList.contains("select")?".select":n.classList.contains("zoom-button")&&n.dataset.zoom?`.zoom-button[data-zoom="${ot(n.dataset.zoom)}"]`:n.classList.contains("today-button")?".today-button":n.classList.contains("add-button")?".add-button":n.classList.contains("rename")?".rename":n.classList.contains("head-button")&&n.dataset.sort?`.head-button[data-sort="${ot(n.dataset.sort)}"]`:n.classList.contains("splitter")&&n.getAttribute("role")==="separator"?'.splitter[role="separator"]':n.classList.contains("link-hit")&&n.dataset.linkId?`.link-hit[data-link-id="${ot(n.dataset.linkId)}"]`:n.classList.contains("bar")&&n.dataset.taskId?At(n.dataset.taskId):n.classList.contains("grid-row")&&n.dataset.taskId?Nt(n.dataset.taskId):n.classList.contains("expander")&&n.dataset.taskId?`.expander[data-task-id="${ot(n.dataset.taskId)}"]`:null}const Et={title:"Project schedule",tasksCount:"{shown}/{total} tasks",filterPlaceholder:"Filter tasks",filterLabel:"Filter tasks",sortLabel:"Sort tasks",sortManual:"Manual",sortStart:"Start date",sortEnd:"End date",sortName:"Name",sortProgress:"Progress",zoomDay:"day",zoomWeek:"week",zoomMonth:"month",zoomQuarter:"quarter",zoomYear:"year",zoomFit:"fit",zoomFitTitle:"Fit the whole project to the width",columnTask:"Task",columnOwner:"Owner",columnDates:"Dates",columnProgress:"%",columnStart:"Start",columnEnd:"End",columnDuration:"Days",splitter:"Resize the task list",scrollToToday:"Scroll to today",addTask:"Add task",rename:"Rename task",linkViolated:"dependency not met",empty:"No tasks in this range",noMatches:"No matching tasks",expand:"Expand",collapse:"Collapse",timeline:"Timeline",today:"Today",summary:"summary",milestone:"milestone",to:"to",complete:"complete",assigned:"assigned to",critical:"critical"},Rt={label:{title:"columnTask",sort:"label",width:170},assignee:{title:"columnOwner",width:82},dates:{title:"columnDates",sort:"start",width:80},start:{title:"columnStart",sort:"start",width:74},end:{title:"columnEnd",sort:"end",width:74},duration:{title:"columnDuration",width:56},progress:{title:"columnProgress",sort:"progress",width:44}},rr=["label","assignee","dates","progress"],re=96;function ir(n){let t=rr;if(n)try{const a=JSON.parse(n);Array.isArray(a)&&a.length&&(t=a)}catch{}const e=[],r=new Set;for(const a of t){const s=a&&typeof a=="object"?a:null;let o=typeof a=="string"?a:s?s.key:null;if(o==="owner"&&(o="assignee"),typeof o!="string"||!(o in Rt)||r.has(o))continue;r.add(o);const c=Rt[o],h=s?Number(s.width):NaN;e.push({key:o,title:c.title,custom:s&&typeof s.label=="string"&&s.label?s.label:void 0,sort:c.sort,width:Number.isFinite(h)&&h>=36?Math.min(Math.round(h),400):c.width})}const i=e.findIndex(a=>a.key==="label");return i>0&&e.unshift(e.splice(i,1)[0]),i<0&&e.unshift({key:"label",title:"columnTask",sort:"label",width:Rt.label.width}),e}function nr(n,t){const e=n.slice(1).reduce((a,s)=>a+s.width,0),r=t!=null?re:n[0].width,i=e+re;return{width:t!=null?Math.max(Math.round(t),i):e+n[0].width,min:i,template:n.map((a,s)=>s===0?`minmax(${r}px, 1fr)`:`${a.width}px`).join(" ")}}let Lt;function Z(n){try{return new Intl.DateTimeFormat(Lt,n)}catch{return new Intl.DateTimeFormat(void 0,n)}}function sr(n,t,e,r){const i=e.format(new Date(n.startMs)),a=t==="milestone"?i:`${i} ${r.to} ${e.format(new Date(n.endMs))}`,s=t==="summary"||t==="milestone"?r[t]:"",o=[];return n.progress!=null&&t!=="milestone"&&o.push(`${Math.round(n.progress)}% ${r.complete}`),n.assignee&&o.push(`${r.assigned} ${n.assignee}`),n.critical&&o.push(r.critical),{name:[n.label,s,a,...o].filter(Boolean).join(", "),title:n.label,kindWord:s,when:[s,a].filter(Boolean).join(" · "),more:o.join(" · ")}}function ar(n,t){return{day:t.zoomDay,week:t.zoomWeek,month:t.zoomMonth,quarter:t.zoomQuarter,year:t.zoomYear,fit:t.zoomFit}[n]}function or(n){const t=(n||"").trim();return t==="none"||/^\d*\.?\d+(px|em|rem|vh|dvh|svh|lvh|vw|%|ch)$/.test(t)?t:null}function Wt(n){return{id:n.id,source:n.source,target:n.target,type:n.type||"e2s",lag:n.lag??0}}function ie(n){return n==="auto"||n==="off"?n:"warn"}function yt(n){const t=$(n.start),e=$(n.end);return t==null||e==null?null:{id:n.id,start:t,end:e,parent:n.parent,type:n.type,readonly:n.readonly,progress:n.progress}}function lr(n){const t=Te(n.map(yt).filter(e=>e!=null));return n.map(e=>{const r=t.get(e.id);return r?{...e,undated:!1,start:W(r.start),end:W(r.end),progress:e.progress??r.progress}:e}).filter(e=>!e.undated)}function dr(n,t){const e=ze(n.map(yt).filter(r=>r!=null),t.map(Wt));return e.size?n.map(r=>e.has(r.id)&&!r.critical?{...r,critical:!0}:r):n}function qt(n){if(!n)return[];try{const t=JSON.parse(n);return Array.isArray(t)?t:[]}catch{return[]}}function xt(n){return n instanceof Date?Number.isFinite(n.getTime())?W(n.getTime()):void 0:n}function ne(n,t,e,r){if(!Array.isArray(e)){n.removeAttribute(t);return}const i=r?e.map(a=>{const s={...a};for(const o of["start","end","baselineStart","baselineEnd"])o in s&&(s[o]=xt(s[o]));return Array.isArray(s.segments)&&(s.segments=s.segments.map(o=>({...o,start:xt(o.start),end:xt(o.end)}))),s}):e;try{n.setAttribute(t,JSON.stringify(i))}catch{}}function cr(n){const t=n==null||n===""?NaN:Number(n);return Number.isFinite(t)&&t>0?t:null}function ut(n){return n.type==="summary"||n.hasChildren?"summary":n.type==="milestone"||n.startMs===n.endMs?"milestone":"task"}function se(n){const t=ut(n);return t==="summary"?17+9/2:t==="milestone"?7+vt/2:12+18/2}function hr(n,t){return ut(n)==="milestone"?t(n.startMs)-he:t(n.startMs)}function ur(n,t){return ut(n)==="milestone"?t(n.startMs)+he:t(n.endMs)}function ae(n,t,e){return t==="start"?hr(n,e):ur(n,e)}function pr(n="e2s"){return n==="s2s"?{source:"start",target:"start"}:n==="e2e"?{source:"end",target:"end"}:n==="s2e"?{source:"start",target:"end"}:{source:"end",target:"start"}}function oe(n,t,e,r,i,a){const s=pr(i),o=s.source==="start"?-1:1,c=s.target==="start"?1:-1,h=ae(n,s.source,a),d=ae(e,s.target,a),g=t*S+se(n),u=r*S+se(e),b=22,m=h+o*b,p=d-c*b,k=26;let y=(m+p)/2;if(o===c){const M=o===1?Math.max(m,p,h,d)+k:Math.min(m,p,h,d)-k;y=(o===1?p>m+k:p<m-k)?y:M}else(o===1?p<m:p>m)&&(y=o===1?Math.max(m,h,d)+k:Math.min(m,h,d)-k);const w=Math.abs(u-g)<1?s.target==="start"?u-16:u+16:u>g?u-S/2+3:u+S/2-3;return[[h,g],[m,g],[y,g],[y,w],[p,w],[p,u],[d,u]].map(([M,T],z)=>`${z===0?"M":"L"} ${M.toFixed(1)} ${T.toFixed(1)}`).join(" ")}class me extends Ee.ElementBase{constructor(){super(...arguments),this.focusRequest=null,this.collapsed=new Set,this.seededIds=new Set,this.overrides=new Map,this.drag=null,this.selectedId=null,this.internalFilter="",this.viewportTop=0,this.viewportLeft=0,this.viewportWidth=1800,this.hostWidth=0,this.renderedLeft=0,this.smoothTarget=null,this.selectedLinkId=null,this.linking=null,this.editingId=null,this.editingValue="",this.suppressBlur=!1,this.layoutInfo={min:0,dayWidth:13,gridWidth:Tt,rangeEnd:0},this.visibleIds=[],this.initialScrollPending=!0,this.pendingReveal=null,this.hostHeight=0,this.virtualizedNow=!1,this.gridBounds={min:0,max:0,width:Tt},this.descriptions=new Map,this.tipTimer=null,this.pointerFocus=!1,this.scrollbarWidth=0,this.dayWidthNow=Jt.week,this.resizeObserver=null,this.viewportHeight=620,this.renderedFirstRow=0,this.renderedLastRow=0,this.scrollFrame=null,this.overridesVersion=0,this.taskCacheRaw=null,this.taskCacheVersion=-1,this.taskCacheAuto=!1,this.taskCacheCritical=null,this.taskCache=[],this.linkCacheRaw=null,this.linkCache=[],this.visibleCacheKey="",this.visibleCache=[],this.labelsRaw=null,this.labelsCache=Et}static get observedAttributes(){return["tasks","links","zoom","filter","sort","bar-variant","variant","readonly","show-toolbar","show-today","headless","week-start","labels","locale","columns","grid-width","fill","max-height","snap","creatable","auto-summary","cascade","schedule","critical-path","non-working-days","holidays","linkable"]}connectedCallback(){for(const t of["tasks","links","holidays"])if(Object.prototype.hasOwnProperty.call(this,t)){const e=this[t];delete this[t],this[t]=e}super.connectedCallback(),!(typeof ResizeObserver>"u"||this.resizeObserver)&&(this.resizeObserver=new ResizeObserver(t=>{const e=t[t.length-1]?.contentRect,r=e?.width??0,i=e?.height??0,a=Math.abs(r-this.hostWidth)>=1,s=Math.abs(i-this.hostHeight)>=1&&(this.hasAttribute("fill")||this.virtualizedNow);this.hostHeight=i,!(!a&&!s)&&(a&&(this.hostWidth=Math.round(r)),this.captureViewport(),this.requestRender())}),this.resizeObserver.observe(this))}disconnectedCallback(){this.resizeObserver?.disconnect(),this.resizeObserver=null,this.tipTimer!=null&&window.clearTimeout(this.tipTimer),this.tipTimer=null,super.disconnectedCallback()}labelSet(){const t=this.getAttribute("labels");if(t===this.labelsRaw)return this.labelsCache;if(this.labelsRaw=t,this.labelsCache=Et,t)try{const e=JSON.parse(t);if(e&&typeof e=="object"){const r={...Et};for(const[i,a]of Object.entries(e))i in Et&&typeof a=="string"&&(r[i]=a);this.labelsCache=r}}catch{}return this.labelsCache}render(){this.suppressBlur=!0,queueMicrotask(()=>{this.suppressBlur=!1}),Lt=this.getAttribute("locale")||void 0;const t=this.labelSet(),e=this.getTasks(),r=this.getLinks(),i=qe(this.getAttribute("zoom")),a=bt(this.getAttribute("sort")),s=_e(this.getAttribute("bar-variant")),o=this.getAttribute("filter")??this.internalFilter,c=this.getVisibleTasks(e,o,a),h=this.hasAttribute("readonly"),d=this.hasAttribute("creatable")&&!h,g=this.hasAttribute("cascade"),u=this.hasAttribute("linkable")&&!h,b=this.getAttribute("show-toolbar")!=="false",m=this.getAttribute("show-today")!=="false";if(!e.length){this.setContent(`
|
|
1083
|
+
<style>${Gt}</style>
|
|
672
1084
|
<section class="frame" part="frame">
|
|
673
|
-
<div class="empty" part="empty"
|
|
1085
|
+
<div class="empty" part="empty">${v(t.empty)}</div>
|
|
674
1086
|
</section>
|
|
675
|
-
`);return}const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
<div class="grid-cell badge" role="gridcell">${b(r.assignee||D)}</div>
|
|
682
|
-
<div class="grid-cell badge" role="gridcell">${b(U)}</div>
|
|
683
|
-
<div class="grid-cell badge" role="gridcell">${b(G)}</div>
|
|
1087
|
+
`);return}const p=e.map(l=>$(l.start)).filter(l=>l!=null),k=e.map(l=>$(l.end)).filter(l=>l!=null),y=A(Math.min(...p),-2),w=A(Math.max(...k),3),x=Math.max(7,Math.ceil((w-y)/D));this.hostWidth=this.clientWidth||this.hostWidth;const M=this.hostWidth-Fe;this.hostHeight=this.clientHeight||this.hostHeight;const T=or(this.getAttribute("max-height")),z=this.hostWidth>0&&M<=Ce,U=ir(this.getAttribute("columns")),P=nr(U,cr(this.getAttribute("grid-width"))),lt=z?De:P.width;this.gridBounds={min:P.min,max:Math.max(P.min,this.hostWidth>0?M-240:1200),width:P.width};const st=i==="fit",R=this.hostWidth>0?M-lt-this.scrollbarWidth:Be,q=st?Math.max(Ne,Math.min(We,R/x)):Jt[i],K=st?Pe(q):i;this.dayWidthNow=q;const J=Math.max(st?Oe:680,x*q),O=Math.max(c.length*S,S),V=this.getAttribute("virtualized")!=="false"&&c.length>240;this.virtualizedNow=V;const et=Math.max(20,Math.ceil(Math.max(420,this.viewportHeight-N)/S)),f=160;this.viewportTop=Math.min(this.viewportTop,Math.max(0,O+N-this.viewportHeight));const E=Math.max(0,this.viewportTop-N),L=Math.max(0,Math.floor(E/S)),_=Math.max(180,et*4),G=V?Math.max(0,Math.floor(L/_)*_-f):0,at=V?Math.min(c.length,G+et+f*2+_):c.length,dt=c.slice(G,at),rt=G*S,it=Math.max(0,(c.length-at)*S);this.renderedFirstRow=G,this.renderedLastRow=at;const $t=Z({dateStyle:"medium"}),pt=new Map,F=new Map(c.map((l,B)=>[l.id,{task:l,index:B}])),C=new Set(dt.map(l=>l.id)),tt=this.selectedId!=null&&C.has(this.selectedId)?this.selectedId:dt[0]?.id,nt=l=>(l-y)/D*q,be=dt.map((l,B)=>{const I=G+B,Q=this.selectedId===l.id?" selected":"",X=ut(l),ct=ft=>{switch(ft.key){case"label":return`<div class="grid-cell task-name" role="gridcell" style="padding-left:${10+l.depth*18}px">
|
|
1088
|
+
${l.hasChildren?`<button class="expander" data-action="toggle" data-task-id="${v(l.id)}" aria-label="${v(this.collapsed.has(l.id)?t.expand:t.collapse)} ${v(l.label)}">${this.collapsed.has(l.id)?"›":"⌄"}</button>`:'<span style="inline-size:22px"></span>'}
|
|
1089
|
+
${this.editingId===l.id?`<input class="rename" value="${v(this.editingValue)}" aria-label="${v(t.rename)}" />`:`<span class="name-text" title="${v(l.label)}">${v(l.label)}</span>`}
|
|
1090
|
+
</div>`;case"assignee":return`<div class="grid-cell badge" role="gridcell">${v(l.assignee||X)}</div>`;case"dates":return`<div class="grid-cell badge" role="gridcell">${v(X==="milestone"?ht(l.startMs):`${ht(l.startMs)} - ${ht(l.endMs)}`)}</div>`;case"start":return`<div class="grid-cell badge" role="gridcell">${v(ht(l.startMs))}</div>`;case"end":return`<div class="grid-cell badge" role="gridcell">${v(X==="milestone"?"-":ht(l.endMs))}</div>`;case"duration":return`<div class="grid-cell badge" role="gridcell">${X==="milestone"?"-":Math.max(0,Math.round((l.endMs-l.startMs)/D))}</div>`;default:return`<div class="grid-cell badge" role="gridcell">${l.progress==null?"-":`${Math.round(l.progress)}%`}</div>`}};return`
|
|
1091
|
+
<div class="grid-row${Q}" part="grid-row" data-task-id="${v(l.id)}" role="row" tabindex="${l.id===tt?0:-1}" aria-rowindex="${I+2}" aria-level="${l.depth+1}" ${Q?'aria-selected="true"':""} ${l.hasChildren?`aria-expanded="${!this.collapsed.has(l.id)}"`:""}>
|
|
1092
|
+
${U.map(ct).join("")}
|
|
684
1093
|
</div>
|
|
685
|
-
`}).join("")
|
|
686
|
-
<div class="timeline-row${
|
|
687
|
-
${
|
|
1094
|
+
`}).join(""),ve=dt.map((l,B)=>{const I=ut(l),Q=sr(l,I,$t,t);pt.set(l.id,Q);const X=this.selectedId===l.id?" selected":"",ct=l.id===tt,ft=l.critical?mt.danger:mt[l.tone||(I==="summary"?"info":"default")]||mt.default,Mt=I==="milestone"?nt(l.startMs)-vt/2:nt(l.startMs),Se=nt(I==="milestone"?l.startMs:l.endMs),Xt=I==="milestone"?vt:Math.max(12,Se-Mt),St=Math.max(0,Math.min(100,Number(l.progress??0))),Yt=!h&&!l.readonly&&(I!=="summary"||g),Ut=Yt&&I==="task",Kt=I==="task"&&l.segments?.length?tr(l,St):"";return`
|
|
1095
|
+
<div class="timeline-row${X}" part="timeline-row" data-task-id="${v(l.id)}">
|
|
1096
|
+
${l.baselineStart&&l.baselineEnd?`<span class="baseline" style="left:${nt($(l.baselineStart)||l.startMs).toFixed(2)}px;width:${Math.max(4,nt($(l.baselineEnd)||l.endMs)-nt($(l.baselineStart)||l.startMs)).toFixed(2)}px"></span>`:""}
|
|
688
1097
|
<button
|
|
689
|
-
class="bar ${
|
|
690
|
-
part="bar ${
|
|
691
|
-
data-task-id="${
|
|
692
|
-
data-kind="${
|
|
693
|
-
|
|
694
|
-
${
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
1098
|
+
class="bar ${I}${l.critical?" critical":""}${Kt?" split":""}${St>=100?" complete":""}"
|
|
1099
|
+
part="bar ${I}"
|
|
1100
|
+
data-task-id="${v(l.id)}"
|
|
1101
|
+
data-kind="${I}"
|
|
1102
|
+
${l.progress!=null?`data-progress="${Math.round(St)}"`:""}
|
|
1103
|
+
tabindex="${ct?"0":"-1"}"
|
|
1104
|
+
${this.selectedId===l.id?'aria-current="true"':""}
|
|
1105
|
+
style="left:${Mt.toFixed(2)}px;width:${Xt.toFixed(2)}px;--tone:${ft};--progress:${St.toFixed(2)}%"
|
|
1106
|
+
aria-label="${v(Q.name)}"
|
|
1107
|
+
${Yt?'data-draggable="true"':""}
|
|
698
1108
|
>
|
|
699
|
-
${
|
|
1109
|
+
${Ut?'<span class="handle start" data-mode="resize-start"></span>':""}
|
|
700
1110
|
<span class="progress"></span>
|
|
701
|
-
${
|
|
702
|
-
${
|
|
703
|
-
<span class="
|
|
704
|
-
${nt?'<span class="handle end" data-mode="resize-end"></span>':""}
|
|
1111
|
+
${Kt}
|
|
1112
|
+
${I==="milestone"?'<span class="milestone-shape"></span>':""}
|
|
1113
|
+
${Ut?'<span class="handle end" data-mode="resize-end"></span>':""}
|
|
705
1114
|
</button>
|
|
1115
|
+
${u?`<span class="connector" data-task-id="${v(l.id)}" data-side="start" style="left:${(Mt-18).toFixed(2)}px"></span><span class="connector" data-task-id="${v(l.id)}" data-side="end" style="left:${(Mt+Xt+6).toFixed(2)}px"></span>`:""}
|
|
706
1116
|
</div>
|
|
707
|
-
`}).join(""),
|
|
708
|
-
<style>${
|
|
709
|
-
|
|
710
|
-
|
|
1117
|
+
`}).join("");this.descriptions=pt,this.selectedLinkId&&!r.some(l=>l.id===this.selectedLinkId)&&(this.selectedLinkId=null);const ye=ie(this.getAttribute("schedule"))==="off"?new Set:Le(e.map(yt).filter(l=>l!=null),r.map(Wt)),Ot=r.map(l=>{const B=F.get(l.source),I=F.get(l.target);if(!B||!I||V&&!C.has(l.source)&&!C.has(l.target))return"";const Q=oe(B.task,B.index,I.task,I.index,l.type,nt),X=ye.has(l.id),ct=this.selectedLinkId===l.id,ft=`${B.task.label} dependency to ${I.task.label}${X?`, ${t.linkViolated}`:""}`;return`<path class="link-hit${X?" violated":""}${ct?" selected":""}" tabindex="-1" d="${Q}" data-link-id="${v(l.id)}" data-source-id="${v(l.source)}" data-target-id="${v(l.target)}" data-link-type="${v(l.type||"e2s")}"${X?' data-violated="true"':""} aria-label="${v(ft)}" /><path class="${[X?"violated":"",ct?"selected":""].filter(Boolean).join(" ")}" d="${Q}" />`}).join(""),Ht=l=>`<marker id="${l}" markerWidth="9" markerHeight="9" refX="8.5" refY="4.5" orient="auto" markerUnits="userSpaceOnUse"><path d="M 0.5 0.75 L 8.5 4.5 L 0.5 8.25 z" /></marker>`,xe=Ot?`<defs>${Ht("ui-gantt-arrow")}${Ht("ui-gantt-arrow-bad")}</defs>`:"",Pt=Ft(this.getAttribute("week-start")),_t=te(this.getAttribute("non-working-days"),this.getAttribute("holidays")),we=Math.max(J,M-lt),gt=y+we/q*D;this.layoutInfo={min:y,dayWidth:q,gridWidth:lt,rangeEnd:gt},this.renderedLeft=this.viewportLeft,this.visibleIds=c.map(l=>l.id);const zt=Y(Date.now()),Ct=nt(zt),Dt=zt>=y&&zt<=gt,jt=m&&Dt,ke=jt?`<div class="today" part="today" style="left:${Ct.toFixed(2)}px"></div>`:"",$e=jt&&K!=="day"?`<span class="today-pill" part="today-pill" style="left:clamp(22px, ${Ct.toFixed(2)}px, calc(100% - 22px))">${v(t.today)}</span>`:"",Me=this.focusRequest??this.captureFocus();this.focusRequest=null;const Vt=this.root.querySelector(".frame");this.setContent(`
|
|
1118
|
+
<style>${Gt}</style>
|
|
1119
|
+
${P.width!==Tt||P.template!==ce?`<style>@container ui-gantt (min-width: 641px) { .surface { --gantt-grid-w: ${P.width}px; --gantt-cols: ${P.template}; } }</style>`:""}
|
|
1120
|
+
<section class="frame" part="frame" data-bar-variant="${s}"${T?` style="--ui-gantt-max-height:${T}"`:""}>
|
|
1121
|
+
${b?`
|
|
711
1122
|
<header class="toolbar" part="toolbar">
|
|
712
|
-
<div class="title"
|
|
1123
|
+
<div class="title">${v(t.title)} <span class="meta">${v(t.tasksCount.replace("{shown}",String(c.length)).replace("{total}",String(e.length)))}</span></div>
|
|
713
1124
|
<div class="controls">
|
|
714
|
-
<input class="control" value="${
|
|
715
|
-
<select class="select" aria-label="
|
|
716
|
-
${[["none",
|
|
1125
|
+
<input class="control" value="${v(o)}" placeholder="${v(t.filterPlaceholder)}" aria-label="${v(t.filterLabel)}" />
|
|
1126
|
+
<select class="select" aria-label="${v(t.sortLabel)}">
|
|
1127
|
+
${[["none",t.sortManual],["start",t.sortStart],["end",t.sortEnd],["label",t.sortName],["progress",t.sortProgress]].map(([l,B])=>`<option value="${l}" ${a===l?"selected":""}>${v(B)}</option>`).join("")}
|
|
717
1128
|
</select>
|
|
718
|
-
${
|
|
1129
|
+
${d?`<button class="add-button" data-action="add"><span aria-hidden="true">+</span> ${v(t.addTask)}</button>`:""}
|
|
1130
|
+
${m?`<button class="today-button" data-action="today" title="${v(t.scrollToToday)}" aria-label="${v(t.scrollToToday)}"${Dt?"":" disabled"}>${v(t.today)}</button>`:""}
|
|
1131
|
+
${["day","week","month","quarter","year","fit"].map(l=>`<button class="zoom-button" data-zoom="${l}" aria-pressed="${i===l}"${l==="fit"?` title="${v(t.zoomFitTitle)}"`:""}>${v(ar(l,t))}</button>`).join("")}
|
|
719
1132
|
</div>
|
|
720
1133
|
</header>
|
|
721
1134
|
`:""}
|
|
722
1135
|
<div class="viewport" part="viewport">
|
|
723
|
-
<div class="surface" part="surface" style="--day-width:${
|
|
724
|
-
<div class="grid-semantics" role="treegrid" aria-label="${
|
|
1136
|
+
<div class="surface" part="surface" style="--day-width:${q}px;grid-template-columns:var(--gantt-grid-w) minmax(${J.toFixed(2)}px, 1fr);inline-size:max(100%, calc(var(--gantt-grid-w) + ${J.toFixed(2)}px))">
|
|
1137
|
+
<div class="grid-semantics" role="treegrid" aria-label="${v(this.getAttribute("aria-label")||t.title)}" aria-rowcount="${c.length+1}" aria-colcount="${z?1:U.length}">
|
|
725
1138
|
<div class="grid-head" part="grid-head" role="row">
|
|
726
|
-
|
|
727
|
-
<span role="columnheader">Owner</span>
|
|
728
|
-
<div role="columnheader" aria-sort="${n==="start"?"ascending":"none"}" style="display:contents"><button class="head-button" data-sort="start">Dates</button></div>
|
|
729
|
-
<div role="columnheader" aria-sort="${n==="progress"?"descending":"none"}" style="display:contents"><button class="head-button" data-sort="progress">%</button></div>
|
|
1139
|
+
${U.map(l=>{const B=v(l.custom??t[l.title]);if(!l.sort)return`<span role="columnheader">${B}</span>`;const I=a===l.sort,Q=l.sort==="progress"?"descending":"ascending";return`<div role="columnheader" aria-sort="${I?Q:"none"}" style="display:contents"><button class="head-button" data-sort="${l.sort}">${B}</button></div>`}).join("")}
|
|
730
1140
|
</div>
|
|
731
1141
|
<div class="grid-body" part="grid-body" role="rowgroup">
|
|
732
|
-
${
|
|
733
|
-
${
|
|
734
|
-
${
|
|
1142
|
+
${V&&rt?`<div style="height:${rt}px"></div>`:""}
|
|
1143
|
+
${be||`<div class="empty">${v(t.noMatches)}</div>`}
|
|
1144
|
+
${V&&it?`<div style="height:${it}px"></div>`:""}
|
|
735
1145
|
</div>
|
|
736
1146
|
</div>
|
|
1147
|
+
<div class="splitter-rail head"><div class="splitter" role="separator" aria-orientation="vertical" aria-label="${v(t.splitter)}" aria-valuemin="${P.min}" aria-valuemax="${this.gridBounds.max}" aria-valuenow="${P.width}" tabindex="0"></div></div>
|
|
1148
|
+
<div class="splitter-rail body"><div class="splitter" aria-hidden="true"></div></div>
|
|
737
1149
|
<div class="timeline-head" part="timeline-head" aria-hidden="true">
|
|
738
|
-
<div class="scale" style="width:${
|
|
1150
|
+
<div class="scale" data-zoom="${K}" style="min-width:${J.toFixed(2)}px">${Je(y,gt,q,K,Pt,this.viewportLeft,this.viewportWidth,_t)}${$e}</div>
|
|
739
1151
|
</div>
|
|
740
|
-
<div class="timeline-body" part="timeline-body" role="group" aria-label="
|
|
741
|
-
|
|
742
|
-
${
|
|
743
|
-
${
|
|
744
|
-
${
|
|
745
|
-
${
|
|
1152
|
+
<div class="timeline-body" part="timeline-body" role="group" aria-label="${v(t.timeline)}" data-zoom="${K}" style="min-width:${J.toFixed(2)}px;min-height:${O}px">
|
|
1153
|
+
${Ke(y,gt,q,_t,this.viewportLeft,this.viewportWidth)}
|
|
1154
|
+
${Qe(y,gt,q,K,Pt,this.viewportLeft,this.viewportWidth)}
|
|
1155
|
+
<svg class="links" width="${J.toFixed(0)}" height="${O}" viewBox="0 0 ${J.toFixed(0)} ${O}" aria-hidden="true">${xe}${Ot}</svg>
|
|
1156
|
+
${ke}
|
|
1157
|
+
${V&&rt?`<div style="height:${rt}px"></div>`:""}
|
|
1158
|
+
${ve}
|
|
1159
|
+
${V&&it?`<div style="height:${it}px"></div>`:""}
|
|
1160
|
+
<div class="bar-tip" part="tip" aria-hidden="true"></div>
|
|
746
1161
|
</div>
|
|
747
1162
|
</div>
|
|
748
1163
|
</div>
|
|
749
1164
|
</section>
|
|
750
|
-
`);const q=this.root.querySelector(".viewport");q&&(q.scrollTop=this.viewportTop,q.scrollLeft=this.viewportLeft,this.viewportWidth=q.clientWidth||this.viewportWidth,this.viewportHeight=q.clientHeight||this.viewportHeight),this.bindEvents()}bindEvents(){this.root.querySelectorAll("[data-task-id]").forEach(t=>{t.addEventListener("click",i=>{const e=i.target,n=i.currentTarget;if(!n.classList.contains("bar")&&e.closest(".bar"))return;if(this.drag?.moved){i.stopPropagation();return}const l=i.currentTarget.dataset.taskId;l&&(e.closest('[data-action="toggle"]')||(n.classList.contains("bar")&&i.stopPropagation(),this.selectTask(l)))})}),this.root.querySelectorAll('[data-action="toggle"]').forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation();const e=t.dataset.taskId;e&&(this.collapsed.has(e)?this.collapsed.delete(e):this.collapsed.add(e),this.requestRender())})}),this.root.querySelectorAll("[data-zoom]").forEach(t=>{t.addEventListener("click",()=>{const i=t.dataset.zoom||"week";this.setAttribute("zoom",i),this.dispatchEvent(new CustomEvent("zoomchange",{detail:{zoom:i},bubbles:!0,composed:!0}))})}),this.root.querySelectorAll(".head-button[data-sort]").forEach(t=>{t.addEventListener("click",()=>{const i=W(t.dataset.sort||null);i==="none"?this.removeAttribute("sort"):this.setAttribute("sort",i),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:i},bubbles:!0,composed:!0}))})}),this.root.querySelector(".viewport")?.addEventListener("scroll",t=>{const i=t.currentTarget,e=i.scrollTop,n=i.scrollLeft,s=Math.max(20,Math.ceil(Math.max(420,this.viewportHeight-V)/y)),l=Math.max(0,Math.floor(Math.max(0,e-V)/y)),o=l<this.renderedFirstRow+64||l+s>this.renderedLastRow-64,p=Math.abs(n-this.viewportLeft)>=Math.max(480,this.viewportWidth*.6);this.viewportTop=e,this.viewportLeft=n,!(!o&&!p)&&this.scrollFrame==null&&(this.scrollFrame=window.setTimeout(()=>{this.scrollFrame=null,this.requestRender()},24))},{passive:!0}),this.root.querySelector(".control")?.addEventListener("input",t=>{this.internalFilter=t.currentTarget.value,this.dispatchEvent(new CustomEvent("filterchange",{detail:{filter:this.internalFilter},bubbles:!0,composed:!0})),this.requestRender()}),this.root.querySelector(".select")?.addEventListener("change",t=>{const i=W(t.currentTarget.value);i==="none"?this.removeAttribute("sort"):this.setAttribute("sort",i),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:i},bubbles:!0,composed:!0}))}),this.root.querySelectorAll(".link-hit").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this.dispatchEvent(new CustomEvent("linkselect",{detail:{id:t.dataset.linkId||"",source:t.dataset.sourceId||"",target:t.dataset.targetId||"",type:t.dataset.linkType||"e2s"},bubbles:!0,composed:!0}))})}),!this.hasAttribute("readonly")&&this.root.querySelectorAll('.bar[data-draggable="true"]').forEach(t=>{t.addEventListener("pointerdown",e=>{if(e.button!==0)return;const n=t.dataset.taskId;if(!n)return;const l=this.getTasks().find(h=>h.id===n),o=f(l?.start),p=f(l?.end);if(!l||o==null||p==null)return;e.preventDefault();const u=t.dataset.kind||"task",d=e.target.dataset.mode||"move",g=u==="milestone"?"move":d,c=bt(this.getAttribute("zoom")),m=this.selectedId!==n;this.selectedId=n,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:n},bubbles:!0,composed:!0})),this.drag={taskId:n,mode:g,startX:e.clientX,originalStart:o,originalEnd:p,kind:u,rangeMin:this.rangeMin(),dayWidth:gt[c],latestStart:o,latestEnd:p,frame:null,bar:t,moved:!1,selectedChanged:m},t.classList.add("dragging"),t.setPointerCapture(e.pointerId)}),t.addEventListener("pointermove",e=>{if(!this.drag||this.drag.taskId!==t.dataset.taskId)return;e.preventDefault();const n=e.clientX-this.drag.startX;Math.abs(n)>2&&(this.drag.moved=!0);let s=this.drag.originalStart,l=this.drag.originalEnd;if(this.drag.mode==="move"){const o=Math.round(n/this.drag.dayWidth);s=x(this.drag.originalStart,o),l=this.drag.kind==="milestone"?s:x(this.drag.originalEnd,o)}else if(this.drag.mode==="resize-start"){const o=Math.round(n/this.drag.dayWidth);s=Math.min(x(this.drag.originalStart,o),x(l,-1))}else{const o=Math.round(n/this.drag.dayWidth);l=Math.max(x(this.drag.originalEnd,o),x(s,1))}this.drag.latestStart=s,this.drag.latestEnd=l,this.drag.frame==null&&(this.drag.frame=requestAnimationFrame(()=>{if(!this.drag)return;this.drag.frame=null;const o=(this.drag.latestStart-this.drag.rangeMin)/I*this.drag.dayWidth-(this.drag.kind==="milestone"?N/2:0),p=this.drag.kind==="milestone"?N:Math.max(12,(this.drag.latestEnd-this.drag.latestStart)/I*this.drag.dayWidth);this.drag.bar.style.left=`${o.toFixed(2)}px`,this.drag.bar.style.width=`${p.toFixed(2)}px`;const u=this.drag.bar.querySelector(".drag-tip");u&&(u.textContent=this.drag.kind==="milestone"?E(this.drag.latestStart):`${E(this.drag.latestStart)} - ${E(this.drag.latestEnd)}`)}))});const i=()=>{if(!this.drag)return;this.drag.frame!=null&&cancelAnimationFrame(this.drag.frame);const e=this.drag;if(e.bar.classList.remove("dragging"),this.drag=null,!e.moved){e.selectedChanged&&this.requestRender();return}const n={id:e.taskId,start:E(e.latestStart),end:E(e.latestEnd)};this.overrides.set(e.taskId,{start:n.start,end:n.end}),this.bumpOverrides(),this.dispatchEvent(new CustomEvent("taskchange",{detail:n,bubbles:!0,composed:!0})),this.requestRender()};t.addEventListener("pointerup",i),t.addEventListener("pointercancel",i),t.addEventListener("keydown",e=>{const n=t.dataset.taskId;if(!n)return;if(e.key==="Delete"||e.key==="Backspace"){e.preventDefault(),this.dispatchEvent(new CustomEvent("taskdelete",{detail:{id:n},bubbles:!0,composed:!0}));return}if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.selectTask(n);return}if(e.key==="ArrowUp"||e.key==="ArrowDown"){e.preventDefault(),this.selectAdjacentTask(n,e.key==="ArrowDown"?1:-1);return}if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const l=this.getTasks().find(h=>h.id===n),o=f(l?.start),p=f(l?.end);if(!l||o==null||p==null)return;e.preventDefault();const u=e.key==="ArrowLeft"?-1:1,d=t.dataset.kind==="milestone",g=e.shiftKey&&!d?o:x(o,u),c=d?g:e.shiftKey?Math.max(x(p,u),x(o,1)):x(p,u),m={id:n,start:E(g),end:E(c)};this.overrides.set(n,{start:m.start,end:m.end}),this.bumpOverrides(),this.dispatchEvent(new CustomEvent("taskchange",{detail:m,bubbles:!0,composed:!0})),this.requestRender()})})}rangeMin(){const i=this.getTasks().map(e=>f(e.start)).filter(e=>e!=null);return i.length?x(Math.min(...i),-2):F(Date.now())}selectTask(t){if(this.captureViewport(),this.selectedId===t){this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:t},bubbles:!0,composed:!0}));return}this.selectedId=t,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:t},bubbles:!0,composed:!0})),this.requestRender()}selectAdjacentTask(t,i){const e=this.getVisibleTasks(this.getTasks(),this.getAttribute("filter")??this.internalFilter,W(this.getAttribute("sort"))),n=e.findIndex(l=>l.id===t),s=e[Math.max(0,Math.min(e.length-1,n+i))];!s||s.id===t||(this.selectedId=s.id,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:s.id},bubbles:!0,composed:!0})),this.requestRender(),window.requestAnimationFrame(()=>{this.root.querySelector(`.bar[data-task-id="${CSS.escape(s.id)}"]`)?.focus()}))}captureViewport(){const t=this.root.querySelector(".viewport");t&&(this.viewportTop=t.scrollTop,this.viewportLeft=t.scrollLeft,this.viewportWidth=t.clientWidth||this.viewportWidth,this.viewportHeight=t.clientHeight||this.viewportHeight)}getTasks(){const t=this.getAttribute("tasks");return t===this.taskCacheRaw&&this.taskCacheVersion===this.overridesVersion?this.taskCache:(this.taskCacheRaw=t,this.taskCacheVersion=this.overridesVersion,this.taskCache=Ft(t,this.overrides),this.visibleCacheKey="",this.taskCache)}getLinks(){const t=this.getAttribute("links");return t===this.linkCacheRaw?this.linkCache:(this.linkCacheRaw=t,this.linkCache=Rt(t),this.linkCache)}getVisibleTasks(t,i,e){const n=Array.from(this.collapsed).sort().join(","),s=`${this.taskCacheRaw||""}|${this.overridesVersion}|${i}|${e}|${n}`;return s===this.visibleCacheKey?this.visibleCache:(this.visibleCacheKey=s,this.visibleCache=Nt(t,this.collapsed,i,e),this.visibleCache)}bumpOverrides(){this.overridesVersion+=1,this.taskCacheVersion=-1,this.visibleCacheKey=""}shouldRenderOnAttributeChange(t,i,e){return t==="tasks"&&(this.overrides.clear(),this.bumpOverrides(),this.viewportTop=0,this.viewportLeft=0),t==="links"&&(this.linkCacheRaw=null),!0}}typeof customElements<"u"&&!customElements.get("ui-gantt")&&customElements.define("ui-gantt",wt);exports.UIGantt=wt;
|
|
1165
|
+
`);const j=this.root.querySelector(".viewport");if(j){this.root.querySelector(".frame")!==Vt&&(j.scrollTop=this.viewportTop,j.scrollLeft=this.viewportLeft,this.smoothTarget&&typeof j.scrollTo=="function"&&j.scrollTo({...this.smoothTarget,behavior:"smooth"})),this.viewportWidth=j.clientWidth||this.viewportWidth,this.viewportHeight=j.clientHeight||this.viewportHeight;const l=Math.max(0,j.offsetWidth-j.clientWidth);l!==this.scrollbarWidth&&(this.scrollbarWidth=l,st&&this.requestRender())}if(this.root.querySelector(".frame")!==Vt&&this.bindEvents(),this.restoreFocus(Me),j&&j.clientWidth>0&&this.initialScrollPending&&(this.initialScrollPending=!1,this.getAttribute("initial-scroll")!=="start"&&!st&&m&&Dt&&Ct>j.clientWidth-lt-48&&this.scrollToDate("today",{behavior:"auto"})),this.pendingReveal){const l=this.pendingReveal;this.pendingReveal=null,this.reveal(l.id,l.behavior)}}captureFocus(){const t=this.root.activeElement;if(!t)return null;const e=er(t);if(!e)return null;const r={selector:e};return t instanceof HTMLInputElement&&(r.selection=[t.selectionStart,t.selectionEnd,t.selectionDirection]),r}restoreFocus(t){if(!t)return;const e=this.root.querySelector(t.selector);if(!e&&t.reveal&&(t.retries??0)<5){this.focusRequest={...t,retries:(t.retries??0)+1};return}if(!(!e||this.root.activeElement===e)&&(e.focus({preventScroll:!t.reveal}),t.selectAll&&e instanceof HTMLInputElement&&e.select(),t.selection&&e instanceof HTMLInputElement))try{e.setSelectionRange(t.selection[0],t.selection[1],t.selection[2]??void 0)}catch{}}bindEvents(){this.root.querySelectorAll("[data-task-id]").forEach(t=>{t.addEventListener("click",e=>{const r=e.target,i=e.currentTarget;if(!i.classList.contains("bar")&&r.closest(".bar"))return;if(this.drag?.moved){e.stopPropagation();return}const s=e.currentTarget.dataset.taskId;s&&(r.closest('[data-action="toggle"]')||(i.classList.contains("bar")&&e.stopPropagation(),this.selectTask(s)))})}),this.root.querySelectorAll('[data-action="toggle"]').forEach(t=>{t.addEventListener("click",e=>{e.stopPropagation();const r=t.dataset.taskId;r&&this.toggleTask(r)})}),this.root.querySelector(".today-button")?.addEventListener("click",()=>{this.scrollToDate("today",{behavior:"smooth",align:"center"})}),this.root.querySelectorAll(".zoom-button[data-zoom]").forEach(t=>{t.addEventListener("click",()=>{const e=t.dataset.zoom||"week";this.setAttribute("zoom",e),this.dispatchEvent(new CustomEvent("zoomchange",{detail:{zoom:e},bubbles:!0,composed:!0}))})}),this.root.querySelectorAll(".head-button[data-sort]").forEach(t=>{t.addEventListener("click",()=>{const e=bt(t.dataset.sort||null);e==="none"?this.removeAttribute("sort"):this.setAttribute("sort",e),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:e},bubbles:!0,composed:!0}))})});for(const t of["wheel","pointerdown","touchstart","keydown"])this.root.querySelector(".viewport")?.addEventListener(t,()=>{this.smoothTarget=null},{passive:!0});this.root.querySelector(".viewport")?.addEventListener("scroll",t=>{const e=t.currentTarget,r=e.scrollTop,i=e.scrollLeft,a=Math.max(20,Math.ceil(Math.max(420,this.viewportHeight-N)/S)),s=Math.max(0,Math.floor(Math.max(0,r-N)/S)),o=this.virtualizedNow&&(s<this.renderedFirstRow+64||s+a>this.renderedLastRow-64),c=Math.abs(i-this.renderedLeft)>=400;this.viewportTop=r,this.viewportLeft=i;const h=this.smoothTarget;h&&(h.left==null||Math.abs(i-h.left)<2)&&(h.top==null||Math.abs(r-h.top)<2)&&(this.smoothTarget=null),!(this.drag||this.linking||!o&&!c)&&this.scrollFrame==null&&(this.scrollFrame=window.setTimeout(()=>{this.scrollFrame=null,this.requestRender()},24))},{passive:!0}),this.root.querySelector(".control")?.addEventListener("input",t=>{this.internalFilter=t.currentTarget.value,this.dispatchEvent(new CustomEvent("filterchange",{detail:{filter:this.internalFilter},bubbles:!0,composed:!0})),this.requestRender()}),this.root.querySelector(".select")?.addEventListener("change",t=>{const e=bt(t.currentTarget.value);e==="none"?this.removeAttribute("sort"):this.setAttribute("sort",e),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:e},bubbles:!0,composed:!0}))}),this.bindLinks(),this.root.querySelectorAll(".bar").forEach(t=>{t.addEventListener("keydown",e=>this.handleBarKeydown(t,e))}),this.bindTooltips(),this.bindSplitters(),this.bindRows(),this.bindEditing(),!this.hasAttribute("readonly")&&this.root.querySelectorAll('.bar[data-draggable="true"]').forEach(t=>{t.addEventListener("pointerdown",e=>this.startDrag(t,e)),t.addEventListener("pointermove",e=>{!this.drag||this.drag.bar!==t||(e.preventDefault(),this.drag.lastClientX=e.clientX,this.updateDrag())}),t.addEventListener("pointerup",()=>this.endDrag(!0)),t.addEventListener("pointercancel",()=>this.endDrag(!1))})}snapUnit(){const t=this.getAttribute("snap");return t==="week"||t==="month"?t:"day"}snapDate(t){const e=this.snapUnit();if(e==="day")return t;const r=Ft(this.getAttribute("week-start")),i=ue(t,e,r),a=pe(i,e);return t-i<a-t?i:a}startDrag(t,e){if(e.button!==0)return;const r=t.dataset.taskId;if(!r)return;const i=this.getTasks().find(u=>u.id===r),a=$(i?.start),s=$(i?.end);if(!i||a==null||s==null)return;e.preventDefault();const o=t.dataset.kind||"task",c=e.target.dataset.mode||"move",h=o==="milestone"?"move":c,d=this.selectedId!==r;this.selectedId=r,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:r},bubbles:!0,composed:!0}));const g=u=>{u.key==="Escape"&&(u.preventDefault(),u.stopPropagation(),this.endDrag(!1))};this.drag={taskId:r,mode:h,startX:e.clientX,startScroll:this.root.querySelector(".viewport")?.scrollLeft??0,lastClientX:e.clientX,originalStart:a,originalEnd:s,kind:o,rangeMin:this.rangeMin(),dayWidth:this.dayWidthNow,latestStart:a,latestEnd:s,frame:null,scrollFrame:null,bar:t,originalLeft:t.style.left,originalWidth:t.style.width,moved:!1,selectedChanged:d,onKey:g},window.addEventListener("keydown",g,!0),t.classList.add("dragging"),t.setPointerCapture(e.pointerId),this.autoScrollLoop()}updateDrag(){const t=this.drag;if(!t)return;const e=this.root.querySelector(".viewport"),r=t.lastClientX-t.startX+(e?e.scrollLeft-t.startScroll:0);Math.abs(r)>2&&(t.moved=!0);const i=Math.round(r/t.dayWidth);let a=t.originalStart,s=t.originalEnd;if(t.mode==="move"){const o=Math.round((this.snapDate(A(t.originalStart,i))-t.originalStart)/D);a=A(t.originalStart,o),s=t.kind==="milestone"?a:A(t.originalEnd,o)}else t.mode==="resize-start"?a=Math.min(this.snapDate(A(t.originalStart,i)),A(s,-1)):s=Math.max(this.snapDate(A(t.originalEnd,i)),A(a,1));t.latestStart=a,t.latestEnd=s,t.frame==null&&(t.frame=requestAnimationFrame(()=>{const o=this.drag;if(!o)return;o.frame=null;const c=(o.latestStart-o.rangeMin)/D*o.dayWidth-(o.kind==="milestone"?vt/2:0),h=o.kind==="milestone"?vt:Math.max(12,(o.latestEnd-o.latestStart)/D*o.dayWidth);o.bar.style.left=`${c.toFixed(2)}px`,o.bar.style.width=`${h.toFixed(2)}px`,Lt=this.getAttribute("locale")||void 0;const d=Z({dateStyle:"medium"}),g=this.labelSet();this.showTip(o.bar,o.kind==="milestone"?d.format(new Date(o.latestStart)):`${d.format(new Date(o.latestStart))} ${g.to} ${d.format(new Date(o.latestEnd))}`)}))}autoScrollLoop(){const t=this.drag;t&&(t.scrollFrame=requestAnimationFrame(()=>{const e=this.drag;if(!e)return;const r=this.root.querySelector(".viewport");if(r&&r.clientWidth>0&&e.moved){const i=r.getBoundingClientRect(),a=56,s=Math.max(i.left,this.root.querySelector(".grid-body")?.getBoundingClientRect().right??i.left);let o=0;e.lastClientX>i.right-a?o=(e.lastClientX-(i.right-a))/a:e.lastClientX<s+a&&r.scrollLeft>0&&(o=-(s+a-e.lastClientX)/a),o&&(r.scrollLeft+=Math.max(-1.5,Math.min(1.5,o))*16,this.updateDrag())}this.autoScrollLoop()}))}endDrag(t){const e=this.drag;if(!e)return;e.frame!=null&&cancelAnimationFrame(e.frame),e.scrollFrame!=null&&cancelAnimationFrame(e.scrollFrame),window.removeEventListener("keydown",e.onKey,!0),e.bar.classList.remove("dragging"),this.drag=null,this.hideTip();const r=()=>{e.bar.style.left=e.originalLeft,e.bar.style.width=e.originalWidth};if(!e.moved){e.selectedChanged&&this.requestRender();return}if(!t){r(),this.requestRender();return}if(e.latestStart===e.originalStart&&e.latestEnd===e.originalEnd){r();return}this.applyChanges(this.plan({id:e.taskId,start:e.latestStart,end:e.latestEnd,previousStart:e.originalStart,previousEnd:e.originalEnd}),e.mode==="move"?"drag":"resize")||r()}plan(t){const e=this.withCascade(t);if(ie(this.getAttribute("schedule"))!=="auto")return e;const r=this.getLinks();if(!r.length)return e;const i=this.getTasks().map(yt).filter(c=>c!=null),a=new Map(i.map(c=>[c.id,c])),s=new Map(e.map(c=>[c.id,{start:c.start,end:c.end}])),o=[...e];for(const c of Ie(i,r.map(Wt),s,this.hasAttribute("cascade"))){const h=o.findIndex(d=>d.id===c.id);if(h>=0)o[h]={...o[h],start:c.start,end:c.end};else{const d=a.get(c.id);d&&o.push({id:c.id,start:c.start,end:c.end,previousStart:d.start,previousEnd:d.end})}}return o}withCascade(t){if(!this.hasAttribute("cascade"))return[t];const e=wt(t.previousStart,t.start);if(e===0||t.end-t.start!==t.previousEnd-t.previousStart)return[t];const r=this.getTasks(),i=de(r.map(yt).filter(s=>s!=null),t.id);if(!i.length)return[t];const a=i.filter(s=>!s.readonly).map(s=>({id:s.id,start:H(s.start,e),end:H(s.end,e),previousStart:s.start,previousEnd:s.end}));return[t,...a]}applyChanges(t,e){const[r,...i]=t,a=o=>({id:o.id,start:W(o.start),end:W(o.end),previousStart:W(o.previousStart),previousEnd:W(o.previousEnd)});if(!this.dispatchEvent(new CustomEvent("beforetaskchange",{detail:{...a(r),source:e,affected:i.map(a)},bubbles:!0,composed:!0,cancelable:!0})))return this.requestRender(),!1;for(const o of t)this.overrides.set(o.id,{...this.overrides.get(o.id),start:W(o.start),end:W(o.end)});this.bumpOverrides();for(const o of t)this.dispatchEvent(new CustomEvent("taskchange",{detail:{id:o.id,start:W(o.start),end:W(o.end)},bubbles:!0,composed:!0}));return this.requestRender(),!0}handleBarKeydown(t,e){const r=t.dataset.taskId;if(!r)return;const i=t.dataset.draggable==="true"&&!this.hasAttribute("readonly");if(e.key==="Escape"){this.hideTip();return}if(e.key==="F2"){e.preventDefault(),this.startRename(r);return}if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.selectTask(r);return}if(["ArrowUp","ArrowDown","Home","End","PageUp","PageDown"].includes(e.key)){e.preventDefault(),this.navigate(r,e.key,"bar");return}if(!i)return;if(e.key==="Delete"||e.key==="Backspace"){e.preventDefault(),this.dispatchEvent(new CustomEvent("taskdelete",{detail:{id:r},bubbles:!0,composed:!0}));return}if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const a=this.getTasks().find(b=>b.id===r),s=$(a?.start),o=$(a?.end);if(!a||s==null||o==null)return;e.preventDefault();const c=e.key==="ArrowLeft"?-1:1,h=t.dataset.kind==="milestone",d=e.shiftKey&&!h&&t.dataset.kind!=="summary",g=d?s:A(s,c),u=h?g:d?Math.max(A(o,c),A(s,1)):A(o,c);this.applyChanges(this.plan({id:r,start:g,end:u,previousStart:s,previousEnd:o}),"keyboard")}showTip(t,e){const r=this.root.querySelector(".bar-tip"),i=this.root.querySelector(".timeline-body"),a=this.root.querySelector(".viewport"),s=this.root.querySelector(".grid-body"),o=this.descriptions.get(t.dataset.taskId||"");if(!r||!i||!a||!o)return;r.innerHTML=`<strong>${v(o.title)}</strong><span>${v(e?[o.kindWord,e].filter(Boolean).join(" · "):o.when)}</span>`+(o.more?`<span>${v(o.more)}</span>`:""),r.setAttribute("data-open","");const c=i.getBoundingClientRect(),h=t.getBoundingClientRect(),d=a.getBoundingClientRect(),g=Math.max(d.left,s?s.getBoundingClientRect().right:d.left)+4,u=d.right-4,b=r.offsetWidth,m=r.offsetHeight,p=(Math.max(h.left,g)+Math.min(h.right,u))/2,k=Math.max(g,Math.min(p-b/2,u-b)),w=h.top-(d.top+N)>=m+8?h.top-m-6:h.bottom+6;r.style.left=`${(k-c.left).toFixed(1)}px`,r.style.top=`${(w-c.top).toFixed(1)}px`}hideTip(){this.tipTimer!=null&&(window.clearTimeout(this.tipTimer),this.tipTimer=null),this.root.querySelector(".bar-tip")?.removeAttribute("data-open")}bindLinks(){const t=e=>({id:e.dataset.linkId||"",source:e.dataset.sourceId||"",target:e.dataset.targetId||"",type:e.dataset.linkType||"e2s"});this.root.querySelectorAll(".link-hit").forEach(e=>{e.addEventListener("click",r=>{r.stopPropagation(),this.selectedLinkId=e.dataset.linkId||null,this.focusRequest={selector:`.link-hit[data-link-id="${ot(e.dataset.linkId||"")}"]`},this.dispatchEvent(new CustomEvent("linkselect",{detail:t(e),bubbles:!0,composed:!0})),this.requestRender()}),e.addEventListener("keydown",r=>{if(r.key==="Delete"||r.key==="Backspace"){if(this.hasAttribute("readonly"))return;r.preventDefault(),this.dispatchEvent(new CustomEvent("linkdelete",{detail:t(e),bubbles:!0,composed:!0}))}else r.key==="Enter"||r.key===" "?(r.preventDefault(),this.dispatchEvent(new CustomEvent("linkselect",{detail:t(e),bubbles:!0,composed:!0}))):r.key==="Escape"&&(this.selectedLinkId=null,this.requestRender())})}),this.root.querySelectorAll(".connector").forEach(e=>{e.addEventListener("pointerdown",r=>this.startLink(e,r)),e.addEventListener("pointermove",r=>this.updateLink(r)),e.addEventListener("pointerup",()=>this.endLink(!0)),e.addEventListener("pointercancel",()=>this.endLink(!1))})}startLink(t,e){if(e.button!==0)return;const r=t.dataset.taskId,i=t.dataset.side==="start"?"start":"end",a=this.root.querySelector(".timeline-body"),s=this.root.querySelector("svg.links"),o=r?this.root.querySelector(At(r)):null;if(!r||!a||!s||!o)return;e.preventDefault();const c=a.getBoundingClientRect(),h=o.getBoundingClientRect(),d=document.createElementNS("http://www.w3.org/2000/svg","path");d.setAttribute("class","link-draft"),s.appendChild(d);const g=u=>{u.key==="Escape"&&(u.preventDefault(),u.stopPropagation(),this.endLink(!1))};this.linking={sourceId:r,side:i,fromX:(i==="start"?h.left:h.right)-c.left,fromY:h.top+h.height/2-c.top,draft:d,targetId:null,targetSide:null,onKey:g},window.addEventListener("keydown",g,!0),this.root.querySelector(".frame")?.setAttribute("data-linking",""),t.setPointerCapture(e.pointerId),this.updateLink(e)}updateLink(t){const e=this.linking,r=this.root.querySelector(".timeline-body");if(!e||!r)return;const i=r.getBoundingClientRect();e.draft.setAttribute("d",`M ${e.fromX.toFixed(1)} ${e.fromY.toFixed(1)} L ${(t.clientX-i.left).toFixed(1)} ${(t.clientY-i.top).toFixed(1)}`),this.root.querySelectorAll(".bar.link-target").forEach(d=>{d.classList.remove("link-target"),d.removeAttribute("data-link-side")}),e.targetId=null,e.targetSide=null;const a=this.root.elementFromPoint(t.clientX,t.clientY),s=a?.closest?.(".connector"),o=s?this.root.querySelector(At(s.dataset.taskId||"")):a?.closest?.(".bar"),c=o?.dataset.taskId;if(!o||!c||c===e.sourceId)return;const h=o.getBoundingClientRect();e.targetId=c,e.targetSide=s?s.dataset.side==="start"?"start":"end":t.clientX<h.left+h.width/2?"start":"end",o.classList.add("link-target"),o.setAttribute("data-link-side",e.targetSide)}endLink(t){const e=this.linking;if(!e||(window.removeEventListener("keydown",e.onKey,!0),this.linking=null,e.draft.remove(),this.root.querySelector(".frame")?.removeAttribute("data-linking"),this.root.querySelectorAll(".bar.link-target").forEach(i=>{i.classList.remove("link-target"),i.removeAttribute("data-link-side")}),!t||!e.targetId||!e.targetSide))return;const r=`${e.side==="start"?"s":"e"}2${e.targetSide==="start"?"s":"e"}`;this.getLinks().some(i=>i.source===e.sourceId&&i.target===e.targetId&&(i.type||"e2s")===r)||this.dispatchEvent(new CustomEvent("linkcreate",{detail:{source:e.sourceId,target:e.targetId,type:r},bubbles:!0,composed:!0}))}startRename(t){if(this.hasAttribute("readonly"))return;const e=this.getTasks().find(r=>r.id===t);!e||e.readonly||(this.editingId=t,this.editingValue=e.label,this.focusRequest={selector:".rename",reveal:!0,retries:0,selectAll:!0},this.reveal(t,"auto"),this.requestRender())}finishRename(t){const e=this.editingId;if(!e)return;const r=this.editingValue.trim(),i=this.getTasks().find(a=>a.id===e)?.label;this.editingId=null,t&&r&&i!=null&&r!==i&&this.dispatchEvent(new CustomEvent("taskrename",{detail:{id:e,label:r,previousLabel:i},bubbles:!0,composed:!0,cancelable:!0}))&&(this.overrides.set(e,{...this.overrides.get(e),label:r}),this.bumpOverrides()),this.focusRequest={selector:Nt(e)},this.requestRender()}requestCreate(t,e){const r=e?this.getTasks().find(i=>i.id===e):void 0;this.dispatchEvent(new CustomEvent("taskcreate",{detail:{start:W(t),end:W(A(t,He)),parent:r?.parent,after:r?.id},bubbles:!0,composed:!0}))}bindEditing(){this.root.querySelectorAll(".grid-row .task-name").forEach(e=>{e.addEventListener("dblclick",r=>{if(r.target.closest(".expander, .rename"))return;const i=e.closest(".grid-row")?.dataset.taskId;i&&this.startRename(i)})});const t=this.root.querySelector(".rename");t&&(t.addEventListener("input",()=>{this.editingValue=t.value}),t.addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"?(e.preventDefault(),this.finishRename(!0)):e.key==="Escape"&&(e.preventDefault(),this.finishRename(!1))}),t.addEventListener("blur",()=>{this.suppressBlur||this.finishRename(!0)})),this.root.querySelector(".add-button")?.addEventListener("click",()=>{const{min:e,rangeEnd:r}=this.layoutInfo,i=Y(Date.now());this.requestCreate(i>=e&&i<=r?i:e,this.selectedId??void 0)}),this.hasAttribute("creatable")&&!this.hasAttribute("readonly")&&this.root.querySelectorAll(".timeline-row").forEach(e=>{e.addEventListener("dblclick",r=>{if(r.target!==e)return;const i=this.root.querySelector(".timeline-body");if(!i)return;const{min:a,dayWidth:s}=this.layoutInfo,o=Math.floor((r.clientX-i.getBoundingClientRect().left)/s);this.requestCreate(A(a,o),e.dataset.taskId)})})}bindRows(){this.root.querySelectorAll(".grid-row").forEach(t=>{t.addEventListener("keydown",e=>{if(e.target!==t)return;const r=t.dataset.taskId;if(r){if(e.key==="Enter"||e.key===" "){e.preventDefault(),this.selectTask(r);return}if(e.key==="F2"){e.preventDefault(),this.startRename(r);return}this.navigate(r,e.key,"row")&&e.preventDefault()}})})}bindSplitters(){const t=this.root.querySelector(".surface"),e=this.root.querySelectorAll(".splitter"),r=i=>{const a=Math.round(Math.max(this.gridBounds.min,Math.min(this.gridBounds.max,i)));a!==this.gridBounds.width&&(this.setAttribute("grid-width",String(a)),this.dispatchEvent(new CustomEvent("gridresize",{detail:{width:a},bubbles:!0,composed:!0})))};e.forEach(i=>{i.addEventListener("pointerdown",a=>{if(a.button!==0||!t)return;a.preventDefault();const s=a.clientX,{min:o,max:c,width:h}=this.gridBounds;let d=h;i.setPointerCapture(a.pointerId),e.forEach(b=>b.classList.add("dragging"));const g=b=>{d=Math.max(o,Math.min(c,h+b.clientX-s)),t.style.setProperty("--gantt-grid-w",`${d}px`)},u=b=>{if(i.removeEventListener("pointermove",g),i.removeEventListener("pointerup",u),i.removeEventListener("pointercancel",u),e.forEach(m=>m.classList.remove("dragging")),b.type==="pointercancel"){t.style.removeProperty("--gantt-grid-w");return}r(d)};i.addEventListener("pointermove",g),i.addEventListener("pointerup",u),i.addEventListener("pointercancel",u)}),i.addEventListener("keydown",a=>{if(i.getAttribute("role")!=="separator")return;const s=a.shiftKey?64:16,{min:o,max:c,width:h}=this.gridBounds,d=a.key==="ArrowLeft"?h-s:a.key==="ArrowRight"?h+s:a.key==="Home"?o:a.key==="End"?c:null;d!=null&&(a.preventDefault(),r(d))})})}bindTooltips(){this.root.querySelectorAll(".bar").forEach(t=>{t.addEventListener("pointerenter",e=>{e.pointerType!=="touch"&&(this.hideTip(),this.tipTimer=window.setTimeout(()=>{this.tipTimer=null,this.showTip(t)},150))}),t.addEventListener("pointerleave",()=>this.hideTip()),t.addEventListener("pointerdown",()=>{this.pointerFocus=!0,window.setTimeout(()=>{this.pointerFocus=!1},0),this.hideTip()}),t.addEventListener("blur",()=>this.hideTip()),t.addEventListener("focus",()=>{this.pointerFocus||this.showTip(t)})})}get tasks(){return qt(this.getAttribute("tasks"))}set tasks(t){ne(this,"tasks",t,!0)}get holidays(){return qt(this.getAttribute("holidays"))}set holidays(t){if(!Array.isArray(t)){this.removeAttribute("holidays");return}try{this.setAttribute("holidays",JSON.stringify(t.map(e=>e&&typeof e=="object"&&!(e instanceof Date)?{...e,date:xt(e.date)}:xt(e))))}catch{}}get links(){return qt(this.getAttribute("links"))}set links(t){ne(this,"links",t,!1)}resolveBehavior(t){return t==="smooth"&&typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches?"auto":t??"auto"}scrollViewport(t,e){const r=this.root.querySelector(".viewport");if(!r)return;const i=this.resolveBehavior(e);if(this.smoothTarget=i==="smooth"?t:null,this.smoothTarget){const a=this.smoothTarget;window.setTimeout(()=>{this.smoothTarget===a&&(this.smoothTarget=null)},2e3)}if(i!=="smooth"&&(t.left!=null&&(this.viewportLeft=t.left),t.top!=null&&(this.viewportTop=t.top)),typeof r.scrollTo=="function"){r.scrollTo({...t,behavior:i});return}t.left!=null&&(r.scrollLeft=t.left),t.top!=null&&(r.scrollTop=t.top)}scrollToDate(t,e={}){const r=t==="today"?Y(Date.now()):typeof t=="number"?Number.isFinite(t)?Y(t):null:$(t),i=this.root.querySelector(".viewport");r==null||!i||this.scrollViewport({left:this.leftFor(i,r,e.align??"center")},e.behavior)}leftFor(t,e,r){const{min:i,dayWidth:a,gridWidth:s}=this.layoutInfo,o=(e-i)/D*a,c=r==="start"?o-24:o-Math.max(0,t.clientWidth-s)/2;return Math.max(0,Math.min(c,Math.max(0,t.scrollWidth-t.clientWidth)))}scrollToTask(t,e={}){const r=this.getTasks(),i=new Map(r.map(d=>[d.id,d])),a=i.get(t);if(!a)return!1;let s=!1,o=a.parent;for(let d=0;o&&d<1e3;d+=1)this.collapsed.has(o)&&(this.collapsed.delete(o),this.dispatchEvent(new CustomEvent("tasktoggle",{detail:{id:o,open:!0},bubbles:!0,composed:!0})),s=!0),o=i.get(o)?.parent;const c=this.getAttribute("filter")??this.internalFilter;return this.getVisibleTasks(r,c,bt(this.getAttribute("sort"))).some(d=>d.id===t)?s||!this.visibleIds.includes(t)?(this.pendingReveal={id:t,behavior:e.behavior??"auto"},this.requestRender(),!0):this.reveal(t,e.behavior??"auto"):!1}reveal(t,e){const r=this.visibleIds.indexOf(t),i=this.root.querySelector(".viewport"),a=this.getTasks().find(g=>g.id===t);if(r<0||!i||!a)return!1;const s={},o=N+r*S;if(!(o>=i.scrollTop+N&&o+S<=i.scrollTop+i.clientHeight)){const g=r*S+S/2-(i.clientHeight-N)/2;s.top=Math.max(0,Math.min(g,Math.max(0,i.scrollHeight-i.clientHeight)))}const h=$(a.start),d=$(a.end);if(h!=null){const{min:g,dayWidth:u,gridWidth:b}=this.layoutInfo,m=(h-g)/D*u,p=((d??h)-g)/D*u,k=i.scrollLeft;(m<k||p>k+i.clientWidth-b)&&(s.left=this.leftFor(i,h,"start"))}return(s.left!=null||s.top!=null)&&this.scrollViewport(s,e),!0}toggleTask(t,e){const r=!this.collapsed.has(t),i=e??!r;i!==r&&(i?this.collapsed.delete(t):this.collapsed.add(t),this.dispatchEvent(new CustomEvent("tasktoggle",{detail:{id:t,open:i},bubbles:!0,composed:!0})),this.requestRender())}expandAll(){for(const t of[...this.collapsed])this.toggleTask(t,!0)}collapseAll(){const t=new Set(this.getTasks().map(e=>e.parent).filter(e=>!!e));for(const e of t)this.toggleTask(e,!1)}exportSvg(){Lt=this.getAttribute("locale")||void 0;const t=this.labelSet(),e=this.getTasks(),{min:r,dayWidth:i}=this.layoutInfo;if(!e.length||r===0)return"";const a=this.getVisibleTasks(e,this.getAttribute("filter")??this.internalFilter,bt(this.getAttribute("sort")));if(!a.length)return"";const s=getComputedStyle(this),o=f=>{const E=/^var\((--[\w-]+),\s*([^)]+)\)$/.exec(f);return E?s.getPropertyValue(E[1]).trim()||E[2].trim():f},c=o("var(--ui-color-text, #0f172a)"),h=o("var(--ui-color-muted, #526175)"),d=o("var(--ui-color-border, #cbd5e1)"),g=o("var(--ui-color-surface, #ffffff)");o("var(--ui-color-primary, #2563eb)");const u=o("var(--ui-color-danger, #dc2626)"),b=this.root.querySelector(".scale")?.getAttribute("data-zoom")||"week",m=Ft(this.getAttribute("week-start")),p=te(this.getAttribute("non-working-days"),this.getAttribute("holidays")),k=A(Math.max(...e.map(f=>$(f.end)??0)),3),y=Math.max(320,(k-r)/D*i),w=r+y/i*D,x=260,M=x+y,T=N+a.length*S,z=f=>(f-r)/D*i,U=Z({dateStyle:"medium"}),P=Z({month:"long",year:"numeric"}),lt=Z({month:"short"}),st=(f,E)=>{const L=new Date(f);return E==="day"||E==="week"?String(L.getDate()):E==="month"?lt.format(L):E==="quarter"?`Q${Math.floor(L.getMonth()/3)+1}`:String(L.getFullYear())},R=[],q=(f,E,L,_,G)=>`<rect x="${f.toFixed(1)}" y="${E.toFixed(1)}" width="${Math.max(0,L).toFixed(1)}" height="${_}" ${G}/>`;R.push(q(0,0,M,T,`fill="${g}"`));const K=b==="year"?null:b==="day"||b==="week"?"month":"year";if(K)for(const f of kt(K,m,r,w,i,0,Number.POSITIVE_INFINITY)){const E=K==="month"?P.format(new Date(f.start)):String(new Date(f.start).getFullYear());R.push(`<line x1="${(x+f.left).toFixed(1)}" y1="0" x2="${(x+f.left).toFixed(1)}" y2="26" stroke="${d}"/>`),f.width>=It&&R.push(`<text x="${(x+f.left+8).toFixed(1)}" y="17" font-size="11" font-weight="700" fill="${c}">${v(E)}</text>`)}const J=K?26:0;for(const f of kt(b,m,r,w,i,0,Number.POSITIVE_INFINITY))R.push(`<line x1="${(x+f.left).toFixed(1)}" y1="${J}" x2="${(x+f.left).toFixed(1)}" y2="${T}" stroke="${d}" stroke-opacity=".45"/>`),(f.width>=It||b==="day")&&R.push(`<text x="${(x+f.left+8).toFixed(1)}" y="${J+18}" font-size="11" font-weight="650" fill="${h}">${v(st(f.start,b))}</text>`);if(R.push(`<line x1="0" y1="${N}" x2="${M}" y2="${N}" stroke="${d}"/>`),R.push(`<text x="10" y="${N/2+4}" font-size="11" font-weight="700" fill="${h}">${v(t.columnTask.toUpperCase())}</text>`),i>=fe&&(p.weekdays.size||p.holidays.size))for(let f=r;f<w;f=A(f,1))ge(f,p)&&R.push(q(x+z(f),N,i,a.length*S,`fill="${p.holidays.has(f)?"#d97706":h}" fill-opacity="${p.holidays.has(f)?".15":".1"}"`));a.forEach((f,E)=>{const L=N+E*S;R.push(`<line x1="0" y1="${L+S}" x2="${M}" y2="${L+S}" stroke="${d}" stroke-opacity=".5"/>`),R.push(`<text x="${10+f.depth*18}" y="${L+S/2+4}" font-size="12" font-weight="650" fill="${c}">${v(f.label.length>34-f.depth*2?`${f.label.slice(0,33-f.depth*2)}…`:f.label)}</text>`)}),R.push(`<line x1="${x}" y1="0" x2="${x}" y2="${T}" stroke="${d}"/>`);const O=[],V=new Map(a.map((f,E)=>[f.id,{task:f,index:E}]));for(const f of this.getLinks()){const E=V.get(f.source),L=V.get(f.target);!E||!L||O.push(`<path d="${oe(E.task,E.index,L.task,L.index,f.type,z)}" fill="none" stroke="${h}" stroke-width="1.35" stroke-linecap="round" stroke-linejoin="round" marker-end="url(#arrow)"/>`)}a.forEach((f,E)=>{const L=E*S,_=ut(f),G=f.critical?u:o(mt[f.tone||(_==="summary"?"info":"default")]||mt.default),at=z(f.startMs),dt=Math.max(12,z(f.endMs)-at);if(f.baselineStart&&f.baselineEnd){const F=$(f.baselineStart)??f.startMs,C=$(f.baselineEnd)??f.endMs;O.push(q(z(F),L+33,Math.max(4,z(C)-z(F)),4,`rx="2" fill="${h}" fill-opacity=".5"`))}if(_==="milestone"){const F=at,C=L+21;O.push(`<polygon points="${F},${C-10} ${F+10},${C} ${F},${C+10} ${F-10},${C}" fill="${G}"/>`);return}const rt=_==="summary"?L+17:L+12,it=_==="summary"?9:18,$t=Math.max(0,Math.min(100,Number(f.progress??0))),pt=(F,C,tt)=>{O.push(q(F,rt,C,it,`rx="4" fill="${G}"`)),_==="summary"&&O.push(q(F,rt,C,it,'rx="3" fill="#000" fill-opacity=".2"')),tt>0&&O.push(q(F,rt,C*tt/100,it,'rx="4" fill="#000" fill-opacity=".28"'))};if(_==="task"&&f.segments?.length)for(const F of f.segments){const C=$(F.start),tt=$(F.end);C==null||tt==null||tt<=C||pt(z(Math.max(f.startMs,C)),z(Math.min(f.endMs,tt))-z(Math.max(f.startMs,C)),F.progress??$t)}else pt(at,dt,$t)});const et=Y(Date.now());return this.getAttribute("show-today")!=="false"&&et>=r&&et<=w&&(O.push(`<line x1="${z(et).toFixed(1)}" y1="0" x2="${z(et).toFixed(1)}" y2="${a.length*S}" stroke="${u}" stroke-width="2"/>`),R.push(`<text x="${(x+z(et)).toFixed(1)}" y="${N-6}" font-size="10" font-weight="700" text-anchor="middle" fill="${u}">${v(t.today)}</text>`)),R.push(`<g transform="translate(${x} ${N})">${O.join("")}</g>`),R.push(`<title>${v(this.getAttribute("aria-label")||t.title)} (${v(U.format(new Date(r)))} – ${v(U.format(new Date(k)))})</title>`),`<svg xmlns="http://www.w3.org/2000/svg" width="${Math.round(M)}" height="${T}" viewBox="0 0 ${Math.round(M)} ${T}" font-family="system-ui, -apple-system, 'Segoe UI', sans-serif"><defs><marker id="arrow" markerWidth="9" markerHeight="9" refX="8.5" refY="4.5" orient="auto" markerUnits="userSpaceOnUse"><path d="M 0.5 0.75 L 8.5 4.5 L 0.5 8.25 z" fill="${h}"/></marker></defs>`+R.join("")+"</svg>"}rangeMin(){const e=this.getTasks().map(r=>$(r.start)).filter(r=>r!=null);return e.length?A(Math.min(...e),-2):Y(Date.now())}selectTask(t){if(this.captureViewport(),this.selectedLinkId=null,this.selectedId===t){this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:t},bubbles:!0,composed:!0}));return}this.selectedId=t,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:t},bubbles:!0,composed:!0})),this.requestRender()}focusTask(t,e){this.selectedId!==t&&(this.selectedId=t,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:t},bubbles:!0,composed:!0}))),this.focusRequest={selector:e==="row"?Nt(t):At(t),reveal:!0,retries:0},this.reveal(t,"auto"),this.requestRender()}navigate(t,e,r){const i=this.visibleIds,a=i.indexOf(t);if(a<0)return!1;let s;switch(e){case"ArrowUp":s=i[a-1];break;case"ArrowDown":s=i[a+1];break;case"Home":s=i[0];break;case"End":s=i[i.length-1];break;case"PageUp":s=i[Math.max(0,a-10)];break;case"PageDown":s=i[Math.min(i.length-1,a+10)];break;case"ArrowRight":case"ArrowLeft":{if(r!=="row")return!1;const o=this.getTasks(),h=new Set(o.map(d=>d.parent).filter(d=>!!d)).has(t);if(e==="ArrowRight"){if(!h)return!0;this.collapsed.has(t)?this.toggleTask(t,!0):s=i[a+1]}else if(h&&!this.collapsed.has(t))this.toggleTask(t,!1);else{const d=o.find(g=>g.id===t)?.parent;d&&i.includes(d)&&(s=d)}break}default:return!1}return s&&s!==t&&this.focusTask(s,r),!0}captureViewport(){const t=this.root.querySelector(".viewport");t&&(this.viewportTop=t.scrollTop,this.viewportLeft=t.scrollLeft,this.viewportWidth=t.clientWidth||this.viewportWidth,this.viewportHeight=t.clientHeight||this.viewportHeight)}getTasks(){const t=this.getAttribute("tasks"),e=this.hasAttribute("auto-summary"),r=this.hasAttribute("critical-path")?this.getAttribute("links")??"":null;return t===this.taskCacheRaw&&this.taskCacheVersion===this.overridesVersion&&e===this.taskCacheAuto&&r===this.taskCacheCritical?this.taskCache:(this.taskCacheRaw=t,this.taskCacheVersion=this.overridesVersion,this.taskCacheAuto=e,this.taskCacheCritical=r,this.taskCache=je(t,this.overrides,e),e&&(this.taskCache=lr(this.taskCache)),r!==null&&(this.taskCache=dr(this.taskCache,Zt(r))),this.seedCollapsed(this.taskCache),this.visibleCacheKey="",this.taskCache)}seedCollapsed(t){for(const e of t)this.seededIds.has(e.id)||(this.seededIds.add(e.id),e.open===!1&&this.collapsed.add(e.id))}getLinks(){const t=this.getAttribute("links");return t===this.linkCacheRaw?this.linkCache:(this.linkCacheRaw=t,this.linkCache=Zt(t),this.linkCache)}getVisibleTasks(t,e,r){const i=Array.from(this.collapsed).sort().join(","),a=`${this.taskCacheRaw||""}|${this.overridesVersion}|${e}|${r}|${i}`;return a===this.visibleCacheKey?this.visibleCache:(this.visibleCacheKey=a,this.visibleCache=Xe(t,this.collapsed,e,r),this.visibleCache)}bumpOverrides(){this.overridesVersion+=1,this.taskCacheVersion=-1,this.visibleCacheKey=""}shouldRenderOnAttributeChange(t,e,r){if(t==="tasks"){this.overrides.clear(),this.bumpOverrides();const i=ee(r);Ge(ee(e),i)||(this.viewportTop=0,this.viewportLeft=0,this.initialScrollPending=!0,this.collapsed.clear(),this.seededIds.clear()),this.selectedId!=null&&!i.has(this.selectedId)&&(this.selectedId=null)}return t==="links"&&(this.linkCacheRaw=null),(t==="auto-summary"||t==="cascade")&&this.bumpOverrides(),!0}}typeof customElements<"u"&&!customElements.get("ui-gantt")&&customElements.define("ui-gantt",me);exports.UIGantt=me;
|