@editora/ui-core 0.1.13 → 0.1.14

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.
Files changed (73) hide show
  1. package/README.md +96 -6
  2. package/dist/color-picker.cjs.js +1 -1
  3. package/dist/color-picker.esm.js +2 -1
  4. package/dist/components/date-time-utils.d.ts.map +1 -1
  5. package/dist/components/ui-context-menu.d.ts +6 -0
  6. package/dist/components/ui-context-menu.d.ts.map +1 -1
  7. package/dist/components/ui-floating-toolbar.d.ts +3 -0
  8. package/dist/components/ui-floating-toolbar.d.ts.map +1 -1
  9. package/dist/components/ui-gantt.d.ts +30 -1
  10. package/dist/components/ui-gantt.d.ts.map +1 -1
  11. package/dist/components/ui-hover-card.d.ts +3 -0
  12. package/dist/components/ui-hover-card.d.ts.map +1 -1
  13. package/dist/components/ui-positioner.d.ts.map +1 -1
  14. package/dist/context-menu.cjs.js +12 -12
  15. package/dist/context-menu.esm.js +159 -132
  16. package/dist/date-field.cjs.js +1 -1
  17. package/dist/date-field.esm.js +2 -1
  18. package/dist/date-picker.cjs.js +1 -1
  19. package/dist/date-picker.esm.js +2 -1
  20. package/dist/date-range-picker.cjs.js +1 -1
  21. package/dist/date-range-picker.esm.js +2 -1
  22. package/dist/date-range-time-picker.cjs.js +2 -2
  23. package/dist/date-range-time-picker.esm.js +2 -1
  24. package/dist/date-time-picker.cjs.js +2 -2
  25. package/dist/date-time-picker.esm.js +2 -1
  26. package/dist/date-time-utils-66480de4.js +1 -0
  27. package/dist/date-time-utils-a2c7af25.mjs +307 -0
  28. package/dist/floating-toolbar.cjs.js +4 -4
  29. package/dist/floating-toolbar.esm.js +52 -25
  30. package/dist/gantt.cjs.js +656 -74
  31. package/dist/gantt.esm.js +1050 -100
  32. package/dist/hover-card.cjs.js +4 -4
  33. package/dist/hover-card.esm.js +61 -38
  34. package/dist/index.cjs.js +1 -1
  35. package/dist/index.esm.js +158 -146
  36. package/dist/menu.cjs.js +1 -1
  37. package/dist/menu.esm.js +2 -2
  38. package/dist/menubar.cjs.js +1 -1
  39. package/dist/menubar.esm.js +2 -2
  40. package/dist/popover.cjs.js +1 -1
  41. package/dist/popover.esm.js +2 -2
  42. package/dist/portal-c69756c0.js +1 -0
  43. package/dist/portal-fe73e5cc.mjs +123 -0
  44. package/dist/portal.d.ts +29 -3
  45. package/dist/portal.d.ts.map +1 -1
  46. package/dist/positioner-33529bb8.js +1 -0
  47. package/dist/positioner-e9770c66.mjs +582 -0
  48. package/dist/positioner.cjs.js +2 -2
  49. package/dist/positioner.esm.js +36 -26
  50. package/dist/primitives/positioner.d.ts +199 -1
  51. package/dist/primitives/positioner.d.ts.map +1 -1
  52. package/dist/{runtime-864efe2f.mjs → runtime-161f68a2.mjs} +24 -23
  53. package/dist/runtime-3f13807b.js +1 -0
  54. package/dist/runtime.cjs.js +1 -1
  55. package/dist/runtime.d.ts +2 -0
  56. package/dist/runtime.d.ts.map +1 -1
  57. package/dist/runtime.esm.js +39 -24
  58. package/dist/split-button.cjs.js +1 -1
  59. package/dist/split-button.esm.js +2 -2
  60. package/dist/time-field.cjs.js +1 -1
  61. package/dist/time-field.esm.js +14 -13
  62. package/dist/time-picker.cjs.js +1 -1
  63. package/dist/time-picker.esm.js +2 -1
  64. package/dist/tooltip.cjs.js +1 -1
  65. package/dist/tooltip.esm.js +2 -1
  66. package/package.json +2 -2
  67. package/dist/date-time-utils-378ecc21.js +0 -1
  68. package/dist/date-time-utils-a8b17ea7.mjs +0 -299
  69. package/dist/portal-9060f7a6.mjs +0 -114
  70. package/dist/portal-d9bae456.js +0 -1
  71. package/dist/positioner-16f3cca1.mjs +0 -132
  72. package/dist/positioner-43b1c75a.js +0 -1
  73. package/dist/runtime-668914fe.js +0 -1
package/dist/gantt.cjs.js CHANGED
@@ -1,157 +1,739 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const y=require("./ElementBase-1b301e7f.js"),d=`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const Lt=require("./ElementBase-1b301e7f.js"),I=24*60*60*1e3,$=42,W=62,J=376,N=28,Ft=15,wt=Ft*Math.SQRT2/2,ht={day:36,week:13,month:4.4,quarter:2.2,year:1.15},mt=`
2
2
  :host {
3
- --ui-gantt-bg: color-mix(in srgb, var(--ui-color-surface, #ffffff) 95%, transparent);
4
- --ui-gantt-border: color-mix(in srgb, var(--ui-color-border, #cbd5e1) 74%, transparent);
3
+ --ui-gantt-bg: color-mix(in srgb, var(--ui-color-surface, #ffffff) 96%, transparent);
4
+ --ui-gantt-panel: var(--ui-color-surface, #ffffff);
5
+ --ui-gantt-border: color-mix(in srgb, var(--ui-color-border, #cbd5e1) 76%, transparent);
6
+ --ui-gantt-grid: color-mix(in srgb, var(--ui-color-border, #cbd5e1) 56%, transparent);
5
7
  --ui-gantt-text: var(--ui-color-text, #0f172a);
6
8
  --ui-gantt-muted: var(--ui-color-muted, #64748b);
7
9
  --ui-gantt-accent: var(--ui-color-primary, #2563eb);
8
-
10
+ --ui-gantt-selected: color-mix(in srgb, var(--ui-gantt-accent) 10%, transparent);
9
11
  display: block;
10
12
  min-inline-size: 0;
11
13
  color-scheme: light dark;
12
14
  font-family: "Inter", "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
13
15
  }
14
16
 
17
+ *,
18
+ *::before,
19
+ *::after {
20
+ box-sizing: border-box;
21
+ }
22
+
15
23
  .frame {
16
24
  border: 1px solid var(--ui-gantt-border);
17
- border-radius: 14px;
25
+ border-radius: 12px;
18
26
  background: var(--ui-gantt-bg);
19
- box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
20
- padding: 12px;
21
- display: grid;
22
- gap: 10px;
27
+ box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
28
+ overflow: hidden;
23
29
  }
24
30
 
25
- .header {
31
+ .toolbar {
26
32
  display: flex;
33
+ align-items: center;
27
34
  justify-content: space-between;
28
- gap: 8px;
29
- font-size: 12px;
35
+ gap: 12px;
36
+ padding: 10px 12px;
37
+ border-bottom: 1px solid var(--ui-gantt-border);
38
+ background: color-mix(in srgb, var(--ui-gantt-panel) 92%, transparent);
39
+ }
40
+
41
+ .title {
42
+ min-inline-size: 0;
43
+ font-size: 13px;
44
+ font-weight: 750;
45
+ color: var(--ui-gantt-text);
46
+ }
47
+
48
+ .meta {
30
49
  color: var(--ui-gantt-muted);
50
+ font-weight: 600;
51
+ margin-inline-start: 8px;
52
+ }
53
+
54
+ .controls {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 6px;
58
+ flex-wrap: wrap;
59
+ }
60
+
61
+ .control,
62
+ .select,
63
+ .zoom-button {
64
+ border: 1px solid var(--ui-gantt-border);
65
+ background: var(--ui-gantt-panel);
66
+ color: var(--ui-gantt-text);
67
+ border-radius: 7px;
68
+ min-block-size: 30px;
69
+ font: inherit;
70
+ font-size: 12px;
71
+ }
72
+
73
+ .control {
74
+ inline-size: min(220px, 34vw);
75
+ padding: 0 9px;
76
+ }
77
+
78
+ .select {
79
+ padding: 0 28px 0 9px;
80
+ min-inline-size: 118px;
81
+ }
82
+
83
+ .zoom-button {
84
+ padding: 0 9px;
85
+ cursor: pointer;
86
+ }
87
+
88
+ .zoom-button[aria-pressed="true"] {
89
+ border-color: color-mix(in srgb, var(--ui-gantt-accent) 46%, var(--ui-gantt-border));
90
+ background: color-mix(in srgb, var(--ui-gantt-accent) 10%, var(--ui-gantt-panel));
91
+ color: var(--ui-gantt-accent);
92
+ }
93
+
94
+ .viewport {
95
+ overflow: auto;
96
+ max-block-size: var(--ui-gantt-max-height, 620px);
31
97
  }
32
98
 
33
- .rows {
99
+ .surface {
34
100
  display: grid;
35
- gap: 8px;
101
+ grid-template-columns: ${J}px minmax(640px, 1fr);
102
+ min-inline-size: 100%;
36
103
  }
37
104
 
38
- .row {
105
+ .grid-head,
106
+ .timeline-head {
107
+ position: sticky;
108
+ top: 0;
109
+ z-index: 4;
110
+ min-block-size: 62px;
111
+ background: color-mix(in srgb, var(--ui-gantt-panel) 96%, transparent);
112
+ border-bottom: 1px solid var(--ui-gantt-border);
113
+ }
114
+
115
+ .grid-head {
116
+ left: 0;
117
+ z-index: 5;
39
118
  display: grid;
40
- grid-template-columns: minmax(110px, 0.4fr) minmax(0, 1fr);
41
- gap: 10px;
119
+ grid-template-columns: minmax(170px, 1fr) 82px 80px 44px;
120
+ border-right: 1px solid var(--ui-gantt-border);
121
+ }
122
+
123
+ .grid-head span,
124
+ .head-button,
125
+ .grid-cell {
126
+ display: flex;
42
127
  align-items: center;
128
+ min-inline-size: 0;
129
+ padding: 0 10px;
130
+ border-right: 1px solid color-mix(in srgb, var(--ui-gantt-border) 62%, transparent);
43
131
  }
44
132
 
45
- .label {
46
- font-size: 12px;
133
+ .grid-head span {
134
+ font-size: 11px;
135
+ font-weight: 750;
136
+ color: var(--ui-gantt-muted);
137
+ text-transform: uppercase;
138
+ letter-spacing: 0;
139
+ }
140
+
141
+ .head-button {
142
+ border: 0;
143
+ background: transparent;
144
+ color: var(--ui-gantt-muted);
145
+ cursor: pointer;
146
+ font: inherit;
147
+ font-size: 11px;
148
+ font-weight: 750;
149
+ text-align: left;
150
+ text-transform: uppercase;
151
+ letter-spacing: 0;
152
+ }
153
+
154
+ .head-button:hover,
155
+ .head-button[aria-sort]:not([aria-sort="none"]) {
156
+ color: var(--ui-gantt-accent);
157
+ }
158
+
159
+ .grid-head span:last-child,
160
+ .grid-cell:last-child {
161
+ border-right: 0;
162
+ }
163
+
164
+ .timeline-head {
165
+ position: sticky;
166
+ top: 0;
167
+ overflow: hidden;
168
+ }
169
+
170
+ .scale {
171
+ position: relative;
172
+ min-block-size: 62px;
173
+ }
174
+
175
+ .tick {
176
+ position: absolute;
177
+ inset-block: 0;
178
+ border-left: 1px solid var(--ui-gantt-grid);
179
+ padding: 9px 8px;
180
+ color: var(--ui-gantt-muted);
181
+ font-size: 11px;
182
+ font-weight: 650;
183
+ white-space: nowrap;
184
+ }
185
+
186
+ .grid-body {
187
+ position: sticky;
188
+ left: 0;
189
+ z-index: 3;
190
+ background: var(--ui-gantt-panel);
191
+ border-right: 1px solid var(--ui-gantt-border);
192
+ }
193
+
194
+ .timeline-body {
195
+ position: relative;
196
+ background:
197
+ linear-gradient(to right, var(--ui-gantt-grid) 1px, transparent 1px) 0 0 / var(--day-width) 100%,
198
+ color-mix(in srgb, var(--ui-gantt-panel) 98%, transparent);
199
+ }
200
+
201
+ .grid-row,
202
+ .timeline-row {
203
+ block-size: ${$}px;
204
+ border-bottom: 1px solid color-mix(in srgb, var(--ui-gantt-border) 56%, transparent);
205
+ }
206
+
207
+ .grid-row {
208
+ display: grid;
209
+ grid-template-columns: minmax(170px, 1fr) 82px 80px 44px;
47
210
  color: var(--ui-gantt-text);
48
- font-weight: 600;
211
+ font-size: 12px;
212
+ }
213
+
214
+ .grid-row.selected,
215
+ .timeline-row.selected {
216
+ background: var(--ui-gantt-selected);
217
+ }
218
+
219
+ .task-name {
220
+ gap: 7px;
221
+ font-weight: 650;
222
+ }
223
+
224
+ .expander {
225
+ flex: 0 0 22px;
226
+ inline-size: 22px;
227
+ block-size: 22px;
228
+ border: 0;
229
+ border-radius: 6px;
230
+ background: transparent;
231
+ color: var(--ui-gantt-muted);
232
+ cursor: pointer;
233
+ display: grid;
234
+ place-items: center;
235
+ font-size: 13px;
236
+ }
237
+
238
+ .expander:hover {
239
+ background: color-mix(in srgb, var(--ui-gantt-accent) 9%, transparent);
240
+ color: var(--ui-gantt-accent);
241
+ }
242
+
243
+ .name-text {
49
244
  overflow: hidden;
50
245
  text-overflow: ellipsis;
51
246
  white-space: nowrap;
52
247
  }
53
248
 
54
- .track {
249
+ .badge {
250
+ justify-content: center;
251
+ font-variant-numeric: tabular-nums;
252
+ color: var(--ui-gantt-muted);
253
+ font-size: 11px;
254
+ }
255
+
256
+ .timeline-row {
55
257
  position: relative;
56
- border: 1px solid color-mix(in srgb, var(--ui-gantt-border) 72%, transparent);
57
- border-radius: 999px;
58
- background: color-mix(in srgb, var(--ui-gantt-bg) 90%, transparent);
59
- min-block-size: 14px;
60
258
  }
61
259
 
62
260
  .bar {
63
261
  position: absolute;
64
- top: 1px;
65
- bottom: 1px;
66
- border-radius: 999px;
67
- background: var(--tone, var(--ui-gantt-accent));
68
- box-shadow: 0 6px 14px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 26%, transparent);
262
+ top: 12px;
263
+ block-size: 18px;
264
+ min-inline-size: 10px;
265
+ border: 0;
266
+ border-radius: 4px;
267
+ background:
268
+ linear-gradient(180deg, color-mix(in srgb, #ffffff 22%, transparent), transparent 42%),
269
+ var(--tone, var(--ui-gantt-accent));
270
+ box-shadow:
271
+ 0 4px 10px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 18%, transparent),
272
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 20%, transparent);
273
+ cursor: grab;
69
274
  overflow: hidden;
275
+ outline: 0;
276
+ touch-action: none;
277
+ transition: box-shadow 140ms ease, filter 140ms ease, transform 140ms ease;
278
+ will-change: left, width;
279
+ }
280
+
281
+ .bar:hover,
282
+ .bar.dragging {
283
+ filter: saturate(1.08);
284
+ box-shadow:
285
+ 0 6px 14px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 26%, transparent),
286
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 30%, transparent);
287
+ }
288
+
289
+ .bar.dragging {
290
+ cursor: grabbing;
291
+ z-index: 5;
292
+ transform: translateY(-1px);
293
+ }
294
+
295
+ .bar:focus-visible {
296
+ outline: 2px solid var(--ui-gantt-accent);
297
+ outline-offset: 2px;
298
+ }
299
+
300
+ .bar.critical {
301
+ --tone: var(--ui-color-danger, #dc2626);
302
+ box-shadow:
303
+ 0 5px 12px color-mix(in srgb, var(--ui-color-danger, #dc2626) 24%, transparent),
304
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 28%, transparent);
305
+ }
306
+
307
+ .bar.split {
308
+ background: transparent;
309
+ box-shadow: none;
310
+ overflow: visible;
311
+ }
312
+
313
+ .bar.split .progress {
314
+ display: none;
315
+ }
316
+
317
+ .split-segment {
318
+ position: absolute;
319
+ inset-block: 0;
320
+ border-radius: 4px;
321
+ background:
322
+ linear-gradient(180deg, color-mix(in srgb, #ffffff 22%, transparent), transparent 42%),
323
+ var(--tone, var(--ui-gantt-accent));
324
+ box-shadow:
325
+ 0 4px 10px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 18%, transparent),
326
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 24%, transparent);
327
+ }
328
+
329
+ .baseline {
330
+ position: absolute;
331
+ top: 33px;
332
+ block-size: 4px;
333
+ border-radius: 999px;
334
+ background: color-mix(in srgb, var(--ui-gantt-muted) 54%, transparent);
335
+ z-index: 1;
336
+ }
337
+
338
+ .bar.summary {
339
+ block-size: 9px;
340
+ top: 17px;
341
+ border-radius: 3px;
342
+ background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 82%, #0f172a);
343
+ }
344
+
345
+ .bar.milestone {
346
+ inline-size: 28px !important;
347
+ min-inline-size: 28px;
348
+ block-size: 28px;
349
+ top: 7px;
350
+ border-radius: 8px;
351
+ background: transparent;
352
+ box-shadow: none;
353
+ cursor: grab;
354
+ overflow: visible;
355
+ display: grid;
356
+ place-items: center;
357
+ }
358
+
359
+ .bar.milestone:hover,
360
+ .bar.milestone.dragging {
361
+ box-shadow: none;
362
+ }
363
+
364
+ .milestone-shape {
365
+ inline-size: 15px;
366
+ block-size: 15px;
367
+ border-radius: 4px;
368
+ background:
369
+ linear-gradient(135deg, color-mix(in srgb, #ffffff 24%, transparent), transparent 48%),
370
+ var(--tone, var(--ui-gantt-accent));
371
+ box-shadow:
372
+ 0 7px 18px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 28%, transparent),
373
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 34%, transparent);
374
+ transform: rotate(45deg);
375
+ transition: transform 140ms ease, box-shadow 140ms ease, filter 140ms ease;
376
+ }
377
+
378
+ .bar.milestone:hover .milestone-shape,
379
+ .bar.milestone.dragging .milestone-shape {
380
+ filter: saturate(1.1);
381
+ transform: rotate(45deg) scale(1.08);
382
+ box-shadow:
383
+ 0 10px 24px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 36%, transparent),
384
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 44%, transparent);
385
+ }
386
+
387
+ .bar.milestone .progress,
388
+ .bar.milestone .handle,
389
+ .bar.summary .handle {
390
+ display: none;
70
391
  }
71
392
 
72
393
  .progress {
394
+ position: absolute;
395
+ inset-block: 0;
396
+ inset-inline-start: 0;
397
+ background: linear-gradient(90deg, color-mix(in srgb, #000 22%, transparent), transparent);
398
+ opacity: 0.3;
399
+ inline-size: var(--progress, 0%);
400
+ }
401
+
402
+ .handle {
403
+ position: absolute;
404
+ inset-block: 0;
405
+ inline-size: 14px;
406
+ cursor: ew-resize;
407
+ z-index: 2;
408
+ opacity: 0;
409
+ transition: opacity 120ms ease;
410
+ }
411
+
412
+ .handle.start {
413
+ inset-inline-start: 0;
414
+ }
415
+
416
+ .handle.end {
417
+ inset-inline-end: 0;
418
+ }
419
+
420
+ .handle::after {
421
+ content: "";
422
+ position: absolute;
423
+ inset-block-start: 50%;
424
+ inline-size: 4px;
425
+ block-size: 11px;
426
+ border-radius: 999px;
427
+ background: color-mix(in srgb, #ffffff 82%, transparent);
428
+ transform: translateY(-50%);
429
+ }
430
+
431
+ .handle.start::after {
432
+ inset-inline-start: 4px;
433
+ }
434
+
435
+ .handle.end::after {
436
+ inset-inline-end: 4px;
437
+ }
438
+
439
+ .bar:hover .handle,
440
+ .bar.dragging .handle {
441
+ opacity: 1;
442
+ }
443
+
444
+ .drag-tip {
445
+ position: absolute;
446
+ z-index: 6;
447
+ inset-block-start: -28px;
448
+ inset-inline-start: 50%;
449
+ transform: translateX(-50%);
450
+ padding: 4px 7px;
451
+ border-radius: 6px;
452
+ background: #0f172a;
453
+ color: #f8fafc;
454
+ font-size: 11px;
455
+ font-weight: 700;
456
+ white-space: nowrap;
457
+ pointer-events: none;
458
+ opacity: 0;
459
+ }
460
+
461
+ .bar.dragging .drag-tip {
462
+ opacity: 1;
463
+ }
464
+
465
+ :host([bar-variant="soft"]) .bar.task {
466
+ background:
467
+ linear-gradient(180deg, color-mix(in srgb, #ffffff 38%, transparent), transparent 46%),
468
+ color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 22%, var(--ui-gantt-panel));
469
+ color: var(--ui-gantt-text);
470
+ box-shadow:
471
+ inset 0 0 0 1px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 34%, transparent),
472
+ 0 6px 15px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 14%, transparent);
473
+ }
474
+
475
+ :host([bar-variant="soft"]) .milestone-shape {
476
+ background:
477
+ linear-gradient(135deg, color-mix(in srgb, #ffffff 42%, transparent), transparent 52%),
478
+ color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 28%, var(--ui-gantt-panel));
479
+ box-shadow:
480
+ inset 0 0 0 1px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 42%, transparent),
481
+ 0 7px 16px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 16%, transparent);
482
+ }
483
+
484
+ :host([bar-variant="striped"]) .bar.task {
485
+ background:
486
+ repeating-linear-gradient(135deg, color-mix(in srgb, #ffffff 24%, transparent) 0 7px, transparent 7px 14px),
487
+ var(--tone, var(--ui-gantt-accent));
488
+ }
489
+
490
+ :host([bar-variant="striped"]) .milestone-shape {
491
+ background:
492
+ repeating-linear-gradient(135deg, color-mix(in srgb, #ffffff 28%, transparent) 0 5px, transparent 5px 10px),
493
+ var(--tone, var(--ui-gantt-accent));
494
+ }
495
+
496
+ :host([bar-variant="outline"]) .bar.task {
497
+ background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 8%, var(--ui-gantt-panel));
498
+ box-shadow:
499
+ inset 0 0 0 1.5px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 72%, transparent),
500
+ 0 6px 15px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 10%, transparent);
501
+ }
502
+
503
+ :host([bar-variant="outline"]) .bar.task .progress {
504
+ background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 28%, transparent);
505
+ opacity: 1;
506
+ }
507
+
508
+ :host([bar-variant="outline"]) .milestone-shape {
509
+ background: color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 10%, var(--ui-gantt-panel));
510
+ box-shadow:
511
+ inset 0 0 0 2px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 72%, transparent),
512
+ 0 7px 16px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 10%, transparent);
513
+ }
514
+
515
+ :host([bar-variant="glass"]) .bar.task {
516
+ background:
517
+ linear-gradient(180deg, color-mix(in srgb, #ffffff 50%, transparent), color-mix(in srgb, #ffffff 10%, transparent)),
518
+ color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 72%, transparent);
519
+ backdrop-filter: blur(8px);
520
+ box-shadow:
521
+ inset 0 1px 0 color-mix(in srgb, #ffffff 48%, transparent),
522
+ inset 0 0 0 1px color-mix(in srgb, #ffffff 26%, transparent),
523
+ 0 10px 24px color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 20%, transparent);
524
+ }
525
+
526
+ :host([bar-variant="glass"]) .milestone-shape {
527
+ background:
528
+ linear-gradient(135deg, color-mix(in srgb, #ffffff 52%, transparent), color-mix(in srgb, #ffffff 8%, transparent)),
529
+ color-mix(in srgb, var(--tone, var(--ui-gantt-accent)) 74%, transparent);
530
+ backdrop-filter: blur(8px);
531
+ }
532
+
533
+ .today {
534
+ position: absolute;
535
+ inset-block: 0;
536
+ inline-size: 2px;
537
+ background: var(--ui-color-danger, #dc2626);
538
+ z-index: 2;
539
+ pointer-events: none;
540
+ }
541
+
542
+ .today::before {
543
+ content: "Today";
544
+ position: absolute;
545
+ inset-block-start: 4px;
546
+ inset-inline-start: 6px;
547
+ color: var(--ui-color-danger, #dc2626);
548
+ font-size: 11px;
549
+ font-weight: 750;
550
+ }
551
+
552
+ .links {
73
553
  position: absolute;
74
554
  inset: 0;
75
- background: linear-gradient(90deg, color-mix(in srgb, #000 18%, transparent), transparent);
76
- opacity: 0.28;
77
- width: var(--progress, 0%);
555
+ overflow: visible;
556
+ pointer-events: none;
557
+ z-index: 1;
558
+ }
559
+
560
+ .links path {
561
+ fill: none;
562
+ stroke: color-mix(in srgb, var(--ui-gantt-muted) 82%, transparent);
563
+ stroke-width: 1.35;
564
+ stroke-linecap: round;
565
+ stroke-linejoin: round;
566
+ vector-effect: non-scaling-stroke;
567
+ marker-end: url(#ui-gantt-arrow);
568
+ }
569
+
570
+ .links .link-hit {
571
+ stroke: transparent;
572
+ stroke-width: 10;
573
+ marker-end: none;
574
+ pointer-events: stroke;
575
+ cursor: pointer;
576
+ }
577
+
578
+ .links path:not(.link-hit) {
579
+ pointer-events: none;
580
+ }
581
+
582
+ .links marker path {
583
+ fill: color-mix(in srgb, var(--ui-gantt-muted) 82%, transparent);
584
+ stroke: none;
585
+ }
586
+
587
+ .empty {
588
+ padding: 28px;
589
+ color: var(--ui-gantt-muted);
590
+ font-size: 13px;
78
591
  }
79
592
 
80
593
  :host([variant="contrast"]) {
81
594
  --ui-gantt-bg: #0f172a;
595
+ --ui-gantt-panel: #111827;
82
596
  --ui-gantt-border: #334155;
597
+ --ui-gantt-grid: #263449;
83
598
  --ui-gantt-text: #e2e8f0;
84
599
  --ui-gantt-muted: #93a4bd;
85
- --ui-gantt-accent: #93c5fd;
600
+ --ui-gantt-accent: #60a5fa;
601
+ --ui-gantt-selected: rgba(96, 165, 250, 0.13);
602
+ }
603
+
604
+ :host([readonly]) .bar {
605
+ cursor: pointer;
86
606
  }
87
607
 
88
608
  :host([headless]) .frame {
89
609
  display: none;
90
610
  }
91
611
 
92
- @media (prefers-reduced-motion: reduce) {
93
- .bar,
94
- .progress {
95
- transition: none !important;
612
+ @media (max-width: 760px) {
613
+ .surface {
614
+ grid-template-columns: 270px minmax(560px, 1fr);
96
615
  }
97
- }
98
616
 
99
- @media (prefers-contrast: more) {
100
- .frame {
101
- box-shadow: none;
617
+ .grid-head,
618
+ .grid-row {
619
+ grid-template-columns: minmax(150px, 1fr) 64px 56px;
102
620
  }
103
621
 
104
- .track {
105
- border-width: 2px;
622
+ .grid-head span:nth-child(3),
623
+ .grid-cell:nth-child(3) {
624
+ display: none;
625
+ }
626
+ }
627
+
628
+ @media (prefers-reduced-motion: reduce) {
629
+ .bar,
630
+ .progress {
631
+ transition: none !important;
106
632
  }
107
633
  }
108
634
 
109
635
  @media (forced-colors: active) {
110
636
  :host {
111
637
  --ui-gantt-bg: Canvas;
638
+ --ui-gantt-panel: Canvas;
112
639
  --ui-gantt-border: CanvasText;
640
+ --ui-gantt-grid: CanvasText;
113
641
  --ui-gantt-text: CanvasText;
114
642
  --ui-gantt-muted: CanvasText;
115
643
  --ui-gantt-accent: Highlight;
644
+ --ui-gantt-selected: Highlight;
116
645
  }
117
646
 
118
647
  .frame,
119
- .track,
648
+ .grid-head,
649
+ .timeline-head,
650
+ .grid-body,
120
651
  .bar,
121
- .progress {
652
+ .select,
653
+ .control,
654
+ .zoom-button {
122
655
  forced-color-adjust: none;
123
656
  box-shadow: none;
124
- border-color: CanvasText;
125
- }
126
-
127
- .frame,
128
- .track {
129
- background: Canvas;
130
- color: CanvasText;
131
- }
132
-
133
- .bar {
134
- background: Highlight;
135
657
  }
136
658
  }
137
- `,u={default:"var(--ui-color-primary, #2563eb)",info:"var(--ui-color-info, #0891b2)",success:"var(--ui-color-success, #16a34a)",warning:"var(--ui-color-warning, #d97706)",danger:"var(--ui-color-danger, #dc2626)"};function s(o){const e=Date.parse(o);return Number.isFinite(e)?e:null}function k(o){if(!o)return[];try{const e=JSON.parse(o);return Array.isArray(e)?e.map(t=>{if(!t||typeof t!="object")return null;const i=String(t.label||"").trim(),a=String(t.start||"").trim(),n=String(t.end||"").trim();return!i||!a||!n||s(a)==null||s(n)==null?null:{id:t.id?String(t.id):void 0,label:i,start:a,end:n,progress:Number.isFinite(Number(t.progress))?Number(t.progress):void 0,tone:t.tone}}).filter(Boolean):[]}catch{return[]}}class p extends y.ElementBase{static get observedAttributes(){return["tasks","variant","headless"]}render(){const e=k(this.getAttribute("tasks"));if(!e.length){this.setContent(`
138
- <style>${d}</style>
659
+ `,bt={default:"var(--ui-color-primary, #2563eb)",info:"var(--ui-color-info, #0891b2)",success:"var(--ui-color-success, #16a34a)",warning:"var(--ui-color-warning, #d97706)",danger:"var(--ui-color-danger, #dc2626)"};function f(n){return String(n??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function x(n){if(n instanceof Date){const a=n.getTime();return Number.isFinite(a)?D(a):null}const r=String(n||"").trim(),d=/^(\d{4})-(\d{2})-(\d{2})$/.exec(r);if(d){const a=Number(d[1]),e=Number(d[2]),i=Number(d[3]),g=new Date(a,e-1,i).getTime();return Number.isFinite(g)?D(g):null}const l=Date.parse(r);return Number.isFinite(l)?D(l):null}function D(n){const r=new Date(n);return r.setHours(0,0,0,0),r.getTime()}function w(n,r){return D(n+r*I)}function S(n){const r=new Date(n),d=r.getFullYear(),l=String(r.getMonth()+1).padStart(2,"0"),a=String(r.getDate()).padStart(2,"0");return`${d}-${l}-${a}`}function O(n){return new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric"}).format(new Date(n))}function ft(n){return n==="day"||n==="month"||n==="quarter"||n==="year"?n:"week"}function j(n){return n==="start"||n==="end"||n==="label"||n==="progress"?n:"none"}function Dt(n){return n==="soft"||n==="striped"||n==="outline"||n==="glass"?n:"solid"}function Rt(n,r){if(!n)return[];try{const d=JSON.parse(n);return Array.isArray(d)?d.map((l,a)=>{if(!l||typeof l!="object")return null;const e=l,i=String(e.label||e.text||"").trim(),s=x(e.start),g=Number(e.duration);let c=x(e.end);if(c==null&&s!=null&&Number.isFinite(g)&&(c=w(s,Math.max(0,g))),!i||s==null)return null;const o=e.type==="summary"||e.type==="milestone"?e.type:"task",u=o==="milestone"?s:Math.max(c??w(s,1),w(s,1)),p=String(e.id||`task-${a+1}`),m=r.get(p)||{};return{id:p,label:i,start:m.start||S(s),end:m.end||S(u),progress:Number.isFinite(Number(e.progress))?Math.max(0,Math.min(100,Number(e.progress))):void 0,tone:typeof e.tone=="string"?e.tone:void 0,type:o,parent:e.parent!=null?String(e.parent):void 0,open:e.open!==!1,assignee:e.assignee!=null?String(e.assignee):e.owner!=null?String(e.owner):void 0,readonly:e.readonly===!0,baselineStart:e.baselineStart!=null?String(e.baselineStart):void 0,baselineEnd:e.baselineEnd!=null?String(e.baselineEnd):void 0,critical:e.critical===!0,segments:Array.isArray(e.segments)?e.segments:void 0}}).filter(Boolean):[]}catch{return[]}}function qt(n){if(!n)return[];try{const r=JSON.parse(n);return Array.isArray(r)?r.map((d,l)=>{if(!d||typeof d!="object")return null;const a=d,e=String(a.source||"").trim(),i=String(a.target||"").trim();if(!e||!i)return null;const s=a.type==="s2s"||a.type==="e2e"||a.type==="s2e"?a.type:"e2s";return{id:String(a.id||`link-${l+1}`),source:e,target:i,type:s}}).filter(Boolean):[]}catch{return[]}}function Nt(n,r){return r==="none"?n:[...n].sort((d,l)=>{if(r==="label")return d.label.localeCompare(l.label);if(r==="progress")return Number(l.progress??0)-Number(d.progress??0);const a=x(r==="start"?d.start:d.end)??0,e=x(r==="start"?l.start:l.end)??0;return a-e})}function Ht(n,r,d,l){const a=new Map,e=new Map(n.map(o=>[o.id,o]));n.forEach(o=>{const u=o.parent&&e.has(o.parent)?o.parent:"__root__",p=a.get(u)||[];p.push(o),a.set(u,p)});const i=d.trim().toLowerCase(),s=o=>!i||o.label.toLowerCase().includes(i)||(o.assignee||"").toLowerCase().includes(i)?!0:(a.get(o.id)||[]).some(s),g=[],c=(o,u)=>{Nt(a.get(o)||[],l).forEach(p=>{if(!s(p))return;const m=x(p.start),h=x(p.end);if(m==null||h==null)return;const b=(a.get(p.id)||[]).length>0;g.push({...p,depth:u,hasChildren:b,startMs:m,endMs:h}),b&&!r.has(p.id)&&c(p.id,u+1)})};return c("__root__",0),g}function _t(n,r,d,l,a=0,e=Number.POSITIVE_INFINITY){const i=Math.max(1,Math.ceil((r-n)/I)),s=l==="day"?1:l==="week"?7:l==="month"?30:l==="quarter"?91:365,g=Math.max(0,Math.floor(Math.max(0,a-480)/d/s)*s),c=Math.min(i,Math.ceil((a+e+960)/d/s)*s),o=[];for(let u=g;u<=c;u+=s){const p=u*d,m=w(n,u),h=l==="day"?O(m):new Intl.DateTimeFormat(void 0,{month:"short",year:l==="week"||l==="month"?void 0:"numeric"}).format(new Date(m));o.push(`<span class="tick" style="left:${p.toFixed(2)}px">${f(h)}</span>`)}return o.join("")}function H(n){return n.type==="summary"||n.hasChildren?"summary":n.type==="milestone"||n.startMs===n.endMs?"milestone":"task"}function xt(n){const r=H(n);return r==="summary"?17+9/2:r==="milestone"?7+N/2:12+18/2}function Vt(n,r){return H(n)==="milestone"?r(n.startMs)-wt:r(n.startMs)}function Wt(n,r){return H(n)==="milestone"?r(n.startMs)+wt:r(n.endMs)}function vt(n,r,d){return r==="start"?Vt(n,d):Wt(n,d)}function jt(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 Ot(n,r,d,l,a,e){const i=jt(a),s=i.source==="start"?-1:1,g=i.target==="start"?1:-1,c=vt(n,i.source,e),o=vt(d,i.target,e),u=r*$+xt(n),p=l*$+xt(d),m=22,h=c+s*m,b=o-g*m,v=26;let y=(h+b)/2;if(s===g){const T=s===1?Math.max(h,b,c,o)+v:Math.min(h,b,c,o)-v;y=(s===1?b>h+v:b<h-v)?y:T}else(s===1?b<h:b>h)&&(y=s===1?Math.max(h,c,o)+v:Math.min(h,c,o)-v);const A=Math.abs(p-u)<1?i.target==="start"?p-16:p+16:p>u?p-$/2+3:p+$/2-3;return[[c,u],[h,u],[y,u],[y,A],[b,A],[b,p],[o,p]].map(([T,R],P)=>`${P===0?"M":"L"} ${T.toFixed(1)} ${R.toFixed(1)}`).join(" ")}class yt extends Lt.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 r=this.getTasks(),d=this.getLinks(),l=ft(this.getAttribute("zoom")),a=j(this.getAttribute("sort")),e=Dt(this.getAttribute("bar-variant")),i=this.getAttribute("filter")??this.internalFilter,s=this.getVisibleTasks(r,i,a),g=this.hasAttribute("readonly"),c=this.getAttribute("show-toolbar")!=="false",o=this.getAttribute("show-today")!=="false";if(!r.length){this.setContent(`
660
+ <style>${mt}</style>
139
661
  <section class="frame" part="frame">
140
- <div class="header">No tasks in this range</div>
662
+ <div class="empty" part="empty">No tasks in this range</div>
141
663
  </section>
142
- `);return}const t=e.map(r=>s(r.start)||0),i=e.map(r=>s(r.end)||0),a=Math.min(...t),n=Math.max(...i),c=Math.max(1,n-a),g=e.map(r=>{const l=s(r.start)||a,f=s(r.end)||l,x=(l-a)/c*100,v=Math.max(2,(Math.max(f,l)-l)/c*100),h=Math.max(0,Math.min(100,Number(r.progress??0))),w=u[r.tone||"default"]||u.default;return`
143
- <article class="row" part="row">
144
- <span class="label" title="${r.label}">${r.label}</span>
145
- <div class="track">
146
- <div class="bar" style="left:${x.toFixed(2)}%;width:${v.toFixed(2)}%;--tone:${w}">
147
- <span class="progress" style="--progress:${h.toFixed(2)}%"></span>
148
- </div>
664
+ `);return}const u=r.map(t=>x(t.start)).filter(t=>t!=null),p=r.map(t=>x(t.end)).filter(t=>t!=null),m=w(Math.min(...u),-2),h=w(Math.max(...p),3),b=Math.max(7,Math.ceil((h-m)/I)),v=ht[l],y=Math.max(680,b*v),A=Math.max(s.length*$,$),z=this.getAttribute("virtualized")!=="false"&&s.length>240,T=Math.max(20,Math.ceil(Math.max(420,this.viewportHeight-W)/$)),R=160,P=Math.max(0,this.viewportTop-W),kt=Math.max(0,Math.floor(P/$)),X=Math.max(180,T*4),L=z?Math.max(0,Math.floor(kt/X)*X-R):0,B=z?Math.min(s.length,L+T+R*2+X):s.length,K=s.slice(L,B),_=L*$,V=Math.max(0,(s.length-B)*$);this.renderedFirstRow=L,this.renderedLastRow=B;const Q=new Map(s.map((t,M)=>[t.id,{task:t,index:M}])),tt=new Set(K.map(t=>t.id)),C=t=>(t-m)/I*v,$t=K.map((t,M)=>{const E=L+M,k=this.selectedId===t.id?" selected":"",F=H(t),G=t.progress==null?"-":`${Math.round(t.progress)}%`,U=F==="milestone"?O(t.startMs):`${O(t.startMs)} - ${O(t.endMs)}`;return`
665
+ <article class="grid-row${k}" part="grid-row" data-task-id="${f(t.id)}" role="row" aria-rowindex="${E+2}" aria-level="${t.depth+1}" ${t.hasChildren?`aria-expanded="${!this.collapsed.has(t.id)}"`:""}>
666
+ <div class="grid-cell task-name" role="gridcell" style="padding-left:${10+t.depth*18}px">
667
+ ${t.hasChildren?`<button class="expander" data-action="toggle" data-task-id="${f(t.id)}" aria-label="${this.collapsed.has(t.id)?"Expand":"Collapse"} ${f(t.label)}">${this.collapsed.has(t.id)?"›":"⌄"}</button>`:'<span style="inline-size:22px"></span>'}
668
+ <span class="name-text" title="${f(t.label)}">${f(t.label)}</span>
669
+ </div>
670
+ <div class="grid-cell badge" role="gridcell">${f(t.assignee||F)}</div>
671
+ <div class="grid-cell badge" role="gridcell">${f(U)}</div>
672
+ <div class="grid-cell badge" role="gridcell">${f(G)}</div>
673
+ </article>
674
+ `}).join(""),Mt=K.map((t,M)=>{var st;const E=L+M,k=H(t),F=this.selectedId===t.id?" selected":"",G=this.selectedId===t.id||!this.selectedId&&E===0,U=bt[t.tone||(k==="summary"?"info":"default")]||bt.default,rt=k==="milestone"?C(t.startMs)-N/2:C(t.startMs),Ct=C(k==="milestone"?t.startMs:t.endMs),Tt=k==="milestone"?N:Math.max(12,Ct-rt),It=Math.max(0,Math.min(100,Number(t.progress??0))),at=!g&&!t.readonly&&k!=="summary",nt=at&&k==="task",it=k==="task"&&((st=t.segments)!=null&&st.length)?t.segments.map(ot=>{const lt=x(ot.start),dt=x(ot.end);if(lt==null||dt==null)return"";const ct=Math.max(I,t.endMs-t.startMs),Z=Math.max(t.startMs,lt),pt=Math.min(t.endMs,dt);if(pt<=Z)return"";const ut=Math.max(0,Math.min(100,(Z-t.startMs)/ct*100)),At=(pt-Z)/ct*100,gt=Math.min(100-ut,Math.max(1,At));return gt<=0?"":`<span class="split-segment" style="left:${ut.toFixed(2)}%;width:${gt.toFixed(2)}%"></span>`}).join(""):"";return`
675
+ <article class="timeline-row${F}" part="timeline-row" data-task-id="${f(t.id)}" role="row" aria-rowindex="${E+2}">
676
+ ${t.baselineStart&&t.baselineEnd?`<span class="baseline" style="left:${C(x(t.baselineStart)||t.startMs).toFixed(2)}px;width:${Math.max(4,C(x(t.baselineEnd)||t.endMs)-C(x(t.baselineStart)||t.startMs)).toFixed(2)}px"></span>`:""}
677
+ <button
678
+ class="bar ${k}${t.critical?" critical":""}${it?" split":""}"
679
+ part="bar ${k}"
680
+ data-task-id="${f(t.id)}"
681
+ data-kind="${k}"
682
+ role="gridcell"
683
+ tabindex="${G?"0":"-1"}"
684
+ aria-selected="${this.selectedId===t.id}"
685
+ aria-colindex="5"
686
+ style="left:${rt.toFixed(2)}px;width:${Tt.toFixed(2)}px;--tone:${U};--progress:${It.toFixed(2)}%"
687
+ aria-label="${f(t.label)}"
688
+ ${at?'data-draggable="true"':""}
689
+ >
690
+ ${nt?'<span class="handle start" data-mode="resize-start"></span>':""}
691
+ <span class="progress"></span>
692
+ ${it}
693
+ ${k==="milestone"?'<span class="milestone-shape"></span>':""}
694
+ <span class="drag-tip"></span>
695
+ ${nt?'<span class="handle end" data-mode="resize-end"></span>':""}
696
+ </button>
697
+ </article>
698
+ `}).join(""),et=d.map(t=>{const M=Q.get(t.source),E=Q.get(t.target);if(!M||!E||z&&!tt.has(t.source)&&!tt.has(t.target))return"";const k=Ot(M.task,M.index,E.task,E.index,t.type,C),F=`${M.task.label} dependency to ${E.task.label}`;return`<path class="link-hit" d="${k}" data-link-id="${f(t.id)}" data-source-id="${f(t.source)}" data-target-id="${f(t.target)}" data-link-type="${f(t.type||"e2s")}" aria-label="${f(F)}" /><path d="${k}" />`}).join(""),Et=et?'<defs><marker id="ui-gantt-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" /></marker></defs>':"",Y=D(Date.now()),St=C(Y),zt=o&&Y>=m&&Y<=h?`<div class="today" part="today" style="left:${St.toFixed(2)}px"></div>`:"";this.setContent(`
699
+ <style>${mt}</style>
700
+ <section class="frame" part="frame" data-bar-variant="${e}">
701
+ ${c?`
702
+ <header class="toolbar" part="toolbar">
703
+ <div class="title">Project schedule <span class="meta">${s.length}/${r.length} tasks</span></div>
704
+ <div class="controls">
705
+ <input class="control" value="${f(i)}" placeholder="Filter tasks" aria-label="Filter tasks" />
706
+ <select class="select" aria-label="Sort tasks">
707
+ ${[["none","Manual"],["start","Start date"],["end","End date"],["label","Name"],["progress","Progress"]].map(([t,M])=>`<option value="${t}" ${a===t?"selected":""}>${M}</option>`).join("")}
708
+ </select>
709
+ ${["day","week","month","quarter","year"].map(t=>`<button class="zoom-button" data-zoom="${t}" aria-pressed="${l===t}">${t}</button>`).join("")}
710
+ </div>
711
+ </header>
712
+ `:""}
713
+ <div class="viewport" part="viewport">
714
+ <div class="surface" part="surface" style="--day-width:${v}px;grid-template-columns:${J}px ${y.toFixed(2)}px;inline-size:max(100%, ${(J+y).toFixed(2)}px)">
715
+ <header class="grid-head" part="grid-head" role="row">
716
+ <button class="head-button" data-sort="label" role="columnheader" aria-sort="${a==="label"?"ascending":"none"}">Task</button>
717
+ <span role="columnheader">Owner</span>
718
+ <button class="head-button" data-sort="start" role="columnheader" aria-sort="${a==="start"?"ascending":"none"}">Dates</button>
719
+ <button class="head-button" data-sort="progress" role="columnheader" aria-sort="${a==="progress"?"descending":"none"}">%</button>
720
+ </header>
721
+ <header class="timeline-head" part="timeline-head">
722
+ <div class="scale" style="width:${y.toFixed(2)}px">${_t(m,h,v,l,this.viewportLeft,this.viewportWidth)}</div>
723
+ </header>
724
+ <div class="grid-body" part="grid-body" role="treegrid" aria-rowcount="${s.length+1}" aria-colcount="4">
725
+ ${z&&_?`<div style="height:${_}px"></div>`:""}
726
+ ${$t||'<div class="empty">No matching tasks</div>'}
727
+ ${z&&V?`<div style="height:${V}px"></div>`:""}
728
+ </div>
729
+ <div class="timeline-body" part="timeline-body" style="width:${y.toFixed(2)}px;min-height:${A}px">
730
+ <svg class="links" width="${y.toFixed(0)}" height="${A}" viewBox="0 0 ${y.toFixed(0)} ${A}" aria-hidden="true">${Et}${et}</svg>
731
+ ${zt}
732
+ ${z&&_?`<div style="height:${_}px"></div>`:""}
733
+ ${Mt}
734
+ ${z&&V?`<div style="height:${V}px"></div>`:""}
149
735
  </div>
150
- </article>
151
- `}).join(""),m=new Date(a).toLocaleDateString(),b=new Date(n).toLocaleDateString();this.setContent(`
152
- <style>${d}</style>
153
- <section class="frame" part="frame">
154
- <header class="header" part="header"><span>${m}</span><span>${b}</span></header>
155
- <div class="rows" part="rows">${g}</div>
736
+ </div>
737
+ </div>
156
738
  </section>
157
- `)}shouldRenderOnAttributeChange(e,t,i){return!0}}typeof customElements<"u"&&!customElements.get("ui-gantt")&&customElements.define("ui-gantt",p);exports.UIGantt=p;
739
+ `);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(){var r,d,l;this.root.querySelectorAll("[data-task-id]").forEach(a=>{a.addEventListener("click",e=>{var o;const i=e.target,s=e.currentTarget;if(!s.classList.contains("bar")&&i.closest(".bar"))return;if((o=this.drag)!=null&&o.moved){e.stopPropagation();return}const c=e.currentTarget.dataset.taskId;c&&(i.closest('[data-action="toggle"]')||(s.classList.contains("bar")&&e.stopPropagation(),this.selectTask(c)))})}),this.root.querySelectorAll('[data-action="toggle"]').forEach(a=>{a.addEventListener("click",e=>{e.stopPropagation();const i=a.dataset.taskId;i&&(this.collapsed.has(i)?this.collapsed.delete(i):this.collapsed.add(i),this.requestRender())})}),this.root.querySelectorAll("[data-zoom]").forEach(a=>{a.addEventListener("click",()=>{const e=a.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(a=>{a.addEventListener("click",()=>{const e=j(a.dataset.sort||null);e==="none"?this.removeAttribute("sort"):this.setAttribute("sort",e),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:e},bubbles:!0,composed:!0}))})}),(r=this.root.querySelector(".viewport"))==null||r.addEventListener("scroll",a=>{const e=a.currentTarget,i=e.scrollTop,s=e.scrollLeft,g=Math.max(20,Math.ceil(Math.max(420,this.viewportHeight-W)/$)),c=Math.max(0,Math.floor(Math.max(0,i-W)/$)),o=c<this.renderedFirstRow+64||c+g>this.renderedLastRow-64,u=Math.abs(s-this.viewportLeft)>=Math.max(480,this.viewportWidth*.6);this.viewportTop=i,this.viewportLeft=s,!(!o&&!u)&&this.scrollFrame==null&&(this.scrollFrame=window.setTimeout(()=>{this.scrollFrame=null,this.requestRender()},24))},{passive:!0}),(d=this.root.querySelector(".control"))==null||d.addEventListener("input",a=>{this.internalFilter=a.currentTarget.value,this.dispatchEvent(new CustomEvent("filterchange",{detail:{filter:this.internalFilter},bubbles:!0,composed:!0})),this.requestRender()}),(l=this.root.querySelector(".select"))==null||l.addEventListener("change",a=>{const e=j(a.currentTarget.value);e==="none"?this.removeAttribute("sort"):this.setAttribute("sort",e),this.dispatchEvent(new CustomEvent("sortchange",{detail:{sort:e},bubbles:!0,composed:!0}))}),this.root.querySelectorAll(".link-hit").forEach(a=>{a.addEventListener("click",e=>{e.stopPropagation(),this.dispatchEvent(new CustomEvent("linkselect",{detail:{id:a.dataset.linkId||"",source:a.dataset.sourceId||"",target:a.dataset.targetId||"",type:a.dataset.linkType||"e2s"},bubbles:!0,composed:!0}))})}),!this.hasAttribute("readonly")&&this.root.querySelectorAll('.bar[data-draggable="true"]').forEach(a=>{a.addEventListener("pointerdown",i=>{if(i.button!==0)return;const s=a.dataset.taskId;if(!s)return;const c=this.getTasks().find(y=>y.id===s),o=x(c==null?void 0:c.start),u=x(c==null?void 0:c.end);if(!c||o==null||u==null)return;i.preventDefault();const p=a.dataset.kind||"task",m=i.target.dataset.mode||"move",h=p==="milestone"?"move":m,b=ft(this.getAttribute("zoom")),v=this.selectedId!==s;this.selectedId=s,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:s},bubbles:!0,composed:!0})),this.drag={taskId:s,mode:h,startX:i.clientX,originalStart:o,originalEnd:u,kind:p,rangeMin:this.rangeMin(),dayWidth:ht[b],latestStart:o,latestEnd:u,frame:null,bar:a,moved:!1,selectedChanged:v},a.classList.add("dragging"),a.setPointerCapture(i.pointerId)}),a.addEventListener("pointermove",i=>{if(!this.drag||this.drag.taskId!==a.dataset.taskId)return;i.preventDefault();const s=i.clientX-this.drag.startX;Math.abs(s)>2&&(this.drag.moved=!0);let g=this.drag.originalStart,c=this.drag.originalEnd;if(this.drag.mode==="move"){const o=Math.round(s/this.drag.dayWidth);g=w(this.drag.originalStart,o),c=this.drag.kind==="milestone"?g:w(this.drag.originalEnd,o)}else if(this.drag.mode==="resize-start"){const o=Math.round(s/this.drag.dayWidth);g=Math.min(w(this.drag.originalStart,o),w(c,-1))}else{const o=Math.round(s/this.drag.dayWidth);c=Math.max(w(this.drag.originalEnd,o),w(g,1))}this.drag.latestStart=g,this.drag.latestEnd=c,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),u=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=`${u.toFixed(2)}px`;const p=this.drag.bar.querySelector(".drag-tip");p&&(p.textContent=this.drag.kind==="milestone"?S(this.drag.latestStart):`${S(this.drag.latestStart)} - ${S(this.drag.latestEnd)}`)}))});const e=()=>{if(!this.drag)return;this.drag.frame!=null&&cancelAnimationFrame(this.drag.frame);const i=this.drag;if(i.bar.classList.remove("dragging"),this.drag=null,!i.moved){i.selectedChanged&&this.requestRender();return}const s={id:i.taskId,start:S(i.latestStart),end:S(i.latestEnd)};this.overrides.set(i.taskId,{start:s.start,end:s.end}),this.bumpOverrides(),this.dispatchEvent(new CustomEvent("taskchange",{detail:s,bubbles:!0,composed:!0})),this.requestRender()};a.addEventListener("pointerup",e),a.addEventListener("pointercancel",e),a.addEventListener("keydown",i=>{const s=a.dataset.taskId;if(!s)return;if(i.key==="Delete"||i.key==="Backspace"){i.preventDefault(),this.dispatchEvent(new CustomEvent("taskdelete",{detail:{id:s},bubbles:!0,composed:!0}));return}if(i.key==="Enter"||i.key===" "){i.preventDefault(),this.selectTask(s);return}if(i.key==="ArrowUp"||i.key==="ArrowDown"){i.preventDefault(),this.selectAdjacentTask(s,i.key==="ArrowDown"?1:-1);return}if(i.key!=="ArrowLeft"&&i.key!=="ArrowRight")return;const c=this.getTasks().find(y=>y.id===s),o=x(c==null?void 0:c.start),u=x(c==null?void 0:c.end);if(!c||o==null||u==null)return;i.preventDefault();const p=i.key==="ArrowLeft"?-1:1,m=a.dataset.kind==="milestone",h=i.shiftKey&&!m?o:w(o,p),b=m?h:i.shiftKey?Math.max(w(u,p),w(o,1)):w(u,p),v={id:s,start:S(h),end:S(b)};this.overrides.set(s,{start:v.start,end:v.end}),this.bumpOverrides(),this.dispatchEvent(new CustomEvent("taskchange",{detail:v,bubbles:!0,composed:!0})),this.requestRender()})})}rangeMin(){const d=this.getTasks().map(l=>x(l.start)).filter(l=>l!=null);return d.length?w(Math.min(...d),-2):D(Date.now())}selectTask(r){if(this.captureViewport(),this.selectedId===r){this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:r},bubbles:!0,composed:!0}));return}this.selectedId=r,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:r},bubbles:!0,composed:!0})),this.requestRender()}selectAdjacentTask(r,d){const l=this.getVisibleTasks(this.getTasks(),this.getAttribute("filter")??this.internalFilter,j(this.getAttribute("sort"))),a=l.findIndex(i=>i.id===r),e=l[Math.max(0,Math.min(l.length-1,a+d))];!e||e.id===r||(this.selectedId=e.id,this.dispatchEvent(new CustomEvent("taskselect",{detail:{id:e.id},bubbles:!0,composed:!0})),this.requestRender(),window.requestAnimationFrame(()=>{var i;(i=this.root.querySelector(`.bar[data-task-id="${CSS.escape(e.id)}"]`))==null||i.focus()}))}captureViewport(){const r=this.root.querySelector(".viewport");r&&(this.viewportTop=r.scrollTop,this.viewportLeft=r.scrollLeft,this.viewportWidth=r.clientWidth||this.viewportWidth,this.viewportHeight=r.clientHeight||this.viewportHeight)}getTasks(){const r=this.getAttribute("tasks");return r===this.taskCacheRaw&&this.taskCacheVersion===this.overridesVersion?this.taskCache:(this.taskCacheRaw=r,this.taskCacheVersion=this.overridesVersion,this.taskCache=Rt(r,this.overrides),this.visibleCacheKey="",this.taskCache)}getLinks(){const r=this.getAttribute("links");return r===this.linkCacheRaw?this.linkCache:(this.linkCacheRaw=r,this.linkCache=qt(r),this.linkCache)}getVisibleTasks(r,d,l){const a=Array.from(this.collapsed).sort().join(","),e=`${this.taskCacheRaw||""}|${this.overridesVersion}|${d}|${l}|${a}`;return e===this.visibleCacheKey?this.visibleCache:(this.visibleCacheKey=e,this.visibleCache=Ht(r,this.collapsed,d,l),this.visibleCache)}bumpOverrides(){this.overridesVersion+=1,this.taskCacheVersion=-1,this.visibleCacheKey=""}shouldRenderOnAttributeChange(r,d,l){return r==="tasks"&&(this.overrides.clear(),this.bumpOverrides(),this.viewportTop=0,this.viewportLeft=0),r==="links"&&(this.linkCacheRaw=null),!0}}typeof customElements<"u"&&!customElements.get("ui-gantt")&&customElements.define("ui-gantt",yt);exports.UIGantt=yt;